From 5c757e0196a8e148b45b6fb46829837e5c25df94 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 23 Aug 2014 14:39:28 -0400 Subject: [PATCH] add patch propagate-errors-up-to-ext4_find_entry-s-callers --- propagate-errors-up-to-ext4_find_entry-s-callers | 146 +++++++++++++++++++++++ series | 3 +- timestamps | 7 +- 3 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 propagate-errors-up-to-ext4_find_entry-s-callers diff --git a/propagate-errors-up-to-ext4_find_entry-s-callers b/propagate-errors-up-to-ext4_find_entry-s-callers new file mode 100644 index 00000000..727a9d83 --- /dev/null +++ b/propagate-errors-up-to-ext4_find_entry-s-callers @@ -0,0 +1,146 @@ +ext4: propagate errors up to ext4_find_entry()'s callers + +If we run into some kind of error, such as ENOMEM, while calling +ext4_getblk() or ext4_dx_find_entry(), we need to make sure this error +gets propagated up to ext4_find_entry() and then to its callers. This +way, transient errors such as ENOMEM can get propagated to the VFS. +This is important so that the system calls return the appropriate +error, and also so that in the case of ext4_lookup(), we return an +error instead of a NULL inode, since that will result in a negative +dentry cache entry that will stick around long past the OOM condition +which caused a transient ENOMEM error. + +Google-Bug-Id: #17142205 + +Signed-off-by: Theodore Ts'o +Cc: stable@vger.kernel.org +--- + fs/ext4/namei.c | 35 +++++++++++++++++++++++++++++++++-- + 1 file changed, 33 insertions(+), 2 deletions(-) + +diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c +index b147a67..ae7088b 100644 +--- a/fs/ext4/namei.c ++++ b/fs/ext4/namei.c +@@ -1227,7 +1227,7 @@ static struct buffer_head * ext4_find_entry (struct inode *dir, + buffer */ + int num = 0; + ext4_lblk_t nblocks; +- int i, err; ++ int i, err = 0; + int namelen; + + *res_dir = NULL; +@@ -1264,7 +1264,11 @@ static struct buffer_head * ext4_find_entry (struct inode *dir, + * return. Otherwise, fall back to doing a search the + * old fashioned way. + */ +- if (bh || (err != ERR_BAD_DX_DIR)) ++ if (err == -ENOENT) ++ return NULL; ++ if (err && err != ERR_BAD_DX_DIR) ++ return ERR_PTR(err); ++ if (bh) + return bh; + dxtrace(printk(KERN_DEBUG "ext4_find_entry: dx failed, " + "falling back\n")); +@@ -1295,6 +1299,11 @@ restart: + } + num++; + bh = ext4_getblk(NULL, dir, b++, 0, &err); ++ if (unlikely(err)) { ++ if (ra_max == 0) ++ return ERR_PTR(err); ++ break; ++ } + bh_use[ra_max] = bh; + if (bh) + ll_rw_block(READ | REQ_META | REQ_PRIO, +@@ -1417,6 +1426,8 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi + return ERR_PTR(-ENAMETOOLONG); + + bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL); ++ if (IS_ERR(bh)) ++ return (struct dentry *) bh; + inode = NULL; + if (bh) { + __u32 ino = le32_to_cpu(de->inode); +@@ -1450,6 +1461,8 @@ struct dentry *ext4_get_parent(struct dentry *child) + struct buffer_head *bh; + + bh = ext4_find_entry(child->d_inode, &dotdot, &de, NULL); ++ if (IS_ERR(bh)) ++ return (struct dentry *) bh; + if (!bh) + return ERR_PTR(-ENOENT); + ino = le32_to_cpu(de->inode); +@@ -2727,6 +2740,8 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry) + + retval = -ENOENT; + bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL); ++ if (IS_ERR(bh)) ++ return PTR_ERR(bh); + if (!bh) + goto end_rmdir; + +@@ -2794,6 +2809,8 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry) + + retval = -ENOENT; + bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL); ++ if (IS_ERR(bh)) ++ return PTR_ERR(bh); + if (!bh) + goto end_unlink; + +@@ -3121,6 +3138,8 @@ static int ext4_find_delete_entry(handle_t *handle, struct inode *dir, + struct ext4_dir_entry_2 *de; + + bh = ext4_find_entry(dir, d_name, &de, NULL); ++ if (IS_ERR(bh)) ++ return PTR_ERR(bh); + if (bh) { + retval = ext4_delete_entry(handle, dir, de, bh); + brelse(bh); +@@ -3202,6 +3221,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, + dquot_initialize(new.inode); + + old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, NULL); ++ if (IS_ERR(old.bh)) ++ return PTR_ERR(old.bh); + /* + * Check for inode number is _not_ due to possible IO errors. + * We might rmdir the source, keep it as pwd of some process +@@ -3214,6 +3235,10 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, + + new.bh = ext4_find_entry(new.dir, &new.dentry->d_name, + &new.de, &new.inlined); ++ if (IS_ERR(new.bh)) { ++ retval = PTR_ERR(new.bh); ++ goto end_rename; ++ } + if (new.bh) { + if (!new.inode) { + brelse(new.bh); +@@ -3330,6 +3355,8 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry, + + old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, + &old.de, &old.inlined); ++ if (IS_ERR(old.bh)) ++ return PTR_ERR(old.bh); + /* + * Check for inode number is _not_ due to possible IO errors. + * We might rmdir the source, keep it as pwd of some process +@@ -3342,6 +3369,10 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry, + + new.bh = ext4_find_entry(new.dir, &new.dentry->d_name, + &new.de, &new.inlined); ++ if (IS_ERR(new.bh)) { ++ retval = PTR_ERR(new.bh); ++ goto end_rename; ++ } + + /* RENAME_EXCHANGE case: old *and* new must both exist */ + if (!new.bh || le32_to_cpu(new.de->inode) != new.inode->i_ino) +-- +2.1.0 + diff --git a/series b/series index 1db15c5b..6df23b69 100644 --- a/series +++ b/series @@ -1,5 +1,6 @@ -# BASE 8e099d1e8be3f598dcefd04d3cd5eb3673d4e098 +# BASE v3.17-rc1 +propagate-errors-up-to-ext4_find_entry-s-callers ########################################## # unstable patches diff --git a/timestamps b/timestamps index 6f2a35af..5c44167c 100755 --- a/timestamps +++ b/timestamps @@ -17,6 +17,7 @@ touch -d @1407210954 add-sysfs-bool-support touch -d @1407211014 add-squelch-errors-support touch -d @1407211074 dump-in-use-buffers touch -d @1407211134 akpm-jbd2-locking-fix -touch -d @1407421282 status -touch -d @1407421325 series -touch -d @1407421337 timestamps +touch -d @1408816815 propagate-errors-up-to-ext4_find_entry-s-callers +touch -d @1408817110 series +touch -d @1408817133 status +touch -d @1408819151 timestamps -- 2.11.4.GIT