|
@@ -17,6 +17,7 @@
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/crc32.h>
|
|
#include <linux/crc32.h>
|
|
#include <linux/magic.h>
|
|
#include <linux/magic.h>
|
|
|
|
+#include <linux/kobject.h>
|
|
|
|
|
|
/*
|
|
/*
|
|
* For mount options
|
|
* For mount options
|
|
@@ -28,6 +29,7 @@
|
|
#define F2FS_MOUNT_XATTR_USER 0x00000010
|
|
#define F2FS_MOUNT_XATTR_USER 0x00000010
|
|
#define F2FS_MOUNT_POSIX_ACL 0x00000020
|
|
#define F2FS_MOUNT_POSIX_ACL 0x00000020
|
|
#define F2FS_MOUNT_DISABLE_EXT_IDENTIFY 0x00000040
|
|
#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 clear_opt(sbi, option) (sbi->mount_opt.opt &= ~F2FS_MOUNT_##option)
|
|
#define set_opt(sbi, option) (sbi->mount_opt.opt |= F2FS_MOUNT_##option)
|
|
#define set_opt(sbi, option) (sbi->mount_opt.opt |= F2FS_MOUNT_##option)
|
|
@@ -134,11 +136,13 @@ static inline int update_sits_in_cursum(struct f2fs_summary_block *rs, int i)
|
|
/*
|
|
/*
|
|
* For INODE and NODE manager
|
|
* 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 {
|
|
enum {
|
|
ALLOC_NODE, /* allocate a new node page if needed */
|
|
ALLOC_NODE, /* allocate a new node page if needed */
|
|
LOOKUP_NODE, /* look up a node without readahead */
|
|
LOOKUP_NODE, /* look up a node without readahead */
|
|
@@ -178,6 +182,7 @@ struct f2fs_inode_info {
|
|
f2fs_hash_t chash; /* hash value of given file name */
|
|
f2fs_hash_t chash; /* hash value of given file name */
|
|
unsigned int clevel; /* maximum level of given file name */
|
|
unsigned int clevel; /* maximum level of given file name */
|
|
nid_t i_xattr_nid; /* node id that contains xattrs */
|
|
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 */
|
|
struct extent_info ext; /* in-memory extent cache entry */
|
|
};
|
|
};
|
|
|
|
|
|
@@ -295,15 +300,6 @@ struct f2fs_sm_info {
|
|
unsigned int ovp_segments; /* # of overprovision segments */
|
|
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
|
|
* For superblock
|
|
*/
|
|
*/
|
|
@@ -350,6 +346,7 @@ enum page_type {
|
|
|
|
|
|
struct f2fs_sb_info {
|
|
struct f2fs_sb_info {
|
|
struct super_block *sb; /* pointer to VFS super block */
|
|
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 buffer_head *raw_super_buf; /* buffer head of raw sb */
|
|
struct f2fs_super_block *raw_super; /* raw super block pointer */
|
|
struct f2fs_super_block *raw_super; /* raw super block pointer */
|
|
int s_dirty; /* dirty flag for checkpoint */
|
|
int s_dirty; /* dirty flag for checkpoint */
|
|
@@ -429,6 +426,10 @@ struct f2fs_sb_info {
|
|
#endif
|
|
#endif
|
|
unsigned int last_victim[2]; /* last victim segment # */
|
|
unsigned int last_victim[2]; /* last victim segment # */
|
|
spinlock_t stat_lock; /* lock for stat operations */
|
|
spinlock_t stat_lock; /* lock for stat operations */
|
|
|
|
+
|
|
|
|
+ /* For sysfs suppport */
|
|
|
|
+ struct kobject s_kobj;
|
|
|
|
+ struct completion s_kobj_unregister;
|
|
};
|
|
};
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -454,6 +455,11 @@ static inline struct f2fs_checkpoint *F2FS_CKPT(struct f2fs_sb_info *sbi)
|
|
return (struct f2fs_checkpoint *)(sbi->ckpt);
|
|
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)
|
|
static inline struct f2fs_nm_info *NM_I(struct f2fs_sb_info *sbi)
|
|
{
|
|
{
|
|
return (struct f2fs_nm_info *)(sbi->nm_info);
|
|
return (struct f2fs_nm_info *)(sbi->nm_info);
|
|
@@ -489,6 +495,11 @@ static inline void F2FS_RESET_SB_DIRT(struct f2fs_sb_info *sbi)
|
|
sbi->s_dirty = 0;
|
|
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)
|
|
static inline bool is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
|
|
{
|
|
{
|
|
unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags);
|
|
unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags);
|
|
@@ -677,7 +688,7 @@ static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi)
|
|
{
|
|
{
|
|
block_t start_addr;
|
|
block_t start_addr;
|
|
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
|
|
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);
|
|
start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr);
|
|
|
|
|
|
@@ -812,7 +823,7 @@ static inline struct kmem_cache *f2fs_kmem_cache_create(const char *name,
|
|
|
|
|
|
static inline bool IS_INODE(struct page *page)
|
|
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);
|
|
return RAW_IS_INODE(p);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -826,7 +837,7 @@ static inline block_t datablock_addr(struct page *node_page,
|
|
{
|
|
{
|
|
struct f2fs_node *raw_node;
|
|
struct f2fs_node *raw_node;
|
|
__le32 *addr_array;
|
|
__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);
|
|
addr_array = blkaddr_in_node(raw_node);
|
|
return le32_to_cpu(addr_array[offset]);
|
|
return le32_to_cpu(addr_array[offset]);
|
|
}
|
|
}
|
|
@@ -873,6 +884,7 @@ enum {
|
|
FI_NO_ALLOC, /* should not allocate any blocks */
|
|
FI_NO_ALLOC, /* should not allocate any blocks */
|
|
FI_UPDATE_DIR, /* should update inode block for consistency */
|
|
FI_UPDATE_DIR, /* should update inode block for consistency */
|
|
FI_DELAY_IPUT, /* used for the recovery */
|
|
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)
|
|
static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag)
|
|
@@ -905,6 +917,45 @@ static inline int cond_clear_inode_flag(struct f2fs_inode_info *fi, int flag)
|
|
return 0;
|
|
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)
|
|
static inline int f2fs_readonly(struct super_block *sb)
|
|
{
|
|
{
|
|
return sb->s_flags & MS_RDONLY;
|
|
return sb->s_flags & MS_RDONLY;
|
|
@@ -947,6 +998,7 @@ struct f2fs_dir_entry *f2fs_parent_dir(struct inode *, struct page **);
|
|
ino_t f2fs_inode_by_name(struct inode *, struct qstr *);
|
|
ino_t f2fs_inode_by_name(struct inode *, struct qstr *);
|
|
void f2fs_set_link(struct inode *, struct f2fs_dir_entry *,
|
|
void f2fs_set_link(struct inode *, struct f2fs_dir_entry *,
|
|
struct page *, struct inode *);
|
|
struct page *, struct inode *);
|
|
|
|
+int update_dent_inode(struct inode *, const struct qstr *);
|
|
int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *);
|
|
int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *);
|
|
void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *);
|
|
void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *);
|
|
int f2fs_make_empty(struct inode *, struct inode *);
|
|
int f2fs_make_empty(struct inode *, struct inode *);
|
|
@@ -980,6 +1032,7 @@ int is_checkpointed_node(struct f2fs_sb_info *, nid_t);
|
|
void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *);
|
|
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 get_dnode_of_data(struct dnode_of_data *, pgoff_t, int);
|
|
int truncate_inode_blocks(struct inode *, pgoff_t);
|
|
int truncate_inode_blocks(struct inode *, pgoff_t);
|
|
|
|
+int truncate_xattr_node(struct inode *, struct page *);
|
|
int remove_inode_page(struct inode *);
|
|
int remove_inode_page(struct inode *);
|
|
struct page *new_inode_page(struct inode *, const struct qstr *);
|
|
struct page *new_inode_page(struct inode *, const struct qstr *);
|
|
struct page *new_node_page(struct dnode_of_data *, unsigned int, struct page *);
|
|
struct page *new_node_page(struct dnode_of_data *, unsigned int, struct page *);
|
|
@@ -1012,7 +1065,8 @@ int npages_for_summary_flush(struct f2fs_sb_info *);
|
|
void allocate_new_segments(struct f2fs_sb_info *);
|
|
void allocate_new_segments(struct f2fs_sb_info *);
|
|
struct page *get_sum_page(struct f2fs_sb_info *, unsigned int);
|
|
struct page *get_sum_page(struct f2fs_sb_info *, unsigned int);
|
|
struct bio *f2fs_bio_alloc(struct block_device *, 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_meta_page(struct f2fs_sb_info *, struct page *);
|
|
void write_node_page(struct f2fs_sb_info *, struct page *, unsigned int,
|
|
void write_node_page(struct f2fs_sb_info *, struct page *, unsigned int,
|
|
block_t, block_t *);
|
|
block_t, block_t *);
|
|
@@ -1037,7 +1091,8 @@ void destroy_segment_manager(struct f2fs_sb_info *);
|
|
struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t);
|
|
struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t);
|
|
struct page *get_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);
|
|
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 add_orphan_inode(struct f2fs_sb_info *, nid_t);
|
|
void remove_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 *);
|
|
int recover_orphan_inodes(struct f2fs_sb_info *);
|
|
@@ -1068,7 +1123,7 @@ int do_write_data_page(struct page *);
|
|
*/
|
|
*/
|
|
int start_gc_thread(struct f2fs_sb_info *);
|
|
int start_gc_thread(struct f2fs_sb_info *);
|
|
void stop_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 *);
|
|
int f2fs_gc(struct f2fs_sb_info *);
|
|
void build_gc_manager(struct f2fs_sb_info *);
|
|
void build_gc_manager(struct f2fs_sb_info *);
|
|
int __init create_gc_caches(void);
|
|
int __init create_gc_caches(void);
|
|
@@ -1112,11 +1167,16 @@ struct f2fs_stat_info {
|
|
unsigned base_mem, cache_mem;
|
|
unsigned base_mem, cache_mem;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+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_call_count(si) ((si)->call_count++)
|
|
|
|
|
|
#define stat_inc_seg_count(sbi, type) \
|
|
#define stat_inc_seg_count(sbi, type) \
|
|
do { \
|
|
do { \
|
|
- struct f2fs_stat_info *si = sbi->stat_info; \
|
|
|
|
|
|
+ struct f2fs_stat_info *si = F2FS_STAT(sbi); \
|
|
(si)->tot_segs++; \
|
|
(si)->tot_segs++; \
|
|
if (type == SUM_TYPE_DATA) \
|
|
if (type == SUM_TYPE_DATA) \
|
|
si->data_segs++; \
|
|
si->data_segs++; \
|
|
@@ -1129,14 +1189,14 @@ struct f2fs_stat_info {
|
|
|
|
|
|
#define stat_inc_data_blk_count(sbi, blks) \
|
|
#define stat_inc_data_blk_count(sbi, blks) \
|
|
do { \
|
|
do { \
|
|
- struct f2fs_stat_info *si = sbi->stat_info; \
|
|
|
|
|
|
+ struct f2fs_stat_info *si = F2FS_STAT(sbi); \
|
|
stat_inc_tot_blk_count(si, blks); \
|
|
stat_inc_tot_blk_count(si, blks); \
|
|
si->data_blks += (blks); \
|
|
si->data_blks += (blks); \
|
|
} while (0)
|
|
} while (0)
|
|
|
|
|
|
#define stat_inc_node_blk_count(sbi, blks) \
|
|
#define stat_inc_node_blk_count(sbi, blks) \
|
|
do { \
|
|
do { \
|
|
- struct f2fs_stat_info *si = sbi->stat_info; \
|
|
|
|
|
|
+ struct f2fs_stat_info *si = F2FS_STAT(sbi); \
|
|
stat_inc_tot_blk_count(si, blks); \
|
|
stat_inc_tot_blk_count(si, blks); \
|
|
si->node_blks += (blks); \
|
|
si->node_blks += (blks); \
|
|
} while (0)
|
|
} while (0)
|