Commit dd70edbd authored by Vyacheslav Dubeyko's avatar Vyacheslav Dubeyko Committed by Linus Torvalds

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: default avatarMichael L. Semon <mlsemon35@gmail.com>
Signed-off-by: default avatarVyacheslav Dubeyko <Vyacheslav.Dubeyko@hgst.com>
Cc: Vyacheslav Dubeyko <slava@dubeyko.com>
Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Tested-by: default avatarMichael L. Semon <mlsemon35@gmail.com>
Signed-off-by: default avatarFengguang Wu <fengguang.wu@intel.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent a5a7332a
...@@ -2,4 +2,4 @@ obj-$(CONFIG_NILFS2_FS) += nilfs2.o ...@@ -2,4 +2,4 @@ obj-$(CONFIG_NILFS2_FS) += nilfs2.o
nilfs2-y := inode.o file.o dir.o super.o namei.o page.o mdt.o \ nilfs2-y := inode.o file.o dir.o super.o namei.o page.o mdt.o \
btnode.o bmap.o btree.o direct.o dat.o recovery.o \ btnode.o bmap.o btree.o direct.o dat.o recovery.o \
the_nilfs.o segbuf.o segment.o cpfile.o sufile.o \ the_nilfs.o segbuf.o segment.o cpfile.o sufile.o \
ifile.o alloc.o gcinode.o ioctl.o ifile.o alloc.o gcinode.o ioctl.o sysfs.o
...@@ -320,6 +320,14 @@ int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *); ...@@ -320,6 +320,14 @@ int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *);
int nilfs_init_gcinode(struct inode *inode); int nilfs_init_gcinode(struct inode *inode);
void nilfs_remove_all_gcinodes(struct the_nilfs *nilfs); void nilfs_remove_all_gcinodes(struct the_nilfs *nilfs);
/* sysfs.c */
int __init nilfs_sysfs_init(void);
void nilfs_sysfs_exit(void);
int nilfs_sysfs_create_device_group(struct super_block *);
void nilfs_sysfs_delete_device_group(struct the_nilfs *);
int nilfs_sysfs_create_snapshot_group(struct nilfs_root *);
void nilfs_sysfs_delete_snapshot_group(struct nilfs_root *);
/* /*
* Inodes and files operations * Inodes and files operations
*/ */
......
...@@ -1452,13 +1452,19 @@ static int __init init_nilfs_fs(void) ...@@ -1452,13 +1452,19 @@ static int __init init_nilfs_fs(void)
if (err) if (err)
goto fail; goto fail;
err = register_filesystem(&nilfs_fs_type); err = nilfs_sysfs_init();
if (err) if (err)
goto free_cachep; goto free_cachep;
err = register_filesystem(&nilfs_fs_type);
if (err)
goto deinit_sysfs_entry;
printk(KERN_INFO "NILFS version 2 loaded\n"); printk(KERN_INFO "NILFS version 2 loaded\n");
return 0; return 0;
deinit_sysfs_entry:
nilfs_sysfs_exit();
free_cachep: free_cachep:
nilfs_destroy_cachep(); nilfs_destroy_cachep();
fail: fail:
...@@ -1468,6 +1474,7 @@ static int __init init_nilfs_fs(void) ...@@ -1468,6 +1474,7 @@ static int __init init_nilfs_fs(void)
static void __exit exit_nilfs_fs(void) static void __exit exit_nilfs_fs(void)
{ {
nilfs_destroy_cachep(); nilfs_destroy_cachep();
nilfs_sysfs_exit();
unregister_filesystem(&nilfs_fs_type); unregister_filesystem(&nilfs_fs_type);
} }
......
...@@ -87,7 +87,7 @@ static struct kobj_type nilfs_##name##_ktype = { \ ...@@ -87,7 +87,7 @@ static struct kobj_type nilfs_##name##_ktype = { \
}; };
#define NILFS_DEV_INT_GROUP_FNS(name, parent_name) \ #define NILFS_DEV_INT_GROUP_FNS(name, parent_name) \
int nilfs_sysfs_create_##name##_group(struct the_nilfs *nilfs) \ static int nilfs_sysfs_create_##name##_group(struct the_nilfs *nilfs) \
{ \ { \
struct kobject *parent; \ struct kobject *parent; \
struct kobject *kobj; \ struct kobject *kobj; \
...@@ -106,7 +106,7 @@ int nilfs_sysfs_create_##name##_group(struct the_nilfs *nilfs) \ ...@@ -106,7 +106,7 @@ int nilfs_sysfs_create_##name##_group(struct the_nilfs *nilfs) \
return err; \ return err; \
return 0; \ return 0; \
} \ } \
void nilfs_sysfs_delete_##name##_group(struct the_nilfs *nilfs) \ static void nilfs_sysfs_delete_##name##_group(struct the_nilfs *nilfs) \
{ \ { \
kobject_del(&nilfs->ns_##parent_name##_subgroups->sg_##name##_kobj); \ kobject_del(&nilfs->ns_##parent_name##_subgroups->sg_##name##_kobj); \
} }
......
...@@ -98,6 +98,7 @@ void destroy_nilfs(struct the_nilfs *nilfs) ...@@ -98,6 +98,7 @@ void destroy_nilfs(struct the_nilfs *nilfs)
{ {
might_sleep(); might_sleep();
if (nilfs_init(nilfs)) { if (nilfs_init(nilfs)) {
nilfs_sysfs_delete_device_group(nilfs);
brelse(nilfs->ns_sbh[0]); brelse(nilfs->ns_sbh[0]);
brelse(nilfs->ns_sbh[1]); brelse(nilfs->ns_sbh[1]);
} }
...@@ -641,6 +642,10 @@ int init_nilfs(struct the_nilfs *nilfs, struct super_block *sb, char *data) ...@@ -641,6 +642,10 @@ int init_nilfs(struct the_nilfs *nilfs, struct super_block *sb, char *data)
if (err) if (err)
goto failed_sbh; goto failed_sbh;
err = nilfs_sysfs_create_device_group(sb);
if (err)
goto failed_sbh;
set_nilfs_init(nilfs); set_nilfs_init(nilfs);
err = 0; err = 0;
out: out:
...@@ -741,12 +746,13 @@ nilfs_find_or_create_root(struct the_nilfs *nilfs, __u64 cno) ...@@ -741,12 +746,13 @@ nilfs_find_or_create_root(struct the_nilfs *nilfs, __u64 cno)
{ {
struct rb_node **p, *parent; struct rb_node **p, *parent;
struct nilfs_root *root, *new; struct nilfs_root *root, *new;
int err;
root = nilfs_lookup_root(nilfs, cno); root = nilfs_lookup_root(nilfs, cno);
if (root) if (root)
return root; return root;
new = kmalloc(sizeof(*root), GFP_KERNEL); new = kzalloc(sizeof(*root), GFP_KERNEL);
if (!new) if (!new)
return NULL; return NULL;
...@@ -783,6 +789,12 @@ nilfs_find_or_create_root(struct the_nilfs *nilfs, __u64 cno) ...@@ -783,6 +789,12 @@ nilfs_find_or_create_root(struct the_nilfs *nilfs, __u64 cno)
spin_unlock(&nilfs->ns_cptree_lock); spin_unlock(&nilfs->ns_cptree_lock);
err = nilfs_sysfs_create_snapshot_group(new);
if (err) {
kfree(new);
new = NULL;
}
return new; return new;
} }
...@@ -791,6 +803,8 @@ void nilfs_put_root(struct nilfs_root *root) ...@@ -791,6 +803,8 @@ void nilfs_put_root(struct nilfs_root *root)
if (atomic_dec_and_test(&root->count)) { if (atomic_dec_and_test(&root->count)) {
struct the_nilfs *nilfs = root->nilfs; struct the_nilfs *nilfs = root->nilfs;
nilfs_sysfs_delete_snapshot_group(root);
spin_lock(&nilfs->ns_cptree_lock); spin_lock(&nilfs->ns_cptree_lock);
rb_erase(&root->rb_node, &nilfs->ns_cptree); rb_erase(&root->rb_node, &nilfs->ns_cptree);
spin_unlock(&nilfs->ns_cptree_lock); spin_unlock(&nilfs->ns_cptree_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment