Skip to content

Commit

Permalink
ceph: use __getname/__putname in ceph_mdsc_build_path
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Jeff Layton <[email protected]>
Reviewed-by: "Yan, Zheng" <[email protected]>
Signed-off-by: Ilya Dryomov <[email protected]>
  • Loading branch information
jtlayton authored and idryomov committed May 7, 2019
1 parent 964fff7 commit f77f21b
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 39 deletions.
4 changes: 2 additions & 2 deletions fs/ceph/debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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,
Expand Down
65 changes: 28 additions & 37 deletions fs/ceph/mds_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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,
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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:
Expand Down
6 changes: 6 additions & 0 deletions fs/ceph/mds_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit f77f21b

Please sign in to comment.