summaryrefslogtreecommitdiffstats
path: root/drivers/block/nbd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/block/nbd.c')
-rw-r--r--drivers/block/nbd.c112
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 @@
* Note that you can not swap over this thing, yet. Seems to work but
* deadlocks sometimes - you can not swap over TCP in general.
*
- * Copyright 1997-2000 Pavel Machek <pavel@ucw.cz>
+ * Copyright 1997-2000, 2008 Pavel Machek <pavel@suse.cz>
* Parts copyright 2001 Steven Whitehouse <steve@chygwyn.com>
*
* This file is released under GPLv2 or later.
@@ -276,7 +276,7 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req)
return 0;
error_out:
- return 1;
+ return -EIO;
}
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)
mutex_unlock(&lo->tx_lock);
printk(KERN_ERR "%s: Attempted send on closed socket\n",
lo->disk->disk_name);
- req->errors++;
- nbd_end_request(req);
- return;
+ goto error_out;
}
lo->active_req = req;
@@ -531,7 +529,7 @@ static int nbd_thread(void *data)
* { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); }
*/
-static void do_nbd_request(struct request_queue * q)
+static void do_nbd_request(struct request_queue *q)
{
struct request *req;
@@ -568,27 +566,17 @@ static void do_nbd_request(struct request_queue * q)
}
}
-static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg)
-{
- struct nbd_device *lo = bdev->bd_disk->private_data;
- struct file *file;
- int error;
- struct request sreq ;
- struct task_struct *thread;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- BUG_ON(lo->magic != LO_MAGIC);
-
- /* Anyone capable of this syscall can do *real bad* things */
- dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n",
- lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg);
+/* Must be called with tx_lock held */
+static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo,
+ unsigned int cmd, unsigned long arg)
+{
switch (cmd) {
- case NBD_DISCONNECT:
+ case NBD_DISCONNECT: {
+ struct request sreq;
+
printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name);
+
blk_rq_init(NULL, &sreq);
sreq.cmd_type = REQ_TYPE_SPECIAL;
nbd_cmd(&sreq) = NBD_CMD_DISC;
@@ -599,29 +587,29 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
*/
sreq.sector = 0;
sreq.nr_sectors = 0;
- if (!lo->sock)
+ if (!lo->sock)
return -EINVAL;
- mutex_lock(&lo->tx_lock);
- nbd_send_req(lo, &sreq);
- mutex_unlock(&lo->tx_lock);
+ nbd_send_req(lo, &sreq);
return 0;
+ }
- case NBD_CLEAR_SOCK:
- error = 0;
- mutex_lock(&lo->tx_lock);
+ case NBD_CLEAR_SOCK: {
+ struct file *file;
+
lo->sock = NULL;
- mutex_unlock(&lo->tx_lock);
file = lo->file;
lo->file = NULL;
nbd_clear_que(lo);
BUG_ON(!list_empty(&lo->queue_head));
if (file)
fput(file);
- return error;
- case NBD_SET_SOCK:
+ return 0;
+ }
+
+ case NBD_SET_SOCK: {
+ struct file *file;
if (lo->file)
return -EBUSY;
- error = -EINVAL;
file = fget(arg);
if (file) {
struct inode *inode = file->f_path.dentry->d_inode;
@@ -630,12 +618,14 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
lo->sock = SOCKET_I(inode);
if (max_part > 0)
bdev->bd_invalidated = 1;
- error = 0;
+ return 0;
} else {
fput(file);
}
}
- return error;
+ return -EINVAL;
+ }
+
case NBD_SET_BLKSIZE:
lo->blksize = arg;
lo->bytesize &= ~(lo->blksize-1);
@@ -643,35 +633,50 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
set_blocksize(bdev, lo->blksize);
set_capacity(lo->disk, lo->bytesize >> 9);
return 0;
+
case NBD_SET_SIZE:
lo->bytesize = arg & ~(lo->blksize-1);
bdev->bd_inode->i_size = lo->bytesize;
set_blocksize(bdev, lo->blksize);
set_capacity(lo->disk, lo->bytesize >> 9);
return 0;
+
case NBD_SET_TIMEOUT:
lo->xmit_timeout = arg * HZ;
return 0;
+
case NBD_SET_SIZE_BLOCKS:
lo->bytesize = ((u64) arg) * lo->blksize;
bdev->bd_inode->i_size = lo->bytesize;
set_blocksize(bdev, lo->blksize);
set_capacity(lo->disk, lo->bytesize >> 9);
return 0;
- case NBD_DO_IT:
+
+ case NBD_DO_IT: {
+ struct task_struct *thread;
+ struct file *file;
+ int error;
+
if (lo->pid)
return -EBUSY;
if (!lo->file)
return -EINVAL;
+
+ mutex_unlock(&lo->tx_lock);
+
thread = kthread_create(nbd_thread, lo, lo->disk->disk_name);
- if (IS_ERR(thread))
+ if (IS_ERR(thread)) {
+ mutex_lock(&lo->tx_lock);
return PTR_ERR(thread);
+ }
wake_up_process(thread);
error = nbd_do_it(lo);
kthread_stop(thread);
+
+ mutex_lock(&lo->tx_lock);
if (error)
return error;
- sock_shutdown(lo, 1);
+ sock_shutdown(lo, 0);
file = lo->file;
lo->file = NULL;
nbd_clear_que(lo);
@@ -684,6 +689,8 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
if (max_part > 0)
ioctl_by_bdev(bdev, BLKRRPART, 0);
return lo->harderror;
+ }
+
case NBD_CLEAR_QUE:
/*
* 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,
*/
BUG_ON(!lo->sock && !list_empty(&lo->queue_head));
return 0;
+
case NBD_PRINT_DEBUG:
printk(KERN_INFO "%s: next = %p, prev = %p, head = %p\n",
bdev->bd_disk->disk_name,
@@ -698,7 +706,29 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
&lo->queue_head);
return 0;
}
- return -EINVAL;
+ return -ENOTTY;
+}
+
+static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
+{
+ struct nbd_device *lo = bdev->bd_disk->private_data;
+ int error;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ BUG_ON(lo->magic != LO_MAGIC);
+
+ /* Anyone capable of this syscall can do *real bad* things */
+ dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n",
+ lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg);
+
+ mutex_lock(&lo->tx_lock);
+ error = __nbd_ioctl(bdev, lo, cmd, arg);
+ mutex_unlock(&lo->tx_lock);
+
+ return error;
}
static struct block_device_operations nbd_fops =