Skip to content

Commit

Permalink
ceph analog of cifs build_path_from_dentry() race fix
Browse files Browse the repository at this point in the history
... unfortunately, cifs bug got copied.  Fix is essentially the same.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
  • Loading branch information
Al Viro committed Jul 17, 2011
1 parent dc137bf commit 1b71fe2
Showing 1 changed file with 16 additions and 3 deletions.
19 changes: 16 additions & 3 deletions fs/ceph/mds_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -1438,12 +1438,15 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
struct dentry *temp;
char *path;
int len, pos;
unsigned seq;

if (dentry == NULL)
return ERR_PTR(-EINVAL);

retry:
len = 0;
seq = read_seqbegin(&rename_lock);
rcu_read_lock();
for (temp = dentry; !IS_ROOT(temp);) {
struct inode *inode = temp->d_inode;
if (inode && ceph_snap(inode) == CEPH_SNAPDIR)
Expand All @@ -1455,10 +1458,12 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
len += 1 + temp->d_name.len;
temp = temp->d_parent;
if (temp == NULL) {
rcu_read_unlock();
pr_err("build_path corrupt dentry %p\n", dentry);
return ERR_PTR(-EINVAL);
}
}
rcu_read_unlock();
if (len)
len--; /* no leading '/' */

Expand All @@ -1467,9 +1472,12 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
return ERR_PTR(-ENOMEM);
pos = len;
path[pos] = 0; /* trailing null */
rcu_read_lock();
for (temp = dentry; !IS_ROOT(temp) && pos != 0; ) {
struct inode *inode = temp->d_inode;
struct inode *inode;

spin_lock(&temp->d_lock);
inode = temp->d_inode;
if (inode && ceph_snap(inode) == CEPH_SNAPDIR) {
dout("build_path path+%d: %p SNAPDIR\n",
pos, temp);
Expand All @@ -1478,21 +1486,26 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
break;
} else {
pos -= temp->d_name.len;
if (pos < 0)
if (pos < 0) {
spin_unlock(&temp->d_lock);
break;
}
strncpy(path + pos, temp->d_name.name,
temp->d_name.len);
}
spin_unlock(&temp->d_lock);
if (pos)
path[--pos] = '/';
temp = temp->d_parent;
if (temp == NULL) {
rcu_read_unlock();
pr_err("build_path corrupt dentry\n");
kfree(path);
return ERR_PTR(-EINVAL);
}
}
if (pos != 0) {
rcu_read_unlock();
if (pos != 0 || read_seqretry(&rename_lock, seq)) {
pr_err("build_path did not end path lookup where "
"expected, namelen is %d, pos is %d\n", len, pos);
/* presumably this is only possible if racing with a
Expand Down

0 comments on commit 1b71fe2

Please sign in to comment.