diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-14 15:18:50 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-14 15:18:50 -0400 |
commit | f34d3606f76a8121b9d4940d2dd436bebeb2f9d7 (patch) | |
tree | 61a9deb6a950568df274580fbbd44a7015af9f7c /fs/kernfs/dir.c | |
parent | b6daa51b9a6a02a644dcf6b880fd50c1f70ec07f (diff) | |
parent | bbb427e342495df1cda10051d0566388697499c0 (diff) |
Merge branch 'for-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
Pull cgroup updates from Tejun Heo:
- tracepoints for basic cgroup management operations added
- kernfs and cgroup path formatting functions updated to behave in the
style of strlcpy()
- non-critical bug fixes
* 'for-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup:
blkcg: Unlock blkcg_pol_mutex only once when cpd == NULL
cgroup: fix error handling regressions in proc_cgroup_show() and cgroup_release_agent()
cpuset: fix error handling regression in proc_cpuset_show()
cgroup: add tracepoints for basic operations
cgroup: make cgroup_path() and friends behave in the style of strlcpy()
kernfs: remove kernfs_path_len()
kernfs: make kernfs_path*() behave in the style of strlcpy()
kernfs: add dummy implementation of kernfs_path_from_node()
Diffstat (limited to 'fs/kernfs/dir.c')
-rw-r--r-- | fs/kernfs/dir.c | 84 |
1 files changed, 17 insertions, 67 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index dcd96aac02f5..cf4c636ff4da 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 | */ |
116 | static int kernfs_path_from_node_locked(struct kernfs_node *kn_to, | 117 | static 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 | /** |
@@ -186,29 +180,6 @@ int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen) | |||
186 | } | 180 | } |
187 | 181 | ||
188 | /** | 182 | /** |
189 | * kernfs_path_len - determine the length of the full path of a given node | ||
190 | * @kn: kernfs_node of interest | ||
191 | * | ||
192 | * The returned length doesn't include the space for the terminating '\0'. | ||
193 | */ | ||
194 | size_t kernfs_path_len(struct kernfs_node *kn) | ||
195 | { | ||
196 | size_t len = 0; | ||
197 | unsigned long flags; | ||
198 | |||
199 | spin_lock_irqsave(&kernfs_rename_lock, flags); | ||
200 | |||
201 | do { | ||
202 | len += strlen(kn->name) + 1; | ||
203 | kn = kn->parent; | ||
204 | } while (kn && kn->parent); | ||
205 | |||
206 | spin_unlock_irqrestore(&kernfs_rename_lock, flags); | ||
207 | |||
208 | return len; | ||
209 | } | ||
210 | |||
211 | /** | ||
212 | * kernfs_path_from_node - build path of node @to relative to @from. | 183 | * kernfs_path_from_node - build path of node @to relative to @from. |
213 | * @from: parent kernfs_node relative to which we need to build the path | 184 | * @from: parent kernfs_node relative to which we need to build the path |
214 | * @to: kernfs_node of interest | 185 | * @to: kernfs_node of interest |
@@ -220,8 +191,9 @@ size_t kernfs_path_len(struct kernfs_node *kn) | |||
220 | * path (which includes '..'s) as needed to reach from @from to @to is | 191 | * path (which includes '..'s) as needed to reach from @from to @to is |
221 | * returned. | 192 | * returned. |
222 | * | 193 | * |
223 | * If @buf isn't long enough, the return value will be greater than @buflen | 194 | * Returns the length of the full path. If the full length is equal to or |
224 | * and @buf contents are undefined. | 195 | * greater than @buflen, @buf contains the truncated path with the trailing |
196 | * '\0'. On error, -errno is returned. | ||
225 | */ | 197 | */ |
226 | int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from, | 198 | int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from, |
227 | char *buf, size_t buflen) | 199 | char *buf, size_t buflen) |
@@ -237,28 +209,6 @@ int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from, | |||
237 | EXPORT_SYMBOL_GPL(kernfs_path_from_node); | 209 | EXPORT_SYMBOL_GPL(kernfs_path_from_node); |
238 | 210 | ||
239 | /** | 211 | /** |
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 | */ | ||
250 | char *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 | } | ||
259 | EXPORT_SYMBOL_GPL(kernfs_path); | ||
260 | |||
261 | /** | ||
262 | * pr_cont_kernfs_name - pr_cont name of a kernfs_node | 212 | * pr_cont_kernfs_name - pr_cont name of a kernfs_node |
263 | * @kn: kernfs_node of interest | 213 | * @kn: kernfs_node of interest |
264 | * | 214 | * |