nbd.c revision a8cdc308c0ca3809e37e2be62174906a45b92670
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Network block device - make block devices work over TCP
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that you can not swap over this thing, yet. Seems to work but
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * deadlocks sometimes - you can not swap over TCP in general.
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 1997-2000 Pavel Machek <pavel@ucw.cz>
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Parts copyright 2001 Steven Whitehouse <steve@chygwyn.com>
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10dbf492d6c1a1bf5a8bda40274f479119f4c42ca4Pavel Machek * This file is released under GPLv2 or later.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
12dbf492d6c1a1bf5a8bda40274f479119f4c42ca4Pavel Machek * (part of code stolen from loop.c)
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/major.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bio.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/stat.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/file.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioctl.h>
274b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu#include <linux/compiler.h>
284b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu#include <linux/err.h>
294b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu#include <linux/kernel.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/sock.h>
3191cf45f02af5c871251165d000c3f42a2a0b0552Trond Myklebust#include <linux/net.h>
3248cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier#include <linux/kthread.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
354b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu#include <asm/system.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/types.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/nbd.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LO_MAGIC 0x68797548
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef NDEBUG
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define dprintk(flags, fmt...)
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else /* NDEBUG */
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define dprintk(flags, fmt...) do { \
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (debugflags & (flags)) printk(KERN_DEBUG fmt); \
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0)
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG_IOCTL       0x0004
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG_INIT        0x0010
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG_EXIT        0x0020
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG_BLKDEV      0x0100
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG_RX          0x0200
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG_TX          0x0400
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int debugflags;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* NDEBUG */
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
579c7a41691f37a1538a88e5eb9b0b73df1f834542Ingo van Lilstatic unsigned int nbds_max = 16;
5820a8143eaa3300a58326156eaf43e03db0fd2cb6Paul Clementsstatic struct nbd_device *nbd_dev;
59d71a6d7332e5881a65249f4fb97b0db3c61dd5ecLaurent Vivierstatic int max_part;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Use just one lock (or at most 1 per NIC). Two arguments for this:
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1. Each NIC is essentially a synchronization point for all servers
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    accessed through that NIC so there's no need to have more locks
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    than NICs anyway.
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2. More locks lead to more "Dirty cache line bouncing" which will slow
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    down each lock to the point where they're actually slower than just
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    a single lock.
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Thanks go to Jens Axboe and Al Viro for their LKML emails explaining this!
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_SPINLOCK(nbd_lock);
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef NDEBUG
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *ioctl_cmd_to_ascii(int cmd)
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NBD_SET_SOCK: return "set-sock";
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NBD_SET_BLKSIZE: return "set-blksize";
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NBD_SET_SIZE: return "set-size";
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NBD_DO_IT: return "do-it";
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NBD_CLEAR_SOCK: return "clear-sock";
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NBD_CLEAR_QUE: return "clear-que";
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NBD_PRINT_DEBUG: return "print-debug";
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NBD_SET_SIZE_BLOCKS: return "set-size-blocks";
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NBD_DISCONNECT: return "disconnect";
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BLKROSET: return "set-read-only";
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case BLKFLSBUF: return "flush-buffer-cache";
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return "unknown";
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *nbdcmd_to_ascii(int cmd)
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case  NBD_CMD_READ: return "read";
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NBD_CMD_WRITE: return "write";
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case  NBD_CMD_DISC: return "disconnect";
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return "invalid";
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* NDEBUG */
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void nbd_end_request(struct request *req)
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
105097c94a4e8bde978c8d12683d9a34048e9139e4bKiyoshi Ueda	int error = req->errors ? -EIO : 0;
106165125e1e480f9510a5ffcfbfee4e3ee38c05f23Jens Axboe	struct request_queue *q = req->q;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk(DBG_BLKDEV, "%s: request %p: %s\n", req->rq_disk->disk_name,
110097c94a4e8bde978c8d12683d9a34048e9139e4bKiyoshi Ueda			req, error ? "failed" : "done");
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(q->queue_lock, flags);
113097c94a4e8bde978c8d12683d9a34048e9139e4bKiyoshi Ueda	__blk_end_request(req, error, req->nr_sectors << 9);
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(q->queue_lock, flags);
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1177fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clementsstatic void sock_shutdown(struct nbd_device *lo, int lock)
1187fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements{
1197fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements	/* Forcibly shutdown the socket causing all listeners
1207fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements	 * to error
1217fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements	 *
1227fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements	 * FIXME: This code is duplicated from sys_shutdown, but
1237fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements	 * there should be a more generic interface rather than
1247fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements	 * calling socket ops directly here */
1257fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements	if (lock)
1267fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements		mutex_lock(&lo->tx_lock);
1277fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements	if (lo->sock) {
1287fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements		printk(KERN_WARNING "%s: shutting down socket\n",
1297fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements			lo->disk->disk_name);
13091cf45f02af5c871251165d000c3f42a2a0b0552Trond Myklebust		kernel_sock_shutdown(lo->sock, SHUT_RDWR);
1317fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements		lo->sock = NULL;
1327fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements	}
1337fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements	if (lock)
1347fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements		mutex_unlock(&lo->tx_lock);
1357fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements}
1367fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements
1377fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clementsstatic void nbd_xmit_timeout(unsigned long arg)
1387fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements{
1397fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements	struct task_struct *task = (struct task_struct *)arg;
1407fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements
1417fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements	printk(KERN_WARNING "nbd: killing hung xmit (%s, pid: %d)\n",
1427fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements		task->comm, task->pid);
1437fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements	force_sig(SIGKILL, task);
1447fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements}
1457fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Send or receive packet.
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1497fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clementsstatic int sock_xmit(struct nbd_device *lo, int send, void *buf, int size,
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int msg_flags)
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1527fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements	struct socket *sock = lo->sock;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct msghdr msg;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kvec iov;
156be0ef957c9eed4ebae873ee3fbcfb9dfde486decOleg Nesterov	sigset_t blocked, oldset;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
158ffc41cf8dbb1b895a87daf47d0e5bf6dfbfcab4cMike Snitzer	if (unlikely(!sock)) {
159ffc41cf8dbb1b895a87daf47d0e5bf6dfbfcab4cMike Snitzer		printk(KERN_ERR "%s: Attempted %s on closed socket in sock_xmit\n",
160ffc41cf8dbb1b895a87daf47d0e5bf6dfbfcab4cMike Snitzer		       lo->disk->disk_name, (send ? "send" : "recv"));
161ffc41cf8dbb1b895a87daf47d0e5bf6dfbfcab4cMike Snitzer		return -EINVAL;
162ffc41cf8dbb1b895a87daf47d0e5bf6dfbfcab4cMike Snitzer	}
163ffc41cf8dbb1b895a87daf47d0e5bf6dfbfcab4cMike Snitzer
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Allow interception of SIGKILL only
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Don't allow other signals to interrupt the transmission */
166be0ef957c9eed4ebae873ee3fbcfb9dfde486decOleg Nesterov	siginitsetinv(&blocked, sigmask(SIGKILL));
167be0ef957c9eed4ebae873ee3fbcfb9dfde486decOleg Nesterov	sigprocmask(SIG_SETMASK, &blocked, &oldset);
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sock->sk->sk_allocation = GFP_NOIO;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iov.iov_base = buf;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iov.iov_len = size;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		msg.msg_name = NULL;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		msg.msg_namelen = 0;
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		msg.msg_control = NULL;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		msg.msg_controllen = 0;
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		msg.msg_flags = msg_flags | MSG_NOSIGNAL;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1797fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements		if (send) {
1807fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements			struct timer_list ti;
1817fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements
1827fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements			if (lo->xmit_timeout) {
1837fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements				init_timer(&ti);
1847fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements				ti.function = nbd_xmit_timeout;
1857fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements				ti.data = (unsigned long)current;
1867fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements				ti.expires = jiffies + lo->xmit_timeout;
1877fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements				add_timer(&ti);
1887fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements			}
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			result = kernel_sendmsg(sock, &msg, &iov, 1, size);
1907fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements			if (lo->xmit_timeout)
1917fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements				del_timer_sync(&ti);
1927fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements		} else
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			result = kernel_recvmsg(sock, &msg, &iov, 1, size, 0);
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (signal_pending(current)) {
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			siginfo_t info;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_WARNING "nbd (pid %d: %s) got signal %d\n",
198ba25f9dcc4ea6e30839fcab5a5516f2176d5bfedPavel Emelyanov				task_pid_nr(current), current->comm,
199be0ef957c9eed4ebae873ee3fbcfb9dfde486decOleg Nesterov				dequeue_signal_lock(current, &current->blocked, &info));
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			result = -EINTR;
2017fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements			sock_shutdown(lo, !send);
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (result <= 0) {
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (result == 0)
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				result = -EPIPE; /* short read */
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size -= result;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf += result;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while (size > 0);
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
214be0ef957c9eed4ebae873ee3fbcfb9dfde486decOleg Nesterov	sigprocmask(SIG_SETMASK, &oldset, NULL);
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2197fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clementsstatic inline int sock_send_bvec(struct nbd_device *lo, struct bio_vec *bvec,
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int flags)
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *kaddr = kmap(bvec->bv_page);
2247fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements	result = sock_xmit(lo, 1, kaddr + bvec->bv_offset, bvec->bv_len, flags);
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kunmap(bvec->bv_page);
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2297fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements/* always call with the tx_lock held */
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nbd_send_req(struct nbd_device *lo, struct request *req)
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2325705f7021748a69d84d6567e68e8851dab551464NeilBrown	int result, flags;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nbd_request request;
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long size = req->nr_sectors << 9;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	request.magic = htonl(NBD_REQUEST_MAGIC);
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	request.type = htonl(nbd_cmd(req));
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	request.from = cpu_to_be64((u64) req->sector << 9);
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	request.len = htonl(size);
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(request.handle, &req, sizeof(req));
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%luB)\n",
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lo->disk->disk_name, req,
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nbdcmd_to_ascii(nbd_cmd(req)),
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(unsigned long long)req->sector << 9,
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			req->nr_sectors << 9);
2477fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements	result = sock_xmit(lo, 1, &request, sizeof(request),
2487fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements			(nbd_cmd(req) == NBD_CMD_WRITE) ? MSG_MORE : 0);
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result <= 0) {
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "%s: Send control failed (result %d)\n",
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lo->disk->disk_name, result);
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error_out;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (nbd_cmd(req) == NBD_CMD_WRITE) {
2565705f7021748a69d84d6567e68e8851dab551464NeilBrown		struct req_iterator iter;
2575705f7021748a69d84d6567e68e8851dab551464NeilBrown		struct bio_vec *bvec;
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * we are really probing at internals to determine
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * whether to set MSG_MORE or not...
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
2625705f7021748a69d84d6567e68e8851dab551464NeilBrown		rq_for_each_segment(bvec, req, iter) {
2636c92e699b56287da582ccb12a64b959b6d6109baJens Axboe			flags = 0;
2646c92e699b56287da582ccb12a64b959b6d6109baJens Axboe			if (!rq_iter_last(req, iter))
2656c92e699b56287da582ccb12a64b959b6d6109baJens Axboe				flags = MSG_MORE;
2666c92e699b56287da582ccb12a64b959b6d6109baJens Axboe			dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n",
2676c92e699b56287da582ccb12a64b959b6d6109baJens Axboe					lo->disk->disk_name, req, bvec->bv_len);
2687fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements			result = sock_send_bvec(lo, bvec, flags);
2696c92e699b56287da582ccb12a64b959b6d6109baJens Axboe			if (result <= 0) {
2706c92e699b56287da582ccb12a64b959b6d6109baJens Axboe				printk(KERN_ERR "%s: Send data failed (result %d)\n",
2716c92e699b56287da582ccb12a64b959b6d6109baJens Axboe						lo->disk->disk_name, result);
2726c92e699b56287da582ccb12a64b959b6d6109baJens Axboe				goto error_out;
2736c92e699b56287da582ccb12a64b959b6d6109baJens Axboe			}
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror_out:
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2820cbc591bf884a5662b2fbb21b5c09fa1c1c7b579Denis Chengstatic struct request *nbd_find_request(struct nbd_device *lo,
2830cbc591bf884a5662b2fbb21b5c09fa1c1c7b579Denis Cheng					struct request *xreq)
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
285d2c9740b499f959ed513375b6e35c2ab161921cbDenis Cheng	struct request *req, *tmp;
2864b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu	int err;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2884b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu	err = wait_event_interruptible(lo->active_wq, lo->active_req != xreq);
2894b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu	if (unlikely(err))
2904b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu		goto out;
2914b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&lo->queue_lock);
293d2c9740b499f959ed513375b6e35c2ab161921cbDenis Cheng	list_for_each_entry_safe(req, tmp, &lo->queue_head, queuelist) {
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (req != xreq)
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_del_init(&req->queuelist);
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock(&lo->queue_lock);
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return req;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&lo->queue_lock);
3014b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu
3024b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu	err = -ENOENT;
3034b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu
3044b2f0260c74324abca76ccaa42d426af163125e7Herbert Xuout:
3054b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu	return ERR_PTR(err);
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3087fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clementsstatic inline int sock_recv_bvec(struct nbd_device *lo, struct bio_vec *bvec)
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *kaddr = kmap(bvec->bv_page);
3127fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements	result = sock_xmit(lo, 0, kaddr + bvec->bv_offset, bvec->bv_len,
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			MSG_WAITALL);
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kunmap(bvec->bv_page);
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* NULL returned = something went wrong, inform userspace */
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct request *nbd_read_stat(struct nbd_device *lo)
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nbd_reply reply;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct request *req;
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reply.magic = 0;
3267fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements	result = sock_xmit(lo, 0, &reply, sizeof(reply), MSG_WAITALL);
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result <= 0) {
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "%s: Receive control failed (result %d)\n",
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lo->disk->disk_name, result);
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto harderror;
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
332e4b57e0842621f597d744b193ea325d62724596bMichal Feix
333e4b57e0842621f597d744b193ea325d62724596bMichal Feix	if (ntohl(reply.magic) != NBD_REPLY_MAGIC) {
334e4b57e0842621f597d744b193ea325d62724596bMichal Feix		printk(KERN_ERR "%s: Wrong magic (0x%lx)\n",
335e4b57e0842621f597d744b193ea325d62724596bMichal Feix				lo->disk->disk_name,
336e4b57e0842621f597d744b193ea325d62724596bMichal Feix				(unsigned long)ntohl(reply.magic));
337e4b57e0842621f597d744b193ea325d62724596bMichal Feix		result = -EPROTO;
338e4b57e0842621f597d744b193ea325d62724596bMichal Feix		goto harderror;
339e4b57e0842621f597d744b193ea325d62724596bMichal Feix	}
340e4b57e0842621f597d744b193ea325d62724596bMichal Feix
3410cbc591bf884a5662b2fbb21b5c09fa1c1c7b579Denis Cheng	req = nbd_find_request(lo, *(struct request **)reply.handle);
342801678c5a3b4c79236970bcca27c733f5559e0d1Hirofumi Nakagawa	if (IS_ERR(req)) {
3434b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu		result = PTR_ERR(req);
3444b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu		if (result != -ENOENT)
3454b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu			goto harderror;
3464b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "%s: Unexpected reply (%p)\n",
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lo->disk->disk_name, reply.handle);
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = -EBADR;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto harderror;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ntohl(reply.error)) {
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "%s: Other side returned error (%d)\n",
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lo->disk->disk_name, ntohl(reply.error));
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->errors++;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return req;
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk(DBG_RX, "%s: request %p: got reply\n",
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lo->disk->disk_name, req);
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (nbd_cmd(req) == NBD_CMD_READ) {
3635705f7021748a69d84d6567e68e8851dab551464NeilBrown		struct req_iterator iter;
3645705f7021748a69d84d6567e68e8851dab551464NeilBrown		struct bio_vec *bvec;
3655705f7021748a69d84d6567e68e8851dab551464NeilBrown
3665705f7021748a69d84d6567e68e8851dab551464NeilBrown		rq_for_each_segment(bvec, req, iter) {
3677fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements			result = sock_recv_bvec(lo, bvec);
3686c92e699b56287da582ccb12a64b959b6d6109baJens Axboe			if (result <= 0) {
3696c92e699b56287da582ccb12a64b959b6d6109baJens Axboe				printk(KERN_ERR "%s: Receive data failed (result %d)\n",
3706c92e699b56287da582ccb12a64b959b6d6109baJens Axboe						lo->disk->disk_name, result);
3716c92e699b56287da582ccb12a64b959b6d6109baJens Axboe				req->errors++;
3726c92e699b56287da582ccb12a64b959b6d6109baJens Axboe				return req;
3736c92e699b56287da582ccb12a64b959b6d6109baJens Axboe			}
3746c92e699b56287da582ccb12a64b959b6d6109baJens Axboe			dprintk(DBG_RX, "%s: request %p: got %d bytes data\n",
3756c92e699b56287da582ccb12a64b959b6d6109baJens Axboe				lo->disk->disk_name, req, bvec->bv_len);
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return req;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsharderror:
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lo->harderror = result;
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
384edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sieversstatic ssize_t pid_show(struct device *dev,
385edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sievers			struct device_attribute *attr, char *buf)
3866b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements{
387edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sievers	struct gendisk *disk = dev_to_disk(dev);
388edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sievers
389edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sievers	return sprintf(buf, "%ld\n",
3906b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements		(long) ((struct nbd_device *)disk->private_data)->pid);
3916b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements}
3926b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements
393edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sieversstatic struct device_attribute pid_attr = {
39401e8ef11bc1a74e65678ed55795f59266d4add01Parag Warudkar	.attr = { .name = "pid", .mode = S_IRUGO},
3956b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements	.show = pid_show,
3966b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements};
3976b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements
39884963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Congstatic int nbd_do_it(struct nbd_device *lo)
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct request *req;
40184963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Cong	int ret;
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUG_ON(lo->magic != LO_MAGIC);
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4056b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements	lo->pid = current->pid;
406ed9e1982347b36573cd622ee5f4e2a7ccd79b3fdTejun Heo	ret = sysfs_create_file(&disk_to_dev(lo->disk)->kobj, &pid_attr.attr);
40784963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Cong	if (ret) {
40884963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Cong		printk(KERN_ERR "nbd: sysfs_create_file failed!");
40984963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Cong		return ret;
41084963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Cong	}
4116b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((req = nbd_read_stat(lo)) != NULL)
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nbd_end_request(req);
4146b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements
415ed9e1982347b36573cd622ee5f4e2a7ccd79b3fdTejun Heo	sysfs_remove_file(&disk_to_dev(lo->disk)->kobj, &pid_attr.attr);
41684963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Cong	return 0;
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void nbd_clear_que(struct nbd_device *lo)
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct request *req;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUG_ON(lo->magic != LO_MAGIC);
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4254b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu	/*
4264b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu	 * Because we have set lo->sock to NULL under the tx_lock, all
4274b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu	 * modifications to the list must have completed by now.  For
4284b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu	 * the same reason, the active_req must be NULL.
4294b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu	 *
4304b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu	 * As a consequence, we don't need to take the spin lock while
4314b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu	 * purging the list here.
4324b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu	 */
4334b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu	BUG_ON(lo->sock);
4344b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu	BUG_ON(lo->active_req);
4354b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu
4364b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu	while (!list_empty(&lo->queue_head)) {
4374b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu		req = list_entry(lo->queue_head.next, struct request,
4384b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu				 queuelist);
4394b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu		list_del_init(&req->queuelist);
4404b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu		req->errors++;
4414b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu		nbd_end_request(req);
4424b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu	}
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4457fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements
44648cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivierstatic void nbd_handle_req(struct nbd_device *lo, struct request *req)
44748cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier{
44848cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	if (!blk_fs_request(req))
44948cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		goto error_out;
45048cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier
45148cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	nbd_cmd(req) = NBD_CMD_READ;
45248cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	if (rq_data_dir(req) == WRITE) {
45348cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		nbd_cmd(req) = NBD_CMD_WRITE;
45448cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		if (lo->flags & NBD_READ_ONLY) {
45548cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier			printk(KERN_ERR "%s: Write on read-only\n",
45648cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier					lo->disk->disk_name);
45748cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier			goto error_out;
45848cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		}
45948cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	}
46048cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier
46148cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	req->errors = 0;
46248cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier
46348cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	mutex_lock(&lo->tx_lock);
46448cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	if (unlikely(!lo->sock)) {
46548cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		mutex_unlock(&lo->tx_lock);
46648cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		printk(KERN_ERR "%s: Attempted send on closed socket\n",
46748cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		       lo->disk->disk_name);
46848cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		req->errors++;
46948cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		nbd_end_request(req);
47048cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		return;
47148cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	}
47248cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier
47348cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	lo->active_req = req;
47448cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier
47548cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	if (nbd_send_req(lo, req) != 0) {
47648cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		printk(KERN_ERR "%s: Request send failed\n",
47748cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier				lo->disk->disk_name);
47848cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		req->errors++;
47948cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		nbd_end_request(req);
48048cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	} else {
48148cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		spin_lock(&lo->queue_lock);
48248cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		list_add(&req->queuelist, &lo->queue_head);
48348cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		spin_unlock(&lo->queue_lock);
48448cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	}
48548cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier
48648cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	lo->active_req = NULL;
48748cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	mutex_unlock(&lo->tx_lock);
48848cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	wake_up_all(&lo->active_wq);
48948cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier
49048cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	return;
49148cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier
49248cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Viviererror_out:
49348cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	req->errors++;
49448cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	nbd_end_request(req);
49548cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier}
49648cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier
49748cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivierstatic int nbd_thread(void *data)
49848cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier{
49948cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	struct nbd_device *lo = data;
50048cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	struct request *req;
50148cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier
50248cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	set_user_nice(current, -20);
50348cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	while (!kthread_should_stop() || !list_empty(&lo->waiting_queue)) {
50448cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		/* wait for something to do */
50548cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		wait_event_interruptible(lo->waiting_wq,
50648cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier					 kthread_should_stop() ||
50748cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier					 !list_empty(&lo->waiting_queue));
50848cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier
50948cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		/* extract request */
51048cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		if (list_empty(&lo->waiting_queue))
51148cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier			continue;
51248cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier
51348cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		spin_lock_irq(&lo->queue_lock);
51448cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		req = list_entry(lo->waiting_queue.next, struct request,
51548cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier				 queuelist);
51648cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		list_del_init(&req->queuelist);
51748cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		spin_unlock_irq(&lo->queue_lock);
51848cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier
51948cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		/* handle request */
52048cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		nbd_handle_req(lo, req);
52148cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	}
52248cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	return 0;
52348cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier}
52448cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We always wait for result of write, for now. It would be nice to make it optional
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in future
528e654bc4393e85e326993256d80b9710a4d6411ffBoaz Harrosh * if ((rq_data_dir(req) == WRITE) && (lo->flags & NBD_WRITE_NOCHK))
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); }
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
532165125e1e480f9510a5ffcfbfee4e3ee38c05f23Jens Axboestatic void do_nbd_request(struct request_queue * q)
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct request *req;
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((req = elv_next_request(q)) != NULL) {
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct nbd_device *lo;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		blkdev_dequeue_request(req);
54048cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier
54148cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		spin_unlock_irq(q->queue_lock);
54248cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier
5434aff5e2333c9a1609662f2091f55c3f6fffdad36Jens Axboe		dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%x)\n",
5444aff5e2333c9a1609662f2091f55c3f6fffdad36Jens Axboe				req->rq_disk->disk_name, req, req->cmd_type);
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lo = req->rq_disk->private_data;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG_ON(lo->magic != LO_MAGIC);
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
55048cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		spin_lock_irq(&lo->queue_lock);
55148cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		list_add_tail(&req->queuelist, &lo->waiting_queue);
55248cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		spin_unlock_irq(&lo->queue_lock);
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
55448cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		wake_up(&lo->waiting_wq);
5554b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_irq(q->queue_lock);
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
560a8cdc308c0ca3809e37e2be62174906a45b92670Al Virostatic int nbd_ioctl(struct block_device *bdev, fmode_t mode,
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     unsigned int cmd, unsigned long arg)
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
563a8cdc308c0ca3809e37e2be62174906a45b92670Al Viro	struct nbd_device *lo = bdev->bd_disk->private_data;
564a8cdc308c0ca3809e37e2be62174906a45b92670Al Viro	struct file *file;
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int error;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct request sreq ;
56748cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier	struct task_struct *thread;
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!capable(CAP_SYS_ADMIN))
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EPERM;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUG_ON(lo->magic != LO_MAGIC);
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Anyone capable of this syscall can do *real bad* things */
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n",
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg);
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NBD_DISCONNECT:
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	        printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name);
5814f54eec8311c3325888c29ce8e4496daf4dbe624FUJITA Tomonori		blk_rq_init(NULL, &sreq);
5824aff5e2333c9a1609662f2091f55c3f6fffdad36Jens Axboe		sreq.cmd_type = REQ_TYPE_SPECIAL;
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nbd_cmd(&sreq) = NBD_CMD_DISC;
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Set these to sane values in case server implementation
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * fails to check the request type first and also to keep
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * debugging output cleaner.
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sreq.sector = 0;
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sreq.nr_sectors = 0;
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                if (!lo->sock)
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
5937fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements		mutex_lock(&lo->tx_lock);
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                nbd_send_req(lo, &sreq);
5957fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements		mutex_unlock(&lo->tx_lock);
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                return 0;
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NBD_CLEAR_SOCK:
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		error = 0;
60082d4dc5adb0055393248ad4ab8de392fac708a12Ingo Molnar		mutex_lock(&lo->tx_lock);
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lo->sock = NULL;
60282d4dc5adb0055393248ad4ab8de392fac708a12Ingo Molnar		mutex_unlock(&lo->tx_lock);
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		file = lo->file;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lo->file = NULL;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nbd_clear_que(lo);
6064b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu		BUG_ON(!list_empty(&lo->queue_head));
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (file)
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fput(file);
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return error;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NBD_SET_SOCK:
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (lo->file)
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EBUSY;
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		error = -EINVAL;
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		file = fget(arg);
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (file) {
616a8cdc308c0ca3809e37e2be62174906a45b92670Al Viro			struct inode *inode = file->f_path.dentry->d_inode;
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (S_ISSOCK(inode->i_mode)) {
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lo->file = file;
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lo->sock = SOCKET_I(inode);
620d71a6d7332e5881a65249f4fb97b0db3c61dd5ecLaurent Vivier				if (max_part > 0)
621d71a6d7332e5881a65249f4fb97b0db3c61dd5ecLaurent Vivier					bdev->bd_invalidated = 1;
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				error = 0;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fput(file);
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return error;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NBD_SET_BLKSIZE:
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lo->blksize = arg;
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lo->bytesize &= ~(lo->blksize-1);
631a8cdc308c0ca3809e37e2be62174906a45b92670Al Viro		bdev->bd_inode->i_size = lo->bytesize;
632a8cdc308c0ca3809e37e2be62174906a45b92670Al Viro		set_blocksize(bdev, lo->blksize);
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_capacity(lo->disk, lo->bytesize >> 9);
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NBD_SET_SIZE:
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lo->bytesize = arg & ~(lo->blksize-1);
637a8cdc308c0ca3809e37e2be62174906a45b92670Al Viro		bdev->bd_inode->i_size = lo->bytesize;
638a8cdc308c0ca3809e37e2be62174906a45b92670Al Viro		set_blocksize(bdev, lo->blksize);
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_capacity(lo->disk, lo->bytesize >> 9);
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
6417fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements	case NBD_SET_TIMEOUT:
6427fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements		lo->xmit_timeout = arg * HZ;
6437fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements		return 0;
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NBD_SET_SIZE_BLOCKS:
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lo->bytesize = ((u64) arg) * lo->blksize;
646a8cdc308c0ca3809e37e2be62174906a45b92670Al Viro		bdev->bd_inode->i_size = lo->bytesize;
647a8cdc308c0ca3809e37e2be62174906a45b92670Al Viro		set_blocksize(bdev, lo->blksize);
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_capacity(lo->disk, lo->bytesize >> 9);
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NBD_DO_IT:
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!lo->file)
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
65348cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		thread = kthread_create(nbd_thread, lo, lo->disk->disk_name);
65448cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		if (IS_ERR(thread))
65548cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier			return PTR_ERR(thread);
65648cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		wake_up_process(thread);
65784963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Cong		error = nbd_do_it(lo);
65848cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		kthread_stop(thread);
65984963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Cong		if (error)
66084963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Cong			return error;
6617fdfd4065c264bddd2d9277470a6a99d34e01befPaul Clements		sock_shutdown(lo, 1);
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		file = lo->file;
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lo->file = NULL;
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nbd_clear_que(lo);
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "%s: queue cleared\n", lo->disk->disk_name);
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (file)
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fput(file);
6684b86a872561ad052bdc6f092a06807822d26beb1Paul Clements		lo->bytesize = 0;
669a8cdc308c0ca3809e37e2be62174906a45b92670Al Viro		bdev->bd_inode->i_size = 0;
6704b86a872561ad052bdc6f092a06807822d26beb1Paul Clements		set_capacity(lo->disk, 0);
671d71a6d7332e5881a65249f4fb97b0db3c61dd5ecLaurent Vivier		if (max_part > 0)
672a8cdc308c0ca3809e37e2be62174906a45b92670Al Viro			ioctl_by_bdev(bdev, BLKRRPART, 0);
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return lo->harderror;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NBD_CLEAR_QUE:
6754b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu		/*
6764b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu		 * This is for compatibility only.  The queue is always cleared
6774b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu		 * by NBD_DO_IT or NBD_CLEAR_SOCK.
6784b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu		 */
6794b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu		BUG_ON(!lo->sock && !list_empty(&lo->queue_head));
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NBD_PRINT_DEBUG:
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_INFO "%s: next = %p, prev = %p, head = %p\n",
683a8cdc308c0ca3809e37e2be62174906a45b92670Al Viro			bdev->bd_disk->disk_name,
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lo->queue_head.next, lo->queue_head.prev,
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			&lo->queue_head);
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct block_device_operations nbd_fops =
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner =	THIS_MODULE,
694a8cdc308c0ca3809e37e2be62174906a45b92670Al Viro	.locked_ioctl =	nbd_ioctl,
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * And here should be modules and kernel interface
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  (Just smiley confuses emacs :-)
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init nbd_init(void)
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = -ENOMEM;
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
706d71a6d7332e5881a65249f4fb97b0db3c61dd5ecLaurent Vivier	int part_shift;
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7085b7b18ccdeb17dcc4a2ddbf4ce87094c7365f4b9Adrian Bunk	BUILD_BUG_ON(sizeof(struct nbd_request) != 28);
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
710d71a6d7332e5881a65249f4fb97b0db3c61dd5ecLaurent Vivier	if (max_part < 0) {
711d71a6d7332e5881a65249f4fb97b0db3c61dd5ecLaurent Vivier		printk(KERN_CRIT "nbd: max_part must be >= 0\n");
712d71a6d7332e5881a65249f4fb97b0db3c61dd5ecLaurent Vivier		return -EINVAL;
713d71a6d7332e5881a65249f4fb97b0db3c61dd5ecLaurent Vivier	}
714d71a6d7332e5881a65249f4fb97b0db3c61dd5ecLaurent Vivier
715f3944d61ddc65722539ffd7b6f5b7c7217c136ccSven Wegener	nbd_dev = kcalloc(nbds_max, sizeof(*nbd_dev), GFP_KERNEL);
716f3944d61ddc65722539ffd7b6f5b7c7217c136ccSven Wegener	if (!nbd_dev)
717f3944d61ddc65722539ffd7b6f5b7c7217c136ccSven Wegener		return -ENOMEM;
718f3944d61ddc65722539ffd7b6f5b7c7217c136ccSven Wegener
719d71a6d7332e5881a65249f4fb97b0db3c61dd5ecLaurent Vivier	part_shift = 0;
720d71a6d7332e5881a65249f4fb97b0db3c61dd5ecLaurent Vivier	if (max_part > 0)
721d71a6d7332e5881a65249f4fb97b0db3c61dd5ecLaurent Vivier		part_shift = fls(max_part);
722d71a6d7332e5881a65249f4fb97b0db3c61dd5ecLaurent Vivier
72340be0c28b33ff0821594a3fa7126354dfe6eccd1Lars Marowsky-Bree	for (i = 0; i < nbds_max; i++) {
724d71a6d7332e5881a65249f4fb97b0db3c61dd5ecLaurent Vivier		struct gendisk *disk = alloc_disk(1 << part_shift);
72548f15b93b2c9f4ec9b8af08ab78f7a27db7c8378Paul Clements		elevator_t *old_e;
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!disk)
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nbd_dev[i].disk = disk;
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * The new linux 2.5 block layer implementation requires
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * every gendisk to have its very own request_queue struct.
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * These structs are big so we dynamically allocate them.
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		disk->queue = blk_init_queue(do_nbd_request, &nbd_lock);
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!disk->queue) {
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			put_disk(disk);
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
73948f15b93b2c9f4ec9b8af08ab78f7a27db7c8378Paul Clements		old_e = disk->queue->elevator;
74048f15b93b2c9f4ec9b8af08ab78f7a27db7c8378Paul Clements		if (elevator_init(disk->queue, "deadline") == 0 ||
74148f15b93b2c9f4ec9b8af08ab78f7a27db7c8378Paul Clements			elevator_init(disk->queue, "noop") == 0) {
74248f15b93b2c9f4ec9b8af08ab78f7a27db7c8378Paul Clements				elevator_exit(old_e);
74348f15b93b2c9f4ec9b8af08ab78f7a27db7c8378Paul Clements		}
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (register_blkdev(NBD_MAJOR, "nbd")) {
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -EIO;
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "nbd: registered device at major %d\n", NBD_MAJOR);
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk(DBG_INIT, "nbd: debugflags=0x%x\n", debugflags);
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
75440be0c28b33ff0821594a3fa7126354dfe6eccd1Lars Marowsky-Bree	for (i = 0; i < nbds_max; i++) {
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct gendisk *disk = nbd_dev[i].disk;
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nbd_dev[i].file = NULL;
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nbd_dev[i].magic = LO_MAGIC;
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nbd_dev[i].flags = 0;
75948cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		INIT_LIST_HEAD(&nbd_dev[i].waiting_queue);
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_init(&nbd_dev[i].queue_lock);
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		INIT_LIST_HEAD(&nbd_dev[i].queue_head);
76282d4dc5adb0055393248ad4ab8de392fac708a12Ingo Molnar		mutex_init(&nbd_dev[i].tx_lock);
7634b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu		init_waitqueue_head(&nbd_dev[i].active_wq);
76448cf6061b30205b29b306bf9bc22dd6f0b091461Laurent Vivier		init_waitqueue_head(&nbd_dev[i].waiting_wq);
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nbd_dev[i].blksize = 1024;
7664b86a872561ad052bdc6f092a06807822d26beb1Paul Clements		nbd_dev[i].bytesize = 0;
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		disk->major = NBD_MAJOR;
768d71a6d7332e5881a65249f4fb97b0db3c61dd5ecLaurent Vivier		disk->first_minor = i << part_shift;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		disk->fops = &nbd_fops;
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		disk->private_data = &nbd_dev[i];
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sprintf(disk->disk_name, "nbd%d", i);
7724b86a872561ad052bdc6f092a06807822d26beb1Paul Clements		set_capacity(disk, 0);
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		add_disk(disk);
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (i--) {
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		blk_cleanup_queue(nbd_dev[i].disk->queue);
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		put_disk(nbd_dev[i].disk);
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
782f3944d61ddc65722539ffd7b6f5b7c7217c136ccSven Wegener	kfree(nbd_dev);
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit nbd_cleanup(void)
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
78940be0c28b33ff0821594a3fa7126354dfe6eccd1Lars Marowsky-Bree	for (i = 0; i < nbds_max; i++) {
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct gendisk *disk = nbd_dev[i].disk;
79140be0c28b33ff0821594a3fa7126354dfe6eccd1Lars Marowsky-Bree		nbd_dev[i].magic = 0;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (disk) {
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			del_gendisk(disk);
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			blk_cleanup_queue(disk->queue);
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			put_disk(disk);
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_blkdev(NBD_MAJOR, "nbd");
799f3944d61ddc65722539ffd7b6f5b7c7217c136ccSven Wegener	kfree(nbd_dev);
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "nbd: unregistered device at major %d\n", NBD_MAJOR);
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(nbd_init);
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(nbd_cleanup);
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Network Block Device");
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
80940be0c28b33ff0821594a3fa7126354dfe6eccd1Lars Marowsky-Breemodule_param(nbds_max, int, 0444);
810d71a6d7332e5881a65249f4fb97b0db3c61dd5ecLaurent VivierMODULE_PARM_DESC(nbds_max, "number of network block devices to initialize (default: 16)");
811d71a6d7332e5881a65249f4fb97b0db3c61dd5ecLaurent Viviermodule_param(max_part, int, 0444);
812d71a6d7332e5881a65249f4fb97b0db3c61dd5ecLaurent VivierMODULE_PARM_DESC(max_part, "number of partitions per device (default: 0)");
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef NDEBUG
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debugflags, int, 0644);
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debugflags, "flags for controlling debug output");
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
817