diff options
Diffstat (limited to 'fs/debugfs/inode.c')
-rw-r--r-- | fs/debugfs/inode.c | 108 |
1 files changed, 88 insertions, 20 deletions
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 8580831ed237..4bc1f68243c1 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c | |||
@@ -27,9 +27,14 @@ | |||
27 | #include <linux/parser.h> | 27 | #include <linux/parser.h> |
28 | #include <linux/magic.h> | 28 | #include <linux/magic.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/srcu.h> | ||
31 | |||
32 | #include "internal.h" | ||
30 | 33 | ||
31 | #define DEBUGFS_DEFAULT_MODE 0700 | 34 | #define DEBUGFS_DEFAULT_MODE 0700 |
32 | 35 | ||
36 | DEFINE_SRCU(debugfs_srcu); | ||
37 | |||
33 | static struct vfsmount *debugfs_mount; | 38 | static struct vfsmount *debugfs_mount; |
34 | static int debugfs_mount_count; | 39 | static int debugfs_mount_count; |
35 | static bool debugfs_registered; | 40 | static bool debugfs_registered; |
@@ -39,7 +44,8 @@ static struct inode *debugfs_get_inode(struct super_block *sb) | |||
39 | struct inode *inode = new_inode(sb); | 44 | struct inode *inode = new_inode(sb); |
40 | if (inode) { | 45 | if (inode) { |
41 | inode->i_ino = get_next_ino(); | 46 | inode->i_ino = get_next_ino(); |
42 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 47 | inode->i_atime = inode->i_mtime = |
48 | inode->i_ctime = current_fs_time(sb); | ||
43 | } | 49 | } |
44 | return inode; | 50 | return inode; |
45 | } | 51 | } |
@@ -294,6 +300,37 @@ static struct dentry *end_creating(struct dentry *dentry) | |||
294 | return dentry; | 300 | return dentry; |
295 | } | 301 | } |
296 | 302 | ||
303 | static struct dentry *__debugfs_create_file(const char *name, umode_t mode, | ||
304 | struct dentry *parent, void *data, | ||
305 | const struct file_operations *proxy_fops, | ||
306 | const struct file_operations *real_fops) | ||
307 | { | ||
308 | struct dentry *dentry; | ||
309 | struct inode *inode; | ||
310 | |||
311 | if (!(mode & S_IFMT)) | ||
312 | mode |= S_IFREG; | ||
313 | BUG_ON(!S_ISREG(mode)); | ||
314 | dentry = start_creating(name, parent); | ||
315 | |||
316 | if (IS_ERR(dentry)) | ||
317 | return NULL; | ||
318 | |||
319 | inode = debugfs_get_inode(dentry->d_sb); | ||
320 | if (unlikely(!inode)) | ||
321 | return failed_creating(dentry); | ||
322 | |||
323 | inode->i_mode = mode; | ||
324 | inode->i_private = data; | ||
325 | |||
326 | inode->i_fop = proxy_fops; | ||
327 | dentry->d_fsdata = (void *)real_fops; | ||
328 | |||
329 | d_instantiate(dentry, inode); | ||
330 | fsnotify_create(d_inode(dentry->d_parent), dentry); | ||
331 | return end_creating(dentry); | ||
332 | } | ||
333 | |||
297 | /** | 334 | /** |
298 | * debugfs_create_file - create a file in the debugfs filesystem | 335 | * debugfs_create_file - create a file in the debugfs filesystem |
299 | * @name: a pointer to a string containing the name of the file to create. | 336 | * @name: a pointer to a string containing the name of the file to create. |
@@ -324,29 +361,52 @@ struct dentry *debugfs_create_file(const char *name, umode_t mode, | |||
324 | struct dentry *parent, void *data, | 361 | struct dentry *parent, void *data, |
325 | const struct file_operations *fops) | 362 | const struct file_operations *fops) |
326 | { | 363 | { |
327 | struct dentry *dentry; | ||
328 | struct inode *inode; | ||
329 | 364 | ||
330 | if (!(mode & S_IFMT)) | 365 | return __debugfs_create_file(name, mode, parent, data, |
331 | mode |= S_IFREG; | 366 | fops ? &debugfs_full_proxy_file_operations : |
332 | BUG_ON(!S_ISREG(mode)); | 367 | &debugfs_noop_file_operations, |
333 | dentry = start_creating(name, parent); | 368 | fops); |
334 | 369 | } | |
335 | if (IS_ERR(dentry)) | 370 | EXPORT_SYMBOL_GPL(debugfs_create_file); |
336 | return NULL; | ||
337 | 371 | ||
338 | inode = debugfs_get_inode(dentry->d_sb); | 372 | /** |
339 | if (unlikely(!inode)) | 373 | * debugfs_create_file_unsafe - create a file in the debugfs filesystem |
340 | return failed_creating(dentry); | 374 | * @name: a pointer to a string containing the name of the file to create. |
375 | * @mode: the permission that the file should have. | ||
376 | * @parent: a pointer to the parent dentry for this file. This should be a | ||
377 | * directory dentry if set. If this parameter is NULL, then the | ||
378 | * file will be created in the root of the debugfs filesystem. | ||
379 | * @data: a pointer to something that the caller will want to get to later | ||
380 | * on. The inode.i_private pointer will point to this value on | ||
381 | * the open() call. | ||
382 | * @fops: a pointer to a struct file_operations that should be used for | ||
383 | * this file. | ||
384 | * | ||
385 | * debugfs_create_file_unsafe() is completely analogous to | ||
386 | * debugfs_create_file(), the only difference being that the fops | ||
387 | * handed it will not get protected against file removals by the | ||
388 | * debugfs core. | ||
389 | * | ||
390 | * It is your responsibility to protect your struct file_operation | ||
391 | * methods against file removals by means of debugfs_use_file_start() | ||
392 | * and debugfs_use_file_finish(). ->open() is still protected by | ||
393 | * debugfs though. | ||
394 | * | ||
395 | * Any struct file_operations defined by means of | ||
396 | * DEFINE_DEBUGFS_ATTRIBUTE() is protected against file removals and | ||
397 | * thus, may be used here. | ||
398 | */ | ||
399 | struct dentry *debugfs_create_file_unsafe(const char *name, umode_t mode, | ||
400 | struct dentry *parent, void *data, | ||
401 | const struct file_operations *fops) | ||
402 | { | ||
341 | 403 | ||
342 | inode->i_mode = mode; | 404 | return __debugfs_create_file(name, mode, parent, data, |
343 | inode->i_fop = fops ? fops : &debugfs_file_operations; | 405 | fops ? &debugfs_open_proxy_file_operations : |
344 | inode->i_private = data; | 406 | &debugfs_noop_file_operations, |
345 | d_instantiate(dentry, inode); | 407 | fops); |
346 | fsnotify_create(d_inode(dentry->d_parent), dentry); | ||
347 | return end_creating(dentry); | ||
348 | } | 408 | } |
349 | EXPORT_SYMBOL_GPL(debugfs_create_file); | 409 | EXPORT_SYMBOL_GPL(debugfs_create_file_unsafe); |
350 | 410 | ||
351 | /** | 411 | /** |
352 | * debugfs_create_file_size - create a file in the debugfs filesystem | 412 | * debugfs_create_file_size - create a file in the debugfs filesystem |
@@ -461,7 +521,11 @@ struct dentry *debugfs_create_automount(const char *name, | |||
461 | inode->i_flags |= S_AUTOMOUNT; | 521 | inode->i_flags |= S_AUTOMOUNT; |
462 | inode->i_private = data; | 522 | inode->i_private = data; |
463 | dentry->d_fsdata = (void *)f; | 523 | dentry->d_fsdata = (void *)f; |
524 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ | ||
525 | inc_nlink(inode); | ||
464 | d_instantiate(dentry, inode); | 526 | d_instantiate(dentry, inode); |
527 | inc_nlink(d_inode(dentry->d_parent)); | ||
528 | fsnotify_mkdir(d_inode(dentry->d_parent), dentry); | ||
465 | return end_creating(dentry); | 529 | return end_creating(dentry); |
466 | } | 530 | } |
467 | EXPORT_SYMBOL(debugfs_create_automount); | 531 | EXPORT_SYMBOL(debugfs_create_automount); |
@@ -565,6 +629,8 @@ void debugfs_remove(struct dentry *dentry) | |||
565 | inode_unlock(d_inode(parent)); | 629 | inode_unlock(d_inode(parent)); |
566 | if (!ret) | 630 | if (!ret) |
567 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); | 631 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); |
632 | |||
633 | synchronize_srcu(&debugfs_srcu); | ||
568 | } | 634 | } |
569 | EXPORT_SYMBOL_GPL(debugfs_remove); | 635 | EXPORT_SYMBOL_GPL(debugfs_remove); |
570 | 636 | ||
@@ -642,6 +708,8 @@ void debugfs_remove_recursive(struct dentry *dentry) | |||
642 | if (!__debugfs_remove(child, parent)) | 708 | if (!__debugfs_remove(child, parent)) |
643 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); | 709 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); |
644 | inode_unlock(d_inode(parent)); | 710 | inode_unlock(d_inode(parent)); |
711 | |||
712 | synchronize_srcu(&debugfs_srcu); | ||
645 | } | 713 | } |
646 | EXPORT_SYMBOL_GPL(debugfs_remove_recursive); | 714 | EXPORT_SYMBOL_GPL(debugfs_remove_recursive); |
647 | 715 | ||