[f2fs-dev] [PATCH 02/09] f2fs: invalidate inmemory page
If user truncates file's data, we should truncate inmemory pages too. Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c| 3 +++ fs/f2fs/f2fs.h| 1 + fs/f2fs/segment.c | 16 3 files changed, 20 insertions(+) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 84f20e9..5b80ada 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1116,6 +1116,9 @@ static void f2fs_invalidate_data_page(struct page *page, unsigned int offset, if (offset % PAGE_CACHE_SIZE || length != PAGE_CACHE_SIZE) return; + if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode)) + invalidate_inmem_page(inode, page); + if (PageDirty(page)) inode_dec_dirty_pages(inode); ClearPagePrivate(page); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 28f24ea..d41d1b7 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1297,6 +1297,7 @@ void destroy_node_manager_caches(void); * segment.c */ void register_inmem_page(struct inode *, struct page *); +void invalidate_inmem_page(struct inode *, struct page *); void commit_inmem_pages(struct inode *, bool); void f2fs_balance_fs(struct f2fs_sb_info *); void f2fs_balance_fs_bg(struct f2fs_sb_info *); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 9d4a7ab..902c4c3 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -203,6 +203,22 @@ retry: mutex_unlock(&fi->inmem_lock); } +void invalidate_inmem_page(struct inode *inode, struct page *page) +{ + struct f2fs_inode_info *fi = F2FS_I(inode); + struct inmem_pages *cur; + + mutex_lock(&fi->inmem_lock); + cur = radix_tree_lookup(&fi->inmem_root, page->index); + if (cur) { + radix_tree_delete(&fi->inmem_root, cur->page->index); + f2fs_put_page(cur->page, 0); + list_del(&cur->list); + kmem_cache_free(inmem_entry_slab, cur); + } + mutex_unlock(&fi->inmem_lock); +} + void commit_inmem_pages(struct inode *inode, bool abort) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); -- 2.1.1 -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://p.sf.net/sfu/Zoho ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH 05/09] f2fs: use highmem for directory pages
This patch fixes to use highmem for directory pages. Signed-off-by: Jaegeuk Kim --- fs/f2fs/inode.c | 2 +- include/linux/f2fs_fs.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 0deead4..52d6f54 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -156,7 +156,7 @@ make_now: inode->i_op = &f2fs_dir_inode_operations; inode->i_fop = &f2fs_dir_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; - mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO); + mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_HIGH_ZERO); } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &f2fs_symlink_inode_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index 860313a..6d7381b 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -33,7 +33,8 @@ #define F2FS_META_INO(sbi) (sbi->meta_ino_num) /* This flag is used by node and meta inodes, and by recovery */ -#define GFP_F2FS_ZERO (GFP_NOFS | __GFP_ZERO) +#define GFP_F2FS_ZERO (GFP_NOFS | __GFP_ZERO) +#define GFP_F2FS_HIGH_ZERO (GFP_NOFS | __GFP_ZERO | __GFP_HIGHMEM) /* * For further optimization on multi-head logs, on-disk layout supports maximum -- 2.1.1 -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://p.sf.net/sfu/Zoho ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH 08/09] f2fs: avoid build warning
This patch removes build warning. Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 902c4c3..2c1e608 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1715,7 +1715,7 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) * #2, flush sit entries to sit page. */ list_for_each_entry_safe(ses, tmp, head, set_list) { - struct page *page; + struct page *page = NULL; struct f2fs_sit_block *raw_sit = NULL; unsigned int start_segno = ses->start_segno; unsigned int end = min(start_segno + SIT_ENTRY_PER_BLOCK, -- 2.1.1 -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://p.sf.net/sfu/Zoho ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH 07/09] f2fs: fix to call f2fs_unlock_op
This patch fixes to call f2fs_unlock_op, which was missing before. Signed-off-by: Jaegeuk Kim --- fs/f2fs/file.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 456df07..80d9a04 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -494,7 +494,7 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock) /* writepage can convert inline_data under get_donde_of_data */ if (f2fs_has_inline_data(inode)) { f2fs_put_dnode(&dn); - goto done; + goto unlock_done; } count = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode)); @@ -510,6 +510,7 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock) f2fs_put_dnode(&dn); free_next: err = truncate_inode_blocks(inode, free_from); +unlock_done: if (lock) f2fs_unlock_op(sbi); done: -- 2.1.1 -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://p.sf.net/sfu/Zoho ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH 01/09] f2fs: do not make dirty any inmemory pages
This patch let inmemory pages be clean all the time. Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c| 11 +++ fs/f2fs/f2fs.h| 1 + fs/f2fs/segment.c | 14 +- fs/f2fs/super.c | 1 + 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 8e58c4c..84f20e9 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1052,10 +1052,7 @@ static int f2fs_write_end(struct file *file, trace_f2fs_write_end(inode, pos, len, copied); - if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode)) - register_inmem_page(inode, page); - else - set_page_dirty(page); + set_page_dirty(page); if (pos + copied > i_size_read(inode)) { i_size_write(inode, pos + copied); @@ -1138,6 +1135,12 @@ static int f2fs_set_data_page_dirty(struct page *page) trace_f2fs_set_page_dirty(page, DATA); SetPageUptodate(page); + + if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode)) { + register_inmem_page(inode, page); + return 1; + } + mark_inode_dirty(inode); if (!PageDirty(page)) { diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 8171e80..28f24ea 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -269,6 +269,7 @@ struct f2fs_inode_info { struct extent_info ext; /* in-memory extent cache entry */ struct dir_inode_entry *dirty_dir; /* the pointer of dirty dir */ + struct radix_tree_root inmem_root; /* radix tree for inmem pages */ struct list_head inmem_pages; /* inmemory pages managed by f2fs */ struct mutex inmem_lock;/* lock for inmemory pages */ }; diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 923cb76..9d4a7ab 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -178,7 +178,8 @@ void register_inmem_page(struct inode *inode, struct page *page) { struct f2fs_inode_info *fi = F2FS_I(inode); struct inmem_pages *new; - + int err; +retry: new = f2fs_kmem_cache_alloc(inmem_entry_slab, GFP_NOFS); /* add atomic page indices to the list */ @@ -187,6 +188,16 @@ void register_inmem_page(struct inode *inode, struct page *page) /* increase reference count with clean state */ mutex_lock(&fi->inmem_lock); + err = radix_tree_insert(&fi->inmem_root, page->index, new); + if (err == -EEXIST) { + mutex_unlock(&fi->inmem_lock); + kmem_cache_free(inmem_entry_slab, new); + return; + } else if (err) { + mutex_unlock(&fi->inmem_lock); + kmem_cache_free(inmem_entry_slab, new); + goto retry; + } get_page(page); list_add_tail(&new->list, &fi->inmem_pages); mutex_unlock(&fi->inmem_lock); @@ -216,6 +227,7 @@ void commit_inmem_pages(struct inode *inode, bool abort) do_write_data_page(cur->page, &fio); submit_bio = true; } + radix_tree_delete(&fi->inmem_root, cur->page->index); f2fs_put_page(cur->page, 1); list_del(&cur->list); kmem_cache_free(inmem_entry_slab, cur); diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 41d6f70..76b14c8 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -373,6 +373,7 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) fi->i_advise = 0; rwlock_init(&fi->ext.ext_lock); init_rwsem(&fi->i_sem); + INIT_RADIX_TREE(&fi->inmem_root, GFP_NOFS); INIT_LIST_HEAD(&fi->inmem_pages); mutex_init(&fi->inmem_lock); -- 2.1.1 -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://p.sf.net/sfu/Zoho ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH 03/09] f2fs: should truncate any allocated block for inline_data write
When trying to write inline_data, we should truncate any data block allocated and pointed by the inode block. We should consider the data index is not 0. Signed-off-by: Jaegeuk Kim --- fs/f2fs/inline.c | 15 --- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index 88036fd..e3abcfb 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c @@ -166,6 +166,14 @@ int f2fs_write_inline_data(struct inode *inode, return err; ipage = dn.inode_page; + /* Release any data block if it is allocated */ + if (!f2fs_has_inline_data(inode)) { + int count = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode)); + truncate_data_blocks_range(&dn, count); + set_inode_flag(F2FS_I(inode), FI_INLINE_DATA); + stat_inc_inline_inode(inode); + } + f2fs_wait_on_page_writeback(ipage, NODE); zero_user_segment(ipage, INLINE_DATA_OFFSET, INLINE_DATA_OFFSET + MAX_INLINE_DATA); @@ -174,13 +182,6 @@ int f2fs_write_inline_data(struct inode *inode, memcpy(dst_addr, src_addr, size); kunmap(page); - /* Release the first data block if it is allocated */ - if (!f2fs_has_inline_data(inode)) { - truncate_data_blocks_range(&dn, 1); - set_inode_flag(F2FS_I(inode), FI_INLINE_DATA); - stat_inc_inline_inode(inode); - } - set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE); sync_inode_page(&dn); f2fs_put_dnode(&dn); -- 2.1.1 -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://p.sf.net/sfu/Zoho ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH 06/09] f2fs: avoid to allocate when inline_data was written
The sceanrio is like this. inline_data i_size page write_begin/vm_page_mkwrite X 30 dirty_page X 30write to #4096 position X 30 get_dnode_of_datawait for get_dnode_of_data O 30 write inline_data O 30get_dnode_of_data O 30reserve data block .. In this case, we have #0 = NEW_ADDR and inline_data as well. We should not allow this condition for further access. Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 32 +++- fs/f2fs/file.c | 26 ++ 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 5b80ada..973fd77 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -257,9 +257,6 @@ int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index) bool need_put = dn->inode_page ? false : true; int err; - /* if inode_page exists, index should be zero */ - f2fs_bug_on(F2FS_I_SB(dn->inode), !need_put && index); - err = get_dnode_of_data(dn, index, ALLOC_NODE); if (err) return err; @@ -951,7 +948,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, { struct inode *inode = mapping->host; struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - struct page *page; + struct page *page, *ipage; pgoff_t index = ((unsigned long long) pos) >> PAGE_CACHE_SHIFT; struct dnode_of_data dn; int err = 0; @@ -979,13 +976,26 @@ repeat: goto inline_data; f2fs_lock_op(sbi); - set_new_dnode(&dn, inode, NULL, NULL, 0); - err = f2fs_reserve_block(&dn, index); - f2fs_unlock_op(sbi); - if (err) { + + /* check inline_data */ + ipage = get_node_page(sbi, inode->i_ino); + if (IS_ERR(ipage)) + goto unlock_fail; + + if (f2fs_has_inline_data(inode)) { + f2fs_put_page(ipage, 1); + f2fs_unlock_op(sbi); f2fs_put_page(page, 0); - goto fail; + goto repeat; } + + set_new_dnode(&dn, inode, ipage, NULL, 0); + err = f2fs_reserve_block(&dn, index); + if (err) + goto unlock_fail; + f2fs_put_dnode(&dn); + f2fs_unlock_op(sbi); + inline_data: lock_page(page); if (unlikely(page->mapping != mapping)) { @@ -1038,6 +1048,10 @@ out: SetPageUptodate(page); clear_cold_data(page); return 0; + +unlock_fail: + f2fs_unlock_op(sbi); + f2fs_put_page(page, 0); fail: f2fs_write_failed(mapping, pos + len); return err; diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 543d8c6..456df07 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -35,12 +35,13 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, struct inode *inode = file_inode(vma->vm_file); struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct dnode_of_data dn; + struct page *ipage; int err; f2fs_balance_fs(sbi); sb_start_pagefault(inode->i_sb); - +retry: /* force to convert with normal data indices */ err = f2fs_convert_inline_data(inode, MAX_INLINE_DATA + 1, page); if (err) @@ -48,11 +49,28 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, /* block allocation */ f2fs_lock_op(sbi); - set_new_dnode(&dn, inode, NULL, NULL, 0); + + /* check inline_data */ + ipage = get_node_page(sbi, inode->i_ino); + if (IS_ERR(ipage)) { + f2fs_unlock_op(sbi); + goto out; + } + + if (f2fs_has_inline_data(inode)) { + f2fs_put_page(ipage, 1); + f2fs_unlock_op(sbi); + goto retry; + } + + set_new_dnode(&dn, inode, ipage, NULL, 0); err = f2fs_reserve_block(&dn, page->index); - f2fs_unlock_op(sbi); - if (err) + if (err) { + f2fs_unlock_op(sbi); goto out; + } + f2fs_put_dnode(&dn); + f2fs_unlock_op(sbi); file_update_time(vma->vm_file); lock_page(page); -- 2.1.1 -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://p.sf.net/sfu/Zoho ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH 04/09] f2fs: fix race conditon on truncation with inline_data
Let's consider the following scenario. blkaddr[0] inline_data i_size i_blocks writepage truncate NEWX40962dirty page #0 NEWX 0change i_size NEWX 0 2f2fs_write_inline_data NEWX 0 2get_dnode_of_data NEWX 0 2truncate_data_blocks_range NULL O 0 1memcpy(inline_data) NULL O 0 1f2fs_put_dnode NULL O 0 1 f2fs_truncate NULL O 0 1 get_dnode_of_data NULL O 0 1 *invalid block addr* This patch adds checking inline_data flag during f2fs_truncate not to refer corrupted block indices. Signed-off-by: Jaegeuk Kim --- fs/f2fs/file.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 8e68bb6..543d8c6 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -473,6 +473,12 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock) return err; } + /* writepage can convert inline_data under get_donde_of_data */ + if (f2fs_has_inline_data(inode)) { + f2fs_put_dnode(&dn); + goto done; + } + count = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode)); count -= dn.ofs_in_node; -- 2.1.1 -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://p.sf.net/sfu/Zoho ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH 09/09] f2fs: avoid infinite loop at cp_error
This patch avoids an infinite loop in sync_dirty_inode_page when -EIO was detected. Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index dd10a03..ca514d5 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -731,6 +731,9 @@ void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi) struct dir_inode_entry *entry; struct inode *inode; retry: + if (unlikely(f2fs_cp_error(sbi))) + return; + spin_lock(&sbi->dir_inode_lock); head = &sbi->dir_inode_list; -- 2.1.1 -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://p.sf.net/sfu/Zoho ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH 02/11] f2fs: reuse find_in_block code for find_in_inline_dir
This patch removes redundant copied code in find_in_inline_dir. Signed-off-by: Jaegeuk Kim --- 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; } -
[f2fs-dev] [PATCH 09/11] f2fs: introduce f2fs_dentry_ptr structure for code clean-up
This patch introduces f2fs_dentry_ptr structure for the use of a function parameter in inline_dentry operations. Signed-off-by: Jaegeuk Kim --- 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; -
[f2fs-dev] [PATCH 03/11] f2fs: fix to wait correct block type
The inode page needs to wait NODE block io. Signed-off-by: Jaegeuk Kim --- 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 -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://p.sf.net/sfu/Zoho ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH 10/11] f2fs: reuse make_empty_dir code for inline_dentry
This patch introduces do_make_empty_dir to mitigate code redundancy for inline_dentry. Signed-off-by: Jaegeuk Kim --- 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 -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://p.sf.net/sfu/Zoho ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH 11/11] f2fs: use kmap_atomic instead of kmap
For better performance, we need to use kmap_atomic instead of kmap. Signed-off-by: Jaegeuk Kim --- 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 -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://p.sf.net/sfu/Zoho ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH 01/11] f2fs: reuse room_for_filename for inline dentry operation
This patch introduces to reuse the existing room_for_filename for inline dentry operation. Signed-off-by: Jaegeuk Kim --- 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 -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://p.sf.net/sfu/Zoho ___
[f2fs-dev] [PATCH 08/11] f2fs: should not truncate any inline_dentry
If the inode has inline_dentry, we should not truncate any block indices. Signed-off-by: Jaegeuk Kim --- 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 -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://p.sf.net/sfu/Zoho ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH 06/11] f2fs: fix counting inline_data inode numbers
This patch fixes wrongly counting inline_data inode numbers. Signed-off-by: Jaegeuk Kim --- 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 -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://p.sf.net/sfu/Zoho ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH 07/11] f2fs: reuse core function in f2fs_readdir for inline_dentry
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 --- 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 ino
[f2fs-dev] [PATCH 04/11] f2fs: avoid deadlock on init_inode_metadata
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 88003fc94580 0 11006 11004 0x 880007717b10 0002 88003c323220 880007717fd8 00014580 00014580 88003daecb30 88003c323220 88003fc94e80 88003ffbb4e8 880007717ba0 0002 Call Trace: [] ? bit_wait+0x50/0x50 [] io_schedule+0x9d/0x130 [] bit_wait_io+0x2c/0x50 [] __wait_on_bit_lock+0x4b/0xb0 [] __lock_page+0x67/0x70 [] ? autoremove_wake_function+0x40/0x40 [] pagecache_get_page+0x14c/0x1e0 [] get_node_page+0x59/0x130 [f2fs] [] read_all_xattrs+0x24d/0x430 [f2fs] [] f2fs_getxattr+0x52/0xe0 [f2fs] [] f2fs_get_acl+0x41/0x2d0 [f2fs] [] get_acl+0x47/0x70 [] posix_acl_create+0x5a/0x150 [] f2fs_init_acl+0x29/0xcb [f2fs] [] init_inode_metadata+0x5d/0x340 [f2fs] [] f2fs_add_inline_entry+0x12a/0x2e0 [f2fs] [] __f2fs_add_link+0x45/0x4a0 [f2fs] [] ? f2fs_new_inode+0x146/0x220 [f2fs] [] f2fs_mknod+0x86/0xf0 [f2fs] [] vfs_mknod+0xe1/0x160 [] SyS_mknod+0x1f6/0x200 [] tracesys+0xe1/0xe6 Signed-off-by: Jaegeuk Kim --- 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
[f2fs-dev] [PATCH 05/11] f2fs: add stat info for inline_dentry inodes
This patch adds status information for inline_dentry inodes. Signed-off-by: Jaegeuk Kim --- 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,