diff options
author | Vyacheslav Dubeyko <Vyacheslav.Dubeyko@hgst.com> | 2014-08-08 17:20:55 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-08 18:57:21 -0400 |
commit | dd70edbde2627f47df118d899de6bbb55abcfdbf (patch) | |
tree | 57043f8164a0c5a5c7e02336fefbcae473d4b953 | |
parent | a5a7332a291b55beb0863b119816d12ffc04dfb0 (diff) |
nilfs2: integrate sysfs support into driver
This patch integrates creation of sysfs groups and
attributes into NILFS file system driver.
It was found the issue with nilfs_sysfs_{create/delete}_snapshot_group
functions by Michael L Semon <mlsemon35@gmail.com> in the first
version of the patch:
BUG: sleeping function called from invalid context at kernel/locking/mutex.c:579
in_atomic(): 1, irqs_disabled(): 0, pid: 32676, name: umount.nilfs2
2 locks held by umount.nilfs2/32676:
#0: (&type->s_umount_key#21){++++..}, at: [<790c18e2>] deactivate_super+0x37/0x58
#1: (&(&nilfs->ns_cptree_lock)->rlock){+.+...}, at: [<791bf659>] nilfs_put_root+0x23/0x5a
Preemption disabled at:[<791bf659>] nilfs_put_root+0x23/0x5a
CPU: 0 PID: 32676 Comm: umount.nilfs2 Not tainted 3.14.0+ #2
Hardware name: Dell Computer Corporation Dimension 2350/07W080, BIOS A01 12/17/2002
Call Trace:
dump_stack+0x4b/0x75
__might_sleep+0x111/0x16f
mutex_lock_nested+0x1e/0x3ad
kernfs_remove+0x12/0x26
sysfs_remove_dir+0x3d/0x62
kobject_del+0x13/0x38
nilfs_sysfs_delete_snapshot_group+0xb/0xd
nilfs_put_root+0x2a/0x5a
nilfs_detach_log_writer+0x1ab/0x2c1
nilfs_put_super+0x13/0x68
generic_shutdown_super+0x60/0xd1
kill_block_super+0x1d/0x60
deactivate_locked_super+0x22/0x3f
deactivate_super+0x3e/0x58
mntput_no_expire+0xe2/0x141
SyS_oldumount+0x70/0xa5
syscall_call+0x7/0xb
The reason of the issue was placement of
nilfs_sysfs_{create/delete}_snapshot_group() call under
nilfs->ns_cptree_lock protection. But this protection is unnecessary and
wrong solution. The second version of the patch fixes this issue.
[fengguang.wu@intel.com: nilfs_sysfs_create_mounted_snapshots_group can be static]
Reported-by: Michael L. Semon <mlsemon35@gmail.com>
Signed-off-by: Vyacheslav Dubeyko <Vyacheslav.Dubeyko@hgst.com>
Cc: Vyacheslav Dubeyko <slava@dubeyko.com>
Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Tested-by: Michael L. Semon <mlsemon35@gmail.com>
Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/nilfs2/Makefile | 2 | ||||
-rw-r--r-- | fs/nilfs2/nilfs.h | 8 | ||||
-rw-r--r-- | fs/nilfs2/super.c | 9 | ||||
-rw-r--r-- | fs/nilfs2/sysfs.c | 4 | ||||
-rw-r--r-- | fs/nilfs2/the_nilfs.c | 16 |
5 files changed, 34 insertions, 5 deletions
diff --git a/fs/nilfs2/Makefile b/fs/nilfs2/Makefile index 85c98737a146..fc603e0431bb 100644 --- a/fs/nilfs2/Makefile +++ b/fs/nilfs2/Makefile | |||
@@ -2,4 +2,4 @@ obj-$(CONFIG_NILFS2_FS) += nilfs2.o | |||
2 | nilfs2-y := inode.o file.o dir.o super.o namei.o page.o mdt.o \ | 2 | nilfs2-y := inode.o file.o dir.o super.o namei.o page.o mdt.o \ |
3 | btnode.o bmap.o btree.o direct.o dat.o recovery.o \ | 3 | btnode.o bmap.o btree.o direct.o dat.o recovery.o \ |
4 | the_nilfs.o segbuf.o segment.o cpfile.o sufile.o \ | 4 | the_nilfs.o segbuf.o segment.o cpfile.o sufile.o \ |
5 | ifile.o alloc.o gcinode.o ioctl.o | 5 | ifile.o alloc.o gcinode.o ioctl.o sysfs.o |
diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index 9bc72dec3fa6..0696161bf59d 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h | |||
@@ -320,6 +320,14 @@ int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *); | |||
320 | int nilfs_init_gcinode(struct inode *inode); | 320 | int nilfs_init_gcinode(struct inode *inode); |
321 | void nilfs_remove_all_gcinodes(struct the_nilfs *nilfs); | 321 | void nilfs_remove_all_gcinodes(struct the_nilfs *nilfs); |
322 | 322 | ||
323 | /* sysfs.c */ | ||
324 | int __init nilfs_sysfs_init(void); | ||
325 | void nilfs_sysfs_exit(void); | ||
326 | int nilfs_sysfs_create_device_group(struct super_block *); | ||
327 | void nilfs_sysfs_delete_device_group(struct the_nilfs *); | ||
328 | int nilfs_sysfs_create_snapshot_group(struct nilfs_root *); | ||
329 | void nilfs_sysfs_delete_snapshot_group(struct nilfs_root *); | ||
330 | |||
323 | /* | 331 | /* |
324 | * Inodes and files operations | 332 | * Inodes and files operations |
325 | */ | 333 | */ |
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 8c532b2ca3ab..c519927b7b5e 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c | |||
@@ -1452,13 +1452,19 @@ static int __init init_nilfs_fs(void) | |||
1452 | if (err) | 1452 | if (err) |
1453 | goto fail; | 1453 | goto fail; |
1454 | 1454 | ||
1455 | err = register_filesystem(&nilfs_fs_type); | 1455 | err = nilfs_sysfs_init(); |
1456 | if (err) | 1456 | if (err) |
1457 | goto free_cachep; | 1457 | goto free_cachep; |
1458 | 1458 | ||
1459 | err = register_filesystem(&nilfs_fs_type); | ||
1460 | if (err) | ||
1461 | goto deinit_sysfs_entry; | ||
1462 | |||
1459 | printk(KERN_INFO "NILFS version 2 loaded\n"); | 1463 | printk(KERN_INFO "NILFS version 2 loaded\n"); |
1460 | return 0; | 1464 | return 0; |
1461 | 1465 | ||
1466 | deinit_sysfs_entry: | ||
1467 | nilfs_sysfs_exit(); | ||
1462 | free_cachep: | 1468 | free_cachep: |
1463 | nilfs_destroy_cachep(); | 1469 | nilfs_destroy_cachep(); |
1464 | fail: | 1470 | fail: |
@@ -1468,6 +1474,7 @@ fail: | |||
1468 | static void __exit exit_nilfs_fs(void) | 1474 | static void __exit exit_nilfs_fs(void) |
1469 | { | 1475 | { |
1470 | nilfs_destroy_cachep(); | 1476 | nilfs_destroy_cachep(); |
1477 | nilfs_sysfs_exit(); | ||
1471 | unregister_filesystem(&nilfs_fs_type); | 1478 | unregister_filesystem(&nilfs_fs_type); |
1472 | } | 1479 | } |
1473 | 1480 | ||
diff --git a/fs/nilfs2/sysfs.c b/fs/nilfs2/sysfs.c index 0f6148c8121a..bbb0dcc35905 100644 --- a/fs/nilfs2/sysfs.c +++ b/fs/nilfs2/sysfs.c | |||
@@ -87,7 +87,7 @@ static struct kobj_type nilfs_##name##_ktype = { \ | |||
87 | }; | 87 | }; |
88 | 88 | ||
89 | #define NILFS_DEV_INT_GROUP_FNS(name, parent_name) \ | 89 | #define NILFS_DEV_INT_GROUP_FNS(name, parent_name) \ |
90 | int nilfs_sysfs_create_##name##_group(struct the_nilfs *nilfs) \ | 90 | static int nilfs_sysfs_create_##name##_group(struct the_nilfs *nilfs) \ |
91 | { \ | 91 | { \ |
92 | struct kobject *parent; \ | 92 | struct kobject *parent; \ |
93 | struct kobject *kobj; \ | 93 | struct kobject *kobj; \ |
@@ -106,7 +106,7 @@ int nilfs_sysfs_create_##name##_group(struct the_nilfs *nilfs) \ | |||
106 | return err; \ | 106 | return err; \ |
107 | return 0; \ | 107 | return 0; \ |
108 | } \ | 108 | } \ |
109 | void nilfs_sysfs_delete_##name##_group(struct the_nilfs *nilfs) \ | 109 | static void nilfs_sysfs_delete_##name##_group(struct the_nilfs *nilfs) \ |
110 | { \ | 110 | { \ |
111 | kobject_del(&nilfs->ns_##parent_name##_subgroups->sg_##name##_kobj); \ | 111 | kobject_del(&nilfs->ns_##parent_name##_subgroups->sg_##name##_kobj); \ |
112 | } | 112 | } |
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 59d50088b886..9da25fe9ea61 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c | |||
@@ -98,6 +98,7 @@ void destroy_nilfs(struct the_nilfs *nilfs) | |||
98 | { | 98 | { |
99 | might_sleep(); | 99 | might_sleep(); |
100 | if (nilfs_init(nilfs)) { | 100 | if (nilfs_init(nilfs)) { |
101 | nilfs_sysfs_delete_device_group(nilfs); | ||
101 | brelse(nilfs->ns_sbh[0]); | 102 | brelse(nilfs->ns_sbh[0]); |
102 | brelse(nilfs->ns_sbh[1]); | 103 | brelse(nilfs->ns_sbh[1]); |
103 | } | 104 | } |
@@ -641,6 +642,10 @@ int init_nilfs(struct the_nilfs *nilfs, struct super_block *sb, char *data) | |||
641 | if (err) | 642 | if (err) |
642 | goto failed_sbh; | 643 | goto failed_sbh; |
643 | 644 | ||
645 | err = nilfs_sysfs_create_device_group(sb); | ||
646 | if (err) | ||
647 | goto failed_sbh; | ||
648 | |||
644 | set_nilfs_init(nilfs); | 649 | set_nilfs_init(nilfs); |
645 | err = 0; | 650 | err = 0; |
646 | out: | 651 | out: |
@@ -741,12 +746,13 @@ nilfs_find_or_create_root(struct the_nilfs *nilfs, __u64 cno) | |||
741 | { | 746 | { |
742 | struct rb_node **p, *parent; | 747 | struct rb_node **p, *parent; |
743 | struct nilfs_root *root, *new; | 748 | struct nilfs_root *root, *new; |
749 | int err; | ||
744 | 750 | ||
745 | root = nilfs_lookup_root(nilfs, cno); | 751 | root = nilfs_lookup_root(nilfs, cno); |
746 | if (root) | 752 | if (root) |
747 | return root; | 753 | return root; |
748 | 754 | ||
749 | new = kmalloc(sizeof(*root), GFP_KERNEL); | 755 | new = kzalloc(sizeof(*root), GFP_KERNEL); |
750 | if (!new) | 756 | if (!new) |
751 | return NULL; | 757 | return NULL; |
752 | 758 | ||
@@ -783,6 +789,12 @@ nilfs_find_or_create_root(struct the_nilfs *nilfs, __u64 cno) | |||
783 | 789 | ||
784 | spin_unlock(&nilfs->ns_cptree_lock); | 790 | spin_unlock(&nilfs->ns_cptree_lock); |
785 | 791 | ||
792 | err = nilfs_sysfs_create_snapshot_group(new); | ||
793 | if (err) { | ||
794 | kfree(new); | ||
795 | new = NULL; | ||
796 | } | ||
797 | |||
786 | return new; | 798 | return new; |
787 | } | 799 | } |
788 | 800 | ||
@@ -791,6 +803,8 @@ void nilfs_put_root(struct nilfs_root *root) | |||
791 | if (atomic_dec_and_test(&root->count)) { | 803 | if (atomic_dec_and_test(&root->count)) { |
792 | struct the_nilfs *nilfs = root->nilfs; | 804 | struct the_nilfs *nilfs = root->nilfs; |
793 | 805 | ||
806 | nilfs_sysfs_delete_snapshot_group(root); | ||
807 | |||
794 | spin_lock(&nilfs->ns_cptree_lock); | 808 | spin_lock(&nilfs->ns_cptree_lock); |
795 | rb_erase(&root->rb_node, &nilfs->ns_cptree); | 809 | rb_erase(&root->rb_node, &nilfs->ns_cptree); |
796 | spin_unlock(&nilfs->ns_cptree_lock); | 810 | spin_unlock(&nilfs->ns_cptree_lock); |