ceph analog of cifs build_path_from_dentry() race fix
... unfortunately, cifs bug got copied. Fix is essentially the same. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
dc137bf553
commit
1b71fe2efa
1 changed files with 16 additions and 3 deletions
|
@ -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)
|
||||
|
@ -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 '/' */
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue