|
@@ -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 @@ retry:
|
|
|
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 @@ retry:
|
|
|
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 @@ retry:
|
|
|
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
|