]> git.pld-linux.org Git - packages/kernel.git/blame - nwd-1.4-pre.common.patch
- obsolete
[packages/kernel.git] / nwd-1.4-pre.common.patch
CommitLineData
dd19de18 1diff -Nur linux.orig/drivers/block/nwd/Makefile linux/drivers/block/nwd/Makefile
2--- linux.orig/drivers/block/nwd/Makefile Thu Jan 1 01:00:00 1970
3+++ linux/drivers/block/nwd/Makefile Mon Sep 3 21:04:07 2001
4@@ -0,0 +1,17 @@
5+#
6+# Makefile for the Network disk client driver (NWD)
7+#
8+# Note 1! Dependencies are done automagically by 'make dep', which also
9+# removes any old dependencies. DON'T put your own dependencies here
10+# unless it's something special (ie not a .c file).
11+#
12+# Note 2! The CFLAGS definitions are now in the main makefile...
13+#
14+#
15+
16+O_TARGET := nwd.o
17+
18+obj-y += nwd_clt.o nwd_xdr.o
19+obj-$(CONFIG_BLK_DEV_NWD) += $(O_TARGET)
20+
21+include $(TOPDIR)/Rules.make
22diff -Nur linux.orig/drivers/block/nwd/nwd_clt.c linux/drivers/block/nwd/nwd_clt.c
23--- linux.orig/drivers/block/nwd/nwd_clt.c Thu Jan 1 01:00:00 1970
24+++ linux/drivers/block/nwd/nwd_clt.c Fri Sep 14 10:51:32 2001
25@@ -0,0 +1,1034 @@
26+/*
27+ * Network disk client
28+ * Kernel block device driver
29+ *
30+ * Copyright (c) 1996 Petr Salinger
31+ * Copyright (c) 1999 Libor Bus <l.bus@sh.cvut.cz>
32+ * Copyright (c) 2001 Lubomir Bulej <pallas@kadan.cz>
33+ *
34+ *
35+ * This program is free software; you can redistribute it and/or modify
36+ * it under the terms of the GNU General Public License as published by
37+ * the Free Software Foundation; either version 2 of the License, or
38+ * (at your option) any later version.
39+ *
40+ * This program is distributed in the hope that it will be useful,
41+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
42+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43+ * GNU General Public License for more details.
44+ *
45+ * You should have received a copy of the GNU General Public License
46+ * along with this program; if not, write to the Free Software
47+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
48+ *
49+ */
50+
51+
52+#include <linux/kernel.h>
53+#include <linux/module.h>
54+#include <linux/errno.h>
55+
56+#include <linux/net.h> /* struct net_proto for inet.h */
57+#include <linux/inet.h> /* in_aton, in_ntoa */
58+
59+#include <linux/init.h> /* __init, __exit and stuff */
60+#include <linux/slab.h> /* kmalloc, kfree */
61+#include <linux/reboot.h> /* register_reboot_notifier */
62+#include <linux/devfs_fs_kernel.h> /* devfs_register/unregister */
63+
64+#include <linux/sunrpc/clnt.h> /* rpc_call, xprt stuff, etc. */
65+
66+#include <asm/uaccess.h> /* verify_area, get/put_user */
67+
68+#define MAJOR_NR NWD_MAJOR /* required for blk.h */
69+#include <linux/blk.h> /* block device macros */
70+#include <linux/blkpg.h> /* blk_ioctl */
71+
72+#include <linux/nwd.h>
73+#include "nwd_xdr.h"
74+#include "nwd_dbg.h"
75+
76+
77+/*****************************************************************************\
78+| PRIVATE GLOBALS |
79+\*****************************************************************************/
80+
81+static int * nwd_sizes; /* block device sizes in KiB */
82+static int * nwd_blksizes; /* device block/sector sizes */
83+
84+static int nwd_maxdevs = NWD_MAX_DEVICES; /* max number of devices */
85+static nwd_device_t * nwd_devices; /* device structures */
86+static struct semaphore nwd_mxdev; /* whole device structure mutex */
87+
88+static devfs_handle_t devfs_handle; /* devfs directory handle */
89+
90+
91+/*****************************************************************************\
92+| DEVICE OPERATIONS |
93+\*****************************************************************************/
94+
95+static
96+int nwd_disconnect (nwd_device_t * device)
97+{
98+ if (device->client == NULL)
99+ return 0;
100+ if (rpc_shutdown_client (device->client) != 0)
101+ eprintk ("unable to shutdown RPC client for device %d\n", device->devnum);
102+
103+ /* disconnected device must have device->client == NULL */
104+ nwd_sizes [device->devnum] = 0;
105+ device->client = NULL;
106+ return 0;
107+} /* nwd_disconnect */
108+
109+
110+static
111+int nwd_connect_opt (nwd_device_t * device, int ver, int proto)
112+{
113+ int error;
114+ char * pname;
115+ struct rpc_xprt * p_xprt;
116+ nwd_lookupres lookup_res;
117+
118+ /* refuse to connect on already connected device */
119+ if (device->client != NULL)
120+ return -EISCONN;
121+
122+
123+ /* make string with server name */
124+ memset (device->sname, 0, NWD_MAX_SNLEN);
125+ strncpy (device->sname, in_ntoa (device->server.saddr.sin_addr.s_addr), NWD_MAX_SNLEN);
126+ pname = (proto == IPPROTO_TCP) ? "TCP" : "UDP";
127+
128+
129+ /* create protocol */
130+ p_xprt = xprt_create_proto (proto, & device->server.saddr, NULL);
131+ if (p_xprt == NULL) {
132+ eprintk ("could not create RPC/%s transport\n", pname);
133+ return -EACCES;
134+ }
135+
136+
137+ /* create client & set options */
138+ device->client = rpc_create_client (p_xprt, device->sname, & nwd_program, ver, RPC_AUTH_NULL);
139+ if (device->client == NULL) {
140+ xprt_destroy (p_xprt);
141+ eprintk ("could not create RPC client\n");
142+ return -EACCES;
143+ }
144+
145+ device->client->cl_intr = 1;
146+ device->client->cl_chatty = 0;
147+ device->client->cl_autobind = 1;
148+ device->client->cl_softrtry = 1;
149+
150+
151+ /* lookup file id on server & fill in device size in blocks */
152+ error = rpc_call (device->client, NWDPROC_LOOKUP, & device->server.devid, & lookup_res, 0);
153+ if (error < 0) {
154+ nwd_disconnect (device);
155+ eprintk ("lookup failed on device %d: version %d, proto %s, devid %d, error %d\n",
156+ device->devnum, ver, pname, device->server.devid, abs (error));
157+ return error;
158+ }
159+
160+ nwd_sizes [device->devnum] = lookup_res.size >> BLOCK_SIZE_BITS;
161+ device->remid = lookup_res.file;
162+
163+ iprintk ("lookup successful on device %d: version %d, proto %s, remid %d, blocks %d\n",
164+ device->devnum, ver, pname, device->remid, nwd_sizes [device->devnum]);
165+ return 0;
166+} /* nwd_connect_opt */
167+
168+
169+static
170+int nwd_connect (nwd_device_t * device)
171+{
172+ int error;
173+ int proto = IPPROTO_UDP;
174+
175+ /*
176+ * Try to connect using NWD protocol version 2 first.
177+ * If that fails, fall back to version 1.
178+ */
179+ proto = (device->options & NWD_OPT_PROTO_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
180+ error = nwd_connect_opt (device, NWD_VERSION_2, proto);
181+ if (error == 0)
182+ return 0;
183+
184+ return nwd_connect_opt (device, NWD_VERSION_1, proto);
185+} /* nwd_connect */
186+
187+
188+static
189+int nwd_dispose (nwd_device_t * device)
190+{
191+ nwd_res result;
192+ if (device->client == NULL)
193+ return -ENOTCONN;
194+
195+ return rpc_call (device->client, NWDPROC_DISPOSE, & device->remid, & result, 0);
196+} /* nwd_dispose */
197+
198+
199+static
200+int nwd_sync (nwd_device_t * device)
201+{
202+ nwd_res result;
203+ if (device->client == NULL)
204+ return -ENOTCONN;
205+ if (device->client->cl_vers < 2)
206+ return 0;
207+
208+ return rpc_call (device->client, NWDPROC_SYNC, & device->remid, & result, 0);
209+} /* nwd_sync */
210+
211+
212+/*****************************************************************************\
213+| REQUEST PROCESSING |
214+\*****************************************************************************/
215+
216+static inline
217+int nwd_devnum (kdev_t kdev)
218+{
219+ int devnum = DEVICE_NR (kdev);
220+ if (devnum >= nwd_maxdevs) {
221+ static int limit = 0;
222+ if (limit++ < 5)
223+ wprintk ("invalid device number (%d)", devnum);
224+
225+ return -1;
226+ }
227+
228+ return devnum;
229+} /* nwd_devnum */
230+
231+
232+static
233+request_queue_t * nwd_find_queue (kdev_t kdev)
234+{
235+ int devnum = nwd_devnum (kdev);
236+ if (devnum == -1)
237+ return NULL;
238+
239+ return & nwd_devices [devnum].queue;
240+} /* nwd_find_queue */
241+
242+
243+static inline
244+nwd_device_t * nwd_find_device (kdev_t kdev)
245+{
246+ int devnum = nwd_devnum (kdev);
247+ if (devnum == -1)
248+ return NULL;
249+
250+ return nwd_devices + devnum;
251+} /* nwd_find_device */
252+
253+
254+static inline
255+int nwd_transfer (nwd_device_t * device, const struct request * req)
256+{
257+ u32 dgmlen; /* datagram length in bytes */
258+ u32 reqlen; /* request length in bytes */
259+ u64 offset; /* request offset in bytes */
260+ char * buffer;
261+
262+ /* request attributes */
263+ reqlen = req->current_nr_sectors << NWD_SEC_BITS;
264+ offset = (u64) req->sector << NWD_SEC_BITS;
265+ buffer = req->buffer;
266+
267+
268+ /*
269+ * Split the request into chunks/datagrams handled by individual
270+ * calls. For the request to be successful, all remote calls must
271+ * return without errors.
272+ */
273+ dgmlen = NWD_MAX_DGLEN;
274+ while (reqlen > 0) {
275+ int result; /* remote call result */
276+ int retries; /* call retry counter */
277+ nwd_res res; /* write result */
278+ nwd_rwargs args; /* R/W arguments */
279+ nwd_readres rdres; /* read result */
280+
281+ if (reqlen < dgmlen)
282+ dgmlen = reqlen;
283+
284+ /* remote call arguments */
285+ args.file = device->remid;
286+ args.offset = offset;
287+ args.count = dgmlen;
288+ args.buffer = buffer;
289+
290+ retries = 0;
291+retry_call: switch (req->cmd) {
292+ case READ:
293+ result = rpc_call (device->client, NWDPROC_READ, & args, & rdres, 0);
294+ break;
295+
296+ case WRITE:
297+ result = rpc_call (device->client, NWDPROC_WRITE, & args, & res, 0);
298+ break;
299+
300+ default:
301+ /* should not really happen */
302+ eprintk ("invalid request command: %d\n", req->cmd);
303+ return 0;
304+ } /* command switch */
305+
306+
307+ /*
308+ * Repeat the call in case of timeout. Prolong the timeout
309+ * for initial retries & bail out with error when the number
310+ * of retries reached its limit.
311+ */
312+ if (result == -ETIMEDOUT) {
313+ if (retries == 0)
314+ device->client->cl_timeout.to_initval <<= 1;
315+
316+ if (retries++ < NWD_MAX_RETRIES) {
317+ wprintk ("server not responding, retrying (%d)\n", retries);
318+ goto retry_call;
319+ }
320+ }
321+
322+ /* fail if errors persist (including too many timeouts) */
323+ if (result < 0) {
324+ eprintk ("request for %ld sectors at %ld failed, error %d\n",
325+ req->current_nr_sectors, req->sector, abs (result));
326+ return 0;
327+ }
328+
329+
330+ /* next chunk */
331+ offset += dgmlen;
332+ buffer += dgmlen;
333+ reqlen -= dgmlen;
334+ } /* request loop */
335+
336+ return 1;
337+} /* nwd_transfer */
338+
339+
340+static
341+void nwd_request (request_queue_t * rq)
342+{
343+ /* lookup device, io_request_lock held */
344+ struct request * req = blkdev_entry_next_request (& rq->queue_head);
345+ nwd_device_t * device = nwd_find_device (req->rq_dev);
346+ if (device == NULL)
347+ goto fail_request;
348+ if (device->client == NULL)
349+ goto fail_request;
350+
351+ /*
352+ * Process the request(s). The assumption behind this code is
353+ * that the rpc_call will sleep while waiting for RPC response
354+ * (correct me if I'm wrong, please), therefore we drop the
355+ * io_request_lock to allow processing of other requests and
356+ * also (if rpc_call sleeps) because we must not hold it.
357+ */
358+ while (! list_empty (& rq->queue_head)) {
359+ int status;
360+
361+ /* pull request from queue & release io_request_lock */
362+ req = blkdev_entry_next_request (& rq->queue_head);
363+ blkdev_dequeue_request (req);
364+ spin_unlock_irq (& io_request_lock);
365+
366+ /* process buffers in the request */
367+ do {
368+ status = nwd_transfer (device, req);
369+ } while (end_that_request_first (req, status, DEVICE_NAME));
370+
371+ /* grab io_request_lock & finish the request */
372+ spin_lock_irq (& io_request_lock);
373+ end_that_request_last (req);
374+ } /* request loop */
375+ return;
376+
377+
378+ /*
379+ * Make the request fail if the device was not found
380+ * or the device was not connected.
381+ */
382+fail_request:
383+ while (end_that_request_first (req, 0, DEVICE_NAME));
384+ blkdev_dequeue_request (req);
385+ end_that_request_last (req);
386+} /* nwd_request */
387+
388+
389+/*****************************************************************************\
390+| BLOCK DEVICE OPERATIONS |
391+\*****************************************************************************/
392+
393+static
394+int nwd_open (struct inode * inode, struct file * filp)
395+{
396+ int error;
397+ nwd_device_t * device = nwd_find_device (inode->i_rdev);
398+ if (device == NULL)
399+ return -ENODEV;
400+
401+ MOD_INC_USE_COUNT;
402+
403+
404+ /*
405+ * The code for several ioctls requires that the ioctl issuer be the
406+ * only one having the device opened. The code checks device->users
407+ * so we must not change it behind its back.
408+ */
409+ error = down_interruptible (& device->mxctl);
410+ if (error) {
411+ MOD_DEC_USE_COUNT;
412+ return error;
413+ }
414+
415+ device->users++;
416+ up (& device->mxctl);
417+ return 0;
418+} /* nwd_open */
419+
420+
421+static
422+int nwd_release (struct inode * inode, struct file * filp)
423+{
424+ int error;
425+ nwd_device_t * device;
426+
427+ device = nwd_find_device (inode->i_rdev);
428+ if (device == NULL)
429+ return -ENODEV;
430+
431+
432+ /*
433+ * Process NWD client options when last user releases the device. As
434+ * in the case of nwd_open, we grab the device->mxctl mutex before
435+ * updating device->users because we can sleep while issuing remote
436+ * calls, and don't want anybody opening the device at that time.
437+ *
438+ * We also don't want anyone changing the options under us.
439+ */
440+ error = down_interruptible (& device->mxctl);
441+ if (error)
442+ return error;
443+
444+ device->users--;
445+ if (device->users == 0 && device->client != NULL) {
446+ if (device->options & (NWD_OPT_DISPOSE | NWD_OPT_DISCONNECT))
447+ invalidate_device (inode->i_rdev, 1);
448+
449+ /* get rid of changes made on device */
450+ if (device->options & NWD_OPT_DISPOSE) {
451+ if (nwd_dispose (device))
452+ wprintk ("failed to dispose changes on device %d\n", device->devnum);
453+ }
454+
455+ /* disconnect from server */
456+ if (device->options & NWD_OPT_DISCONNECT)
457+ nwd_disconnect (device);
458+ } /* release actions */
459+
460+ up (& device->mxctl);
461+ MOD_DEC_USE_COUNT;
462+ return 0;
463+} /* nwd_release */
464+
465+
466+static
467+int nwd_check_server (nwd_peer_t * server, nwd_device_t * device)
468+{
469+ int devnum;
470+
471+ /* skip INADDR_ANY servers telling us to disconnect only*/
472+ if (server->saddr.sin_addr.s_addr == INADDR_ANY)
473+ return 0;
474+
475+ /* check other devices except the one we are setting peer on */
476+ for (devnum = 0; devnum < nwd_maxdevs; devnum++) {
477+ if (devnum == device->devnum)
478+ continue;
479+ if (memcmp (server, & nwd_devices [devnum].server, sizeof (nwd_peer_t)) == 0)
480+ return -EADDRINUSE;
481+ }
482+
483+ return 0;
484+} /* nwd_check_server */
485+
486+
487+static
488+int nwd_ioctl (struct inode * inode, struct file * filp,
489+ unsigned int cmd, unsigned long arg)
490+{
491+ int error;
492+ long longv;
493+ long * longp;
494+ nwd_peer_t server;
495+ nwd_device_t * device;
496+
497+ device = nwd_find_device (inode->i_rdev);
498+ if (device == NULL)
499+ return -ENODEV;
500+
501+
502+ longp = (long *) arg;
503+ switch (cmd) {
504+ case NWD_CTL_SETPEER:
505+ case NWD_CTL_DISPOSE:
506+ /*
507+ * First, the user must have sufficient privileges to
508+ * set/change peer or dispose changes on the device.
509+ */
510+ if (! capable (CAP_SYS_ADMIN))
511+ return -EPERM;
512+
513+ error = verify_area (VERIFY_READ, longp, sizeof (nwd_peer_t));
514+ if (error)
515+ return error;
516+
517+ /*
518+ * Second, make sure nobody is going to open the device
519+ * while we are doing this. We also make sure to be the
520+ * only ones having the device opened -- we don't want
521+ * to do this under active users.
522+ */
523+ error = down_interruptible (& device->mxctl);
524+ if (error)
525+ return error;
526+
527+ error = -EBUSY;
528+ if (device->users > 1)
529+ goto setpeer_exit_mxctl;
530+
531+
532+ /*
533+ * Third, make sure we are the only ones doing this
534+ * kind of ioctl, because we want to check that we are
535+ * not setting server:devid pair used on other devices.
536+ */
537+ if (cmd == NWD_CTL_SETPEER) {
538+ __copy_from_user (& server, longp, sizeof (nwd_peer_t));
539+
540+ error = down_interruptible (& nwd_mxdev);
541+ if (error)
542+ goto setpeer_exit_mxctl;
543+
544+ error = nwd_check_server (& server, device);
545+ if (error)
546+ goto setpeer_exit_mxdev;
547+ }
548+
549+
550+ /*
551+ * Fourth, invalidate the device. After that, no new
552+ * requests should arrive because it's only us having
553+ * the device opened. Then we can safely disconnect
554+ * from server and connect to new one or dispose of
555+ * changes made on the device.
556+ */
557+ invalidate_device (inode->i_rdev, 1);
558+
559+ if (cmd == NWD_CTL_SETPEER) {
560+ error = nwd_disconnect (device);
561+ if (server.saddr.sin_addr.s_addr != INADDR_ANY) {
562+ device->server = server;
563+ error = nwd_connect (device);
564+ }
565+ } else
566+ error = nwd_dispose (device);
567+
568+
569+ setpeer_exit_mxdev:
570+ if (cmd == NWD_CTL_SETPEER)
571+ up (& nwd_mxdev);
572+ setpeer_exit_mxctl:
573+ up (& device->mxctl);
574+ return error;
575+
576+
577+ case NWD_CTL_GETPEER:
578+ error = verify_area (VERIFY_WRITE, longp, sizeof (nwd_peer_t));
579+ if (error)
580+ return error;
581+
582+ /*
583+ * Make sure the peer is not being changed.
584+ */
585+ error = down_interruptible (& device->mxctl);
586+ if (error)
587+ return error;
588+
589+ /* report disconnected device to have peer 0.0.0.0 */
590+ server = device->server;
591+ if (device->client == NULL)
592+ server.saddr.sin_addr.s_addr = INADDR_ANY;
593+
594+ /* store peer structure to user space */
595+ __copy_to_user (longp, & server, sizeof (nwd_peer_t));
596+ up (& device->mxctl);
597+ return 0;
598+
599+
600+ case NWD_CTL_SETOPTS:
601+ /* must have sufficient privileges first */
602+ if (! capable (CAP_SYS_ADMIN))
603+ return -EPERM;
604+
605+ /*
606+ * Make sure we are not changing the options
607+ * under anybody reading them.
608+ */
609+ error = down_interruptible (& device->mxctl);
610+ if (error)
611+ return error;
612+
613+ device->options = arg;
614+ up (& device->mxctl);
615+ return error;
616+
617+
618+ case NWD_CTL_GETOPTS:
619+ /*
620+ * Make sure the options are not being changed.
621+ */
622+ error = down_interruptible (& device->mxctl);
623+ if (error)
624+ return error;
625+
626+ error = put_user (device->options, longp);
627+ up (& device->mxctl);
628+ return error;
629+
630+
631+ case BLKGETSIZE:
632+ /*
633+ * Make sure the size is not being changed.
634+ */
635+ error = down_interruptible (& device->mxctl);
636+ if (error)
637+ return error;
638+
639+ /* return device size in sectors */
640+ longv = nwd_sizes [device->devnum] << abs (NWD_B2S_SHIFT);
641+ if (NWD_B2S_SHIFT < 0)
642+ longv = nwd_sizes [device->devnum] >> abs (NWD_B2S_SHIFT);
643+
644+ error = put_user (longv, longp);
645+ up (& device->mxctl);
646+ return error;
647+
648+
649+ case BLKRRPART:
650+ /* partition re-reading is not supported */
651+ return -ENOTTY;
652+
653+
654+ case BLKFLSBUF:
655+ /* flush device locally */
656+ error = blk_ioctl (inode->i_rdev, cmd, arg);
657+ if (error)
658+ return error;
659+
660+ /* fsync remote file */
661+ return nwd_sync (device);
662+
663+
664+ default:
665+ /* let block layer handle other ioctls */
666+ return blk_ioctl (inode->i_rdev, cmd, arg);
667+ } /* command switch */
668+
669+ return -ENOTTY;
670+} /* nwd_ioctl */
671+
672+
673+static struct block_device_operations nwd_bdops = {
674+ open: nwd_open,
675+ release: nwd_release,
676+ ioctl: nwd_ioctl,
677+}; /* nwd_bdops */
678+
679+
680+/*****************************************************************************\
681+| INITIALIZATION & FINALIZATION |
682+\*****************************************************************************/
683+
684+void nwd_cleanup (void)
685+{
686+ /* devfs cleanup */
687+ if (devfs_handle != NULL)
688+ devfs_unregister (devfs_handle);
689+
690+ /* memory cleanup */
691+ if (nwd_blksizes != NULL)
692+ kfree (nwd_blksizes);
693+ if (nwd_sizes != NULL)
694+ kfree (nwd_sizes);
695+ if (nwd_devices != NULL)
696+ kfree (nwd_devices);
697+
698+ /* stop RPC I/O daemon */
699+ rpciod_down ();
700+} /* nwd_cleanup */
701+
702+
703+int __init nwd_init (void)
704+{
705+ int error;
706+ int devnum;
707+
708+ /* start RPC I/O daemon */
709+ error = rpciod_up ();
710+ if (error) {
711+ eprintk ("failed to start RPC I/O daemon\n");
712+ return error;
713+ }
714+
715+
716+ /* register block device and create devfs entries */
717+ error = devfs_register_blkdev (MAJOR_NR, DEVICE_NAME, & nwd_bdops);
718+ if (error) {
719+ eprintk ("unable to register as major %d block device\n", MAJOR_NR);
720+ nwd_cleanup ();
721+ return error;
722+ }
723+
724+ devfs_handle = devfs_mk_dir (NULL, "nwd", NULL);
725+ devfs_register_series (devfs_handle, "%u", nwd_maxdevs, DEVFS_FL_DEFAULT,
726+ MAJOR_NR, 0, S_IFBLK | S_IRUSR | S_IWUSR, & nwd_bdops, NULL);
727+
728+
729+ /* alloc memory for device structures */
730+ if (nwd_maxdevs < 1 || nwd_maxdevs > 255) {
731+ wprintk ("invalid nwd_maxdevs (%d), using default (%d)\n", nwd_maxdevs, NWD_MAX_DEVICES);
732+ nwd_maxdevs = NWD_MAX_DEVICES;
733+ }
734+
735+ nwd_devices = kmalloc (nwd_maxdevs * sizeof (nwd_device_t), GFP_KERNEL);
736+ nwd_sizes = kmalloc (nwd_maxdevs * sizeof (int), GFP_KERNEL);
737+ nwd_blksizes = kmalloc (nwd_maxdevs * sizeof (int), GFP_KERNEL);
738+ if (!nwd_devices || !nwd_sizes || !nwd_blksizes) {
739+ /* unregister device */
740+ if (devfs_unregister_blkdev (MAJOR_NR, DEVICE_NAME) != 0)
741+ wprintk ("failed to unregister block device\n");
742+
743+ eprintk ("unable to allocate memory for device structures\n");
744+ nwd_cleanup ();
745+ return -ENOMEM;
746+ }
747+
748+
749+ /*
750+ * Initialize device structures & queues. The assumption behind
751+ * multiple queues is that rpc_call sleeps while waiting for the
752+ * remote call to return (correct me if I'm wrong). Therefore with
753+ * per-device queues we can process requests to different devices
754+ * (which might possibly send remote calls through different network
755+ * interfaces) independently.
756+ */
757+ init_MUTEX (& nwd_mxdev);
758+ memset (nwd_sizes, 0, nwd_maxdevs * sizeof (nwd_sizes));
759+ memset (nwd_devices, 0, nwd_maxdevs * sizeof (nwd_device_t));
760+ for (devnum = 0; devnum < nwd_maxdevs; devnum++) {
761+ nwd_devices [devnum].devnum = devnum;
762+ nwd_devices [devnum].options = NWD_DFL_OPTIONS;
763+
764+ nwd_blksizes [devnum] = NWD_SEC_SIZE;
765+
766+ init_MUTEX (& nwd_devices [devnum].mxctl);
767+
768+ blk_init_queue (& nwd_devices [devnum].queue, DEVICE_REQUEST);
769+ blk_queue_headactive (& nwd_devices [devnum].queue, 0);
770+ }
771+
772+ blk_dev [MAJOR_NR].queue = & nwd_find_queue;
773+ blksize_size [MAJOR_NR] = nwd_blksizes;
774+ blk_size [MAJOR_NR] = nwd_sizes;
775+
776+
777+ /* register disks */
778+ for (devnum = 0; devnum < nwd_maxdevs; devnum++)
779+ register_disk (NULL, MKDEV (MAJOR_NR, devnum), 1, & nwd_bdops, 0);
780+
781+ iprintk ("version 1.4, block major %d, devices %d\n", MAJOR_NR, nwd_maxdevs);
782+ return 0;
783+} /* nwd_init */
784+
785+
786+void __exit nwd_exit (void)
787+{
788+ int devnum;
789+
790+ /* must-have-been-initialized stuff */
791+ for (devnum = 0; devnum < nwd_maxdevs; devnum++)
792+ invalidate_device (MKDEV (MAJOR_NR, devnum), 1);
793+
794+ if (devfs_unregister_blkdev (MAJOR_NR, DEVICE_NAME) != 0)
795+ wprintk ("failed to unregister block device\n");
796+
797+ for (devnum = 0; devnum < nwd_maxdevs; devnum++)
798+ blk_cleanup_queue (& nwd_devices [devnum].queue);
799+
800+ blk_dev [MAJOR_NR].queue = NULL;
801+ blksize_size [MAJOR_NR] = NULL;
802+ blk_size [MAJOR_NR] = NULL;
803+
804+ /* might-have-been-initialized stuff */
805+ nwd_cleanup ();
806+ iprintk ("driver module removed\n");
807+} /* nwd_exit */
808+
809+
810+
811+#ifdef MODULE
812+
813+/*****************************************************************************\
814+| BUILT-AS-MODULE INTERFACE |
815+\*****************************************************************************/
816+
817+MODULE_AUTHOR ("Petr Salinger, Libor Bus, Lubomir Bulej");
818+MODULE_DESCRIPTION ("Network Disk driver v1.4");
819+MODULE_SUPPORTED_DEVICE ("nwd");
820+
821+MODULE_PARM (nwd_maxdevs, "i");
822+MODULE_PARM_DESC (nwd_maxdevs, "Maximum number of NWD devices (1-255).");
823+
824+module_init (nwd_init);
825+module_exit (nwd_exit);
826+
827+#else /* not a module */
828+
829+/*****************************************************************************\
830+| BUILT-IN-KERNEL INTERFACE |
831+\*****************************************************************************/
832+
833+static int nwd_ini_port __initdata = 0;
834+static int nwd_ini_dispose __initdata = NWD_DFL_INIDISPOSE;
835+static int nwd_ini_devid __initdata = NWD_DFL_DEVID;
836+static int nwd_ini_options __initdata = NWD_DFL_OPTIONS;
837+static struct in_addr nwd_ini_server __initdata = { INADDR_ANY };
838+static struct notifier_block nwd_notifier;
839+
840+
841+static
842+int nwd_reboot (struct notifier_block * nb, unsigned long event, void * buf)
843+{
844+ struct inode inode;
845+ nwd_device_t * device;
846+
847+ /* ignore other devices & uninteresting events */
848+ if (MAJOR (ROOT_DEV) != NWD_MAJOR)
849+ return NOTIFY_DONE;
850+
851+ if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF)
852+ return NOTIFY_DONE;
853+
854+ device = nwd_find_device (ROOT_DEV);
855+ if (device == NULL)
856+ return NOTIFY_BAD;
857+
858+
859+ /* release the device before reboot */
860+ iprintk ("releasing root filesystem at %s (devid=%d)\n",
861+ in_ntoa (device->server.saddr.sin_addr.s_addr),
862+ device->server.devid);
863+
864+ inode.i_rdev = ROOT_DEV;
865+ nwd_release (& inode, NULL);
866+
867+
868+ /* unlink from notifier chain */
869+ unregister_reboot_notifier (& nwd_notifier);
870+ return NOTIFY_OK;
871+} /* nwd_reboot */
872+
873+
874+static struct notifier_block nwd_notifier = {
875+ notifier_call: nwd_reboot,
876+ next: NULL,
877+ priority: 0,
878+}; /* nwd_notifier */
879+
880+
881+int __init nwd_boot_init (void)
882+{
883+ int error;
884+ nwd_res result;
885+ nwd_device_t * device;
886+
887+ error = nwd_init ();
888+ if (error)
889+ return error;
890+
891+ /* ignore other devices */
892+ if (MAJOR (ROOT_DEV) != NWD_MAJOR)
893+ return 0;
894+
895+ device = nwd_find_device (ROOT_DEV);
896+ if (device == NULL)
897+ return -ENODEV;
898+
899+
900+ /* fill the device structure with init info */
901+ device->options = nwd_ini_options;
902+ device->server.devid = nwd_ini_devid;
903+ device->server.saddr.sin_family = AF_INET;
904+ device->server.saddr.sin_addr = nwd_ini_server;
905+ device->server.saddr.sin_port = htons (nwd_ini_port);
906+
907+ if (nwd_ini_server.s_addr == INADDR_ANY) {
908+ wprintk ("server address not specified, cannot connect\n");
909+ return -EDESTADDRREQ;
910+ }
911+
912+
913+ /* connect to the server */
914+ iprintk ("connecting to server at %s:%d (devid=%d)\n",
915+ in_ntoa (nwd_ini_server.s_addr), nwd_ini_port, nwd_ini_devid);
916+
917+ error = nwd_connect (device);
918+ if (error)
919+ return error;
920+
921+
922+ /* initial dispose requested? */
923+ if (nwd_ini_dispose)
924+ nwd_dispose (device);
925+
926+ register_reboot_notifier (& nwd_notifier);
927+ return error;
928+} /* nwd_boot_init */
929+
930+
931+/*****************************************************************************\
932+| KERNEL BOOT COMMAND-LINE |
933+\*****************************************************************************/
934+
935+static
936+void __init nwd_adjust_bit (int mask, char * str, int * where)
937+{
938+ if ((*str == 'Y') || (*str == 'y') || (*str == '1'))
939+ * where |= mask;
940+ if ((*str == 'N') || (*str == 'n') || (*str == '0'))
941+ * where &= ~mask;
942+} /* nwd_adjust_bit */
943+
944+
945+static
946+int __init nwd_devid_setup (char * str)
947+{
948+ nwd_ini_devid = simple_strtol (str, NULL, 0);
949+ return 1;
950+} /* nwd_devid_setup */
951+
952+
953+static
954+int __init nwd_server_setup (char * str)
955+{
956+ char * pstr;
957+ nwd_ini_server.s_addr = in_aton (str);
958+ if ((pstr = strchr (str, ':')))
959+ nwd_ini_port = simple_strtol (pstr + 1, NULL, 0);
960+
961+ return 1;
962+} /* nwd_server_setup */
963+
964+
965+static
966+int __init nwd_maxdevs_setup (char * str)
967+{
968+ nwd_maxdevs = simple_strtol (str, NULL, 0);
969+ return 1;
970+} /* nwd_maxdevs_setup */
971+
972+
973+static
974+int __init nwd_ini_dispose_setup (char * str)
975+{
976+ nwd_adjust_bit (1, str, & nwd_ini_dispose);
977+ return 1;
978+} /* nwd_ini_dispose_setup */
979+
980+
981+static
982+int __init nwd_opt_dispose_setup (char * str)
983+{
984+ nwd_adjust_bit (NWD_OPT_DISPOSE, str, & nwd_ini_options);
985+ return 1;
986+} /* nwd_opt_dispose_setup */
987+
988+
989+static
990+int __init nwd_opt_disconnect_setup (char * str)
991+{
992+ nwd_adjust_bit (NWD_OPT_DISCONNECT, str, & nwd_ini_options);
993+ return 1;
994+} /* nwd_opt_disconnect_setup */
995+
996+
997+static
998+int __init nwd_opt_proto_tcp_setup (char * str)
999+{
1000+ nwd_adjust_bit (NWD_OPT_PROTO_TCP, str, & nwd_ini_options);
1001+ return 1;
1002+} /* nwd_opt_proto_tcp_setup */
1003+
1004+
1005+static struct nwd_option {
1006+ char * str;
1007+ int (* parse) (char *);
1008+} nwd_options [] __initdata = {
1009+ { "disconnect=", nwd_opt_disconnect_setup },
1010+ { "inidispose=", nwd_ini_dispose_setup },
1011+ { "dispose=", nwd_opt_dispose_setup },
1012+ { "maxdevs=", nwd_maxdevs_setup },
1013+ { "server=", nwd_server_setup },
1014+ { "devid=", nwd_devid_setup },
1015+ { "tcp=", nwd_opt_proto_tcp_setup },
1016+}; /* nwd_options */
1017+
1018+
1019+static
1020+int __init nwd_parse_options (char * options)
1021+{
1022+ char * optstr;
1023+
1024+ optstr = strsep (& options, ",");
1025+ while (optstr != NULL) {
1026+ int num;
1027+ int len;
1028+ struct nwd_option * opt;
1029+
1030+ for (num = 0; num < ARRAY_SIZE (nwd_options); num++) {
1031+ opt = nwd_options + num;
1032+ len = strlen (opt->str);
1033+ if (strncmp (optstr, opt->str, len) == 0)
1034+ break;
1035+ }
1036+
1037+ if (num < ARRAY_SIZE (nwd_options))
1038+ opt->parse (optstr + len);
1039+
1040+ optstr = strsep (& options, ",");
1041+ }
1042+
1043+ return 1;
1044+} /* nwd_parse_options */
1045+
1046+
1047+/*****************************************************************************\
1048+| COMMAND-LINE PARAMETER HOOKS |
1049+\*****************************************************************************/
1050+
1051+/* new style options */
1052+__setup ("nwd:", nwd_parse_options);
1053+
1054+/* backward compatible options */
1055+__setup ("nwddispose=", nwd_ini_dispose_setup);
1056+__setup ("nwdserver=", nwd_server_setup);
1057+__setup ("nwddevid=", nwd_devid_setup);
1058+
1059+#endif /* not a module */
1060diff -Nur linux.orig/drivers/block/nwd/nwd_dbg.h linux/drivers/block/nwd/nwd_dbg.h
1061--- linux.orig/drivers/block/nwd/nwd_dbg.h Thu Jan 1 01:00:00 1970
1062+++ linux/drivers/block/nwd/nwd_dbg.h Fri Sep 14 11:01:53 2001
1063@@ -0,0 +1,45 @@
1064+/*
1065+ * Network disk client
1066+ * Debugging support
1067+ *
1068+ * Copyright (c) 1996 Petr Salinger
1069+ * Copyright (c) 1999 Libor Bus <l.bus@sh.cvut.cz>
1070+ * Copyright (c) 2001 Lubomir Bulej <pallas@kadan.cz>
1071+ *
1072+ *
1073+ * This program is free software; you can redistribute it and/or modify
1074+ * it under the terms of the GNU General Public License as published by
1075+ * the Free Software Foundation; either version 2 of the License, or
1076+ * (at your option) any later version.
1077+ *
1078+ * This program is distributed in the hope that it will be useful,
1079+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1080+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1081+ * GNU General Public License for more details.
1082+ *
1083+ * You should have received a copy of the GNU General Public License
1084+ * along with this program; if not, write to the Free Software
1085+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1086+ *
1087+ */
1088+
1089+#ifndef _NWD_DEBUG_H
1090+#define _NWD_DEBUG_H
1091+
1092+#include <linux/kernel.h>
1093+
1094+#if 0
1095+#define dprintk(args...) printk (KERN_DEBUG "nwd: " args)
1096+#define denterfn(args...) printk (KERN_DEBUG "nwd: enter " __FUNCTION__ args)
1097+#define dleavefn(args...) printk (KERN_DEBUG "nwd: leave " __FUNCTION__ args)
1098+#else
1099+#define dprintk(args...)
1100+#define denterfn(args...)
1101+#define dleavefn(args...)
1102+#endif
1103+
1104+#define iprintk(args...) printk (KERN_INFO "nwd: " args)
1105+#define eprintk(args...) printk (KERN_ERR "nwd: error: " args)
1106+#define wprintk(args...) printk (KERN_WARNING "nwd: warning: " args)
1107+
1108+#endif /* _NWD_DEBUG_H */
1109diff -Nur linux.orig/drivers/block/nwd/nwd_xdr.c linux/drivers/block/nwd/nwd_xdr.c
1110--- linux.orig/drivers/block/nwd/nwd_xdr.c Thu Jan 1 01:00:00 1970
1111+++ linux/drivers/block/nwd/nwd_xdr.c Wed Aug 29 01:48:41 2001
1112@@ -0,0 +1,370 @@
1113+/*
1114+ * Network disk client
1115+ * Server RPC info, XDR routines
1116+ *
1117+ * Copyright (c) 1996 Petr Salinger
1118+ * Copyright (c) 2001 Lubomir Bulej <pallas@kadan.cz>
1119+ *
1120+ *
1121+ * This program is free software; you can redistribute it and/or modify
1122+ * it under the terms of the GNU General Public License as published by
1123+ * the Free Software Foundation; either version 2 of the License, or
1124+ * (at your option) any later version.
1125+ *
1126+ * This program is distributed in the hope that it will be useful,
1127+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1128+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1129+ * GNU General Public License for more details.
1130+ *
1131+ * You should have received a copy of the GNU General Public License
1132+ * along with this program; if not, write to the Free Software
1133+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1134+ *
1135+ */
1136+
1137+#include <linux/kernel.h>
1138+#include <linux/sunrpc/clnt.h>
1139+
1140+#include "nwd_xdr.h"
1141+#include "nwd_dbg.h"
1142+
1143+
1144+/*
1145+ * Space requirements for procedure arguments and
1146+ * return types, all sizes are in 32-bit words
1147+ */
1148+
1149+#define NWD_null_sz 0
1150+#define NWD_res_sz 1
1151+#define NWD_handle_sz 1
1152+#define NWD_readargs1_sz 3
1153+#define NWD_readargs2_sz 4
1154+#define NWD_readres_sz 2
1155+#define NWD_writeargs1_sz 3
1156+#define NWD_writeargs2_sz 4
1157+#define NWD_lookupres1_sz 3
1158+#define NWD_lookupres2_sz 4
1159+
1160+
1161+/*****************************************************************************\
1162+| XDR HELPER FUNCTIONS |
1163+\*****************************************************************************/
1164+
1165+static inline
1166+u32 * xdr_encode_int (u32 * p, __u32 val)
1167+{
1168+ * p++ = htonl (val);
1169+ return p;
1170+} /* xdr_encode_int */
1171+
1172+
1173+static inline
1174+u32 * xdr_decode_int (u32 * p, __u32 * val)
1175+{
1176+ * val = ntohl (* p++);
1177+ return p;
1178+} /* xdr_decode_int */
1179+
1180+
1181+static inline
1182+u32 * xdr_encode_h2int (u32 * p, __u64 val)
1183+{
1184+ * p++ = htonl (val & 0xFFFFFFFF);
1185+ return p;
1186+} /* xdr_encode_h2int */
1187+
1188+
1189+static inline
1190+u32 * xdr_decode_int2h (u32 * p, __u64 * val)
1191+{
1192+ * val = (__u64) ntohl (* p++);
1193+ return p;
1194+} /* xdr_decode_int2h */
1195+
1196+
1197+/*****************************************************************************\
1198+| NWD XDR FUNCTIONS |
1199+\*****************************************************************************/
1200+
1201+static
1202+int nwd_xdr_null (struct rpc_rqst * req, u32 * p, void * dummy)
1203+{
1204+ return -EIO;
1205+} /* nwd_xdr_null */
1206+
1207+
1208+/*
1209+ * Decode result status
1210+ */
1211+
1212+static
1213+int nwd_xdr_res (struct rpc_rqst * req, u32 * p, nwd_res * res)
1214+{
1215+ p = xdr_decode_int (p, res);
1216+ if (* res != NWD_OK)
1217+ return -(* res);
1218+ return 0;
1219+} /* nwd_xdr_res */
1220+
1221+
1222+/*
1223+ * Encode remote file handle
1224+ */
1225+
1226+static
1227+int nwd_xdr_handle (struct rpc_rqst * req, u32 * p, nwd_handle * hnd)
1228+{
1229+ p = xdr_encode_int (p, * hnd);
1230+ req->rq_slen = xdr_adjust_iovec (req->rq_svec, p);
1231+ return 0;
1232+} /* nwd_xdr_handle */
1233+
1234+
1235+/*
1236+ * Encode READ arguments
1237+ *
1238+ * We read data directly into request buffer so we setup the
1239+ * recv iovec [1] buffer base to point at the request buffer.
1240+ *
1241+ * Note: auth->au_rslack contains estimate of the size of verf part of RPC
1242+ * reply. Together with RPC reply header size and the size of (non file-data)
1243+ * fields of procedure result it determines the "offset" of file data in the
1244+ * reply. Knowing that we can align the receive iovecs so that the file-data
1245+ * part of the reply ends up in the request buffer.
1246+ */
1247+
1248+static inline
1249+int nwd_xdr_readargs (struct rpc_rqst * req, u32 * p, nwd_rwargs * args, const int ver)
1250+{
1251+ struct rpc_auth * auth = req->rq_task->tk_auth;
1252+ int replen = (RPC_REPHDRSIZE + auth->au_rslack + NWD_readres_sz) << 2;
1253+
1254+ p = xdr_encode_int (p, args->file);
1255+ if (ver == NWD_VERSION_1)
1256+ p = xdr_encode_h2int (p, args->offset);
1257+ else if (ver == NWD_VERSION_2)
1258+ p = xdr_encode_hyper (p, args->offset);
1259+ else {
1260+ eprintk ("cannot encode readargs for version %d\n", ver);
1261+ return -EINVAL;
1262+ }
1263+
1264+ p = xdr_encode_int (p, args->count);
1265+ req->rq_slen = xdr_adjust_iovec (req->rq_svec, p);
1266+
1267+
1268+ /* set up reply iovec */
1269+ req->rq_rvec [0].iov_len = replen;
1270+ req->rq_rvec [1].iov_len = args->count;
1271+ req->rq_rvec [1].iov_base = args->buffer;
1272+ req->rq_rlen = replen + args->count;
1273+ req->rq_rnr = 2;
1274+ return 0;
1275+} /* nwd_xdr_readargs */
1276+
1277+
1278+static
1279+int nwd_xdr_readargs1 (struct rpc_rqst * req, u32 * p, nwd_rwargs * args)
1280+{
1281+ return nwd_xdr_readargs (req, p, args, NWD_VERSION_1);
1282+} /* nwd_xdr_readargs1 */
1283+
1284+
1285+static
1286+int nwd_xdr_readargs2 (struct rpc_rqst * req, u32 * p, nwd_rwargs * args)
1287+{
1288+ return nwd_xdr_readargs (req, p, args, NWD_VERSION_2);
1289+} /* nwd_xdr_readargs2 */
1290+
1291+
1292+/*
1293+ * Decode READ result
1294+ *
1295+ * Note: The file data are optional and valid only if the operation
1296+ * result status was NWD_OK. In that case, the file data were written
1297+ * directly into request buffer, for which recv iovec [1] was configured.
1298+ */
1299+
1300+static
1301+int nwd_xdr_readres (struct rpc_rqst * req, u32 * p, nwd_readres * res)
1302+{
1303+ int hdlen, recvd;
1304+
1305+ p = xdr_decode_int (p, & res->status);
1306+ if (res->status != NWD_OK)
1307+ return -res->status;
1308+
1309+ p = xdr_decode_int (p, & res->count);
1310+
1311+ /* check length of returned data */
1312+ hdlen = (u8 *) p - (u8 *) req->rq_rvec [0].iov_base;
1313+ recvd = req->rq_rlen - hdlen;
1314+ if (res->count > recvd) {
1315+ wprintk ("server cheating in read reply: count (%d) > recvd (%d)\n", res->count, recvd);
1316+ res->count = recvd;
1317+ }
1318+
1319+ return res->count;
1320+} /* nwd_xdr_readres */
1321+
1322+
1323+/*
1324+ * Encode WRITE arguments
1325+ *
1326+ * We send the data directly from request buffer, so we setup the
1327+ * send iovec [1] buffer base to point at the request buffer.
1328+ */
1329+
1330+static inline
1331+int nwd_xdr_writeargs (struct rpc_rqst * req, u32 * p, nwd_rwargs * args, const int ver)
1332+{
1333+ p = xdr_encode_int (p, args->file);
1334+ if (ver == NWD_VERSION_1)
1335+ p = xdr_encode_h2int (p, args->offset);
1336+ else if (ver == NWD_VERSION_2)
1337+ p = xdr_encode_hyper (p, args->offset);
1338+ else {
1339+ eprintk ("cannot encode writeargs for version %d\n", ver);
1340+ return -EINVAL;
1341+ }
1342+
1343+ p = xdr_encode_int (p, args->count);
1344+ req->rq_slen = xdr_adjust_iovec (req->rq_svec, p);
1345+
1346+ req->rq_svec [1].iov_base = args->buffer;
1347+ req->rq_svec [1].iov_len = args->count;
1348+ req->rq_slen += args->count;
1349+ req->rq_snr = 2;
1350+ return 0;
1351+} /* nwd_xdr_writeargs */
1352+
1353+
1354+static
1355+int nwd_xdr_writeargs1 (struct rpc_rqst * req, u32 * p, nwd_rwargs * args)
1356+{
1357+ return nwd_xdr_writeargs (req, p, args, NWD_VERSION_1);
1358+} /* nwd_xdr_writeargs1 */
1359+
1360+
1361+static
1362+int nwd_xdr_writeargs2 (struct rpc_rqst * req, u32 * p, nwd_rwargs * args)
1363+{
1364+ return nwd_xdr_writeargs (req, p, args, NWD_VERSION_2);
1365+} /* nwd_xdr_writeargs2 */
1366+
1367+
1368+/*
1369+ * Decode LOOKUP result
1370+ *
1371+ * Note: The file lookup info is optional and valid only if the
1372+ * operation result status was NWD_OK.
1373+ */
1374+
1375+static inline
1376+int nwd_xdr_lookupres (struct rpc_rqst * req, u32 * p, nwd_lookupres * res, const int ver)
1377+{
1378+ p = xdr_decode_int (p, & res->status);
1379+ if (res->status != NWD_OK)
1380+ return -res->status;
1381+
1382+ p = xdr_decode_int (p, & res->file);
1383+ if (ver == NWD_VERSION_1)
1384+ p = xdr_decode_int2h (p, & res->size);
1385+ else if (ver == NWD_VERSION_2)
1386+ p = xdr_decode_hyper (p, & res->size);
1387+ else {
1388+ eprintk ("cannot decode lookupres for version %d\n", ver);
1389+ return -EINVAL;
1390+ }
1391+
1392+ return 0;
1393+} /* nwd_xdr_lookupres */
1394+
1395+
1396+static
1397+int nwd_xdr_lookupres1 (struct rpc_rqst * req, u32 * p, nwd_lookupres * res)
1398+{
1399+ return nwd_xdr_lookupres (req, p, res, NWD_VERSION_1);
1400+} /* nwd_xdr_lookupres1 */
1401+
1402+
1403+static
1404+int nwd_xdr_lookupres2 (struct rpc_rqst * req, u32 * p, nwd_lookupres * res)
1405+{
1406+ return nwd_xdr_lookupres (req, p, res, NWD_VERSION_2);
1407+} /* nwd_xdr_lookupres2 */
1408+
1409+
1410+/*****************************************************************************\
1411+| XDR ENCODE/DECODE STRUCTURES |
1412+\*****************************************************************************/
1413+
1414+#ifndef MAX
1415+# define MAX(a, b) (((a) > (b)) ? (a) : (b))
1416+#endif
1417+
1418+/*
1419+ * Template for RPC procinfo structure
1420+ */
1421+
1422+#define PROC(proc, atype, rtype) \
1423+{ \
1424+ p_procname: "nwdproc_" #proc, \
1425+ p_encode: (kxdrproc_t) nwd_xdr_##atype, \
1426+ p_decode: (kxdrproc_t) nwd_xdr_##rtype, \
1427+ p_bufsiz: MAX (NWD_##atype##_sz, NWD_##rtype##_sz) << 2, \
1428+ p_count: 0 \
1429+}
1430+
1431+
1432+static struct rpc_procinfo nwd_procedures_1 [] = {
1433+ PROC (null, null, null),
1434+ PROC (dispose, handle, res),
1435+ PROC (read, readargs1, readres),
1436+ PROC (write, writeargs1, res),
1437+ PROC (lookup, handle, lookupres1)
1438+}; /* nwd_procedures_1 */
1439+
1440+
1441+static struct rpc_procinfo nwd_procedures_2 [] = {
1442+ PROC (null, null, null),
1443+ PROC (dispose, handle, res),
1444+ PROC (read, readargs2, readres),
1445+ PROC (write, writeargs2, res),
1446+ PROC (lookup, handle, lookupres2),
1447+ PROC (sync, handle, res)
1448+}; /* nwd_procedures_2 */
1449+
1450+
1451+static struct rpc_version nwd_version_1 = {
1452+ number: NWD_VERSION_1,
1453+ nrprocs: ARRAY_SIZE (nwd_procedures_1),
1454+ procs: nwd_procedures_1
1455+}; /* nwd_version_1 */
1456+
1457+
1458+static struct rpc_version nwd_version_2 = {
1459+ number: NWD_VERSION_2,
1460+ nrprocs: ARRAY_SIZE (nwd_procedures_2),
1461+ procs: nwd_procedures_2
1462+}; /* nwd_version_2 */
1463+
1464+
1465+
1466+static struct rpc_version * nwd_versions [] = {
1467+ NULL,
1468+ & nwd_version_1,
1469+ & nwd_version_2
1470+}; /* nwd_versions */
1471+
1472+
1473+static struct rpc_stat nwd_rpcstat;
1474+
1475+
1476+struct rpc_program nwd_program = {
1477+ name: "nwd",
1478+ number: NWD_PROGRAM,
1479+ nrvers: ARRAY_SIZE (nwd_versions),
1480+ version: nwd_versions,
1481+ stats: & nwd_rpcstat
1482+}; /* nwd_program */
1483diff -Nur linux.orig/drivers/block/nwd/nwd_xdr.h linux/drivers/block/nwd/nwd_xdr.h
1484--- linux.orig/drivers/block/nwd/nwd_xdr.h Thu Jan 1 01:00:00 1970
1485+++ linux/drivers/block/nwd/nwd_xdr.h Sun Sep 9 23:22:15 2001
1486@@ -0,0 +1,78 @@
1487+/*
1488+ * Network disk client
1489+ * Server RPC info, XDR routines
1490+ *
1491+ * Copyright (c) 1996 Petr Salinger
1492+ * Copyright (c) 1999 Libor Bus <l.bus@sh.cvut.cz>
1493+ * Copyright (c) 2001 Lubomir Bulej <pallas@kadan.cz>
1494+ *
1495+ *
1496+ * This program is free software; you can redistribute it and/or modify
1497+ * it under the terms of the GNU General Public License as published by
1498+ * the Free Software Foundation; either version 2 of the License, or
1499+ * (at your option) any later version.
1500+ *
1501+ * This program is distributed in the hope that it will be useful,
1502+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1503+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1504+ * GNU General Public License for more details.
1505+ *
1506+ * You should have received a copy of the GNU General Public License
1507+ * along with this program; if not, write to the Free Software
1508+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1509+ */
1510+
1511+#ifndef _NWD_XDR_H
1512+#define _NWD_XDR_H
1513+
1514+#include <linux/errno.h>
1515+#include <linux/types.h>
1516+
1517+
1518+#define NWD_PROGRAM 0x21050003
1519+#define NWD_VERSION_1 1
1520+#define NWD_VERSION_2 2
1521+
1522+#define NWD_OK 0
1523+#define NWD_ENOENT ENOENT
1524+#define NWD_EIO EIO
1525+#define NWD_EINVAL EINVAL
1526+#define NWD_ENOSPC ENOSPC
1527+
1528+#define NWDPROC_NULL 0
1529+#define NWDPROC_DISPOSE 1
1530+#define NWDPROC_READ 2
1531+#define NWDPROC_WRITE 3
1532+#define NWDPROC_LOOKUP 4
1533+#define NWDPROC_SYNC 5
1534+
1535+
1536+typedef __s32 nwd_res;
1537+typedef __s32 nwd_handle;
1538+
1539+
1540+typedef struct nwd_rwargs {
1541+ nwd_handle file;
1542+ __u64 offset;
1543+ __u32 count;
1544+ void * buffer;
1545+} nwd_rwargs;
1546+
1547+
1548+typedef struct nwd_readres {
1549+ nwd_res status;
1550+ __u32 count;
1551+} nwd_readres;
1552+
1553+
1554+typedef struct nwd_lookupres {
1555+ nwd_res status;
1556+ nwd_handle file;
1557+ __u64 size;
1558+} nwd_lookupres;
1559+
1560+
1561+extern struct rpc_stat nwd_rpcstat;
1562+extern struct rpc_program nwd_program;
1563+
1564+#endif /* _NWD_XDR_H */
1565diff -Nur linux.orig/fs/Config.in linux/fs/Config.in
1566--- linux.orig/fs/Config.in Mon Oct 22 14:57:05 2001
1567+++ linux/fs/Config.in Mon Oct 22 15:08:52 2001
1568@@ -113,17 +113,25 @@
1569 dep_mbool ' Provide NFSv3 server support' CONFIG_NFSD_V3 $CONFIG_NFSD
1570
1571 if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
1572- define_tristate CONFIG_SUNRPC y
1573 define_tristate CONFIG_LOCKD y
1574 else
1575 if [ "$CONFIG_NFS_FS" = "m" -o "$CONFIG_NFSD" = "m" ]; then
1576- define_tristate CONFIG_SUNRPC m
1577 define_tristate CONFIG_LOCKD m
1578- else
1579- define_tristate CONFIG_SUNRPC n
1580- define_tristate CONFIG_LOCKD n
1581+ else
1582+ define_tristate CONFIG_LOCKD n
1583 fi
1584 fi
1585+
1586+ if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" -o "$CONFIG_BLK_DEV_NWD" = "y" ]; then
1587+ define_tristate CONFIG_SUNRPC y
1588+ else
1589+ if [ "$CONFIG_NFS_FS" = "m" -o "$CONFIG_NFSD" = "m" -o "$CONFIG_BLK_DEV_NWD" = "m" ]; then
1590+ define_tristate CONFIG_SUNRPC m
1591+ else
1592+ define_tristate CONFIG_SUNRPC n
1593+ fi
1594+ fi
1595+
1596 if [ "$CONFIG_NFSD_V3" = "y" -o "$CONFIG_NFS_V3" = "y" ]; then
1597 define_bool CONFIG_LOCKD_V4 y
1598 fi
1599diff -Nur linux.orig/include/linux/nwd.h linux/include/linux/nwd.h
1600--- linux.orig/include/linux/nwd.h Thu Jan 1 01:00:00 1970
1601+++ linux/include/linux/nwd.h Fri Sep 14 01:26:34 2001
1602@@ -0,0 +1,102 @@
1603+/*
1604+ * Network disk client
1605+ * Kernel block device driver
1606+ *
1607+ * Copyright (c) 1996 Petr Salinger
1608+ * Copyright (c) 1999 Libor Bus <l.bus@sh.cvut.cz>
1609+ * Copyright (c) 2001 Lubomir Bulej <pallas@kadan.cz>
1610+ *
1611+ *
1612+ * This program is free software; you can redistribute it and/or modify
1613+ * it under the terms of the GNU General Public License as published by
1614+ * the Free Software Foundation; either version 2 of the License, or
1615+ * (at your option) any later version.
1616+ *
1617+ * This program is distributed in the hope that it will be useful,
1618+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1619+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1620+ * GNU General Public License for more details.
1621+ *
1622+ * You should have received a copy of the GNU General Public License
1623+ * along with this program; if not, write to the Free Software
1624+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1625+ *
1626+ */
1627+
1628+#ifndef _LINUX_NWD_H
1629+#define _LINUX_NWD_H
1630+
1631+#include <linux/ioctl.h>
1632+
1633+
1634+/*****************************************************************************\
1635+| KERNEL & USER SPACE |
1636+\*****************************************************************************/
1637+
1638+#define NWD_IOCTL_CHAR 'N'
1639+#define NWD_CTL_SETPEER _IOW (NWD_IOCTL_CHAR, 0, nwd_peer_t)
1640+#define NWD_CTL_GETPEER _IOR (NWD_IOCTL_CHAR, 1, nwd_peer_t)
1641+#define NWD_CTL_SETOPTS _IO (NWD_IOCTL_CHAR, 3)
1642+#define NWD_CTL_GETOPTS _IO (NWD_IOCTL_CHAR, 4)
1643+#define NWD_CTL_DISPOSE _IO (NWD_IOCTL_CHAR, 5)
1644+
1645+#define NWD_OPT_DISPOSE 0x1 /* dispose changes on release */
1646+#define NWD_OPT_DISCONNECT 0x2 /* disconnect from server on release */
1647+#define NWD_OPT_PROTO_TCP 0x4 /* use TCP for RPC transport */
1648+
1649+typedef struct nwd_peer {
1650+ struct sockaddr_in saddr; /* socket address of the server */
1651+ int devid; /* requested identification for lookup */
1652+} nwd_peer_t;
1653+
1654+
1655+/*****************************************************************************\
1656+| KERNEL ONLY |
1657+\*****************************************************************************/
1658+
1659+#ifdef __KERNEL__
1660+
1661+#include <linux/fs.h>
1662+#include <asm/semaphore.h>
1663+#include <linux/sunrpc/clnt.h>
1664+
1665+#define NWD_MAJOR 62
1666+
1667+#define NWD_DFL_DEVID 1
1668+#define NWD_DFL_OPTIONS (NWD_OPT_DISPOSE)
1669+#define NWD_DFL_INIDISPOSE 1
1670+
1671+#define NWD_SEC_BITS 9 /* device sector size in bits */
1672+#define NWD_SEC_SIZE (1U << NWD_SEC_BITS) /* sector size (must be power of 2) */
1673+#define NWD_B2S_SHIFT (BLOCK_SIZE_BITS-NWD_SEC_BITS) /* shift to convert blocks to sectors */
1674+
1675+
1676+/*
1677+ * NWD_MAX_DGLEN determines the number of fragments per datagram
1678+ * 1024 - one fragment is enough; this is usually used for ext2
1679+ * 4096 - more fragments; useful for paging
1680+ */
1681+
1682+#define NWD_MAX_DGLEN (4 * NWD_SEC_SIZE) /* must be multiple of NWD_SEC_SIZE */
1683+#define NWD_MAX_SNLEN 20 /* max. length of server name */
1684+#define NWD_MAX_DEVICES 8 /* default number of nwd devices */
1685+#define NWD_MAX_RETRIES 10 /* how many times we retry the request */
1686+
1687+
1688+typedef struct nwd_device {
1689+ int remid; /* id of remote file disk operations */
1690+ int devnum; /* NWD device number */
1691+ int options; /* NWD device options */
1692+ nwd_peer_t server; /* server address & lookup id */
1693+ struct rpc_clnt * client; /* RPC client */
1694+ char sname [NWD_MAX_SNLEN]; /* server name for debug messages */
1695+
1696+ int users; /* reference counter */
1697+ struct semaphore mxctl; /* device control mutex */
1698+
1699+ request_queue_t queue; /* device request queue */
1700+} nwd_device_t;
1701+
1702+#endif /* __KERNEL__ */
1703+
1704+#endif /* _LINUX_NWD_H */
This page took 0.65777 seconds and 4 git commands to generate.