diff options
Diffstat (limited to 'drivers/block/nbd.c')
-rw-r--r-- | drivers/block/nbd.c | 112 |
1 files changed, 71 insertions, 41 deletions
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 8299e2d3b611..4d6de4f15ccb 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * Note that you can not swap over this thing, yet. Seems to work but | 4 | * Note that you can not swap over this thing, yet. Seems to work but |
5 | * deadlocks sometimes - you can not swap over TCP in general. | 5 | * deadlocks sometimes - you can not swap over TCP in general. |
6 | * | 6 | * |
7 | * Copyright 1997-2000 Pavel Machek <pavel@ucw.cz> | 7 | * Copyright 1997-2000, 2008 Pavel Machek <pavel@suse.cz> |
8 | * Parts copyright 2001 Steven Whitehouse <steve@chygwyn.com> | 8 | * Parts copyright 2001 Steven Whitehouse <steve@chygwyn.com> |
9 | * | 9 | * |
10 | * This file is released under GPLv2 or later. | 10 | * This file is released under GPLv2 or later. |
@@ -276,7 +276,7 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req) | |||
276 | return 0; | 276 | return 0; |
277 | 277 | ||
278 | error_out: | 278 | error_out: |
279 | return 1; | 279 | return -EIO; |
280 | } | 280 | } |
281 | 281 | ||
282 | static struct request *nbd_find_request(struct nbd_device *lo, | 282 | static struct request *nbd_find_request(struct nbd_device *lo, |
@@ -467,9 +467,7 @@ static void nbd_handle_req(struct nbd_device *lo, struct request *req) | |||
467 | mutex_unlock(&lo->tx_lock); | 467 | mutex_unlock(&lo->tx_lock); |
468 | printk(KERN_ERR "%s: Attempted send on closed socket\n", | 468 | printk(KERN_ERR "%s: Attempted send on closed socket\n", |
469 | lo->disk->disk_name); | 469 | lo->disk->disk_name); |
470 | req->errors++; | 470 | goto error_out; |
471 | nbd_end_request(req); | ||
472 | return; | ||
473 | } | 471 | } |
474 | 472 | ||
475 | lo->active_req = req; | 473 | lo->active_req = req; |
@@ -531,7 +529,7 @@ static int nbd_thread(void *data) | |||
531 | * { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); } | 529 | * { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); } |
532 | */ | 530 | */ |
533 | 531 | ||
534 | static void do_nbd_request(struct request_queue * q) | 532 | static void do_nbd_request(struct request_queue *q) |
535 | { | 533 | { |
536 | struct request *req; | 534 | struct request *req; |
537 | 535 | ||
@@ -568,27 +566,17 @@ static void do_nbd_request(struct request_queue * q) | |||
568 | } | 566 | } |
569 | } | 567 | } |
570 | 568 | ||
571 | static int nbd_ioctl(struct block_device *bdev, fmode_t mode, | 569 | /* 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 | 570 | ||
571 | static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo, | ||
572 | unsigned int cmd, unsigned long arg) | ||
573 | { | ||
589 | switch (cmd) { | 574 | switch (cmd) { |
590 | case NBD_DISCONNECT: | 575 | case NBD_DISCONNECT: { |
576 | struct request sreq; | ||
577 | |||
591 | printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name); | 578 | printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name); |
579 | |||
592 | blk_rq_init(NULL, &sreq); | 580 | blk_rq_init(NULL, &sreq); |
593 | sreq.cmd_type = REQ_TYPE_SPECIAL; | 581 | sreq.cmd_type = REQ_TYPE_SPECIAL; |
594 | nbd_cmd(&sreq) = NBD_CMD_DISC; | 582 | nbd_cmd(&sreq) = NBD_CMD_DISC; |
@@ -599,29 +587,29 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, | |||
599 | */ | 587 | */ |
600 | sreq.sector = 0; | 588 | sreq.sector = 0; |
601 | sreq.nr_sectors = 0; | 589 | sreq.nr_sectors = 0; |
602 | if (!lo->sock) | 590 | if (!lo->sock) |
603 | return -EINVAL; | 591 | return -EINVAL; |
604 | mutex_lock(&lo->tx_lock); | 592 | nbd_send_req(lo, &sreq); |
605 | nbd_send_req(lo, &sreq); | ||
606 | mutex_unlock(&lo->tx_lock); | ||
607 | return 0; | 593 | return 0; |
594 | } | ||
608 | 595 | ||
609 | case NBD_CLEAR_SOCK: | 596 | case NBD_CLEAR_SOCK: { |
610 | error = 0; | 597 | struct file *file; |
611 | mutex_lock(&lo->tx_lock); | 598 | |
612 | lo->sock = NULL; | 599 | lo->sock = NULL; |
613 | mutex_unlock(&lo->tx_lock); | ||
614 | file = lo->file; | 600 | file = lo->file; |
615 | lo->file = NULL; | 601 | lo->file = NULL; |
616 | nbd_clear_que(lo); | 602 | nbd_clear_que(lo); |
617 | BUG_ON(!list_empty(&lo->queue_head)); | 603 | BUG_ON(!list_empty(&lo->queue_head)); |
618 | if (file) | 604 | if (file) |
619 | fput(file); | 605 | fput(file); |
620 | return error; | 606 | return 0; |
621 | case NBD_SET_SOCK: | 607 | } |
608 | |||
609 | case NBD_SET_SOCK: { | ||
610 | struct file *file; | ||
622 | if (lo->file) | 611 | if (lo->file) |
623 | return -EBUSY; | 612 | return -EBUSY; |
624 | error = -EINVAL; | ||
625 | file = fget(arg); | 613 | file = fget(arg); |
626 | if (file) { | 614 | if (file) { |
627 | struct inode *inode = file->f_path.dentry->d_inode; | 615 | struct inode *inode = file->f_path.dentry->d_inode; |
@@ -630,12 +618,14 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, | |||
630 | lo->sock = SOCKET_I(inode); | 618 | lo->sock = SOCKET_I(inode); |
631 | if (max_part > 0) | 619 | if (max_part > 0) |
632 | bdev->bd_invalidated = 1; | 620 | bdev->bd_invalidated = 1; |
633 | error = 0; | 621 | return 0; |
634 | } else { | 622 | } else { |
635 | fput(file); | 623 | fput(file); |
636 | } | 624 | } |
637 | } | 625 | } |
638 | return error; | 626 | return -EINVAL; |
627 | } | ||
628 | |||
639 | case NBD_SET_BLKSIZE: | 629 | case NBD_SET_BLKSIZE: |
640 | lo->blksize = arg; | 630 | lo->blksize = arg; |
641 | lo->bytesize &= ~(lo->blksize-1); | 631 | lo->bytesize &= ~(lo->blksize-1); |
@@ -643,35 +633,50 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, | |||
643 | set_blocksize(bdev, lo->blksize); | 633 | set_blocksize(bdev, lo->blksize); |
644 | set_capacity(lo->disk, lo->bytesize >> 9); | 634 | set_capacity(lo->disk, lo->bytesize >> 9); |
645 | return 0; | 635 | return 0; |
636 | |||
646 | case NBD_SET_SIZE: | 637 | case NBD_SET_SIZE: |
647 | lo->bytesize = arg & ~(lo->blksize-1); | 638 | lo->bytesize = arg & ~(lo->blksize-1); |
648 | bdev->bd_inode->i_size = lo->bytesize; | 639 | bdev->bd_inode->i_size = lo->bytesize; |
649 | set_blocksize(bdev, lo->blksize); | 640 | set_blocksize(bdev, lo->blksize); |
650 | set_capacity(lo->disk, lo->bytesize >> 9); | 641 | set_capacity(lo->disk, lo->bytesize >> 9); |
651 | return 0; | 642 | return 0; |
643 | |||
652 | case NBD_SET_TIMEOUT: | 644 | case NBD_SET_TIMEOUT: |
653 | lo->xmit_timeout = arg * HZ; | 645 | lo->xmit_timeout = arg * HZ; |
654 | return 0; | 646 | return 0; |
647 | |||
655 | case NBD_SET_SIZE_BLOCKS: | 648 | case NBD_SET_SIZE_BLOCKS: |
656 | lo->bytesize = ((u64) arg) * lo->blksize; | 649 | lo->bytesize = ((u64) arg) * lo->blksize; |
657 | bdev->bd_inode->i_size = lo->bytesize; | 650 | bdev->bd_inode->i_size = lo->bytesize; |
658 | set_blocksize(bdev, lo->blksize); | 651 | set_blocksize(bdev, lo->blksize); |
659 | set_capacity(lo->disk, lo->bytesize >> 9); | 652 | set_capacity(lo->disk, lo->bytesize >> 9); |
660 | return 0; | 653 | return 0; |
661 | case NBD_DO_IT: | 654 | |
655 | case NBD_DO_IT: { | ||
656 | struct task_struct *thread; | ||
657 | struct file *file; | ||
658 | int error; | ||
659 | |||
662 | if (lo->pid) | 660 | if (lo->pid) |
663 | return -EBUSY; | 661 | return -EBUSY; |
664 | if (!lo->file) | 662 | if (!lo->file) |
665 | return -EINVAL; | 663 | return -EINVAL; |
664 | |||
665 | mutex_unlock(&lo->tx_lock); | ||
666 | |||
666 | thread = kthread_create(nbd_thread, lo, lo->disk->disk_name); | 667 | thread = kthread_create(nbd_thread, lo, lo->disk->disk_name); |
667 | if (IS_ERR(thread)) | 668 | if (IS_ERR(thread)) { |
669 | mutex_lock(&lo->tx_lock); | ||
668 | return PTR_ERR(thread); | 670 | return PTR_ERR(thread); |
671 | } | ||
669 | wake_up_process(thread); | 672 | wake_up_process(thread); |
670 | error = nbd_do_it(lo); | 673 | error = nbd_do_it(lo); |
671 | kthread_stop(thread); | 674 | kthread_stop(thread); |
675 | |||
676 | mutex_lock(&lo->tx_lock); | ||
672 | if (error) | 677 | if (error) |
673 | return error; | 678 | return error; |
674 | sock_shutdown(lo, 1); | 679 | sock_shutdown(lo, 0); |
675 | file = lo->file; | 680 | file = lo->file; |
676 | lo->file = NULL; | 681 | lo->file = NULL; |
677 | nbd_clear_que(lo); | 682 | nbd_clear_que(lo); |
@@ -684,6 +689,8 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, | |||
684 | if (max_part > 0) | 689 | if (max_part > 0) |
685 | ioctl_by_bdev(bdev, BLKRRPART, 0); | 690 | ioctl_by_bdev(bdev, BLKRRPART, 0); |
686 | return lo->harderror; | 691 | return lo->harderror; |
692 | } | ||
693 | |||
687 | case NBD_CLEAR_QUE: | 694 | case NBD_CLEAR_QUE: |
688 | /* | 695 | /* |
689 | * This is for compatibility only. The queue is always cleared | 696 | * This is for compatibility only. The queue is always cleared |
@@ -691,6 +698,7 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, | |||
691 | */ | 698 | */ |
692 | BUG_ON(!lo->sock && !list_empty(&lo->queue_head)); | 699 | BUG_ON(!lo->sock && !list_empty(&lo->queue_head)); |
693 | return 0; | 700 | return 0; |
701 | |||
694 | case NBD_PRINT_DEBUG: | 702 | case NBD_PRINT_DEBUG: |
695 | printk(KERN_INFO "%s: next = %p, prev = %p, head = %p\n", | 703 | printk(KERN_INFO "%s: next = %p, prev = %p, head = %p\n", |
696 | bdev->bd_disk->disk_name, | 704 | bdev->bd_disk->disk_name, |
@@ -698,7 +706,29 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, | |||
698 | &lo->queue_head); | 706 | &lo->queue_head); |
699 | return 0; | 707 | return 0; |
700 | } | 708 | } |
701 | return -EINVAL; | 709 | return -ENOTTY; |
710 | } | ||
711 | |||
712 | static int nbd_ioctl(struct block_device *bdev, fmode_t mode, | ||
713 | unsigned int cmd, unsigned long arg) | ||
714 | { | ||
715 | struct nbd_device *lo = bdev->bd_disk->private_data; | ||
716 | int error; | ||
717 | |||
718 | if (!capable(CAP_SYS_ADMIN)) | ||
719 | return -EPERM; | ||
720 | |||
721 | BUG_ON(lo->magic != LO_MAGIC); | ||
722 | |||
723 | /* Anyone capable of this syscall can do *real bad* things */ | ||
724 | dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n", | ||
725 | lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg); | ||
726 | |||
727 | mutex_lock(&lo->tx_lock); | ||
728 | error = __nbd_ioctl(bdev, lo, cmd, arg); | ||
729 | mutex_unlock(&lo->tx_lock); | ||
730 | |||
731 | return error; | ||
702 | } | 732 | } |
703 | 733 | ||
704 | static struct block_device_operations nbd_fops = | 734 | static struct block_device_operations nbd_fops = |