]>
Commit | Line | Data |
---|---|---|
4bf12011 | 1 | diff -urN linux-2.6.7/drivers/block/Kconfig linux-2.6.7-patched/drivers/block/Kconfig |
2 | --- linux-2.6.7/drivers/block/Kconfig 2004-06-16 00:19:01.000000000 -0500 | |
3 | +++ linux-2.6.7-patched/drivers/block/Kconfig 2004-06-17 16:38:45.000000000 -0500 | |
4 | @@ -347,6 +347,13 @@ | |
5 | your machine, or if you want to have a raid or loopback device | |
6 | bigger than 2TB. Otherwise say N. | |
7 | ||
8 | +config BLK_DEV_GNBD | |
9 | + tristate "Global network block device support" | |
10 | + depends on NET | |
11 | + ---help--- | |
12 | + | |
13 | + If unsure, say N. | |
14 | + | |
15 | source "drivers/s390/block/Kconfig" | |
16 | ||
17 | endmenu | |
18 | diff -urN linux-2.6.7/drivers/block/Makefile linux-2.6.7-patched/drivers/block/Makefile | |
19 | --- linux-2.6.7/drivers/block/Makefile 2004-06-16 00:19:52.000000000 -0500 | |
20 | +++ linux-2.6.7-patched/drivers/block/Makefile 2004-06-17 16:38:45.000000000 -0500 | |
21 | @@ -42,4 +42,4 @@ | |
22 | ||
23 | obj-$(CONFIG_VIODASD) += viodasd.o | |
24 | obj-$(CONFIG_BLK_DEV_SX8) += sx8.o | |
25 | - | |
26 | +obj-$(CONFIG_BLK_DEV_GNBD) += gnbd.o | |
27 | diff -urN linux-orig/drivers/block/gnbd.c linux-patched/drivers/block/gnbd.c | |
28 | --- linux-orig/drivers/block/gnbd.c 1969-12-31 18:00:00.000000000 -0600 | |
5cdbd17b AM |
29 | +++ linux-patched/drivers/block/gnbd.c 2004-06-30 16:48:06.000000000 -0500 |
30 | @@ -0,0 +1,1076 @@ | |
4bf12011 | 31 | +/****************************************************************************** |
32 | +******************************************************************************* | |
33 | +** | |
34 | +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | |
35 | +** Copyright (C) 2004 Red Hat, Inc. All rights reserved. | |
36 | +** | |
37 | +** This copyrighted material is made available to anyone wishing to use, | |
38 | +** modify, copy, or redistribute it subject to the terms and conditions | |
39 | +** of the GNU General Public License v.2. | |
40 | +** | |
41 | +******************************************************************************* | |
42 | +******************************************************************************/ | |
43 | + | |
44 | +/* Large chunks of this code were lifted from nbd.c */ | |
45 | + | |
46 | +#include <linux/major.h> | |
47 | + | |
48 | +#include <linux/blkdev.h> | |
49 | +#include <linux/module.h> | |
50 | +#include <linux/init.h> | |
51 | +#include <linux/sched.h> | |
52 | +#include <linux/fs.h> | |
53 | +#include <linux/bio.h> | |
54 | +#include <linux/stat.h> | |
55 | +#include <linux/errno.h> | |
56 | +#include <linux/file.h> | |
57 | +#include <linux/ioctl.h> | |
58 | +#include <net/sock.h> | |
59 | +#include <linux/in.h> | |
60 | +#include <linux/buffer_head.h> | |
61 | +#include <linux/miscdevice.h> | |
62 | + | |
63 | +#include <linux/devfs_fs_kernel.h> | |
64 | + | |
65 | +#include <asm/uaccess.h> | |
66 | +#include <asm/types.h> | |
67 | + | |
68 | +#include <linux/gnbd.h> | |
69 | + | |
70 | +static int major_nr = 0; | |
71 | +uint64_t insmod_time; | |
72 | + | |
73 | + | |
74 | +#define GNBD_MAGIC 0x74d06100 | |
75 | + | |
76 | +#ifdef NDEBUG | |
77 | +#define dprintk(flags, fmt...) | |
78 | +#else /* NDEBUG */ | |
79 | +#define dprintk(flags, fmt...) do { \ | |
80 | + if (debugflags & (flags)) printk(KERN_DEBUG fmt); \ | |
81 | +} while (0) | |
82 | +#define DBG_IOCTL 0x0004 | |
83 | +#define DBG_INIT 0x0010 | |
84 | +#define DBG_EXIT 0x0020 | |
85 | +#define DBG_BLKDEV 0x0100 | |
86 | +#define DBG_RX 0x0200 | |
87 | +#define DBG_TX 0x0400 | |
88 | +static unsigned int debugflags; | |
89 | +#endif /* NDEBUG */ | |
90 | + | |
91 | +static struct gnbd_device gnbd_dev[MAX_GNBD]; | |
92 | + | |
93 | +struct request shutdown_req; | |
94 | +struct request ping_req; | |
95 | + | |
96 | +static spinlock_t gnbd_lock = SPIN_LOCK_UNLOCKED; | |
97 | + | |
98 | +#define to_gnbd_dev(d) container_of(d, struct gnbd_device, class_dev) | |
99 | + | |
100 | +static void gnbd_class_release(struct class_device *class_dev) | |
101 | +{ | |
102 | + printk("releasing gnbd class\n"); | |
103 | + /* FIXME -- What the hell do I have to free up here */ | |
104 | +} | |
105 | + | |
106 | +static struct class gnbd_class = { | |
107 | + .name = "gnbd", | |
108 | + .release = gnbd_class_release | |
109 | +}; | |
110 | + | |
111 | + | |
112 | +static ssize_t show_pid(struct class_device *class_dev, char *buf) | |
113 | +{ | |
114 | + struct gnbd_device *dev = to_gnbd_dev(class_dev); | |
115 | + return sprintf(buf, "%d\n", dev->receiver_pid); | |
116 | +} | |
117 | + | |
118 | +static CLASS_DEVICE_ATTR(pid, S_IRUGO, show_pid, NULL); | |
119 | + | |
120 | +static ssize_t show_server(struct class_device *class_dev, char *buf) | |
121 | +{ | |
122 | + struct gnbd_device *dev = to_gnbd_dev(class_dev); | |
5cdbd17b AM |
123 | + if (dev->server_name) |
124 | + return sprintf(buf, "%s/%hx\n", dev->server_name, | |
125 | + dev->server_port); | |
126 | + else | |
127 | + return sprintf(buf, "\n"); | |
4bf12011 | 128 | +} |
129 | + | |
5cdbd17b | 130 | +/* FIXME -- should a empty store free the memory */ |
4bf12011 | 131 | +static ssize_t store_server(struct class_device *class_dev, |
132 | + const char *buf, size_t count) | |
133 | +{ | |
134 | + int res; | |
4bf12011 | 135 | + short unsigned int port; |
5cdbd17b | 136 | + char *ptr; |
4bf12011 | 137 | + struct gnbd_device *dev = to_gnbd_dev(class_dev); |
138 | + if (down_trylock(&dev->do_it_lock)) | |
139 | + return -EBUSY; | |
5cdbd17b AM |
140 | + if (dev->server_name) |
141 | + kfree(dev->server_name); | |
142 | + dev->server_name = kmalloc(count + 1, GFP_KERNEL); | |
143 | + if (!dev->server_name) | |
144 | + return -ENOMEM; | |
145 | + memcpy(dev->server_name, buf, count); | |
146 | + dev->server_name[count] = 0; | |
147 | + ptr = strchr(dev->server_name, '/'); | |
148 | + if (!ptr) | |
149 | + return -EINVAL; | |
150 | + *ptr++ = 0; | |
151 | + res = sscanf(ptr, "%4hx", &port); | |
152 | + if (res != 1){ | |
4bf12011 | 153 | + up(&dev->do_it_lock); |
154 | + return -EINVAL; | |
155 | + } | |
4bf12011 | 156 | + dev->server_port = port; |
157 | + up(&dev->do_it_lock); | |
158 | + return count; | |
159 | +} | |
160 | + | |
161 | +CLASS_DEVICE_ATTR(server, S_IRUGO | S_IWUSR, show_server, store_server); | |
162 | + | |
163 | +static ssize_t show_name(struct class_device *class_dev, char *buf) | |
164 | +{ | |
165 | + struct gnbd_device *dev = to_gnbd_dev(class_dev); | |
166 | + return sprintf(buf, "%s\n", dev->name); | |
167 | +} | |
168 | + | |
169 | +static ssize_t store_name(struct class_device *class_dev, | |
170 | + const char *buf, size_t count) | |
171 | +{ | |
172 | + int res; | |
173 | + struct gnbd_device *dev = to_gnbd_dev(class_dev); | |
174 | + if (down_trylock(&dev->do_it_lock)) | |
175 | + return -EBUSY; | |
176 | + res = sscanf(buf, "%31s", dev->name); | |
177 | + up(&dev->do_it_lock); | |
178 | + if (res != 1) | |
179 | + return -EINVAL; | |
180 | + return count; | |
181 | +} | |
182 | + | |
183 | +CLASS_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_name, store_name); | |
184 | + | |
185 | + | |
186 | +static ssize_t show_sectors(struct class_device *class_dev, char *buf) | |
187 | +{ | |
188 | + struct gnbd_device *dev = to_gnbd_dev(class_dev); | |
189 | + return sprintf(buf, "%Lu\n", | |
190 | + (unsigned long long)get_capacity(dev->disk)); | |
191 | +} | |
192 | + | |
193 | +static ssize_t store_sectors(struct class_device *class_dev, | |
194 | + const char *buf, size_t count) | |
195 | +{ | |
196 | + int res; | |
197 | + sector_t size; | |
198 | + struct block_device *bdev; | |
199 | + struct gnbd_device *dev = to_gnbd_dev(class_dev); | |
200 | + | |
201 | + if (down_trylock(&dev->do_it_lock)) | |
202 | + return -EBUSY; | |
203 | + res = sscanf(buf, "%Lu\n", &size); | |
204 | + if (res != 1){ | |
205 | + up(&dev->do_it_lock); | |
206 | + return -EINVAL; | |
207 | + } | |
208 | + /* FIXME -- should I switch the order here, so that I don't have | |
209 | + capacity set to one thing and the bdev inode size set to another */ | |
210 | + set_capacity(dev->disk, size); | |
211 | + bdev = bdget_disk(dev->disk, 0); | |
212 | + if (bdev) { | |
213 | + down(&bdev->bd_inode->i_sem); | |
214 | + i_size_write(bdev->bd_inode, (loff_t)size << 9); | |
215 | + up(&bdev->bd_inode->i_sem); | |
216 | + bdput(bdev); | |
217 | + } | |
218 | + up(&dev->do_it_lock); | |
219 | + return count; | |
220 | +} | |
221 | + | |
222 | +CLASS_DEVICE_ATTR(sectors, S_IRUGO | S_IWUSR, show_sectors, store_sectors); | |
223 | + | |
224 | +static ssize_t show_usage(struct class_device *class_dev, char *buf) | |
225 | +{ | |
226 | + struct gnbd_device *dev = to_gnbd_dev(class_dev); | |
227 | + return sprintf(buf, "%d\n", dev->open_count); | |
228 | +} | |
229 | + | |
230 | +CLASS_DEVICE_ATTR(usage, S_IRUGO, show_usage, NULL); | |
231 | + | |
232 | +static ssize_t show_flags(struct class_device *class_dev, char *buf) | |
233 | +{ | |
234 | + struct gnbd_device *dev = to_gnbd_dev(class_dev); | |
235 | + return sprintf(buf, "0x%04x\n", dev->flags); | |
236 | +} | |
237 | + | |
238 | +static ssize_t store_flags(struct class_device *class_dev, | |
239 | + const char *buf, size_t count) | |
240 | +{ | |
241 | + int res; | |
242 | + | |
243 | + struct gnbd_device *dev = to_gnbd_dev(class_dev); | |
244 | + if (down_trylock(&dev->do_it_lock)) | |
245 | + return -EBUSY; | |
246 | + res = sscanf(buf, "0x%hx", &dev->flags); | |
247 | + up(&dev->do_it_lock); | |
248 | + if (res != 1) | |
249 | + return -EINVAL; | |
250 | + return count; | |
251 | +} | |
252 | + | |
253 | + | |
254 | +CLASS_DEVICE_ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags); | |
255 | + | |
256 | +static ssize_t show_waittime(struct class_device *class_dev, char *buf) | |
257 | +{ | |
258 | + struct gnbd_device *dev = to_gnbd_dev(class_dev); | |
259 | + if (list_empty(&dev->queue_head)) | |
260 | + return sprintf(buf, "-1\n"); | |
261 | + return sprintf(buf, "%ld\n", | |
262 | + ((long)jiffies - (long)dev->last_received) / HZ); | |
263 | +} | |
264 | + | |
265 | +CLASS_DEVICE_ATTR(waittime, S_IRUGO, show_waittime, NULL); | |
266 | + | |
267 | +static ssize_t show_connected(struct class_device *class_dev, char *buf) | |
268 | +{ | |
269 | + struct gnbd_device *dev = to_gnbd_dev(class_dev); | |
270 | + return sprintf(buf, "%d\n", (dev->sock != NULL)); | |
271 | +} | |
272 | + | |
273 | +CLASS_DEVICE_ATTR(connected, S_IRUGO, show_connected, NULL); | |
274 | + | |
275 | +#ifndef NDEBUG | |
276 | +static const char *ioctl_cmd_to_ascii(int cmd) | |
277 | +{ | |
278 | + switch (cmd) { | |
279 | + case GNBD_DO_IT: return "do-it"; | |
280 | + case GNBD_CLEAR_QUE: return "clear-que"; | |
281 | + case GNBD_PRINT_DEBUG: return "print-debug"; | |
282 | + case GNBD_DISCONNECT: return "disconnect"; | |
283 | + } | |
284 | + return "unknown"; | |
285 | +} | |
286 | + | |
287 | +static const char *gnbdcmd_to_ascii(int cmd) | |
288 | +{ | |
289 | + switch (cmd) { | |
290 | + case GNBD_CMD_READ: return "read"; | |
291 | + case GNBD_CMD_WRITE: return "write"; | |
292 | + case GNBD_CMD_DISC: return "disconnect"; | |
293 | + case GNBD_CMD_PING: return "ping"; | |
294 | + } | |
295 | + return "invalid"; | |
296 | +} | |
297 | +#endif /* NDEBUG */ | |
298 | + | |
299 | +static void gnbd_end_request(struct request *req) | |
300 | +{ | |
301 | + int uptodate = (req->errors == 0) ? 1 : 0; | |
302 | + request_queue_t *q = req->q; | |
303 | + struct gnbd_device *dev = req->rq_disk->private_data; | |
304 | + unsigned long flags; | |
305 | + | |
306 | + dprintk(DBG_BLKDEV, "%s: request %p: %s\n", req->rq_disk->disk_name, | |
307 | + req, uptodate? "done": "failed"); | |
308 | + | |
309 | + if (!uptodate) | |
310 | + printk("%s %d called gnbd_end_request with and error\n", | |
311 | + current->comm, current->pid); | |
312 | + | |
313 | + spin_lock(&dev->queue_lock); | |
314 | + while (req->ref_count > 1) { /* still in send */ | |
315 | + spin_unlock(&dev->queue_lock); | |
316 | + printk(KERN_DEBUG "%s: request %p still in use (%d), waiting\n", | |
317 | + dev->disk->disk_name, req, req->ref_count); | |
318 | + set_current_state(TASK_UNINTERRUPTIBLE); | |
319 | + schedule_timeout(HZ); /* wait a second */ | |
320 | + spin_lock(&dev->queue_lock); | |
321 | + } | |
322 | + spin_unlock(&dev->queue_lock); | |
323 | + | |
324 | + spin_lock_irqsave(q->queue_lock, flags); | |
325 | + if (!end_that_request_first(req, uptodate, req->nr_sectors)) { | |
326 | + end_that_request_last(req); | |
327 | + } | |
328 | + spin_unlock_irqrestore(q->queue_lock, flags); | |
329 | +} | |
330 | + | |
331 | +/* | |
332 | + * Send or receive packet. | |
333 | + */ | |
334 | +static int sock_xmit(struct socket *sock, int send, void *buf, int size, | |
335 | + int msg_flags) | |
336 | +{ | |
337 | + mm_segment_t oldfs; | |
338 | + int result; | |
339 | + struct msghdr msg; | |
340 | + struct iovec iov; | |
341 | + unsigned long flags; | |
342 | + sigset_t oldset; | |
343 | + | |
344 | + oldfs = get_fs(); | |
345 | + set_fs(get_ds()); | |
346 | + /* Allow interception of SIGKILL only | |
347 | + * Don't allow other signals to interrupt the transmission */ | |
348 | + spin_lock_irqsave(¤t->sighand->siglock, flags); | |
349 | + oldset = current->blocked; | |
350 | + sigfillset(¤t->blocked); | |
351 | + sigdelsetmask(¤t->blocked, sigmask(SIGKILL)); | |
352 | + recalc_sigpending(); | |
353 | + spin_unlock_irqrestore(¤t->sighand->siglock, flags); | |
354 | + | |
355 | + do { | |
356 | + sock->sk->sk_allocation = GFP_NOIO; | |
357 | + iov.iov_base = buf; | |
358 | + iov.iov_len = size; | |
359 | + msg.msg_name = NULL; | |
360 | + msg.msg_namelen = 0; | |
361 | + msg.msg_iov = &iov; | |
362 | + msg.msg_iovlen = 1; | |
363 | + msg.msg_control = NULL; | |
364 | + msg.msg_controllen = 0; | |
365 | + msg.msg_namelen = 0; | |
366 | + msg.msg_flags = msg_flags | MSG_NOSIGNAL; | |
367 | + | |
368 | + if (send) | |
369 | + result = sock_sendmsg(sock, &msg, size); | |
370 | + else | |
371 | + result = sock_recvmsg(sock, &msg, size, 0); | |
372 | + | |
373 | + if (signal_pending(current)) { | |
374 | + siginfo_t info; | |
375 | + spin_lock_irqsave(¤t->sighand->siglock, flags); | |
376 | + printk(KERN_WARNING "gnbd (pid %d: %s) got signal %d\n", | |
377 | + current->pid, current->comm, | |
378 | + dequeue_signal(current, ¤t->blocked, &info)); | |
379 | + spin_unlock_irqrestore(¤t->sighand->siglock, flags); | |
380 | + result = -EINTR; | |
381 | + break; | |
382 | + } | |
383 | + | |
384 | + if (result <= 0) { | |
385 | + if (result == 0) | |
386 | + result = -EPIPE; /* short read */ | |
387 | + break; | |
388 | + } | |
389 | + size -= result; | |
390 | + buf += result; | |
391 | + } while (size > 0); | |
392 | + | |
393 | + spin_lock_irqsave(¤t->sighand->siglock, flags); | |
394 | + current->blocked = oldset; | |
395 | + recalc_sigpending(); | |
396 | + spin_unlock_irqrestore(¤t->sighand->siglock, flags); | |
397 | + | |
398 | + set_fs(oldfs); | |
399 | + return result; | |
400 | +} | |
401 | + | |
402 | +static inline int sock_send_bvec(struct socket *sock, struct bio_vec *bvec, | |
403 | + int flags) | |
404 | +{ | |
405 | + int result; | |
406 | + void *kaddr = kmap(bvec->bv_page); | |
407 | + result = sock_xmit(sock, 1, kaddr + bvec->bv_offset, bvec->bv_len, | |
408 | + flags); | |
409 | + kunmap(bvec->bv_page); | |
410 | + return result; | |
411 | +} | |
412 | + | |
413 | + | |
414 | +#define gnbd_send_req(dev, req) __gnbd_send_req((dev), (dev)->sock, (req)) | |
415 | + | |
416 | +int __gnbd_send_req(struct gnbd_device *dev, struct socket *sock, | |
417 | + struct request *req) | |
418 | +{ | |
419 | + int result, i, flags; | |
420 | + struct gnbd_request request; | |
421 | + unsigned long size = req->nr_sectors << 9; | |
422 | + | |
423 | + request.magic = htonl(GNBD_REQUEST_MAGIC); | |
424 | + request.type = htonl(gnbd_cmd(req)); | |
425 | + request.from = cpu_to_be64((u64) req->sector << 9); | |
426 | + request.len = htonl(size); | |
427 | + memcpy(request.handle, &req, sizeof(req)); | |
428 | + | |
429 | + down(&dev->tx_lock); | |
430 | + | |
431 | + if (!sock) { | |
432 | + printk(KERN_ERR "%s: Attempted send on closed socket\n", | |
433 | + dev->disk->disk_name); | |
434 | + result = -ENOTCONN; | |
435 | + goto error_out; | |
436 | + } | |
437 | + | |
438 | + dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%luB)\n", | |
439 | + dev->disk->disk_name, req, | |
440 | + gnbdcmd_to_ascii(gnbd_cmd(req)), | |
441 | + (unsigned long long)req->sector << 9, | |
442 | + req->nr_sectors << 9); | |
443 | + result = sock_xmit(sock, 1, &request, sizeof(request), | |
444 | + (gnbd_cmd(req) == GNBD_CMD_WRITE)? MSG_MORE: 0); | |
445 | + if (result < 0) { | |
446 | + printk(KERN_ERR "%s: Send control failed (result %d)\n", | |
447 | + dev->disk->disk_name, result); | |
448 | + goto error_out; | |
449 | + } | |
450 | + | |
451 | + if (gnbd_cmd(req) == GNBD_CMD_WRITE) { | |
452 | + struct bio *bio; | |
453 | + /* | |
454 | + * we are really probing at internals to determine | |
455 | + * whether to set MSG_MORE or not... | |
456 | + */ | |
457 | + rq_for_each_bio(bio, req) { | |
458 | + struct bio_vec *bvec; | |
459 | + bio_for_each_segment(bvec, bio, i) { | |
460 | + flags = 0; | |
461 | + if ((i < (bio->bi_vcnt - 1)) || bio->bi_next) | |
462 | + flags = MSG_MORE; | |
463 | + dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n", | |
464 | + dev->disk->disk_name, req, | |
465 | + bvec->bv_len); | |
466 | + result = sock_send_bvec(sock, bvec, flags); | |
467 | + if (result < 0) { | |
468 | + printk(KERN_ERR "%s: Send data failed (result %d)\n", | |
469 | + dev->disk->disk_name, | |
470 | + result); | |
471 | + goto error_out; | |
472 | + } | |
473 | + } | |
474 | + } | |
475 | + } | |
476 | + up(&dev->tx_lock); | |
477 | + return 0; | |
478 | + | |
479 | +error_out: | |
480 | + up(&dev->tx_lock); | |
481 | + return result; | |
482 | +} | |
483 | + | |
484 | + | |
485 | +static int gnbd_find_request(struct gnbd_device *dev, struct request *xreq) | |
486 | +{ | |
487 | + struct request *req; | |
488 | + struct list_head *tmp; | |
489 | + | |
490 | + list_for_each(tmp, &dev->queue_head) { | |
491 | + req = list_entry(tmp, struct request, queuelist); | |
492 | + if (req != xreq) | |
493 | + continue; | |
494 | + return 1; | |
495 | + } | |
496 | + return 0; | |
497 | +} | |
498 | + | |
499 | +static inline int sock_recv_bvec(struct socket *sock, struct bio_vec *bvec) | |
500 | +{ | |
501 | + int result; | |
502 | + void *kaddr = kmap(bvec->bv_page); | |
503 | + result = sock_xmit(sock, 0, kaddr + bvec->bv_offset, bvec->bv_len, | |
504 | + MSG_WAITALL); | |
505 | + kunmap(bvec->bv_page); | |
506 | + return result; | |
507 | +} | |
508 | + | |
509 | +int gnbd_recv_req(struct gnbd_device *dev, struct request *req) | |
510 | +{ | |
511 | + int result; | |
512 | + int i; | |
513 | + struct bio *bio; | |
514 | + rq_for_each_bio(bio, req) { | |
515 | + struct bio_vec *bvec; | |
516 | + bio_for_each_segment(bvec, bio, i) { | |
517 | + result = sock_recv_bvec(dev->sock, bvec); | |
518 | + if (result < 0) { | |
519 | + printk(KERN_ERR "%s: Receive data failed (result %d)\n", | |
520 | + dev->disk->disk_name, | |
521 | + result); | |
522 | + return result; | |
523 | + } | |
524 | + dprintk(DBG_RX, "%s: request %p: got %d bytes data\n", | |
525 | + dev->disk->disk_name, req, bvec->bv_len); | |
526 | + } | |
527 | + } | |
528 | + return 0; | |
529 | +} | |
530 | + | |
531 | +int gnbd_do_it(struct gnbd_device *dev) | |
532 | +{ | |
533 | + int result; | |
534 | + struct gnbd_reply reply; | |
535 | + struct request *req; | |
536 | + struct socket *sock = dev->sock; | |
537 | + | |
538 | + BUG_ON(dev->magic != GNBD_MAGIC); | |
539 | + | |
540 | + while((result = sock_xmit(sock, 0, &reply,sizeof(reply), MSG_WAITALL)) > 0){ | |
541 | + if (ntohl(reply.magic) == GNBD_KEEP_ALIVE_MAGIC) | |
542 | + /* FIXME -- I should reset the wait time here */ | |
543 | + continue; | |
544 | + | |
545 | + memcpy(&req, reply.handle, sizeof(req)); | |
546 | + if (req == &shutdown_req) | |
547 | + return 0; | |
548 | + | |
549 | + if (!gnbd_find_request(dev, req)){ | |
550 | + printk(KERN_ERR "%s: Unexpected reply (%p)\n", | |
551 | + dev->disk->disk_name, reply.handle); | |
552 | + return -EBADR; | |
553 | + } | |
554 | + if (ntohl(reply.magic) != GNBD_REPLY_MAGIC) { | |
555 | + printk(KERN_ERR "%s: Wrong magic (0x%lx)\n", | |
556 | + dev->disk->disk_name, | |
557 | + (unsigned long)ntohl(reply.magic)); | |
558 | + return -EPROTO; | |
559 | + } | |
560 | + if (ntohl(reply.error)) { | |
561 | + printk(KERN_ERR "%s: Other side returned error (%d)\n", | |
562 | + dev->disk->disk_name, ntohl(reply.error)); | |
563 | + req->errors++; | |
564 | + goto remove_req; | |
565 | + } | |
566 | + dprintk(DBG_RX, "%s: request %p: got reply\n", | |
567 | + dev->disk->disk_name, req); | |
568 | + | |
569 | + if (gnbd_cmd(req) == GNBD_CMD_READ){ | |
570 | + result = gnbd_recv_req(dev, req); | |
571 | + if (result < 0) | |
572 | + return result; | |
573 | + } | |
574 | +remove_req: | |
575 | + spin_lock(&dev->queue_lock); | |
576 | + list_del_init(&req->queuelist); | |
577 | + dev->last_received = jiffies; | |
578 | + spin_unlock(&dev->queue_lock); | |
579 | + if (req != &ping_req) | |
580 | + gnbd_end_request(req); | |
581 | + } | |
582 | + printk(KERN_ERR "%s: Receive control failed (result %d)\n", | |
583 | + dev->disk->disk_name, result); | |
584 | + return result; | |
585 | +} | |
586 | + | |
587 | +void gnbd_clear_que(struct gnbd_device *dev) | |
588 | +{ | |
589 | + struct request *req; | |
590 | + | |
591 | + BUG_ON(dev->magic != GNBD_MAGIC); | |
592 | + | |
593 | + do { | |
594 | + req = NULL; | |
595 | + if (!list_empty(&dev->queue_head)) { | |
596 | + req = list_entry(dev->queue_head.next, struct request, queuelist); | |
597 | + list_del_init(&req->queuelist); | |
598 | + } | |
599 | + if (req && req != &ping_req) { | |
600 | + req->errors++; | |
601 | + gnbd_end_request(req); | |
602 | + } | |
603 | + } while (req); | |
604 | +} | |
605 | + | |
606 | +/* | |
607 | + * We always wait for result of write, for now. It would be nice to make it optional | |
608 | + * in future | |
609 | + * if ((req->cmd == WRITE) && (dev->flags & GNBD_WRITE_NOCHK)) | |
610 | + * { printk( "Warning: Ignoring result!\n"); gnbd_end_request( req ); } | |
611 | + */ | |
612 | + | |
613 | +static void do_gnbd_request(request_queue_t * q) | |
614 | +{ | |
615 | + int err; | |
616 | + struct request *req; | |
617 | + | |
618 | + while ((req = elv_next_request(q)) != NULL) { | |
619 | + struct gnbd_device *dev; | |
620 | + | |
621 | + blkdev_dequeue_request(req); | |
622 | + dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%lx)\n", | |
623 | + req->rq_disk->disk_name, req, req->flags); | |
624 | + | |
625 | + if (!(req->flags & REQ_CMD)) | |
626 | + goto error_out; | |
627 | + | |
628 | + dev = req->rq_disk->private_data; | |
629 | + | |
630 | + if (dev->receiver_pid == -1) | |
631 | + goto error_out; | |
632 | + | |
633 | + BUG_ON(dev->magic != GNBD_MAGIC); | |
634 | + | |
635 | + gnbd_cmd(req) = GNBD_CMD_READ; | |
636 | + if (rq_data_dir(req) == WRITE) { | |
637 | + gnbd_cmd(req) = GNBD_CMD_WRITE; | |
638 | + if (dev->flags & GNBD_READ_ONLY) { | |
639 | + printk(KERN_ERR "%s: Write on read-only\n", | |
640 | + dev->disk->disk_name); | |
641 | + goto error_out; | |
642 | + } | |
643 | + } | |
644 | + | |
645 | + req->errors = 0; | |
646 | + spin_unlock_irq(q->queue_lock); | |
647 | + | |
648 | + spin_lock(&dev->queue_lock); | |
649 | + | |
650 | + if (list_empty(&dev->queue_head)) | |
651 | + dev->last_received = jiffies; | |
652 | + list_add(&req->queuelist, &dev->queue_head); | |
653 | + req->ref_count++; /* make sure req does not get freed */ | |
654 | + spin_unlock(&dev->queue_lock); | |
655 | + | |
656 | + err = gnbd_send_req(dev, req); | |
657 | + | |
658 | + spin_lock(&dev->queue_lock); | |
659 | + req->ref_count--; | |
660 | + spin_unlock(&dev->queue_lock); | |
661 | + spin_lock_irq(q->queue_lock); | |
662 | + if (err) | |
663 | + goto sock_error; | |
664 | + continue; | |
665 | + | |
666 | +error_out: | |
667 | + req->errors++; | |
668 | + spin_unlock(q->queue_lock); | |
669 | + gnbd_end_request(req); | |
670 | + spin_lock(q->queue_lock); | |
671 | + } | |
672 | + return; | |
673 | + | |
674 | +sock_error: | |
675 | + return; | |
676 | +} | |
677 | + | |
678 | +/* | |
679 | + * This is called before dev-sock is set, so you dodn't need | |
680 | + * to worry about the tx_lock or the queue_lock | |
681 | + */ | |
682 | +static int gnbd_resend_requests(struct gnbd_device *dev, struct socket *sock) | |
683 | +{ | |
684 | + int err = 0; | |
685 | + struct request *req; | |
686 | + struct list_head *tmp; | |
687 | + | |
688 | + printk("resending requests\n"); | |
689 | + list_for_each(tmp, &dev->queue_head) { | |
690 | + req = list_entry(tmp, struct request, queuelist); | |
691 | + err = __gnbd_send_req(dev, sock, req); | |
692 | + | |
693 | + if (err){ | |
694 | + printk("failed trying to resend request (%d)\n", err); | |
695 | + break; | |
696 | + } | |
697 | + } | |
698 | + | |
699 | + return err; | |
700 | +} | |
701 | +/* | |
702 | +static int get_server_info(struct gnbd_device *dev, struct socket *sock) | |
703 | +{ | |
704 | + struct sockaddr_in server; | |
705 | + int len; | |
706 | + int err; | |
707 | + | |
708 | + err = sock->ops->getname(sock, (struct sockaddr *) &server, &len, 1); | |
709 | + if (err) { | |
710 | + printk(KERN_WARNING "cannot get socket info, shutting down\n"); | |
711 | + } else{ | |
712 | + dev->server_addr = server.sin_addr; | |
713 | + dev->server_port = server.sin_port; | |
714 | + } | |
715 | + return err; | |
716 | +} | |
717 | +*/ | |
718 | + | |
719 | +static int gnbd_ctl_ioctl(struct inode *inode, struct file *file, | |
720 | + unsigned int cmd, unsigned long arg) | |
721 | +{ | |
722 | + struct gnbd_device *dev = NULL; | |
723 | + struct block_device *bdev; | |
724 | + do_it_req_t req; | |
725 | + int error; | |
726 | + | |
727 | + if (!capable(CAP_SYS_ADMIN)) | |
728 | + return -EPERM; | |
729 | + | |
730 | + if (cmd == GNBD_DISCONNECT || cmd == GNBD_CLEAR_QUE || | |
731 | + cmd == GNBD_PING || cmd == GNBD_PRINT_DEBUG) { | |
732 | + if (arg >= MAX_GNBD) | |
733 | + return -EINVAL; | |
734 | + dev = &gnbd_dev[arg]; | |
735 | + BUG_ON(dev->magic != GNBD_MAGIC); | |
736 | + } | |
737 | + | |
738 | + /* Anyone capable of this syscall can do *real bad* things */ | |
739 | + dprintk(DBG_IOCTL, "%s: gnbd_ioctl cmd=%s(0x%x) arg=%lu\n", | |
740 | + dev->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg); | |
741 | + | |
742 | + switch (cmd) { | |
743 | + case GNBD_DISCONNECT: | |
744 | + printk(KERN_INFO "%s: GNBD_DISCONNECT\n", dev->disk->disk_name); | |
745 | + spin_lock(&dev->open_lock); | |
746 | + if (dev->open_count > 0){ | |
747 | + spin_unlock(&dev->open_lock); | |
748 | + return -EBUSY; | |
749 | + } | |
750 | + dev->receiver_pid = -1; | |
751 | + spin_unlock(&dev->open_lock); | |
752 | + /* There is no one using the device, you can disconnect it */ | |
753 | + if (dev->sock == NULL) | |
754 | + return -ENOTCONN; | |
755 | + gnbd_send_req(dev, &shutdown_req); | |
756 | + return 0; | |
757 | + case GNBD_CLEAR_QUE: | |
758 | + if (down_interruptible(&dev->do_it_lock)) | |
759 | + return -EBUSY; | |
760 | + dev->receiver_pid = -1; | |
761 | + gnbd_clear_que(dev); | |
762 | + bdev = dev->bdev; | |
763 | + if (bdev) { | |
764 | + blk_run_queue(dev->disk->queue); | |
765 | + fsync_bdev(bdev); | |
766 | + invalidate_bdev(bdev, 0); | |
767 | + } | |
768 | + up(&dev->do_it_lock); | |
769 | + return 0; | |
770 | + case GNBD_DO_IT: | |
771 | + if (copy_from_user(&req, (do_it_req_t *)arg, sizeof(req))) | |
772 | + return -EFAULT; | |
773 | + if (req.minor >= 128) | |
774 | + return -EINVAL; | |
775 | + dev = &gnbd_dev[req.minor]; | |
776 | + BUG_ON(dev->magic != GNBD_MAGIC); | |
777 | + if (dev->file) | |
778 | + return -EBUSY; | |
779 | + error = -EINVAL; | |
780 | + file = fget(req.sock_fd); | |
781 | + if (!file) | |
782 | + return error; | |
783 | + inode = file->f_dentry->d_inode; | |
784 | + if (!inode->i_sock) { | |
785 | + fput(file); | |
786 | + return error; | |
787 | + } | |
788 | + if (down_trylock(&dev->do_it_lock)){ | |
789 | + fput(file); | |
790 | + return -EBUSY; | |
791 | + } | |
792 | + /* FIXME -- Why do this? I connected with the | |
793 | + server. I know what these values are */ | |
794 | + /* | |
795 | + error = get_server_info(dev, SOCKET_I(inode)); | |
796 | + if (error){ | |
797 | + fput(file); | |
798 | + return error; | |
799 | + } | |
800 | + */ | |
801 | + error = gnbd_resend_requests(dev, SOCKET_I(inode)); | |
802 | + if (error){ | |
803 | + printk("quitting NBD_DO_IT\n"); | |
804 | + up(&dev->do_it_lock); | |
805 | + fput(file); | |
806 | + return error; | |
807 | + } | |
808 | + dev->file = file; | |
809 | + dev->sock = SOCKET_I(inode); | |
810 | + dev->receiver_pid = current->pid; | |
811 | + blk_run_queue(dev->disk->queue); | |
812 | + error = gnbd_do_it(dev); | |
813 | + /* should I kill the socket first */ | |
814 | + up(&dev->do_it_lock); | |
815 | + down(&dev->tx_lock); | |
816 | + if (dev->sock) { | |
817 | + printk(KERN_WARNING "%s: shutting down socket\n", | |
818 | + dev->disk->disk_name); | |
819 | + dev->sock->ops->shutdown(dev->sock, | |
820 | + SEND_SHUTDOWN|RCV_SHUTDOWN); | |
821 | + dev->sock = NULL; | |
822 | + } | |
823 | + up(&dev->tx_lock); | |
824 | + file = dev->file; | |
825 | + dev->file = NULL; | |
826 | + if (file) | |
827 | + fput(file); | |
828 | + printk("exitting GNBD_DO_IT ioctl\n"); | |
829 | + return error; | |
830 | + case GNBD_PING: | |
831 | + /* FIXME -- should I allow pings if everything is compeletely | |
832 | + * shutdown */ | |
833 | + spin_lock(&dev->queue_lock); | |
834 | + /* only one outstanding ping at a time */ | |
835 | + if (list_empty(&ping_req.queuelist)){ | |
836 | + if (list_empty(&dev->queue_head)) | |
837 | + dev->last_received = jiffies; | |
838 | + list_add(&ping_req.queuelist, &dev->queue_head); | |
839 | + } | |
840 | + spin_unlock(&dev->queue_lock); | |
841 | + gnbd_send_req(dev, &ping_req); /* ignore the errors */ | |
842 | + return 0; | |
843 | + case GNBD_PRINT_DEBUG: | |
844 | + printk(KERN_INFO "%s: next = %p, prev = %p, head = %p\n", | |
845 | + dev->disk->disk_name, | |
846 | + dev->queue_head.next, dev->queue_head.prev, | |
847 | + &dev->queue_head); | |
848 | + return 0; | |
849 | + case GNBD_GET_TIME: | |
850 | + if (copy_to_user((void *)arg, &insmod_time, sizeof(uint64_t))){ | |
851 | + printk(KERN_WARNING "couldn't compy time argument to user\n"); | |
852 | + return -EFAULT; | |
853 | + } | |
854 | + return 0; | |
855 | + } | |
856 | + /* FIXME -- should I print something, is EINVAL the right error */ | |
857 | + return -EINVAL; | |
858 | +} | |
859 | + | |
860 | +static int gnbd_open(struct inode *inode, struct file *file) | |
861 | +{ | |
862 | + struct gnbd_device *dev = inode->i_bdev->bd_disk->private_data; | |
863 | + spin_lock(&dev->open_lock); | |
864 | + if (dev->receiver_pid == -1){ | |
865 | + spin_unlock(&dev->open_lock); | |
866 | + return -ENXIO; | |
867 | + } | |
868 | + spin_unlock(&dev->open_lock); | |
869 | + if ((file->f_mode & FMODE_WRITE) && (dev->flags & GNBD_READ_ONLY)){ | |
870 | + printk(KERN_INFO "cannot open read only gnbd device read/write"); | |
871 | + return -EROFS; | |
872 | + } | |
873 | + | |
874 | + dev->open_count++; | |
875 | + dev->bdev = inode->i_bdev; | |
876 | + return 0; | |
877 | +} | |
878 | + | |
879 | +/* FIXME -- I don't sync the device at close. This means that If you write | |
880 | + * something, and close the device, and expect that then it is written, | |
881 | + * you are wrong.... This might cause problems */ | |
882 | +static int gnbd_release(struct inode *inode, struct file *file) | |
883 | +{ | |
884 | + struct gnbd_device *dev = inode->i_bdev->bd_disk->private_data; | |
885 | + | |
886 | + dev->open_count--; | |
887 | + if (dev->open_count == 0) | |
888 | + dev->bdev = NULL; | |
889 | + return 0; | |
890 | +} | |
891 | + | |
892 | +static struct file_operations _gnbd_ctl_fops = | |
893 | +{ | |
894 | + .ioctl = gnbd_ctl_ioctl, | |
895 | + .owner = THIS_MODULE, | |
896 | +}; | |
897 | + | |
898 | +static struct miscdevice _gnbd_misc = | |
899 | +{ | |
900 | + .minor = MISC_DYNAMIC_MINOR, | |
901 | + .name = "gnbd_ctl", | |
902 | + .devfs_name = "gnbd_ctl", | |
903 | + .fops = &_gnbd_ctl_fops | |
904 | +}; | |
905 | + | |
906 | +/* FIXME -- I should probably do more here */ | |
907 | +int __init gnbd_ctl_init(void) | |
908 | +{ | |
909 | + int err; | |
910 | + | |
911 | + err = misc_register(&_gnbd_misc); | |
912 | + if (err) { | |
913 | + printk("cannot register control device\n"); | |
914 | + return err; | |
915 | + } | |
916 | + return 0; | |
917 | +} | |
918 | + | |
919 | +void gnbd_ctl_cleanup(void) | |
920 | +{ | |
921 | + if (misc_deregister(&_gnbd_misc) < 0) | |
922 | + printk("cannot deregister control device\n"); | |
923 | +} | |
924 | + | |
925 | +static struct block_device_operations gnbd_fops = | |
926 | +{ | |
927 | + .open = gnbd_open, | |
928 | + .release = gnbd_release, | |
929 | + .owner = THIS_MODULE, | |
930 | +}; | |
931 | + | |
932 | +/* | |
933 | + * And here should be modules and kernel interface | |
934 | + * (Just smiley confuses emacs :-) | |
935 | + */ | |
936 | + | |
937 | +static int __init gnbd_init(void) | |
938 | +{ | |
939 | + int err = -ENOMEM; | |
940 | + struct timeval tv; | |
941 | + int i; | |
942 | + | |
943 | + if (sizeof(struct gnbd_request) != 28) { | |
944 | + printk(KERN_CRIT "gnbd: sizeof gnbd_request needs to be 28 in order to work!\n" ); | |
945 | + return -EIO; | |
946 | + } | |
947 | + shutdown_req.flags = REQ_SPECIAL; | |
948 | + gnbd_cmd(&shutdown_req) = GNBD_CMD_DISC; | |
949 | + shutdown_req.sector = 0; | |
950 | + shutdown_req.nr_sectors = 0; | |
951 | + | |
952 | + ping_req.flags = REQ_SPECIAL; | |
953 | + gnbd_cmd(&ping_req) = GNBD_CMD_PING; | |
954 | + ping_req.sector = 0; | |
955 | + ping_req.nr_sectors = 0; | |
956 | + | |
957 | + for (i = 0; i < MAX_GNBD; i++) { | |
958 | + struct gendisk *disk = alloc_disk(1); | |
959 | + if (!disk) | |
960 | + goto out; | |
961 | + gnbd_dev[i].disk = disk; | |
962 | + /* | |
963 | + * The new linux 2.5 block layer implementation requires | |
964 | + * every gendisk to have its very own request_queue struct. | |
965 | + * These structs are big so we dynamically allocate them. | |
966 | + */ | |
967 | + disk->queue = blk_init_queue(do_gnbd_request, &gnbd_lock); | |
968 | + if (!disk->queue) { | |
969 | + put_disk(disk); | |
970 | + goto out; | |
971 | + } | |
972 | + } | |
973 | + major_nr = register_blkdev(major_nr, "gnbd"); | |
974 | + if (major_nr < 0) { | |
975 | + printk("gnbd: unable to get a major number\n"); | |
976 | + err = major_nr; | |
977 | + goto out; | |
978 | + } | |
979 | + | |
980 | + printk(KERN_INFO "gnbd: registered device at major %d\n", major_nr); | |
981 | + dprintk(DBG_INIT, "gnbd: debugflags=0x%x\n", debugflags); | |
982 | + | |
5cdbd17b | 983 | + devfs_mk_dir("gnbd_minor"); |
4bf12011 | 984 | + err = class_register(&gnbd_class); |
985 | + if (err) | |
986 | + goto out_unregister; | |
987 | + for (i = 0; i < MAX_GNBD; i++) { | |
988 | + struct gendisk *disk = gnbd_dev[i].disk; | |
989 | + gnbd_dev[i].file = NULL; | |
990 | + gnbd_dev[i].magic = GNBD_MAGIC; | |
991 | + gnbd_dev[i].flags = 0; | |
992 | + gnbd_dev[i].open_count = 0; | |
993 | + gnbd_dev[i].receiver_pid = -1; | |
5cdbd17b | 994 | + gnbd_dev[i].server_name = NULL; |
4bf12011 | 995 | + gnbd_dev[i].server_port = 0; |
996 | + gnbd_dev[i].name[0] = '\0'; | |
997 | + gnbd_dev[i].bdev = NULL; | |
998 | + spin_lock_init(&gnbd_dev[i].queue_lock); | |
999 | + spin_lock_init(&gnbd_dev[i].open_lock); | |
1000 | + INIT_LIST_HEAD(&gnbd_dev[i].queue_head); | |
1001 | + init_MUTEX(&gnbd_dev[i].tx_lock); | |
1002 | + init_MUTEX(&gnbd_dev[i].do_it_lock); | |
1003 | + gnbd_dev[i].class_dev.class = &gnbd_class; | |
1004 | + sprintf(gnbd_dev[i].class_dev.class_id, "gnbd%d", i); | |
1005 | + err = class_device_register(&gnbd_dev[i].class_dev); | |
1006 | + if (err){ | |
1007 | + printk("class_device_register failed with %d\n", err); | |
1008 | + goto out_unregister_class; | |
1009 | + } | |
1010 | + if(class_device_create_file(&gnbd_dev[i].class_dev, | |
1011 | + &class_device_attr_pid)) | |
1012 | + goto out_remove_file; | |
1013 | + if(class_device_create_file(&gnbd_dev[i].class_dev, | |
1014 | + &class_device_attr_server)) | |
1015 | + goto out_remove_file; | |
1016 | + if(class_device_create_file(&gnbd_dev[i].class_dev, | |
1017 | + &class_device_attr_name)) | |
1018 | + goto out_remove_file; | |
1019 | + if(class_device_create_file(&gnbd_dev[i].class_dev, | |
1020 | + &class_device_attr_sectors)) | |
1021 | + goto out_remove_file; | |
1022 | + if(class_device_create_file(&gnbd_dev[i].class_dev, | |
1023 | + &class_device_attr_usage)) | |
1024 | + goto out_remove_file; | |
1025 | + if(class_device_create_file(&gnbd_dev[i].class_dev, | |
1026 | + &class_device_attr_flags)) | |
1027 | + goto out_remove_file; | |
1028 | + if(class_device_create_file(&gnbd_dev[i].class_dev, | |
1029 | + &class_device_attr_waittime)) | |
1030 | + goto out_remove_file; | |
1031 | + if(class_device_create_file(&gnbd_dev[i].class_dev, | |
1032 | + &class_device_attr_connected)) | |
1033 | + goto out_remove_file; | |
1034 | + disk->major = major_nr; | |
1035 | + disk->first_minor = i; | |
1036 | + disk->fops = &gnbd_fops; | |
1037 | + disk->private_data = &gnbd_dev[i]; | |
1038 | + sprintf(disk->disk_name, "gnbd%d", i); | |
5cdbd17b | 1039 | + sprintf(disk->devfs_name, "gnbd_minor/%d", i); |
4bf12011 | 1040 | + set_capacity(disk, 0); |
1041 | + add_disk(disk); | |
1042 | + if(sysfs_create_link(&gnbd_dev[i].class_dev.kobj, | |
1043 | + &gnbd_dev[i].disk->kobj, "block")) | |
1044 | + goto out_remove_disk; | |
1045 | + | |
1046 | + } | |
1047 | + | |
1048 | + err = gnbd_ctl_init(); | |
1049 | + if (err) | |
1050 | + goto out_unregister_class; | |
1051 | + | |
1052 | + insmod_time = (uint64_t) tv.tv_sec * 1000000 + tv.tv_usec; | |
1053 | + | |
1054 | + return 0; | |
1055 | +out_remove_disk: | |
1056 | + del_gendisk(gnbd_dev[i].disk); | |
1057 | +out_remove_file: | |
1058 | + class_device_unregister(&gnbd_dev[i].class_dev); | |
1059 | +out_unregister_class: | |
1060 | + while(i--){ | |
1061 | + del_gendisk(gnbd_dev[i].disk); | |
1062 | + class_device_unregister(&gnbd_dev[i].class_dev); | |
1063 | + } | |
1064 | + i = MAX_GNBD; | |
1065 | + class_unregister(&gnbd_class); | |
1066 | +out_unregister: | |
1067 | + unregister_blkdev(major_nr, "gnbd"); | |
1068 | +out: | |
1069 | + while (i--) { | |
1070 | + blk_cleanup_queue(gnbd_dev[i].disk->queue); | |
1071 | + put_disk(gnbd_dev[i].disk); | |
1072 | + } | |
1073 | + return err; | |
1074 | +} | |
1075 | + | |
1076 | +static void __exit gnbd_cleanup(void) | |
1077 | +{ | |
1078 | + int i; | |
1079 | + | |
1080 | + gnbd_ctl_cleanup(); | |
1081 | + for (i = 0; i < MAX_GNBD; i++) { | |
1082 | + struct gendisk *disk = gnbd_dev[i].disk; | |
1083 | + if (disk) { | |
1084 | + del_gendisk(disk); | |
1085 | + blk_cleanup_queue(disk->queue); | |
1086 | + put_disk(disk); | |
1087 | + } | |
5cdbd17b AM |
1088 | + if (gnbd_dev[i].server_name) |
1089 | + kfree(gnbd_dev[i].server_name); | |
4bf12011 | 1090 | + } |
1091 | + class_unregister(&gnbd_class); | |
1092 | + devfs_remove("gnbd"); | |
1093 | + unregister_blkdev(major_nr, "gnbd"); | |
1094 | + printk(KERN_INFO "gnbd: unregistered device at major %d\n", major_nr); | |
1095 | +} | |
1096 | + | |
1097 | +module_init(gnbd_init); | |
1098 | +module_exit(gnbd_cleanup); | |
1099 | + | |
1100 | +MODULE_DESCRIPTION("Network Block Device"); | |
1101 | +MODULE_LICENSE("GPL"); | |
1102 | + | |
1103 | +#ifndef NDEBUG | |
1104 | +MODULE_PARM(debugflags, "i"); | |
1105 | +MODULE_PARM_DESC(debugflags, "flags for controlling debug output"); | |
1106 | +#endif | |
1107 | diff -urN linux-orig/include/linux/gnbd.h linux-patched/include/linux/gnbd.h | |
1108 | --- linux-orig/include/linux/gnbd.h 1969-12-31 18:00:00.000000000 -0600 | |
5cdbd17b | 1109 | +++ linux-patched/include/linux/gnbd.h 2004-06-30 16:48:06.000000000 -0500 |
4bf12011 | 1110 | @@ -0,0 +1,103 @@ |
1111 | +/****************************************************************************** | |
1112 | +******************************************************************************* | |
1113 | +** | |
1114 | +** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | |
1115 | +** Copyright (C) 2004 Red Hat, Inc. All rights reserved. | |
1116 | +** | |
1117 | +** This copyrighted material is made available to anyone wishing to use, | |
1118 | +** modify, copy, or redistribute it subject to the terms and conditions | |
1119 | +** of the GNU General Public License v.2. | |
1120 | +** | |
1121 | +******************************************************************************* | |
1122 | +******************************************************************************/ | |
1123 | + | |
1124 | +#ifndef LINUX_GNBD_H | |
1125 | +#define LINUX_GNBD_H | |
1126 | + | |
1127 | +#define GNBD_DO_IT _IO( 0xab, 0x20 ) | |
1128 | +#define GNBD_CLEAR_QUE _IO( 0xab, 0x21 ) | |
1129 | +#define GNBD_PRINT_DEBUG _IO( 0xab, 0x22 ) | |
1130 | +#define GNBD_DISCONNECT _IO( 0xab, 0x23 ) | |
1131 | +#define GNBD_PING _IO( 0xab, 0x24 ) | |
1132 | +#define GNBD_GET_TIME _IO( 0xab, 0x25 ) | |
1133 | + | |
1134 | +enum { | |
1135 | + GNBD_CMD_READ = 0, | |
1136 | + GNBD_CMD_WRITE = 1, | |
1137 | + GNBD_CMD_DISC = 2, | |
1138 | + GNBD_CMD_PING = 3 | |
1139 | +}; | |
1140 | + | |
1141 | +#define gnbd_cmd(req) ((req)->cmd[0]) | |
1142 | +#define MAX_GNBD 128 | |
1143 | + | |
1144 | +/* values for flags field */ | |
1145 | +#define GNBD_READ_ONLY 0x0001 | |
1146 | + | |
1147 | +/* userspace doesn't need the gnbd_device structure */ | |
1148 | +#ifdef __KERNEL__ | |
1149 | + | |
1150 | +struct gnbd_device { | |
1151 | + unsigned short int flags; | |
1152 | + struct socket * sock; | |
1153 | + struct file * file; /* If == NULL, device is not ready, yet */ | |
1154 | + int magic; | |
1155 | + spinlock_t queue_lock; | |
1156 | + spinlock_t open_lock; | |
1157 | + struct list_head queue_head;/* Requests are added here... */ | |
1158 | + struct semaphore tx_lock; | |
1159 | + struct gendisk *disk; | |
1160 | + pid_t receiver_pid; | |
1161 | + struct semaphore do_it_lock; | |
1162 | + int open_count; | |
1163 | + struct class_device class_dev; | |
1164 | + unsigned short int server_port; | |
5cdbd17b | 1165 | + char *server_name; |
4bf12011 | 1166 | + char name[32]; |
1167 | + unsigned long last_received; | |
1168 | + struct block_device *bdev; | |
1169 | +}; | |
1170 | + | |
1171 | +#endif /* __KERNEL__ */ | |
1172 | + | |
1173 | +/* These are sent over the network in the request/reply magic fields */ | |
1174 | + | |
1175 | +#define GNBD_REQUEST_MAGIC 0x37a07e00 | |
1176 | +#define GNBD_REPLY_MAGIC 0x41f09370 | |
1177 | +#define GNBD_KEEP_ALIVE_MAGIC 0x5B46D8C2 | |
1178 | +/* Do *not* use magics: 0x12560953 0x96744668. */ | |
1179 | + | |
1180 | +/* | |
1181 | + * This is the packet used for communication between client and | |
1182 | + * server. All data are in network byte order. | |
1183 | + */ | |
1184 | +struct gnbd_request { | |
1185 | + uint32_t magic; | |
1186 | + uint32_t type; /* == READ || == WRITE why so long */ | |
1187 | + char handle[8]; /* why is this a char array instead of a u64 */ | |
1188 | + uint64_t from; | |
1189 | + uint32_t len; | |
1190 | +} | |
1191 | +#ifdef __GNUC__ | |
1192 | + __attribute__ ((packed)) | |
1193 | +#endif /* __GNUC__ */ | |
1194 | +; | |
1195 | + | |
1196 | +/* | |
1197 | + * This is the reply packet that gnbd-server sends back to the client after | |
1198 | + * it has completed an I/O request (or an error occurs). | |
1199 | + */ | |
1200 | +#define SIZE_OF_REPLY 16 | |
1201 | +struct gnbd_reply { | |
1202 | + uint32_t magic; | |
1203 | + uint32_t error; /* 0 = ok, else error */ | |
1204 | + char handle[8]; /* handle you got from request */ | |
1205 | +}; | |
1206 | + | |
1207 | +struct do_it_req_s { | |
1208 | + unsigned int minor; | |
1209 | + int sock_fd; | |
1210 | +}; | |
1211 | +typedef struct do_it_req_s do_it_req_t; | |
1212 | + | |
1213 | +#endif /* LINUX_GNBD_H */ |