]> git.pld-linux.org Git - packages/kernel.git/blob - linux-cluster-gnbd.patch
- moving config-* fixed.
[packages/kernel.git] / linux-cluster-gnbd.patch
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
29 +++ linux-patched/drivers/block/gnbd.c  2004-06-30 16:48:06.000000000 -0500
30 @@ -0,0 +1,1076 @@
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);
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");
128 +}
129 +
130 +/* FIXME -- should a empty store free the memory */
131 +static ssize_t store_server(struct class_device *class_dev,
132 +               const char *buf, size_t count)
133 +{
134 +       int res;
135 +       short unsigned int port;
136 +       char *ptr;
137 +       struct gnbd_device *dev = to_gnbd_dev(class_dev);
138 +       if (down_trylock(&dev->do_it_lock))
139 +               return -EBUSY;
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){
153 +               up(&dev->do_it_lock);
154 +               return -EINVAL;
155 +       }
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(&current->sighand->siglock, flags);
349 +       oldset = current->blocked;
350 +       sigfillset(&current->blocked);
351 +       sigdelsetmask(&current->blocked, sigmask(SIGKILL));
352 +       recalc_sigpending();
353 +       spin_unlock_irqrestore(&current->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(&current->sighand->siglock, flags);
376 +                       printk(KERN_WARNING "gnbd (pid %d: %s) got signal %d\n",
377 +                               current->pid, current->comm, 
378 +                               dequeue_signal(current, &current->blocked, &info));
379 +                       spin_unlock_irqrestore(&current->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(&current->sighand->siglock, flags);
394 +       current->blocked = oldset;
395 +       recalc_sigpending();
396 +       spin_unlock_irqrestore(&current->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 +
983 +       devfs_mk_dir("gnbd_minor");
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;
994 +               gnbd_dev[i].server_name = NULL;
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);
1039 +               sprintf(disk->devfs_name, "gnbd_minor/%d", i);
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 +               }
1088 +               if (gnbd_dev[i].server_name)
1089 +                       kfree(gnbd_dev[i].server_name);
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
1109 +++ linux-patched/include/linux/gnbd.h  2004-06-30 16:48:06.000000000 -0500
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;
1165 +       char *server_name;
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 */
This page took 0.116475 seconds and 3 git commands to generate.