nbd.c revision 4b86a872561ad052bdc6f092a06807822d26beb1
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> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 334b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu#include <asm/system.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/types.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/nbd.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LO_MAGIC 0x68797548 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef NDEBUG 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define dprintk(flags, fmt...) 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else /* NDEBUG */ 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define dprintk(flags, fmt...) do { \ 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debugflags & (flags)) printk(KERN_DEBUG fmt); \ 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0) 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG_IOCTL 0x0004 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG_INIT 0x0010 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG_EXIT 0x0020 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG_BLKDEV 0x0100 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG_RX 0x0200 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG_TX 0x0400 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int debugflags; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* NDEBUG */ 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 559c7a41691f37a1538a88e5eb9b0b73df1f834542Ingo van Lilstatic unsigned int nbds_max = 16; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct nbd_device nbd_dev[MAX_NBD]; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Use just one lock (or at most 1 per NIC). Two arguments for this: 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1. Each NIC is essentially a synchronization point for all servers 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * accessed through that NIC so there's no need to have more locks 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * than NICs anyway. 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2. More locks lead to more "Dirty cache line bouncing" which will slow 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * down each lock to the point where they're actually slower than just 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a single lock. 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Thanks go to Jens Axboe and Al Viro for their LKML emails explaining this! 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_SPINLOCK(nbd_lock); 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef NDEBUG 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *ioctl_cmd_to_ascii(int cmd) 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_SET_SOCK: return "set-sock"; 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_SET_BLKSIZE: return "set-blksize"; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_SET_SIZE: return "set-size"; 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_DO_IT: return "do-it"; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_CLEAR_SOCK: return "clear-sock"; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_CLEAR_QUE: return "clear-que"; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_PRINT_DEBUG: return "print-debug"; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_SET_SIZE_BLOCKS: return "set-size-blocks"; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_DISCONNECT: return "disconnect"; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case BLKROSET: return "set-read-only"; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case BLKFLSBUF: return "flush-buffer-cache"; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return "unknown"; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *nbdcmd_to_ascii(int cmd) 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_CMD_READ: return "read"; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_CMD_WRITE: return "write"; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_CMD_DISC: return "disconnect"; 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return "invalid"; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* NDEBUG */ 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void nbd_end_request(struct request *req) 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int uptodate = (req->errors == 0) ? 1 : 0; 103165125e1e480f9510a5ffcfbfee4e3ee38c05f23Jens Axboe struct request_queue *q = req->q; 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk(DBG_BLKDEV, "%s: request %p: %s\n", req->rq_disk->disk_name, 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req, uptodate? "done": "failed"); 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(q->queue_lock, flags); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!end_that_request_first(req, uptodate, req->nr_sectors)) { 1118ffdc6550c47f75ca4e6c9f30a2a89063e035cf2Tejun Heo end_that_request_last(req, uptodate); 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(q->queue_lock, flags); 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send or receive packet. 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sock_xmit(struct socket *sock, int send, void *buf, int size, 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int msg_flags) 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct msghdr msg; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct kvec iov; 125be0ef957c9eed4ebae873ee3fbcfb9dfde486decOleg Nesterov sigset_t blocked, oldset; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allow interception of SIGKILL only 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Don't allow other signals to interrupt the transmission */ 129be0ef957c9eed4ebae873ee3fbcfb9dfde486decOleg Nesterov siginitsetinv(&blocked, sigmask(SIGKILL)); 130be0ef957c9eed4ebae873ee3fbcfb9dfde486decOleg Nesterov sigprocmask(SIG_SETMASK, &blocked, &oldset); 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sock->sk->sk_allocation = GFP_NOIO; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iov.iov_base = buf; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iov.iov_len = size; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg.msg_name = NULL; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg.msg_namelen = 0; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg.msg_control = NULL; 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg.msg_controllen = 0; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg.msg_flags = msg_flags | MSG_NOSIGNAL; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (send) 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = kernel_sendmsg(sock, &msg, &iov, 1, size); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = kernel_recvmsg(sock, &msg, &iov, 1, size, 0); 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) { 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds siginfo_t info; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "nbd (pid %d: %s) got signal %d\n", 150be0ef957c9eed4ebae873ee3fbcfb9dfde486decOleg Nesterov current->pid, current->comm, 151be0ef957c9eed4ebae873ee3fbcfb9dfde486decOleg Nesterov dequeue_signal_lock(current, ¤t->blocked, &info)); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -EINTR; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result <= 0) { 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result == 0) 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -EPIPE; /* short read */ 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size -= result; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += result; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (size > 0); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 165be0ef957c9eed4ebae873ee3fbcfb9dfde486decOleg Nesterov sigprocmask(SIG_SETMASK, &oldset, NULL); 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int sock_send_bvec(struct socket *sock, struct bio_vec *bvec, 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int flags) 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *kaddr = kmap(bvec->bv_page); 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = sock_xmit(sock, 1, kaddr + bvec->bv_offset, bvec->bv_len, 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags); 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kunmap(bvec->bv_page); 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nbd_send_req(struct nbd_device *lo, struct request *req) 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1835705f7021748a69d84d6567e68e8851dab551464NeilBrown int result, flags; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct nbd_request request; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long size = req->nr_sectors << 9; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct socket *sock = lo->sock; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request.magic = htonl(NBD_REQUEST_MAGIC); 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request.type = htonl(nbd_cmd(req)); 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request.from = cpu_to_be64((u64) req->sector << 9); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request.len = htonl(size); 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(request.handle, &req, sizeof(req)); 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%luB)\n", 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->disk->disk_name, req, 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nbdcmd_to_ascii(nbd_cmd(req)), 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long long)req->sector << 9, 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->nr_sectors << 9); 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = sock_xmit(sock, 1, &request, sizeof(request), 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (nbd_cmd(req) == NBD_CMD_WRITE)? MSG_MORE: 0); 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result <= 0) { 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s: Send control failed (result %d)\n", 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->disk->disk_name, result); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error_out; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nbd_cmd(req) == NBD_CMD_WRITE) { 2085705f7021748a69d84d6567e68e8851dab551464NeilBrown struct req_iterator iter; 2095705f7021748a69d84d6567e68e8851dab551464NeilBrown struct bio_vec *bvec; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we are really probing at internals to determine 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * whether to set MSG_MORE or not... 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2145705f7021748a69d84d6567e68e8851dab551464NeilBrown rq_for_each_segment(bvec, req, iter) { 2156c92e699b56287da582ccb12a64b959b6d6109baJens Axboe flags = 0; 2166c92e699b56287da582ccb12a64b959b6d6109baJens Axboe if (!rq_iter_last(req, iter)) 2176c92e699b56287da582ccb12a64b959b6d6109baJens Axboe flags = MSG_MORE; 2186c92e699b56287da582ccb12a64b959b6d6109baJens Axboe dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n", 2196c92e699b56287da582ccb12a64b959b6d6109baJens Axboe lo->disk->disk_name, req, bvec->bv_len); 2206c92e699b56287da582ccb12a64b959b6d6109baJens Axboe result = sock_send_bvec(sock, bvec, flags); 2216c92e699b56287da582ccb12a64b959b6d6109baJens Axboe if (result <= 0) { 2226c92e699b56287da582ccb12a64b959b6d6109baJens Axboe printk(KERN_ERR "%s: Send data failed (result %d)\n", 2236c92e699b56287da582ccb12a64b959b6d6109baJens Axboe lo->disk->disk_name, result); 2246c92e699b56287da582ccb12a64b959b6d6109baJens Axboe goto error_out; 2256c92e699b56287da582ccb12a64b959b6d6109baJens Axboe } 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror_out: 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2340cbc591bf884a5662b2fbb21b5c09fa1c1c7b579Denis Chengstatic struct request *nbd_find_request(struct nbd_device *lo, 2350cbc591bf884a5662b2fbb21b5c09fa1c1c7b579Denis Cheng struct request *xreq) 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 237d2c9740b499f959ed513375b6e35c2ab161921cbDenis Cheng struct request *req, *tmp; 2384b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu int err; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2404b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu err = wait_event_interruptible(lo->active_wq, lo->active_req != xreq); 2414b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu if (unlikely(err)) 2424b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu goto out; 2434b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&lo->queue_lock); 245d2c9740b499f959ed513375b6e35c2ab161921cbDenis Cheng list_for_each_entry_safe(req, tmp, &lo->queue_head, queuelist) { 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req != xreq) 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del_init(&req->queuelist); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&lo->queue_lock); 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return req; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&lo->queue_lock); 2534b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu 2544b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu err = -ENOENT; 2554b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu 2564b2f0260c74324abca76ccaa42d426af163125e7Herbert Xuout: 2574b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu return ERR_PTR(err); 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int sock_recv_bvec(struct socket *sock, struct bio_vec *bvec) 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *kaddr = kmap(bvec->bv_page); 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = sock_xmit(sock, 0, kaddr + bvec->bv_offset, bvec->bv_len, 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MSG_WAITALL); 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kunmap(bvec->bv_page); 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* NULL returned = something went wrong, inform userspace */ 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct request *nbd_read_stat(struct nbd_device *lo) 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct nbd_reply reply; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct request *req; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct socket *sock = lo->sock; 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply.magic = 0; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = sock_xmit(sock, 0, &reply, sizeof(reply), MSG_WAITALL); 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result <= 0) { 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s: Receive control failed (result %d)\n", 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->disk->disk_name, result); 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto harderror; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 285e4b57e0842621f597d744b193ea325d62724596bMichal Feix 286e4b57e0842621f597d744b193ea325d62724596bMichal Feix if (ntohl(reply.magic) != NBD_REPLY_MAGIC) { 287e4b57e0842621f597d744b193ea325d62724596bMichal Feix printk(KERN_ERR "%s: Wrong magic (0x%lx)\n", 288e4b57e0842621f597d744b193ea325d62724596bMichal Feix lo->disk->disk_name, 289e4b57e0842621f597d744b193ea325d62724596bMichal Feix (unsigned long)ntohl(reply.magic)); 290e4b57e0842621f597d744b193ea325d62724596bMichal Feix result = -EPROTO; 291e4b57e0842621f597d744b193ea325d62724596bMichal Feix goto harderror; 292e4b57e0842621f597d744b193ea325d62724596bMichal Feix } 293e4b57e0842621f597d744b193ea325d62724596bMichal Feix 2940cbc591bf884a5662b2fbb21b5c09fa1c1c7b579Denis Cheng req = nbd_find_request(lo, *(struct request **)reply.handle); 2954b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu if (unlikely(IS_ERR(req))) { 2964b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu result = PTR_ERR(req); 2974b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu if (result != -ENOENT) 2984b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu goto harderror; 2994b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s: Unexpected reply (%p)\n", 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->disk->disk_name, reply.handle); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -EBADR; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto harderror; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ntohl(reply.error)) { 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s: Other side returned error (%d)\n", 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->disk->disk_name, ntohl(reply.error)); 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->errors++; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return req; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk(DBG_RX, "%s: request %p: got reply\n", 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->disk->disk_name, req); 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nbd_cmd(req) == NBD_CMD_READ) { 3165705f7021748a69d84d6567e68e8851dab551464NeilBrown struct req_iterator iter; 3175705f7021748a69d84d6567e68e8851dab551464NeilBrown struct bio_vec *bvec; 3185705f7021748a69d84d6567e68e8851dab551464NeilBrown 3195705f7021748a69d84d6567e68e8851dab551464NeilBrown rq_for_each_segment(bvec, req, iter) { 3206c92e699b56287da582ccb12a64b959b6d6109baJens Axboe result = sock_recv_bvec(sock, bvec); 3216c92e699b56287da582ccb12a64b959b6d6109baJens Axboe if (result <= 0) { 3226c92e699b56287da582ccb12a64b959b6d6109baJens Axboe printk(KERN_ERR "%s: Receive data failed (result %d)\n", 3236c92e699b56287da582ccb12a64b959b6d6109baJens Axboe lo->disk->disk_name, result); 3246c92e699b56287da582ccb12a64b959b6d6109baJens Axboe req->errors++; 3256c92e699b56287da582ccb12a64b959b6d6109baJens Axboe return req; 3266c92e699b56287da582ccb12a64b959b6d6109baJens Axboe } 3276c92e699b56287da582ccb12a64b959b6d6109baJens Axboe dprintk(DBG_RX, "%s: request %p: got %d bytes data\n", 3286c92e699b56287da582ccb12a64b959b6d6109baJens Axboe lo->disk->disk_name, req, bvec->bv_len); 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return req; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsharderror: 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->harderror = result; 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3376b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clementsstatic ssize_t pid_show(struct gendisk *disk, char *page) 3386b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements{ 3396b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements return sprintf(page, "%ld\n", 3406b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements (long) ((struct nbd_device *)disk->private_data)->pid); 3416b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements} 3426b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements 3436b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clementsstatic struct disk_attribute pid_attr = { 3446b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements .attr = { .name = "pid", .mode = S_IRUGO }, 3456b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements .show = pid_show, 3466b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements}; 3476b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements 34884963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Congstatic int nbd_do_it(struct nbd_device *lo) 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct request *req; 35184963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Cong int ret; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(lo->magic != LO_MAGIC); 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3556b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements lo->pid = current->pid; 35684963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Cong ret = sysfs_create_file(&lo->disk->kobj, &pid_attr.attr); 35784963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Cong if (ret) { 35884963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Cong printk(KERN_ERR "nbd: sysfs_create_file failed!"); 35984963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Cong return ret; 36084963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Cong } 3616b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((req = nbd_read_stat(lo)) != NULL) 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nbd_end_request(req); 3646b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements 3656b39bb6548d60b9a18826134b5ccd5c3cef85fe2Paul Clements sysfs_remove_file(&lo->disk->kobj, &pid_attr.attr); 36684963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Cong return 0; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void nbd_clear_que(struct nbd_device *lo) 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct request *req; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(lo->magic != LO_MAGIC); 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3754b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu /* 3764b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu * Because we have set lo->sock to NULL under the tx_lock, all 3774b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu * modifications to the list must have completed by now. For 3784b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu * the same reason, the active_req must be NULL. 3794b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu * 3804b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu * As a consequence, we don't need to take the spin lock while 3814b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu * purging the list here. 3824b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu */ 3834b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu BUG_ON(lo->sock); 3844b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu BUG_ON(lo->active_req); 3854b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu 3864b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu while (!list_empty(&lo->queue_head)) { 3874b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu req = list_entry(lo->queue_head.next, struct request, 3884b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu queuelist); 3894b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu list_del_init(&req->queuelist); 3904b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu req->errors++; 3914b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu nbd_end_request(req); 3924b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu } 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We always wait for result of write, for now. It would be nice to make it optional 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in future 398e654bc4393e85e326993256d80b9710a4d6411ffBoaz Harrosh * if ((rq_data_dir(req) == WRITE) && (lo->flags & NBD_WRITE_NOCHK)) 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); } 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 402165125e1e480f9510a5ffcfbfee4e3ee38c05f23Jens Axboestatic void do_nbd_request(struct request_queue * q) 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct request *req; 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((req = elv_next_request(q)) != NULL) { 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct nbd_device *lo; 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blkdev_dequeue_request(req); 4104aff5e2333c9a1609662f2091f55c3f6fffdad36Jens Axboe dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%x)\n", 4114aff5e2333c9a1609662f2091f55c3f6fffdad36Jens Axboe req->rq_disk->disk_name, req, req->cmd_type); 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4134aff5e2333c9a1609662f2091f55c3f6fffdad36Jens Axboe if (!blk_fs_request(req)) 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error_out; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo = req->rq_disk->private_data; 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(lo->magic != LO_MAGIC); 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nbd_cmd(req) = NBD_CMD_READ; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rq_data_dir(req) == WRITE) { 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nbd_cmd(req) = NBD_CMD_WRITE; 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lo->flags & NBD_READ_ONLY) { 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s: Write on read-only\n", 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->disk->disk_name); 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error_out; 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->errors = 0; 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(q->queue_lock); 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43382d4dc5adb0055393248ad4ab8de392fac708a12Ingo Molnar mutex_lock(&lo->tx_lock); 4344b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu if (unlikely(!lo->sock)) { 43582d4dc5adb0055393248ad4ab8de392fac708a12Ingo Molnar mutex_unlock(&lo->tx_lock); 4364b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu printk(KERN_ERR "%s: Attempted send on closed socket\n", 4374b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu lo->disk->disk_name); 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->errors++; 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nbd_end_request(req); 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(q->queue_lock); 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4444b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu lo->active_req = req; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nbd_send_req(lo, req) != 0) { 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s: Request send failed\n", 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->disk->disk_name); 4494b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu req->errors++; 4504b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu nbd_end_request(req); 4514b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu } else { 4524b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu spin_lock(&lo->queue_lock); 4534b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu list_add(&req->queuelist, &lo->queue_head); 4544b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu spin_unlock(&lo->queue_lock); 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4574b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu lo->active_req = NULL; 45882d4dc5adb0055393248ad4ab8de392fac708a12Ingo Molnar mutex_unlock(&lo->tx_lock); 4594b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu wake_up_all(&lo->active_wq); 4604b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(q->queue_lock); 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror_out: 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->errors++; 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(q->queue_lock); 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nbd_end_request(req); 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(q->queue_lock); 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nbd_ioctl(struct inode *inode, struct file *file, 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cmd, unsigned long arg) 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct nbd_device *lo = inode->i_bdev->bd_disk->private_data; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error; 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct request sreq ; 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(lo->magic != LO_MAGIC); 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Anyone capable of this syscall can do *real bad* things */ 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n", 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg); 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_DISCONNECT: 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name); 4924aff5e2333c9a1609662f2091f55c3f6fffdad36Jens Axboe sreq.cmd_type = REQ_TYPE_SPECIAL; 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nbd_cmd(&sreq) = NBD_CMD_DISC; 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set these to sane values in case server implementation 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fails to check the request type first and also to keep 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * debugging output cleaner. 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sreq.sector = 0; 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sreq.nr_sectors = 0; 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!lo->sock) 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nbd_send_req(lo, &sreq); 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_CLEAR_SOCK: 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = 0; 50882d4dc5adb0055393248ad4ab8de392fac708a12Ingo Molnar mutex_lock(&lo->tx_lock); 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->sock = NULL; 51082d4dc5adb0055393248ad4ab8de392fac708a12Ingo Molnar mutex_unlock(&lo->tx_lock); 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file = lo->file; 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->file = NULL; 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nbd_clear_que(lo); 5144b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu BUG_ON(!list_empty(&lo->queue_head)); 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (file) 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fput(file); 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return error; 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_SET_SOCK: 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lo->file) 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -EINVAL; 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file = fget(arg); 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (file) { 52417506041de973bdc718b9a255d822e571b12b421Josef Sipek inode = file->f_path.dentry->d_inode; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (S_ISSOCK(inode->i_mode)) { 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->file = file; 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->sock = SOCKET_I(inode); 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = 0; 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fput(file); 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return error; 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_SET_BLKSIZE: 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->blksize = arg; 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->bytesize &= ~(lo->blksize-1); 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inode->i_bdev->bd_inode->i_size = lo->bytesize; 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_blocksize(inode->i_bdev, lo->blksize); 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_capacity(lo->disk, lo->bytesize >> 9); 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_SET_SIZE: 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->bytesize = arg & ~(lo->blksize-1); 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inode->i_bdev->bd_inode->i_size = lo->bytesize; 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_blocksize(inode->i_bdev, lo->blksize); 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_capacity(lo->disk, lo->bytesize >> 9); 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_SET_SIZE_BLOCKS: 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->bytesize = ((u64) arg) * lo->blksize; 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inode->i_bdev->bd_inode->i_size = lo->bytesize; 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_blocksize(inode->i_bdev, lo->blksize); 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_capacity(lo->disk, lo->bytesize >> 9); 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_DO_IT: 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!lo->file) 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 55684963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Cong error = nbd_do_it(lo); 55784963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Cong if (error) 55884963048ca8093e0aa71ac90c2a5fe7af5f617c3WANG Cong return error; 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* on return tidy up in case we have a signal */ 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Forcibly shutdown the socket causing all listeners 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to error 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIXME: This code is duplicated from sys_shutdown, but 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * there should be a more generic interface rather than 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * calling socket ops directly here */ 56682d4dc5adb0055393248ad4ab8de392fac708a12Ingo Molnar mutex_lock(&lo->tx_lock); 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lo->sock) { 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "%s: shutting down socket\n", 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->disk->disk_name); 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->sock->ops->shutdown(lo->sock, 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SEND_SHUTDOWN|RCV_SHUTDOWN); 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->sock = NULL; 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 57482d4dc5adb0055393248ad4ab8de392fac708a12Ingo Molnar mutex_unlock(&lo->tx_lock); 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file = lo->file; 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->file = NULL; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nbd_clear_que(lo); 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "%s: queue cleared\n", lo->disk->disk_name); 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (file) 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fput(file); 5814b86a872561ad052bdc6f092a06807822d26beb1Paul Clements lo->bytesize = 0; 5824b86a872561ad052bdc6f092a06807822d26beb1Paul Clements inode->i_bdev->bd_inode->i_size = 0; 5834b86a872561ad052bdc6f092a06807822d26beb1Paul Clements set_capacity(lo->disk, 0); 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return lo->harderror; 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_CLEAR_QUE: 5864b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu /* 5874b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu * This is for compatibility only. The queue is always cleared 5884b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu * by NBD_DO_IT or NBD_CLEAR_SOCK. 5894b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu */ 5904b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu BUG_ON(!lo->sock && !list_empty(&lo->queue_head)); 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NBD_PRINT_DEBUG: 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "%s: next = %p, prev = %p, head = %p\n", 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inode->i_bdev->bd_disk->disk_name, 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo->queue_head.next, lo->queue_head.prev, 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &lo->queue_head); 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct block_device_operations nbd_fops = 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = nbd_ioctl, 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * And here should be modules and kernel interface 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (Just smiley confuses emacs :-) 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init nbd_init(void) 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = -ENOMEM; 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6185b7b18ccdeb17dcc4a2ddbf4ce87094c7365f4b9Adrian Bunk BUILD_BUG_ON(sizeof(struct nbd_request) != 28); 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62040be0c28b33ff0821594a3fa7126354dfe6eccd1Lars Marowsky-Bree if (nbds_max > MAX_NBD) { 62140be0c28b33ff0821594a3fa7126354dfe6eccd1Lars Marowsky-Bree printk(KERN_CRIT "nbd: cannot allocate more than %u nbds; %u requested.\n", MAX_NBD, 62240be0c28b33ff0821594a3fa7126354dfe6eccd1Lars Marowsky-Bree nbds_max); 62340be0c28b33ff0821594a3fa7126354dfe6eccd1Lars Marowsky-Bree return -EINVAL; 62440be0c28b33ff0821594a3fa7126354dfe6eccd1Lars Marowsky-Bree } 62540be0c28b33ff0821594a3fa7126354dfe6eccd1Lars Marowsky-Bree 62640be0c28b33ff0821594a3fa7126354dfe6eccd1Lars Marowsky-Bree for (i = 0; i < nbds_max; i++) { 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gendisk *disk = alloc_disk(1); 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!disk) 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nbd_dev[i].disk = disk; 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The new linux 2.5 block layer implementation requires 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * every gendisk to have its very own request_queue struct. 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These structs are big so we dynamically allocate them. 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disk->queue = blk_init_queue(do_nbd_request, &nbd_lock); 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!disk->queue) { 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_disk(disk); 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (register_blkdev(NBD_MAJOR, "nbd")) { 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EIO; 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "nbd: registered device at major %d\n", NBD_MAJOR); 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk(DBG_INIT, "nbd: debugflags=0x%x\n", debugflags); 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65140be0c28b33ff0821594a3fa7126354dfe6eccd1Lars Marowsky-Bree for (i = 0; i < nbds_max; i++) { 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gendisk *disk = nbd_dev[i].disk; 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nbd_dev[i].file = NULL; 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nbd_dev[i].magic = LO_MAGIC; 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nbd_dev[i].flags = 0; 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&nbd_dev[i].queue_lock); 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(&nbd_dev[i].queue_head); 65882d4dc5adb0055393248ad4ab8de392fac708a12Ingo Molnar mutex_init(&nbd_dev[i].tx_lock); 6594b2f0260c74324abca76ccaa42d426af163125e7Herbert Xu init_waitqueue_head(&nbd_dev[i].active_wq); 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nbd_dev[i].blksize = 1024; 6614b86a872561ad052bdc6f092a06807822d26beb1Paul Clements nbd_dev[i].bytesize = 0; 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disk->major = NBD_MAJOR; 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disk->first_minor = i; 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disk->fops = &nbd_fops; 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disk->private_data = &nbd_dev[i]; 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO; 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(disk->disk_name, "nbd%d", i); 6684b86a872561ad052bdc6f092a06807822d26beb1Paul Clements set_capacity(disk, 0); 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_disk(disk); 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (i--) { 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blk_cleanup_queue(nbd_dev[i].disk->queue); 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_disk(nbd_dev[i].disk); 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit nbd_cleanup(void) 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 68440be0c28b33ff0821594a3fa7126354dfe6eccd1Lars Marowsky-Bree for (i = 0; i < nbds_max; i++) { 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gendisk *disk = nbd_dev[i].disk; 68640be0c28b33ff0821594a3fa7126354dfe6eccd1Lars Marowsky-Bree nbd_dev[i].magic = 0; 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (disk) { 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds del_gendisk(disk); 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blk_cleanup_queue(disk->queue); 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_disk(disk); 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_blkdev(NBD_MAJOR, "nbd"); 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "nbd: unregistered device at major %d\n", NBD_MAJOR); 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(nbd_init); 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(nbd_cleanup); 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Network Block Device"); 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 70340be0c28b33ff0821594a3fa7126354dfe6eccd1Lars Marowsky-Breemodule_param(nbds_max, int, 0444); 70440be0c28b33ff0821594a3fa7126354dfe6eccd1Lars Marowsky-BreeMODULE_PARM_DESC(nbds_max, "How many network block devices to initialize."); 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef NDEBUG 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debugflags, int, 0644); 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debugflags, "flags for controlling debug output"); 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 709