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, ¤t->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