/*
  * Copyright (C) 2000 Jens Axboe <axboe@suse.de>
  * Copyright (C) 2001-2004 Peter Osterlund <petero2@telia.com>
+ * Copyright (C) 2006 Thomas Maier <balagi@justmail.de>
  *
  * May be copied or modified under the terms of the GNU General Public
  * License.  See linux/COPYING for more information.
 /*
  * Set up mapping from pktcdvd device to CD-ROM device.
  */
-static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd)
+static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
 {
        int idx;
        int ret = -ENOMEM;
        struct pktcdvd_device *pd;
        struct gendisk *disk;
-       dev_t dev = new_decode_dev(ctrl_cmd->dev);
+
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
 
        for (idx = 0; idx < MAX_WRITERS; idx++)
                if (!pkt_devs[idx])
                        break;
        if (idx == MAX_WRITERS) {
                printk(DRIVER_NAME": max %d writers supported\n", MAX_WRITERS);
-               return -EBUSY;
+               ret = -EBUSY;
+               goto out_mutex;
        }
 
        pd = kzalloc(sizeof(struct pktcdvd_device), GFP_KERNEL);
        if (!pd)
-               return ret;
+               goto out_mutex;
 
        pd->rb_pool = mempool_create_kmalloc_pool(PKT_RB_POOL_SIZE,
                                                  sizeof(struct pkt_rb_node));
        if (!pd->rb_pool)
                goto out_mem;
 
-       disk = alloc_disk(1);
-       if (!disk)
-               goto out_mem;
-       pd->disk = disk;
-
        INIT_LIST_HEAD(&pd->cdrw.pkt_free_list);
        INIT_LIST_HEAD(&pd->cdrw.pkt_active_list);
        spin_lock_init(&pd->cdrw.active_list_lock);
        init_waitqueue_head(&pd->wqueue);
        pd->bio_queue = RB_ROOT;
 
+       disk = alloc_disk(1);
+       if (!disk)
+               goto out_mem;
+       pd->disk = disk;
        disk->major = pktdev_major;
        disk->first_minor = idx;
        disk->fops = &pktcdvd_ops;
        disk->flags = GENHD_FL_REMOVABLE;
-       sprintf(disk->disk_name, DRIVER_NAME"%d", idx);
+       strcpy(disk->disk_name, pd->name);
        disk->private_data = pd;
        disk->queue = blk_alloc_queue(GFP_KERNEL);
        if (!disk->queue)
                goto out_new_dev;
 
        add_disk(disk);
+
        pkt_devs[idx] = pd;
-       ctrl_cmd->pkt_dev = new_encode_dev(pd->pkt_dev);
+       if (pkt_dev)
+               *pkt_dev = pd->pkt_dev;
+
+       mutex_unlock(&ctl_mutex);
        return 0;
 
 out_new_dev:
        if (pd->rb_pool)
                mempool_destroy(pd->rb_pool);
        kfree(pd);
+out_mutex:
+       mutex_unlock(&ctl_mutex);
+       printk(DRIVER_NAME": setup of pktcdvd device failed\n");
        return ret;
 }
 
 /*
  * Tear down mapping from pktcdvd device to CD-ROM device.
  */
-static int pkt_remove_dev(struct pkt_ctrl_command *ctrl_cmd)
+static int pkt_remove_dev(dev_t pkt_dev)
 {
        struct pktcdvd_device *pd;
        int idx;
-       dev_t pkt_dev = new_decode_dev(ctrl_cmd->pkt_dev);
+       int ret = 0;
+
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
 
        for (idx = 0; idx < MAX_WRITERS; idx++) {
                pd = pkt_devs[idx];
        }
        if (idx == MAX_WRITERS) {
                DPRINTK(DRIVER_NAME": dev not setup\n");
-               return -ENXIO;
+               ret = -ENXIO;
+               goto out;
        }
 
-       if (pd->refcnt > 0)
-               return -EBUSY;
-
+       if (pd->refcnt > 0) {
+               ret = -EBUSY;
+               goto out;
+       }
        if (!IS_ERR(pd->cdrw.thread))
                kthread_stop(pd->cdrw.thread);
 
 
        /* This is safe: open() is still holding a reference. */
        module_put(THIS_MODULE);
-       return 0;
+
+out:
+       mutex_unlock(&ctl_mutex);
+       return ret;
 }
 
 static void pkt_get_status(struct pkt_ctrl_command *ctrl_cmd)
 {
-       struct pktcdvd_device *pd = pkt_find_dev_from_minor(ctrl_cmd->dev_index);
+       struct pktcdvd_device *pd;
+
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+       pd = pkt_find_dev_from_minor(ctrl_cmd->dev_index);
        if (pd) {
                ctrl_cmd->dev = new_encode_dev(pd->bdev->bd_dev);
                ctrl_cmd->pkt_dev = new_encode_dev(pd->pkt_dev);
                ctrl_cmd->pkt_dev = 0;
        }
        ctrl_cmd->num_devices = MAX_WRITERS;
+
+       mutex_unlock(&ctl_mutex);
 }
 
 static int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
        void __user *argp = (void __user *)arg;
        struct pkt_ctrl_command ctrl_cmd;
        int ret = 0;
+       dev_t pkt_dev = 0;
 
        if (cmd != PACKET_CTRL_CMD)
                return -ENOTTY;
        case PKT_CTRL_CMD_SETUP:
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-               ret = pkt_setup_dev(&ctrl_cmd);
-               mutex_unlock(&ctl_mutex);
+               ret = pkt_setup_dev(new_decode_dev(ctrl_cmd.dev), &pkt_dev);
+               ctrl_cmd.pkt_dev = new_encode_dev(pkt_dev);
                break;
        case PKT_CTRL_CMD_TEARDOWN:
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-               ret = pkt_remove_dev(&ctrl_cmd);
-               mutex_unlock(&ctl_mutex);
+               ret = pkt_remove_dev(new_decode_dev(ctrl_cmd.pkt_dev));
                break;
        case PKT_CTRL_CMD_STATUS:
-               mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
                pkt_get_status(&ctrl_cmd);
-               mutex_unlock(&ctl_mutex);
                break;
        default:
                return -ENOTTY;