RDMA/core: Properly increment and decrement QP usecnts
[linux-2.6-microblaze.git] / fs / f2fs / f2fs.h
index c83d901..ee8eb33 100644 (file)
@@ -98,6 +98,7 @@ extern const char *f2fs_fault_name[FAULT_MAX];
 #define F2FS_MOUNT_ATGC                        0x08000000
 #define F2FS_MOUNT_MERGE_CHECKPOINT    0x10000000
 #define        F2FS_MOUNT_GC_MERGE             0x20000000
+#define F2FS_MOUNT_COMPRESS_CACHE      0x40000000
 
 #define F2FS_OPTION(sbi)       ((sbi)->mount_opt)
 #define clear_opt(sbi, option) (F2FS_OPTION(sbi).opt &= ~F2FS_MOUNT_##option)
@@ -150,8 +151,10 @@ struct f2fs_mount_info {
        unsigned char compress_level;           /* compress level */
        bool compress_chksum;                   /* compressed data chksum */
        unsigned char compress_ext_cnt;         /* extension count */
+       unsigned char nocompress_ext_cnt;               /* nocompress extension count */
        int compress_mode;                      /* compression mode */
        unsigned char extensions[COMPRESS_EXT_NUM][F2FS_EXTENSION_LEN]; /* extensions */
+       unsigned char noextensions[COMPRESS_EXT_NUM][F2FS_EXTENSION_LEN]; /* extensions */
 };
 
 #define F2FS_FEATURE_ENCRYPT           0x0001
@@ -168,6 +171,7 @@ struct f2fs_mount_info {
 #define F2FS_FEATURE_SB_CHKSUM         0x0800
 #define F2FS_FEATURE_CASEFOLD          0x1000
 #define F2FS_FEATURE_COMPRESSION       0x2000
+#define F2FS_FEATURE_RO                        0x4000
 
 #define __F2FS_HAS_FEATURE(raw_super, mask)                            \
        ((raw_super->feature & cpu_to_le32(mask)) != 0)
@@ -706,6 +710,8 @@ enum {
        FI_COMPRESS_CORRUPT,    /* indicate compressed cluster is corrupted */
        FI_MMAP_FILE,           /* indicate file was mmapped */
        FI_ENABLE_COMPRESS,     /* enable compression in "user" compression mode */
+       FI_COMPRESS_RELEASED,   /* compressed blocks were released */
+       FI_ALIGNED_WRITE,       /* enable aligned write */
        FI_MAX,                 /* max flag, never be used */
 };
 
@@ -939,6 +945,7 @@ static inline void set_new_dnode(struct dnode_of_data *dn, struct inode *inode,
 #define        NR_CURSEG_DATA_TYPE     (3)
 #define NR_CURSEG_NODE_TYPE    (3)
 #define NR_CURSEG_INMEM_TYPE   (2)
+#define NR_CURSEG_RO_TYPE      (2)
 #define NR_CURSEG_PERSIST_TYPE (NR_CURSEG_DATA_TYPE + NR_CURSEG_NODE_TYPE)
 #define NR_CURSEG_TYPE         (NR_CURSEG_INMEM_TYPE + NR_CURSEG_PERSIST_TYPE)
 
@@ -1291,17 +1298,119 @@ enum {
                                 */
 };
 
+static inline int f2fs_test_bit(unsigned int nr, char *addr);
+static inline void f2fs_set_bit(unsigned int nr, char *addr);
+static inline void f2fs_clear_bit(unsigned int nr, char *addr);
+
 /*
- * this value is set in page as a private data which indicate that
- * the page is atomically written, and it is in inmem_pages list.
+ * Layout of f2fs page.private:
+ *
+ * Layout A: lowest bit should be 1
+ * | bit0 = 1 | bit1 | bit2 | ... | bit MAX | private data .... |
+ * bit 0       PAGE_PRIVATE_NOT_POINTER
+ * bit 1       PAGE_PRIVATE_ATOMIC_WRITE
+ * bit 2       PAGE_PRIVATE_DUMMY_WRITE
+ * bit 3       PAGE_PRIVATE_ONGOING_MIGRATION
+ * bit 4       PAGE_PRIVATE_INLINE_INODE
+ * bit 5       PAGE_PRIVATE_REF_RESOURCE
+ * bit 6-      f2fs private data
+ *
+ * Layout B: lowest bit should be 0
+ * page.private is a wrapped pointer.
  */
-#define ATOMIC_WRITTEN_PAGE            ((unsigned long)-1)
-#define DUMMY_WRITTEN_PAGE             ((unsigned long)-2)
+enum {
+       PAGE_PRIVATE_NOT_POINTER,               /* private contains non-pointer data */
+       PAGE_PRIVATE_ATOMIC_WRITE,              /* data page from atomic write path */
+       PAGE_PRIVATE_DUMMY_WRITE,               /* data page for padding aligned IO */
+       PAGE_PRIVATE_ONGOING_MIGRATION,         /* data page which is on-going migrating */
+       PAGE_PRIVATE_INLINE_INODE,              /* inode page contains inline data */
+       PAGE_PRIVATE_REF_RESOURCE,              /* dirty page has referenced resources */
+       PAGE_PRIVATE_MAX
+};
 
-#define IS_ATOMIC_WRITTEN_PAGE(page)                   \
-               (page_private(page) == ATOMIC_WRITTEN_PAGE)
-#define IS_DUMMY_WRITTEN_PAGE(page)                    \
-               (page_private(page) == DUMMY_WRITTEN_PAGE)
+#define PAGE_PRIVATE_GET_FUNC(name, flagname) \
+static inline bool page_private_##name(struct page *page) \
+{ \
+       return PagePrivate(page) && \
+               test_bit(PAGE_PRIVATE_NOT_POINTER, &page_private(page)) && \
+               test_bit(PAGE_PRIVATE_##flagname, &page_private(page)); \
+}
+
+#define PAGE_PRIVATE_SET_FUNC(name, flagname) \
+static inline void set_page_private_##name(struct page *page) \
+{ \
+       if (!PagePrivate(page)) { \
+               get_page(page); \
+               SetPagePrivate(page); \
+               set_page_private(page, 0); \
+       } \
+       set_bit(PAGE_PRIVATE_NOT_POINTER, &page_private(page)); \
+       set_bit(PAGE_PRIVATE_##flagname, &page_private(page)); \
+}
+
+#define PAGE_PRIVATE_CLEAR_FUNC(name, flagname) \
+static inline void clear_page_private_##name(struct page *page) \
+{ \
+       clear_bit(PAGE_PRIVATE_##flagname, &page_private(page)); \
+       if (page_private(page) == 1 << PAGE_PRIVATE_NOT_POINTER) { \
+               set_page_private(page, 0); \
+               if (PagePrivate(page)) { \
+                       ClearPagePrivate(page); \
+                       put_page(page); \
+               }\
+       } \
+}
+
+PAGE_PRIVATE_GET_FUNC(nonpointer, NOT_POINTER);
+PAGE_PRIVATE_GET_FUNC(reference, REF_RESOURCE);
+PAGE_PRIVATE_GET_FUNC(inline, INLINE_INODE);
+PAGE_PRIVATE_GET_FUNC(gcing, ONGOING_MIGRATION);
+PAGE_PRIVATE_GET_FUNC(atomic, ATOMIC_WRITE);
+PAGE_PRIVATE_GET_FUNC(dummy, DUMMY_WRITE);
+
+PAGE_PRIVATE_SET_FUNC(reference, REF_RESOURCE);
+PAGE_PRIVATE_SET_FUNC(inline, INLINE_INODE);
+PAGE_PRIVATE_SET_FUNC(gcing, ONGOING_MIGRATION);
+PAGE_PRIVATE_SET_FUNC(atomic, ATOMIC_WRITE);
+PAGE_PRIVATE_SET_FUNC(dummy, DUMMY_WRITE);
+
+PAGE_PRIVATE_CLEAR_FUNC(reference, REF_RESOURCE);
+PAGE_PRIVATE_CLEAR_FUNC(inline, INLINE_INODE);
+PAGE_PRIVATE_CLEAR_FUNC(gcing, ONGOING_MIGRATION);
+PAGE_PRIVATE_CLEAR_FUNC(atomic, ATOMIC_WRITE);
+PAGE_PRIVATE_CLEAR_FUNC(dummy, DUMMY_WRITE);
+
+static inline unsigned long get_page_private_data(struct page *page)
+{
+       unsigned long data = page_private(page);
+
+       if (!test_bit(PAGE_PRIVATE_NOT_POINTER, &data))
+               return 0;
+       return data >> PAGE_PRIVATE_MAX;
+}
+
+static inline void set_page_private_data(struct page *page, unsigned long data)
+{
+       if (!PagePrivate(page)) {
+               get_page(page);
+               SetPagePrivate(page);
+               set_page_private(page, 0);
+       }
+       set_bit(PAGE_PRIVATE_NOT_POINTER, &page_private(page));
+       page_private(page) |= data << PAGE_PRIVATE_MAX;
+}
+
+static inline void clear_page_private_data(struct page *page)
+{
+       page_private(page) &= (1 << PAGE_PRIVATE_MAX) - 1;
+       if (page_private(page) == 1 << PAGE_PRIVATE_NOT_POINTER) {
+               set_page_private(page, 0);
+               if (PagePrivate(page)) {
+                       ClearPagePrivate(page);
+                       put_page(page);
+               }
+       }
+}
 
 /* For compression */
 enum compress_algorithm_type {
@@ -1317,6 +1426,9 @@ enum compress_flag {
        COMPRESS_MAX_FLAG,
 };
 
+#define        COMPRESS_WATERMARK                      20
+#define        COMPRESS_PERCENT                        20
+
 #define COMPRESS_DATA_RESERVED_SIZE            4
 struct compress_data {
        __le32 clen;                    /* compressed data size */
@@ -1594,6 +1706,9 @@ struct f2fs_sb_info {
        struct kobject s_stat_kobj;             /* /sys/fs/f2fs/<devname>/stat */
        struct completion s_stat_kobj_unregister;
 
+       struct kobject s_feature_list_kobj;             /* /sys/fs/f2fs/<devname>/feature_list */
+       struct completion s_feature_list_kobj_unregister;
+
        /* For shrinker support */
        struct list_head s_list;
        int s_ndevs;                            /* number of devices */
@@ -1626,6 +1741,12 @@ struct f2fs_sb_info {
        u64 compr_written_block;
        u64 compr_saved_block;
        u32 compr_new_inode;
+
+       /* For compressed block cache */
+       struct inode *compress_inode;           /* cache compressed blocks */
+       unsigned int compress_percent;          /* cache page percentage */
+       unsigned int compress_watermark;        /* cache page watermark */
+       atomic_t compress_page_hit;             /* cache hit count */
 #endif
 };
 
@@ -2678,6 +2799,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,
        case FI_DATA_EXIST:
        case FI_INLINE_DOTS:
        case FI_PIN_FILE:
+       case FI_COMPRESS_RELEASED:
                f2fs_mark_inode_dirty_sync(inode, true);
        }
 }
@@ -2799,6 +2921,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)
                set_bit(FI_EXTRA_ATTR, fi->flags);
        if (ri->i_inline & F2FS_PIN_FILE)
                set_bit(FI_PIN_FILE, fi->flags);
+       if (ri->i_inline & F2FS_COMPRESS_RELEASED)
+               set_bit(FI_COMPRESS_RELEASED, fi->flags);
 }
 
 static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri)
@@ -2819,6 +2943,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri)
                ri->i_inline |= F2FS_EXTRA_ATTR;
        if (is_inode_flag_set(inode, FI_PIN_FILE))
                ri->i_inline |= F2FS_PIN_FILE;
+       if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED))
+               ri->i_inline |= F2FS_COMPRESS_RELEASED;
 }
 
 static inline int f2fs_has_extra_attr(struct inode *inode)
@@ -3027,25 +3153,6 @@ static inline bool is_dot_dotdot(const u8 *name, size_t len)
        return false;
 }
 
-static inline bool f2fs_may_extent_tree(struct inode *inode)
-{
-       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
-
-       if (!test_opt(sbi, EXTENT_CACHE) ||
-                       is_inode_flag_set(inode, FI_NO_EXTENT) ||
-                       is_inode_flag_set(inode, FI_COMPRESSED_FILE))
-               return false;
-
-       /*
-        * for recovered files during mount do not create extents
-        * if shrinker is not registered.
-        */
-       if (list_empty(&sbi->s_list))
-               return false;
-
-       return S_ISREG(inode->i_mode);
-}
-
 static inline void *f2fs_kmalloc(struct f2fs_sb_info *sbi,
                                        size_t size, gfp_t flags)
 {
@@ -3169,20 +3276,6 @@ static inline bool __is_valid_data_blkaddr(block_t blkaddr)
        return true;
 }
 
-static inline void f2fs_set_page_private(struct page *page,
-                                               unsigned long data)
-{
-       if (PagePrivate(page))
-               return;
-
-       attach_page_private(page, (void *)data);
-}
-
-static inline void f2fs_clear_page_private(struct page *page)
-{
-       detach_page_private(page);
-}
-
 /*
  * file.c
  */
@@ -3566,6 +3659,8 @@ void f2fs_destroy_garbage_collection_cache(void);
  */
 int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only);
 bool f2fs_space_for_roll_forward(struct f2fs_sb_info *sbi);
+int __init f2fs_create_recovery_cache(void);
+void f2fs_destroy_recovery_cache(void);
 
 /*
  * debug.c
@@ -3604,7 +3699,8 @@ struct f2fs_stat_info {
        unsigned int bimodal, avg_vblocks;
        int util_free, util_valid, util_invalid;
        int rsvd_segs, overp_segs;
-       int dirty_count, node_pages, meta_pages;
+       int dirty_count, node_pages, meta_pages, compress_pages;
+       int compress_page_hit;
        int prefree_count, call_count, cp_count, bg_cp_count;
        int tot_segs, node_segs, data_segs, free_segs, free_secs;
        int bg_node_segs, bg_data_segs;
@@ -3940,7 +4036,9 @@ void f2fs_compress_write_end_io(struct bio *bio, struct page *page);
 bool f2fs_is_compress_backend_ready(struct inode *inode);
 int f2fs_init_compress_mempool(void);
 void f2fs_destroy_compress_mempool(void);
-void f2fs_end_read_compressed_page(struct page *page, bool failed);
+void f2fs_decompress_cluster(struct decompress_io_ctx *dic);
+void f2fs_end_read_compressed_page(struct page *page, bool failed,
+                                                       block_t blkaddr);
 bool f2fs_cluster_is_empty(struct compress_ctx *cc);
 bool f2fs_cluster_can_merge_page(struct compress_ctx *cc, pgoff_t index);
 void f2fs_compress_ctx_add_page(struct compress_ctx *cc, struct page *page);
@@ -3958,10 +4056,19 @@ void f2fs_put_page_dic(struct page *page);
 int f2fs_init_compress_ctx(struct compress_ctx *cc);
 void f2fs_destroy_compress_ctx(struct compress_ctx *cc, bool reuse);
 void f2fs_init_compress_info(struct f2fs_sb_info *sbi);
+int f2fs_init_compress_inode(struct f2fs_sb_info *sbi);
+void f2fs_destroy_compress_inode(struct f2fs_sb_info *sbi);
 int f2fs_init_page_array_cache(struct f2fs_sb_info *sbi);
 void f2fs_destroy_page_array_cache(struct f2fs_sb_info *sbi);
 int __init f2fs_init_compress_cache(void);
 void f2fs_destroy_compress_cache(void);
+struct address_space *COMPRESS_MAPPING(struct f2fs_sb_info *sbi);
+void f2fs_invalidate_compress_page(struct f2fs_sb_info *sbi, block_t blkaddr);
+void f2fs_cache_compressed_page(struct f2fs_sb_info *sbi, struct page *page,
+                                               nid_t ino, block_t blkaddr);
+bool f2fs_load_compressed_page(struct f2fs_sb_info *sbi, struct page *page,
+                                                               block_t blkaddr);
+void f2fs_invalidate_compress_pages(struct f2fs_sb_info *sbi, nid_t ino);
 #define inc_compr_inode_stat(inode)                                    \
        do {                                                            \
                struct f2fs_sb_info *sbi = F2FS_I_SB(inode);            \
@@ -3990,7 +4097,9 @@ static inline struct page *f2fs_compress_control_page(struct page *page)
 }
 static inline int f2fs_init_compress_mempool(void) { return 0; }
 static inline void f2fs_destroy_compress_mempool(void) { }
-static inline void f2fs_end_read_compressed_page(struct page *page, bool failed)
+static inline void f2fs_decompress_cluster(struct decompress_io_ctx *dic) { }
+static inline void f2fs_end_read_compressed_page(struct page *page,
+                                               bool failed, block_t blkaddr)
 {
        WARN_ON_ONCE(1);
 }
@@ -3998,10 +4107,20 @@ static inline void f2fs_put_page_dic(struct page *page)
 {
        WARN_ON_ONCE(1);
 }
+static inline int f2fs_init_compress_inode(struct f2fs_sb_info *sbi) { return 0; }
+static inline void f2fs_destroy_compress_inode(struct f2fs_sb_info *sbi) { }
 static inline int f2fs_init_page_array_cache(struct f2fs_sb_info *sbi) { return 0; }
 static inline void f2fs_destroy_page_array_cache(struct f2fs_sb_info *sbi) { }
 static inline int __init f2fs_init_compress_cache(void) { return 0; }
 static inline void f2fs_destroy_compress_cache(void) { }
+static inline void f2fs_invalidate_compress_page(struct f2fs_sb_info *sbi,
+                               block_t blkaddr) { }
+static inline void f2fs_cache_compressed_page(struct f2fs_sb_info *sbi,
+                               struct page *page, nid_t ino, block_t blkaddr) { }
+static inline bool f2fs_load_compressed_page(struct f2fs_sb_info *sbi,
+                               struct page *page, block_t blkaddr) { return false; }
+static inline void f2fs_invalidate_compress_pages(struct f2fs_sb_info *sbi,
+                                                       nid_t ino) { }
 #define inc_compr_inode_stat(inode)            do { } while (0)
 #endif
 
@@ -4066,6 +4185,27 @@ F2FS_FEATURE_FUNCS(verity, VERITY);
 F2FS_FEATURE_FUNCS(sb_chksum, SB_CHKSUM);
 F2FS_FEATURE_FUNCS(casefold, CASEFOLD);
 F2FS_FEATURE_FUNCS(compression, COMPRESSION);
+F2FS_FEATURE_FUNCS(readonly, RO);
+
+static inline bool f2fs_may_extent_tree(struct inode *inode)
+{
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+
+       if (!test_opt(sbi, EXTENT_CACHE) ||
+                       is_inode_flag_set(inode, FI_NO_EXTENT) ||
+                       (is_inode_flag_set(inode, FI_COMPRESSED_FILE) &&
+                        !f2fs_sb_has_readonly(sbi)))
+               return false;
+
+       /*
+        * for recovered files during mount do not create extents
+        * if shrinker is not registered.
+        */
+       if (list_empty(&sbi->s_list))
+               return false;
+
+       return S_ISREG(inode->i_mode);
+}
 
 #ifdef CONFIG_BLK_DEV_ZONED
 static inline bool f2fs_blkz_is_seq(struct f2fs_sb_info *sbi, int devi,