diff options
Diffstat (limited to 'fs/debugfs/file.c')
-rw-r--r-- | fs/debugfs/file.c | 436 |
1 files changed, 370 insertions, 66 deletions
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index d2ba12e23ed9..9c1c9a01b7e5 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c | |||
@@ -22,6 +22,12 @@ | |||
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/atomic.h> | 23 | #include <linux/atomic.h> |
24 | #include <linux/device.h> | 24 | #include <linux/device.h> |
25 | #include <linux/srcu.h> | ||
26 | #include <asm/poll.h> | ||
27 | |||
28 | #include "internal.h" | ||
29 | |||
30 | struct poll_table_struct; | ||
25 | 31 | ||
26 | static ssize_t default_read_file(struct file *file, char __user *buf, | 32 | static ssize_t default_read_file(struct file *file, char __user *buf, |
27 | size_t count, loff_t *ppos) | 33 | size_t count, loff_t *ppos) |
@@ -35,27 +41,293 @@ static ssize_t default_write_file(struct file *file, const char __user *buf, | |||
35 | return count; | 41 | return count; |
36 | } | 42 | } |
37 | 43 | ||
38 | const struct file_operations debugfs_file_operations = { | 44 | const struct file_operations debugfs_noop_file_operations = { |
39 | .read = default_read_file, | 45 | .read = default_read_file, |
40 | .write = default_write_file, | 46 | .write = default_write_file, |
41 | .open = simple_open, | 47 | .open = simple_open, |
42 | .llseek = noop_llseek, | 48 | .llseek = noop_llseek, |
43 | }; | 49 | }; |
44 | 50 | ||
45 | static struct dentry *debugfs_create_mode(const char *name, umode_t mode, | 51 | /** |
46 | struct dentry *parent, void *value, | 52 | * debugfs_use_file_start - mark the beginning of file data access |
47 | const struct file_operations *fops, | 53 | * @dentry: the dentry object whose data is being accessed. |
48 | const struct file_operations *fops_ro, | 54 | * @srcu_idx: a pointer to some memory to store a SRCU index in. |
49 | const struct file_operations *fops_wo) | 55 | * |
56 | * Up to a matching call to debugfs_use_file_finish(), any | ||
57 | * successive call into the file removing functions debugfs_remove() | ||
58 | * and debugfs_remove_recursive() will block. Since associated private | ||
59 | * file data may only get freed after a successful return of any of | ||
60 | * the removal functions, you may safely access it after a successful | ||
61 | * call to debugfs_use_file_start() without worrying about | ||
62 | * lifetime issues. | ||
63 | * | ||
64 | * If -%EIO is returned, the file has already been removed and thus, | ||
65 | * it is not safe to access any of its data. If, on the other hand, | ||
66 | * it is allowed to access the file data, zero is returned. | ||
67 | * | ||
68 | * Regardless of the return code, any call to | ||
69 | * debugfs_use_file_start() must be followed by a matching call | ||
70 | * to debugfs_use_file_finish(). | ||
71 | */ | ||
72 | int debugfs_use_file_start(const struct dentry *dentry, int *srcu_idx) | ||
73 | __acquires(&debugfs_srcu) | ||
74 | { | ||
75 | *srcu_idx = srcu_read_lock(&debugfs_srcu); | ||
76 | barrier(); | ||
77 | if (d_unlinked(dentry)) | ||
78 | return -EIO; | ||
79 | return 0; | ||
80 | } | ||
81 | EXPORT_SYMBOL_GPL(debugfs_use_file_start); | ||
82 | |||
83 | /** | ||
84 | * debugfs_use_file_finish - mark the end of file data access | ||
85 | * @srcu_idx: the SRCU index "created" by a former call to | ||
86 | * debugfs_use_file_start(). | ||
87 | * | ||
88 | * Allow any ongoing concurrent call into debugfs_remove() or | ||
89 | * debugfs_remove_recursive() blocked by a former call to | ||
90 | * debugfs_use_file_start() to proceed and return to its caller. | ||
91 | */ | ||
92 | void debugfs_use_file_finish(int srcu_idx) __releases(&debugfs_srcu) | ||
93 | { | ||
94 | srcu_read_unlock(&debugfs_srcu, srcu_idx); | ||
95 | } | ||
96 | EXPORT_SYMBOL_GPL(debugfs_use_file_finish); | ||
97 | |||
98 | #define F_DENTRY(filp) ((filp)->f_path.dentry) | ||
99 | |||
100 | #define REAL_FOPS_DEREF(dentry) \ | ||
101 | ((const struct file_operations *)(dentry)->d_fsdata) | ||
102 | |||
103 | static int open_proxy_open(struct inode *inode, struct file *filp) | ||
104 | { | ||
105 | const struct dentry *dentry = F_DENTRY(filp); | ||
106 | const struct file_operations *real_fops = NULL; | ||
107 | int srcu_idx, r; | ||
108 | |||
109 | r = debugfs_use_file_start(dentry, &srcu_idx); | ||
110 | if (r) { | ||
111 | r = -ENOENT; | ||
112 | goto out; | ||
113 | } | ||
114 | |||
115 | real_fops = REAL_FOPS_DEREF(dentry); | ||
116 | real_fops = fops_get(real_fops); | ||
117 | if (!real_fops) { | ||
118 | /* Huh? Module did not clean up after itself at exit? */ | ||
119 | WARN(1, "debugfs file owner did not clean up at exit: %pd", | ||
120 | dentry); | ||
121 | r = -ENXIO; | ||
122 | goto out; | ||
123 | } | ||
124 | replace_fops(filp, real_fops); | ||
125 | |||
126 | if (real_fops->open) | ||
127 | r = real_fops->open(inode, filp); | ||
128 | |||
129 | out: | ||
130 | fops_put(real_fops); | ||
131 | debugfs_use_file_finish(srcu_idx); | ||
132 | return r; | ||
133 | } | ||
134 | |||
135 | const struct file_operations debugfs_open_proxy_file_operations = { | ||
136 | .open = open_proxy_open, | ||
137 | }; | ||
138 | |||
139 | #define PROTO(args...) args | ||
140 | #define ARGS(args...) args | ||
141 | |||
142 | #define FULL_PROXY_FUNC(name, ret_type, filp, proto, args) \ | ||
143 | static ret_type full_proxy_ ## name(proto) \ | ||
144 | { \ | ||
145 | const struct dentry *dentry = F_DENTRY(filp); \ | ||
146 | const struct file_operations *real_fops = \ | ||
147 | REAL_FOPS_DEREF(dentry); \ | ||
148 | int srcu_idx; \ | ||
149 | ret_type r; \ | ||
150 | \ | ||
151 | r = debugfs_use_file_start(dentry, &srcu_idx); \ | ||
152 | if (likely(!r)) \ | ||
153 | r = real_fops->name(args); \ | ||
154 | debugfs_use_file_finish(srcu_idx); \ | ||
155 | return r; \ | ||
156 | } | ||
157 | |||
158 | FULL_PROXY_FUNC(llseek, loff_t, filp, | ||
159 | PROTO(struct file *filp, loff_t offset, int whence), | ||
160 | ARGS(filp, offset, whence)); | ||
161 | |||
162 | FULL_PROXY_FUNC(read, ssize_t, filp, | ||
163 | PROTO(struct file *filp, char __user *buf, size_t size, | ||
164 | loff_t *ppos), | ||
165 | ARGS(filp, buf, size, ppos)); | ||
166 | |||
167 | FULL_PROXY_FUNC(write, ssize_t, filp, | ||
168 | PROTO(struct file *filp, const char __user *buf, size_t size, | ||
169 | loff_t *ppos), | ||
170 | ARGS(filp, buf, size, ppos)); | ||
171 | |||
172 | FULL_PROXY_FUNC(unlocked_ioctl, long, filp, | ||
173 | PROTO(struct file *filp, unsigned int cmd, unsigned long arg), | ||
174 | ARGS(filp, cmd, arg)); | ||
175 | |||
176 | static unsigned int full_proxy_poll(struct file *filp, | ||
177 | struct poll_table_struct *wait) | ||
178 | { | ||
179 | const struct dentry *dentry = F_DENTRY(filp); | ||
180 | const struct file_operations *real_fops = REAL_FOPS_DEREF(dentry); | ||
181 | int srcu_idx; | ||
182 | unsigned int r = 0; | ||
183 | |||
184 | if (debugfs_use_file_start(dentry, &srcu_idx)) { | ||
185 | debugfs_use_file_finish(srcu_idx); | ||
186 | return POLLHUP; | ||
187 | } | ||
188 | |||
189 | r = real_fops->poll(filp, wait); | ||
190 | debugfs_use_file_finish(srcu_idx); | ||
191 | return r; | ||
192 | } | ||
193 | |||
194 | static int full_proxy_release(struct inode *inode, struct file *filp) | ||
195 | { | ||
196 | const struct dentry *dentry = F_DENTRY(filp); | ||
197 | const struct file_operations *real_fops = REAL_FOPS_DEREF(dentry); | ||
198 | const struct file_operations *proxy_fops = filp->f_op; | ||
199 | int r = 0; | ||
200 | |||
201 | /* | ||
202 | * We must not protect this against removal races here: the | ||
203 | * original releaser should be called unconditionally in order | ||
204 | * not to leak any resources. Releasers must not assume that | ||
205 | * ->i_private is still being meaningful here. | ||
206 | */ | ||
207 | if (real_fops->release) | ||
208 | r = real_fops->release(inode, filp); | ||
209 | |||
210 | replace_fops(filp, d_inode(dentry)->i_fop); | ||
211 | kfree((void *)proxy_fops); | ||
212 | fops_put(real_fops); | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static void __full_proxy_fops_init(struct file_operations *proxy_fops, | ||
217 | const struct file_operations *real_fops) | ||
218 | { | ||
219 | proxy_fops->release = full_proxy_release; | ||
220 | if (real_fops->llseek) | ||
221 | proxy_fops->llseek = full_proxy_llseek; | ||
222 | if (real_fops->read) | ||
223 | proxy_fops->read = full_proxy_read; | ||
224 | if (real_fops->write) | ||
225 | proxy_fops->write = full_proxy_write; | ||
226 | if (real_fops->poll) | ||
227 | proxy_fops->poll = full_proxy_poll; | ||
228 | if (real_fops->unlocked_ioctl) | ||
229 | proxy_fops->unlocked_ioctl = full_proxy_unlocked_ioctl; | ||
230 | } | ||
231 | |||
232 | static int full_proxy_open(struct inode *inode, struct file *filp) | ||
233 | { | ||
234 | const struct dentry *dentry = F_DENTRY(filp); | ||
235 | const struct file_operations *real_fops = NULL; | ||
236 | struct file_operations *proxy_fops = NULL; | ||
237 | int srcu_idx, r; | ||
238 | |||
239 | r = debugfs_use_file_start(dentry, &srcu_idx); | ||
240 | if (r) { | ||
241 | r = -ENOENT; | ||
242 | goto out; | ||
243 | } | ||
244 | |||
245 | real_fops = REAL_FOPS_DEREF(dentry); | ||
246 | real_fops = fops_get(real_fops); | ||
247 | if (!real_fops) { | ||
248 | /* Huh? Module did not cleanup after itself at exit? */ | ||
249 | WARN(1, "debugfs file owner did not clean up at exit: %pd", | ||
250 | dentry); | ||
251 | r = -ENXIO; | ||
252 | goto out; | ||
253 | } | ||
254 | |||
255 | proxy_fops = kzalloc(sizeof(*proxy_fops), GFP_KERNEL); | ||
256 | if (!proxy_fops) { | ||
257 | r = -ENOMEM; | ||
258 | goto free_proxy; | ||
259 | } | ||
260 | __full_proxy_fops_init(proxy_fops, real_fops); | ||
261 | replace_fops(filp, proxy_fops); | ||
262 | |||
263 | if (real_fops->open) { | ||
264 | r = real_fops->open(inode, filp); | ||
265 | |||
266 | if (filp->f_op != proxy_fops) { | ||
267 | /* No protection against file removal anymore. */ | ||
268 | WARN(1, "debugfs file owner replaced proxy fops: %pd", | ||
269 | dentry); | ||
270 | goto free_proxy; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | goto out; | ||
275 | free_proxy: | ||
276 | kfree(proxy_fops); | ||
277 | fops_put(real_fops); | ||
278 | out: | ||
279 | debugfs_use_file_finish(srcu_idx); | ||
280 | return r; | ||
281 | } | ||
282 | |||
283 | const struct file_operations debugfs_full_proxy_file_operations = { | ||
284 | .open = full_proxy_open, | ||
285 | }; | ||
286 | |||
287 | ssize_t debugfs_attr_read(struct file *file, char __user *buf, | ||
288 | size_t len, loff_t *ppos) | ||
289 | { | ||
290 | ssize_t ret; | ||
291 | int srcu_idx; | ||
292 | |||
293 | ret = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); | ||
294 | if (likely(!ret)) | ||
295 | ret = simple_attr_read(file, buf, len, ppos); | ||
296 | debugfs_use_file_finish(srcu_idx); | ||
297 | return ret; | ||
298 | } | ||
299 | EXPORT_SYMBOL_GPL(debugfs_attr_read); | ||
300 | |||
301 | ssize_t debugfs_attr_write(struct file *file, const char __user *buf, | ||
302 | size_t len, loff_t *ppos) | ||
303 | { | ||
304 | ssize_t ret; | ||
305 | int srcu_idx; | ||
306 | |||
307 | ret = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); | ||
308 | if (likely(!ret)) | ||
309 | ret = simple_attr_write(file, buf, len, ppos); | ||
310 | debugfs_use_file_finish(srcu_idx); | ||
311 | return ret; | ||
312 | } | ||
313 | EXPORT_SYMBOL_GPL(debugfs_attr_write); | ||
314 | |||
315 | static struct dentry *debugfs_create_mode_unsafe(const char *name, umode_t mode, | ||
316 | struct dentry *parent, void *value, | ||
317 | const struct file_operations *fops, | ||
318 | const struct file_operations *fops_ro, | ||
319 | const struct file_operations *fops_wo) | ||
50 | { | 320 | { |
51 | /* if there are no write bits set, make read only */ | 321 | /* if there are no write bits set, make read only */ |
52 | if (!(mode & S_IWUGO)) | 322 | if (!(mode & S_IWUGO)) |
53 | return debugfs_create_file(name, mode, parent, value, fops_ro); | 323 | return debugfs_create_file_unsafe(name, mode, parent, value, |
324 | fops_ro); | ||
54 | /* if there are no read bits set, make write only */ | 325 | /* if there are no read bits set, make write only */ |
55 | if (!(mode & S_IRUGO)) | 326 | if (!(mode & S_IRUGO)) |
56 | return debugfs_create_file(name, mode, parent, value, fops_wo); | 327 | return debugfs_create_file_unsafe(name, mode, parent, value, |
328 | fops_wo); | ||
57 | 329 | ||
58 | return debugfs_create_file(name, mode, parent, value, fops); | 330 | return debugfs_create_file_unsafe(name, mode, parent, value, fops); |
59 | } | 331 | } |
60 | 332 | ||
61 | static int debugfs_u8_set(void *data, u64 val) | 333 | static int debugfs_u8_set(void *data, u64 val) |
@@ -68,9 +340,9 @@ static int debugfs_u8_get(void *data, u64 *val) | |||
68 | *val = *(u8 *)data; | 340 | *val = *(u8 *)data; |
69 | return 0; | 341 | return 0; |
70 | } | 342 | } |
71 | DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n"); | 343 | DEFINE_DEBUGFS_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n"); |
72 | DEFINE_SIMPLE_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, "%llu\n"); | 344 | DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, "%llu\n"); |
73 | DEFINE_SIMPLE_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%llu\n"); | 345 | DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%llu\n"); |
74 | 346 | ||
75 | /** | 347 | /** |
76 | * debugfs_create_u8 - create a debugfs file that is used to read and write an unsigned 8-bit value | 348 | * debugfs_create_u8 - create a debugfs file that is used to read and write an unsigned 8-bit value |
@@ -99,7 +371,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%llu\n"); | |||
99 | struct dentry *debugfs_create_u8(const char *name, umode_t mode, | 371 | struct dentry *debugfs_create_u8(const char *name, umode_t mode, |
100 | struct dentry *parent, u8 *value) | 372 | struct dentry *parent, u8 *value) |
101 | { | 373 | { |
102 | return debugfs_create_mode(name, mode, parent, value, &fops_u8, | 374 | return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u8, |
103 | &fops_u8_ro, &fops_u8_wo); | 375 | &fops_u8_ro, &fops_u8_wo); |
104 | } | 376 | } |
105 | EXPORT_SYMBOL_GPL(debugfs_create_u8); | 377 | EXPORT_SYMBOL_GPL(debugfs_create_u8); |
@@ -114,9 +386,9 @@ static int debugfs_u16_get(void *data, u64 *val) | |||
114 | *val = *(u16 *)data; | 386 | *val = *(u16 *)data; |
115 | return 0; | 387 | return 0; |
116 | } | 388 | } |
117 | DEFINE_SIMPLE_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n"); | 389 | DEFINE_DEBUGFS_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n"); |
118 | DEFINE_SIMPLE_ATTRIBUTE(fops_u16_ro, debugfs_u16_get, NULL, "%llu\n"); | 390 | DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_ro, debugfs_u16_get, NULL, "%llu\n"); |
119 | DEFINE_SIMPLE_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%llu\n"); | 391 | DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%llu\n"); |
120 | 392 | ||
121 | /** | 393 | /** |
122 | * debugfs_create_u16 - create a debugfs file that is used to read and write an unsigned 16-bit value | 394 | * debugfs_create_u16 - create a debugfs file that is used to read and write an unsigned 16-bit value |
@@ -145,7 +417,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%llu\n"); | |||
145 | struct dentry *debugfs_create_u16(const char *name, umode_t mode, | 417 | struct dentry *debugfs_create_u16(const char *name, umode_t mode, |
146 | struct dentry *parent, u16 *value) | 418 | struct dentry *parent, u16 *value) |
147 | { | 419 | { |
148 | return debugfs_create_mode(name, mode, parent, value, &fops_u16, | 420 | return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u16, |
149 | &fops_u16_ro, &fops_u16_wo); | 421 | &fops_u16_ro, &fops_u16_wo); |
150 | } | 422 | } |
151 | EXPORT_SYMBOL_GPL(debugfs_create_u16); | 423 | EXPORT_SYMBOL_GPL(debugfs_create_u16); |
@@ -160,9 +432,9 @@ static int debugfs_u32_get(void *data, u64 *val) | |||
160 | *val = *(u32 *)data; | 432 | *val = *(u32 *)data; |
161 | return 0; | 433 | return 0; |
162 | } | 434 | } |
163 | DEFINE_SIMPLE_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n"); | 435 | DEFINE_DEBUGFS_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n"); |
164 | DEFINE_SIMPLE_ATTRIBUTE(fops_u32_ro, debugfs_u32_get, NULL, "%llu\n"); | 436 | DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_ro, debugfs_u32_get, NULL, "%llu\n"); |
165 | DEFINE_SIMPLE_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%llu\n"); | 437 | DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%llu\n"); |
166 | 438 | ||
167 | /** | 439 | /** |
168 | * debugfs_create_u32 - create a debugfs file that is used to read and write an unsigned 32-bit value | 440 | * debugfs_create_u32 - create a debugfs file that is used to read and write an unsigned 32-bit value |
@@ -191,7 +463,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%llu\n"); | |||
191 | struct dentry *debugfs_create_u32(const char *name, umode_t mode, | 463 | struct dentry *debugfs_create_u32(const char *name, umode_t mode, |
192 | struct dentry *parent, u32 *value) | 464 | struct dentry *parent, u32 *value) |
193 | { | 465 | { |
194 | return debugfs_create_mode(name, mode, parent, value, &fops_u32, | 466 | return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u32, |
195 | &fops_u32_ro, &fops_u32_wo); | 467 | &fops_u32_ro, &fops_u32_wo); |
196 | } | 468 | } |
197 | EXPORT_SYMBOL_GPL(debugfs_create_u32); | 469 | EXPORT_SYMBOL_GPL(debugfs_create_u32); |
@@ -207,9 +479,9 @@ static int debugfs_u64_get(void *data, u64 *val) | |||
207 | *val = *(u64 *)data; | 479 | *val = *(u64 *)data; |
208 | return 0; | 480 | return 0; |
209 | } | 481 | } |
210 | DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n"); | 482 | DEFINE_DEBUGFS_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n"); |
211 | DEFINE_SIMPLE_ATTRIBUTE(fops_u64_ro, debugfs_u64_get, NULL, "%llu\n"); | 483 | DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_ro, debugfs_u64_get, NULL, "%llu\n"); |
212 | DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n"); | 484 | DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n"); |
213 | 485 | ||
214 | /** | 486 | /** |
215 | * debugfs_create_u64 - create a debugfs file that is used to read and write an unsigned 64-bit value | 487 | * debugfs_create_u64 - create a debugfs file that is used to read and write an unsigned 64-bit value |
@@ -238,7 +510,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n"); | |||
238 | struct dentry *debugfs_create_u64(const char *name, umode_t mode, | 510 | struct dentry *debugfs_create_u64(const char *name, umode_t mode, |
239 | struct dentry *parent, u64 *value) | 511 | struct dentry *parent, u64 *value) |
240 | { | 512 | { |
241 | return debugfs_create_mode(name, mode, parent, value, &fops_u64, | 513 | return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u64, |
242 | &fops_u64_ro, &fops_u64_wo); | 514 | &fops_u64_ro, &fops_u64_wo); |
243 | } | 515 | } |
244 | EXPORT_SYMBOL_GPL(debugfs_create_u64); | 516 | EXPORT_SYMBOL_GPL(debugfs_create_u64); |
@@ -254,9 +526,10 @@ static int debugfs_ulong_get(void *data, u64 *val) | |||
254 | *val = *(unsigned long *)data; | 526 | *val = *(unsigned long *)data; |
255 | return 0; | 527 | return 0; |
256 | } | 528 | } |
257 | DEFINE_SIMPLE_ATTRIBUTE(fops_ulong, debugfs_ulong_get, debugfs_ulong_set, "%llu\n"); | 529 | DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong, debugfs_ulong_get, debugfs_ulong_set, |
258 | DEFINE_SIMPLE_ATTRIBUTE(fops_ulong_ro, debugfs_ulong_get, NULL, "%llu\n"); | 530 | "%llu\n"); |
259 | DEFINE_SIMPLE_ATTRIBUTE(fops_ulong_wo, NULL, debugfs_ulong_set, "%llu\n"); | 531 | DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_ro, debugfs_ulong_get, NULL, "%llu\n"); |
532 | DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_wo, NULL, debugfs_ulong_set, "%llu\n"); | ||
260 | 533 | ||
261 | /** | 534 | /** |
262 | * debugfs_create_ulong - create a debugfs file that is used to read and write | 535 | * debugfs_create_ulong - create a debugfs file that is used to read and write |
@@ -286,26 +559,30 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_ulong_wo, NULL, debugfs_ulong_set, "%llu\n"); | |||
286 | struct dentry *debugfs_create_ulong(const char *name, umode_t mode, | 559 | struct dentry *debugfs_create_ulong(const char *name, umode_t mode, |
287 | struct dentry *parent, unsigned long *value) | 560 | struct dentry *parent, unsigned long *value) |
288 | { | 561 | { |
289 | return debugfs_create_mode(name, mode, parent, value, &fops_ulong, | 562 | return debugfs_create_mode_unsafe(name, mode, parent, value, |
290 | &fops_ulong_ro, &fops_ulong_wo); | 563 | &fops_ulong, &fops_ulong_ro, |
564 | &fops_ulong_wo); | ||
291 | } | 565 | } |
292 | EXPORT_SYMBOL_GPL(debugfs_create_ulong); | 566 | EXPORT_SYMBOL_GPL(debugfs_create_ulong); |
293 | 567 | ||
294 | DEFINE_SIMPLE_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%02llx\n"); | 568 | DEFINE_DEBUGFS_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%02llx\n"); |
295 | DEFINE_SIMPLE_ATTRIBUTE(fops_x8_ro, debugfs_u8_get, NULL, "0x%02llx\n"); | 569 | DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_ro, debugfs_u8_get, NULL, "0x%02llx\n"); |
296 | DEFINE_SIMPLE_ATTRIBUTE(fops_x8_wo, NULL, debugfs_u8_set, "0x%02llx\n"); | 570 | DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_wo, NULL, debugfs_u8_set, "0x%02llx\n"); |
297 | 571 | ||
298 | DEFINE_SIMPLE_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%04llx\n"); | 572 | DEFINE_DEBUGFS_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, |
299 | DEFINE_SIMPLE_ATTRIBUTE(fops_x16_ro, debugfs_u16_get, NULL, "0x%04llx\n"); | 573 | "0x%04llx\n"); |
300 | DEFINE_SIMPLE_ATTRIBUTE(fops_x16_wo, NULL, debugfs_u16_set, "0x%04llx\n"); | 574 | DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_ro, debugfs_u16_get, NULL, "0x%04llx\n"); |
575 | DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_wo, NULL, debugfs_u16_set, "0x%04llx\n"); | ||
301 | 576 | ||
302 | DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%08llx\n"); | 577 | DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, |
303 | DEFINE_SIMPLE_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, "0x%08llx\n"); | 578 | "0x%08llx\n"); |
304 | DEFINE_SIMPLE_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, "0x%08llx\n"); | 579 | DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, "0x%08llx\n"); |
580 | DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, "0x%08llx\n"); | ||
305 | 581 | ||
306 | DEFINE_SIMPLE_ATTRIBUTE(fops_x64, debugfs_u64_get, debugfs_u64_set, "0x%016llx\n"); | 582 | DEFINE_DEBUGFS_ATTRIBUTE(fops_x64, debugfs_u64_get, debugfs_u64_set, |
307 | DEFINE_SIMPLE_ATTRIBUTE(fops_x64_ro, debugfs_u64_get, NULL, "0x%016llx\n"); | 583 | "0x%016llx\n"); |
308 | DEFINE_SIMPLE_ATTRIBUTE(fops_x64_wo, NULL, debugfs_u64_set, "0x%016llx\n"); | 584 | DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_ro, debugfs_u64_get, NULL, "0x%016llx\n"); |
585 | DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_wo, NULL, debugfs_u64_set, "0x%016llx\n"); | ||
309 | 586 | ||
310 | /* | 587 | /* |
311 | * debugfs_create_x{8,16,32,64} - create a debugfs file that is used to read and write an unsigned {8,16,32,64}-bit value | 588 | * debugfs_create_x{8,16,32,64} - create a debugfs file that is used to read and write an unsigned {8,16,32,64}-bit value |
@@ -328,7 +605,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_x64_wo, NULL, debugfs_u64_set, "0x%016llx\n"); | |||
328 | struct dentry *debugfs_create_x8(const char *name, umode_t mode, | 605 | struct dentry *debugfs_create_x8(const char *name, umode_t mode, |
329 | struct dentry *parent, u8 *value) | 606 | struct dentry *parent, u8 *value) |
330 | { | 607 | { |
331 | return debugfs_create_mode(name, mode, parent, value, &fops_x8, | 608 | return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x8, |
332 | &fops_x8_ro, &fops_x8_wo); | 609 | &fops_x8_ro, &fops_x8_wo); |
333 | } | 610 | } |
334 | EXPORT_SYMBOL_GPL(debugfs_create_x8); | 611 | EXPORT_SYMBOL_GPL(debugfs_create_x8); |
@@ -346,7 +623,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_x8); | |||
346 | struct dentry *debugfs_create_x16(const char *name, umode_t mode, | 623 | struct dentry *debugfs_create_x16(const char *name, umode_t mode, |
347 | struct dentry *parent, u16 *value) | 624 | struct dentry *parent, u16 *value) |
348 | { | 625 | { |
349 | return debugfs_create_mode(name, mode, parent, value, &fops_x16, | 626 | return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x16, |
350 | &fops_x16_ro, &fops_x16_wo); | 627 | &fops_x16_ro, &fops_x16_wo); |
351 | } | 628 | } |
352 | EXPORT_SYMBOL_GPL(debugfs_create_x16); | 629 | EXPORT_SYMBOL_GPL(debugfs_create_x16); |
@@ -364,7 +641,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_x16); | |||
364 | struct dentry *debugfs_create_x32(const char *name, umode_t mode, | 641 | struct dentry *debugfs_create_x32(const char *name, umode_t mode, |
365 | struct dentry *parent, u32 *value) | 642 | struct dentry *parent, u32 *value) |
366 | { | 643 | { |
367 | return debugfs_create_mode(name, mode, parent, value, &fops_x32, | 644 | return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x32, |
368 | &fops_x32_ro, &fops_x32_wo); | 645 | &fops_x32_ro, &fops_x32_wo); |
369 | } | 646 | } |
370 | EXPORT_SYMBOL_GPL(debugfs_create_x32); | 647 | EXPORT_SYMBOL_GPL(debugfs_create_x32); |
@@ -382,7 +659,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_x32); | |||
382 | struct dentry *debugfs_create_x64(const char *name, umode_t mode, | 659 | struct dentry *debugfs_create_x64(const char *name, umode_t mode, |
383 | struct dentry *parent, u64 *value) | 660 | struct dentry *parent, u64 *value) |
384 | { | 661 | { |
385 | return debugfs_create_mode(name, mode, parent, value, &fops_x64, | 662 | return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x64, |
386 | &fops_x64_ro, &fops_x64_wo); | 663 | &fops_x64_ro, &fops_x64_wo); |
387 | } | 664 | } |
388 | EXPORT_SYMBOL_GPL(debugfs_create_x64); | 665 | EXPORT_SYMBOL_GPL(debugfs_create_x64); |
@@ -398,10 +675,10 @@ static int debugfs_size_t_get(void *data, u64 *val) | |||
398 | *val = *(size_t *)data; | 675 | *val = *(size_t *)data; |
399 | return 0; | 676 | return 0; |
400 | } | 677 | } |
401 | DEFINE_SIMPLE_ATTRIBUTE(fops_size_t, debugfs_size_t_get, debugfs_size_t_set, | 678 | DEFINE_DEBUGFS_ATTRIBUTE(fops_size_t, debugfs_size_t_get, debugfs_size_t_set, |
402 | "%llu\n"); /* %llu and %zu are more or less the same */ | 679 | "%llu\n"); /* %llu and %zu are more or less the same */ |
403 | DEFINE_SIMPLE_ATTRIBUTE(fops_size_t_ro, debugfs_size_t_get, NULL, "%llu\n"); | 680 | DEFINE_DEBUGFS_ATTRIBUTE(fops_size_t_ro, debugfs_size_t_get, NULL, "%llu\n"); |
404 | DEFINE_SIMPLE_ATTRIBUTE(fops_size_t_wo, NULL, debugfs_size_t_set, "%llu\n"); | 681 | DEFINE_DEBUGFS_ATTRIBUTE(fops_size_t_wo, NULL, debugfs_size_t_set, "%llu\n"); |
405 | 682 | ||
406 | /** | 683 | /** |
407 | * debugfs_create_size_t - create a debugfs file that is used to read and write an size_t value | 684 | * debugfs_create_size_t - create a debugfs file that is used to read and write an size_t value |
@@ -416,8 +693,9 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_size_t_wo, NULL, debugfs_size_t_set, "%llu\n"); | |||
416 | struct dentry *debugfs_create_size_t(const char *name, umode_t mode, | 693 | struct dentry *debugfs_create_size_t(const char *name, umode_t mode, |
417 | struct dentry *parent, size_t *value) | 694 | struct dentry *parent, size_t *value) |
418 | { | 695 | { |
419 | return debugfs_create_mode(name, mode, parent, value, &fops_size_t, | 696 | return debugfs_create_mode_unsafe(name, mode, parent, value, |
420 | &fops_size_t_ro, &fops_size_t_wo); | 697 | &fops_size_t, &fops_size_t_ro, |
698 | &fops_size_t_wo); | ||
421 | } | 699 | } |
422 | EXPORT_SYMBOL_GPL(debugfs_create_size_t); | 700 | EXPORT_SYMBOL_GPL(debugfs_create_size_t); |
423 | 701 | ||
@@ -431,10 +709,12 @@ static int debugfs_atomic_t_get(void *data, u64 *val) | |||
431 | *val = atomic_read((atomic_t *)data); | 709 | *val = atomic_read((atomic_t *)data); |
432 | return 0; | 710 | return 0; |
433 | } | 711 | } |
434 | DEFINE_SIMPLE_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get, | 712 | DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get, |
435 | debugfs_atomic_t_set, "%lld\n"); | 713 | debugfs_atomic_t_set, "%lld\n"); |
436 | DEFINE_SIMPLE_ATTRIBUTE(fops_atomic_t_ro, debugfs_atomic_t_get, NULL, "%lld\n"); | 714 | DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_ro, debugfs_atomic_t_get, NULL, |
437 | DEFINE_SIMPLE_ATTRIBUTE(fops_atomic_t_wo, NULL, debugfs_atomic_t_set, "%lld\n"); | 715 | "%lld\n"); |
716 | DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_wo, NULL, debugfs_atomic_t_set, | ||
717 | "%lld\n"); | ||
438 | 718 | ||
439 | /** | 719 | /** |
440 | * debugfs_create_atomic_t - create a debugfs file that is used to read and | 720 | * debugfs_create_atomic_t - create a debugfs file that is used to read and |
@@ -450,8 +730,9 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_atomic_t_wo, NULL, debugfs_atomic_t_set, "%lld\n"); | |||
450 | struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode, | 730 | struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode, |
451 | struct dentry *parent, atomic_t *value) | 731 | struct dentry *parent, atomic_t *value) |
452 | { | 732 | { |
453 | return debugfs_create_mode(name, mode, parent, value, &fops_atomic_t, | 733 | return debugfs_create_mode_unsafe(name, mode, parent, value, |
454 | &fops_atomic_t_ro, &fops_atomic_t_wo); | 734 | &fops_atomic_t, &fops_atomic_t_ro, |
735 | &fops_atomic_t_wo); | ||
455 | } | 736 | } |
456 | EXPORT_SYMBOL_GPL(debugfs_create_atomic_t); | 737 | EXPORT_SYMBOL_GPL(debugfs_create_atomic_t); |
457 | 738 | ||
@@ -459,9 +740,17 @@ ssize_t debugfs_read_file_bool(struct file *file, char __user *user_buf, | |||
459 | size_t count, loff_t *ppos) | 740 | size_t count, loff_t *ppos) |
460 | { | 741 | { |
461 | char buf[3]; | 742 | char buf[3]; |
462 | bool *val = file->private_data; | 743 | bool val; |
744 | int r, srcu_idx; | ||
463 | 745 | ||
464 | if (*val) | 746 | r = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); |
747 | if (likely(!r)) | ||
748 | val = *(bool *)file->private_data; | ||
749 | debugfs_use_file_finish(srcu_idx); | ||
750 | if (r) | ||
751 | return r; | ||
752 | |||
753 | if (val) | ||
465 | buf[0] = 'Y'; | 754 | buf[0] = 'Y'; |
466 | else | 755 | else |
467 | buf[0] = 'N'; | 756 | buf[0] = 'N'; |
@@ -477,6 +766,7 @@ ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf, | |||
477 | char buf[32]; | 766 | char buf[32]; |
478 | size_t buf_size; | 767 | size_t buf_size; |
479 | bool bv; | 768 | bool bv; |
769 | int r, srcu_idx; | ||
480 | bool *val = file->private_data; | 770 | bool *val = file->private_data; |
481 | 771 | ||
482 | buf_size = min(count, (sizeof(buf)-1)); | 772 | buf_size = min(count, (sizeof(buf)-1)); |
@@ -484,8 +774,14 @@ ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf, | |||
484 | return -EFAULT; | 774 | return -EFAULT; |
485 | 775 | ||
486 | buf[buf_size] = '\0'; | 776 | buf[buf_size] = '\0'; |
487 | if (strtobool(buf, &bv) == 0) | 777 | if (strtobool(buf, &bv) == 0) { |
488 | *val = bv; | 778 | r = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); |
779 | if (likely(!r)) | ||
780 | *val = bv; | ||
781 | debugfs_use_file_finish(srcu_idx); | ||
782 | if (r) | ||
783 | return r; | ||
784 | } | ||
489 | 785 | ||
490 | return count; | 786 | return count; |
491 | } | 787 | } |
@@ -537,7 +833,7 @@ static const struct file_operations fops_bool_wo = { | |||
537 | struct dentry *debugfs_create_bool(const char *name, umode_t mode, | 833 | struct dentry *debugfs_create_bool(const char *name, umode_t mode, |
538 | struct dentry *parent, bool *value) | 834 | struct dentry *parent, bool *value) |
539 | { | 835 | { |
540 | return debugfs_create_mode(name, mode, parent, value, &fops_bool, | 836 | return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_bool, |
541 | &fops_bool_ro, &fops_bool_wo); | 837 | &fops_bool_ro, &fops_bool_wo); |
542 | } | 838 | } |
543 | EXPORT_SYMBOL_GPL(debugfs_create_bool); | 839 | EXPORT_SYMBOL_GPL(debugfs_create_bool); |
@@ -546,8 +842,15 @@ static ssize_t read_file_blob(struct file *file, char __user *user_buf, | |||
546 | size_t count, loff_t *ppos) | 842 | size_t count, loff_t *ppos) |
547 | { | 843 | { |
548 | struct debugfs_blob_wrapper *blob = file->private_data; | 844 | struct debugfs_blob_wrapper *blob = file->private_data; |
549 | return simple_read_from_buffer(user_buf, count, ppos, blob->data, | 845 | ssize_t r; |
550 | blob->size); | 846 | int srcu_idx; |
847 | |||
848 | r = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); | ||
849 | if (likely(!r)) | ||
850 | r = simple_read_from_buffer(user_buf, count, ppos, blob->data, | ||
851 | blob->size); | ||
852 | debugfs_use_file_finish(srcu_idx); | ||
853 | return r; | ||
551 | } | 854 | } |
552 | 855 | ||
553 | static const struct file_operations fops_blob = { | 856 | static const struct file_operations fops_blob = { |
@@ -584,7 +887,7 @@ struct dentry *debugfs_create_blob(const char *name, umode_t mode, | |||
584 | struct dentry *parent, | 887 | struct dentry *parent, |
585 | struct debugfs_blob_wrapper *blob) | 888 | struct debugfs_blob_wrapper *blob) |
586 | { | 889 | { |
587 | return debugfs_create_file(name, mode, parent, blob, &fops_blob); | 890 | return debugfs_create_file_unsafe(name, mode, parent, blob, &fops_blob); |
588 | } | 891 | } |
589 | EXPORT_SYMBOL_GPL(debugfs_create_blob); | 892 | EXPORT_SYMBOL_GPL(debugfs_create_blob); |
590 | 893 | ||
@@ -689,7 +992,8 @@ struct dentry *debugfs_create_u32_array(const char *name, umode_t mode, | |||
689 | data->array = array; | 992 | data->array = array; |
690 | data->elements = elements; | 993 | data->elements = elements; |
691 | 994 | ||
692 | return debugfs_create_file(name, mode, parent, data, &u32_array_fops); | 995 | return debugfs_create_file_unsafe(name, mode, parent, data, |
996 | &u32_array_fops); | ||
693 | } | 997 | } |
694 | EXPORT_SYMBOL_GPL(debugfs_create_u32_array); | 998 | EXPORT_SYMBOL_GPL(debugfs_create_u32_array); |
695 | 999 | ||