]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/f2fs/f2fs.h
Merge remote-tracking branch 'wireless-next/master'
[karo-tx-linux.git] / fs / f2fs / f2fs.h
index 467d42d65c488a0ed3841b01e798841d0e48a395..590a09efce4a3a8fde298f6d9999212616ac4eb5 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/slab.h>
 #include <linux/crc32.h>
 #include <linux/magic.h>
+#include <linux/kobject.h>
+#include <linux/sched.h>
 
 /*
  * For mount options
@@ -28,6 +30,7 @@
 #define F2FS_MOUNT_XATTR_USER          0x00000010
 #define F2FS_MOUNT_POSIX_ACL           0x00000020
 #define F2FS_MOUNT_DISABLE_EXT_IDENTIFY        0x00000040
+#define F2FS_MOUNT_INLINE_XATTR                0x00000080
 
 #define clear_opt(sbi, option) (sbi->mount_opt.opt &= ~F2FS_MOUNT_##option)
 #define set_opt(sbi, option)   (sbi->mount_opt.opt |= F2FS_MOUNT_##option)
@@ -134,11 +137,13 @@ static inline int update_sits_in_cursum(struct f2fs_summary_block *rs, int i)
 /*
  * For INODE and NODE manager
  */
-#define XATTR_NODE_OFFSET      (-1)    /*
-                                        * store xattrs to one node block per
-                                        * file keeping -1 as its node offset to
-                                        * distinguish from index node blocks.
-                                        */
+/*
+ * XATTR_NODE_OFFSET stores xattrs to one node block per file keeping -1
+ * as its node offset to distinguish from index node blocks.
+ * But some bits are used to mark the node block.
+ */
+#define XATTR_NODE_OFFSET      ((((unsigned int)-1) << OFFSET_BIT_SHIFT) \
+                               >> OFFSET_BIT_SHIFT)
 enum {
        ALLOC_NODE,                     /* allocate a new node page if needed */
        LOOKUP_NODE,                    /* look up a node without readahead */
@@ -178,6 +183,7 @@ struct f2fs_inode_info {
        f2fs_hash_t chash;              /* hash value of given file name */
        unsigned int clevel;            /* maximum level of given file name */
        nid_t i_xattr_nid;              /* node id that contains xattrs */
+       unsigned long long xattr_ver;   /* cp version of xattr modification */
        struct extent_info ext;         /* in-memory extent cache entry */
 };
 
@@ -295,15 +301,6 @@ struct f2fs_sm_info {
        unsigned int ovp_segments;      /* # of overprovision segments */
 };
 
-/*
- * For directory operation
- */
-#define        NODE_DIR1_BLOCK         (ADDRS_PER_INODE + 1)
-#define        NODE_DIR2_BLOCK         (ADDRS_PER_INODE + 2)
-#define        NODE_IND1_BLOCK         (ADDRS_PER_INODE + 3)
-#define        NODE_IND2_BLOCK         (ADDRS_PER_INODE + 4)
-#define        NODE_DIND_BLOCK         (ADDRS_PER_INODE + 5)
-
 /*
  * For superblock
  */
@@ -321,14 +318,6 @@ enum count_type {
        NR_COUNT_TYPE,
 };
 
-/*
- * Uses as sbi->fs_lock[NR_GLOBAL_LOCKS].
- * The checkpoint procedure blocks all the locks in this fs_lock array.
- * Some FS operations grab free locks, and if there is no free lock,
- * then wait to grab a lock in a round-robin manner.
- */
-#define NR_GLOBAL_LOCKS        8
-
 /*
  * The below are the page types of bios used in submti_bio().
  * The available types are:
@@ -350,6 +339,7 @@ enum page_type {
 
 struct f2fs_sb_info {
        struct super_block *sb;                 /* pointer to VFS super block */
+       struct proc_dir_entry *s_proc;          /* proc entry */
        struct buffer_head *raw_super_buf;      /* buffer head of raw sb */
        struct f2fs_super_block *raw_super;     /* raw super block pointer */
        int s_dirty;                            /* dirty flag for checkpoint */
@@ -368,12 +358,12 @@ struct f2fs_sb_info {
        struct f2fs_checkpoint *ckpt;           /* raw checkpoint pointer */
        struct inode *meta_inode;               /* cache meta blocks */
        struct mutex cp_mutex;                  /* checkpoint procedure lock */
-       struct mutex fs_lock[NR_GLOBAL_LOCKS];  /* blocking FS operations */
+       struct rw_semaphore cp_rwsem;           /* blocking FS operations */
        struct mutex node_write;                /* locking node writes */
        struct mutex writepages;                /* mutex for writepages() */
-       unsigned char next_lock_num;            /* round-robin global locks */
-       int por_doing;                          /* recovery is doing or not */
-       int on_build_free_nids;                 /* build_free_nids is doing */
+       bool por_doing;                         /* recovery is doing or not */
+       bool on_build_free_nids;                /* build_free_nids is doing */
+       struct task_struct *cp_task;            /* checkpoint task */
 
        /* for orphan inode management */
        struct list_head orphan_inode_list;     /* orphan inode list */
@@ -429,6 +419,10 @@ struct f2fs_sb_info {
 #endif
        unsigned int last_victim[2];            /* last victim segment # */
        spinlock_t stat_lock;                   /* lock for stat operations */
+
+       /* For sysfs suppport */
+       struct kobject s_kobj;
+       struct completion s_kobj_unregister;
 };
 
 /*
@@ -454,6 +448,11 @@ static inline struct f2fs_checkpoint *F2FS_CKPT(struct f2fs_sb_info *sbi)
        return (struct f2fs_checkpoint *)(sbi->ckpt);
 }
 
+static inline struct f2fs_node *F2FS_NODE(struct page *page)
+{
+       return (struct f2fs_node *)page_address(page);
+}
+
 static inline struct f2fs_nm_info *NM_I(struct f2fs_sb_info *sbi)
 {
        return (struct f2fs_nm_info *)(sbi->nm_info);
@@ -489,6 +488,11 @@ static inline void F2FS_RESET_SB_DIRT(struct f2fs_sb_info *sbi)
        sbi->s_dirty = 0;
 }
 
+static inline unsigned long long cur_cp_version(struct f2fs_checkpoint *cp)
+{
+       return le64_to_cpu(cp->checkpoint_ver);
+}
+
 static inline bool is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
 {
        unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags);
@@ -509,48 +513,24 @@ static inline void clear_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
        cp->ckpt_flags = cpu_to_le32(ckpt_flags);
 }
 
-static inline void mutex_lock_all(struct f2fs_sb_info *sbi)
+static inline void f2fs_lock_op(struct f2fs_sb_info *sbi)
 {
-       int i;
-
-       for (i = 0; i < NR_GLOBAL_LOCKS; i++) {
-               /*
-                * This is the only time we take multiple fs_lock[]
-                * instances; the order is immaterial since we
-                * always hold cp_mutex, which serializes multiple
-                * such operations.
-                */
-               mutex_lock_nest_lock(&sbi->fs_lock[i], &sbi->cp_mutex);
-       }
+       down_read(&sbi->cp_rwsem);
 }
 
-static inline void mutex_unlock_all(struct f2fs_sb_info *sbi)
+static inline void f2fs_unlock_op(struct f2fs_sb_info *sbi)
 {
-       int i = 0;
-       for (; i < NR_GLOBAL_LOCKS; i++)
-               mutex_unlock(&sbi->fs_lock[i]);
+       up_read(&sbi->cp_rwsem);
 }
 
-static inline int mutex_lock_op(struct f2fs_sb_info *sbi)
+static inline void f2fs_lock_all(struct f2fs_sb_info *sbi)
 {
-       unsigned char next_lock = sbi->next_lock_num % NR_GLOBAL_LOCKS;
-       int i = 0;
-
-       for (; i < NR_GLOBAL_LOCKS; i++)
-               if (mutex_trylock(&sbi->fs_lock[i]))
-                       return i;
-
-       mutex_lock(&sbi->fs_lock[next_lock]);
-       sbi->next_lock_num++;
-       return next_lock;
+       down_write_nest_lock(&sbi->cp_rwsem, &sbi->cp_mutex);
 }
 
-static inline void mutex_unlock_op(struct f2fs_sb_info *sbi, int ilock)
+static inline void f2fs_unlock_all(struct f2fs_sb_info *sbi)
 {
-       if (ilock < 0)
-               return;
-       BUG_ON(ilock >= NR_GLOBAL_LOCKS);
-       mutex_unlock(&sbi->fs_lock[ilock]);
+       up_write(&sbi->cp_rwsem);
 }
 
 /*
@@ -677,7 +657,7 @@ static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi)
 {
        block_t start_addr;
        struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
-       unsigned long long ckpt_version = le64_to_cpu(ckpt->checkpoint_ver);
+       unsigned long long ckpt_version = cur_cp_version(ckpt);
 
        start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr);
 
@@ -808,11 +788,25 @@ static inline struct kmem_cache *f2fs_kmem_cache_create(const char *name,
        return kmem_cache_create(name, size, 0, SLAB_RECLAIM_ACCOUNT, ctor);
 }
 
+static inline void *f2fs_kmem_cache_alloc(struct kmem_cache *cachep,
+                                               gfp_t flags)
+{
+       void *entry;
+retry:
+       entry = kmem_cache_alloc(cachep, flags);
+       if (!entry) {
+               cond_resched();
+               goto retry;
+       }
+
+       return entry;
+}
+
 #define RAW_IS_INODE(p)        ((p)->footer.nid == (p)->footer.ino)
 
 static inline bool IS_INODE(struct page *page)
 {
-       struct f2fs_node *p = (struct f2fs_node *)page_address(page);
+       struct f2fs_node *p = F2FS_NODE(page);
        return RAW_IS_INODE(p);
 }
 
@@ -826,7 +820,7 @@ static inline block_t datablock_addr(struct page *node_page,
 {
        struct f2fs_node *raw_node;
        __le32 *addr_array;
-       raw_node = (struct f2fs_node *)page_address(node_page);
+       raw_node = F2FS_NODE(node_page);
        addr_array = blkaddr_in_node(raw_node);
        return le32_to_cpu(addr_array[offset]);
 }
@@ -873,6 +867,7 @@ enum {
        FI_NO_ALLOC,            /* should not allocate any blocks */
        FI_UPDATE_DIR,          /* should update inode block for consistency */
        FI_DELAY_IPUT,          /* used for the recovery */
+       FI_INLINE_XATTR,        /* used for inline xattr */
 };
 
 static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag)
@@ -905,6 +900,45 @@ static inline int cond_clear_inode_flag(struct f2fs_inode_info *fi, int flag)
        return 0;
 }
 
+static inline void get_inline_info(struct f2fs_inode_info *fi,
+                                       struct f2fs_inode *ri)
+{
+       if (ri->i_inline & F2FS_INLINE_XATTR)
+               set_inode_flag(fi, FI_INLINE_XATTR);
+}
+
+static inline void set_raw_inline(struct f2fs_inode_info *fi,
+                                       struct f2fs_inode *ri)
+{
+       ri->i_inline = 0;
+
+       if (is_inode_flag_set(fi, FI_INLINE_XATTR))
+               ri->i_inline |= F2FS_INLINE_XATTR;
+}
+
+static inline unsigned int addrs_per_inode(struct f2fs_inode_info *fi)
+{
+       if (is_inode_flag_set(fi, FI_INLINE_XATTR))
+               return DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS;
+       return DEF_ADDRS_PER_INODE;
+}
+
+static inline void *inline_xattr_addr(struct page *page)
+{
+       struct f2fs_inode *ri;
+       ri = (struct f2fs_inode *)page_address(page);
+       return (void *)&(ri->i_addr[DEF_ADDRS_PER_INODE -
+                                       F2FS_INLINE_XATTR_ADDRS]);
+}
+
+static inline int inline_xattr_size(struct inode *inode)
+{
+       if (is_inode_flag_set(F2FS_I(inode), FI_INLINE_XATTR))
+               return F2FS_INLINE_XATTR_ADDRS << 2;
+       else
+               return 0;
+}
+
 static inline int f2fs_readonly(struct super_block *sb)
 {
        return sb->s_flags & MS_RDONLY;
@@ -947,6 +981,7 @@ struct f2fs_dir_entry *f2fs_parent_dir(struct inode *, struct page **);
 ino_t f2fs_inode_by_name(struct inode *, struct qstr *);
 void f2fs_set_link(struct inode *, struct f2fs_dir_entry *,
                                struct page *, struct inode *);
+int update_dent_inode(struct inode *, const struct qstr *);
 int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *);
 void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *);
 int f2fs_make_empty(struct inode *, struct inode *);
@@ -980,6 +1015,7 @@ int is_checkpointed_node(struct f2fs_sb_info *, nid_t);
 void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *);
 int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int);
 int truncate_inode_blocks(struct inode *, pgoff_t);
+int truncate_xattr_node(struct inode *, struct page *);
 int remove_inode_page(struct inode *);
 struct page *new_inode_page(struct inode *, const struct qstr *);
 struct page *new_node_page(struct dnode_of_data *, unsigned int, struct page *);
@@ -1012,7 +1048,8 @@ int npages_for_summary_flush(struct f2fs_sb_info *);
 void allocate_new_segments(struct f2fs_sb_info *);
 struct page *get_sum_page(struct f2fs_sb_info *, unsigned int);
 struct bio *f2fs_bio_alloc(struct block_device *, int);
-void f2fs_submit_bio(struct f2fs_sb_info *, enum page_type, bool sync);
+void f2fs_submit_bio(struct f2fs_sb_info *, enum page_type, bool);
+void f2fs_wait_on_page_writeback(struct page *, enum page_type, bool);
 void write_meta_page(struct f2fs_sb_info *, struct page *);
 void write_node_page(struct f2fs_sb_info *, struct page *, unsigned int,
                                        block_t, block_t *);
@@ -1037,7 +1074,8 @@ void destroy_segment_manager(struct f2fs_sb_info *);
 struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t);
 struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t);
 long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long);
-int check_orphan_space(struct f2fs_sb_info *);
+int acquire_orphan_inode(struct f2fs_sb_info *);
+void release_orphan_inode(struct f2fs_sb_info *);
 void add_orphan_inode(struct f2fs_sb_info *, nid_t);
 void remove_orphan_inode(struct f2fs_sb_info *, nid_t);
 int recover_orphan_inodes(struct f2fs_sb_info *);
@@ -1068,7 +1106,7 @@ int do_write_data_page(struct page *);
  */
 int start_gc_thread(struct f2fs_sb_info *);
 void stop_gc_thread(struct f2fs_sb_info *);
-block_t start_bidx_of_node(unsigned int);
+block_t start_bidx_of_node(unsigned int, struct f2fs_inode_info *);
 int f2fs_gc(struct f2fs_sb_info *);
 void build_gc_manager(struct f2fs_sb_info *);
 int __init create_gc_caches(void);
@@ -1112,11 +1150,22 @@ struct f2fs_stat_info {
        unsigned base_mem, cache_mem;
 };
 
-#define stat_inc_call_count(si)        ((si)->call_count++)
+static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi)
+{
+       return (struct f2fs_stat_info*)sbi->stat_info;
+}
+
+#define stat_inc_call_count(si)                ((si)->call_count++)
+#define stat_inc_bggc_count(sbi)       ((sbi)->bg_gc++)
+#define stat_inc_dirty_dir(sbi)                ((sbi)->n_dirty_dirs++)
+#define stat_dec_dirty_dir(sbi)                ((sbi)->n_dirty_dirs--)
+#define stat_inc_hit_ext(sb)           ((F2FS_SB(sb))->total_hit_ext++)
+#define stat_inc_alloc_type(sbi, curseg)                               \
+               ((sbi)->segment_count[(curseg)->alloc_type]++)
 
 #define stat_inc_seg_count(sbi, type)                                  \
        do {                                                            \
-               struct f2fs_stat_info *si = sbi->stat_info;             \
+               struct f2fs_stat_info *si = F2FS_STAT(sbi);             \
                (si)->tot_segs++;                                       \
                if (type == SUM_TYPE_DATA)                              \
                        si->data_segs++;                                \
@@ -1129,24 +1178,30 @@ struct f2fs_stat_info {
 
 #define stat_inc_data_blk_count(sbi, blks)                             \
        do {                                                            \
-               struct f2fs_stat_info *si = sbi->stat_info;             \
+               struct f2fs_stat_info *si = F2FS_STAT(sbi);             \
                stat_inc_tot_blk_count(si, blks);                       \
                si->data_blks += (blks);                                \
        } while (0)
 
 #define stat_inc_node_blk_count(sbi, blks)                             \
        do {                                                            \
-               struct f2fs_stat_info *si = sbi->stat_info;             \
+               struct f2fs_stat_info *si = F2FS_STAT(sbi);             \
                stat_inc_tot_blk_count(si, blks);                       \
                si->node_blks += (blks);                                \
        } while (0)
 
+
 int f2fs_build_stats(struct f2fs_sb_info *);
 void f2fs_destroy_stats(struct f2fs_sb_info *);
 void __init f2fs_create_root_stats(void);
 void f2fs_destroy_root_stats(void);
 #else
 #define stat_inc_call_count(si)
+#define stat_inc_bggc_count(si)
+#define stat_inc_dirty_dir(sbi)
+#define stat_dec_dirty_dir(sbi)
+#define stat_inc_hit_ext(sb)
+#define stat_inc_alloc_type(sbi, curseg)
 #define stat_inc_seg_count(si, type)
 #define stat_inc_tot_blk_count(si, blks)
 #define stat_inc_data_blk_count(si, blks)