ext4: return ENOMEM if sb_getblk() fails
authorTheodore Ts'o <tytso@mit.edu>
Sat, 12 Jan 2013 21:19:36 +0000 (16:19 -0500)
committerBen Hutchings <ben@decadent.org.uk>
Wed, 6 Mar 2013 03:22:36 +0000 (03:22 +0000)
commit 860d21e2c585f7ee8a4ecc06f474fdc33c9474f4 upstream.

The only reason for sb_getblk() failing is if it can't allocate the
buffer_head.  So ENOMEM is more appropriate than EIO.  In addition,
make sure that the file system is marked as being inconsistent if
sb_getblk() fails.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
[bwh: Backported to 3.2:
 - Adjust context
 - Drop change to inline.c
 - Call to ext4_ext_check() from ext4_ext_find_extent() is conditional]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
fs/ext4/extents.c
fs/ext4/indirect.c
fs/ext4/inode.c
fs/ext4/mmp.c
fs/ext4/resize.c
fs/ext4/xattr.c

index fbb92e6..aaa01cc 100644 (file)
@@ -636,6 +636,7 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
        struct ext4_extent_header *eh;
        struct buffer_head *bh;
        short int depth, i, ppos = 0, alloc = 0;
+       int ret;
 
        eh = ext_inode_hdr(inode);
        depth = ext_depth(inode);
@@ -665,12 +666,15 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
                path[ppos].p_ext = NULL;
 
                bh = sb_getblk(inode->i_sb, path[ppos].p_block);
-               if (unlikely(!bh))
+               if (unlikely(!bh)) {
+                       ret = -ENOMEM;
                        goto err;
+               }
                if (!bh_uptodate_or_lock(bh)) {
                        trace_ext4_ext_load_extent(inode, block,
                                                path[ppos].p_block);
-                       if (bh_submit_read(bh) < 0) {
+                       ret = bh_submit_read(bh);
+                       if (ret < 0) {
                                put_bh(bh);
                                goto err;
                        }
@@ -683,13 +687,15 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
                        put_bh(bh);
                        EXT4_ERROR_INODE(inode,
                                         "ppos %d > depth %d", ppos, depth);
+                       ret = -EIO;
                        goto err;
                }
                path[ppos].p_bh = bh;
                path[ppos].p_hdr = eh;
                i--;
 
-               if (need_to_validate && ext4_ext_check(inode, eh, i))
+               ret = need_to_validate ? ext4_ext_check(inode, eh, i) : 0;
+               if (ret < 0)
                        goto err;
        }
 
@@ -711,7 +717,7 @@ err:
        ext4_ext_drop_refs(path);
        if (alloc)
                kfree(path);
-       return ERR_PTR(-EIO);
+       return ERR_PTR(ret);
 }
 
 /*
@@ -866,7 +872,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
        }
        bh = sb_getblk(inode->i_sb, newblock);
        if (!bh) {
-               err = -EIO;
+               err = -ENOMEM;
                goto cleanup;
        }
        lock_buffer(bh);
@@ -938,7 +944,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
                newblock = ablocks[--a];
                bh = sb_getblk(inode->i_sb, newblock);
                if (!bh) {
-                       err = -EIO;
+                       err = -ENOMEM;
                        goto cleanup;
                }
                lock_buffer(bh);
@@ -1049,11 +1055,8 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
                return err;
 
        bh = sb_getblk(inode->i_sb, newblock);
-       if (!bh) {
-               err = -EIO;
-               ext4_std_error(inode->i_sb, err);
-               return err;
-       }
+       if (!bh)
+               return -ENOMEM;
        lock_buffer(bh);
 
        err = ext4_journal_get_create_access(handle, bh);
index 3cfc73f..26d6dbf 100644 (file)
@@ -146,6 +146,7 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth,
        struct super_block *sb = inode->i_sb;
        Indirect *p = chain;
        struct buffer_head *bh;
+       int ret = -EIO;
 
        *err = 0;
        /* i_data is not going away, no lock needed */
@@ -154,8 +155,10 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth,
                goto no_block;
        while (--depth) {
                bh = sb_getblk(sb, le32_to_cpu(p->key));
-               if (unlikely(!bh))
+               if (unlikely(!bh)) {
+                       ret = -ENOMEM;
                        goto failure;
+               }
 
                if (!bh_uptodate_or_lock(bh)) {
                        if (bh_submit_read(bh) < 0) {
@@ -177,7 +180,7 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth,
        return NULL;
 
 failure:
-       *err = -EIO;
+       *err = ret;
 no_block:
        return p;
 }
@@ -471,7 +474,7 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
                 */
                bh = sb_getblk(inode->i_sb, new_blocks[n-1]);
                if (unlikely(!bh)) {
-                       err = -EIO;
+                       err = -ENOMEM;
                        goto failed;
                }
 
index 8424dda..770eeb3 100644 (file)
@@ -661,7 +661,7 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode,
 
        bh = sb_getblk(inode->i_sb, map.m_pblk);
        if (!bh) {
-               *errp = -EIO;
+               *errp = -ENOMEM;
                return NULL;
        }
        if (map.m_flags & EXT4_MAP_NEW) {
@@ -3575,11 +3575,8 @@ static int __ext4_get_inode_loc(struct inode *inode,
        iloc->offset = (inode_offset % inodes_per_block) * EXT4_INODE_SIZE(sb);
 
        bh = sb_getblk(sb, block);
-       if (!bh) {
-               EXT4_ERROR_INODE_BLOCK(inode, block,
-                                      "unable to read itable block");
-               return -EIO;
-       }
+       if (!bh)
+               return -ENOMEM;
        if (!buffer_uptodate(bh)) {
                lock_buffer(bh);
 
index 7ea4ba4..f3358ab 100644 (file)
@@ -41,6 +41,8 @@ static int read_mmp_block(struct super_block *sb, struct buffer_head **bh,
         * is not blocked in the elevator. */
        if (!*bh)
                *bh = sb_getblk(sb, mmp_block);
+       if (!*bh)
+               return -ENOMEM;
        if (*bh) {
                get_bh(*bh);
                lock_buffer(*bh);
index 4eac337..33129c0 100644 (file)
@@ -142,7 +142,7 @@ static struct buffer_head *bclean(handle_t *handle, struct super_block *sb,
 
        bh = sb_getblk(sb, blk);
        if (!bh)
-               return ERR_PTR(-EIO);
+               return ERR_PTR(-ENOMEM);
        if ((err = ext4_journal_get_write_access(handle, bh))) {
                brelse(bh);
                bh = ERR_PTR(err);
@@ -220,7 +220,7 @@ static int setup_new_group_blocks(struct super_block *sb,
 
                gdb = sb_getblk(sb, block);
                if (!gdb) {
-                       err = -EIO;
+                       err = -ENOMEM;
                        goto exit_journal;
                }
                if ((err = ext4_journal_get_write_access(handle, gdb))) {
@@ -694,7 +694,7 @@ static void update_backups(struct super_block *sb,
 
                bh = sb_getblk(sb, group * bpg + blk_off);
                if (!bh) {
-                       err = -EIO;
+                       err = -ENOMEM;
                        break;
                }
                ext4_debug("update metadata backup %#04lx\n",
index 4410ae7..1115dda 100644 (file)
@@ -839,16 +839,17 @@ inserted:
 
                        new_bh = sb_getblk(sb, block);
                        if (!new_bh) {
+                               error = -ENOMEM;
 getblk_failed:
                                ext4_free_blocks(handle, inode, NULL, block, 1,
                                                 EXT4_FREE_BLOCKS_METADATA);
-                               error = -EIO;
                                goto cleanup;
                        }
                        lock_buffer(new_bh);
                        error = ext4_journal_get_create_access(handle, new_bh);
                        if (error) {
                                unlock_buffer(new_bh);
+                               error = -EIO;
                                goto getblk_failed;
                        }
                        memcpy(new_bh->b_data, s->base, new_bh->b_size);