Blame view
drivers/block/nbd.c
20.3 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 |
/* * Network block device - make block devices work over TCP * * Note that you can not swap over this thing, yet. Seems to work but * deadlocks sometimes - you can not swap over TCP in general. * |
15746fcaa nbd: trivial clea... |
7 |
* Copyright 1997-2000, 2008 Pavel Machek <pavel@suse.cz> |
1da177e4c Linux-2.6.12-rc2 |
8 9 |
* Parts copyright 2001 Steven Whitehouse <steve@chygwyn.com> * |
dbf492d6c [PATCH] nbd: kill... |
10 |
* This file is released under GPLv2 or later. |
1da177e4c Linux-2.6.12-rc2 |
11 |
* |
dbf492d6c [PATCH] nbd: kill... |
12 |
* (part of code stolen from loop.c) |
1da177e4c Linux-2.6.12-rc2 |
13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
*/ #include <linux/major.h> #include <linux/blkdev.h> #include <linux/module.h> #include <linux/init.h> #include <linux/sched.h> #include <linux/fs.h> #include <linux/bio.h> #include <linux/stat.h> #include <linux/errno.h> #include <linux/file.h> #include <linux/ioctl.h> |
4b2f0260c [PATCH] nbd: fix ... |
27 28 29 |
#include <linux/compiler.h> #include <linux/err.h> #include <linux/kernel.h> |
1da177e4c Linux-2.6.12-rc2 |
30 |
#include <net/sock.h> |
91cf45f02 [NET]: Add the he... |
31 |
#include <linux/net.h> |
48cf6061b NBD: allow nbd to... |
32 |
#include <linux/kthread.h> |
1da177e4c Linux-2.6.12-rc2 |
33 |
|
1da177e4c Linux-2.6.12-rc2 |
34 |
#include <asm/uaccess.h> |
4b2f0260c [PATCH] nbd: fix ... |
35 |
#include <asm/system.h> |
1da177e4c Linux-2.6.12-rc2 |
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
#include <asm/types.h> #include <linux/nbd.h> #define LO_MAGIC 0x68797548 #ifdef NDEBUG #define dprintk(flags, fmt...) #else /* NDEBUG */ #define dprintk(flags, fmt...) do { \ if (debugflags & (flags)) printk(KERN_DEBUG fmt); \ } while (0) #define DBG_IOCTL 0x0004 #define DBG_INIT 0x0010 #define DBG_EXIT 0x0020 #define DBG_BLKDEV 0x0100 #define DBG_RX 0x0200 #define DBG_TX 0x0400 static unsigned int debugflags; #endif /* NDEBUG */ |
9c7a41691 [PATCH] drivers/b... |
56 |
static unsigned int nbds_max = 16; |
20a8143ea NBD: remove limit... |
57 |
static struct nbd_device *nbd_dev; |
d71a6d733 NBD: add partitio... |
58 |
static int max_part; |
1da177e4c Linux-2.6.12-rc2 |
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
/* * Use just one lock (or at most 1 per NIC). Two arguments for this: * 1. Each NIC is essentially a synchronization point for all servers * accessed through that NIC so there's no need to have more locks * than NICs anyway. * 2. More locks lead to more "Dirty cache line bouncing" which will slow * down each lock to the point where they're actually slower than just * a single lock. * Thanks go to Jens Axboe and Al Viro for their LKML emails explaining this! */ static DEFINE_SPINLOCK(nbd_lock); #ifndef NDEBUG static const char *ioctl_cmd_to_ascii(int cmd) { switch (cmd) { case NBD_SET_SOCK: return "set-sock"; case NBD_SET_BLKSIZE: return "set-blksize"; case NBD_SET_SIZE: return "set-size"; case NBD_DO_IT: return "do-it"; case NBD_CLEAR_SOCK: return "clear-sock"; case NBD_CLEAR_QUE: return "clear-que"; case NBD_PRINT_DEBUG: return "print-debug"; case NBD_SET_SIZE_BLOCKS: return "set-size-blocks"; case NBD_DISCONNECT: return "disconnect"; case BLKROSET: return "set-read-only"; case BLKFLSBUF: return "flush-buffer-cache"; } return "unknown"; } static const char *nbdcmd_to_ascii(int cmd) { switch (cmd) { case NBD_CMD_READ: return "read"; case NBD_CMD_WRITE: return "write"; case NBD_CMD_DISC: return "disconnect"; } return "invalid"; } #endif /* NDEBUG */ static void nbd_end_request(struct request *req) { |
097c94a4e blk_end_request: ... |
104 |
int error = req->errors ? -EIO : 0; |
165125e1e [BLOCK] Get rid o... |
105 |
struct request_queue *q = req->q; |
1da177e4c Linux-2.6.12-rc2 |
106 107 108 109 |
unsigned long flags; dprintk(DBG_BLKDEV, "%s: request %p: %s ", req->rq_disk->disk_name, |
097c94a4e blk_end_request: ... |
110 |
req, error ? "failed" : "done"); |
1da177e4c Linux-2.6.12-rc2 |
111 112 |
spin_lock_irqsave(q->queue_lock, flags); |
097c94a4e blk_end_request: ... |
113 |
__blk_end_request(req, error, req->nr_sectors << 9); |
1da177e4c Linux-2.6.12-rc2 |
114 115 |
spin_unlock_irqrestore(q->queue_lock, flags); } |
7fdfd4065 NBD: allow hung n... |
116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
static void sock_shutdown(struct nbd_device *lo, int lock) { /* Forcibly shutdown the socket causing all listeners * to error * * FIXME: This code is duplicated from sys_shutdown, but * there should be a more generic interface rather than * calling socket ops directly here */ if (lock) mutex_lock(&lo->tx_lock); if (lo->sock) { printk(KERN_WARNING "%s: shutting down socket ", lo->disk->disk_name); |
91cf45f02 [NET]: Add the he... |
130 |
kernel_sock_shutdown(lo->sock, SHUT_RDWR); |
7fdfd4065 NBD: allow hung n... |
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
lo->sock = NULL; } if (lock) mutex_unlock(&lo->tx_lock); } static void nbd_xmit_timeout(unsigned long arg) { struct task_struct *task = (struct task_struct *)arg; printk(KERN_WARNING "nbd: killing hung xmit (%s, pid: %d) ", task->comm, task->pid); force_sig(SIGKILL, task); } |
1da177e4c Linux-2.6.12-rc2 |
146 147 148 |
/* * Send or receive packet. */ |
7fdfd4065 NBD: allow hung n... |
149 |
static int sock_xmit(struct nbd_device *lo, int send, void *buf, int size, |
1da177e4c Linux-2.6.12-rc2 |
150 151 |
int msg_flags) { |
7fdfd4065 NBD: allow hung n... |
152 |
struct socket *sock = lo->sock; |
1da177e4c Linux-2.6.12-rc2 |
153 154 155 |
int result; struct msghdr msg; struct kvec iov; |
be0ef957c nbd.c: sock_xmit:... |
156 |
sigset_t blocked, oldset; |
1da177e4c Linux-2.6.12-rc2 |
157 |
|
ffc41cf8d nbd: prevent sock... |
158 159 160 161 162 163 |
if (unlikely(!sock)) { printk(KERN_ERR "%s: Attempted %s on closed socket in sock_xmit ", lo->disk->disk_name, (send ? "send" : "recv")); return -EINVAL; } |
1da177e4c Linux-2.6.12-rc2 |
164 165 |
/* Allow interception of SIGKILL only * Don't allow other signals to interrupt the transmission */ |
be0ef957c nbd.c: sock_xmit:... |
166 167 |
siginitsetinv(&blocked, sigmask(SIGKILL)); sigprocmask(SIG_SETMASK, &blocked, &oldset); |
1da177e4c Linux-2.6.12-rc2 |
168 169 170 171 172 173 174 175 176 |
do { sock->sk->sk_allocation = GFP_NOIO; iov.iov_base = buf; iov.iov_len = size; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_control = NULL; msg.msg_controllen = 0; |
1da177e4c Linux-2.6.12-rc2 |
177 |
msg.msg_flags = msg_flags | MSG_NOSIGNAL; |
7fdfd4065 NBD: allow hung n... |
178 179 180 181 182 183 184 185 186 187 |
if (send) { struct timer_list ti; if (lo->xmit_timeout) { init_timer(&ti); ti.function = nbd_xmit_timeout; ti.data = (unsigned long)current; ti.expires = jiffies + lo->xmit_timeout; add_timer(&ti); } |
1da177e4c Linux-2.6.12-rc2 |
188 |
result = kernel_sendmsg(sock, &msg, &iov, 1, size); |
7fdfd4065 NBD: allow hung n... |
189 190 191 |
if (lo->xmit_timeout) del_timer_sync(&ti); } else |
1da177e4c Linux-2.6.12-rc2 |
192 193 194 195 |
result = kernel_recvmsg(sock, &msg, &iov, 1, size, 0); if (signal_pending(current)) { siginfo_t info; |
1da177e4c Linux-2.6.12-rc2 |
196 197 |
printk(KERN_WARNING "nbd (pid %d: %s) got signal %d ", |
ba25f9dcc Use helpers to ob... |
198 |
task_pid_nr(current), current->comm, |
be0ef957c nbd.c: sock_xmit:... |
199 |
dequeue_signal_lock(current, ¤t->blocked, &info)); |
1da177e4c Linux-2.6.12-rc2 |
200 |
result = -EINTR; |
7fdfd4065 NBD: allow hung n... |
201 |
sock_shutdown(lo, !send); |
1da177e4c Linux-2.6.12-rc2 |
202 203 204 205 206 207 208 209 210 211 212 |
break; } if (result <= 0) { if (result == 0) result = -EPIPE; /* short read */ break; } size -= result; buf += result; } while (size > 0); |
be0ef957c nbd.c: sock_xmit:... |
213 |
sigprocmask(SIG_SETMASK, &oldset, NULL); |
1da177e4c Linux-2.6.12-rc2 |
214 215 216 |
return result; } |
7fdfd4065 NBD: allow hung n... |
217 |
static inline int sock_send_bvec(struct nbd_device *lo, struct bio_vec *bvec, |
1da177e4c Linux-2.6.12-rc2 |
218 219 220 221 |
int flags) { int result; void *kaddr = kmap(bvec->bv_page); |
7fdfd4065 NBD: allow hung n... |
222 |
result = sock_xmit(lo, 1, kaddr + bvec->bv_offset, bvec->bv_len, flags); |
1da177e4c Linux-2.6.12-rc2 |
223 224 225 |
kunmap(bvec->bv_page); return result; } |
7fdfd4065 NBD: allow hung n... |
226 |
/* always call with the tx_lock held */ |
1da177e4c Linux-2.6.12-rc2 |
227 228 |
static int nbd_send_req(struct nbd_device *lo, struct request *req) { |
5705f7021 Introduce rq_for_... |
229 |
int result, flags; |
1da177e4c Linux-2.6.12-rc2 |
230 231 |
struct nbd_request request; unsigned long size = req->nr_sectors << 9; |
1da177e4c Linux-2.6.12-rc2 |
232 233 234 235 236 237 |
request.magic = htonl(NBD_REQUEST_MAGIC); request.type = htonl(nbd_cmd(req)); request.from = cpu_to_be64((u64) req->sector << 9); request.len = htonl(size); memcpy(request.handle, &req, sizeof(req)); |
1da177e4c Linux-2.6.12-rc2 |
238 239 240 241 242 243 |
dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%luB) ", lo->disk->disk_name, req, nbdcmd_to_ascii(nbd_cmd(req)), (unsigned long long)req->sector << 9, req->nr_sectors << 9); |
7fdfd4065 NBD: allow hung n... |
244 245 |
result = sock_xmit(lo, 1, &request, sizeof(request), (nbd_cmd(req) == NBD_CMD_WRITE) ? MSG_MORE : 0); |
1da177e4c Linux-2.6.12-rc2 |
246 247 248 249 250 251 252 253 |
if (result <= 0) { printk(KERN_ERR "%s: Send control failed (result %d) ", lo->disk->disk_name, result); goto error_out; } if (nbd_cmd(req) == NBD_CMD_WRITE) { |
5705f7021 Introduce rq_for_... |
254 255 |
struct req_iterator iter; struct bio_vec *bvec; |
1da177e4c Linux-2.6.12-rc2 |
256 257 258 259 |
/* * we are really probing at internals to determine * whether to set MSG_MORE or not... */ |
5705f7021 Introduce rq_for_... |
260 |
rq_for_each_segment(bvec, req, iter) { |
6c92e699b Fixup rq_for_each... |
261 262 263 264 265 266 |
flags = 0; if (!rq_iter_last(req, iter)) flags = MSG_MORE; dprintk(DBG_TX, "%s: request %p: sending %d bytes data ", lo->disk->disk_name, req, bvec->bv_len); |
7fdfd4065 NBD: allow hung n... |
267 |
result = sock_send_bvec(lo, bvec, flags); |
6c92e699b Fixup rq_for_each... |
268 269 270 271 272 273 |
if (result <= 0) { printk(KERN_ERR "%s: Send data failed (result %d) ", lo->disk->disk_name, result); goto error_out; } |
1da177e4c Linux-2.6.12-rc2 |
274 275 |
} } |
1da177e4c Linux-2.6.12-rc2 |
276 277 278 |
return 0; error_out: |
15746fcaa nbd: trivial clea... |
279 |
return -EIO; |
1da177e4c Linux-2.6.12-rc2 |
280 |
} |
0cbc591bf nbd: change a par... |
281 282 |
static struct request *nbd_find_request(struct nbd_device *lo, struct request *xreq) |
1da177e4c Linux-2.6.12-rc2 |
283 |
{ |
d2c9740b4 nbd: use list_for... |
284 |
struct request *req, *tmp; |
4b2f0260c [PATCH] nbd: fix ... |
285 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
286 |
|
4b2f0260c [PATCH] nbd: fix ... |
287 288 289 |
err = wait_event_interruptible(lo->active_wq, lo->active_req != xreq); if (unlikely(err)) goto out; |
1da177e4c Linux-2.6.12-rc2 |
290 |
spin_lock(&lo->queue_lock); |
d2c9740b4 nbd: use list_for... |
291 |
list_for_each_entry_safe(req, tmp, &lo->queue_head, queuelist) { |
1da177e4c Linux-2.6.12-rc2 |
292 293 294 295 296 297 298 |
if (req != xreq) continue; list_del_init(&req->queuelist); spin_unlock(&lo->queue_lock); return req; } spin_unlock(&lo->queue_lock); |
4b2f0260c [PATCH] nbd: fix ... |
299 300 301 302 303 |
err = -ENOENT; out: return ERR_PTR(err); |
1da177e4c Linux-2.6.12-rc2 |
304 |
} |
7fdfd4065 NBD: allow hung n... |
305 |
static inline int sock_recv_bvec(struct nbd_device *lo, struct bio_vec *bvec) |
1da177e4c Linux-2.6.12-rc2 |
306 307 308 |
{ int result; void *kaddr = kmap(bvec->bv_page); |
7fdfd4065 NBD: allow hung n... |
309 |
result = sock_xmit(lo, 0, kaddr + bvec->bv_offset, bvec->bv_len, |
1da177e4c Linux-2.6.12-rc2 |
310 311 312 313 314 315 316 317 318 319 320 |
MSG_WAITALL); kunmap(bvec->bv_page); return result; } /* NULL returned = something went wrong, inform userspace */ static struct request *nbd_read_stat(struct nbd_device *lo) { int result; struct nbd_reply reply; struct request *req; |
1da177e4c Linux-2.6.12-rc2 |
321 322 |
reply.magic = 0; |
7fdfd4065 NBD: allow hung n... |
323 |
result = sock_xmit(lo, 0, &reply, sizeof(reply), MSG_WAITALL); |
1da177e4c Linux-2.6.12-rc2 |
324 325 326 327 328 329 |
if (result <= 0) { printk(KERN_ERR "%s: Receive control failed (result %d) ", lo->disk->disk_name, result); goto harderror; } |
e4b57e084 [PATCH] nbd: Chec... |
330 331 332 333 334 335 336 337 338 |
if (ntohl(reply.magic) != NBD_REPLY_MAGIC) { printk(KERN_ERR "%s: Wrong magic (0x%lx) ", lo->disk->disk_name, (unsigned long)ntohl(reply.magic)); result = -EPROTO; goto harderror; } |
0cbc591bf nbd: change a par... |
339 |
req = nbd_find_request(lo, *(struct request **)reply.handle); |
801678c5a Remove duplicated... |
340 |
if (IS_ERR(req)) { |
4b2f0260c [PATCH] nbd: fix ... |
341 342 343 |
result = PTR_ERR(req); if (result != -ENOENT) goto harderror; |
1da177e4c Linux-2.6.12-rc2 |
344 345 346 347 348 349 |
printk(KERN_ERR "%s: Unexpected reply (%p) ", lo->disk->disk_name, reply.handle); result = -EBADR; goto harderror; } |
1da177e4c Linux-2.6.12-rc2 |
350 351 352 353 354 355 356 357 358 359 360 361 |
if (ntohl(reply.error)) { printk(KERN_ERR "%s: Other side returned error (%d) ", lo->disk->disk_name, ntohl(reply.error)); req->errors++; return req; } dprintk(DBG_RX, "%s: request %p: got reply ", lo->disk->disk_name, req); if (nbd_cmd(req) == NBD_CMD_READ) { |
5705f7021 Introduce rq_for_... |
362 363 364 365 |
struct req_iterator iter; struct bio_vec *bvec; rq_for_each_segment(bvec, req, iter) { |
7fdfd4065 NBD: allow hung n... |
366 |
result = sock_recv_bvec(lo, bvec); |
6c92e699b Fixup rq_for_each... |
367 368 369 370 371 372 373 374 375 376 |
if (result <= 0) { printk(KERN_ERR "%s: Receive data failed (result %d) ", lo->disk->disk_name, result); req->errors++; return req; } dprintk(DBG_RX, "%s: request %p: got %d bytes data ", lo->disk->disk_name, req, bvec->bv_len); |
1da177e4c Linux-2.6.12-rc2 |
377 378 379 380 381 382 383 |
} } return req; harderror: lo->harderror = result; return NULL; } |
edfaa7c36 Driver core: conv... |
384 385 |
static ssize_t pid_show(struct device *dev, struct device_attribute *attr, char *buf) |
6b39bb654 [PATCH] nbd: show... |
386 |
{ |
edfaa7c36 Driver core: conv... |
387 388 389 390 |
struct gendisk *disk = dev_to_disk(dev); return sprintf(buf, "%ld ", |
6b39bb654 [PATCH] nbd: show... |
391 392 |
(long) ((struct nbd_device *)disk->private_data)->pid); } |
edfaa7c36 Driver core: conv... |
393 |
static struct device_attribute pid_attr = { |
01e8ef11b x86: sysfs: kill ... |
394 |
.attr = { .name = "pid", .mode = S_IRUGO}, |
6b39bb654 [PATCH] nbd: show... |
395 396 |
.show = pid_show, }; |
84963048c nbd: check the re... |
397 |
static int nbd_do_it(struct nbd_device *lo) |
1da177e4c Linux-2.6.12-rc2 |
398 399 |
{ struct request *req; |
84963048c nbd: check the re... |
400 |
int ret; |
1da177e4c Linux-2.6.12-rc2 |
401 402 |
BUG_ON(lo->magic != LO_MAGIC); |
6b39bb654 [PATCH] nbd: show... |
403 |
lo->pid = current->pid; |
ed9e19823 block: implement ... |
404 |
ret = sysfs_create_file(&disk_to_dev(lo->disk)->kobj, &pid_attr.attr); |
84963048c nbd: check the re... |
405 406 |
if (ret) { printk(KERN_ERR "nbd: sysfs_create_file failed!"); |
c91192d66 nbd: do not allow... |
407 |
lo->pid = 0; |
84963048c nbd: check the re... |
408 409 |
return ret; } |
6b39bb654 [PATCH] nbd: show... |
410 |
|
1da177e4c Linux-2.6.12-rc2 |
411 412 |
while ((req = nbd_read_stat(lo)) != NULL) nbd_end_request(req); |
6b39bb654 [PATCH] nbd: show... |
413 |
|
ed9e19823 block: implement ... |
414 |
sysfs_remove_file(&disk_to_dev(lo->disk)->kobj, &pid_attr.attr); |
c91192d66 nbd: do not allow... |
415 |
lo->pid = 0; |
84963048c nbd: check the re... |
416 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
417 418 419 420 421 422 423 |
} static void nbd_clear_que(struct nbd_device *lo) { struct request *req; BUG_ON(lo->magic != LO_MAGIC); |
4b2f0260c [PATCH] nbd: fix ... |
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 |
/* * Because we have set lo->sock to NULL under the tx_lock, all * modifications to the list must have completed by now. For * the same reason, the active_req must be NULL. * * As a consequence, we don't need to take the spin lock while * purging the list here. */ BUG_ON(lo->sock); BUG_ON(lo->active_req); while (!list_empty(&lo->queue_head)) { req = list_entry(lo->queue_head.next, struct request, queuelist); list_del_init(&req->queuelist); req->errors++; nbd_end_request(req); } |
1da177e4c Linux-2.6.12-rc2 |
442 |
} |
7fdfd4065 NBD: allow hung n... |
443 |
|
48cf6061b NBD: allow nbd to... |
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 |
static void nbd_handle_req(struct nbd_device *lo, struct request *req) { if (!blk_fs_request(req)) goto error_out; nbd_cmd(req) = NBD_CMD_READ; if (rq_data_dir(req) == WRITE) { nbd_cmd(req) = NBD_CMD_WRITE; if (lo->flags & NBD_READ_ONLY) { printk(KERN_ERR "%s: Write on read-only ", lo->disk->disk_name); goto error_out; } } req->errors = 0; mutex_lock(&lo->tx_lock); if (unlikely(!lo->sock)) { mutex_unlock(&lo->tx_lock); printk(KERN_ERR "%s: Attempted send on closed socket ", lo->disk->disk_name); |
15746fcaa nbd: trivial clea... |
468 |
goto error_out; |
48cf6061b NBD: allow nbd to... |
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 |
} lo->active_req = req; if (nbd_send_req(lo, req) != 0) { printk(KERN_ERR "%s: Request send failed ", lo->disk->disk_name); req->errors++; nbd_end_request(req); } else { spin_lock(&lo->queue_lock); list_add(&req->queuelist, &lo->queue_head); spin_unlock(&lo->queue_lock); } lo->active_req = NULL; mutex_unlock(&lo->tx_lock); wake_up_all(&lo->active_wq); return; error_out: req->errors++; nbd_end_request(req); } static int nbd_thread(void *data) { struct nbd_device *lo = data; struct request *req; set_user_nice(current, -20); while (!kthread_should_stop() || !list_empty(&lo->waiting_queue)) { /* wait for something to do */ wait_event_interruptible(lo->waiting_wq, kthread_should_stop() || !list_empty(&lo->waiting_queue)); /* extract request */ if (list_empty(&lo->waiting_queue)) continue; spin_lock_irq(&lo->queue_lock); req = list_entry(lo->waiting_queue.next, struct request, queuelist); list_del_init(&req->queuelist); spin_unlock_irq(&lo->queue_lock); /* handle request */ nbd_handle_req(lo, req); } return 0; } |
1da177e4c Linux-2.6.12-rc2 |
523 524 525 |
/* * We always wait for result of write, for now. It would be nice to make it optional * in future |
e654bc439 [PATCH] fix reque... |
526 |
* if ((rq_data_dir(req) == WRITE) && (lo->flags & NBD_WRITE_NOCHK)) |
1da177e4c Linux-2.6.12-rc2 |
527 528 529 |
* { printk( "Warning: Ignoring result! "); nbd_end_request( req ); } */ |
15746fcaa nbd: trivial clea... |
530 |
static void do_nbd_request(struct request_queue *q) |
1da177e4c Linux-2.6.12-rc2 |
531 532 533 534 535 536 537 |
{ struct request *req; while ((req = elv_next_request(q)) != NULL) { struct nbd_device *lo; blkdev_dequeue_request(req); |
48cf6061b NBD: allow nbd to... |
538 539 |
spin_unlock_irq(q->queue_lock); |
4aff5e233 [PATCH] Split str... |
540 541 542 |
dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%x) ", req->rq_disk->disk_name, req, req->cmd_type); |
1da177e4c Linux-2.6.12-rc2 |
543 |
|
1da177e4c Linux-2.6.12-rc2 |
544 545 546 |
lo = req->rq_disk->private_data; BUG_ON(lo->magic != LO_MAGIC); |
4d48a542b nbd: fix I/O hang... |
547 548 549 550 551 552 553 554 555 |
if (unlikely(!lo->sock)) { printk(KERN_ERR "%s: Attempted send on closed socket ", lo->disk->disk_name); req->errors++; nbd_end_request(req); spin_lock_irq(q->queue_lock); continue; } |
48cf6061b NBD: allow nbd to... |
556 557 558 |
spin_lock_irq(&lo->queue_lock); list_add_tail(&req->queuelist, &lo->waiting_queue); spin_unlock_irq(&lo->queue_lock); |
1da177e4c Linux-2.6.12-rc2 |
559 |
|
48cf6061b NBD: allow nbd to... |
560 |
wake_up(&lo->waiting_wq); |
4b2f0260c [PATCH] nbd: fix ... |
561 |
|
1da177e4c Linux-2.6.12-rc2 |
562 |
spin_lock_irq(q->queue_lock); |
1da177e4c Linux-2.6.12-rc2 |
563 |
} |
1da177e4c Linux-2.6.12-rc2 |
564 |
} |
1a2ad2112 nbd: add locking ... |
565 |
/* Must be called with tx_lock held */ |
1da177e4c Linux-2.6.12-rc2 |
566 |
|
1a2ad2112 nbd: add locking ... |
567 568 569 |
static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo, unsigned int cmd, unsigned long arg) { |
1da177e4c Linux-2.6.12-rc2 |
570 |
switch (cmd) { |
1a2ad2112 nbd: add locking ... |
571 572 |
case NBD_DISCONNECT: { struct request sreq; |
1da177e4c Linux-2.6.12-rc2 |
573 574 |
printk(KERN_INFO "%s: NBD_DISCONNECT ", lo->disk->disk_name); |
1a2ad2112 nbd: add locking ... |
575 |
|
4f54eec83 block: use blk_rq... |
576 |
blk_rq_init(NULL, &sreq); |
4aff5e233 [PATCH] Split str... |
577 |
sreq.cmd_type = REQ_TYPE_SPECIAL; |
1da177e4c Linux-2.6.12-rc2 |
578 579 580 581 582 583 584 585 |
nbd_cmd(&sreq) = NBD_CMD_DISC; /* * Set these to sane values in case server implementation * fails to check the request type first and also to keep * debugging output cleaner. */ sreq.sector = 0; sreq.nr_sectors = 0; |
1a2ad2112 nbd: add locking ... |
586 |
if (!lo->sock) |
1da177e4c Linux-2.6.12-rc2 |
587 |
return -EINVAL; |
1a2ad2112 nbd: add locking ... |
588 |
nbd_send_req(lo, &sreq); |
1da177e4c Linux-2.6.12-rc2 |
589 |
return 0; |
1a2ad2112 nbd: add locking ... |
590 |
} |
1da177e4c Linux-2.6.12-rc2 |
591 |
|
1a2ad2112 nbd: add locking ... |
592 593 |
case NBD_CLEAR_SOCK: { struct file *file; |
1da177e4c Linux-2.6.12-rc2 |
594 |
lo->sock = NULL; |
1da177e4c Linux-2.6.12-rc2 |
595 596 |
file = lo->file; lo->file = NULL; |
1da177e4c Linux-2.6.12-rc2 |
597 |
nbd_clear_que(lo); |
4b2f0260c [PATCH] nbd: fix ... |
598 |
BUG_ON(!list_empty(&lo->queue_head)); |
1da177e4c Linux-2.6.12-rc2 |
599 600 |
if (file) fput(file); |
1a2ad2112 nbd: add locking ... |
601 602 603 604 605 |
return 0; } case NBD_SET_SOCK: { struct file *file; |
1da177e4c Linux-2.6.12-rc2 |
606 607 |
if (lo->file) return -EBUSY; |
1da177e4c Linux-2.6.12-rc2 |
608 609 |
file = fget(arg); if (file) { |
a8cdc308c [PATCH] switch nbd |
610 |
struct inode *inode = file->f_path.dentry->d_inode; |
1da177e4c Linux-2.6.12-rc2 |
611 612 613 |
if (S_ISSOCK(inode->i_mode)) { lo->file = file; lo->sock = SOCKET_I(inode); |
d71a6d733 NBD: add partitio... |
614 615 |
if (max_part > 0) bdev->bd_invalidated = 1; |
1a2ad2112 nbd: add locking ... |
616 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
617 618 619 620 |
} else { fput(file); } } |
1a2ad2112 nbd: add locking ... |
621 622 |
return -EINVAL; } |
1da177e4c Linux-2.6.12-rc2 |
623 624 625 |
case NBD_SET_BLKSIZE: lo->blksize = arg; lo->bytesize &= ~(lo->blksize-1); |
a8cdc308c [PATCH] switch nbd |
626 627 |
bdev->bd_inode->i_size = lo->bytesize; set_blocksize(bdev, lo->blksize); |
1da177e4c Linux-2.6.12-rc2 |
628 629 |
set_capacity(lo->disk, lo->bytesize >> 9); return 0; |
1a2ad2112 nbd: add locking ... |
630 |
|
1da177e4c Linux-2.6.12-rc2 |
631 632 |
case NBD_SET_SIZE: lo->bytesize = arg & ~(lo->blksize-1); |
a8cdc308c [PATCH] switch nbd |
633 634 |
bdev->bd_inode->i_size = lo->bytesize; set_blocksize(bdev, lo->blksize); |
1da177e4c Linux-2.6.12-rc2 |
635 636 |
set_capacity(lo->disk, lo->bytesize >> 9); return 0; |
1a2ad2112 nbd: add locking ... |
637 |
|
7fdfd4065 NBD: allow hung n... |
638 639 640 |
case NBD_SET_TIMEOUT: lo->xmit_timeout = arg * HZ; return 0; |
1a2ad2112 nbd: add locking ... |
641 |
|
1da177e4c Linux-2.6.12-rc2 |
642 643 |
case NBD_SET_SIZE_BLOCKS: lo->bytesize = ((u64) arg) * lo->blksize; |
a8cdc308c [PATCH] switch nbd |
644 645 |
bdev->bd_inode->i_size = lo->bytesize; set_blocksize(bdev, lo->blksize); |
1da177e4c Linux-2.6.12-rc2 |
646 647 |
set_capacity(lo->disk, lo->bytesize >> 9); return 0; |
1a2ad2112 nbd: add locking ... |
648 649 650 651 652 |
case NBD_DO_IT: { struct task_struct *thread; struct file *file; int error; |
c91192d66 nbd: do not allow... |
653 654 |
if (lo->pid) return -EBUSY; |
1da177e4c Linux-2.6.12-rc2 |
655 656 |
if (!lo->file) return -EINVAL; |
1a2ad2112 nbd: add locking ... |
657 658 |
mutex_unlock(&lo->tx_lock); |
48cf6061b NBD: allow nbd to... |
659 |
thread = kthread_create(nbd_thread, lo, lo->disk->disk_name); |
1a2ad2112 nbd: add locking ... |
660 661 |
if (IS_ERR(thread)) { mutex_lock(&lo->tx_lock); |
48cf6061b NBD: allow nbd to... |
662 |
return PTR_ERR(thread); |
1a2ad2112 nbd: add locking ... |
663 |
} |
48cf6061b NBD: allow nbd to... |
664 |
wake_up_process(thread); |
84963048c nbd: check the re... |
665 |
error = nbd_do_it(lo); |
48cf6061b NBD: allow nbd to... |
666 |
kthread_stop(thread); |
1a2ad2112 nbd: add locking ... |
667 668 |
mutex_lock(&lo->tx_lock); |
84963048c nbd: check the re... |
669 670 |
if (error) return error; |
1a2ad2112 nbd: add locking ... |
671 |
sock_shutdown(lo, 0); |
1da177e4c Linux-2.6.12-rc2 |
672 673 |
file = lo->file; lo->file = NULL; |
1da177e4c Linux-2.6.12-rc2 |
674 675 676 677 678 |
nbd_clear_que(lo); printk(KERN_WARNING "%s: queue cleared ", lo->disk->disk_name); if (file) fput(file); |
4b86a8725 NBD: set uninitia... |
679 |
lo->bytesize = 0; |
a8cdc308c [PATCH] switch nbd |
680 |
bdev->bd_inode->i_size = 0; |
4b86a8725 NBD: set uninitia... |
681 |
set_capacity(lo->disk, 0); |
d71a6d733 NBD: add partitio... |
682 |
if (max_part > 0) |
a8cdc308c [PATCH] switch nbd |
683 |
ioctl_by_bdev(bdev, BLKRRPART, 0); |
1da177e4c Linux-2.6.12-rc2 |
684 |
return lo->harderror; |
1a2ad2112 nbd: add locking ... |
685 |
} |
1da177e4c Linux-2.6.12-rc2 |
686 |
case NBD_CLEAR_QUE: |
4b2f0260c [PATCH] nbd: fix ... |
687 688 689 690 691 |
/* * This is for compatibility only. The queue is always cleared * by NBD_DO_IT or NBD_CLEAR_SOCK. */ BUG_ON(!lo->sock && !list_empty(&lo->queue_head)); |
1da177e4c Linux-2.6.12-rc2 |
692 |
return 0; |
1a2ad2112 nbd: add locking ... |
693 |
|
1da177e4c Linux-2.6.12-rc2 |
694 695 696 |
case NBD_PRINT_DEBUG: printk(KERN_INFO "%s: next = %p, prev = %p, head = %p ", |
a8cdc308c [PATCH] switch nbd |
697 |
bdev->bd_disk->disk_name, |
1da177e4c Linux-2.6.12-rc2 |
698 699 700 701 |
lo->queue_head.next, lo->queue_head.prev, &lo->queue_head); return 0; } |
1a2ad2112 nbd: add locking ... |
702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 |
return -ENOTTY; } static int nbd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { struct nbd_device *lo = bdev->bd_disk->private_data; int error; if (!capable(CAP_SYS_ADMIN)) return -EPERM; BUG_ON(lo->magic != LO_MAGIC); /* Anyone capable of this syscall can do *real bad* things */ dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu ", lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg); mutex_lock(&lo->tx_lock); error = __nbd_ioctl(bdev, lo, cmd, arg); mutex_unlock(&lo->tx_lock); return error; |
1da177e4c Linux-2.6.12-rc2 |
726 727 728 729 730 |
} static struct block_device_operations nbd_fops = { .owner = THIS_MODULE, |
a8cdc308c [PATCH] switch nbd |
731 |
.locked_ioctl = nbd_ioctl, |
1da177e4c Linux-2.6.12-rc2 |
732 733 734 735 736 737 738 739 740 741 742 |
}; /* * And here should be modules and kernel interface * (Just smiley confuses emacs :-) */ static int __init nbd_init(void) { int err = -ENOMEM; int i; |
d71a6d733 NBD: add partitio... |
743 |
int part_shift; |
1da177e4c Linux-2.6.12-rc2 |
744 |
|
5b7b18ccd [PATCH] drivers/b... |
745 |
BUILD_BUG_ON(sizeof(struct nbd_request) != 28); |
1da177e4c Linux-2.6.12-rc2 |
746 |
|
d71a6d733 NBD: add partitio... |
747 748 749 750 751 |
if (max_part < 0) { printk(KERN_CRIT "nbd: max_part must be >= 0 "); return -EINVAL; } |
f3944d61d nbd: fix memory l... |
752 753 754 |
nbd_dev = kcalloc(nbds_max, sizeof(*nbd_dev), GFP_KERNEL); if (!nbd_dev) return -ENOMEM; |
d71a6d733 NBD: add partitio... |
755 756 757 |
part_shift = 0; if (max_part > 0) part_shift = fls(max_part); |
40be0c28b [PATCH] nbd: Don'... |
758 |
for (i = 0; i < nbds_max; i++) { |
d71a6d733 NBD: add partitio... |
759 |
struct gendisk *disk = alloc_disk(1 << part_shift); |
1da177e4c Linux-2.6.12-rc2 |
760 761 762 763 764 765 766 767 768 769 770 771 772 |
if (!disk) goto out; nbd_dev[i].disk = disk; /* * The new linux 2.5 block layer implementation requires * every gendisk to have its very own request_queue struct. * These structs are big so we dynamically allocate them. */ disk->queue = blk_init_queue(do_nbd_request, &nbd_lock); if (!disk->queue) { put_disk(disk); goto out; } |
31dcfab0a nbd: tell the blo... |
773 774 775 776 |
/* * Tell the block layer that we are not a rotational device */ queue_flag_set_unlocked(QUEUE_FLAG_NONROT, disk->queue); |
1da177e4c Linux-2.6.12-rc2 |
777 778 779 780 781 782 783 784 785 786 787 |
} if (register_blkdev(NBD_MAJOR, "nbd")) { err = -EIO; goto out; } printk(KERN_INFO "nbd: registered device at major %d ", NBD_MAJOR); dprintk(DBG_INIT, "nbd: debugflags=0x%x ", debugflags); |
40be0c28b [PATCH] nbd: Don'... |
788 |
for (i = 0; i < nbds_max; i++) { |
1da177e4c Linux-2.6.12-rc2 |
789 790 791 792 |
struct gendisk *disk = nbd_dev[i].disk; nbd_dev[i].file = NULL; nbd_dev[i].magic = LO_MAGIC; nbd_dev[i].flags = 0; |
48cf6061b NBD: allow nbd to... |
793 |
INIT_LIST_HEAD(&nbd_dev[i].waiting_queue); |
1da177e4c Linux-2.6.12-rc2 |
794 795 |
spin_lock_init(&nbd_dev[i].queue_lock); INIT_LIST_HEAD(&nbd_dev[i].queue_head); |
82d4dc5ad [PATCH] sem2mutex... |
796 |
mutex_init(&nbd_dev[i].tx_lock); |
4b2f0260c [PATCH] nbd: fix ... |
797 |
init_waitqueue_head(&nbd_dev[i].active_wq); |
48cf6061b NBD: allow nbd to... |
798 |
init_waitqueue_head(&nbd_dev[i].waiting_wq); |
1da177e4c Linux-2.6.12-rc2 |
799 |
nbd_dev[i].blksize = 1024; |
4b86a8725 NBD: set uninitia... |
800 |
nbd_dev[i].bytesize = 0; |
1da177e4c Linux-2.6.12-rc2 |
801 |
disk->major = NBD_MAJOR; |
d71a6d733 NBD: add partitio... |
802 |
disk->first_minor = i << part_shift; |
1da177e4c Linux-2.6.12-rc2 |
803 804 |
disk->fops = &nbd_fops; disk->private_data = &nbd_dev[i]; |
1da177e4c Linux-2.6.12-rc2 |
805 |
sprintf(disk->disk_name, "nbd%d", i); |
4b86a8725 NBD: set uninitia... |
806 |
set_capacity(disk, 0); |
1da177e4c Linux-2.6.12-rc2 |
807 808 809 810 811 812 813 814 815 |
add_disk(disk); } return 0; out: while (i--) { blk_cleanup_queue(nbd_dev[i].disk->queue); put_disk(nbd_dev[i].disk); } |
f3944d61d nbd: fix memory l... |
816 |
kfree(nbd_dev); |
1da177e4c Linux-2.6.12-rc2 |
817 818 819 820 821 822 |
return err; } static void __exit nbd_cleanup(void) { int i; |
40be0c28b [PATCH] nbd: Don'... |
823 |
for (i = 0; i < nbds_max; i++) { |
1da177e4c Linux-2.6.12-rc2 |
824 |
struct gendisk *disk = nbd_dev[i].disk; |
40be0c28b [PATCH] nbd: Don'... |
825 |
nbd_dev[i].magic = 0; |
1da177e4c Linux-2.6.12-rc2 |
826 827 828 829 830 831 |
if (disk) { del_gendisk(disk); blk_cleanup_queue(disk->queue); put_disk(disk); } } |
1da177e4c Linux-2.6.12-rc2 |
832 |
unregister_blkdev(NBD_MAJOR, "nbd"); |
f3944d61d nbd: fix memory l... |
833 |
kfree(nbd_dev); |
1da177e4c Linux-2.6.12-rc2 |
834 835 836 837 838 839 840 841 842 |
printk(KERN_INFO "nbd: unregistered device at major %d ", NBD_MAJOR); } module_init(nbd_init); module_exit(nbd_cleanup); MODULE_DESCRIPTION("Network Block Device"); MODULE_LICENSE("GPL"); |
40be0c28b [PATCH] nbd: Don'... |
843 |
module_param(nbds_max, int, 0444); |
d71a6d733 NBD: add partitio... |
844 845 846 |
MODULE_PARM_DESC(nbds_max, "number of network block devices to initialize (default: 16)"); module_param(max_part, int, 0444); MODULE_PARM_DESC(max_part, "number of partitions per device (default: 0)"); |
1da177e4c Linux-2.6.12-rc2 |
847 848 849 850 |
#ifndef NDEBUG module_param(debugflags, int, 0644); MODULE_PARM_DESC(debugflags, "flags for controlling debug output"); #endif |