Skip to content

Commit 1a2ad21

Browse files
Pavel Machektorvalds
Pavel Machek
authored andcommitted
nbd: add locking to nbd_ioctl
The code was written to rely on big kernel lock to protect it from races. It mostly works when interface is not abused. So this uses tx_lock to protect data structures from concurrent use between ioctl and worker threads. Next step will be moving from ioctl to unlocked_ioctl. [[email protected]: coding-style fixes] [[email protected]: add missing return] Signed-off-by: Pavel Machek <[email protected]> Acked-by: Paul Clements <[email protected]> Cc: Jens Axboe <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 1b0f7ff commit 1a2ad21

File tree

1 file changed

+67
-35
lines changed

1 file changed

+67
-35
lines changed

drivers/block/nbd.c

Lines changed: 67 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -568,27 +568,17 @@ static void do_nbd_request(struct request_queue * q)
568568
}
569569
}
570570

571-
static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
572-
unsigned int cmd, unsigned long arg)
573-
{
574-
struct nbd_device *lo = bdev->bd_disk->private_data;
575-
struct file *file;
576-
int error;
577-
struct request sreq ;
578-
struct task_struct *thread;
579-
580-
if (!capable(CAP_SYS_ADMIN))
581-
return -EPERM;
582-
583-
BUG_ON(lo->magic != LO_MAGIC);
584-
585-
/* Anyone capable of this syscall can do *real bad* things */
586-
dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n",
587-
lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg);
571+
/* Must be called with tx_lock held */
588572

573+
static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo,
574+
unsigned int cmd, unsigned long arg)
575+
{
589576
switch (cmd) {
590-
case NBD_DISCONNECT:
577+
case NBD_DISCONNECT: {
578+
struct request sreq;
579+
591580
printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name);
581+
592582
blk_rq_init(NULL, &sreq);
593583
sreq.cmd_type = REQ_TYPE_SPECIAL;
594584
nbd_cmd(&sreq) = NBD_CMD_DISC;
@@ -599,29 +589,29 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
599589
*/
600590
sreq.sector = 0;
601591
sreq.nr_sectors = 0;
602-
if (!lo->sock)
592+
if (!lo->sock)
603593
return -EINVAL;
604-
mutex_lock(&lo->tx_lock);
605-
nbd_send_req(lo, &sreq);
606-
mutex_unlock(&lo->tx_lock);
594+
nbd_send_req(lo, &sreq);
607595
return 0;
596+
}
608597

609-
case NBD_CLEAR_SOCK:
610-
error = 0;
611-
mutex_lock(&lo->tx_lock);
598+
case NBD_CLEAR_SOCK: {
599+
struct file *file;
600+
612601
lo->sock = NULL;
613-
mutex_unlock(&lo->tx_lock);
614602
file = lo->file;
615603
lo->file = NULL;
616604
nbd_clear_que(lo);
617605
BUG_ON(!list_empty(&lo->queue_head));
618606
if (file)
619607
fput(file);
620-
return error;
621-
case NBD_SET_SOCK:
608+
return 0;
609+
}
610+
611+
case NBD_SET_SOCK: {
612+
struct file *file;
622613
if (lo->file)
623614
return -EBUSY;
624-
error = -EINVAL;
625615
file = fget(arg);
626616
if (file) {
627617
struct inode *inode = file->f_path.dentry->d_inode;
@@ -630,48 +620,65 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
630620
lo->sock = SOCKET_I(inode);
631621
if (max_part > 0)
632622
bdev->bd_invalidated = 1;
633-
error = 0;
623+
return 0;
634624
} else {
635625
fput(file);
636626
}
637627
}
638-
return error;
628+
return -EINVAL;
629+
}
630+
639631
case NBD_SET_BLKSIZE:
640632
lo->blksize = arg;
641633
lo->bytesize &= ~(lo->blksize-1);
642634
bdev->bd_inode->i_size = lo->bytesize;
643635
set_blocksize(bdev, lo->blksize);
644636
set_capacity(lo->disk, lo->bytesize >> 9);
645637
return 0;
638+
646639
case NBD_SET_SIZE:
647640
lo->bytesize = arg & ~(lo->blksize-1);
648641
bdev->bd_inode->i_size = lo->bytesize;
649642
set_blocksize(bdev, lo->blksize);
650643
set_capacity(lo->disk, lo->bytesize >> 9);
651644
return 0;
645+
652646
case NBD_SET_TIMEOUT:
653647
lo->xmit_timeout = arg * HZ;
654648
return 0;
649+
655650
case NBD_SET_SIZE_BLOCKS:
656651
lo->bytesize = ((u64) arg) * lo->blksize;
657652
bdev->bd_inode->i_size = lo->bytesize;
658653
set_blocksize(bdev, lo->blksize);
659654
set_capacity(lo->disk, lo->bytesize >> 9);
660655
return 0;
661-
case NBD_DO_IT:
656+
657+
case NBD_DO_IT: {
658+
struct task_struct *thread;
659+
struct file *file;
660+
int error;
661+
662662
if (lo->pid)
663663
return -EBUSY;
664664
if (!lo->file)
665665
return -EINVAL;
666+
667+
mutex_unlock(&lo->tx_lock);
668+
666669
thread = kthread_create(nbd_thread, lo, lo->disk->disk_name);
667-
if (IS_ERR(thread))
670+
if (IS_ERR(thread)) {
671+
mutex_lock(&lo->tx_lock);
668672
return PTR_ERR(thread);
673+
}
669674
wake_up_process(thread);
670675
error = nbd_do_it(lo);
671676
kthread_stop(thread);
677+
678+
mutex_lock(&lo->tx_lock);
672679
if (error)
673680
return error;
674-
sock_shutdown(lo, 1);
681+
sock_shutdown(lo, 0);
675682
file = lo->file;
676683
lo->file = NULL;
677684
nbd_clear_que(lo);
@@ -684,21 +691,46 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
684691
if (max_part > 0)
685692
ioctl_by_bdev(bdev, BLKRRPART, 0);
686693
return lo->harderror;
694+
}
695+
687696
case NBD_CLEAR_QUE:
688697
/*
689698
* This is for compatibility only. The queue is always cleared
690699
* by NBD_DO_IT or NBD_CLEAR_SOCK.
691700
*/
692701
BUG_ON(!lo->sock && !list_empty(&lo->queue_head));
693702
return 0;
703+
694704
case NBD_PRINT_DEBUG:
695705
printk(KERN_INFO "%s: next = %p, prev = %p, head = %p\n",
696706
bdev->bd_disk->disk_name,
697707
lo->queue_head.next, lo->queue_head.prev,
698708
&lo->queue_head);
699709
return 0;
700710
}
701-
return -EINVAL;
711+
return -ENOTTY;
712+
}
713+
714+
static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
715+
unsigned int cmd, unsigned long arg)
716+
{
717+
struct nbd_device *lo = bdev->bd_disk->private_data;
718+
int error;
719+
720+
if (!capable(CAP_SYS_ADMIN))
721+
return -EPERM;
722+
723+
BUG_ON(lo->magic != LO_MAGIC);
724+
725+
/* Anyone capable of this syscall can do *real bad* things */
726+
dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n",
727+
lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg);
728+
729+
mutex_lock(&lo->tx_lock);
730+
error = __nbd_ioctl(bdev, lo, cmd, arg);
731+
mutex_unlock(&lo->tx_lock);
732+
733+
return error;
702734
}
703735

704736
static struct block_device_operations nbd_fops =

0 commit comments

Comments
 (0)