From dfb7c0ceab57fee7618f4c9c31c5a89254e8530a Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 12 Dec 2012 09:47:39 +0900 Subject: f2fs: remove set_page_dirty for atomic f2fs_end_io_write We should guarantee not to do *scheduling while atomic*. I found, in atomic f2fs_end_io_write(), there is a set_page_dirty() call to deal with IO errors. But, set_page_dirty() calls: -> f2fs_set_data_page_dirty() -> set_dirty_dir_page() -> cond_resched() which results in scheduling. In order to avoid this, I'd like to remove simply set_page_dirty(), since the page is already marked as ERROR and f2fs will be operated as the read-only mode as well. So, there is no recovery issue with this. Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 1 - 1 file changed, 1 deletion(-) (limited to 'fs') diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 1b26e4ea101..8bc1b6fdcf7 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -631,7 +631,6 @@ static void f2fs_end_io_write(struct bio *bio, int err) if (page->mapping) set_bit(AS_EIO, &page->mapping->flags); set_ckpt_flags(p->sbi->ckpt, CP_ERROR_FLAG); - set_page_dirty(page); } end_page_writeback(page); dec_page_count(p->sbi, F2FS_WRITEBACK); -- cgit v1.2.3 From 1362b5e347e27102ea0fa99c9932bca1ecde330f Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 12 Dec 2012 19:45:49 +0900 Subject: f2fs: fix wrong calculation on f_files in statfs In f2fs_statfs(), f_files should be the total number of available inodes instead of the currently allocated inodes. So, this patch should resolve the reported bug below. Note that, showing 10% usage is not a bug, since f2fs reveals whole volume size as much as possible and shows the space overhead as *used*. This policy is fair enough with respect to other file systems. (loop0 is backed by 1GiB file) $ mkfs.f2fs /dev/loop0 F2FS-tools: Ver: 1.1.0 (2012-12-11) Info: sector size = 512 Info: total sectors = 2097152 (in 512bytes) Info: zone aligned segment0 blkaddr: 512 Info: format successful $ mount /dev/loop0 mnt/ $ df mnt/ Filesystem 1K-blocks Used Available Use% Mounted on /dev/loop0 1046528 98312 929784 10% /home/zeta/linux-devel/mtd-bench/mnt $ df mnt/ -i Filesystem Inodes IUsed IFree IUse% Mounted on /dev/loop0 1 -465918 465919 - /home/zeta/linux-devel/mtd-bench/mnt Notice IUsed is negative. Also, 10% usage on a fresh f2fs seems too much to be correct. Reported-and-Tested-by: Ezequiel Garcia Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 13867322cf5..f4d9e03723d 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -148,8 +148,8 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_bfree = buf->f_blocks - valid_user_blocks(sbi) - ovp_count; buf->f_bavail = user_block_count - valid_user_blocks(sbi); - buf->f_files = valid_inode_count(sbi); - buf->f_ffree = sbi->total_node_count - valid_node_count(sbi); + buf->f_files = sbi->total_node_count; + buf->f_ffree = sbi->total_node_count - valid_inode_count(sbi); buf->f_namelen = F2FS_MAX_NAME_LEN; buf->f_fsid.val[0] = (u32)id; -- cgit v1.2.3 From 38e0abdcfb5e69aa61a1e9b474d434afc1c177a9 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 13 Dec 2012 23:44:11 +0900 Subject: f2fs: fix up f2fs_get_parent issue to retrieve correct parent inode number Test Case: [NFS Client] ls -lR . [NFS Server] while [ 1 ] do echo 3 > /proc/sys/vm/drop_caches done Error on NFS Client: "No such file or directory" When cache is dropped at the server, it results in lookup failure at the NFS client due to non-connection with the parent. The default path is it initiates a lookup by calculating the hash value for the name, even though the hash values stored on the disk for "." and ".." is maintained as zero, which results in failure from find_in_block due to not matching HASH values. Fix up, by using the correct hashing values for these entries. Signed-off-by: Namjae Jeon Signed-off-by: Amit Sahrawat Signed-off-by: Jaegeuk Kim --- fs/f2fs/dir.c | 4 ++-- fs/f2fs/hash.c | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index b4e24f32b54..e1f66df0f97 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -540,13 +540,13 @@ int f2fs_make_empty(struct inode *inode, struct inode *parent) de = &dentry_blk->dentry[0]; de->name_len = cpu_to_le16(1); - de->hash_code = 0; + de->hash_code = f2fs_dentry_hash(".", 1); 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->hash_code = f2fs_dentry_hash("..", 2); de->name_len = cpu_to_le16(2); de->ino = cpu_to_le32(parent->i_ino); memcpy(dentry_blk->filename[1], "..", 2); diff --git a/fs/f2fs/hash.c b/fs/f2fs/hash.c index a60f04200f8..5e48baca359 100644 --- a/fs/f2fs/hash.c +++ b/fs/f2fs/hash.c @@ -76,6 +76,10 @@ f2fs_hash_t f2fs_dentry_hash(const char *name, int len) const char *p; __u32 in[8], buf[4]; + if ((len <= 2) && (name[0] == '.') && + (name[1] == '.' || name[1] == '\0')) + return 0; + /* Initialize the default seed for the hash checksum functions */ buf[0] = 0x67452301; buf[1] = 0xefcdab89; -- cgit v1.2.3 From 398b1ac5a57219823f942a8d3665b27ab99354de Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 19 Dec 2012 15:28:39 +0900 Subject: f2fs: fix handling errors got by f2fs_write_inode Ruslan reported that f2fs hangs with an infinite loop in f2fs_sync_file(): while (sync_node_pages(sbi, inode->i_ino, &wbc) == 0) f2fs_write_inode(inode, NULL); The reason was revealed that the cold flag is not set even thought this inode is a normal file. Therefore, sync_node_pages() skips to write node blocks since it only writes cold node blocks. The cold flag is stored to the node_footer in node block, and whenever a new node page is allocated, it is set according to its file type, file or directory. But, after sudden-power-off, when recovering the inode page, f2fs doesn't recover its cold flag. So, let's assign the cold flag in more right places. One more thing: If f2fs_write_inode() returns an error due to whatever situations, there would be no dirty node pages so that sync_node_pages() returns zero. (i.e., zero means nothing was written.) Reported-by: Ruslan N. Marchenko Signed-off-by: Jaegeuk Kim --- fs/f2fs/dir.c | 2 ++ fs/f2fs/file.c | 10 ++++++---- fs/f2fs/inode.c | 1 + fs/f2fs/node.c | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index e1f66df0f97..4a78d6c4f3a 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -11,6 +11,7 @@ #include #include #include "f2fs.h" +#include "node.h" #include "acl.h" static unsigned long dir_blocks(struct inode *inode) @@ -308,6 +309,7 @@ static int init_inode_metadata(struct inode *inode, struct dentry *dentry) ipage = get_node_page(F2FS_SB(dir->i_sb), inode->i_ino); if (IS_ERR(ipage)) return PTR_ERR(ipage); + set_cold_node(inode, ipage); init_dent_inode(dentry, ipage); f2fs_put_page(ipage, 1); } diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index f9e085dfb1f..7f9ea9271eb 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -160,15 +160,17 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) if (need_to_sync_dir(sbi, inode)) need_cp = true; - f2fs_write_inode(inode, NULL); - if (need_cp) { /* all the dirty node pages should be flushed for POR */ ret = f2fs_sync_fs(inode->i_sb, 1); clear_inode_flag(F2FS_I(inode), FI_NEED_CP); } else { - while (sync_node_pages(sbi, inode->i_ino, &wbc) == 0) - f2fs_write_inode(inode, NULL); + /* if there is no written node page, write its inode page */ + while (!sync_node_pages(sbi, inode->i_ino, &wbc)) { + ret = f2fs_write_inode(inode, NULL); + if (ret) + goto out; + } filemap_fdatawait_range(sbi->node_inode->i_mapping, 0, LONG_MAX); } diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index df5fb381ebf..bf20b4d0321 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -203,6 +203,7 @@ void update_inode(struct inode *inode, struct page *node_page) ri->i_flags = cpu_to_le32(F2FS_I(inode)->i_flags); ri->i_pino = cpu_to_le32(F2FS_I(inode)->i_pino); ri->i_generation = cpu_to_le32(inode->i_generation); + set_cold_node(inode, node_page); set_page_dirty(node_page); } diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 19870361497..dffac1c11f6 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -834,11 +834,11 @@ struct page *new_node_page(struct dnode_of_data *dn, unsigned int ofs) goto fail; } set_node_addr(sbi, &new_ni, NEW_ADDR); + set_cold_node(dn->inode, page); dn->node_page = page; sync_inode_page(dn); set_page_dirty(page); - set_cold_node(dn->inode, page); if (ofs == 0) inc_valid_inode_count(sbi); -- cgit v1.2.3 From 30f0c75858c46a0273ccb838de401b1f5fdebe6f Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 19 Dec 2012 16:09:19 +0900 Subject: f2fs: should recover orphan and fsync data The recovery routine should do all the time regardless of normal umount action. Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index f4d9e03723d..50240d28ca2 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -528,8 +528,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) /* if there are nt orphan nodes free them */ err = -EINVAL; - if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG) && - recover_orphan_inodes(sbi)) + if (recover_orphan_inodes(sbi)) goto free_node_inode; /* read root inode and dentry */ @@ -548,8 +547,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) } /* recover fsynced data */ - if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG) && - !test_opt(sbi, DISABLE_ROLL_FORWARD)) + if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) recover_fsync_data(sbi); /* After POR, we can run background GC thread */ -- cgit v1.2.3 From 1efef832020ef392deb2cd3d74e0c316711245be Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 19 Dec 2012 16:25:21 +0900 Subject: f2fs: do f2fs_balance_fs in front of dir operations In order to conserve free sections to deal with the worst-case scenarios, f2fs should be able to freeze all the directory operations especially when there are not enough free sections. The f2fs_balance_fs() is for this use. When FS utilization becomes almost 100%, directory operations can be failed due to -ENOSPC frequently, which produces some dirty node pages occasionally. Previously, in such a case, f2fs_balance_fs() is not able to be triggered since it is triggered only if the directory operation ends up with success. So, this patch triggers f2fs_balance_fs() at first before handling directory operations. Signed-off-by: Jaegeuk Kim --- fs/f2fs/namei.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'fs') diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 89b7675dc37..b42389f8001 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -123,6 +123,8 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, nid_t ino = 0; int err; + f2fs_balance_fs(sbi); + inode = f2fs_new_inode(dir, mode); if (IS_ERR(inode)) return PTR_ERR(inode); @@ -144,8 +146,6 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, if (!sbi->por_doing) d_instantiate(dentry, inode); unlock_new_inode(inode); - - f2fs_balance_fs(sbi); return 0; out: clear_nlink(inode); @@ -163,6 +163,8 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir, struct f2fs_sb_info *sbi = F2FS_SB(sb); int err; + f2fs_balance_fs(sbi); + inode->i_ctime = CURRENT_TIME; atomic_inc(&inode->i_count); @@ -172,8 +174,6 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir, goto out; d_instantiate(dentry, inode); - - f2fs_balance_fs(sbi); return 0; out: clear_inode_flag(F2FS_I(inode), FI_INC_LINK); @@ -223,6 +223,8 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry) struct page *page; int err = -ENOENT; + f2fs_balance_fs(sbi); + de = f2fs_find_entry(dir, &dentry->d_name, &page); if (!de) goto fail; @@ -238,7 +240,6 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry) /* In order to evict this inode, we set it dirty */ mark_inode_dirty(inode); - f2fs_balance_fs(sbi); fail: return err; } @@ -252,6 +253,8 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, unsigned symlen = strlen(symname) + 1; int err; + f2fs_balance_fs(sbi); + inode = f2fs_new_inode(dir, S_IFLNK | S_IRWXUGO); if (IS_ERR(inode)) return PTR_ERR(inode); @@ -268,9 +271,6 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, d_instantiate(dentry, inode); unlock_new_inode(inode); - - f2fs_balance_fs(sbi); - return err; out: clear_nlink(inode); @@ -286,6 +286,8 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) struct inode *inode; int err; + f2fs_balance_fs(sbi); + inode = f2fs_new_inode(dir, S_IFDIR | mode); if (IS_ERR(inode)) return PTR_ERR(inode); @@ -305,7 +307,6 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) d_instantiate(dentry, inode); unlock_new_inode(inode); - f2fs_balance_fs(sbi); return 0; out_fail: @@ -336,6 +337,8 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry, if (!new_valid_dev(rdev)) return -EINVAL; + f2fs_balance_fs(sbi); + inode = f2fs_new_inode(dir, mode); if (IS_ERR(inode)) return PTR_ERR(inode); @@ -350,9 +353,6 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry, alloc_nid_done(sbi, inode->i_ino); d_instantiate(dentry, inode); unlock_new_inode(inode); - - f2fs_balance_fs(sbi); - return 0; out: clear_nlink(inode); @@ -376,6 +376,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, struct f2fs_dir_entry *new_entry; int err = -ENOENT; + f2fs_balance_fs(sbi); + old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page); if (!old_entry) goto out; @@ -441,8 +443,6 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, } mutex_unlock_op(sbi, RENAME); - - f2fs_balance_fs(sbi); return 0; out_dir: -- cgit v1.2.3 From 690e4a3ead5f88fc95f7650816d1376aa2e79db5 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 19 Dec 2012 22:19:30 +0100 Subject: f2fs: add missing #include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit m68k allmodconfig: fs/f2fs/data.c: In function ‘read_end_io’: fs/f2fs/data.c:311: error: implicit declaration of function ‘prefetchw’ fs/f2fs/segment.c: In function ‘f2fs_end_io_write’: fs/f2fs/segment.c:628: error: implicit declaration of function ‘prefetchw’ Signed-off-by: Geert Uytterhoeven Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 1 + fs/f2fs/segment.c | 1 + 2 files changed, 2 insertions(+) (limited to 'fs') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 655aeabc1dd..3aa5ce7cab8 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "f2fs.h" #include "node.h" diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 8bc1b6fdcf7..ca7b5ffb09d 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "f2fs.h" -- cgit v1.2.3 From 71e9fec548a95b2a4cf378646addd5d3098684a2 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Thu, 20 Dec 2012 15:10:06 +0900 Subject: f2fs: invalidate the node page if allocation is failed The new_node_page() is processed as the following procedure. 1. A new node page is allocated. 2. Set PageUptodate with proper footer information. 3. Check if there is a free space for allocation 4.a. If there is no space, f2fs returns with -ENOSPC. 4.b. Otherwise, go next. In the case of step #4.a, f2fs remains a wrong node page in the page cache with the uptodate flag. Also, even though a new node page is allocated successfully, an error can be occurred afterwards due to allocation failure of the other data structures. In such a case, remove_inode_page() would be triggered, so that we have to clear uptodate flag in truncate_node() too. So, we should remove the uptodate flag, if allocation is failed. Signed-off-by: Jaegeuk Kim --- fs/f2fs/node.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) (limited to 'fs') diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index dffac1c11f6..e85643cc74a 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -484,12 +484,14 @@ static void truncate_node(struct dnode_of_data *dn) struct node_info ni; get_node_info(sbi, dn->nid, &ni); + if (dn->inode->i_blocks == 0) { + BUG_ON(ni.blk_addr != NULL_ADDR); + goto invalidate; + } BUG_ON(ni.blk_addr == NULL_ADDR); - if (ni.blk_addr != NULL_ADDR) - invalidate_blocks(sbi, ni.blk_addr); - /* Deallocate node address */ + invalidate_blocks(sbi, ni.blk_addr); dec_valid_node_count(sbi, dn->inode, 1); set_node_addr(sbi, &ni, NULL_ADDR); @@ -499,7 +501,7 @@ static void truncate_node(struct dnode_of_data *dn) } else { sync_inode_page(dn); } - +invalidate: clear_node_page_dirty(dn->node_page); F2FS_SET_SB_DIRT(sbi); @@ -768,20 +770,12 @@ int remove_inode_page(struct inode *inode) dn.inode_page_locked = 1; truncate_node(&dn); } - if (inode->i_blocks == 1) { - /* inernally call f2fs_put_page() */ - set_new_dnode(&dn, inode, page, page, ino); - truncate_node(&dn); - } else if (inode->i_blocks == 0) { - struct node_info ni; - get_node_info(sbi, inode->i_ino, &ni); - /* called after f2fs_new_inode() is failed */ - BUG_ON(ni.blk_addr != NULL_ADDR); - f2fs_put_page(page, 1); - } else { - BUG(); - } + /* 0 is possible, after f2fs_new_inode() is failed */ + BUG_ON(inode->i_blocks != 0 && inode->i_blocks != 1); + set_new_dnode(&dn, inode, page, page, ino); + truncate_node(&dn); + mutex_unlock_op(sbi, NODE_TRUNC); return 0; } @@ -845,6 +839,7 @@ struct page *new_node_page(struct dnode_of_data *dn, unsigned int ofs) return page; fail: + clear_node_page_dirty(page); f2fs_put_page(page, 1); return ERR_PTR(err); } -- cgit v1.2.3 From 12a67146e35ba1d04ac4a5430eaaa8790158d60e Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 21 Dec 2012 11:47:05 +0900 Subject: f2fs: return a default value for non-void function This patch resolves a build warning reported by kbuild test robot. " fs/f2fs/segment.c: In function '__get_segment_type': fs/f2fs/segment.c:806:1: warning: control reaches end of non-void function [-Wreturn-type] " Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 7 +++---- fs/f2fs/super.c | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index ca7b5ffb09d..fe2cc0bdc11 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -791,11 +791,10 @@ static int __get_segment_type(struct page *page, enum page_type p_type) return __get_segment_type_2(page, p_type); case 4: return __get_segment_type_4(page, p_type); - case 6: - return __get_segment_type_6(page, p_type); - default: - BUG(); } + /* NR_CURSEG_TYPE(6) logs by default */ + BUG_ON(sbi->active_logs != NR_CURSEG_TYPE); + return __get_segment_type_6(page, p_type); } static void do_write_page(struct f2fs_sb_info *sbi, struct page *page, diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 50240d28ca2..cf0ffb80065 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -302,7 +302,7 @@ static int parse_options(struct f2fs_sb_info *sbi, char *options) case Opt_active_logs: if (args->from && match_int(args, &arg)) return -EINVAL; - if (arg != 2 && arg != 4 && arg != 6) + if (arg != 2 && arg != 4 && arg != NR_CURSEG_TYPE) return -EINVAL; sbi->active_logs = arg; break; -- cgit v1.2.3 From 029cd28c1f739bbfc5105035696d5f1f4e45d161 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 21 Dec 2012 17:20:21 +0900 Subject: f2fs: fix equation of has_not_enough_free_secs() Practically, has_not_enough_free_secs() should calculate with the numbers of current node and directory data blocks together. Actually the equation was implemented in need_to_flush(). So, this patch removes need_flush() and moves the equation into has_not_enough_free_secs(). Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 36 ++---------------------------------- fs/f2fs/segment.h | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 35 deletions(-) (limited to 'fs') diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index fe2cc0bdc11..66f5e82ec32 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -19,48 +19,16 @@ #include "segment.h" #include "node.h" -static int need_to_flush(struct f2fs_sb_info *sbi) -{ - unsigned int pages_per_sec = (1 << sbi->log_blocks_per_seg) * - sbi->segs_per_sec; - int node_secs = ((get_pages(sbi, F2FS_DIRTY_NODES) + pages_per_sec - 1) - >> sbi->log_blocks_per_seg) / sbi->segs_per_sec; - int dent_secs = ((get_pages(sbi, F2FS_DIRTY_DENTS) + pages_per_sec - 1) - >> sbi->log_blocks_per_seg) / sbi->segs_per_sec; - - if (sbi->por_doing) - return 0; - - if (free_sections(sbi) <= (node_secs + 2 * dent_secs + - reserved_sections(sbi))) - return 1; - return 0; -} - /* * This function balances dirty node and dentry pages. * In addition, it controls garbage collection. */ void f2fs_balance_fs(struct f2fs_sb_info *sbi) { - struct writeback_control wbc = { - .sync_mode = WB_SYNC_ALL, - .nr_to_write = LONG_MAX, - .for_reclaim = 0, - }; - - if (sbi->por_doing) - return; - /* - * We should do checkpoint when there are so many dirty node pages - * with enough free segments. After then, we should do GC. + * We should do GC or end up with checkpoint, if there are so many dirty + * dir/node pages without enough free segments. */ - if (need_to_flush(sbi)) { - sync_dirty_dir_inodes(sbi); - sync_node_pages(sbi, 0, &wbc); - } - if (has_not_enough_free_secs(sbi)) { mutex_lock(&sbi->gc_mutex); f2fs_gc(sbi, 1); diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index 0948405af6f..66a288a52fd 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -459,7 +459,20 @@ static inline int get_ssr_segment(struct f2fs_sb_info *sbi, int type) static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi) { - return free_sections(sbi) <= reserved_sections(sbi); + unsigned int pages_per_sec = (1 << sbi->log_blocks_per_seg) * + sbi->segs_per_sec; + int node_secs = ((get_pages(sbi, F2FS_DIRTY_NODES) + pages_per_sec - 1) + >> sbi->log_blocks_per_seg) / sbi->segs_per_sec; + int dent_secs = ((get_pages(sbi, F2FS_DIRTY_DENTS) + pages_per_sec - 1) + >> sbi->log_blocks_per_seg) / sbi->segs_per_sec; + + if (sbi->por_doing) + return false; + + if (free_sections(sbi) <= (node_secs + 2 * dent_secs + + reserved_sections(sbi))) + return true; + return false; } static inline int utilization(struct f2fs_sb_info *sbi) -- cgit v1.2.3 From 06025f4df88e9e41f4ebcf6b4c3df30661332bc9 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 22 Dec 2012 12:09:43 +0900 Subject: f2fs: handle error from f2fs_iget_nowait In case f2fs_iget_nowait returns error, it results in truncate_hole being called with 'error' value as inode pointer. There is no check in truncate_hole for valid inode, so it could result in crash due "invalid access to memory". Avoid this by handling error condition properly. Signed-off-by: Namjae Jeon Signed-off-by: Amit Sahrawat Signed-off-by: Jaegeuk Kim --- fs/f2fs/recovery.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'fs') diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index b07e9b6ef37..207e2c865c7 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -228,6 +228,9 @@ static void check_index_in_prev_nodes(struct f2fs_sb_info *sbi, /* Deallocate previous index in the node page */ inode = f2fs_iget_nowait(sbi->sb, ino); + if (IS_ERR(inode)) + return; + truncate_hole(inode, bidx, bidx + 1); iput(inode); } -- cgit v1.2.3 From 344324f10fad05e40b1047c5e09ebbc77e43c24f Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 22 Dec 2012 12:09:58 +0900 Subject: f2fs: remove unneeded initialization of nr_dirty in dirty_seglist_info Since, the memory for the object of dirty_seglist_info is allocated using kzalloc - which returns zeroed out memory. So, there is no need to initialize the nr_dirty values with zeroes. Signed-off-by: Namjae Jeon Signed-off-by: Amit Sahrawat Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 1 - 1 file changed, 1 deletion(-) (limited to 'fs') diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 66f5e82ec32..de6240922b0 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1575,7 +1575,6 @@ static int build_dirty_segmap(struct f2fs_sb_info *sbi) for (i = 0; i < NR_DIRTY_TYPE; i++) { dirty_i->dirty_segmap[i] = kzalloc(bitmap_size, GFP_KERNEL); - dirty_i->nr_dirty[i] = 0; if (!dirty_i->dirty_segmap[i]) return -ENOMEM; } -- cgit v1.2.3 From fd8bb65f796f041ee6ba400255ca9021bc45a992 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 22 Dec 2012 12:10:12 +0900 Subject: f2fs: fix fsync_inode list addition logic and avoid invalid access to memory In function find_fsync_dnodes() - the fsync inodes gets added to the list, but in one path suppose f2fs_iget results in error, in such case - error gets added to the fsync inode list. In next call to recover_data()->get_fsync_inode() entry = list_entry(this, struct fsync_inode_entry, list); if (entry->inode->i_ino == ino) This can result in "invalid access to memory" when it encounters 'error' as entry in the fsync inode list. So, add the fsync inode entry to the list only in case of no errors. And, free the object at that point itself in case of issue. Signed-off-by: Namjae Jeon Signed-off-by: Amit Sahrawat Signed-off-by: Jaegeuk Kim --- fs/f2fs/recovery.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 207e2c865c7..b571fee677d 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -144,14 +144,15 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) goto out; } - INIT_LIST_HEAD(&entry->list); - list_add_tail(&entry->list, head); - entry->inode = f2fs_iget(sbi->sb, ino_of_node(page)); if (IS_ERR(entry->inode)) { err = PTR_ERR(entry->inode); + kmem_cache_free(fsync_entry_slab, entry); goto out; } + + INIT_LIST_HEAD(&entry->list); + list_add_tail(&entry->list, head); entry->blkaddr = blkaddr; } if (IS_INODE(page)) { -- cgit v1.2.3 From 64c576fe51bc6b19e99340d2d0e1bda89f66db25 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 22 Dec 2012 12:10:27 +0900 Subject: f2fs: remove unneeded variable from f2fs_sync_fs We can directly return '0' from the function, instead of introducing a 'ret' variable. Signed-off-by: Namjae Jeon Signed-off-by: Amit Sahrawat Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index cf0ffb80065..08a94c814bd 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -119,7 +119,6 @@ static void f2fs_put_super(struct super_block *sb) int f2fs_sync_fs(struct super_block *sb, int sync) { struct f2fs_sb_info *sbi = F2FS_SB(sb); - int ret = 0; if (!sbi->s_dirty && !get_pages(sbi, F2FS_DIRTY_NODES)) return 0; @@ -127,7 +126,7 @@ int f2fs_sync_fs(struct super_block *sb, int sync) if (sync) write_checkpoint(sbi, false, false); - return ret; + return 0; } static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf) -- cgit v1.2.3 From ce19a5d4321911f98d42e4d724630ae48f413719 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 26 Dec 2012 12:03:22 +0900 Subject: f2fs: clean up the start_bidx_of_node function This patch also resolves the following warning reported by kbuild test robot. fs/f2fs/gc.c: In function 'start_bidx_of_node': fs/f2fs/gc.c:453:21: warning: 'bidx' may be used uninitialized in this function Signed-off-by: Jaegeuk Kim --- fs/f2fs/gc.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) (limited to 'fs') diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 644aa380827..eda8230deb0 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -430,28 +430,22 @@ next_step: */ block_t start_bidx_of_node(unsigned int node_ofs) { - block_t start_bidx; - unsigned int bidx, indirect_blks; - int dec; + unsigned int indirect_blks = 2 * NIDS_PER_BLOCK + 4; + unsigned int bidx; - indirect_blks = 2 * NIDS_PER_BLOCK + 4; + if (node_ofs == 0) + return 0; - start_bidx = 1; - if (node_ofs == 0) { - start_bidx = 0; - } else if (node_ofs <= 2) { + if (node_ofs <= 2) { bidx = node_ofs - 1; } else if (node_ofs <= indirect_blks) { - dec = (node_ofs - 4) / (NIDS_PER_BLOCK + 1); + int dec = (node_ofs - 4) / (NIDS_PER_BLOCK + 1); bidx = node_ofs - 2 - dec; } else { - dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1); + int dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1); bidx = node_ofs - 5 - dec; } - - if (start_bidx) - start_bidx = bidx * ADDRS_PER_BLOCK + ADDRS_PER_INODE; - return start_bidx; + return bidx * ADDRS_PER_BLOCK + ADDRS_PER_INODE; } static int check_dnode(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, -- cgit v1.2.3 From 2b50638decdb9a8585654a5acf1c8ce5962f1951 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 26 Dec 2012 14:39:50 +0900 Subject: f2fs: clean up unused variables and return values This patch cleans up a couple of unnecessary codes related to unused variables and return values. Signed-off-by: Jaegeuk Kim --- fs/f2fs/gc.c | 12 +++--------- fs/f2fs/hash.c | 4 +--- fs/f2fs/node.c | 6 +----- 3 files changed, 5 insertions(+), 17 deletions(-) (limited to 'fs') diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index eda8230deb0..b0ec721e984 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -390,9 +390,7 @@ next_step: } err = check_valid_map(sbi, segno, off); - if (err == GC_ERROR) - return err; - else if (err == GC_NEXT) + if (err == GC_NEXT) continue; if (initial) { @@ -550,9 +548,7 @@ next_step: } err = check_valid_map(sbi, segno, off); - if (err == GC_ERROR) - goto stop; - else if (err == GC_NEXT) + if (err == GC_NEXT) continue; if (phase == 0) { @@ -562,9 +558,7 @@ next_step: /* Get an inode by ino with checking validity */ err = check_dnode(sbi, entry, &dni, start_addr + off, &nofs); - if (err == GC_ERROR) - goto stop; - else if (err == GC_NEXT) + if (err == GC_NEXT) continue; if (phase == 1) { diff --git a/fs/f2fs/hash.c b/fs/f2fs/hash.c index 5e48baca359..6977415c52f 100644 --- a/fs/f2fs/hash.c +++ b/fs/f2fs/hash.c @@ -71,7 +71,7 @@ static void str2hashbuf(const char *msg, int len, unsigned int *buf, int num) f2fs_hash_t f2fs_dentry_hash(const char *name, int len) { - __u32 hash, minor_hash; + __u32 hash; f2fs_hash_t f2fs_hash; const char *p; __u32 in[8], buf[4]; @@ -94,8 +94,6 @@ f2fs_hash_t f2fs_dentry_hash(const char *name, int len) p += 16; } hash = buf[0]; - minor_hash = buf[1]; - f2fs_hash = cpu_to_le32(hash & ~F2FS_HASH_COL_BIT); return f2fs_hash; } diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index e85643cc74a..5066bfd256c 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1088,7 +1088,6 @@ static int f2fs_write_node_page(struct page *page, { struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb); nid_t nid; - unsigned int nofs; block_t new_addr; struct node_info ni; @@ -1105,7 +1104,6 @@ static int f2fs_write_node_page(struct page *page, /* get old block addr of this node page */ nid = nid_of_node(page); - nofs = ofs_of_node(page); BUG_ON(page->index != nid); get_node_info(sbi, nid, &ni); @@ -1566,7 +1564,7 @@ void flush_nat_entries(struct f2fs_sb_info *sbi) nid_t nid; struct f2fs_nat_entry raw_ne; int offset = -1; - block_t old_blkaddr, new_blkaddr; + block_t new_blkaddr; ne = list_entry(cur, struct nat_entry, list); nid = nat_get_nid(ne); @@ -1580,7 +1578,6 @@ void flush_nat_entries(struct f2fs_sb_info *sbi) offset = lookup_journal_in_cursum(sum, NAT_JOURNAL, nid, 1); if (offset >= 0) { raw_ne = nat_in_journal(sum, offset); - old_blkaddr = le32_to_cpu(raw_ne.block_addr); goto flush_now; } to_nat_page: @@ -1602,7 +1599,6 @@ to_nat_page: BUG_ON(!nat_blk); raw_ne = nat_blk->entries[nid - start_nid]; - old_blkaddr = le32_to_cpu(raw_ne.block_addr); flush_now: new_blkaddr = nat_get_blkaddr(ne); -- cgit v1.2.3 From 9836b8b9499cb25ea32cad9fff640eef874c5431 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 27 Dec 2012 19:55:46 +0200 Subject: f2fs: unify string length declarations and usage This patch is intended to unify string length declarations and usage. There are number of calls to strlen which return size_t object. The size of this object depends on compiler if it will be bigger, equal or even smaller than an unsigned int Signed-off-by: Leon Romanovsky Signed-off-by: Jaegeuk Kim --- fs/f2fs/dir.c | 10 +++++----- fs/f2fs/f2fs.h | 2 +- fs/f2fs/hash.c | 10 ++++++---- fs/f2fs/namei.c | 6 +++--- fs/f2fs/xattr.c | 5 +++-- 5 files changed, 18 insertions(+), 15 deletions(-) (limited to 'fs') diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 4a78d6c4f3a..951ed52748f 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -75,7 +75,7 @@ static unsigned long dir_block_index(unsigned int level, unsigned int idx) return bidx; } -static bool early_match_name(const char *name, int namelen, +static bool early_match_name(const char *name, size_t namelen, f2fs_hash_t namehash, struct f2fs_dir_entry *de) { if (le16_to_cpu(de->name_len) != namelen) @@ -88,7 +88,7 @@ static bool early_match_name(const char *name, int namelen, } static struct f2fs_dir_entry *find_in_block(struct page *dentry_page, - const char *name, int namelen, int *max_slots, + const char *name, size_t namelen, int *max_slots, f2fs_hash_t namehash, struct page **res_page) { struct f2fs_dir_entry *de; @@ -127,7 +127,7 @@ found: } static struct f2fs_dir_entry *find_in_level(struct inode *dir, - unsigned int level, const char *name, int namelen, + unsigned int level, const char *name, size_t namelen, f2fs_hash_t namehash, struct page **res_page) { int s = GET_DENTRY_SLOTS(namelen); @@ -182,7 +182,7 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir, struct qstr *child, struct page **res_page) { const char *name = child->name; - int namelen = child->len; + size_t namelen = child->len; unsigned long npages = dir_blocks(dir); struct f2fs_dir_entry *de = NULL; f2fs_hash_t name_hash; @@ -383,7 +383,7 @@ int f2fs_add_link(struct dentry *dentry, struct inode *inode) struct inode *dir = dentry->d_parent->d_inode; struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); const char *name = dentry->d_name.name; - int namelen = dentry->d_name.len; + size_t namelen = dentry->d_name.len; struct page *dentry_page = NULL; struct f2fs_dentry_block *dentry_blk = NULL; int slots = GET_DENTRY_SLOTS(namelen); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index a18d63db2fb..13c6dfbb718 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -881,7 +881,7 @@ int f2fs_sync_fs(struct super_block *, int); /* * hash.c */ -f2fs_hash_t f2fs_dentry_hash(const char *, int); +f2fs_hash_t f2fs_dentry_hash(const char *, size_t); /* * node.c diff --git a/fs/f2fs/hash.c b/fs/f2fs/hash.c index 6977415c52f..6eb8d269b53 100644 --- a/fs/f2fs/hash.c +++ b/fs/f2fs/hash.c @@ -42,7 +42,7 @@ static void TEA_transform(unsigned int buf[4], unsigned int const in[]) buf[1] += b1; } -static void str2hashbuf(const char *msg, int len, unsigned int *buf, int num) +static void str2hashbuf(const char *msg, size_t len, unsigned int *buf, int num) { unsigned pad, val; int i; @@ -69,7 +69,7 @@ static void str2hashbuf(const char *msg, int len, unsigned int *buf, int num) *buf++ = pad; } -f2fs_hash_t f2fs_dentry_hash(const char *name, int len) +f2fs_hash_t f2fs_dentry_hash(const char *name, size_t len) { __u32 hash; f2fs_hash_t f2fs_hash; @@ -87,11 +87,13 @@ f2fs_hash_t f2fs_dentry_hash(const char *name, int len) buf[3] = 0x10325476; p = name; - while (len > 0) { + while (1) { str2hashbuf(p, len, in, 4); TEA_transform(buf, in); - len -= 16; p += 16; + if (len <= 16) + break; + len -= 16; } hash = buf[0]; f2fs_hash = cpu_to_le32(hash & ~F2FS_HASH_COL_BIT); diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index b42389f8001..1a49b881bac 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -77,8 +77,8 @@ fail: static int is_multimedia_file(const unsigned char *s, const char *sub) { - int slen = strlen(s); - int sublen = strlen(sub); + size_t slen = strlen(s); + size_t sublen = strlen(sub); int ret; if (sublen > slen) @@ -250,7 +250,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, struct super_block *sb = dir->i_sb; struct f2fs_sb_info *sbi = F2FS_SB(sb); struct inode *inode; - unsigned symlen = strlen(symname) + 1; + size_t symlen = strlen(symname) + 1; int err; f2fs_balance_fs(sbi); diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index 7d52e8dc0c5..940136a3d3a 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -208,7 +208,7 @@ int f2fs_getxattr(struct inode *inode, int name_index, const char *name, struct page *page; void *base_addr; int error = 0, found = 0; - int value_len, name_len; + size_t value_len, name_len; if (name == NULL) return -EINVAL; @@ -304,7 +304,8 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name, struct f2fs_xattr_entry *here, *last; struct page *page; void *base_addr; - int error, found, free, name_len, newsize; + int error, found, free, newsize; + size_t name_len; char *pval; if (name == NULL) -- cgit v1.2.3