summaryrefslogtreecommitdiffstats
path: root/fs/ext4/super.c
diff options
context:
space:
mode:
authorTheodore Ts'o2018-11-25 23:20:31 +0100
committerTheodore Ts'o2018-11-25 23:20:31 +0100
commitfb265c9cb49e2074ddcdd4de99728aefdd3b3592 (patch)
tree7504b10469a8cbe92672f54e664ae5495e797c50 /fs/ext4/super.c
parentLinux 4.20-rc4 (diff)
downloadkernel-qcow2-linux-fb265c9cb49e2074ddcdd4de99728aefdd3b3592.tar.gz
kernel-qcow2-linux-fb265c9cb49e2074ddcdd4de99728aefdd3b3592.tar.xz
kernel-qcow2-linux-fb265c9cb49e2074ddcdd4de99728aefdd3b3592.zip
ext4: add ext4_sb_bread() to disambiguate ENOMEM cases
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>
Diffstat (limited to 'fs/ext4/super.c')
-rw-r--r--fs/ext4/super.c23
1 files changed, 23 insertions, 0 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 53ff6c2a26ed..361624460431 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)
{