aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorPavel Machek <pavel@suse.cz>2009-04-02 19:58:41 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-04-02 22:05:02 -0400
commit1a2ad21128bb4eb79f3c05e5801edcc5ed3ef1d3 (patch)
treeba5845f5e7f225b427d4ce250b911b9303aa9511 /drivers/block
parent1b0f7ffd0ea27cd3a0b9ca04e3df9522048c32a3 (diff)
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. [akpm@linux-foundation.org: coding-style fixes] [akpm@linux-foundation.org: add missing return] Signed-off-by: Pavel Machek <pavel@suse.cz> Acked-by: Paul Clements <paul.clements@steeleye.com> Cc: Jens Axboe <jens.axboe@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/nbd.c102
1 files changed, 67 insertions, 35 deletions
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 8299e2d3b611..5e982814797d 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -568,27 +568,17 @@ static void do_nbd_request(struct request_queue * q)
568 } 568 }
569} 569}
570 570
571static int nbd_ioctl(struct block_device *bdev, fmode_t mode, 571/* Must be called with tx_lock held */
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);
588 572
573static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo,
574 unsigned int cmd, unsigned long arg)
575{
589 switch (cmd) { 576 switch (cmd) {
590 case NBD_DISCONNECT: 577 case NBD_DISCONNECT: {
578 struct request sreq;
579
591 printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name); 580 printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name);
581
592 blk_rq_init(NULL, &sreq); 582 blk_rq_init(NULL, &sreq);
593 sreq.cmd_type = REQ_TYPE_SPECIAL; 583 sreq.cmd_type = REQ_TYPE_SPECIAL;
594 nbd_cmd(&sreq) = NBD_CMD_DISC; 584 nbd_cmd(&sreq) = NBD_CMD_DISC;
@@ -599,29 +589,29 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
599 */ 589 */
600 sreq.sector = 0; 590 sreq.sector = 0;
601 sreq.nr_sectors = 0; 591 sreq.nr_sectors = 0;
602 if (!lo->sock) 592 if (!lo->sock)
603 return -EINVAL; 593 return -EINVAL;
604 mutex_lock(&lo->tx_lock); 594 nbd_send_req(lo, &sreq);
605 nbd_send_req(lo, &sreq);
606 mutex_unlock(&lo->tx_lock);
607 return 0; 595 return 0;
596 }
608 597
609 case NBD_CLEAR_SOCK: 598 case NBD_CLEAR_SOCK: {
610 error = 0; 599 struct file *file;
611 mutex_lock(&lo->tx_lock); 600
612 lo->sock = NULL; 601 lo->sock = NULL;
613 mutex_unlock(&lo->tx_lock);
614 file = lo->file; 602 file = lo->file;
615 lo->file = NULL; 603 lo->file = NULL;
616 nbd_clear_que(lo); 604 nbd_clear_que(lo);
617 BUG_ON(!list_empty(&lo->queue_head)); 605 BUG_ON(!list_empty(&lo->queue_head));
618 if (file) 606 if (file)
619 fput(file); 607 fput(file);
620 return error; 608 return 0;
621 case NBD_SET_SOCK: 609 }
610
611 case NBD_SET_SOCK: {
612 struct file *file;
622 if (lo->file) 613 if (lo->file)
623 return -EBUSY; 614 return -EBUSY;
624 error = -EINVAL;
625 file = fget(arg); 615 file = fget(arg);
626 if (file) { 616 if (file) {
627 struct inode *inode = file->f_path.dentry->d_inode; 617 struct inode *inode = file->f_path.dentry->d_inode;
@@ -630,12 +620,14 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
630 lo->sock = SOCKET_I(inode); 620 lo->sock = SOCKET_I(inode);
631 if (max_part > 0) 621 if (max_part > 0)
632 bdev->bd_invalidated = 1; 622 bdev->bd_invalidated = 1;
633 error = 0; 623 return 0;
634 } else { 624 } else {
635 fput(file); 625 fput(file);
636 } 626 }
637 } 627 }
638 return error; 628 return -EINVAL;
629 }
630
639 case NBD_SET_BLKSIZE: 631 case NBD_SET_BLKSIZE:
640 lo->blksize = arg; 632 lo->blksize = arg;
641 lo->bytesize &= ~(lo->blksize-1); 633 lo->bytesize &= ~(lo->blksize-1);
@@ -643,35 +635,50 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
643 set_blocksize(bdev, lo->blksize); 635 set_blocksize(bdev, lo->blksize);
644 set_capacity(lo->disk, lo->bytesize >> 9); 636 set_capacity(lo->disk, lo->bytesize >> 9);
645 return 0; 637 return 0;
638
646 case NBD_SET_SIZE: 639 case NBD_SET_SIZE:
647 lo->bytesize = arg & ~(lo->blksize-1); 640 lo->bytesize = arg & ~(lo->blksize-1);
648 bdev->bd_inode->i_size = lo->bytesize; 641 bdev->bd_inode->i_size = lo->bytesize;
649 set_blocksize(bdev, lo->blksize); 642 set_blocksize(bdev, lo->blksize);
650 set_capacity(lo->disk, lo->bytesize >> 9); 643 set_capacity(lo->disk, lo->bytesize >> 9);
651 return 0; 644 return 0;
645
652 case NBD_SET_TIMEOUT: 646 case NBD_SET_TIMEOUT:
653 lo->xmit_timeout = arg * HZ; 647 lo->xmit_timeout = arg * HZ;
654 return 0; 648 return 0;
649
655 case NBD_SET_SIZE_BLOCKS: 650 case NBD_SET_SIZE_BLOCKS:
656 lo->bytesize = ((u64) arg) * lo->blksize; 651 lo->bytesize = ((u64) arg) * lo->blksize;
657 bdev->bd_inode->i_size = lo->bytesize; 652 bdev->bd_inode->i_size = lo->bytesize;
658 set_blocksize(bdev, lo->blksize); 653 set_blocksize(bdev, lo->blksize);
659 set_capacity(lo->disk, lo->bytesize >> 9); 654 set_capacity(lo->disk, lo->bytesize >> 9);
660 return 0; 655 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
662 if (lo->pid) 662 if (lo->pid)
663 return -EBUSY; 663 return -EBUSY;
664 if (!lo->file) 664 if (!lo->file)
665 return -EINVAL; 665 return -EINVAL;
666
667 mutex_unlock(&lo->tx_lock);
668
666 thread = kthread_create(nbd_thread, lo, lo->disk->disk_name); 669 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);
668 return PTR_ERR(thread); 672 return PTR_ERR(thread);
673 }
669 wake_up_process(thread); 674 wake_up_process(thread);
670 error = nbd_do_it(lo); 675 error = nbd_do_it(lo);
671 kthread_stop(thread); 676 kthread_stop(thread);
677
678 mutex_lock(&lo->tx_lock);
672 if (error) 679 if (error)
673 return error; 680 return error;
674 sock_shutdown(lo, 1); 681 sock_shutdown(lo, 0);
675 file = lo->file; 682 file = lo->file;
676 lo->file = NULL; 683 lo->file = NULL;
677 nbd_clear_que(lo); 684 nbd_clear_que(lo);
@@ -684,6 +691,8 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
684 if (max_part > 0) 691 if (max_part > 0)
685 ioctl_by_bdev(bdev, BLKRRPART, 0); 692 ioctl_by_bdev(bdev, BLKRRPART, 0);
686 return lo->harderror; 693 return lo->harderror;
694 }
695
687 case NBD_CLEAR_QUE: 696 case NBD_CLEAR_QUE:
688 /* 697 /*
689 * This is for compatibility only. The queue is always cleared 698 * This is for compatibility only. The queue is always cleared
@@ -691,6 +700,7 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
691 */ 700 */
692 BUG_ON(!lo->sock && !list_empty(&lo->queue_head)); 701 BUG_ON(!lo->sock && !list_empty(&lo->queue_head));
693 return 0; 702 return 0;
703
694 case NBD_PRINT_DEBUG: 704 case NBD_PRINT_DEBUG:
695 printk(KERN_INFO "%s: next = %p, prev = %p, head = %p\n", 705 printk(KERN_INFO "%s: next = %p, prev = %p, head = %p\n",
696 bdev->bd_disk->disk_name, 706 bdev->bd_disk->disk_name,
@@ -698,7 +708,29 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
698 &lo->queue_head); 708 &lo->queue_head);
699 return 0; 709 return 0;
700 } 710 }
701 return -EINVAL; 711 return -ENOTTY;
712}
713
714static 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;
702} 734}
703 735
704static struct block_device_operations nbd_fops = 736static struct block_device_operations nbd_fops =