diff options
author | Theodore Ts'o <tytso@mit.edu> | 2018-11-26 01:20:31 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-01-09 19:14:49 +0300 |
commit | 9da1f6d06b7a6d068e68fcfd7cbbf6b586d888e1 (patch) | |
tree | 3c020bbf9c3b7482ef6fb3d96df564cbd9b65ee9 /fs/ext4/super.c | |
parent | 9f0fc584b6f83d7cb0ec562e44e9ce98bd33b200 (diff) | |
download | linux-9da1f6d06b7a6d068e68fcfd7cbbf6b586d888e1.tar.xz |
ext4: add ext4_sb_bread() to disambiguate ENOMEM cases
commit fb265c9cb49e2074ddcdd4de99728aefdd3b3592 upstream.
Today, when sb_bread() returns NULL, this can either be because of an
I/O error or because the system failed to allocate the buffer. Since
it's an old interface, changing would require changing many call
sites.
So instead we create our own ext4_sb_bread(), which also allows us to
set the REQ_META flag.
Also fixed a problem in the xattr code where a NULL return in a
function could also mean that the xattr was not found, which could
lead to the wrong error getting returned to userspace.
Fixes: ac27a0ec112a ("ext4: initial copy of files from ext3")
Cc: stable@kernel.org # 2.6.19
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/ext4/super.c')
-rw-r--r-- | fs/ext4/super.c | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 7fd64f5f70f0..675f4257597e 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -140,6 +140,29 @@ MODULE_ALIAS_FS("ext3"); MODULE_ALIAS("ext3"); #define IS_EXT3_SB(sb) ((sb)->s_bdev->bd_holder == &ext3_fs_type) +/* + * This works like sb_bread() except it uses ERR_PTR for error + * returns. Currently with sb_bread it's impossible to distinguish + * between ENOMEM and EIO situations (since both result in a NULL + * return. + */ +struct buffer_head * +ext4_sb_bread(struct super_block *sb, sector_t block, int op_flags) +{ + struct buffer_head *bh = sb_getblk(sb, block); + + if (bh == NULL) + return ERR_PTR(-ENOMEM); + if (buffer_uptodate(bh)) + return bh; + ll_rw_block(REQ_OP_READ, REQ_META | op_flags, 1, &bh); + wait_on_buffer(bh); + if (buffer_uptodate(bh)) + return bh; + put_bh(bh); + return ERR_PTR(-EIO); +} + static int ext4_verify_csum_type(struct super_block *sb, struct ext4_super_block *es) { |