1 ext4: propagate errors up to ext4_find_entry()'s callers
3 If we run into some kind of error, such as ENOMEM, while calling
4 ext4_getblk() or ext4_dx_find_entry(), we need to make sure this error
5 gets propagated up to ext4_find_entry() and then to its callers. This
6 way, transient errors such as ENOMEM can get propagated to the VFS.
7 This is important so that the system calls return the appropriate
8 error, and also so that in the case of ext4_lookup(), we return an
9 error instead of a NULL inode, since that will result in a negative
10 dentry cache entry that will stick around long past the OOM condition
11 which caused a transient ENOMEM error.
13 Google-Bug-Id: #17142205
15 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
16 Cc: stable@vger.kernel.org
19 fs/ext4/namei.c | 35 +++++++++++++++++++++++++++++++++--
20 2 files changed, 34 insertions(+), 3 deletions(-)
22 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
23 index 5b19760..4d95c33 100644
26 @@ -1825,7 +1825,7 @@ ext4_group_first_block_no(struct super_block *sb, ext4_group_t group_no)
28 * Special error return code only used by dx_probe() and its callers.
30 -#define ERR_BAD_DX_DIR -75000
31 +#define ERR_BAD_DX_DIR (-(MAX_ERRNO - 1))
34 * Timeout and state flag for lazy initialization inode thread.
35 diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
36 index b147a67..ae7088b 100644
39 @@ -1227,7 +1227,7 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
48 @@ -1264,7 +1264,11 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
49 * return. Otherwise, fall back to doing a search the
52 - if (bh || (err != ERR_BAD_DX_DIR))
55 + if (err && err != ERR_BAD_DX_DIR)
56 + return ERR_PTR(err);
59 dxtrace(printk(KERN_DEBUG "ext4_find_entry: dx failed, "
61 @@ -1295,6 +1299,11 @@ restart:
64 bh = ext4_getblk(NULL, dir, b++, 0, &err);
65 + if (unlikely(err)) {
67 + return ERR_PTR(err);
72 ll_rw_block(READ | REQ_META | REQ_PRIO,
73 @@ -1417,6 +1426,8 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
74 return ERR_PTR(-ENAMETOOLONG);
76 bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
78 + return (struct dentry *) bh;
81 __u32 ino = le32_to_cpu(de->inode);
82 @@ -1450,6 +1461,8 @@ struct dentry *ext4_get_parent(struct dentry *child)
83 struct buffer_head *bh;
85 bh = ext4_find_entry(child->d_inode, &dotdot, &de, NULL);
87 + return (struct dentry *) bh;
89 return ERR_PTR(-ENOENT);
90 ino = le32_to_cpu(de->inode);
91 @@ -2727,6 +2740,8 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
94 bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
100 @@ -2794,6 +2809,8 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
103 bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
105 + return PTR_ERR(bh);
109 @@ -3121,6 +3138,8 @@ static int ext4_find_delete_entry(handle_t *handle, struct inode *dir,
110 struct ext4_dir_entry_2 *de;
112 bh = ext4_find_entry(dir, d_name, &de, NULL);
114 + return PTR_ERR(bh);
116 retval = ext4_delete_entry(handle, dir, de, bh);
118 @@ -3202,6 +3221,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
119 dquot_initialize(new.inode);
121 old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, NULL);
122 + if (IS_ERR(old.bh))
123 + return PTR_ERR(old.bh);
125 * Check for inode number is _not_ due to possible IO errors.
126 * We might rmdir the source, keep it as pwd of some process
127 @@ -3214,6 +3235,10 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
129 new.bh = ext4_find_entry(new.dir, &new.dentry->d_name,
130 &new.de, &new.inlined);
131 + if (IS_ERR(new.bh)) {
132 + retval = PTR_ERR(new.bh);
138 @@ -3330,6 +3355,8 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
140 old.bh = ext4_find_entry(old.dir, &old.dentry->d_name,
141 &old.de, &old.inlined);
142 + if (IS_ERR(old.bh))
143 + return PTR_ERR(old.bh);
145 * Check for inode number is _not_ due to possible IO errors.
146 * We might rmdir the source, keep it as pwd of some process
147 @@ -3342,6 +3369,10 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
149 new.bh = ext4_find_entry(new.dir, &new.dentry->d_name,
150 &new.de, &new.inlined);
151 + if (IS_ERR(new.bh)) {
152 + retval = PTR_ERR(new.bh);
156 /* RENAME_EXCHANGE case: old *and* new must both exist */
157 if (!new.bh || le32_to_cpu(new.de->inode) != new.inode->i_ino)