Discussion:
[PATCH 01/11] f2fs: reuse room_for_filename for inline dentry operation
Jaegeuk Kim
2014-10-20 05:19:29 UTC
Permalink
This patch introduces to reuse the existing room_for_filename for inline dentry
operation.

Signed-off-by: Jaegeuk Kim <***@kernel.org>
---
fs/f2fs/dir.c | 21 +++++++++------------
fs/f2fs/f2fs.h | 1 +
fs/f2fs/inline.c | 27 ++-------------------------
3 files changed, 12 insertions(+), 37 deletions(-)

diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index cc6474a..164c6c9 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -427,27 +427,23 @@ void update_parent_metadata(struct inode *dir, struct inode *inode,
clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
}

-static int room_for_filename(struct f2fs_dentry_block *dentry_blk, int slots)
+int room_for_filename(const void *bitmap, int slots, int max_slots)
{
int bit_start = 0;
int zero_start, zero_end;
next:
- zero_start = find_next_zero_bit_le(&dentry_blk->dentry_bitmap,
- NR_DENTRY_IN_BLOCK,
- bit_start);
- if (zero_start >= NR_DENTRY_IN_BLOCK)
- return NR_DENTRY_IN_BLOCK;
+ zero_start = find_next_zero_bit_le(bitmap, max_slots, bit_start);
+ if (zero_start >= max_slots)
+ return max_slots;

- zero_end = find_next_bit_le(&dentry_blk->dentry_bitmap,
- NR_DENTRY_IN_BLOCK,
- zero_start);
+ zero_end = find_next_bit_le(bitmap, max_slots, zero_start);
if (zero_end - zero_start >= slots)
return zero_start;

bit_start = zero_end + 1;

- if (zero_end + 1 >= NR_DENTRY_IN_BLOCK)
- return NR_DENTRY_IN_BLOCK;
+ if (zero_end + 1 >= max_slots)
+ return max_slots;
goto next;
}

@@ -509,7 +505,8 @@ start:
return PTR_ERR(dentry_page);

dentry_blk = kmap(dentry_page);
- bit_pos = room_for_filename(dentry_blk, slots);
+ bit_pos = room_for_filename(&dentry_blk->dentry_bitmap,
+ slots, NR_DENTRY_IN_BLOCK);
if (bit_pos < NR_DENTRY_IN_BLOCK)
goto add_dentry;

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index c537699..aa055e3 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1248,6 +1248,7 @@ void set_de_type(struct f2fs_dir_entry *, struct inode *);
struct page *init_inode_metadata(struct inode *, struct inode *,
const struct qstr *);
void update_parent_metadata(struct inode *, struct inode *, unsigned int);
+int room_for_filename(const void *, int, int);
void f2fs_drop_nlink(struct inode *, struct inode *, struct page *);
struct f2fs_dir_entry *f2fs_find_entry(struct inode *, struct qstr *,
struct page **);
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index 02e2449..5d9dabb 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -363,30 +363,6 @@ int make_empty_inline_dir(struct inode *inode, struct inode *parent,
return 0;
}

-int room_in_inline_dir(struct f2fs_inline_dentry *dentry_blk, int slots)
-{
- int bit_start = 0;
- int zero_start, zero_end;
-next:
- zero_start = find_next_zero_bit_le(&dentry_blk->dentry_bitmap,
- NR_INLINE_DENTRY,
- bit_start);
- if (zero_start >= NR_INLINE_DENTRY)
- return NR_INLINE_DENTRY;
-
- zero_end = find_next_bit_le(&dentry_blk->dentry_bitmap,
- NR_INLINE_DENTRY,
- zero_start);
- if (zero_end - zero_start >= slots)
- return zero_start;
-
- bit_start = zero_end + 1;
-
- if (zero_end + 1 >= NR_INLINE_DENTRY)
- return NR_INLINE_DENTRY;
- goto next;
-}
-
int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage,
struct f2fs_inline_dentry *inline_dentry)
{
@@ -462,7 +438,8 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name,
return PTR_ERR(ipage);

dentry_blk = inline_data_addr(ipage);
- bit_pos = room_in_inline_dir(dentry_blk, slots);
+ bit_pos = room_for_filename(&dentry_blk->dentry_bitmap,
+ slots, NR_INLINE_DENTRY);
if (bit_pos >= NR_INLINE_DENTRY) {
err = f2fs_convert_inline_dir(dir, ipage, dentry_blk);
if (!err)
--
2.1.1
Jaegeuk Kim
2014-10-20 05:19:30 UTC
Permalink
This patch removes redundant copied code in find_in_inline_dir.

Signed-off-by: Jaegeuk Kim <***@kernel.org>
---
fs/f2fs/dir.c | 72 +++++++++++++++++++++++++++++++++++---------------------
fs/f2fs/f2fs.h | 3 ++-
fs/f2fs/inline.c | 52 +++++++++++++---------------------------
3 files changed, 64 insertions(+), 63 deletions(-)

diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index 164c6c9..c60b93f 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -77,7 +77,7 @@ static unsigned long dir_block_index(unsigned int level,
return bidx;
}

-bool early_match_name(size_t namelen, f2fs_hash_t namehash,
+static bool early_match_name(size_t namelen, f2fs_hash_t namehash,
struct f2fs_dir_entry *de)
{
if (le16_to_cpu(de->name_len) != namelen)
@@ -90,49 +90,68 @@ bool early_match_name(size_t namelen, f2fs_hash_t namehash,
}

static struct f2fs_dir_entry *find_in_block(struct page *dentry_page,
- struct qstr *name, int *max_slots,
- f2fs_hash_t namehash, struct page **res_page)
+ struct qstr *name, int *max_slots,
+ struct page **res_page)
+{
+ struct f2fs_dentry_block *dentry_blk;
+ struct f2fs_dir_entry *de;
+
+ *max_slots = NR_DENTRY_IN_BLOCK;
+
+ dentry_blk = (struct f2fs_dentry_block *)kmap(dentry_page);
+ de = find_target_dentry(name, max_slots, &dentry_blk->dentry_bitmap,
+ dentry_blk->dentry,
+ dentry_blk->filename);
+ kunmap(dentry_page);
+ if (de)
+ *res_page = dentry_page;
+
+ /*
+ * For the most part, it should be a bug when name_len is zero.
+ * We stop here for figuring out where the bugs has occurred.
+ */
+ f2fs_bug_on(F2FS_P_SB(dentry_page), *max_slots < 0);
+ return de;
+}
+
+struct f2fs_dir_entry *find_target_dentry(struct qstr *name, int *max_slots,
+ const void *bitmap, struct f2fs_dir_entry *dentry,
+ __u8 (*filenames)[F2FS_SLOT_LEN])
{
struct f2fs_dir_entry *de;
unsigned long bit_pos = 0;
- struct f2fs_dentry_block *dentry_blk = kmap(dentry_page);
- const void *dentry_bits = &dentry_blk->dentry_bitmap;
+ f2fs_hash_t namehash = f2fs_dentry_hash(name);
+ int max_bits = *max_slots;
int max_len = 0;

- while (bit_pos < NR_DENTRY_IN_BLOCK) {
- if (!test_bit_le(bit_pos, dentry_bits)) {
+ *max_slots = 0;
+ while (bit_pos < max_bits) {
+ if (!test_bit_le(bit_pos, bitmap)) {
if (bit_pos == 0)
max_len = 1;
- else if (!test_bit_le(bit_pos - 1, dentry_bits))
+ else if (!test_bit_le(bit_pos - 1, bitmap))
max_len++;
bit_pos++;
continue;
}
- de = &dentry_blk->dentry[bit_pos];
- if (early_match_name(name->len, namehash, de)) {
- if (!memcmp(dentry_blk->filename[bit_pos],
- name->name,
- name->len)) {
- *res_page = dentry_page;
- goto found;
- }
- }
- if (max_len > *max_slots) {
+ de = &dentry[bit_pos];
+ if (early_match_name(name->len, namehash, de) &&
+ !memcmp(filenames[bit_pos], name->name, name->len))
+ goto found;
+
+ if (*max_slots >= 0 && max_len > *max_slots) {
*max_slots = max_len;
max_len = 0;
}

- /*
- * For the most part, it should be a bug when name_len is zero.
- * We stop here for figuring out where the bugs has occurred.
- */
- f2fs_bug_on(F2FS_P_SB(dentry_page), !de->name_len);
+ /* remain bug on condition */
+ if (unlikely(!de->name_len))
+ *max_slots = -1;

bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
}

de = NULL;
- kunmap(dentry_page);
found:
if (max_len > *max_slots)
*max_slots = max_len;
@@ -149,7 +168,7 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
struct page *dentry_page;
struct f2fs_dir_entry *de = NULL;
bool room = false;
- int max_slots = 0;
+ int max_slots;

f2fs_bug_on(F2FS_I_SB(dir), level > MAX_DIR_HASH_DEPTH);

@@ -168,8 +187,7 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
continue;
}

- de = find_in_block(dentry_page, name, &max_slots,
- namehash, res_page);
+ de = find_in_block(dentry_page, name, &max_slots, res_page);
if (de)
break;

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index aa055e3..6aad6e0 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1243,8 +1243,9 @@ struct dentry *f2fs_get_parent(struct dentry *child);
* dir.c
*/
extern unsigned char f2fs_filetype_table[F2FS_FT_MAX];
-bool early_match_name(size_t, f2fs_hash_t, struct f2fs_dir_entry *);
void set_de_type(struct f2fs_dir_entry *, struct inode *);
+struct f2fs_dir_entry *find_target_dentry(struct qstr *, int *, const void *,
+ struct f2fs_dir_entry *, __u8 (*)[F2FS_SLOT_LEN]);
struct page *init_inode_metadata(struct inode *, struct inode *,
const struct qstr *);
void update_parent_metadata(struct inode *, struct inode *, unsigned int);
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index 5d9dabb..6f9ba80 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -263,49 +263,31 @@ struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir,
struct qstr *name, struct page **res_page)
{
struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
- struct page *ipage;
+ struct f2fs_inline_dentry *inline_dentry;
struct f2fs_dir_entry *de;
- f2fs_hash_t namehash;
- unsigned long bit_pos = 0;
- struct f2fs_inline_dentry *dentry_blk;
- const void *dentry_bits;
+ struct page *ipage;
+ int max_slots = NR_INLINE_DENTRY;

ipage = get_node_page(sbi, dir->i_ino);
if (IS_ERR(ipage))
return NULL;

- namehash = f2fs_dentry_hash(name);
-
- dentry_blk = inline_data_addr(ipage);
- dentry_bits = &dentry_blk->dentry_bitmap;
-
- while (bit_pos < NR_INLINE_DENTRY) {
- if (!test_bit_le(bit_pos, dentry_bits)) {
- bit_pos++;
- continue;
- }
- de = &dentry_blk->dentry[bit_pos];
- if (early_match_name(name->len, namehash, de)) {
- if (!memcmp(dentry_blk->filename[bit_pos],
- name->name,
- name->len)) {
- *res_page = ipage;
- goto found;
- }
- }
-
- /*
- * For the most part, it should be a bug when name_len is zero.
- * We stop here for figuring out where the bugs are occurred.
- */
- f2fs_bug_on(F2FS_P_SB(ipage), !de->name_len);
-
- bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
- }
+ inline_dentry = inline_data_addr(ipage);

- de = NULL;
-found:
+ de = find_target_dentry(name, &max_slots, &inline_dentry->dentry_bitmap,
+ inline_dentry->dentry,
+ inline_dentry->filename);
unlock_page(ipage);
+ if (de)
+ *res_page = ipage;
+ else
+ f2fs_put_page(ipage, 0);
+
+ /*
+ * For the most part, it should be a bug when name_len is zero.
+ * We stop here for figuring out where the bugs has occurred.
+ */
+ f2fs_bug_on(sbi, max_slots < 0);
return de;
}
--
2.1.1
Jaegeuk Kim
2014-10-20 05:19:31 UTC
Permalink
The inode page needs to wait NODE block io.

Signed-off-by: Jaegeuk Kim <***@kernel.org>
---
fs/f2fs/dir.c | 3 ++-
fs/f2fs/inline.c | 4 ++--
2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index c60b93f..644b480 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -282,8 +282,9 @@ ino_t f2fs_inode_by_name(struct inode *dir, struct qstr *qstr)
void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
struct page *page, struct inode *inode)
{
+ enum page_type type = f2fs_has_inline_dentry(dir) ? NODE : DATA;
lock_page(page);
- f2fs_wait_on_page_writeback(page, DATA);
+ f2fs_wait_on_page_writeback(page, type);
de->ino = cpu_to_le32(inode->i_ino);
set_de_type(de, inode);
if (!f2fs_has_inline_dentry(dir))
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index 6f9ba80..6fbdce7 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -429,7 +429,7 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name,
goto out;
}

- f2fs_wait_on_page_writeback(ipage, DATA);
+ f2fs_wait_on_page_writeback(ipage, NODE);

down_write(&F2FS_I(inode)->i_sem);
page = init_inode_metadata(inode, dir, name);
@@ -474,7 +474,7 @@ void f2fs_delete_inline_entry(struct f2fs_dir_entry *dentry, struct page *page,
int i;

lock_page(page);
- f2fs_wait_on_page_writeback(page, DATA);
+ f2fs_wait_on_page_writeback(page, NODE);

inline_dentry = inline_data_addr(page);
bit_pos = dentry - inline_dentry->dentry;
--
2.1.1
Jaegeuk Kim
2014-10-20 05:19:32 UTC
Permalink
Previously, init_inode_metadata does not hold any parent directory's inode
page. So, f2fs_init_acl can grab its parent inode page without any problem.
But, when we use inline_dentry, that page is grabbed during f2fs_add_link,
so that we can fall into deadlock condition like below.

INFO: task mknod:11006 blocked for more than 120 seconds.
Tainted: G OE 3.17.0-rc1+ #13
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
mknod D ffff88003fc94580 0 11006 11004 0x00000000
ffff880007717b10 0000000000000002 ffff88003c323220 ffff880007717fd8
0000000000014580 0000000000014580 ffff88003daecb30 ffff88003c323220
ffff88003fc94e80 ffff88003ffbb4e8 ffff880007717ba0 0000000000000002
Call Trace:
[<ffffffff8173dc40>] ? bit_wait+0x50/0x50
[<ffffffff8173d4cd>] io_schedule+0x9d/0x130
[<ffffffff8173dc6c>] bit_wait_io+0x2c/0x50
[<ffffffff8173da3b>] __wait_on_bit_lock+0x4b/0xb0
[<ffffffff811640a7>] __lock_page+0x67/0x70
[<ffffffff810acf50>] ? autoremove_wake_function+0x40/0x40
[<ffffffff811652cc>] pagecache_get_page+0x14c/0x1e0
[<ffffffffa029afa9>] get_node_page+0x59/0x130 [f2fs]
[<ffffffffa02a63ad>] read_all_xattrs+0x24d/0x430 [f2fs]
[<ffffffffa02a6ca2>] f2fs_getxattr+0x52/0xe0 [f2fs]
[<ffffffffa02a7481>] f2fs_get_acl+0x41/0x2d0 [f2fs]
[<ffffffff8122d847>] get_acl+0x47/0x70
[<ffffffff8122db5a>] posix_acl_create+0x5a/0x150
[<ffffffffa02a7759>] f2fs_init_acl+0x29/0xcb [f2fs]
[<ffffffffa0286a8d>] init_inode_metadata+0x5d/0x340 [f2fs]
[<ffffffffa029253a>] f2fs_add_inline_entry+0x12a/0x2e0 [f2fs]
[<ffffffffa0286ea5>] __f2fs_add_link+0x45/0x4a0 [f2fs]
[<ffffffffa028b5b6>] ? f2fs_new_inode+0x146/0x220 [f2fs]
[<ffffffffa028b816>] f2fs_mknod+0x86/0xf0 [f2fs]
[<ffffffff811e3ec1>] vfs_mknod+0xe1/0x160
[<ffffffff811e4b26>] SyS_mknod+0x1f6/0x200
[<ffffffff81741d7f>] tracesys+0xe1/0xe6

Signed-off-by: Jaegeuk Kim <***@kernel.org>
---
fs/f2fs/acl.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
fs/f2fs/acl.h | 5 +-
fs/f2fs/dir.c | 10 ++--
fs/f2fs/f2fs.h | 2 +-
fs/f2fs/inline.c | 6 +--
fs/f2fs/xattr.c | 6 +--
fs/f2fs/xattr.h | 6 ++-
7 files changed, 157 insertions(+), 22 deletions(-)

diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c
index 83b9b5a..6207455 100644
--- a/fs/f2fs/acl.c
+++ b/fs/f2fs/acl.c
@@ -162,7 +162,8 @@ fail:
return ERR_PTR(-EINVAL);
}

-struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
+static struct posix_acl *__f2fs_get_acl(struct inode *inode, int type,
+ struct page *dpage)
{
int name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT;
void *value = NULL;
@@ -172,12 +173,13 @@ struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
if (type == ACL_TYPE_ACCESS)
name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;

- retval = f2fs_getxattr(inode, name_index, "", NULL, 0);
+ retval = f2fs_getxattr(inode, name_index, "", NULL, 0, dpage);
if (retval > 0) {
value = kmalloc(retval, GFP_F2FS_ZERO);
if (!value)
return ERR_PTR(-ENOMEM);
- retval = f2fs_getxattr(inode, name_index, "", value, retval);
+ retval = f2fs_getxattr(inode, name_index, "", value,
+ retval, dpage);
}

if (retval > 0)
@@ -194,6 +196,11 @@ struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
return acl;
}

+struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
+{
+ return __f2fs_get_acl(inode, type, NULL);
+}
+
static int __f2fs_set_acl(struct inode *inode, int type,
struct posix_acl *acl, struct page *ipage)
{
@@ -249,12 +256,137 @@ int f2fs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
return __f2fs_set_acl(inode, type, acl, NULL);
}

-int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage)
+/*
+ * Most part of f2fs_acl_clone, f2fs_acl_create_masq, f2fs_acl_create
+ * are copied from posix_acl.c
+ */
+static struct posix_acl *f2fs_acl_clone(const struct posix_acl *acl,
+ gfp_t flags)
+{
+ struct posix_acl *clone = NULL;
+
+ if (acl) {
+ int size = sizeof(struct posix_acl) + acl->a_count *
+ sizeof(struct posix_acl_entry);
+ clone = kmemdup(acl, size, flags);
+ if (clone)
+ atomic_set(&clone->a_refcount, 1);
+ }
+ return clone;
+}
+
+static int f2fs_acl_create_masq(struct posix_acl *acl, umode_t *mode_p)
+{
+ struct posix_acl_entry *pa, *pe;
+ struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL;
+ umode_t mode = *mode_p;
+ int not_equiv = 0;
+
+ /* assert(atomic_read(acl->a_refcount) == 1); */
+
+ FOREACH_ACL_ENTRY(pa, acl, pe) {
+ switch(pa->e_tag) {
+ case ACL_USER_OBJ:
+ pa->e_perm &= (mode >> 6) | ~S_IRWXO;
+ mode &= (pa->e_perm << 6) | ~S_IRWXU;
+ break;
+
+ case ACL_USER:
+ case ACL_GROUP:
+ not_equiv = 1;
+ break;
+
+ case ACL_GROUP_OBJ:
+ group_obj = pa;
+ break;
+
+ case ACL_OTHER:
+ pa->e_perm &= mode | ~S_IRWXO;
+ mode &= pa->e_perm | ~S_IRWXO;
+ break;
+
+ case ACL_MASK:
+ mask_obj = pa;
+ not_equiv = 1;
+ break;
+
+ default:
+ return -EIO;
+ }
+ }
+
+ if (mask_obj) {
+ mask_obj->e_perm &= (mode >> 3) | ~S_IRWXO;
+ mode &= (mask_obj->e_perm << 3) | ~S_IRWXG;
+ } else {
+ if (!group_obj)
+ return -EIO;
+ group_obj->e_perm &= (mode >> 3) | ~S_IRWXO;
+ mode &= (group_obj->e_perm << 3) | ~S_IRWXG;
+ }
+
+ *mode_p = (*mode_p & ~S_IRWXUGO) | mode;
+ return not_equiv;
+}
+
+static int f2fs_acl_create(struct inode *dir, umode_t *mode,
+ struct posix_acl **default_acl, struct posix_acl **acl,
+ struct page *dpage)
+{
+ struct posix_acl *p;
+ int ret;
+
+ if (S_ISLNK(*mode) || !IS_POSIXACL(dir))
+ goto no_acl;
+
+ p = __f2fs_get_acl(dir, ACL_TYPE_DEFAULT, dpage);
+ if (IS_ERR(p)) {
+ if (p == ERR_PTR(-EOPNOTSUPP))
+ goto apply_umask;
+ return PTR_ERR(p);
+ }
+
+ if (!p)
+ goto apply_umask;
+
+ *acl = f2fs_acl_clone(p, GFP_NOFS);
+ if (!*acl)
+ return -ENOMEM;
+
+ ret = f2fs_acl_create_masq(*acl, mode);
+ if (ret < 0) {
+ posix_acl_release(*acl);
+ return -ENOMEM;
+ }
+
+ if (ret == 0) {
+ posix_acl_release(*acl);
+ *acl = NULL;
+ }
+
+ if (!S_ISDIR(*mode)) {
+ posix_acl_release(p);
+ *default_acl = NULL;
+ } else {
+ *default_acl = p;
+ }
+ return 0;
+
+apply_umask:
+ *mode &= ~current_umask();
+no_acl:
+ *default_acl = NULL;
+ *acl = NULL;
+ return 0;
+}
+
+int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage,
+ struct page *dpage)
{
- struct posix_acl *default_acl, *acl;
+ struct posix_acl *default_acl = NULL, *acl = NULL;
int error = 0;

- error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
+ error = f2fs_acl_create(dir, &inode->i_mode, &default_acl, &acl, dpage);
if (error)
return error;

diff --git a/fs/f2fs/acl.h b/fs/f2fs/acl.h
index e086465..997ca8e 100644
--- a/fs/f2fs/acl.h
+++ b/fs/f2fs/acl.h
@@ -38,14 +38,15 @@ struct f2fs_acl_header {

extern struct posix_acl *f2fs_get_acl(struct inode *, int);
extern int f2fs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
-extern int f2fs_init_acl(struct inode *, struct inode *, struct page *);
+extern int f2fs_init_acl(struct inode *, struct inode *, struct page *,
+ struct page *);
#else
#define f2fs_check_acl NULL
#define f2fs_get_acl NULL
#define f2fs_set_acl NULL

static inline int f2fs_init_acl(struct inode *inode, struct inode *dir,
- struct page *page)
+ struct page *ipage, struct page *dpage)
{
return 0;
}
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index 644b480..334e227 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -362,8 +362,8 @@ static int make_empty_dir(struct inode *inode,
return 0;
}

-struct page *init_inode_metadata(struct inode *inode,
- struct inode *dir, const struct qstr *name)
+struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
+ const struct qstr *name, struct page *dpage)
{
struct page *page;
int err;
@@ -379,7 +379,7 @@ struct page *init_inode_metadata(struct inode *inode,
goto error;
}

- err = f2fs_init_acl(inode, dir, page);
+ err = f2fs_init_acl(inode, dir, page, dpage);
if (err)
goto put_error;

@@ -540,7 +540,7 @@ add_dentry:
f2fs_wait_on_page_writeback(dentry_page, DATA);

down_write(&F2FS_I(inode)->i_sem);
- page = init_inode_metadata(inode, dir, name);
+ page = init_inode_metadata(inode, dir, name, NULL);
if (IS_ERR(page)) {
err = PTR_ERR(page);
goto fail;
@@ -579,7 +579,7 @@ int f2fs_do_tmpfile(struct inode *inode, struct inode *dir)
int err = 0;

down_write(&F2FS_I(inode)->i_sem);
- page = init_inode_metadata(inode, dir, NULL);
+ page = init_inode_metadata(inode, dir, NULL, NULL);
if (IS_ERR(page)) {
err = PTR_ERR(page);
goto fail;
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 6aad6e0..d4dcd93 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1247,7 +1247,7 @@ void set_de_type(struct f2fs_dir_entry *, struct inode *);
struct f2fs_dir_entry *find_target_dentry(struct qstr *, int *, const void *,
struct f2fs_dir_entry *, __u8 (*)[F2FS_SLOT_LEN]);
struct page *init_inode_metadata(struct inode *, struct inode *,
- const struct qstr *);
+ const struct qstr *, struct page *);
void update_parent_metadata(struct inode *, struct inode *, unsigned int);
int room_for_filename(const void *, int, int);
void f2fs_drop_nlink(struct inode *, struct inode *, struct page *);
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index 6fbdce7..3d44947 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -429,14 +429,14 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name,
goto out;
}

- f2fs_wait_on_page_writeback(ipage, NODE);
-
down_write(&F2FS_I(inode)->i_sem);
- page = init_inode_metadata(inode, dir, name);
+ page = init_inode_metadata(inode, dir, name, ipage);
if (IS_ERR(page)) {
err = PTR_ERR(page);
goto fail;
}
+
+ f2fs_wait_on_page_writeback(ipage, NODE);
de = &dentry_blk->dentry[bit_pos];
de->hash_code = name_hash;
de->name_len = cpu_to_le16(namelen);
diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
index deca872..5072bf9 100644
--- a/fs/f2fs/xattr.c
+++ b/fs/f2fs/xattr.c
@@ -83,7 +83,7 @@ static int f2fs_xattr_generic_get(struct dentry *dentry, const char *name,
}
if (strcmp(name, "") == 0)
return -EINVAL;
- return f2fs_getxattr(dentry->d_inode, type, name, buffer, size);
+ return f2fs_getxattr(dentry->d_inode, type, name, buffer, size, NULL);
}

static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name,
@@ -398,7 +398,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
}

int f2fs_getxattr(struct inode *inode, int index, const char *name,
- void *buffer, size_t buffer_size)
+ void *buffer, size_t buffer_size, struct page *ipage)
{
struct f2fs_xattr_entry *entry;
void *base_addr;
@@ -412,7 +412,7 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name,
if (len > F2FS_NAME_LEN)
return -ERANGE;

- base_addr = read_all_xattrs(inode, NULL);
+ base_addr = read_all_xattrs(inode, ipage);
if (!base_addr)
return -ENOMEM;

diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h
index 34ab7db..969d792 100644
--- a/fs/f2fs/xattr.h
+++ b/fs/f2fs/xattr.h
@@ -115,7 +115,8 @@ extern const struct xattr_handler *f2fs_xattr_handlers[];

extern int f2fs_setxattr(struct inode *, int, const char *,
const void *, size_t, struct page *, int);
-extern int f2fs_getxattr(struct inode *, int, const char *, void *, size_t);
+extern int f2fs_getxattr(struct inode *, int, const char *, void *,
+ size_t, struct page *);
extern ssize_t f2fs_listxattr(struct dentry *, char *, size_t);
#else

@@ -126,7 +127,8 @@ static inline int f2fs_setxattr(struct inode *inode, int index,
return -EOPNOTSUPP;
}
static inline int f2fs_getxattr(struct inode *inode, int index,
- const char *name, void *buffer, size_t buffer_size)
+ const char *name, void *buffer,
+ size_t buffer_size, struct page *dpage)
{
return -EOPNOTSUPP;
}
--
2.1.1
Jaegeuk Kim
2014-10-20 05:19:35 UTC
Permalink
This patch introduces a core function, f2fs_fill_dentries, to remove
redundant code in f2fs_readdir and f2fs_read_inline_dir.

Signed-off-by: Jaegeuk Kim <***@kernel.org>
---
fs/f2fs/dir.c | 64 +++++++++++++++++++++++++++++++++-----------------------
fs/f2fs/f2fs.h | 3 +++
fs/f2fs/inline.c | 39 +++++++---------------------------
3 files changed, 48 insertions(+), 58 deletions(-)

diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index 334e227..721d061 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -705,23 +705,50 @@ bool f2fs_empty_dir(struct inode *dir)
return true;
}

+bool f2fs_fill_dentries(struct dir_context *ctx,
+ const void *bitmap, struct f2fs_dir_entry *dentry,
+ __u8 (*filenames)[F2FS_SLOT_LEN], int max,
+ unsigned int start_pos)
+{
+ unsigned char d_type = DT_UNKNOWN;
+ unsigned int bit_pos;
+ struct f2fs_dir_entry *de = NULL;
+
+ bit_pos = ((unsigned long)ctx->pos % max);
+
+ while (bit_pos < max) {
+ bit_pos = find_next_bit_le(bitmap, max, bit_pos);
+ if (bit_pos >= max)
+ break;
+
+ de = &dentry[bit_pos];
+ if (de->file_type < F2FS_FT_MAX)
+ d_type = f2fs_filetype_table[de->file_type];
+ else
+ d_type = DT_UNKNOWN;
+ if (!dir_emit(ctx, filenames[bit_pos],
+ le16_to_cpu(de->name_len),
+ le32_to_cpu(de->ino), d_type))
+ return true;
+
+ bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
+ ctx->pos = start_pos + bit_pos;
+ }
+ return false;
+}
+
static int f2fs_readdir(struct file *file, struct dir_context *ctx)
{
struct inode *inode = file_inode(file);
unsigned long npages = dir_blocks(inode);
- unsigned int bit_pos = 0;
struct f2fs_dentry_block *dentry_blk = NULL;
- struct f2fs_dir_entry *de = NULL;
struct page *dentry_page = NULL;
struct file_ra_state *ra = &file->f_ra;
unsigned int n = ((unsigned long)ctx->pos / NR_DENTRY_IN_BLOCK);
- unsigned char d_type = DT_UNKNOWN;

if (f2fs_has_inline_dentry(inode))
return f2fs_read_inline_dir(file, ctx);

- bit_pos = ((unsigned long)ctx->pos % NR_DENTRY_IN_BLOCK);
-
/* readahead for multi pages of dir */
if (npages - n > 1 && !ra_has_index(ra, n))
page_cache_sync_readahead(inode->i_mapping, ra, file, n,
@@ -733,28 +760,13 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
continue;

dentry_blk = kmap(dentry_page);
- while (bit_pos < NR_DENTRY_IN_BLOCK) {
- bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
- NR_DENTRY_IN_BLOCK,
- bit_pos);
- if (bit_pos >= NR_DENTRY_IN_BLOCK)
- break;
-
- de = &dentry_blk->dentry[bit_pos];
- if (de->file_type < F2FS_FT_MAX)
- d_type = f2fs_filetype_table[de->file_type];
- else
- d_type = DT_UNKNOWN;
- if (!dir_emit(ctx,
- dentry_blk->filename[bit_pos],
- le16_to_cpu(de->name_len),
- le32_to_cpu(de->ino), d_type))
- goto stop;

- bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
- ctx->pos = n * NR_DENTRY_IN_BLOCK + bit_pos;
- }
- bit_pos = 0;
+ if (f2fs_fill_dentries(ctx,
+ &dentry_blk->dentry_bitmap, dentry_blk->dentry,
+ dentry_blk->filename,
+ NR_DENTRY_IN_BLOCK, n * NR_DENTRY_IN_BLOCK))
+ goto stop;
+
ctx->pos = (n + 1) * NR_DENTRY_IN_BLOCK;
kunmap(dentry_page);
f2fs_put_page(dentry_page, 1);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 9c4c8d1..3b0f490 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1247,6 +1247,9 @@ extern unsigned char f2fs_filetype_table[F2FS_FT_MAX];
void set_de_type(struct f2fs_dir_entry *, struct inode *);
struct f2fs_dir_entry *find_target_dentry(struct qstr *, int *, const void *,
struct f2fs_dir_entry *, __u8 (*)[F2FS_SLOT_LEN]);
+bool f2fs_fill_dentries(struct dir_context *,
+ const void *, struct f2fs_dir_entry *,
+ __u8 (*)[F2FS_SLOT_LEN], int, unsigned int);
struct page *init_inode_metadata(struct inode *, struct inode *,
const struct qstr *, struct page *);
void update_parent_metadata(struct inode *, struct inode *, unsigned int);
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index 633d5e8..403c8f7 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -519,49 +519,24 @@ bool f2fs_empty_inline_dir(struct inode *dir)
int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx)
{
struct inode *inode = file_inode(file);
- struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- unsigned int bit_pos = 0;
struct f2fs_inline_dentry *inline_dentry = NULL;
- struct f2fs_dir_entry *de = NULL;
struct page *ipage = NULL;
- unsigned char d_type = DT_UNKNOWN;

if (ctx->pos == NR_INLINE_DENTRY)
return 0;

- ipage = get_node_page(sbi, inode->i_ino);
+ ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino);
if (IS_ERR(ipage))
return PTR_ERR(ipage);

- bit_pos = ((unsigned long)ctx->pos % NR_INLINE_DENTRY);
-
inline_dentry = inline_data_addr(ipage);
- while (bit_pos < NR_INLINE_DENTRY) {
- bit_pos = find_next_bit_le(&inline_dentry->dentry_bitmap,
- NR_INLINE_DENTRY,
- bit_pos);
- if (bit_pos >= NR_INLINE_DENTRY)
- break;
-
- de = &inline_dentry->dentry[bit_pos];
- if (de->file_type < F2FS_FT_MAX)
- d_type = f2fs_filetype_table[de->file_type];
- else
- d_type = DT_UNKNOWN;
-
- if (!dir_emit(ctx,
- inline_dentry->filename[bit_pos],
- le16_to_cpu(de->name_len),
- le32_to_cpu(de->ino), d_type))
- goto out;
-
- bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
- ctx->pos = bit_pos;
- }

- ctx->pos = NR_INLINE_DENTRY;
-out:
- f2fs_put_page(ipage, 1);
+ if (!f2fs_fill_dentries(ctx, &inline_dentry->dentry_bitmap,
+ inline_dentry->dentry,
+ inline_dentry->filename,
+ NR_INLINE_DENTRY, 0))
+ ctx->pos = NR_INLINE_DENTRY;

+ f2fs_put_page(ipage, 1);
return 0;
}
--
2.1.1
Jaegeuk Kim
2014-10-20 05:19:36 UTC
Permalink
If the inode has inline_dentry, we should not truncate any block indices.

Signed-off-by: Jaegeuk Kim <***@kernel.org>
---
fs/f2fs/file.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index d054e0e..402e381 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -471,7 +471,7 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock)

trace_f2fs_truncate_blocks_enter(inode, from);

- if (f2fs_has_inline_data(inode))
+ if (f2fs_has_inline_data(inode) || f2fs_has_inline_dentry(inode))
goto done;

free_from = (pgoff_t)
--
2.1.1
Jaegeuk Kim
2014-10-20 05:19:33 UTC
Permalink
This patch adds status information for inline_dentry inodes.

Signed-off-by: Jaegeuk Kim <***@kernel.org>
---
fs/f2fs/debug.c | 3 +++
fs/f2fs/f2fs.h | 16 ++++++++++++++--
fs/f2fs/inline.c | 2 +-
fs/f2fs/inode.c | 3 +++
fs/f2fs/namei.c | 1 +
5 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
index 0a91ab8..86e6e92 100644
--- a/fs/f2fs/debug.c
+++ b/fs/f2fs/debug.c
@@ -46,6 +46,7 @@ static void update_general_status(struct f2fs_sb_info *sbi)
si->valid_node_count = valid_node_count(sbi);
si->valid_inode_count = valid_inode_count(sbi);
si->inline_inode = sbi->inline_inode;
+ si->inline_dir = sbi->inline_dir;
si->utilization = utilization(sbi);

si->free_segs = free_segments(sbi);
@@ -200,6 +201,8 @@ static int stat_show(struct seq_file *s, void *v)
si->valid_count - si->valid_node_count);
seq_printf(s, " - Inline_data Inode: %u\n",
si->inline_inode);
+ seq_printf(s, " - Inline_dentry Inode: %u\n",
+ si->inline_dir);
seq_printf(s, "\nMain area: %d segs, %d secs %d zones\n",
si->main_area_segs, si->main_area_sections,
si->main_area_zones);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index d4dcd93..9c4c8d1 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -560,6 +560,7 @@ struct f2fs_sb_info {
unsigned int block_count[2]; /* # of allocated blocks */
int total_hit_ext, read_hit_ext; /* extent cache hit ratio */
int inline_inode; /* # of inline_data inodes */
+ int inline_dir; /* # of inline_dentry inodes */
int bg_gc; /* background gc calls */
unsigned int n_dirty_dirs; /* # of dir inodes */
#endif
@@ -1434,7 +1435,7 @@ struct f2fs_stat_info {
int ndirty_node, ndirty_dent, ndirty_dirs, ndirty_meta;
int nats, sits, fnids;
int total_count, utilization;
- int bg_gc, inline_inode;
+ int bg_gc, inline_inode, inline_dir;
unsigned int valid_count, valid_node_count, valid_inode_count;
unsigned int bimodal, avg_vblocks;
int util_free, util_valid, util_invalid;
@@ -1474,7 +1475,16 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi)
if (f2fs_has_inline_data(inode)) \
((F2FS_I_SB(inode))->inline_inode--); \
} while (0)
-
+#define stat_inc_inline_dir(inode) \
+ do { \
+ if (f2fs_has_inline_dentry(inode)) \
+ ((F2FS_I_SB(inode))->inline_dir++); \
+ } while (0)
+#define stat_dec_inline_dir(inode) \
+ do { \
+ if (f2fs_has_inline_dentry(inode)) \
+ ((F2FS_I_SB(inode))->inline_dir--); \
+ } while (0)
#define stat_inc_seg_type(sbi, curseg) \
((sbi)->segment_count[(curseg)->alloc_type]++)
#define stat_inc_block_count(sbi, curseg) \
@@ -1521,6 +1531,8 @@ void f2fs_destroy_root_stats(void);
#define stat_inc_read_hit(sb)
#define stat_inc_inline_inode(inode)
#define stat_dec_inline_inode(inode)
+#define stat_inc_inline_dir(inode)
+#define stat_dec_inline_dir(inode)
#define stat_inc_seg_type(sbi, curseg)
#define stat_inc_block_count(sbi, curseg)
#define stat_inc_seg_count(si, type)
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index 3d44947..633d5e8 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -384,8 +384,8 @@ int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage,
/* clear inline dir and flag after data writeback */
zero_user_segment(ipage, INLINE_DATA_OFFSET,
INLINE_DATA_OFFSET + MAX_INLINE_DATA);
+ stat_dec_inline_dir(dir);
clear_inode_flag(F2FS_I(dir), FI_INLINE_DENTRY);
- stat_dec_inline_inode(dir);

if (i_size_read(dir) < PAGE_CACHE_SIZE) {
i_size_write(dir, PAGE_CACHE_SIZE);
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 52d6f54..b9b1d6b 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -169,6 +169,7 @@ make_now:
goto bad_inode;
}
unlock_new_inode(inode);
+ stat_inc_inline_dir(inode);
trace_f2fs_iget(inode);
return inode;

@@ -300,6 +301,7 @@ void f2fs_evict_inode(struct inode *inode)

sb_end_intwrite(inode->i_sb);
no_delete:
+ stat_dec_inline_dir(inode);
invalidate_mapping_pages(NODE_MAPPING(sbi), inode->i_ino, inode->i_ino);
if (xnid)
invalidate_mapping_pages(NODE_MAPPING(sbi), xnid, xnid);
@@ -327,6 +329,7 @@ void handle_failed_inode(struct inode *inode)
remove_inode_page(inode);
stat_dec_inline_inode(inode);

+ clear_inode_flag(F2FS_I(inode), FI_INLINE_DENTRY);
alloc_nid_failed(sbi, inode->i_ino);
f2fs_unlock_op(sbi);

diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index c8290da..94ba291 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -297,6 +297,7 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
goto out_fail;
f2fs_unlock_op(sbi);

+ stat_inc_inline_dir(inode);
alloc_nid_done(sbi, inode->i_ino);

d_instantiate(dentry, inode);
--
2.1.1
Jaegeuk Kim
2014-10-20 05:19:34 UTC
Permalink
This patch fixes wrongly counting inline_data inode numbers.

Signed-off-by: Jaegeuk Kim <***@kernel.org>
---
fs/f2fs/inode.c | 4 ++--
fs/f2fs/namei.c | 2 --
2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index b9b1d6b..4131e3c 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -169,6 +169,7 @@ make_now:
goto bad_inode;
}
unlock_new_inode(inode);
+ stat_inc_inline_inode(inode);
stat_inc_inline_dir(inode);
trace_f2fs_iget(inode);
return inode;
@@ -296,12 +297,12 @@ void f2fs_evict_inode(struct inode *inode)

f2fs_lock_op(sbi);
remove_inode_page(inode);
- stat_dec_inline_inode(inode);
f2fs_unlock_op(sbi);

sb_end_intwrite(inode->i_sb);
no_delete:
stat_dec_inline_dir(inode);
+ stat_dec_inline_inode(inode);
invalidate_mapping_pages(NODE_MAPPING(sbi), inode->i_ino, inode->i_ino);
if (xnid)
invalidate_mapping_pages(NODE_MAPPING(sbi), xnid, xnid);
@@ -327,7 +328,6 @@ void handle_failed_inode(struct inode *inode)
f2fs_truncate(inode);

remove_inode_page(inode);
- stat_dec_inline_inode(inode);

clear_inode_flag(F2FS_I(inode), FI_INLINE_DENTRY);
alloc_nid_failed(sbi, inode->i_ino);
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index 94ba291..a004a97 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -198,8 +198,6 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
inode = f2fs_iget(dir->i_sb, ino);
if (IS_ERR(inode))
return ERR_CAST(inode);
-
- stat_inc_inline_inode(inode);
}

return d_splice_alias(inode, dentry);
--
2.1.1
Jaegeuk Kim
2014-10-20 05:19:38 UTC
Permalink
This patch introduces do_make_empty_dir to mitigate code redundancy
for inline_dentry.

Signed-off-by: Jaegeuk Kim <***@kernel.org>
---
fs/f2fs/dir.c | 42 ++++++++++++++++++++++++++----------------
fs/f2fs/f2fs.h | 2 ++
fs/f2fs/inline.c | 20 +++-----------------
3 files changed, 31 insertions(+), 33 deletions(-)

diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index 80665ce..b751f94 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -322,12 +322,35 @@ int update_dent_inode(struct inode *inode, const struct qstr *name)
return 0;
}

+void do_make_empty_dir(struct inode *inode, struct inode *parent,
+ struct f2fs_dentry_ptr *d)
+{
+ struct f2fs_dir_entry *de;
+
+ de = &d->dentry[0];
+ de->name_len = cpu_to_le16(1);
+ de->hash_code = 0;
+ de->ino = cpu_to_le32(inode->i_ino);
+ memcpy(d->filename[0], ".", 1);
+ set_de_type(de, inode);
+
+ de = &d->dentry[1];
+ de->hash_code = 0;
+ de->name_len = cpu_to_le16(2);
+ de->ino = cpu_to_le32(parent->i_ino);
+ memcpy(d->filename[1], "..", 2);
+ set_de_type(de, inode);
+
+ test_and_set_bit_le(0, (void *)d->bitmap);
+ test_and_set_bit_le(1, (void *)d->bitmap);
+}
+
static int make_empty_dir(struct inode *inode,
struct inode *parent, struct page *page)
{
struct page *dentry_page;
struct f2fs_dentry_block *dentry_blk;
- struct f2fs_dir_entry *de;
+ struct f2fs_dentry_ptr d;

if (f2fs_has_inline_dentry(inode))
return make_empty_inline_dir(inode, parent, page);
@@ -338,22 +361,9 @@ static int make_empty_dir(struct inode *inode,

dentry_blk = kmap_atomic(dentry_page);

- de = &dentry_blk->dentry[0];
- de->name_len = cpu_to_le16(1);
- de->hash_code = 0;
- de->ino = cpu_to_le32(inode->i_ino);
- memcpy(dentry_blk->filename[0], ".", 1);
- set_de_type(de, inode);
-
- de = &dentry_blk->dentry[1];
- de->hash_code = 0;
- de->name_len = cpu_to_le16(2);
- de->ino = cpu_to_le32(parent->i_ino);
- memcpy(dentry_blk->filename[1], "..", 2);
- set_de_type(de, inode);
+ make_dentry_ptr(&d, dentry_blk, NULL, 1);
+ do_make_empty_dir(inode, parent, &d);

- test_and_set_bit_le(0, &dentry_blk->dentry_bitmap);
- test_and_set_bit_le(1, &dentry_blk->dentry_bitmap);
kunmap_atomic(dentry_blk);

set_page_dirty(dentry_page);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 0856a38..267d54e 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1274,6 +1274,8 @@ struct f2fs_dir_entry *find_target_dentry(struct qstr *, int *,
struct f2fs_dentry_ptr *);
bool f2fs_fill_dentries(struct dir_context *, struct f2fs_dentry_ptr *,
unsigned int);
+void do_make_empty_dir(struct inode *, struct inode *,
+ struct f2fs_dentry_ptr *);
struct page *init_inode_metadata(struct inode *, struct inode *,
const struct qstr *, struct page *);
void update_parent_metadata(struct inode *, struct inode *, unsigned int);
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index edacfa1..825995f 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -314,26 +314,12 @@ int make_empty_inline_dir(struct inode *inode, struct inode *parent,
struct page *ipage)
{
struct f2fs_inline_dentry *dentry_blk;
- struct f2fs_dir_entry *de;
+ struct f2fs_dentry_ptr d;

dentry_blk = inline_data_addr(ipage);

- de = &dentry_blk->dentry[0];
- de->name_len = cpu_to_le16(1);
- de->hash_code = 0;
- de->ino = cpu_to_le32(inode->i_ino);
- memcpy(dentry_blk->filename[0], ".", 1);
- set_de_type(de, inode);
-
- de = &dentry_blk->dentry[1];
- de->hash_code = 0;
- de->name_len = cpu_to_le16(2);
- de->ino = cpu_to_le32(parent->i_ino);
- memcpy(dentry_blk->filename[1], "..", 2);
- set_de_type(de, inode);
-
- test_and_set_bit_le(0, &dentry_blk->dentry_bitmap);
- test_and_set_bit_le(1, &dentry_blk->dentry_bitmap);
+ make_dentry_ptr(&d, NULL, dentry_blk, 2);
+ do_make_empty_dir(inode, parent, &d);

set_page_dirty(ipage);
--
2.1.1
Jaegeuk Kim
2014-10-20 05:19:39 UTC
Permalink
For better performance, we need to use kmap_atomic instead of kmap.

Signed-off-by: Jaegeuk Kim <***@kernel.org>
---
fs/f2fs/inline.c | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index 825995f..c03653d 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -55,11 +55,10 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page)

/* Copy the whole inline data block */
src_addr = inline_data_addr(ipage);
- dst_addr = kmap(page);
+ dst_addr = kmap_atomic(page);
memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
- kunmap(page);
+ kunmap_atomic(dst_addr);
f2fs_put_page(ipage, 1);
-
out:
SetPageUptodate(page);
unlock_page(page);
@@ -105,9 +104,9 @@ static int __f2fs_convert_inline_data(struct inode *inode, struct page *page)

/* Copy the whole inline data block */
src_addr = inline_data_addr(ipage);
- dst_addr = kmap(page);
+ dst_addr = kmap_atomic(page);
memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
- kunmap(page);
+ kunmap_atomic(dst_addr);
SetPageUptodate(page);

/* write data page to try to make data consistent */
@@ -177,10 +176,10 @@ int f2fs_write_inline_data(struct inode *inode,
f2fs_wait_on_page_writeback(ipage, NODE);
zero_user_segment(ipage, INLINE_DATA_OFFSET,
INLINE_DATA_OFFSET + MAX_INLINE_DATA);
- src_addr = kmap(page);
+ src_addr = kmap_atomic(page);
dst_addr = inline_data_addr(ipage);
memcpy(dst_addr, src_addr, size);
- kunmap(page);
+ kunmap_atomic(src_addr);

set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE);
sync_inode_page(&dn);
@@ -351,7 +350,7 @@ int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage,
f2fs_wait_on_page_writeback(page, DATA);
zero_user_segment(page, 0, PAGE_CACHE_SIZE);

- dentry_blk = kmap(page);
+ dentry_blk = kmap_atomic(page);

/* copy data from inline dentry block to new dentry block */
memcpy(dentry_blk->dentry_bitmap, inline_dentry->dentry_bitmap,
@@ -363,7 +362,7 @@ int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage,
memcpy(dentry_blk->filename, inline_dentry->filename,
NR_INLINE_DENTRY * F2FS_SLOT_LEN);

- kunmap(page);
+ kunmap_atomic(dentry_blk);
SetPageUptodate(page);
set_page_dirty(page);
--
2.1.1
Jaegeuk Kim
2014-10-20 05:19:37 UTC
Permalink
This patch introduces f2fs_dentry_ptr structure for the use of a function
parameter in inline_dentry operations.

Signed-off-by: Jaegeuk Kim <***@kernel.org>
---
fs/f2fs/dir.c | 61 +++++++++++++++++++++++++++-----------------------------
fs/f2fs/f2fs.h | 34 ++++++++++++++++++++++++++-----
fs/f2fs/inline.c | 18 ++++++++---------
3 files changed, 67 insertions(+), 46 deletions(-)

diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index 721d061..80665ce 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -95,13 +95,13 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page,
{
struct f2fs_dentry_block *dentry_blk;
struct f2fs_dir_entry *de;
-
- *max_slots = NR_DENTRY_IN_BLOCK;
+ struct f2fs_dentry_ptr d;

dentry_blk = (struct f2fs_dentry_block *)kmap(dentry_page);
- de = find_target_dentry(name, max_slots, &dentry_blk->dentry_bitmap,
- dentry_blk->dentry,
- dentry_blk->filename);
+
+ make_dentry_ptr(&d, dentry_blk, NULL, 1);
+ de = find_target_dentry(name, max_slots, &d);
+
kunmap(dentry_page);
if (de)
*res_page = dentry_page;
@@ -110,50 +110,49 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page,
* For the most part, it should be a bug when name_len is zero.
* We stop here for figuring out where the bugs has occurred.
*/
- f2fs_bug_on(F2FS_P_SB(dentry_page), *max_slots < 0);
+ f2fs_bug_on(F2FS_P_SB(dentry_page), d.max < 0);
return de;
}

struct f2fs_dir_entry *find_target_dentry(struct qstr *name, int *max_slots,
- const void *bitmap, struct f2fs_dir_entry *dentry,
- __u8 (*filenames)[F2FS_SLOT_LEN])
+ struct f2fs_dentry_ptr *d)
{
struct f2fs_dir_entry *de;
unsigned long bit_pos = 0;
f2fs_hash_t namehash = f2fs_dentry_hash(name);
- int max_bits = *max_slots;
int max_len = 0;

- *max_slots = 0;
- while (bit_pos < max_bits) {
- if (!test_bit_le(bit_pos, bitmap)) {
+ if (max_slots)
+ *max_slots = 0;
+ while (bit_pos < d->max) {
+ if (!test_bit_le(bit_pos, d->bitmap)) {
if (bit_pos == 0)
max_len = 1;
- else if (!test_bit_le(bit_pos - 1, bitmap))
+ else if (!test_bit_le(bit_pos - 1, d->bitmap))
max_len++;
bit_pos++;
continue;
}
- de = &dentry[bit_pos];
+ de = &d->dentry[bit_pos];
if (early_match_name(name->len, namehash, de) &&
- !memcmp(filenames[bit_pos], name->name, name->len))
+ !memcmp(d->filename[bit_pos], name->name, name->len))
goto found;

- if (*max_slots >= 0 && max_len > *max_slots) {
+ if (max_slots && *max_slots >= 0 && max_len > *max_slots) {
*max_slots = max_len;
max_len = 0;
}

/* remain bug on condition */
if (unlikely(!de->name_len))
- *max_slots = -1;
+ d->max = -1;

bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
}

de = NULL;
found:
- if (max_len > *max_slots)
+ if (max_slots && max_len > *max_slots)
*max_slots = max_len;
return de;
}
@@ -705,28 +704,26 @@ bool f2fs_empty_dir(struct inode *dir)
return true;
}

-bool f2fs_fill_dentries(struct dir_context *ctx,
- const void *bitmap, struct f2fs_dir_entry *dentry,
- __u8 (*filenames)[F2FS_SLOT_LEN], int max,
- unsigned int start_pos)
+bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
+ unsigned int start_pos)
{
unsigned char d_type = DT_UNKNOWN;
unsigned int bit_pos;
struct f2fs_dir_entry *de = NULL;

- bit_pos = ((unsigned long)ctx->pos % max);
+ bit_pos = ((unsigned long)ctx->pos % d->max);

- while (bit_pos < max) {
- bit_pos = find_next_bit_le(bitmap, max, bit_pos);
- if (bit_pos >= max)
+ while (bit_pos < d->max) {
+ bit_pos = find_next_bit_le(d->bitmap, d->max, bit_pos);
+ if (bit_pos >= d->max)
break;

- de = &dentry[bit_pos];
+ de = &d->dentry[bit_pos];
if (de->file_type < F2FS_FT_MAX)
d_type = f2fs_filetype_table[de->file_type];
else
d_type = DT_UNKNOWN;
- if (!dir_emit(ctx, filenames[bit_pos],
+ if (!dir_emit(ctx, d->filename[bit_pos],
le16_to_cpu(de->name_len),
le32_to_cpu(de->ino), d_type))
return true;
@@ -745,6 +742,7 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
struct page *dentry_page = NULL;
struct file_ra_state *ra = &file->f_ra;
unsigned int n = ((unsigned long)ctx->pos / NR_DENTRY_IN_BLOCK);
+ struct f2fs_dentry_ptr d;

if (f2fs_has_inline_dentry(inode))
return f2fs_read_inline_dir(file, ctx);
@@ -761,10 +759,9 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)

dentry_blk = kmap(dentry_page);

- if (f2fs_fill_dentries(ctx,
- &dentry_blk->dentry_bitmap, dentry_blk->dentry,
- dentry_blk->filename,
- NR_DENTRY_IN_BLOCK, n * NR_DENTRY_IN_BLOCK))
+ make_dentry_ptr(&d, dentry_blk, NULL, 1);
+
+ if (f2fs_fill_dentries(ctx, &d, n * NR_DENTRY_IN_BLOCK))
goto stop;

ctx->pos = (n + 1) * NR_DENTRY_IN_BLOCK;
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 3b0f490..0856a38 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -212,6 +212,31 @@ static inline bool __has_cursum_space(struct f2fs_summary_block *sum, int size,
/*
* For INODE and NODE manager
*/
+/* for directory operations */
+struct f2fs_dentry_ptr {
+ const void *bitmap;
+ struct f2fs_dir_entry *dentry;
+ __u8 (*filename)[F2FS_SLOT_LEN];
+ int max;
+};
+
+static inline void make_dentry_ptr(struct f2fs_dentry_ptr *d,
+ struct f2fs_dentry_block *d1,
+ struct f2fs_inline_dentry *d2, int type)
+{
+ if (type == 1) {
+ d->max = NR_DENTRY_IN_BLOCK;
+ d->bitmap = &d1->dentry_bitmap;
+ d->dentry = d1->dentry;
+ d->filename = d1->filename;
+ } else {
+ d->max = NR_INLINE_DENTRY;
+ d->bitmap = &d2->dentry_bitmap;
+ d->dentry = d2->dentry;
+ d->filename = d2->filename;
+ }
+}
+
/*
* XATTR_NODE_OFFSET stores xattrs to one node block per file keeping -1
* as its node offset to distinguish from index node blocks.
@@ -1245,11 +1270,10 @@ struct dentry *f2fs_get_parent(struct dentry *child);
*/
extern unsigned char f2fs_filetype_table[F2FS_FT_MAX];
void set_de_type(struct f2fs_dir_entry *, struct inode *);
-struct f2fs_dir_entry *find_target_dentry(struct qstr *, int *, const void *,
- struct f2fs_dir_entry *, __u8 (*)[F2FS_SLOT_LEN]);
-bool f2fs_fill_dentries(struct dir_context *,
- const void *, struct f2fs_dir_entry *,
- __u8 (*)[F2FS_SLOT_LEN], int, unsigned int);
+struct f2fs_dir_entry *find_target_dentry(struct qstr *, int *,
+ struct f2fs_dentry_ptr *);
+bool f2fs_fill_dentries(struct dir_context *, struct f2fs_dentry_ptr *,
+ unsigned int);
struct page *init_inode_metadata(struct inode *, struct inode *,
const struct qstr *, struct page *);
void update_parent_metadata(struct inode *, struct inode *, unsigned int);
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index 403c8f7..edacfa1 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -265,8 +265,8 @@ struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir,
struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
struct f2fs_inline_dentry *inline_dentry;
struct f2fs_dir_entry *de;
+ struct f2fs_dentry_ptr d;
struct page *ipage;
- int max_slots = NR_INLINE_DENTRY;

ipage = get_node_page(sbi, dir->i_ino);
if (IS_ERR(ipage))
@@ -274,9 +274,9 @@ struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir,

inline_dentry = inline_data_addr(ipage);

- de = find_target_dentry(name, &max_slots, &inline_dentry->dentry_bitmap,
- inline_dentry->dentry,
- inline_dentry->filename);
+ make_dentry_ptr(&d, NULL, inline_dentry, 2);
+ de = find_target_dentry(name, NULL, &d);
+
unlock_page(ipage);
if (de)
*res_page = ipage;
@@ -287,7 +287,7 @@ struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir,
* For the most part, it should be a bug when name_len is zero.
* We stop here for figuring out where the bugs has occurred.
*/
- f2fs_bug_on(sbi, max_slots < 0);
+ f2fs_bug_on(sbi, d.max < 0);
return de;
}

@@ -521,6 +521,7 @@ int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx)
struct inode *inode = file_inode(file);
struct f2fs_inline_dentry *inline_dentry = NULL;
struct page *ipage = NULL;
+ struct f2fs_dentry_ptr d;

if (ctx->pos == NR_INLINE_DENTRY)
return 0;
@@ -531,10 +532,9 @@ int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx)

inline_dentry = inline_data_addr(ipage);

- if (!f2fs_fill_dentries(ctx, &inline_dentry->dentry_bitmap,
- inline_dentry->dentry,
- inline_dentry->filename,
- NR_INLINE_DENTRY, 0))
+ make_dentry_ptr(&d, NULL, inline_dentry, 2);
+
+ if (!f2fs_fill_dentries(ctx, &d, 0))
ctx->pos = NR_INLINE_DENTRY;

f2fs_put_page(ipage, 1);
--
2.1.1
Loading...