]>
Commit | Line | Data |
---|---|---|
dd19de18 | 1 | diff -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 | |
22 | diff -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 */ | |
1060 | diff -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 */ | |
1109 | diff -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 */ | |
1483 | diff -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 */ | |
1565 | diff -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 | |
1599 | diff -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 */ |