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: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: "Yan, Zheng" <zyan@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This commit is contained in:
Jeff Layton 2019-04-29 12:13:14 -04:00 committed by Ilya Dryomov
parent 964fff7491
commit f77f21bb28
3 changed files with 36 additions and 39 deletions

View File

@ -88,7 +88,7 @@ static int mdsc_show(struct seq_file *s, void *p)
req->r_dentry, req->r_dentry,
path ? path : ""); path ? path : "");
spin_unlock(&req->r_dentry->d_lock); spin_unlock(&req->r_dentry->d_lock);
kfree(path); ceph_mdsc_free_path(path, pathlen);
} else if (req->r_path1) { } else if (req->r_path1) {
seq_printf(s, " #%llx/%s", req->r_ino1.ino, seq_printf(s, " #%llx/%s", req->r_ino1.ino,
req->r_path1); req->r_path1);
@ -108,7 +108,7 @@ static int mdsc_show(struct seq_file *s, void *p)
req->r_old_dentry, req->r_old_dentry,
path ? path : ""); path ? path : "");
spin_unlock(&req->r_old_dentry->d_lock); 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) { } else if (req->r_path2 && req->r_op != CEPH_MDS_OP_SYMLINK) {
if (req->r_ino2.ino) if (req->r_ino2.ino)
seq_printf(s, " #%llx/%s", req->r_ino2.ino, seq_printf(s, " #%llx/%s", req->r_ino2.ino,

View File

@ -2094,39 +2094,24 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *pbase,
{ {
struct dentry *temp; struct dentry *temp;
char *path; char *path;
int len, pos; int pos;
unsigned seq; unsigned seq;
u64 base; u64 base;
if (!dentry) if (!dentry)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
retry: path = __getname();
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);
if (!path) if (!path)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
pos = len; retry:
path[pos] = 0; /* trailing null */ pos = PATH_MAX - 1;
path[pos] = '\0';
seq = read_seqbegin(&rename_lock);
rcu_read_lock(); rcu_read_lock();
for (temp = dentry; !IS_ROOT(temp) && pos != 0; ) { temp = dentry;
for (;;) {
struct inode *inode; struct inode *inode;
spin_lock(&temp->d_lock); 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); spin_unlock(&temp->d_lock);
break; break;
} }
strncpy(path + pos, temp->d_name.name, memcpy(path + pos, temp->d_name.name, temp->d_name.len);
temp->d_name.len);
} }
spin_unlock(&temp->d_lock); spin_unlock(&temp->d_lock);
if (pos)
path[--pos] = '/';
temp = temp->d_parent; 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)); base = ceph_ino(d_inode(temp));
rcu_read_unlock(); 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 " 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 /* presumably this is only possible if racing with a
rename of one of the parent directories (we can not rename of one of the parent directories (we can not
lock the dentries above us to prevent this, but lock the dentries above us to prevent this, but
retrying should be harmless) */ retrying should be harmless) */
kfree(path);
goto retry; goto retry;
} }
*pbase = base; *pbase = base;
*plen = len; *plen = PATH_MAX - 1 - pos;
dout("build_path on %p %d built %llx '%.*s'\n", dout("build_path on %p %d built %llx '%.*s'\n",
dentry, d_count(dentry), base, len, path); dentry, d_count(dentry), base, *plen, path + pos);
return path; return path + pos;
} }
static int build_dentry_path(struct dentry *dentry, struct inode *dir, 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: out_free2:
if (freepath2) if (freepath2)
kfree((char *)path2); ceph_mdsc_free_path((char *)path2, pathlen2);
out_free1: out_free1:
if (freepath1) if (freepath1)
kfree((char *)path1); ceph_mdsc_free_path((char *)path1, pathlen1);
out: out:
return msg; 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_encode_string(pagelist, path, pathlen);
ceph_pagelist_append(pagelist, &rec, sizeof(rec.v1)); ceph_pagelist_append(pagelist, &rec, sizeof(rec.v1));
out_freepath: out_freepath:
kfree(path); ceph_mdsc_free_path(path, pathlen);
} }
out_err: out_err:

View File

@ -492,6 +492,12 @@ extern int ceph_iterate_session_caps(struct ceph_mds_session *session,
void *arg); void *arg);
extern void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc); 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, extern char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
int stop_on_nosnap); int stop_on_nosnap);