aboutsummaryrefslogtreecommitdiffstats
path: root/fs/kernfs/dir.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2016-08-10 11:23:44 -0400
committerTejun Heo <tj@kernel.org>2016-08-10 11:23:44 -0400
commit3abb1d90f5d930c6183534a624aa0158a71bc5eb (patch)
tree62543ceb8d76287bf17c84ad1d756a29b4beb29c /fs/kernfs/dir.c
parent0e0b2afdf644aa523f5eb10ce1f9e3c6cd8362ec (diff)
kernfs: make kernfs_path*() behave in the style of strlcpy()
kernfs_path*() functions always return the length of the full path but the path content is undefined if the length is larger than the provided buffer. This makes its behavior different from strlcpy() and requires error handling in all its users even when they don't care about truncation. In addition, the implementation can actully be simplified by making it behave properly in strlcpy() style. * Update kernfs_path_from_node_locked() to always fill up the buffer with path. If the buffer is not large enough, the output is truncated and terminated. * kernfs_path() no longer needs error handling. Make it a simple inline wrapper around kernfs_path_from_node(). * sysfs_warn_dup()'s use of kernfs_path() doesn't need error handling. Updated accordingly. * cgroup_path()'s use of kernfs_path() updated to retain the old behavior. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Acked-by: Serge Hallyn <serge.hallyn@ubuntu.com>
Diffstat (limited to 'fs/kernfs/dir.c')
-rw-r--r--fs/kernfs/dir.c61
1 files changed, 17 insertions, 44 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index e57174d43683..09242aaa8829 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -110,8 +110,9 @@ static struct kernfs_node *kernfs_common_ancestor(struct kernfs_node *a,
110 * kn_to: /n1/n2/n3 [depth=3] 110 * kn_to: /n1/n2/n3 [depth=3]
111 * result: /../.. 111 * result: /../..
112 * 112 *
113 * return value: length of the string. If greater than buflen, 113 * Returns the length of the full path. If the full length is equal to or
114 * then contents of buf are undefined. On error, -1 is returned. 114 * greater than @buflen, @buf contains the truncated path with the trailing
115 * '\0'. On error, -errno is returned.
115 */ 116 */
116static int kernfs_path_from_node_locked(struct kernfs_node *kn_to, 117static int kernfs_path_from_node_locked(struct kernfs_node *kn_to,
117 struct kernfs_node *kn_from, 118 struct kernfs_node *kn_from,
@@ -119,9 +120,8 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to,
119{ 120{
120 struct kernfs_node *kn, *common; 121 struct kernfs_node *kn, *common;
121 const char parent_str[] = "/.."; 122 const char parent_str[] = "/..";
122 size_t depth_from, depth_to, len = 0, nlen = 0; 123 size_t depth_from, depth_to, len = 0;
123 char *p; 124 int i, j;
124 int i;
125 125
126 if (!kn_from) 126 if (!kn_from)
127 kn_from = kernfs_root(kn_to)->kn; 127 kn_from = kernfs_root(kn_to)->kn;
@@ -131,7 +131,7 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to,
131 131
132 common = kernfs_common_ancestor(kn_from, kn_to); 132 common = kernfs_common_ancestor(kn_from, kn_to);
133 if (WARN_ON(!common)) 133 if (WARN_ON(!common))
134 return -1; 134 return -EINVAL;
135 135
136 depth_to = kernfs_depth(common, kn_to); 136 depth_to = kernfs_depth(common, kn_to);
137 depth_from = kernfs_depth(common, kn_from); 137 depth_from = kernfs_depth(common, kn_from);
@@ -144,22 +144,16 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to,
144 len < buflen ? buflen - len : 0); 144 len < buflen ? buflen - len : 0);
145 145
146 /* Calculate how many bytes we need for the rest */ 146 /* Calculate how many bytes we need for the rest */
147 for (kn = kn_to; kn != common; kn = kn->parent) 147 for (i = depth_to - 1; i >= 0; i--) {
148 nlen += strlen(kn->name) + 1; 148 for (kn = kn_to, j = 0; j < i; j++)
149 149 kn = kn->parent;
150 if (len + nlen >= buflen) 150 len += strlcpy(buf + len, "/",
151 return len + nlen; 151 len < buflen ? buflen - len : 0);
152 152 len += strlcpy(buf + len, kn->name,
153 p = buf + len + nlen; 153 len < buflen ? buflen - len : 0);
154 *p = '\0';
155 for (kn = kn_to; kn != common; kn = kn->parent) {
156 size_t tmp = strlen(kn->name);
157 p -= tmp;
158 memcpy(p, kn->name, tmp);
159 *(--p) = '/';
160 } 154 }
161 155
162 return len + nlen; 156 return len;
163} 157}
164 158
165/** 159/**
@@ -220,8 +214,9 @@ size_t kernfs_path_len(struct kernfs_node *kn)
220 * path (which includes '..'s) as needed to reach from @from to @to is 214 * path (which includes '..'s) as needed to reach from @from to @to is
221 * returned. 215 * returned.
222 * 216 *
223 * If @buf isn't long enough, the return value will be greater than @buflen 217 * Returns the length of the full path. If the full length is equal to or
224 * and @buf contents are undefined. 218 * greater than @buflen, @buf contains the truncated path with the trailing
219 * '\0'. On error, -errno is returned.
225 */ 220 */
226int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from, 221int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from,
227 char *buf, size_t buflen) 222 char *buf, size_t buflen)
@@ -237,28 +232,6 @@ int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from,
237EXPORT_SYMBOL_GPL(kernfs_path_from_node); 232EXPORT_SYMBOL_GPL(kernfs_path_from_node);
238 233
239/** 234/**
240 * kernfs_path - build full path of a given node
241 * @kn: kernfs_node of interest
242 * @buf: buffer to copy @kn's name into
243 * @buflen: size of @buf
244 *
245 * Builds and returns the full path of @kn in @buf of @buflen bytes. The
246 * path is built from the end of @buf so the returned pointer usually
247 * doesn't match @buf. If @buf isn't long enough, @buf is nul terminated
248 * and %NULL is returned.
249 */
250char *kernfs_path(struct kernfs_node *kn, char *buf, size_t buflen)
251{
252 int ret;
253
254 ret = kernfs_path_from_node(kn, NULL, buf, buflen);
255 if (ret < 0 || ret >= buflen)
256 return NULL;
257 return buf;
258}
259EXPORT_SYMBOL_GPL(kernfs_path);
260
261/**
262 * pr_cont_kernfs_name - pr_cont name of a kernfs_node 235 * pr_cont_kernfs_name - pr_cont name of a kernfs_node
263 * @kn: kernfs_node of interest 236 * @kn: kernfs_node of interest
264 * 237 *