fbdev: move FBIO_WAITFORVSYNC to linux/fb.h
[safe/jmp/linux-2.6] / drivers / block / nbd.c
index d3a91ca..218d091 100644 (file)
@@ -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.
@@ -27,6 +27,7 @@
 #include <linux/compiler.h>
 #include <linux/err.h>
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <net/sock.h>
 #include <linux/net.h>
 #include <linux/kthread.h>
@@ -110,7 +111,7 @@ static void nbd_end_request(struct request *req)
                        req, error ? "failed" : "done");
 
        spin_lock_irqsave(q->queue_lock, flags);
-       __blk_end_request(req, error, req->nr_sectors << 9);
+       __blk_end_request_all(req, error);
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
 
@@ -231,19 +232,19 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req)
 {
        int result, flags;
        struct nbd_request request;
-       unsigned long size = req->nr_sectors << 9;
+       unsigned long size = blk_rq_bytes(req);
 
        request.magic = htonl(NBD_REQUEST_MAGIC);
        request.type = htonl(nbd_cmd(req));
-       request.from = cpu_to_be64((u64) req->sector << 9);
+       request.from = cpu_to_be64((u64)blk_rq_pos(req) << 9);
        request.len = htonl(size);
        memcpy(request.handle, &req, sizeof(req));
 
-       dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%luB)\n",
+       dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%uB)\n",
                        lo->disk->disk_name, req,
                        nbdcmd_to_ascii(nbd_cmd(req)),
-                       (unsigned long long)req->sector << 9,
-                       req->nr_sectors << 9);
+                       (unsigned long long)blk_rq_pos(req) << 9,
+                       blk_rq_bytes(req));
        result = sock_xmit(lo, 1, &request, sizeof(request),
                        (nbd_cmd(req) == NBD_CMD_WRITE) ? MSG_MORE : 0);
        if (result <= 0) {
@@ -276,7 +277,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,
@@ -406,6 +407,7 @@ static int nbd_do_it(struct nbd_device *lo)
        ret = sysfs_create_file(&disk_to_dev(lo->disk)->kobj, &pid_attr.attr);
        if (ret) {
                printk(KERN_ERR "nbd: sysfs_create_file failed!");
+               lo->pid = 0;
                return ret;
        }
 
@@ -413,6 +415,7 @@ static int nbd_do_it(struct nbd_device *lo)
                nbd_end_request(req);
 
        sysfs_remove_file(&disk_to_dev(lo->disk)->kobj, &pid_attr.attr);
+       lo->pid = 0;
        return 0;
 }
 
@@ -465,9 +468,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;
@@ -529,15 +530,13 @@ 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;
        
-       while ((req = elv_next_request(q)) != NULL) {
+       while ((req = blk_fetch_request(q)) != NULL) {
                struct nbd_device *lo;
 
-               blkdev_dequeue_request(req);
-
                spin_unlock_irq(q->queue_lock);
 
                dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%x)\n",
@@ -547,6 +546,15 @@ static void do_nbd_request(struct request_queue * q)
 
                BUG_ON(lo->magic != LO_MAGIC);
 
+               if (unlikely(!lo->sock)) {
+                       printk(KERN_ERR "%s: Attempted send on closed socket\n",
+                               lo->disk->disk_name);
+                       req->errors++;
+                       nbd_end_request(req);
+                       spin_lock_irq(q->queue_lock);
+                       continue;
+               }
+
                spin_lock_irq(&lo->queue_lock);
                list_add_tail(&req->queuelist, &lo->waiting_queue);
                spin_unlock_irq(&lo->queue_lock);
@@ -557,60 +565,43 @@ 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;
-               /*
-                * Set these to sane values in case server implementation
-                * fails to check the request type first and also to keep
-                * debugging output cleaner.
-                */
-               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;
@@ -619,12 +610,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);
@@ -632,33 +625,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);
@@ -671,6 +681,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
@@ -678,6 +690,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,
@@ -685,10 +698,32 @@ 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 =
+static const struct block_device_operations nbd_fops =
 {
        .owner =        THIS_MODULE,
        .locked_ioctl = nbd_ioctl,
@@ -722,7 +757,6 @@ static int __init nbd_init(void)
 
        for (i = 0; i < nbds_max; i++) {
                struct gendisk *disk = alloc_disk(1 << part_shift);
-               elevator_t *old_e;
                if (!disk)
                        goto out;
                nbd_dev[i].disk = disk;
@@ -736,11 +770,10 @@ static int __init nbd_init(void)
                        put_disk(disk);
                        goto out;
                }
-               old_e = disk->queue->elevator;
-               if (elevator_init(disk->queue, "deadline") == 0 ||
-                       elevator_init(disk->queue, "noop") == 0) {
-                               elevator_exit(old_e);
-               }
+               /*
+                * Tell the block layer that we are not a rotational device
+                */
+               queue_flag_set_unlocked(QUEUE_FLAG_NONROT, disk->queue);
        }
 
        if (register_blkdev(NBD_MAJOR, "nbd")) {