Commit 4c793d4c authored by Jeff Layton's avatar Jeff Layton Committed by Ilya Dryomov
Browse files

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: default avatarJeff Layton <jlayton@kernel.org>
Reviewed-by: default avatarXiubo Li <xiubli@redhat.com>
Reviewed-and-tested-by: default avatarLuís Henriques <lhenriques@suse.de>
Reviewed-by: default avatarMilind Changire <mchangir@redhat.com>
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
parent ec9595c0
Loading
Loading
Loading
Loading
+19 −16
Original line number Diff line number Diff line
@@ -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 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *pbase,
	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 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *pbase,

		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;