From 2474f2763e46bcde012d46d61c53ad51ea1fe8e9 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Mon, 27 May 2013 23:21:28 -0400 Subject: [PATCH] Improve zvol initialization code In addition, the following error will occur on some (possibly all) kernels because blk_init_queue() will try to take the spinlock before we initialize it. [ 5.538871] BUG: spinlock bad magic on CPU#0, zpool/4054 [ 5.538885] lock: 0xffff88021a73de60, .magic: 00000000, .owner: /-1, .owner_cpu: 0 [ 5.538888] Pid: 4054, comm: zpool Not tainted 3.9.3 #11 [ 5.538890] Call Trace: [ 5.538898] [] spin_dump+0x8c/0x91 [ 5.538902] [] spin_bug+0x21/0x26 [ 5.538906] [] do_raw_spin_lock+0x127/0x130 [ 5.538911] [] ? zvol_probe+0x91/0xf0 [ 5.538914] [] _raw_spin_lock_irq+0x21/0x30 [ 5.538919] [] cfq_init_queue+0x1fe/0x350 [ 5.538922] [] ? zvol_probe+0xf0/0xf0 [ 5.538926] [] elevator_init+0x78/0x140 [ 5.538930] [] blk_init_allocated_queue+0x87/0xb0 [ 5.538933] [] ? zvol_probe+0xf0/0xf0 [ 5.538937] [] blk_init_queue_node+0x35/0x70 [ 5.538941] [] blk_init_queue+0xe/0x10 [ 5.538944] [] __zvol_create_minor+0x24b/0x620 [ 5.538947] [] zvol_create_minors_cb+0x24/0x30 [ 5.538952] [] dmu_objset_find_spa+0xea/0x510 [ 5.538955] [] ? zvol_free+0x60/0x60 [ 5.538958] [] dmu_objset_find_spa+0x191/0x510 [ 5.538962] [] ? zvol_free+0x60/0x60 [ 5.538965] [] zvol_create_minors+0x92/0x180 [ 5.538969] [] spa_open_common+0x250/0x380 [ 5.538973] [] spa_open+0xe/0x10 [ 5.538977] [] pool_status_check.part.22+0x1e/0x80 [ 5.538980] [] zfsdev_ioctl+0x155/0x190 [ 5.538984] [] do_vfs_ioctl+0x325/0x5a0 [ 5.538989] [] ? final_putname+0x1d/0x40 [ 5.538992] [] sys_ioctl+0x40/0x80 [ 5.538996] [] ? do_page_fault+0x9/0x10 [ 5.539000] [] system_call_fastpath+0x16/0x1b [ 5.541118] zd0: unknown partition table We fix this by calling spin_lock_init before blk_init_queue. Also, we do not cleanup from failures in zvol_init particularly well. We resolve this with changes to zvol_init() and zvol_fini(). Signed-off-by: Richard Yao --- module/zfs/zvol.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c index b41eeb20221d..f9387a7f6413 100644 --- a/module/zfs/zvol.c +++ b/module/zfs/zvol.c @@ -1217,6 +1217,8 @@ zvol_alloc(dev_t dev, const char *name) if (zv == NULL) goto out; + spin_lock_init(&zv->zv_lock); + zv->zv_queue = blk_init_queue(zvol_request, &zv->zv_lock); if (zv->zv_queue == NULL) goto out_kmem; @@ -1250,7 +1252,6 @@ zvol_alloc(dev_t dev, const char *name) sizeof (rl_t), offsetof(rl_t, r_node)); zv->zv_znode.z_is_zvol = TRUE; - spin_lock_init(&zv->zv_lock); list_link_init(&zv->zv_next); zv->zv_disk->major = zvol_major; @@ -1563,36 +1564,40 @@ zvol_init(void) { int error; + list_create(&zvol_state_list, sizeof (zvol_state_t), + offsetof(zvol_state_t, zv_next)); + mutex_init(&zvol_state_lock, NULL, MUTEX_DEFAULT, NULL); + zvol_taskq = taskq_create(ZVOL_DRIVER, zvol_threads, maxclsyspri, zvol_threads, INT_MAX, TASKQ_PREPOPULATE); if (zvol_taskq == NULL) { printk(KERN_INFO "ZFS: taskq_create() failed\n"); - return (-ENOMEM); + error = -ENOMEM; + goto out1; } error = register_blkdev(zvol_major, ZVOL_DRIVER); if (error) { printk(KERN_INFO "ZFS: register_blkdev() failed %d\n", error); - taskq_destroy(zvol_taskq); - return (error); + goto out2; } blk_register_region(MKDEV(zvol_major, 0), 1UL << MINORBITS, THIS_MODULE, zvol_probe, NULL, NULL); - mutex_init(&zvol_state_lock, NULL, MUTEX_DEFAULT, NULL); - list_create(&zvol_state_list, sizeof (zvol_state_t), - offsetof(zvol_state_t, zv_next)); - - (void) zvol_create_minors(NULL); - return (0); + +out2: + taskq_destroy(zvol_taskq); +out1: + mutex_destroy(&zvol_state_lock); + list_destroy(&zvol_state_list); + return (error); } void zvol_fini(void) { - zvol_remove_minors(NULL); blk_unregister_region(MKDEV(zvol_major, 0), 1UL << MINORBITS); unregister_blkdev(zvol_major, ZVOL_DRIVER); taskq_destroy(zvol_taskq);