Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

ceph: use __getname/__putname in ceph_mdsc_build_path



Al suggested we get rid of the kmalloc here and just use __getname
and __putname to get a full PATH_MAX pathname buffer.

Since we build the path in reverse, we continue to return a pointer
to the beginning of the string and the length, and add a new helper
to free the thing at the end.

Suggested-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarJeff Layton <jlayton@kernel.org>
Reviewed-by: default avatar"Yan, Zheng" <zyan@redhat.com>
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
parent 964fff74
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -88,7 +88,7 @@ static int mdsc_show(struct seq_file *s, void *p)
				   req->r_dentry,
				   path ? path : "");
			spin_unlock(&req->r_dentry->d_lock);
			kfree(path);
			ceph_mdsc_free_path(path, pathlen);
		} else if (req->r_path1) {
			seq_printf(s, " #%llx/%s", req->r_ino1.ino,
				   req->r_path1);
@@ -108,7 +108,7 @@ static int mdsc_show(struct seq_file *s, void *p)
				   req->r_old_dentry,
				   path ? path : "");
			spin_unlock(&req->r_old_dentry->d_lock);
			kfree(path);
			ceph_mdsc_free_path(path, pathlen);
		} else if (req->r_path2 && req->r_op != CEPH_MDS_OP_SYMLINK) {
			if (req->r_ino2.ino)
				seq_printf(s, " #%llx/%s", req->r_ino2.ino,
+28 −37
Original line number Diff line number Diff line
@@ -2094,39 +2094,24 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *pbase,
{
	struct dentry *temp;
	char *path;
	int len, pos;
	int pos;
	unsigned seq;
	u64 base;

	if (!dentry)
		return ERR_PTR(-EINVAL);

retry:
	len = 0;
	seq = read_seqbegin(&rename_lock);
	rcu_read_lock();
	for (temp = dentry; !IS_ROOT(temp);) {
		struct inode *inode = d_inode(temp);
		if (inode && ceph_snap(inode) == CEPH_SNAPDIR)
			len++;  /* slash only */
		else if (stop_on_nosnap && inode &&
			 ceph_snap(inode) == CEPH_NOSNAP)
			break;
		else
			len += 1 + temp->d_name.len;
		temp = temp->d_parent;
	}
	rcu_read_unlock();
	if (len)
		len--;  /* no leading '/' */

	path = kmalloc(len+1, GFP_NOFS);
	path = __getname();
	if (!path)
		return ERR_PTR(-ENOMEM);
	pos = len;
	path[pos] = 0;	/* trailing null */
retry:
	pos = PATH_MAX - 1;
	path[pos] = '\0';

	seq = read_seqbegin(&rename_lock);
	rcu_read_lock();
	for (temp = dentry; !IS_ROOT(temp) && pos != 0; ) {
	temp = dentry;
	for (;;) {
		struct inode *inode;

		spin_lock(&temp->d_lock);
@@ -2144,32 +2129,38 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *pbase,
				spin_unlock(&temp->d_lock);
				break;
			}
			strncpy(path + pos, temp->d_name.name,
				temp->d_name.len);
			memcpy(path + pos, temp->d_name.name, temp->d_name.len);
		}
		spin_unlock(&temp->d_lock);
		if (pos)
			path[--pos] = '/';
		temp = temp->d_parent;

		/* Are we at the root? */
		if (IS_ROOT(temp))
			break;

		/* Are we out of buffer? */
		if (--pos < 0)
			break;

		path[pos] = '/';
	}
	base = ceph_ino(d_inode(temp));
	rcu_read_unlock();
	if (pos != 0 || read_seqretry(&rename_lock, seq)) {
	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);
		       "expected, pos is %d\n", pos);
		/* presumably this is only possible if racing with a
		   rename of one of the parent directories (we can not
		   lock the dentries above us to prevent this, but
		   retrying should be harmless) */
		kfree(path);
		goto retry;
	}

	*pbase = base;
	*plen = len;
	*plen = PATH_MAX - 1 - pos;
	dout("build_path on %p %d built %llx '%.*s'\n",
	     dentry, d_count(dentry), base, len, path);
	return path;
	     dentry, d_count(dentry), base, *plen, path + pos);
	return path + pos;
}

static int build_dentry_path(struct dentry *dentry, struct inode *dir,
@@ -2376,10 +2367,10 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc,

out_free2:
	if (freepath2)
		kfree((char *)path2);
		ceph_mdsc_free_path((char *)path2, pathlen2);
out_free1:
	if (freepath1)
		kfree((char *)path1);
		ceph_mdsc_free_path((char *)path1, pathlen1);
out:
	return msg;
}
@@ -3451,7 +3442,7 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,
		ceph_pagelist_encode_string(pagelist, path, pathlen);
		ceph_pagelist_append(pagelist, &rec, sizeof(rec.v1));
out_freepath:
		kfree(path);
		ceph_mdsc_free_path(path, pathlen);
	}

out_err:
+6 −0
Original line number Diff line number Diff line
@@ -492,6 +492,12 @@ extern int ceph_iterate_session_caps(struct ceph_mds_session *session,
				     void *arg);
extern void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc);

static inline void ceph_mdsc_free_path(char *path, int len)
{
	if (path)
		__putname(path - (PATH_MAX - 1 - len));
}

extern char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
				  int stop_on_nosnap);