[PATCH v4 16/17] vfs: have do_sys_truncate retry once on an ESTALE error

From: Jeff Layton
Date: Thu Jul 26 2012 - 07:56:24 EST


Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx>
---
fs/open.c | 92 +++++++++++++++++++++++++++++++++++----------------------------
1 file changed, 51 insertions(+), 41 deletions(-)

diff --git a/fs/open.c b/fs/open.c
index fea9b0e..a7b94ac 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -66,62 +66,72 @@ static long do_sys_truncate(const char __user *pathname, loff_t length)
struct path path;
struct inode *inode;
int error;
+ unsigned int lookup_flags = LOOKUP_FOLLOW;
+ unsigned int try = 0;
+ char *name;

- error = -EINVAL;
if (length < 0) /* sorry, but loff_t says... */
- goto out;
+ return -EINVAL;

- error = user_path(pathname, &path);
- if (error)
- goto out;
- inode = path.dentry->d_inode;
+ name = getname_flags(pathname, lookup_flags, NULL);
+ if (IS_ERR(name))
+ return PTR_ERR(name);

- /* For directories it's -EISDIR, for other non-regulars - -EINVAL */
- error = -EISDIR;
- if (S_ISDIR(inode->i_mode))
- goto dput_and_out;
+ do {
+ error = kern_path_at(AT_FDCWD, name, lookup_flags, &path);
+ if (error)
+ break;
+ inode = path.dentry->d_inode;

- error = -EINVAL;
- if (!S_ISREG(inode->i_mode))
- goto dput_and_out;
+ /* For dirs, -EISDIR. For other non-regulars, -EINVAL */
+ error = -EISDIR;
+ if (S_ISDIR(inode->i_mode))
+ goto dput_and_out;

- error = mnt_want_write(path.mnt);
- if (error)
- goto dput_and_out;
+ error = -EINVAL;
+ if (!S_ISREG(inode->i_mode))
+ goto dput_and_out;

- error = inode_permission(inode, MAY_WRITE);
- if (error)
- goto mnt_drop_write_and_out;
+ error = mnt_want_write(path.mnt);
+ if (error)
+ goto dput_and_out;

- error = -EPERM;
- if (IS_APPEND(inode))
- goto mnt_drop_write_and_out;
+ error = inode_permission(inode, MAY_WRITE);
+ if (error)
+ goto mnt_drop_write_and_out;

- error = get_write_access(inode);
- if (error)
- goto mnt_drop_write_and_out;
+ error = -EPERM;
+ if (IS_APPEND(inode))
+ goto mnt_drop_write_and_out;

- /*
- * Make sure that there are no leases. get_write_access() protects
- * against the truncate racing with a lease-granting setlease().
- */
- error = break_lease(inode, O_WRONLY);
- if (error)
- goto put_write_and_out;
+ error = get_write_access(inode);
+ if (error)
+ goto mnt_drop_write_and_out;

- error = locks_verify_truncate(inode, NULL, length);
- if (!error)
- error = security_path_truncate(&path);
- if (!error)
- error = do_truncate(path.dentry, length, 0, NULL);
+ /*
+ * Make sure that there are no leases. get_write_access()
+ * protects against the truncate racing with a lease-granting
+ * setlease().
+ */
+ error = break_lease(inode, O_WRONLY);
+ if (error)
+ goto put_write_and_out;
+
+ error = locks_verify_truncate(inode, NULL, length);
+ if (!error)
+ error = security_path_truncate(&path);
+ if (!error)
+ error = do_truncate(path.dentry, length, 0, NULL);

put_write_and_out:
- put_write_access(inode);
+ put_write_access(inode);
mnt_drop_write_and_out:
- mnt_drop_write(path.mnt);
+ mnt_drop_write(path.mnt);
dput_and_out:
- path_put(&path);
-out:
+ path_put(&path);
+ lookup_flags |= LOOKUP_REVAL;
+ } while (retry_estale(error, try++));
+ putname(name);
return error;
}

--
1.7.11.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/