ceph: make ceph_msdc_build_path use ref-walk

Encryption potentially requires allocation, at which point we'll need to
be in a non-atomic context. Convert ceph_msdc_build_path to take dentry
spinlocks and references instead of using rcu_read_lock to walk the
path.

This is slightly less efficient, and we may want to eventually allow
using RCU when the leaf dentry isn't encrypted.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Xiubo Li <xiubli@redhat.com>
Reviewed-and-tested-by: Luís Henriques <lhenriques@suse.de>
Reviewed-by: Milind Changire <mchangir@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This commit is contained in:
Jeff Layton 2020-08-05 14:50:48 -04:00 committed by Ilya Dryomov
parent ec9595c080
commit 4c793d4c58
1 changed files with 19 additions and 16 deletions

View File

@ -2387,7 +2387,8 @@ static inline u64 __get_oldest_tid(struct ceph_mds_client *mdsc)
char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *pbase,
int stop_on_nosnap)
{
struct dentry *temp;
struct dentry *cur;
struct inode *inode;
char *path;
int pos;
unsigned seq;
@ -2404,34 +2405,35 @@ retry:
path[pos] = '\0';
seq = read_seqbegin(&rename_lock);
rcu_read_lock();
temp = dentry;
cur = dget(dentry);
for (;;) {
struct inode *inode;
struct dentry *temp;
spin_lock(&temp->d_lock);
inode = d_inode(temp);
spin_lock(&cur->d_lock);
inode = d_inode(cur);
if (inode && ceph_snap(inode) == CEPH_SNAPDIR) {
dout("build_path path+%d: %p SNAPDIR\n",
pos, temp);
} else if (stop_on_nosnap && inode && dentry != temp &&
pos, cur);
} else if (stop_on_nosnap && inode && dentry != cur &&
ceph_snap(inode) == CEPH_NOSNAP) {
spin_unlock(&temp->d_lock);
spin_unlock(&cur->d_lock);
pos++; /* get rid of any prepended '/' */
break;
} else {
pos -= temp->d_name.len;
pos -= cur->d_name.len;
if (pos < 0) {
spin_unlock(&temp->d_lock);
spin_unlock(&cur->d_lock);
break;
}
memcpy(path + pos, temp->d_name.name, temp->d_name.len);
memcpy(path + pos, cur->d_name.name, cur->d_name.len);
}
temp = cur;
spin_unlock(&temp->d_lock);
temp = READ_ONCE(temp->d_parent);
cur = dget_parent(temp);
dput(temp);
/* Are we at the root? */
if (IS_ROOT(temp))
if (IS_ROOT(cur))
break;
/* Are we out of buffer? */
@ -2440,8 +2442,9 @@ retry:
path[pos] = '/';
}
base = ceph_ino(d_inode(temp));
rcu_read_unlock();
inode = d_inode(cur);
base = inode ? ceph_ino(inode) : 0;
dput(cur);
if (read_seqretry(&rename_lock, seq))
goto retry;