aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Layton <jlayton@kernel.org>2019-04-29 12:13:14 -0400
committerIlya Dryomov <idryomov@gmail.com>2019-05-07 13:22:37 -0400
commitf77f21bb28367d0ac4861a24da1db118bba850e6 (patch)
tree09381ee5d6fac1e444a8795da70eb08fe4ce551d
parent964fff7491e4923e18ff08f2a254c4b94e3f83d6 (diff)
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>
-rw-r--r--fs/ceph/debugfs.c4
-rw-r--r--fs/ceph/mds_client.c65
-rw-r--r--fs/ceph/mds_client.h6
3 files changed, 36 insertions, 39 deletions
diff --git a/fs/ceph/debugfs.c b/fs/ceph/debugfs.c
index 777f6ceb5259..b014fc7d4e3c 100644
--- a/fs/ceph/debugfs.c
+++ b/fs/ceph/debugfs.c
@@ -88,7 +88,7 @@ static int mdsc_show(struct seq_file *s, void *p)
88 req->r_dentry, 88 req->r_dentry,
89 path ? path : ""); 89 path ? path : "");
90 spin_unlock(&req->r_dentry->d_lock); 90 spin_unlock(&req->r_dentry->d_lock);
91 kfree(path); 91 ceph_mdsc_free_path(path, pathlen);
92 } else if (req->r_path1) { 92 } else if (req->r_path1) {
93 seq_printf(s, " #%llx/%s", req->r_ino1.ino, 93 seq_printf(s, " #%llx/%s", req->r_ino1.ino,
94 req->r_path1); 94 req->r_path1);
@@ -108,7 +108,7 @@ static int mdsc_show(struct seq_file *s, void *p)
108 req->r_old_dentry, 108 req->r_old_dentry,
109 path ? path : ""); 109 path ? path : "");
110 spin_unlock(&req->r_old_dentry->d_lock); 110 spin_unlock(&req->r_old_dentry->d_lock);
111 kfree(path); 111 ceph_mdsc_free_path(path, pathlen);
112 } else if (req->r_path2 && req->r_op != CEPH_MDS_OP_SYMLINK) { 112 } else if (req->r_path2 && req->r_op != CEPH_MDS_OP_SYMLINK) {
113 if (req->r_ino2.ino) 113 if (req->r_ino2.ino)
114 seq_printf(s, " #%llx/%s", req->r_ino2.ino, 114 seq_printf(s, " #%llx/%s", req->r_ino2.ino,
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 7af722834348..d29f6c094f7c 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -2094,39 +2094,24 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *pbase,
2094{ 2094{
2095 struct dentry *temp; 2095 struct dentry *temp;
2096 char *path; 2096 char *path;
2097 int len, pos; 2097 int pos;
2098 unsigned seq; 2098 unsigned seq;
2099 u64 base; 2099 u64 base;
2100 2100
2101 if (!dentry) 2101 if (!dentry)
2102 return ERR_PTR(-EINVAL); 2102 return ERR_PTR(-EINVAL);
2103 2103
2104retry: 2104 path = __getname();
2105 len = 0;
2106 seq = read_seqbegin(&rename_lock);
2107 rcu_read_lock();
2108 for (temp = dentry; !IS_ROOT(temp);) {
2109 struct inode *inode = d_inode(temp);
2110 if (inode && ceph_snap(inode) == CEPH_SNAPDIR)
2111 len++; /* slash only */
2112 else if (stop_on_nosnap && inode &&
2113 ceph_snap(inode) == CEPH_NOSNAP)
2114 break;
2115 else
2116 len += 1 + temp->d_name.len;
2117 temp = temp->d_parent;
2118 }
2119 rcu_read_unlock();
2120 if (len)
2121 len--; /* no leading '/' */
2122
2123 path = kmalloc(len+1, GFP_NOFS);
2124 if (!path) 2105 if (!path)
2125 return ERR_PTR(-ENOMEM); 2106 return ERR_PTR(-ENOMEM);
2126 pos = len; 2107retry:
2127 path[pos] = 0; /* trailing null */ 2108 pos = PATH_MAX - 1;
2109 path[pos] = '\0';
2110
2111 seq = read_seqbegin(&rename_lock);
2128 rcu_read_lock(); 2112 rcu_read_lock();
2129 for (temp = dentry; !IS_ROOT(temp) && pos != 0; ) { 2113 temp = dentry;
2114 for (;;) {
2130 struct inode *inode; 2115 struct inode *inode;
2131 2116
2132 spin_lock(&temp->d_lock); 2117 spin_lock(&temp->d_lock);
@@ -2144,32 +2129,38 @@ retry:
2144 spin_unlock(&temp->d_lock); 2129 spin_unlock(&temp->d_lock);
2145 break; 2130 break;
2146 } 2131 }
2147 strncpy(path + pos, temp->d_name.name, 2132 memcpy(path + pos, temp->d_name.name, temp->d_name.len);
2148 temp->d_name.len);
2149 } 2133 }
2150 spin_unlock(&temp->d_lock); 2134 spin_unlock(&temp->d_lock);
2151 if (pos)
2152 path[--pos] = '/';
2153 temp = temp->d_parent; 2135 temp = temp->d_parent;
2136
2137 /* Are we at the root? */
2138 if (IS_ROOT(temp))
2139 break;
2140
2141 /* Are we out of buffer? */
2142 if (--pos < 0)
2143 break;
2144
2145 path[pos] = '/';
2154 } 2146 }
2155 base = ceph_ino(d_inode(temp)); 2147 base = ceph_ino(d_inode(temp));
2156 rcu_read_unlock(); 2148 rcu_read_unlock();
2157 if (pos != 0 || read_seqretry(&rename_lock, seq)) { 2149 if (pos < 0 || read_seqretry(&rename_lock, seq)) {
2158 pr_err("build_path did not end path lookup where " 2150 pr_err("build_path did not end path lookup where "
2159 "expected, namelen is %d, pos is %d\n", len, pos); 2151 "expected, pos is %d\n", pos);
2160 /* presumably this is only possible if racing with a 2152 /* presumably this is only possible if racing with a
2161 rename of one of the parent directories (we can not 2153 rename of one of the parent directories (we can not
2162 lock the dentries above us to prevent this, but 2154 lock the dentries above us to prevent this, but
2163 retrying should be harmless) */ 2155 retrying should be harmless) */
2164 kfree(path);
2165 goto retry; 2156 goto retry;
2166 } 2157 }
2167 2158
2168 *pbase = base; 2159 *pbase = base;
2169 *plen = len; 2160 *plen = PATH_MAX - 1 - pos;
2170 dout("build_path on %p %d built %llx '%.*s'\n", 2161 dout("build_path on %p %d built %llx '%.*s'\n",
2171 dentry, d_count(dentry), base, len, path); 2162 dentry, d_count(dentry), base, *plen, path + pos);
2172 return path; 2163 return path + pos;
2173} 2164}
2174 2165
2175static int build_dentry_path(struct dentry *dentry, struct inode *dir, 2166static 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,
2376 2367
2377out_free2: 2368out_free2:
2378 if (freepath2) 2369 if (freepath2)
2379 kfree((char *)path2); 2370 ceph_mdsc_free_path((char *)path2, pathlen2);
2380out_free1: 2371out_free1:
2381 if (freepath1) 2372 if (freepath1)
2382 kfree((char *)path1); 2373 ceph_mdsc_free_path((char *)path1, pathlen1);
2383out: 2374out:
2384 return msg; 2375 return msg;
2385} 2376}
@@ -3451,7 +3442,7 @@ out_freeflocks:
3451 ceph_pagelist_encode_string(pagelist, path, pathlen); 3442 ceph_pagelist_encode_string(pagelist, path, pathlen);
3452 ceph_pagelist_append(pagelist, &rec, sizeof(rec.v1)); 3443 ceph_pagelist_append(pagelist, &rec, sizeof(rec.v1));
3453out_freepath: 3444out_freepath:
3454 kfree(path); 3445 ceph_mdsc_free_path(path, pathlen);
3455 } 3446 }
3456 3447
3457out_err: 3448out_err:
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h
index 0d1f673a5689..ebcad5afc87b 100644
--- a/fs/ceph/mds_client.h
+++ b/fs/ceph/mds_client.h
@@ -492,6 +492,12 @@ extern int ceph_iterate_session_caps(struct ceph_mds_session *session,
492 void *arg); 492 void *arg);
493extern void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc); 493extern void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc);
494 494
495static inline void ceph_mdsc_free_path(char *path, int len)
496{
497 if (path)
498 __putname(path - (PATH_MAX - 1 - len));
499}
500
495extern char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base, 501extern char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
496 int stop_on_nosnap); 502 int stop_on_nosnap);
497 503