From 306a74920ba9ccf6b5f110f97c1cb6bb2caeff93 Mon Sep 17 00:00:00 2001 From: Guo Chao Date: Tue, 18 Dec 2012 16:56:39 +0800 Subject: ext3, ext4, ocfs2: remove unused macro NAMEI_RA_INDEX This macro, initially introduced by ext2 in v0.99.15, does not have any users from the beginning. It has been removed in later ext2 version but still remains in the code of ext3, ext4, ocfs2. Remove this macro there. Cc: Jan Kara Cc: linux-ext4@vger.kernel.org Cc: ocfs2-devel@oss.oracle.com Acked-by: Mark Fasheh Acked-by: "Theodore Ts'o" Signed-off-by: Guo Chao Signed-off-by: Jan Kara --- fs/ext3/namei.c | 1 - fs/ext4/namei.c | 1 - fs/ocfs2/dir.c | 1 - 3 files changed, 3 deletions(-) diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 890b8947c54..88f64eb1b6f 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -36,7 +36,6 @@ #define NAMEI_RA_CHUNKS 2 #define NAMEI_RA_BLOCKS 4 #define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) -#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b)) static struct buffer_head *ext3_append(handle_t *handle, struct inode *inode, diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index f9ed946a448..cc9a512f3a8 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -47,7 +47,6 @@ #define NAMEI_RA_CHUNKS 2 #define NAMEI_RA_BLOCKS 4 #define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) -#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b)) static struct buffer_head *ext4_append(handle_t *handle, struct inode *inode, diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 8fe4e2892ab..fc121350d8c 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -67,7 +67,6 @@ #define NAMEI_RA_CHUNKS 2 #define NAMEI_RA_BLOCKS 4 #define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) -#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b)) static unsigned char ocfs2_filetype_table[] = { DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK -- cgit v1.2.3-18-g5258 From f56426ae4d4414c9c996567710dceecbdfc39acc Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 31 Dec 2012 12:38:36 +0100 Subject: ext3: Fix memory leak when quota options are specified multiple times When usrjquota or grpjquota mount options are specified several times, we leak memory storing the names. Free the memory correctly. Reported-by: Chen Gang Signed-off-by: Jan Kara --- fs/ext3/super.c | 51 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 6e50223b329..0926fe46ae3 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -916,21 +916,24 @@ static int set_qf_name(struct super_block *sb, int qtype, substring_t *args) "Not enough memory for storing quotafile name"); return 0; } - if (sbi->s_qf_names[qtype] && - strcmp(sbi->s_qf_names[qtype], qname)) { - ext3_msg(sb, KERN_ERR, - "%s quota file already specified", QTYPE2NAME(qtype)); + if (sbi->s_qf_names[qtype]) { + int same = !strcmp(sbi->s_qf_names[qtype], qname); + kfree(qname); - return 0; + if (!same) { + ext3_msg(sb, KERN_ERR, + "%s quota file already specified", + QTYPE2NAME(qtype)); + } + return same; } - sbi->s_qf_names[qtype] = qname; - if (strchr(sbi->s_qf_names[qtype], '/')) { + if (strchr(qname, '/')) { ext3_msg(sb, KERN_ERR, "quotafile must be on filesystem root"); - kfree(sbi->s_qf_names[qtype]); - sbi->s_qf_names[qtype] = NULL; + kfree(qname); return 0; } + sbi->s_qf_names[qtype] = qname; set_opt(sbi->s_mount_opt, QUOTA); return 1; } @@ -945,11 +948,10 @@ static int clear_qf_name(struct super_block *sb, int qtype) { " when quota turned on"); return 0; } - /* - * The space will be released later when all options are confirmed - * to be correct - */ - sbi->s_qf_names[qtype] = NULL; + if (sbi->s_qf_names[qtype]) { + kfree(sbi->s_qf_names[qtype]); + sbi->s_qf_names[qtype] = NULL; + } return 1; } #endif @@ -2605,7 +2607,18 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) #ifdef CONFIG_QUOTA old_opts.s_jquota_fmt = sbi->s_jquota_fmt; for (i = 0; i < MAXQUOTAS; i++) - old_opts.s_qf_names[i] = sbi->s_qf_names[i]; + if (sbi->s_qf_names[i]) { + old_opts.s_qf_names[i] = kstrdup(sbi->s_qf_names[i], + GFP_KERNEL); + if (!old_opts.s_qf_names[i]) { + int j; + + for (j = 0; j < i; j++) + kfree(old_opts.s_qf_names[j]); + return -ENOMEM; + } + } else + old_opts.s_qf_names[i] = NULL; #endif /* @@ -2698,9 +2711,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) #ifdef CONFIG_QUOTA /* Release old quota file names */ for (i = 0; i < MAXQUOTAS; i++) - if (old_opts.s_qf_names[i] && - old_opts.s_qf_names[i] != sbi->s_qf_names[i]) - kfree(old_opts.s_qf_names[i]); + kfree(old_opts.s_qf_names[i]); #endif if (enable_quota) dquot_resume(sb, -1); @@ -2714,9 +2725,7 @@ restore_opts: #ifdef CONFIG_QUOTA sbi->s_jquota_fmt = old_opts.s_jquota_fmt; for (i = 0; i < MAXQUOTAS; i++) { - if (sbi->s_qf_names[i] && - old_opts.s_qf_names[i] != sbi->s_qf_names[i]) - kfree(sbi->s_qf_names[i]); + kfree(sbi->s_qf_names[i]); sbi->s_qf_names[i] = old_opts.s_qf_names[i]; } #endif -- cgit v1.2.3-18-g5258 From 8d8759eb488f9e88fa5f976c4fd7ed205661c872 Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Sat, 12 Jan 2013 01:19:32 -0800 Subject: Ext2: free memory allocated and forget buffer head when io error happens Add a necessary check when an io error happens. If io error happens,free the memory allocated and forget buffer head. Signed-off-by: Wang Shilong Signed-off-by: Jan Kara --- fs/ext2/inode.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 6363ac66faf..c3881e56662 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -495,6 +495,10 @@ static int ext2_alloc_branch(struct inode *inode, * parent to disk. */ bh = sb_getblk(inode->i_sb, new_blocks[n-1]); + if (unlikely(!bh)) { + err = -ENOMEM; + goto failed; + } branch[n].bh = bh; lock_buffer(bh); memset(bh->b_data, 0, blocksize); @@ -523,6 +527,14 @@ static int ext2_alloc_branch(struct inode *inode, } *blks = num; return err; + +failed: + for (i = 1; i < n; i++) + bforget(branch[i].bh); + for (i = 0; i < indirect_blks; i++) + ext2_free_blocks(inode, new_blocks[i], 1); + ext2_free_blocks(inode, new_blocks[i], num); + return err; } /** -- cgit v1.2.3-18-g5258 From 61f43e6880dee5983999fe40bf96c1cf43740b4c Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Sat, 12 Jan 2013 01:22:33 -0800 Subject: Ext3: add necessary check in case IO error happens As we know io error may happen when the function 'sb_getblk' is called.Add necessary check for it The patch also fix a coding style problem. Signed-off-by: Wang Shilong Signed-off-by: Jan Kara --- fs/ext3/inode.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index b176d425354..6e4f8a529fb 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -676,6 +676,10 @@ static int ext3_alloc_branch(handle_t *handle, struct inode *inode, * parent to disk. */ bh = sb_getblk(inode->i_sb, new_blocks[n-1]); + if (unlikely(!bh)) { + err = -ENOMEM; + goto failed; + } branch[n].bh = bh; lock_buffer(bh); BUFFER_TRACE(bh, "call get_create_access"); @@ -717,7 +721,7 @@ failed: BUFFER_TRACE(branch[i].bh, "call journal_forget"); ext3_journal_forget(handle, branch[i].bh); } - for (i = 0; i Date: Sat, 12 Jan 2013 01:34:50 -0800 Subject: Ext2: use unlikely to improve the efficiency of the kernel Because the function 'sb_getblk' seldomly fails to return NULL value. It will be better to use unlikely to optimize it. Signed-off-by: Wang shilong Signed-off-by: Jan Kara --- fs/ext2/super.c | 2 +- fs/ext2/xattr.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ext2/super.c b/fs/ext2/super.c index fa04d023177..7f68c811402 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -1500,7 +1500,7 @@ static ssize_t ext2_quota_write(struct super_block *sb, int type, bh = sb_bread(sb, tmp_bh.b_blocknr); else bh = sb_getblk(sb, tmp_bh.b_blocknr); - if (!bh) { + if (unlikely(!bh)) { err = -EIO; goto out; } diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c index b6754dbbce3..06209ec4615 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c @@ -662,7 +662,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, ea_idebug(inode, "creating block %d", block); new_bh = sb_getblk(sb, block); - if (!new_bh) { + if (unlikely(!new_bh)) { ext2_free_blocks(inode, block, 1); mark_inode_dirty(inode); error = -EIO; -- cgit v1.2.3-18-g5258 From 1b7d76e9b1106f2be062f915b05d47658dd4fc63 Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Sat, 12 Jan 2013 01:36:17 -0800 Subject: Ext3: use unlikely to improve the efficiency of the kernel Because the function 'sb_getblk' seldomly fails to return NULL value,it will be better to use unlikely to check it. Signed-off-by: Wang Shilong Signed-off-by: Jan Kara --- fs/ext3/inode.c | 6 +++--- fs/ext3/resize.c | 6 +++--- fs/ext3/xattr.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 6e4f8a529fb..d7df06839f6 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -1082,7 +1082,7 @@ struct buffer_head *ext3_getblk(handle_t *handle, struct inode *inode, if (!err && buffer_mapped(&dummy)) { struct buffer_head *bh; bh = sb_getblk(inode->i_sb, dummy.b_blocknr); - if (!bh) { + if (unlikely(!bh)) { *errp = -EIO; goto err; } @@ -2733,7 +2733,7 @@ static int __ext3_get_inode_loc(struct inode *inode, return -EIO; bh = sb_getblk(inode->i_sb, block); - if (!bh) { + if (unlikely(!bh)) { ext3_error (inode->i_sb, "ext3_get_inode_loc", "unable to read inode block - " "inode=%lu, block="E3FSBLK, @@ -2787,7 +2787,7 @@ static int __ext3_get_inode_loc(struct inode *inode, bitmap_bh = sb_getblk(inode->i_sb, le32_to_cpu(desc->bg_inode_bitmap)); - if (!bitmap_bh) + if (unlikely(!bitmap_bh)) goto make_io; /* diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c index 0f814f3450d..704e8ce7d78 100644 --- a/fs/ext3/resize.c +++ b/fs/ext3/resize.c @@ -116,7 +116,7 @@ static struct buffer_head *bclean(handle_t *handle, struct super_block *sb, int err; bh = sb_getblk(sb, blk); - if (!bh) + if (unlikely(!bh)) return ERR_PTR(-EIO); if ((err = ext3_journal_get_write_access(handle, bh))) { brelse(bh); @@ -234,7 +234,7 @@ static int setup_new_group_blocks(struct super_block *sb, goto exit_bh; gdb = sb_getblk(sb, block); - if (!gdb) { + if (unlikely(!gdb)) { err = -EIO; goto exit_bh; } @@ -722,7 +722,7 @@ static void update_backups(struct super_block *sb, break; bh = sb_getblk(sb, group * bpg + blk_off); - if (!bh) { + if (unlikely(!bh)) { err = -EIO; break; } diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index d22ebb7a4f5..9f57470b172 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -813,7 +813,7 @@ inserted: ea_idebug(inode, "creating block %d", block); new_bh = sb_getblk(sb, block); - if (!new_bh) { + if (unlikely(!new_bh)) { getblk_failed: ext3_free_blocks(handle, inode, block, 1); error = -EIO; -- cgit v1.2.3-18-g5258 From ab6a773dbcbd2bba3ead8676ae21ce5adbbdc035 Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Tue, 15 Jan 2013 21:19:06 -0800 Subject: Ext2: return ENOMEM rather than EIO if sb_getblk fails As the only reason that sb_getblks fails is that allocation fails. It will be better to use ENOMEM rather than EIO. Signed-off-by: Wang Shilong Signed-off-by: Jan Kara --- fs/ext2/xattr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c index 06209ec4615..2d7557db3ae 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c @@ -665,7 +665,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, if (unlikely(!new_bh)) { ext2_free_blocks(inode, block, 1); mark_inode_dirty(inode); - error = -EIO; + error = -ENOMEM; goto cleanup; } lock_buffer(new_bh); -- cgit v1.2.3-18-g5258 From c04e88e271ab67de1409c3b4a4e80dbe13eac7b0 Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Tue, 15 Jan 2013 21:20:01 -0800 Subject: Ext3: return ENOMEM rather than EIO if sb_getblk fails It will be better to use ENOMEM rather than EIO, because the only reason that sb_getblk fails is that allocation fails. Signed-off-by: Wang Shilong Signed-off-by: Jan Kara --- fs/ext3/inode.c | 4 ++-- fs/ext3/resize.c | 6 +++--- fs/ext3/xattr.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index d7df06839f6..d512c4bc4ad 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -1083,7 +1083,7 @@ struct buffer_head *ext3_getblk(handle_t *handle, struct inode *inode, struct buffer_head *bh; bh = sb_getblk(inode->i_sb, dummy.b_blocknr); if (unlikely(!bh)) { - *errp = -EIO; + *errp = -ENOMEM; goto err; } if (buffer_new(&dummy)) { @@ -2738,7 +2738,7 @@ static int __ext3_get_inode_loc(struct inode *inode, "unable to read inode block - " "inode=%lu, block="E3FSBLK, inode->i_ino, block); - return -EIO; + return -ENOMEM; } if (!buffer_uptodate(bh)) { lock_buffer(bh); diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c index 704e8ce7d78..27105655502 100644 --- a/fs/ext3/resize.c +++ b/fs/ext3/resize.c @@ -117,7 +117,7 @@ static struct buffer_head *bclean(handle_t *handle, struct super_block *sb, bh = sb_getblk(sb, blk); if (unlikely(!bh)) - return ERR_PTR(-EIO); + return ERR_PTR(-ENOMEM); if ((err = ext3_journal_get_write_access(handle, bh))) { brelse(bh); bh = ERR_PTR(err); @@ -235,7 +235,7 @@ static int setup_new_group_blocks(struct super_block *sb, gdb = sb_getblk(sb, block); if (unlikely(!gdb)) { - err = -EIO; + err = -ENOMEM; goto exit_bh; } if ((err = ext3_journal_get_write_access(handle, gdb))) { @@ -723,7 +723,7 @@ static void update_backups(struct super_block *sb, bh = sb_getblk(sb, group * bpg + blk_off); if (unlikely(!bh)) { - err = -EIO; + err = -ENOMEM; break; } ext3_debug("update metadata backup %#04lx\n", diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index 9f57470b172..b1fc96383e0 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -816,7 +816,7 @@ inserted: if (unlikely(!new_bh)) { getblk_failed: ext3_free_blocks(handle, inode, block, 1); - error = -EIO; + error = -ENOMEM; goto cleanup; } lock_buffer(new_bh); -- cgit v1.2.3-18-g5258 From 9734c971aa6be6db61226b0046e080ca10383748 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 17 Jan 2013 22:11:38 +0100 Subject: udf: Write LVID to disk after opening / closing So far we just marked the buffer as dirty and left writing on flusher thread but especially on opening that opens possible race window where we could write other modified fs structures to disk before we mark filesystem as open. So sync LVID buffer to disk after opening and closing fs. Reported-by: Steve Nickel Signed-off-by: Jan Kara --- fs/udf/super.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/udf/super.c b/fs/udf/super.c index e9be396a558..186adbf94b2 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1866,6 +1866,8 @@ static void udf_open_lvid(struct super_block *sb) mark_buffer_dirty(bh); sbi->s_lvid_dirty = 0; mutex_unlock(&sbi->s_alloc_mutex); + /* Make opening of filesystem visible on the media immediately */ + sync_dirty_buffer(bh); } static void udf_close_lvid(struct super_block *sb) @@ -1906,6 +1908,8 @@ static void udf_close_lvid(struct super_block *sb) mark_buffer_dirty(bh); sbi->s_lvid_dirty = 0; mutex_unlock(&sbi->s_alloc_mutex); + /* Make closing of filesystem visible on the media immediately */ + sync_dirty_buffer(bh); } u64 lvid_get_unique_id(struct super_block *sb) -- cgit v1.2.3-18-g5258 From 99600051b04bc4ec8bd4d16a8bf993ca54042db6 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 19 Jan 2013 11:17:14 +0900 Subject: udf: add extent cache support in case of file reading This patch implements extent caching in case of file reading. While reading a file, currently, UDF reads metadata serially which takes a lot of time depending on the number of extents present in the file. Caching last accessd extent improves metadata read time. Instead of reading file metadata from start, now we read from the cached extent. This patch considerably improves the time spent by CPU in kernel mode. For example, while reading a 10.9 GB file using dd: Time before applying patch: 11677022208 bytes (10.9GB) copied, 1529.748921 seconds, 7.3MB/s real 25m 29.85s user 0m 12.41s sys 15m 34.75s Time after applying patch: 11677022208 bytes (10.9GB) copied, 1469.338231 seconds, 7.6MB/s real 24m 29.44s user 0m 15.73s sys 3m 27.61s [JK: Fix bh refcounting issues, simplify initialization] Signed-off-by: Namjae Jeon Signed-off-by: Ashish Sangwan Signed-off-by: Bonggil Bak Signed-off-by: Jan Kara --- fs/udf/inode.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- fs/udf/super.c | 2 ++ fs/udf/udf_i.h | 16 +++++++++++ fs/udf/udfdecl.h | 5 ---- 4 files changed, 98 insertions(+), 11 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index cbae1ed0b7c..7a12e48ad81 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -67,6 +67,74 @@ static void udf_update_extents(struct inode *, struct extent_position *); static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); +static void __udf_clear_extent_cache(struct inode *inode) +{ + struct udf_inode_info *iinfo = UDF_I(inode); + + if (iinfo->cached_extent.lstart != -1) { + brelse(iinfo->cached_extent.epos.bh); + iinfo->cached_extent.lstart = -1; + } +} + +/* Invalidate extent cache */ +static void udf_clear_extent_cache(struct inode *inode) +{ + struct udf_inode_info *iinfo = UDF_I(inode); + + spin_lock(&iinfo->i_extent_cache_lock); + __udf_clear_extent_cache(inode); + spin_unlock(&iinfo->i_extent_cache_lock); +} + +/* Return contents of extent cache */ +static int udf_read_extent_cache(struct inode *inode, loff_t bcount, + loff_t *lbcount, struct extent_position *pos) +{ + struct udf_inode_info *iinfo = UDF_I(inode); + int ret = 0; + + spin_lock(&iinfo->i_extent_cache_lock); + if ((iinfo->cached_extent.lstart <= bcount) && + (iinfo->cached_extent.lstart != -1)) { + /* Cache hit */ + *lbcount = iinfo->cached_extent.lstart; + memcpy(pos, &iinfo->cached_extent.epos, + sizeof(struct extent_position)); + if (pos->bh) + get_bh(pos->bh); + ret = 1; + } + spin_unlock(&iinfo->i_extent_cache_lock); + return ret; +} + +/* Add extent to extent cache */ +static void udf_update_extent_cache(struct inode *inode, loff_t estart, + struct extent_position *pos, int next_epos) +{ + struct udf_inode_info *iinfo = UDF_I(inode); + + spin_lock(&iinfo->i_extent_cache_lock); + /* Invalidate previously cached extent */ + __udf_clear_extent_cache(inode); + if (pos->bh) + get_bh(pos->bh); + memcpy(&iinfo->cached_extent.epos, pos, + sizeof(struct extent_position)); + iinfo->cached_extent.lstart = estart; + if (next_epos) + switch (iinfo->i_alloc_type) { + case ICBTAG_FLAG_AD_SHORT: + iinfo->cached_extent.epos.offset -= + sizeof(struct short_ad); + break; + case ICBTAG_FLAG_AD_LONG: + iinfo->cached_extent.epos.offset -= + sizeof(struct long_ad); + } + spin_unlock(&iinfo->i_extent_cache_lock); +} void udf_evict_inode(struct inode *inode) { @@ -90,6 +158,7 @@ void udf_evict_inode(struct inode *inode) } kfree(iinfo->i_ext.i_data); iinfo->i_ext.i_data = NULL; + udf_clear_extent_cache(inode); if (want_delete) { udf_free_inode(inode); } @@ -105,6 +174,7 @@ static void udf_write_failed(struct address_space *mapping, loff_t to) truncate_pagecache(inode, to, isize); if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { down_write(&iinfo->i_data_sem); + udf_clear_extent_cache(inode); udf_truncate_extents(inode); up_write(&iinfo->i_data_sem); } @@ -372,7 +442,7 @@ static int udf_get_block(struct inode *inode, sector_t block, iinfo->i_next_alloc_goal++; } - + udf_clear_extent_cache(inode); phys = inode_getblk(inode, block, &err, &new); if (!phys) goto abort; @@ -1171,6 +1241,7 @@ set_size: } else { if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { down_write(&iinfo->i_data_sem); + udf_clear_extent_cache(inode); memset(iinfo->i_ext.i_data + iinfo->i_lenEAttr + newsize, 0x00, bsize - newsize - udf_file_entry_alloc_offset(inode)); @@ -1184,6 +1255,7 @@ set_size: if (err) return err; down_write(&iinfo->i_data_sem); + udf_clear_extent_cache(inode); truncate_setsize(inode, newsize); udf_truncate_extents(inode); up_write(&iinfo->i_data_sem); @@ -2156,11 +2228,12 @@ int8_t inode_bmap(struct inode *inode, sector_t block, struct udf_inode_info *iinfo; iinfo = UDF_I(inode); - pos->offset = 0; - pos->block = iinfo->i_location; - pos->bh = NULL; + if (!udf_read_extent_cache(inode, bcount, &lbcount, pos)) { + pos->offset = 0; + pos->block = iinfo->i_location; + pos->bh = NULL; + } *elen = 0; - do { etype = udf_next_aext(inode, pos, eloc, elen, 1); if (etype == -1) { @@ -2170,7 +2243,8 @@ int8_t inode_bmap(struct inode *inode, sector_t block, } lbcount += *elen; } while (lbcount <= bcount); - + /* update extent cache */ + udf_update_extent_cache(inode, lbcount - *elen, pos, 1); *offset = (bcount + *elen - lbcount) >> blocksize_bits; return etype; diff --git a/fs/udf/super.c b/fs/udf/super.c index 186adbf94b2..da8ce9f1438 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -134,6 +134,8 @@ static struct inode *udf_alloc_inode(struct super_block *sb) ei->i_next_alloc_goal = 0; ei->i_strat4096 = 0; init_rwsem(&ei->i_data_sem); + ei->cached_extent.lstart = -1; + spin_lock_init(&ei->i_extent_cache_lock); return &ei->vfs_inode; } diff --git a/fs/udf/udf_i.h b/fs/udf/udf_i.h index bb8309dcd5c..b5cd8ed2aa1 100644 --- a/fs/udf/udf_i.h +++ b/fs/udf/udf_i.h @@ -1,6 +1,19 @@ #ifndef _UDF_I_H #define _UDF_I_H +struct extent_position { + struct buffer_head *bh; + uint32_t offset; + struct kernel_lb_addr block; +}; + +struct udf_ext_cache { + /* Extent position */ + struct extent_position epos; + /* Start logical offset in bytes */ + loff_t lstart; +}; + /* * The i_data_sem and i_mutex serve for protection of allocation information * of a regular files and symlinks. This includes all extents belonging to @@ -35,6 +48,9 @@ struct udf_inode_info { __u8 *i_data; } i_ext; struct rw_semaphore i_data_sem; + struct udf_ext_cache cached_extent; + /* Spinlock for protecting extent cache */ + spinlock_t i_extent_cache_lock; struct inode vfs_inode; }; diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index de038da6f6b..be7dabbbcb4 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -113,11 +113,6 @@ struct ustr { uint8_t u_len; }; -struct extent_position { - struct buffer_head *bh; - uint32_t offset; - struct kernel_lb_addr block; -}; /* super.c */ -- cgit v1.2.3-18-g5258 From 89b1f39eb4189de745fae554b0d614d87c8d5c63 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 5 Feb 2013 13:59:56 +0100 Subject: udf: Fix bitmap overflow on large filesystems with small block size For large UDF filesystems with 512-byte blocks the number of necessary bitmap blocks is larger than 2^16 so s_nr_groups in udf_bitmap overflows (the number will overflow for filesystems larger than 128 GB with 512-byte blocks). That results in ENOSPC errors despite the filesystem has plenty of free space. Fix the problem by changing s_nr_groups' type to 'int'. That is enough even for filesystems 2^32 blocks (UDF maximum) and 512-byte blocksize. Reported-and-tested-by: v10lator@myway.de Signed-off-by: Jan Kara --- fs/udf/udf_sb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h index 5f027227f08..8d1c9d4f439 100644 --- a/fs/udf/udf_sb.h +++ b/fs/udf/udf_sb.h @@ -82,7 +82,7 @@ struct udf_virtual_data { struct udf_bitmap { __u32 s_extLength; __u32 s_extPosition; - __u16 s_nr_groups; + int s_nr_groups; struct buffer_head **s_block_bitmap; }; -- cgit v1.2.3-18-g5258 From c60305b578674eefe333198c7476dba2178a9082 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 5 Feb 2013 14:08:57 +0100 Subject: udf: Make s_block_bitmap standard array struct udf_bitmap has array of buffer pointers attached to it. The code unnecessarily used s_block_bitmap as a pointer to the array instead of the standard trick of using 0 length array in the declaration. Change that to make code more readable and actually shrink the structure by one pointer. Signed-off-by: Jan Kara --- fs/udf/super.c | 1 - fs/udf/udf_sb.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index da8ce9f1438..f8830803d38 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1023,7 +1023,6 @@ static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index) if (bitmap == NULL) return NULL; - bitmap->s_block_bitmap = (struct buffer_head **)(bitmap + 1); bitmap->s_nr_groups = nr_groups; return bitmap; } diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h index 8d1c9d4f439..4f7ddb79699 100644 --- a/fs/udf/udf_sb.h +++ b/fs/udf/udf_sb.h @@ -83,7 +83,7 @@ struct udf_bitmap { __u32 s_extLength; __u32 s_extPosition; int s_nr_groups; - struct buffer_head **s_block_bitmap; + struct buffer_head *s_block_bitmap[0]; }; struct udf_part_map { -- cgit v1.2.3-18-g5258 From 288be96de66fa7c09f2cf00a7793db5b4bac4213 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 5 Feb 2013 13:58:29 +0100 Subject: udf: Remove unused s_extLength from udf_bitmap s_extLength was assigned to but the value was never really used. So just remove the field. Signed-off-by: Jan Kara --- fs/udf/super.c | 4 ---- fs/udf/udf_sb.h | 1 - 2 files changed, 5 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index f8830803d38..bc5b30a819e 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1080,8 +1080,6 @@ static int udf_fill_partdesc_info(struct super_block *sb, if (!bitmap) return 1; map->s_uspace.s_bitmap = bitmap; - bitmap->s_extLength = le32_to_cpu( - phd->unallocSpaceBitmap.extLength); bitmap->s_extPosition = le32_to_cpu( phd->unallocSpaceBitmap.extPosition); map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP; @@ -1116,8 +1114,6 @@ static int udf_fill_partdesc_info(struct super_block *sb, if (!bitmap) return 1; map->s_fspace.s_bitmap = bitmap; - bitmap->s_extLength = le32_to_cpu( - phd->freedSpaceBitmap.extLength); bitmap->s_extPosition = le32_to_cpu( phd->freedSpaceBitmap.extPosition); map->s_partition_flags |= UDF_PART_FLAG_FREED_BITMAP; diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h index 4f7ddb79699..ed401e94aa8 100644 --- a/fs/udf/udf_sb.h +++ b/fs/udf/udf_sb.h @@ -80,7 +80,6 @@ struct udf_virtual_data { }; struct udf_bitmap { - __u32 s_extLength; __u32 s_extPosition; int s_nr_groups; struct buffer_head *s_block_bitmap[0]; -- cgit v1.2.3-18-g5258 From 98783e453c1084527388ec1a7f6367cd6aabbe63 Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Wed, 6 Feb 2013 14:14:26 +0800 Subject: Ext2: remove the overhead check about sb in the function ext2_new_blocks It can be guranteed that inode->i_sb should not be null in vfs. So here the check about it is overhead. Signed-off-by: Wang Shilong Signed-off-by: Jan Kara --- fs/ext2/balloc.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index 2616d0ea5c5..ea88181932d 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -1239,10 +1239,6 @@ ext2_fsblk_t ext2_new_blocks(struct inode *inode, ext2_fsblk_t goal, *errp = -ENOSPC; sb = inode->i_sb; - if (!sb) { - printk("ext2_new_blocks: nonexistent device"); - return 0; - } /* * Check quota for allocation of this block. -- cgit v1.2.3-18-g5258 From 8e3dffc651cb668e1ff4d8b89cc1c3dde7540d3b Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Thu, 7 Feb 2013 22:57:53 +0800 Subject: Ext2: mark inode dirty after the function dquot_free_block_nodirty is called We should mark inode dirty after the function dquot_free_block_nodirty is called.Besides,add a check whether it is necessary to call dquot_free_block_nodirty functon. Signed-off-by: Wang Shilong Signed-off-by: Jan Kara --- fs/ext2/balloc.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index ea88181932d..132da4c0692 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -568,8 +568,11 @@ do_more: } error_return: brelse(bitmap_bh); - release_blocks(sb, freed); - dquot_free_block_nodirty(inode, freed); + if (freed) { + release_blocks(sb, freed); + dquot_free_block_nodirty(inode, freed); + mark_inode_dirty(inode); + } } /** @@ -1412,9 +1415,11 @@ allocated: *errp = 0; brelse(bitmap_bh); - dquot_free_block_nodirty(inode, *count-num); - mark_inode_dirty(inode); - *count = num; + if (num < *count) { + dquot_free_block_nodirty(inode, *count-num); + mark_inode_dirty(inode); + *count = num; + } return ret_block; io_error: -- cgit v1.2.3-18-g5258 From 712ddc52ffa1f5324cd8f682d9e5b047b91f34d3 Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Thu, 7 Feb 2013 22:57:54 +0800 Subject: Ext2: remove the static function release_blocks to optimize the kernel Because the static function 'release_blocks' is only called when releasing blocks,it will be more simple and efficient to call the function 'percpu_counter_add' directly. Signed-off-by: Wang Shilong Signed-off-by: Jan Kara --- fs/ext2/balloc.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index 132da4c0692..9f9992b3792 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -159,15 +159,6 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group) return bh; } -static void release_blocks(struct super_block *sb, int count) -{ - if (count) { - struct ext2_sb_info *sbi = EXT2_SB(sb); - - percpu_counter_add(&sbi->s_freeblocks_counter, count); - } -} - static void group_adjust_blocks(struct super_block *sb, int group_no, struct ext2_group_desc *desc, struct buffer_head *bh, int count) { @@ -569,7 +560,7 @@ do_more: error_return: brelse(bitmap_bh); if (freed) { - release_blocks(sb, freed); + percpu_counter_add(&sbi->s_freeblocks_counter, freed); dquot_free_block_nodirty(inode, freed); mark_inode_dirty(inode); } -- cgit v1.2.3-18-g5258