diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index 2616d0ea5c5c089aaa08007cb9d03e19f5a02258..9f9992b37924a43eb4da2c56ecb9b65f68d628a2 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) { @@ -568,8 +559,11 @@ void ext2_free_blocks (struct inode * inode, unsigned long block, } error_return: brelse(bitmap_bh); - release_blocks(sb, freed); - dquot_free_block_nodirty(inode, freed); + if (freed) { + percpu_counter_add(&sbi->s_freeblocks_counter, freed); + dquot_free_block_nodirty(inode, freed); + mark_inode_dirty(inode); + } } /** @@ -1239,10 +1233,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. @@ -1416,9 +1406,11 @@ ext2_fsblk_t ext2_new_blocks(struct inode *inode, ext2_fsblk_t goal, *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: diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 6363ac66fafa48c1c697d993a948fa1a5ff7cf78..c3881e56662efac8c80ec409c5808771303ed24f 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; } /** diff --git a/fs/ext2/super.c b/fs/ext2/super.c index fa04d023177e71dcd8376adfbc097d2ddb4ee3ae..7f68c8114026a7521ca1808775a89cc1e3765542 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 b6754dbbce3c5e4942d8f46273d24c1236f0588b..2d7557db3ae855b614b0c70d2803adafb0f64181 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c @@ -662,10 +662,10 @@ 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; + error = -ENOMEM; goto cleanup; } lock_buffer(new_bh); diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index b176d425354428043ef92c4e680353d90a28c760..d512c4bc4ad7103b968d454266d1814b8d59de41 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 @@ static int ext3_alloc_branch(handle_t *handle, struct inode *inode, BUFFER_TRACE(branch[i].bh, "call journal_forget"); ext3_journal_forget(handle, branch[i].bh); } - for (i = 0; i i_sb, dummy.b_blocknr); - if (!bh) { - *errp = -EIO; + if (unlikely(!bh)) { + *errp = -ENOMEM; goto err; } if (buffer_new(&dummy)) { @@ -2729,12 +2733,12 @@ 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, inode->i_ino, block); - return -EIO; + return -ENOMEM; } if (!buffer_uptodate(bh)) { lock_buffer(bh); @@ -2783,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/namei.c b/fs/ext3/namei.c index 890b8947c5468b863327e87985ef42334f53fa74..88f64eb1b6faaaa12baba47ca8fd74ad371dd429 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/ext3/resize.c b/fs/ext3/resize.c index 0f814f3450de65174573b7ccd0ee4be34ab89065..27105655502cf90a0fa3bb05020698cebfda429a 100644 --- a/fs/ext3/resize.c +++ b/fs/ext3/resize.c @@ -116,8 +116,8 @@ static struct buffer_head *bclean(handle_t *handle, struct super_block *sb, int err; bh = sb_getblk(sb, blk); - if (!bh) - return ERR_PTR(-EIO); + if (unlikely(!bh)) + return ERR_PTR(-ENOMEM); if ((err = ext3_journal_get_write_access(handle, bh))) { brelse(bh); bh = ERR_PTR(err); @@ -234,8 +234,8 @@ static int setup_new_group_blocks(struct super_block *sb, goto exit_bh; gdb = sb_getblk(sb, block); - if (!gdb) { - err = -EIO; + if (unlikely(!gdb)) { + err = -ENOMEM; goto exit_bh; } if ((err = ext3_journal_get_write_access(handle, gdb))) { @@ -722,8 +722,8 @@ static void update_backups(struct super_block *sb, break; bh = sb_getblk(sb, group * bpg + blk_off); - if (!bh) { - err = -EIO; + if (unlikely(!bh)) { + err = -ENOMEM; break; } ext3_debug("update metadata backup %#04lx\n", diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 4ba2683c1d44f0181bc514c155c723c27012d635..5546ca225ffe19ee3e53d75ee4e18936fa47cc83 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 @@ -2606,7 +2608,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 /* @@ -2699,9 +2712,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); @@ -2715,9 +2726,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) #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 diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index d22ebb7a4f55b3fb947e5718c1fbb4d109a7871b..b1fc96383e087157879e853b2affbf0cb87982ec 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -813,10 +813,10 @@ ext3_xattr_block_set(handle_t *handle, struct inode *inode, 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; + error = -ENOMEM; goto cleanup; } lock_buffer(new_bh); diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index f9ed946a448ebb4a7704c5d08fcfe44c42a75f80..cc9a512f3a8af02a8734d44883ef8598db9dad93 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 8fe4e2892ab9ccd983304a825c338df57a5376b8..fc121350d8cb5b6535dcfcddf471e0e1e769d717 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 diff --git a/fs/udf/inode.c b/fs/udf/inode.c index cbae1ed0b7c17dcb966f7d43ca823fa0dcb357bf..7a12e48ad8196d51273fcc2ca66e89d077eb66ee 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 @@ int udf_setsize(struct inode *inode, loff_t newsize) } 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 @@ int udf_setsize(struct inode *inode, loff_t newsize) 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 e9be396a558d944fde7086cce64d22c672cdc5b7..bc5b30a819e82e8622d2ead088c52ef5cf7c268e 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; } @@ -1021,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; } @@ -1079,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; @@ -1115,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; @@ -1866,6 +1863,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 +1905,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) diff --git a/fs/udf/udf_i.h b/fs/udf/udf_i.h index bb8309dcd5c1bd2d797b5e774e86c8e2d97e529f..b5cd8ed2aa12ff3e27a8b3681886152943bf3af4 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/udf_sb.h b/fs/udf/udf_sb.h index 5f027227f085464d33b2434a1cad64a44195c54d..ed401e94aa8c956dd8685ab33f496fc4ea52eec7 100644 --- a/fs/udf/udf_sb.h +++ b/fs/udf/udf_sb.h @@ -80,10 +80,9 @@ struct udf_virtual_data { }; struct udf_bitmap { - __u32 s_extLength; __u32 s_extPosition; - __u16 s_nr_groups; - struct buffer_head **s_block_bitmap; + int s_nr_groups; + struct buffer_head *s_block_bitmap[0]; }; struct udf_part_map { diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index de038da6f6bde90588b95cd0bf70b2ac47930496..be7dabbbcb49ef171b33e0ec2bc4a672c073282d 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 */