]> git.pld-linux.org Git - packages/kernel.git/blob - 2.6.0-t5-enbd-2.4.31_20030506.patch
- obsolete
[packages/kernel.git] / 2.6.0-t5-enbd-2.4.31_20030506.patch
1 --- linux-2.5.64/drivers/block/Kconfig.pre-enbd Mon Mar 24 15:56:52 2003
2 +++ linux-2.5.64/drivers/block/Kconfig  Mon Mar 24 17:45:35 2003
3 @@ -292,6 +292,15 @@
4  
5           If unsure, say N.
6  
7 +config ENBD
8 +        bool 'Enhanced network block device'
9 +       depends on NET
10 +        ---help---
11 +         To use the ENBD support, you must say Y here and select one
12 +         of the driver's units (e.g. BLK_DEV_ENBD, BLK_DEV_ENBD_IOCTL).
13 +
14 +source "drivers/block/enbd/Kconfig"
15 +
16  config BLK_DEV_RAM
17         tristate "RAM disk support"
18         ---help---
19 --- linux-2.5.64/drivers/block/enbd/enbd_base.c.pre-enbd        Mon Mar 24 18:55:25 2003
20 +++ linux-2.5.64/drivers/block/enbd/enbd_base.c Tue Mar 25 15:44:12 2003
21 @@ -0,0 +1,4172 @@
22 +/*
23 + * (Enhanced) Network block device - make block devices work over TCP
24 + *
25 + * Original NBD Copyright 1997 Pavel Machek <pavel@elf.mj.gts.cz>
26 + * Further ENBD Copyrights 1998, 1999, 2000 Peter Breuer <ptb@it.uc3m.es>
27 + *
28 + *
29 + *
30 + * ATTENTION: You need the userspace daemons available from
31 + *            ftp://oboe.it.uc3m.es/pub/Programs/nbd-2.4.*.tgz
32 + *            and/or the ENBD project on http://freshmeat.net
33 + *
34 + *
35 + *
36 + * Development of the ENBD software has been supported by grants and
37 + * contributions from Realm Information Technologies, Inc. of 5555
38 + * Oakbrook Parkway, NW Norcross, GA and iNsu Innovations Inc.  of
39 + * 3465, Boulevard Thimens, Saint-Laurent, Quebec, Canada.
40 + * 
41 + * ------------ Pavel's history notes ----------------------------------
42 + * 97-3-25 compiled 0-th version, not yet tested it 
43 + *   (it did not work, BTW) (later that day) HEY! it works!
44 + *   (bit later) hmm, not that much... 2:00am next day:
45 + *   yes, it works, but it gives something like 50kB/sec
46 + * 97-3-28 it's completely strange - when using 1024 byte "packets"
47 + *   it gives 50kB/sec and CPU idle; with 2048 bytes it gives
48 + *   500kB/sec (and CPU loaded 100% as it should be) (all done
49 + *   against localhost)
50 + * 97-4-1 complete rewrite to make it possible for many requests at 
51 + *   once to be processed
52 + * 97-4-1 23:57 rewrite once again to make it work :-(
53 + * 97-4-3 00:02 hmm, it does not work.
54 + * 97-4-3 23:06 hmm, it will need one more rewrite :-)
55 + * 97-4-10 It looks like it's working and stable. But I still do not
56 + *  have any recovery from lost connection...
57 + * (setq tab-width 4)
58 + * 97-4-11 Making protocol independent of endianity etc.
59 + * 97-4-15 Probably one more rewrite, since it loses requests under
60 + *  heavy loads
61 + * 97-9-13 Cosmetic changes
62 + *
63 + * possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall
64 + * why not: would need verify_area and friends, would share yet another 
65 + *          structure with userland
66 + *
67 + * FIXME: not module-safe
68 + *
69 + * ------------ Peter's history notes ----------------------------------
70 + * 98-12-18 modules now OK ptb@it.uc3m.es (Peter Breuer) ported to
71 + * 2.0.*. + better debugging. Still possible lockup in connection with APM
72 + * and spurious interrupt - only on write. Error treatment should
73 + * be improved. After 100 errors from end_request the kernel can
74 + * do anything. We should catch it ourselves.
75 + * 99-1-sometime fixed lockup by extending semaphore - ptb v1.0.
76 + * 99-3-sometime reconnect protocol (client mod agreed by pavel) - ptb v1.1
77 + * 99-4-25 add /proc/nbdinfo - ptb v1.1.1
78 + * 99-4-sometime add multiplex - ptb v1.2
79 + * 99-4-26 fix multiplex and redundancy - ptb v1.2.1
80 + * 99-4-29 reentrant client threads - ptb v1.2.2
81 + * 99-4-29 socket related stuff placed in user space - amarin v1.3.0
82 + * 99-5-3  fix all, all writes had to be before all reads - ptb v1.2.4
83 + * 99-5-5  fix out-of-order, async - ptb v1.2.5
84 + * 99-5-7  semaphores removed (still works!), fail cases corrected - ptb v1.2.6
85 + * 99-5-12 signals unblocked in xmit, blksize != 1024 fixed, ioctls
86 + *         added  - ptb v1.2.7
87 + * 99-6-1  interaction with client split into two functions - amarin v1.3.0
88 + * 99-6-3  reintegrated fully, mem manager fixed, accounts fixed - ptb v1.2.8.3
89 + * 99-6-3  extra queue removed, mem manager removed  - ptb v1.2.8.4
90 + * 99-7-3  buffer registration introduced - ptb v1.2.8.5
91 + * 99-7-3  some client redundancy reestablished - ptb v2.1.1
92 + * 99-7-10 encapsulated queue calls. One element rollback buffer - ptb v2.1.2
93 + * 99-7-20 timestamp and rollback old abandoned request - ptb v2.1.3
94 + * 99-7-24 64bit file sizes and offsets accepted - ptb v2.1.9
95 + * 99-7-26 experimental request coalesces - ptb v2.1.10
96 + * 99-7-27 partitioning scheme - ptb v2.2.1
97 + * 99-8-3  nbd_clr_sock bug in invalidate_device fixed? - ptb v2.2.4
98 + * 99-8-5  reverse replace of block_fsync, add sig ioctls - ptb v2.2.5
99 + *         reverse bug introduced about v2.2.3 for compound reqs - ptb v2.2.5
100 + *         fix clear_que bug (didn't rollback first) from 2.1.3 - ptb v2.2.5
101 + * 99-8-22 workaround strange nr_sectors bug - ptb v2.2.6
102 + * 99-8-11 fix MY_NBD_SYNC bug. Never sync'ed all - ptb v2.2.7
103 + * 99-8-12 wakeups all moved to enqueue - ptb v2.2.7
104 + * 99-8-23 remove slot->cli_age - ptb v2.2.7
105 + * 99-8-24 first 8 bytes of signature embedded in packets - ptb v2.2.8
106 + *         fix SET_SIG define buglet, remove hardcoded constants - ptb v2.2.8
107 + *         fix huge bug. Missing copy_fromfs in my_nbd_ack - ptb v2.2.8     
108 + *         removed signature embedding and all other decorations - ptb v2.2.8
109 + * 99-8-25 recast fix in my_nbd_ack to avoid align. bug - ptb v2.2.9
110 + *         put in MKDEVs and put back some hardcode const fixes - ptb v2.2.10
111 + * 99-9-29 fix BLKGETSIZE bug - ptb v2.2.14
112 + * 99-10-2 run with interrupts on throughout. Think we lose some - ptb v2.2.15
113 + * 99-10-8 trim dead code, kernel 2.2 ifdef's - ptb v2.2.17
114 + * 99-12-18 further o-o - ptb v2.2.19
115 + * 99-12-28 queue account cleanup. endio on queue reqs at reset - ptb v2.2.20
116 + *          interruptible semaphores for better client recovery - ptb v2.2.20
117 + * 00-1-2   debugging cleanups. Fix race in end_request - ptb v2.2.21
118 + * 00-1-4   semaphores simplified. - ptb v2.2.22
119 + * 00-6-8   emergency control by write to proc - ptb v2.2.24
120 + * 00-7-20  ported to 2.4.0-test1. Possible minor bugs found/fixed - ptb v2.2.24
121 + * 00-7-27  changed proc i/f to read_proc from get_info in 2.2/2.4 - ptb v2.2.25
122 + * 00-7-30  fixed reads before writes under 2.4 by disabling merge - ptb v2.2.25
123 + * 00-7-30  and fixed merge_reqs for 2.4, now that I understand! - ptb v2.2.25
124 + * 00-7-30  fixed/introduced possible bug in end_io  for 2.2/2.4 - ptb v2.2.25
125 + * 00-7-30 added timeval/zone field in requests and replies - ptb v2.4.0
126 + * 00-7-30 fixed hitherto masked bug in read_stat in nbd_client - ptb v2.4.0
127 + * 00-7-30 added timeout to net writes in nbd_client - ptb v2.4.0
128 + * 00-8-20 display fix for devices over 2GB - ptb v2.4.5
129 + * 00-8-23 more 64 bit fixes + error out overrange requests- ptb v2.4.6/2.2.27
130 + * 00-8-31 add NBD_ERR ioctl to error out slot request- ptb v2.4.9
131 + * 00-8-31 soften NBD_SOFT_RESET so doesn't wreck protocol - ptb v2.4.9
132 + * 00-9-1  remove %L's from printfs. Kernel 2.2. doesn't - ptb v2.4.10/2.2.27
133 + * 00-9-6  add various state flags to help init order - ptb v2.4.11
134 + * 00-9-8  add checks for device initialised to set_sock - ptb v2.4.12
135 + * 00-9-17 en/disable device as aslot count goes through 0 - ptb v2.4.13/2.2.28
136 + * 00-9-21 split read/write dev req counts for accounting - ptb v2.4.14
137 + * 00-9-21 renamed sync_intvl to req_timeo - ptb v2.4.14
138 + * 00-9-21 made sync_intvl count write blocks - ptb v2.4.14
139 + * 00-9-22 repair enable after delayed disable when disabled - ptb v2.4.14
140 + * 00-9-22 include sync (nonblocking) after sync_intvl reqs - ptb v2.4.14
141 + * 00-9-25 disable sync (nonblocking) after sync_intvl reqs - ptb v2.4.14
142 + * 00-9-25 bundle invalidate_buffers in clr_sock - ptb v2.4.14
143 + * 00-10-20 implement req_timeo per device + ioctl (Wang Gang) - ptb v2.4.15
144 + * 00-10-20 add raid mode (Wang Gang) - ptb v2.4.15
145 + * 00-10-26 throttle in do_req  - ptb v2.4.15
146 + * 00-10-28 do set_sock on first open and clr_sock on last close - ptb v2.4.15
147 + * 00-11-01 make sync_intvl really sync - ptb v2.4.15
148 + * 00-11-14 rename throttle to plug, nbd_sync takes arg - ptb v2.4.17
149 + * 00-11-19 clr_sock errs req not rollback if show_errs & !aslot - ptb v2.4.17
150 + * 00-11-20 removed autodeadlock when disabled in do_req end_req - ptb v2.4.17
151 + * 00-11-21 make MY_NBD_SYNC only sync when sync_intvl > 0 - ptb v2.4.17
152 + * 00-12-24 make MY_NBD_GET_REQ use a timeout arg - ptb v2.4.18
153 + * 01-02-12 ported to 2.4.0 (works). do_nbd_request rewritten - ptb v2.4.20
154 + * 01-02-20 managed to get plugging and clustered read/writes OK - ptb v2.4.21
155 + * 01-02-21 eliminated slot->buflen for the time being - ptb v2.4.21
156 + * 01-02-27 added proper devfs support - ptb v2.4.22
157 + * 01-03-15 allowed more devices/in devfs, cleaned up endio - ptb v2.4.23
158 + * 01-03-15 added device letter (<= 3 chars) to struct-  - ptb v2.4.23
159 + * 01-03-15 added request size check to do_nbd_req - ptb v2.4.23
160 + * 01-03-15 increased MAX_SECTORS to 512 by default - ptb v2.4.23
161 + * 01-03-15 made major number a module parameter - ptb v2.4.23
162 + * 01-03-18 added max_sectors array - ptb v2.4.23
163 + * 01-03-23 added devfs links - ptb v2.4.23
164 + * 01-04-17 plugging always enabled for 2.4 kernels - ptb v2.4.24
165 + * 01-04-17 made SET_RO set_device_ro as well as set local flags - ptb v2.4.25
166 + * 01-04-28 impl SET_MD5SUM ioctl and proc support for md5sum - ptb v2.4.25
167 + * 01-04-29 added accounting for md5'd reqs - ptb v2.4.25
168 + * 01-07-29 added atomic protections for accounting - ptb v2.4.25
169 + * 01-08-01 fixed 2.4 smp bugs. Interrupts off in spinlocks - ptb v2.4.25
170 + * 01-08-01 removed all semaphores for spinlocks - ptb v2.4.25
171 + * 01-08-01 invalidate_buffers in clr_sock (req'd Rogier Wolff) - ptb v2.4.25
172 + * 01-08-02 fixed smp deadlock - end_that_request_first slept! ptb v2.4.26
173 + * 01-10-16 provisionally added error in device open when notenabled ptb v2.4.27
174 + * 01-10-18 added DIRTY flag to save on repeated invalidate_buffers ptb v2.4.27
175 + * 01-10-31 increment seqno_out before delivery, so really starts at 1  v2.4.27
176 + * 01-11-01 move zeroing of seqno in cmd field to nbe_end_req* ptb v2.4.27
177 + * 01-11-18 add speed calculation, dev fields, display in proc ptb v2.4.27
178 + * 01-11-20 modifications for compiling into monolithic kernel ptb v2.4.27
179 + * 01-12-06 clr requests before reenabling, not after, in nbd_enable ptb 2.4.27
180 + * 02-02-21 make nbd_rollback modal, absirbing nbd_error ptb 2.4.27
181 + * 02-08-08 added local BLKSSZGET (reject) and related ioctls ptb 2.4.30
182 + * 02-08-12 make nbd_ack not ruin req when its rolled back already ptb 2.4.30
183 + * 02-09-18 fix __FUNCTION__ for new gcc ptb 2.4.30
184 + * 02-09-18 always allow daemon death even with reqs waiting ptb 2.4.30
185 + * 02-09-18 eliminate SYNC_REQD, RLSE_REQD ptb 2.4.30
186 + * 02-09-18 eliminate speed_lim ptb 2.4.30
187 + * 02-09-18 fix countq accounting ptb 2.4.30
188 + * 02-09-18 encapsulate remote ioctl handling ptb 2.4.30
189 + * 02-09-18 remote ioctl uses kernel req, not our fake one ptb 2.4.30
190 + * 02-09-18 eliminated ctldta use (too much tricky logic) ptb 2.4.30
191 + * 02-09-28 handle req specials ptb 2.4.30
192 + * 02-10-10 introduce DIRECT flag ptb 2.4.30
193 + * 02-10-13 rollback pushes reqs to local queue, not queues them! ptb 2.4.30
194 + * 02-10-13 add hooks for separate ioctl module  ptb 2.4.30
195 + * 02-10-16 take set_sock out of open. Put pid check in handshake  ptb 2.4.30
196 + * 02-10-16 define MY_NBD_GET_NPORT ioctl ptb 2.4.30
197 + * 02-10-18 remove wait from MY_NBD_SYNC ioctl ptb 2.4.30
198 + * 02-10-20 rollback adds requests to queue in seqno order ptb 2.4.30
199 + * 02-10-23 introduce and use pid_sem instead of req_sem ptb 2.4.30
200 + * 02-10-30 support client fallback to ioctls on whole disk ptb 2.4.30
201 + * 02-11-3  moved set INITIALISED up to coincide with setting inode ptb 2.4.30
202 + * 02-11-3  add media check and revalidate routines ptb 2.4.30
203 + * 02-11-4  encapuslate lives++ and ENABLED changes into nbd_enable ptb 2.4.30
204 + * 02-11-4  set_enable from proc only enables, not clears queue ptb 2.4.30
205 + * 11-11-4  take blk_put_request out of end_request (it locks!) ptb 2.4.30
206 + * 11-11-4  replace list_del by list_del_init ptb 2.4.30
207 + * 02-12-7  nbd_release made aware of daemons on whole disk ptb 2.4.30
208 + * 03-01-7  added ioctls for setfaulty etc. ptb 2.4.31
209 + * 03-02-1  used metalock for non-queue changes ptb 2.4.31
210 + * 03-03-12 add md_list notification ioctls ptb 2.4.31
211 + */
212 +
213 +#include <linux/major.h>
214 +#ifndef UNIX98_PTY_MAJOR_COUNT
215 +  #define UNIX98_PTY_MAJOR_COUNT 8
216 +  #ifndef UNIX98_NR_MAJORS
217 +    #define UNIX98_NR_MAJORS=UNIX98_PTY_MAJOR_COUNT
218 +  #endif
219 +#endif
220 +
221 +#include <linux/module.h>
222 +
223 +#if defined(__GNUC__) && __GNUC__ >= 2
224 +#define _LOOSE_KERNEL_NAMES
225 +#endif
226 +
227 +#include <linux/version.h>
228 +
229 +#include <linux/fs.h>
230 +#include <linux/stat.h>
231 +#include <linux/errno.h>
232 +#include <asm/segment.h>
233 +
234 +#include <asm/uaccess.h>       /* PTB - when did this arrive in kernel? */
235 +#include <asm/byteorder.h>
236 +#include <linux/wrapper.h>
237 +
238 +#define MAJOR_NR NBD_MAJOR
239 +static int major = MAJOR_NR;
240 +
241 +#include <linux/proc_fs.h>
242 +#include <linux/genhd.h>
243 +#include <linux/hdreg.h>
244 +
245 +#include <linux/file.h>                /* PTB - when did this arrive in kernel? */
246 +
247 +#include <linux/smp_lock.h>
248 +
249 +#include <linux/devfs_fs_kernel.h>
250 +
251 +#include <linux/sysctl.h>
252 +#include <linux/init.h>
253 +#include <linux/kdev_t.h>
254 +#include <linux/buffer_head.h>
255 +#include <linux/completion.h>
256 +
257 +/*                                                       *
258 + * PTB --------------- compatibility ------------------- *
259 + *                   layer starts here.                  *
260 + */
261 +
262 +  /*
263 +   * PTB BH_Protected disappeared somewhere around 2.4.10 but this is
264 +   * still needed for the very rare write local/read remote mode. DOn't
265 +   * worry about it in normal operation!
266 +   */
267 +  #define mark_buffer_protected(rbh) \
268 +      { \
269 +       mark_buffer_dirty (rbh); \
270 +       mark_buffer_uptodate (rbh, 1); \
271 +       refile_buffer (rbh); \
272 +       }
273 +
274 +  /* PTB list interface extensions */
275 +  #define list_head(ptr, type, member) \
276 +  (list_empty(ptr)?NULL:list_entry(((struct list_head *)ptr)->next,type,member))
277 +  #define list_tail(ptr, type, member) \
278 +  (list_empty(ptr)?NULL:list_entry(((struct list_head *)ptr)->prev,type,member))
279 +
280 +  /* PTB for arches without the atomic mask ops (and no smp, I think!)
281 +   * - feel free to correct with assembler
282 +   */
283 +   #ifndef atomic_set_mask
284 +     #define atomic_set_mask(mask, x) (x)->counter |= (mask)
285 +   #endif
286 +   #ifndef atomic_clear_mask
287 +     #define atomic_clear_mask(mask, x) (x)->counter &= ~(mask)
288 +   #endif
289 +
290 +/*                                                       *
291 + * PTB --------------- compatibility ------------------- *
292 + *                   layer ENDS here.                    *
293 + */
294 +
295 +int linux_version_code = LINUX_VERSION_CODE;
296 +
297 +#include <linux/bio.h>
298 +#include <linux/enbd.h>
299 +#include <linux/enbd_ioctl.h>
300 +
301 +/*
302 + * PTB kernel data - 4KB worth
303 + * We need space for nda, nda1, .. nda15, ndb, ndb1, ..
304 + * The index is exactly the minor number.
305 + */
306 +  static int nbd_blksizes[MAX_NBD * NBD_MAXCONN];
307 +  static int nbd_sizes[MAX_NBD * NBD_MAXCONN];
308 +  static __u64 nbd_bytesizes[MAX_NBD * NBD_MAXCONN];
309 +  static int nbd_max_sectors[MAX_NBD * NBD_MAXCONN];
310 +
311 +/*
312 + * PTB our data   - about 3KB
313 + * These are nda, ndb, ndc, ...
314 + * Divide the minor by NBD_MAXCONN to get this index.
315 + */
316 +  static struct nbd_device nbd_dev[MAX_NBD];
317 +  static spinlock_t nbd_lock = SPIN_LOCK_UNLOCKED;
318 +  static struct nbd_md nbd_md;
319 +  static struct nbd_ioctl_stub nbd_remote_ioctl;
320 +
321 +  struct nbd_device * nbd_get(int i) {
322 +      return &nbd_dev[i];
323 +  }
324 +
325 +  #define NBD_FAIL( s ) { \
326 +    NBD_DEBUG(1, s " (result %d).\n" , result ); \
327 +    goto error_out; \
328 +  }
329 +  #define NBD_HARDFAIL( s ) { \
330 +    NBD_ERROR( s " (result %d).\n" , result ); \
331 +    lo->harderror = result; \
332 +    goto hard_error_out; \
333 +  }
334 +
335 +/*
336 + * PTB device parameters. These are module parameters too.
337 + */
338 +
339 +  static int rahead     = NBD_RAHEAD_DFLT;/* PTB - read ahead blocks  */
340 +  static int sync_intvl = NBD_SYNC_INTVL; /* PTB - sync every n secs/Kreqs */
341 +  static int merge_requests               /* PTB - bool, do request coalesce */
342 +                        = NBD_MERGE_REQ_DFLT;
343 +  static int buf_sectors = NBD_MAX_SECTORS;
344 +                                          /* PTB - user bufsize required */
345 +  static int show_errs = 1;              /* PTB - RAID mode? not usually */
346 +  static int direct     = 0;              /* PTB - all opens are O_DIRECT  */
347 +  static int plug = NBD_PLUG_DFLT;
348 +
349 +  static int md5sum = 0;                 /* PTB - use md5summing write proto */
350 +  static int md5_on_threshold = 1000;    /* PTB - reqs reqd to turn md5 on */
351 +  static int md5_off_threshold = 10;     /* PTB - errs reqd to turn md5 off */
352 +
353 +#ifndef NO_BUFFERED_WRITES
354 +  static int buffer_writes = 0;                  /* PTB - act like ramd on write */
355 +#endif         /* NO_BUFFERED_WRITES */
356 +
357 +#if defined(MODULE)
358 +  MODULE_PARM (rahead, "i");
359 +  MODULE_PARM (sync_intvl, "i");
360 +  MODULE_PARM (merge_requests, "i");
361 +  MODULE_PARM (buf_sectors, "i");
362 +  MODULE_PARM (show_errs, "i");
363 +  MODULE_PARM (direct,"i");
364 +  #ifndef NO_BUFFERED_WRITES
365 +    MODULE_PARM (buffer_writes, "i");
366 +  #endif               /* NO_BUFFERED_WRITES */
367 +  MODULE_PARM (major, "i");
368 +  MODULE_PARM (md5sum, "i");
369 +  MODULE_PARM (md5_on_threshold, "i");
370 +  MODULE_PARM (md5_off_threshold, "i");
371 +#endif
372 +
373 +  // PTB This pointer is initialised in nbd_init.
374 +  static struct request_queue * nbd_queue;
375 +
376 +#define NO_BUFFERED_WRITES 1
377 +
378 +/*                                                       *
379 + * PTB --------------- functions ----------------------- *
380 + */
381 +
382 +/*
383 + * PTB 
384 + *       Decode the request type of a request and return it. DOn't we
385 + *       have anywhere else to put this? Yes, in private data. But
386 + *       that's just a pointer to our device data so we don't use it.
387 + *
388 + *       we use the low bit (REQ_RW) of the flags and the first high bit
389 + *       (REQ_NBD) to designate the type of request.
390 + *
391 + *       @req the request to get the type of.
392 + */
393 +
394 +static int
395 +rq_type (struct request *req)
396 +{
397 +        if (req->flags & REQ_SPECIAL)
398 +                return SPECIAL;
399 +
400 +        switch ( ((req->flags & REQ_RW) ?1:0)
401 +               | ((req->flags & REQ_NBD)?2:0)
402 +               ) {
403 +            case 0:
404 +                return READ;
405 +            case 1:
406 +                return WRITE;
407 +            case 2:
408 +                return IOCTL;
409 +            case 3:
410 +                return MD5SUM;
411 +        }
412 +        // PTB report what we can of the strangeness if it is strange
413 +        return (req->flags < 4) ? -1: req->flags;
414 +}
415 +
416 +/*
417 + * PTB code the request type into a request.
418 + *
419 + * This appears to be only used when making an ioctl request and it
420 + * never really escapes from our private area and it doesn't matter too
421 + * much how efficient it is either.
422 + *
423 + * This function marks a request for conventional viewing as
424 + * being of the designated conceptual type. It correspomds to the old
425 + * "type" field in requests.
426 + *
427 + *  @req the request to set the type on
428 + *  @type one of READ, WRITE, etc.
429 + */
430 +static void
431 +set_rq_type (struct request *req, int type)
432 +{
433 +        switch (type) {
434 +            case READ:
435 +                req->flags &= ~(REQ_RW | REQ_NBD | REQ_SPECIAL);
436 +                return;
437 +            case WRITE:
438 +                req->flags &= ~(REQ_NBD | REQ_SPECIAL);
439 +                req->flags |= REQ_RW;
440 +                return;
441 +            case IOCTL:
442 +                req->flags &= ~(REQ_RW | REQ_SPECIAL);
443 +                req->flags |= REQ_NBD;
444 +                return;
445 +            case MD5SUM:
446 +                req->flags &= ~REQ_SPECIAL;
447 +                req->flags |= REQ_RW | REQ_NBD;
448 +                return;
449 +            case SPECIAL:
450 +                req->flags |= REQ_RW | REQ_NBD | REQ_SPECIAL;
451 +                return;
452 +        }
453 +}
454 +
455 +/*
456 + * PTB count number of blocks in a request. This will be an overestimate
457 + * if the number is not an exact multiple. It seems to happen. We 
458 + * guarrantee to return -ve only if the request is invalid.
459 + *
460 + * @req - request we want to count
461 + */
462 +inline long
463 +nr_blks (struct request *req)
464 +{
465 +       unsigned log_sectors_per_blk;
466 +       unsigned sectors_per_blk;
467 +       int size;
468 +       int sectors;
469 +       struct nbd_device *lo;
470 +
471 +       if (!req)
472 +               return -EINVAL;
473 +
474 +        if (rq_type(req) == REQ_SPECIAL) // PTB contains no data
475 +                return 0;
476 +
477 +        lo = req->rq_disk->private_data;
478 +
479 +       log_sectors_per_blk = lo->logblksize - 9;
480 +       sectors_per_blk = 1 << log_sectors_per_blk;
481 +
482 +       sectors = req->nr_sectors;
483 +       size = (sectors + sectors_per_blk - 1) >> log_sectors_per_blk;
484 +
485 +       return size;
486 +}
487 +
488 +/*
489 + * return a temporary buffer containing the (1 or 2 char) device letter.
490 + * This works for i up to 26*26. 0 is "a". The buffer is zero
491 + * terminated.
492 + *
493 + *   @i number to be translated to x[y] alphabetical  form.
494 + */
495 +static char *
496 +device_letter (int i)
497 +{
498 +
499 +       static char buf[3];
500 +       static int cached_i = -1;
501 +
502 +       if (cached_i == i)
503 +               return buf;
504 +
505 +       cached_i = i;
506 +
507 +       if (i < 26) {
508 +               buf[0] = 'a' + i;
509 +               buf[1] = 0;
510 +               return buf;
511 +       }
512 +
513 +       buf[0] = 'a' + i / 26;
514 +       buf[1] = 'a' + i % 26;
515 +       buf[2] = 0;
516 +       return buf;
517 +}
518 +
519 +/*
520 + * PTB auxiliary functions for manipulating the sequence number. Isn't
521 + * there anything private we can use in a request?
522 + *
523 + * This function returns the sequno
524 + *
525 + *   @req  the request to get the sequence number of
526 + */
527 +static int
528 +rq_seqno (struct request *req)
529 +{
530 +       return req->flags >> __REQ_NBDSEQNO;
531 +}
532 +static void
533 +rq_set_seqno (struct request *req, int val)
534 +{
535 +        // PTB preserve first __REQ_NR_BITS bits
536 +       req->flags &= REQ_NBDSEQNO - 1;
537 +        // PTB shift by one more than strictly necessary (see rq_seqno)
538 +       req->flags |= val << __REQ_NBDSEQNO;
539 +}
540 +
541 +/*
542 + *  PTB sync the device. Modes:
543 + *  @arg = 1:  Do it sync
544 + *  @arg = 0:  Do it async
545 + *
546 + *  We can't call sync_dev outside a process context. I don't know why.
547 + *  Death results from a scheduled attempt.
548 + *
549 + *  Call without the semaphore held, as we lock it and call sync_dev.
550 + */
551 +static void
552 +nbd_sync (struct nbd_device *lo, long arg)
553 +{
554 +       struct inode *inode = lo->inode;
555 +       short minor, nbd, islot;
556 +
557 +       islot = atomic_read (&lo->islot);
558 +
559 +       if (!(atomic_read (&lo->flags) & NBD_INITIALISED) || !inode) {
560 +               goto fail;
561 +       }
562 +
563 +       minor = minor (inode->i_rdev);
564 +       nbd = minor >> NBD_SHIFT;
565 +
566 +       // PTB sync_dev is async. fsync_dev is sync.
567 +       switch (arg) {
568 +         case 0: // async
569 +               // PTB 2.5.7 does not have async sync!   FIXME
570 +               break;
571 +         default: // sync
572 +               fsync_bdev (inode->i_bdev);
573 +               invalidate_buffers (mk_kdev (major, nbd << NBD_SHIFT));
574 +               break;
575 +       }
576 +
577 +       return;
578 +
579 +      fail:
580 +}
581 +
582 +static void
583 +nbd_async_sync (struct nbd_device *lo)
584 +{
585 +       nbd_sync (lo, 0);
586 +}
587 +static void
588 +nbd_sync_sync (struct nbd_device *lo)
589 +{
590 +       nbd_sync (lo, 1);
591 +}
592 +
593 +/*
594 + *  Do sync async if we're enabled, sync if we're not.
595 + *
596 + *    @lo the device to maybe sync (sync or async sync!)
597 + */
598 +static void
599 +nbd_maybe_sync_sync (struct nbd_device *lo)
600 +{
601 +
602 +       if ((atomic_read (&lo->flags) & NBD_ENABLED)
603 +        &&  !(atomic_read (&lo->flags) & NBD_REMOTE_INVALID)) {
604 +               nbd_async_sync (lo);
605 +               return;
606 +       }
607 +       nbd_sync_sync (lo);
608 +}
609 +
610 +
611 +
612 +
613 +/*
614 + * PTB - put a request onto the head of a nbd device's queue
615 + *     - presumably having taken it off the kernel's queue first!
616 + *     - We take the queue spinlock.
617 + *
618 + *     @lo      = the device we are on (could we get it from the req?)
619 + *     @req     = the request we shift
620 + *     @irqsave = save and restore irqmask when taking our queue spinlock
621 + */
622 +static void
623 +nbd_enqueue (struct nbd_device *lo, struct request *req)
624 +{
625 +       unsigned long req_blks = nr_blks (req);
626 +
627 +       if (req_blks < 0) {
628 +               short islot = atomic_read (&lo->islot);
629 +               NBD_ERROR ("(%d): invalid req %p. Not touching!\n", islot, req);
630 +               return;
631 +       }
632 +
633 +       /* PTB accounting and nothing more - first, specials */
634 +        if (! (req->flags & REQ_SPECIAL)) {
635 +                // PTB the special req counting semantics relies on 
636 +                // countq not including itself in the count!
637 +                int countq;
638 +                int cmd;
639 +               cmd = rq_data_dir (req);
640 +               atomic_add (req_blks, &lo->requests_in[cmd]);
641 +
642 +                // PTB do we need locks here? Apparently not.
643 +               atomic_inc (&lo->countq[cmd]);
644 +                countq = atomic_read (&lo->countq[cmd]);
645 +
646 +                // PTB the maxes are just noncritical stats
647 +               if (atomic_read (&lo->maxq[cmd]) < countq)
648 +                       atomic_set (&lo->maxq[cmd], countq);
649 +               atomic_inc (&lo->req_in[cmd][req_blks]);
650 +                // PTB the maxes are just noncritical stats
651 +               if (atomic_read (&lo->maxreqblks) < req_blks)
652 +                       atomic_set (&lo->maxreqblks, req_blks);
653 +        }
654 +
655 +       write_lock (&lo->queue_lock);
656 +
657 +        list_add (&req->queuelist, &lo->queue);
658 +
659 +       write_unlock (&lo->queue_lock);
660 +
661 +       wake_up_interruptible (&lo->wq);
662 +
663 +}
664 +
665 +/*
666 + * PTB - remove a request from anywhere in the nbd device general queue 
667 + *     - return 0 for success, -ve for fail
668 + *
669 + *     We need to hold the queue lock when calling this routine.
670 + *     It walks the queue.
671 + *
672 + *     @lo the nbd device 
673 + *     @req the request to be removed
674 + */
675 +static int
676 +nbd_remove (struct nbd_device *lo, struct request *req)
677 +{
678 +       int cmd;
679 +
680 +       if (!req)
681 +               return -EINVAL;
682 +
683 +       list_del_init (&req->queuelist);
684 +
685 +        /* PTB accounting and nothing more */
686 +       cmd = rq_data_dir (req);
687 +        atomic_dec (&lo->countq[cmd]);
688 +       return 0;
689 +}
690 +
691 +/*
692 + *  PTB - Open the device. This is the blkops function.
693 + */
694 +int
695 +nbd_open (struct inode *inode, struct file *file)
696 +{
697 +       int dev;
698 +       struct nbd_device *lo;
699 +       int nbd;
700 +       int part;
701 +       int islot;
702 +       char *devnam;
703 +
704 +       if (!inode && file) {   /* added by ptb for 2.0.35. Necessary? */
705 +               inode = file->f_dentry->d_inode;
706 +       }
707 +       if (!inode) {
708 +               NBD_ERROR ("null inode.\n");
709 +               return -EINVAL;
710 +       }
711 +
712 +       dev = minor (inode->i_rdev);
713 +       nbd = dev >> NBD_SHIFT;
714 +       part = dev - (nbd << NBD_SHIFT);
715 +       islot = part - 1;
716 +
717 +       if (nbd >= MAX_NBD) {
718 +               NBD_ERROR ("too many (%d) whole devices open\n", nbd);
719 +               return -ENODEV;
720 +       }
721 +
722 +       lo = &nbd_dev[nbd];
723 +       devnam = lo->devnam;
724 +
725 +        /* PTB provision for opening for direct i/o - gives mount aid */
726 +        if (file
727 +                && (atomic_read(&lo->flags) & NBD_DIRECT)
728 +                && !(file->f_flags & O_DIRECT)) {
729 +                    /* PTB we set NOFOLLOW to show we did it ! */
730 +                    file->f_flags |= O_DIRECT | O_NOFOLLOW;
731 +        }
732 +
733 +       if (part == 0) {
734 +               /* PTB we have got the whole dev's file or inode for 1st time */
735 +               if (!lo->file || lo->file != file) {
736 +                       lo->file = file;
737 +                        atomic_set (&(&lo->wspeed)->frstj, jiffies);
738 +                        atomic_set (&(&lo->rspeed)->frstj, jiffies);
739 +                        atomic_set (&(&lo->tspeed)->frstj, jiffies);
740 +               }
741 +               if (!lo->inode || lo->inode != inode) {
742 +                       lo->inode = inode;
743 +               }
744 +               if (!(atomic_read (&lo->flags) & NBD_INITIALISED)) {
745 +                       atomic_set_mask (NBD_INITIALISED, &lo->flags);
746 +               }
747 +       }
748 +
749 +       atomic_inc (&lo->refcnt);
750 +
751 +        if (!(atomic_read (&lo->flags) & NBD_VALIDATED)
752 +            && lo->aslot > 0
753 +            && (atomic_read (&lo->flags) & NBD_ENABLED)) {
754 +               NBD_INFO ("partition check on device nd%s\n", lo->devnam);
755 +                check_disk_change(inode->i_bdev);
756 +
757 +                /*
758 +                 * PTB do we set VALIDATED here, or let the kernel call
759 +                 * sequence result in it happening via our removable
760 +                 * device routines? Let's go for the latter option.
761 +                 */
762 +        }
763 +
764 +       return 0;
765 +}
766 +
767 +/*
768 + * PTB - complete a transaction irrefutably by taking it out of the
769 + *     - slot pending position it is in, and reporting end_request to kernel
770 + *
771 + *       We are called without locks because our call to end request
772 + *       will take some sort of lock momentarily and we don't need
773 + *       locks because our request should already be off all queues.
774 + *
775 + *       @slot the nbd_slot on which the req notionally was
776 + *       @req  the poor defenceless kernel request about to be acked
777 + */
778 +void
779 +nbd_commit (struct nbd_slot *slot, struct request *req)
780 +{
781 +
782 +       struct nbd_device *lo = slot->lo;
783 +       unsigned long req_blks = nr_blks (req);
784 +       int cmd;
785 +
786 +       if (req_blks < 0) {
787 +               NBD_ERROR ("corrupted req %p. Not touching with bargepole.\n",
788 +                        req);
789 +               return;
790 +       }
791 +
792 +       list_del_init (&req->queuelist);
793 +
794 +       nbd_end_request_lock (req);
795 +        blk_put_request (req);
796 +
797 +       slot->req_age = 0;
798 +       slot->req -= req_blks;
799 +
800 +        /* PTB accounting and nothing more */
801 +       cmd = rq_data_dir (req);
802 +
803 +       atomic_sub (req_blks, &lo->requests_req[cmd]);
804 +       if (req->errors != 0) {
805 +                /* PTB error exit */
806 +               atomic_add (req_blks, &lo->requests_err);
807 +               slot->err += req_blks;
808 +               return;
809 +       }
810 +
811 +       atomic_add (req_blks, &lo->requests_out[cmd]);
812 +       slot->out += req_blks;
813 +
814 +       if (cmd != WRITE)
815 +                /* PTB everything but a write was easy */
816 +               return;
817 +
818 +       /*
819 +         * PTB now non error case writes
820 +         *
821 +        *     account the 4 cases for a md5sum'd transaction
822 +         */ 
823 +
824 +       switch (slot->flags & (NBD_SLOT_MD5SUM | NBD_SLOT_MD5_OK)) {
825 +
826 +         case NBD_SLOT_MD5SUM | NBD_SLOT_MD5_OK:
827 +               atomic_add (req_blks, &lo->wrequests_5to);      // 11
828 +               atomic_add (req_blks, &lo->wrequests_5so);
829 +               // PTB zero the countdown to turning off md5 as it works
830 +               atomic_set (&lo->wrequests_5co, 0);
831 +               break;
832 +
833 +         case NBD_SLOT_MD5SUM:
834 +               atomic_add (req_blks, &lo->wrequests_5to);      // 10
835 +               atomic_add (req_blks, &lo->wrequests_5wo);
836 +               atomic_inc (&lo->wrequests_5co);
837 +               if (atomic_read (&lo->wrequests_5co) > md5_off_threshold) {
838 +                       atomic_set (&lo->wrequests_5co, 0);
839 +                       // PTB turn off md5summing as it is not successful
840 +                       atomic_clear_mask (NBD_MD5SUM, &lo->flags);
841 +               }
842 +               break;
843 +
844 +         case NBD_SLOT_MD5_OK:
845 +               atomic_add (req_blks, &lo->wrequests_5to);      // 01
846 +               atomic_add (req_blks, &lo->wrequests_5eo);
847 +               atomic_inc (&lo->wrequests_5co);
848 +               if (atomic_read (&lo->wrequests_5co) > md5_off_threshold) {
849 +                       atomic_set (&lo->wrequests_5co, 0);
850 +                       // PTB turn off md5summing as it is errored
851 +                       atomic_clear_mask (NBD_MD5SUM, &lo->flags);
852 +               }
853 +               break;
854 +
855 +         default:
856 +         case 0:
857 +               // PTB nobody asked for a md5 and nobdy gave one back
858 +               atomic_inc (&lo->wrequests_5no);
859 +               if (atomic_read (&lo->wrequests_5no) > md5_on_threshold) {
860 +                       atomic_set (&lo->wrequests_5no, 0);
861 +                       // PTB turn on md5summing every so often
862 +                       atomic_set_mask (NBD_MD5SUM, &lo->flags);
863 +               }
864 +               break;
865 +       }
866 +
867 +       // PTB clear the md5sum indicators from the slot afterwards!
868 +       slot->flags &= ~(NBD_SLOT_MD5SUM | NBD_SLOT_MD5_OK);
869 +
870 +        // PTB we ran out of difficult cases, so return
871 +}
872 +
873 +/*
874 + * PTB - error out a transaction irrefutably by taking it out of the
875 + *     - slot pending position it is in, and reporting end_request to kernel
876 + *
877 + *     We must be called without spinlocks held, as we take it in end req
878 + *
879 + *       @slot the nbd_slot on which the req notionally was
880 + *       @req  the poor defenceless kernel request about to be errored
881 + */
882 +void
883 +nbd_error (struct nbd_slot *slot, struct request *req)
884 +{
885 +       struct nbd_device *lo = slot->lo;
886 +       unsigned long req_blks = nr_blks (req);
887 +       int cmd;
888 +
889 +       if (req_blks < 0) {
890 +               NBD_ERROR ("passed illegal request %p\n", req);
891 +       }
892 +
893 +       req->errors++;
894 +
895 +       /*
896 +         * PTB We don't need the queue spinlock since we don't touch our queue,
897 +        * and we're the only ones working on this slot.
898 +         */
899 +       list_del_init (&req->queuelist);
900 +
901 +       NBD_ALERT ("error out req %p from slot %d!\n", req, slot->i);
902 +
903 +       nbd_end_request_lock (req);
904 +        blk_put_request (req);
905 +
906 +       /* PTB accounting and nothing more */
907 +       cmd = rq_data_dir (req);
908 +       atomic_sub (req_blks, &lo->requests_req[cmd]);
909 +
910 +       slot->in -= req_blks;
911 +       slot->req -= req_blks;
912 +
913 +       slot->req_age = 0;
914 +       slot->err += req_blks;
915 +       atomic_add (req_blks, &lo->requests_err);
916 +}
917 +
918 +/*
919 + * Take a request out of a slot. This must not hold the queuelock on
920 + * entry as we take the queue lock in order to play with the devices
921 + * queue.
922 + *
923 + *  @slot the nbd slot on which to work
924 + *  @req the request
925 + */
926 +static void
927 +nbd_rollback (struct nbd_slot *slot, struct request *req)
928 +{
929 +
930 +       struct nbd_device *lo = slot->lo;
931 +       unsigned long req_blks, flags;
932 +       int seqno;
933 +        struct list_head *pos;
934 +        struct request *xreq;
935 +
936 +       if (atomic_read (&lo->flags) & NBD_SHOW_ERRS) {
937 +               nbd_error (slot, req);
938 +               return;
939 +       }
940 +
941 +       req_blks = nr_blks (req);
942 +
943 +       if (req_blks < 0) {
944 +               NBD_ERROR ("passed illegal request %p\n", req);
945 +               return;
946 +       }
947 +
948 +       list_del_init (&req->queuelist);
949 +
950 +       NBD_ALERT ("rollback req %p from slot %d!\n", req, slot->i);
951 +
952 +        if (! (req->flags & REQ_SPECIAL)) {
953 +               /* PTB accounting */
954 +               slot->in -= req_blks;
955 +               slot->req -= req_blks;
956 +        }
957 +
958 +        seqno = rq_seqno(req);
959 +
960 +        write_lock_irqsave(&lo->queue_lock, flags);
961 +        list_for_each_prev (pos, &lo->queue) {
962 +                xreq = list_entry (pos, struct request, queuelist);
963 +                if (rq_seqno(xreq) > seqno) {
964 +                        break;
965 +                }
966 +        }
967 +        list_add_tail (&req->queuelist, pos);
968 +        write_unlock_irqrestore(&lo->queue_lock, flags);
969 +
970 +}
971 +
972 +/*
973 + * PTB - undo transactions by taking them out of the slot pending
974 + *     - position and replacing them on the generic device queue
975 + *     - NB we do not hold the io request lock or queue sem when
976 + *     -    calling this as we take it internall in nbd_rollback
977 + *
978 + *     @slot the nbd slot to scan
979 + */
980 +static void
981 +nbd_rollback_all (struct nbd_slot *slot)
982 +{
983 +
984 +       struct request *req;
985 +       short count = 0;
986 +
987 +       while (!list_empty (&slot->queue)) {
988 +
989 +               if (count++ > 1000)
990 +                       break;
991 +
992 +               req = list_head (&slot->queue, struct request, queuelist);
993 +
994 +               if (!req)
995 +                       break;
996 +
997 +               nbd_rollback (slot, req);
998 +       }
999 +
1000 +}
1001 +
1002 +/*
1003 + * PTB error out all the requests on a slot
1004 + *     
1005 + *     We must be called without the io spinlock held, as we take it in
1006 + *     nbd_error().
1007 + *
1008 + *     @slot the nbd slot to scan
1009 + */
1010 +static void
1011 +nbd_error_all (struct nbd_slot *slot)
1012 +{
1013 +
1014 +       struct request *req;
1015 +       short count = 0;
1016 +
1017 +       while (!list_empty (&slot->queue)) {
1018 +               if (count++ > 1000)
1019 +                       break;
1020 +               req = list_head (&slot->queue, struct request, queuelist);
1021 +               if (!req)
1022 +                       break;
1023 +               nbd_error (slot, req);
1024 +       }
1025 +}
1026 +
1027 +/*
1028 + * PTB - let a request onto the slot pending position
1029 + *     - Can be called without the spinlock and doesn't take the
1030 + *       spinlock as we  only deal with our  unique slot. If there
1031 + *       were more than one client per slot this woould be a problem
1032 + *       but there aren't so it isn't.
1033 + *
1034 + *       @slot the nbd slot to let the request onto
1035 + *       @req the request to move onto the slot queue
1036 + */
1037 +void
1038 +nbd_accept (struct nbd_slot *slot, struct request *req)
1039 +{
1040 +
1041 +       struct nbd_device *lo = slot->lo;
1042 +       unsigned long req_blks = nr_blks (req);
1043 +       int cmd;
1044 +
1045 +       if (req_blks < 0)
1046 +               return;
1047 +
1048 +        /* PTB accounting and nothing more */
1049 +       cmd = rq_data_dir (req);
1050 +
1051 +       atomic_add (req_blks, &lo->requests_req[cmd]);
1052 +       /* PTB - Note that this really is slot and not lo.
1053 +        */
1054 +       list_add (&req->queuelist, &slot->queue);
1055 +
1056 +       slot->req_age = jiffies;
1057 +       slot->in += req_blks;
1058 +       slot->req += req_blks;
1059 +}
1060 +
1061 +/*
1062 + * PTB - read from userspace to a request buffer. Do it piecewuse
1063 + *     - to cope with clustered requests.
1064 + *     - return number of bytes read
1065 + *
1066 + *     Unfortunately the only way we can return less than the right
1067 + *     number of bytes is when the receiving req does not have the
1068 + *     right number of buffers, because the copy_from_user itself
1069 + *     doesn't tell us.
1070 + */
1071 +static int
1072 +copy_from_user_to_req (struct request *req, char *user, int len)
1073 +{
1074 +
1075 +       unsigned size = 0;
1076 +        struct bio *bio /* = req->bio */;
1077 +
1078 +       /* PTB assume user verified */
1079 +
1080 +        rq_for_each_bio(bio, req) {
1081 +
1082 +            int i;
1083 +            struct bio_vec * bvl;
1084 +
1085 +            bio_for_each_segment(bvl, bio, i) {
1086 +
1087 +                struct page *page       = bvl->bv_page;
1088 +                int offset              = bvl->bv_offset;
1089 +                const unsigned current_size
1090 +                                    = bvl->bv_len;
1091 +               char *buffer;
1092 +                buffer = page_address(page) + offset;
1093
1094 +               copy_from_user (buffer, user + size, current_size);
1095 +
1096 +               size += current_size;
1097 +           }
1098 +       }
1099 +       if (size != len) {
1100 +               NBD_ALERT ("requested %d and only read %d bytes to req %p\n",
1101 +                 len, size, req);
1102 +               NBD_ALERT ("request %p wanted to read user space buffer %p\n",
1103 +                 req, user);
1104 +       }
1105 +       return size;
1106 +}
1107 +
1108 +/*
1109 + * PTB - andres' kernel half of the user-space network handshake, used
1110 + *     - to complete a transaction.
1111 + *     - return 0 for success and -ve for fail.
1112 + *
1113 + *     @slot the nbd slot being acted on
1114 + *
1115 + */
1116 +int
1117 +nbd_ack (struct nbd_slot *slot)
1118 +{
1119 +       struct nbd_reply reply;
1120 +       struct request *req, *xreq;
1121 +       int result = 0;
1122 +
1123 +       void *user;
1124 +       unsigned long req_blks = 1;
1125 +       struct nbd_device *lo = slot->lo;
1126 +       unsigned buflen = 0;
1127 +       unsigned reqlen;
1128 +        int cmd;
1129 +       struct list_head *pos;
1130 +       int count = 0;
1131 +
1132 +       if (!(slot->flags & NBD_SLOT_BUFFERED)) {
1133 +               return -EINVAL;
1134 +       }
1135 +
1136 +       atomic_inc (&lo->cthreads);
1137 +       slot->flags |= NBD_SLOT_RUNNING;
1138 +       slot->cli_age = jiffies;
1139 +
1140 +       user = slot->buffer;
1141 +       copy_from_user ((char *) &reply, (char *) user,
1142 +                       sizeof (struct nbd_reply));
1143 +
1144 +       // PTB we keep tracking the write position in the input buffer
1145 +       buflen += NBD_BUFFER_DATA_OFFSET;
1146 +
1147 +       // PTB save the reply handle (which is an address) as our req
1148 +       memcpy (&req, &reply.handle, sizeof (req));
1149 +
1150 +       xreq = NULL;
1151 +       list_for_each (pos, &slot->queue) {
1152 +               xreq = list_entry (pos, struct request, queuelist);
1153 +               if (count++ > 1000)
1154 +                       break;
1155 +               if (xreq == req)
1156 +                       /* PTB found it */
1157 +                       break;
1158 +       }
1159 +
1160 +       if (xreq != req) {
1161 +
1162 +               if (slot->nerrs++ < 3)
1163 +                       NBD_ALERT ("fatal: Bad handle %p != %p!\n",
1164 +                         req, xreq);
1165 +
1166 +                atomic_dec (&lo->cthreads);
1167 +                slot->flags &= ~NBD_SLOT_RUNNING;
1168 +
1169 +                NBD_ALERT("ignoring ack of req %p which slot does not have\n", 
1170 +                    req);
1171 +
1172 +                /*
1173 +                 * PTB we lie and say success because userspace got through to
1174 +                 * us OK and the req they missed has been rolled back and will
1175 +                 * be retransmitted by the kernel later and elsewhere
1176 +                 */
1177 +                return 0;
1178 +       }
1179 +
1180 +       if (reply.magic != NBD_REPLY_MAGIC) {
1181 +
1182 +               if (slot->nerrs++ < 3)
1183 +                       NBD_ALERT ("Not enough reply magic in %s\n",
1184 +                                  __FUNCTION__ );
1185 +                /*
1186 +                 * PTB returning -EAGAIN causes the client to pause 0.5s 
1187 +                 * and throw its reply away, then return to service. We leave
1188 +                 * any request we have to age and be rolled back.
1189 +                 */
1190 +               return -EAGAIN;
1191 +       }
1192 +
1193 +       if (reply.error > 0 || req->errors > 0) {
1194 +               /* PTB wasn't error++'ed before */
1195 +               req->errors++;
1196 +               if (slot->nerrs++ < 3)
1197 +                       NBD_ALERT ("exited with reply error\n");
1198 +               /* PTB we handle this - it's a repmote error */
1199 +                NBD_FAIL ("remote error on request\n");
1200 +       }
1201 +
1202 +       req_blks = nr_blks (req);
1203 +
1204 +       reqlen = req->nr_sectors;
1205 +       reqlen <<= 9;
1206 +
1207 +       cmd = rq_type (req);
1208 +
1209 +        switch (cmd) {
1210 +
1211 +                unsigned long rcmd;
1212 +                char * arg;
1213 +               int size;
1214 +
1215 +         case READ:
1216 +
1217 +               // PTB We have to copy the buffer bit by bit in
1218 +               // case the request is clustered.
1219 +
1220 +               size =
1221 +                copy_from_user_to_req (req, ((char *) user) + buflen, reqlen);
1222 +               if (size < reqlen) {
1223 +                       NBD_ALERT
1224 +                        ("(%d): copy %dB from user to req %p failed (%d)\n",
1225 +                         slot->i, reqlen, req, size);
1226 +                       // PTB we could try again? We should investigate.
1227 +                       NBD_FAIL
1228 +                        ("exited because of bad copy from user\n");
1229 +                        // PTB FIXME - think we want to discard and retry
1230 +               }
1231 +
1232 +               // PTB we keep tracking the write position in the buffer
1233 +               buflen += size;
1234 +               break;
1235 +
1236 +         case WRITE:
1237 +               /*
1238 +                 * PTB we want to know if the reply is md5summed, and if it is
1239 +                *     whether the md5sum is the same as the one on the
1240 +                *     request. But that's not something we can presently see
1241 +                *     from here as we don't make an md5sum in the kernel.
1242 +                *     So we have to rely on the reply flag from userspace.
1243 +                *     We transmit the information to the slot, as we can't
1244 +                *     keep it on the request.
1245 +                 */
1246 +
1247 +               switch (reply.flags &
1248 +                       (NBD_REPLY_MD5SUM | NBD_REPLY_MD5_OK)) {
1249 +
1250 +                 case NBD_REPLY_MD5SUM | NBD_REPLY_MD5_OK:
1251 +                       /*
1252 +                         * PTB we asked for an md5sum comparison and
1253 +                        * the two matched, so we skipped writing the request
1254 +                         */
1255 +                       slot->flags |= (NBD_SLOT_MD5SUM | NBD_SLOT_MD5_OK); //11
1256 +                       break;
1257 +                 case NBD_REPLY_MD5SUM:
1258 +                       // PTB the two differed, so we wrote the request
1259 +                       slot->flags |= NBD_SLOT_MD5SUM;
1260 +                       slot->flags &= ~NBD_SLOT_MD5_OK;        // 10
1261 +                       break;
1262 +                 case NBD_REPLY_MD5_OK:
1263 +                       // PTB the server refused the md5 request
1264 +                       slot->flags &= ~NBD_SLOT_MD5SUM;
1265 +                       slot->flags |= NBD_SLOT_MD5_OK;         // 01
1266 +                       break;
1267 +                 default:
1268 +                 case 0:
1269 +                       // PTB mobody asked for an md5sum comparison
1270 +                       slot->flags &= ~(NBD_SLOT_MD5SUM | NBD_SLOT_MD5_OK);//00
1271 +                       break;
1272 +               }
1273 +               // PTB now we are all set up to do the accounting in commit etc.
1274 +               break;
1275 +
1276 +          case SPECIAL:
1277 +                // PTB FIXME. Just temporary. 
1278 +               NBD_ALERT ("special req %p on slot %d\n", req, slot->i);
1279 +                req->errors = 0;
1280 +                goto success;
1281 +               break;
1282 +
1283 +
1284 +         case IOCTL:
1285 +
1286 +               if (!(reply.flags & NBD_REPLY_IOCTL))
1287 +                       NBD_ALERT ("ioctl reply to req %p has no ioctl flag\n",
1288 +                                req);
1289 +
1290 +               // PTB the commit should emit the request notification
1291 +
1292 +               rcmd = (long) req->special;
1293 +               arg = req->buffer;
1294 +
1295 +               if (cmd == -1l) {
1296 +                       result = -EINVAL;
1297 +                       NBD_FAIL ("unauthorized remote ioctl\n");
1298 +               }
1299 +
1300 +               if (!(_IOC_DIR (cmd) & _IOC_READ)) {
1301 +                        break;
1302 +                }
1303 +
1304 +               /*
1305 +                 * PTB We saved ioctl size in req .. but only approximately,
1306 +                 * as nr_sectors.
1307 +                 */
1308 +
1309 +               /*
1310 +                 * PTB if we are reading, it should be to the local
1311 +                 * buffer arg, which points at lo->ctldata or other buffer
1312 +                 */
1313 +
1314 +                // PTB we are treating a saved local address or direct val
1315 +               if (req->nr_sectors > 0) {
1316 +                       /*
1317 +                         * PTB sectors is an overestimate.  Should be
1318 +                         * OK as we are reading from the client
1319 +                         * buffer which has plenty of room to spare.
1320 +                         */
1321 +                       int size = req->nr_sectors << 9;
1322 +                       copy_from_user (arg, (char *) user + buflen, size);
1323 +                       buflen += size;
1324 +                        break;
1325 +               }
1326 +
1327 +               break;
1328 +       }                       // PTB eswitch
1329 +        goto success;
1330 +
1331 +      success:
1332 +       slot->nerrs = 0;
1333 +       /*
1334 +         * PTB - completion (or erroring) of transaction.
1335 +        * note that nbd_commit will take a lock to do end_req
1336 +         */
1337 +       nbd_commit (slot, req);
1338 +       atomic_dec (&lo->cthreads);
1339 +       slot->flags &= ~NBD_SLOT_RUNNING;
1340 +       return 0;
1341 +
1342 +      error_out:
1343 +       /* PTB we will next do a client rollback on the slot from userspace.
1344 +        *     Right here we just skip the request. 
1345 +         *     But .. don't error the request. We might have rolled it
1346 +         * back and be referencing it.
1347 +         */
1348 +        if (result != -EAGAIN && result != 0) {
1349 +               req->errors += req_blks;
1350 +               slot->err += req_blks;
1351 +        }
1352 +       result = result < 0 ? result : -ENODEV;
1353 +        // PTB one client thread leaves
1354 +       atomic_dec (&lo->cthreads);
1355 +       slot->flags &= ~NBD_SLOT_RUNNING;
1356 +       return result;
1357 +}
1358 +
1359 +/*
1360 + * PTB - write to userspace from a request buffer. Do it piecewuse
1361 + *     - to cope with clustered requests.
1362 + *     - return number of bytes written
1363 + */
1364 +static int
1365 +copy_to_user_from_req (struct request *req, char *user, int len)
1366 +{
1367 +
1368 +       unsigned size = 0;
1369 +        struct bio *bio /* = req->bio */;
1370 +
1371 +       /* PTB assume user verified */
1372 +
1373 +        rq_for_each_bio(bio, req) {
1374 +
1375 +            int i;
1376 +            struct bio_vec * bvl;
1377 +
1378 +            bio_for_each_segment(bvl, bio, i) {
1379 +
1380 +                struct page *page       = bvl->bv_page;
1381 +                int offset              = bvl->bv_offset;
1382 +                const unsigned current_size
1383 +                                        = bvl->bv_len;
1384 +               char *buffer;
1385 +                buffer = page_address(page) + offset;
1386
1387 +               copy_to_user (user + size, buffer, current_size);
1388 +
1389 +               size += current_size;
1390 +            }
1391 +
1392 +       }
1393 +       return size;
1394 +}
1395 +
1396 +/*
1397 + * PTB do the devices three speed updates
1398 + *
1399 + *  @lo  the nbd device to do the update on
1400 + */
1401 +static void
1402 +nbd_set_speed (struct nbd_device *lo)
1403 +{
1404 +        int r, w, t;
1405 +        struct nbd_speed *wspd = &lo->wspeed;
1406 +        struct nbd_speed *rspd = &lo->rspeed;
1407 +        struct nbd_speed *tspd = &lo->tspeed;
1408 +       w = atomic_read (&lo->requests_in[WRITE]);
1409 +       wspd->update (wspd, w);
1410 +       r = atomic_read (&lo->requests_in[READ]);
1411 +       rspd->update (rspd, r);
1412 +        t = w + r;
1413 +       tspd->update (tspd, t);
1414 +}
1415 +
1416 +
1417 +
1418 +/*
1419 + * PTB - andres' kernel half of the userspace networking. This part
1420 + *     - initiates the transaction by taking a request off the generic
1421 + *     - device queue and placing it in the slots pending position.
1422 + *     - I believe we return 0 for success and -ve for fail.
1423 + *     - timeo is the number of jiffies we are prepared to wait
1424 + *
1425 + *     @slot the nbd slot to act on.
1426 + */
1427 +int
1428 +nbd_get_req (struct nbd_slot *slot)
1429 +{
1430 +       struct nbd_request request;
1431 +       struct request *req;
1432 +       int result = 0;
1433 +       static atomic_t count;
1434 +       unsigned start_time = jiffies;
1435 +       struct nbd_device *lo = slot->lo;
1436 +       unsigned timeout = lo->req_timeo * HZ;
1437 +       int islot = slot->i;
1438 +       // PTB for the new timezone field in requests 
1439 +       extern struct timezone sys_tz;
1440 +        struct timeval time;
1441 +       unsigned long flags;
1442 +        struct nbd_seqno * seqno_out = &lo->seqno_out;
1443 +
1444 +       atomic_inc (&lo->cthreads);     // PTB - client thread enters
1445 +       slot->flags |= NBD_SLOT_RUNNING;
1446 +       slot->cli_age = jiffies;
1447 +
1448 +       if (!(slot->flags & NBD_SLOT_BUFFERED)) {
1449 +               NBD_FAIL ("Our slot has no buffer");
1450 +       }
1451 +
1452 +       atomic_set (&lo->islot, islot);
1453 +
1454 +       if (!list_empty (&slot->queue)) {
1455 +               NBD_FAIL ("impossible! already treating one request");
1456 +               // PTB we do a nontrivial rollback from the user daemon 
1457 +       }
1458 +       if (!slot->file) {
1459 +               result = -EBADF;
1460 +               NBD_FAIL ("Our slot has been nofiled");
1461 +       }
1462 +       if (!(atomic_read (&lo->flags) & NBD_ENABLED)) {
1463 +               result = -ENODEV;
1464 +               NBD_FAIL ("Our slot has been vamooshed");
1465 +       }
1466 +
1467 +       atomic_inc (&lo->cwaiters);
1468 +       slot->flags |= NBD_SLOT_WAITING;
1469 +
1470 +       // PTB take spinlock in order to examine queue
1471 +       // we need to protect ourselves against the request fn too
1472 +       read_lock_irqsave (&lo->queue_lock, flags);
1473 +       atomic_dec (&lo->cwaiters);
1474 +       slot->flags &= ~NBD_SLOT_WAITING;
1475 +
1476 +       // PTB - now spin until request arrives to treat 
1477 +       while (slot->file && list_empty (&lo->queue)) {
1478 +
1479 +               static int nbd_clr_sock (struct nbd_slot *slot); // forward decl
1480 +               int siz;
1481 +                int time_left = start_time + timeout - jiffies;
1482 +
1483 +               read_unlock_irqrestore (&lo->queue_lock, flags);
1484 +
1485 +                // PTB one client thread goes to sleep
1486 +               atomic_inc (&lo->cwaiters);
1487 +               slot->flags |= NBD_SLOT_WAITING;
1488 +
1489 +               interruptible_sleep_on_timeout (&lo->wq, time_left);
1490 +
1491 +               slot->flags &= ~NBD_SLOT_WAITING;
1492 +                // PTB one client thread reactivates
1493 +               atomic_dec (&lo->cwaiters);
1494 +               atomic_inc (&count);
1495 +
1496 +               // PTB Have to take the spinlock again to check at the queue
1497 +               atomic_inc (&lo->cwaiters);
1498 +               slot->flags |= NBD_SLOT_WAITING;
1499 +               // we need to protect ourselves against the request fn too
1500 +               read_lock_irqsave (&lo->queue_lock, flags);
1501 +               atomic_dec (&lo->cwaiters);
1502 +               slot->flags &= ~NBD_SLOT_WAITING;
1503 +
1504 +               // PTB fail for recheck if we are inactive too long 
1505 +
1506 +                time_left = start_time + timeout - jiffies;
1507 +               if (time_left > 0 || !list_empty (&lo->queue))
1508 +                        continue;
1509 +
1510 +                // PTB bad. timeout with nothing on queue. Error out.
1511 +               result = -ETIME;
1512 +
1513 +               // PTB we will exit with fail, so up spinlock now
1514 +               read_unlock_irqrestore (&lo->queue_lock, flags);
1515 +
1516 +               siz = lo->blksize + sizeof (struct nbd_request);
1517 +               // PTB verify the buffer is still OK - holds one block 
1518 +               if (access_ok(VERIFY_WRITE,slot->buffer,siz))
1519 +                        goto error_out;
1520 +
1521 +                // PTB buffer is invalid
1522 +               result = -EINVAL;
1523 +
1524 +               // PTB clr_sock takes both the io lock and the spinlock
1525 +               nbd_clr_sock (slot);
1526 +               NBD_FAIL ("Our process has died or lost its buffer");
1527 +
1528 +               /*
1529 +                 * PTB we may do a rollback from the user daemon here
1530 +                * but it'll be trivial - without effect - as we don't
1531 +                * have a request in our slot to treat.
1532 +                 */
1533 +               goto error_out;
1534 +
1535 +       } // end while loop
1536 +
1537 +       // PTB we still have the (read) spinlock here
1538 +
1539 +       if (!(atomic_read (&lo->flags) & NBD_ENABLED)) {
1540 +               read_unlock_irqrestore (&lo->queue_lock, flags);
1541 +               result = -ENODEV;
1542 +               NBD_FAIL ("Our slot vaporized while we slept!");
1543 +       }
1544 +       if (!slot->file) {
1545 +               read_unlock_irqrestore (&lo->queue_lock, flags);
1546 +               result = -EBADF;
1547 +               NBD_FAIL ("Our slot nofiled itself while we slept!");
1548 +       }
1549 +       if (!list_empty (&slot->queue)) {
1550 +               read_unlock_irqrestore (&lo->queue_lock, flags);
1551 +               result = -EINVAL;
1552 +               NBD_FAIL ("impossible! already treating one request");
1553 +               // PTB we do a nontrivial rollback from the user daemon 
1554 +       }
1555 +
1556 +       // PTB now relinquish the read lock and try for the write lock
1557 +       read_unlock_irqrestore (&lo->queue_lock, flags);
1558 +
1559 +       write_lock_irqsave (&lo->queue_lock, flags);
1560 +       // PTB got the write lock
1561 +
1562 +       if (list_empty (&lo->queue)) {
1563 +               write_unlock_irqrestore (&lo->queue_lock, flags);
1564 +               // PTB - somebody else did it while we waited on spinlock. OK 
1565 +               result = -EINVAL;
1566 +               NBD_FAIL ("ho hum beaten to the punch");
1567 +               // PTB we may do a trivial rollback from the user daemon 
1568 +       }
1569 +
1570 +       // PTB cli/sti here looks unnec. hardware interrupts return here 
1571 +       // AMARIN begin uninterruptible code 
1572 +
1573 +       // PTB we have the (write) spinlock
1574 +
1575 +       // PTB oldest=last element in queue 
1576 +       req = list_tail (&lo->queue, struct request, queuelist);
1577 +
1578 +       // PTB this is where we free the req from our queue. We need to be
1579 +       // holding our spinlock at this point
1580 +
1581 +       // PTB - must succeed as have the spinlock 
1582 +       result = nbd_remove (lo, req);
1583 +       // PTB now holding irqs off in nbd_remove 
1584 +
1585 +       // AMARIN end uninterruptable code 
1586 +       // PTB uh - maybe cli/sti is needed? interrupts can muck the queue?
1587 +       //        - Nah! I have left them enabled so we can see any errors.
1588 +
1589 +       write_unlock_irqrestore (&lo->queue_lock, flags);
1590 +
1591 +       request.magic = NBD_REQUEST_MAGIC;
1592 +       request.flags = 0;
1593 +
1594 +       switch (rq_type (req)) {
1595 +
1596 +               unsigned long cmd;
1597 +               char *arg;
1598 +               size_t size;
1599 +
1600 +         case IOCTL:
1601 +
1602 +               request.type = IOCTL;
1603 +
1604 +               // PTB this is our special ioctl kernel request
1605 +
1606 +               cmd = (unsigned long) req->special;
1607 +               arg = req->buffer;
1608 +               size = req->nr_sectors << 9;
1609 +
1610 +               // PTB the arg was a literal
1611 +
1612 +               request.len = 0;
1613 +               // PTB we are in get_req, transferring stored ioctl
1614 +               if ((_IOC_DIR (cmd) & _IOC_READ) && size > 0) {
1615 +                       // PTB if len is +ve we copy to the user buffer later
1616 +                        request.len = size;
1617 +               } 
1618 +               // PTB we store the weirded ioctl id.
1619 +               // PTB Yes, this composition is our private invention.
1620 +               request.from = (((__u64) cmd) << 32)
1621 +                    // PTB really want this to go to a 64 bit request.special
1622 +                    | ((__u64) (unsigned long) arg);
1623 +               break;
1624 +
1625 +         case READ:
1626 +         case WRITE:
1627 +
1628 +               request.type = rq_data_dir (req);
1629 +               request.from = req->sector;
1630 +               request.from <<= 9;
1631 +               request.len = req->nr_sectors;
1632 +               request.len <<= 9;
1633 +               if (atomic_read (&lo->flags) & NBD_MD5SUM) {
1634 +                       // PTB set the please do md5sum flag on the request
1635 +                       request.flags |= NBD_REQUEST_MD5SUM;
1636 +               }
1637 +               break;
1638 +
1639 +          case MD5SUM:
1640 +                break;
1641 +
1642 +          case SPECIAL:
1643 +               request.type = SPECIAL;
1644 +               request.len = req->nr_sectors;
1645 +               request.len <<= 9;
1646 +               request.from = req->sector;
1647 +               request.from <<= 9;
1648 +                if (rq_data_dir (req) == WRITE)
1649 +                        request.flags |= NBD_REQUEST_SPECIALRW;
1650 +                request.special = (typeof(request.special))req->special;
1651 +                break;
1652 +
1653 +         default:
1654 +               NBD_ALERT ("received unknown req %p type %#x\n",
1655 +                          req, rq_type (req));
1656 +               break;
1657 +       }
1658 +
1659 +       request.seqno = seqno_out->calc(seqno_out, rq_seqno (req));
1660 +
1661 +       /*
1662 +         * PTB we should here erase the extra seqno info in the request
1663 +         * so that on error or on ack the kernel can use the right internal
1664 +         * array, but I'll erase it in the ack function instead
1665 +         */
1666 +
1667 +       do_gettimeofday (&time);
1668 +        request.time = time.tv_sec;
1669 +        request.time *= 1000000;
1670 +        request.time += time.tv_usec;
1671 +        request.zone = sys_tz.tz_minuteswest;
1672 +
1673 +       // PTB tz_dsttime = 0 always in linux
1674 +
1675 +       memcpy (&request.handle, &req, sizeof (request.handle));
1676 +
1677 +       copy_to_user (slot->buffer, (char *) &request, sizeof (request));
1678 +
1679 +       switch (request.type) {
1680 +
1681 +               int err;
1682 +                char * arg;
1683 +
1684 +         case READ:
1685 +               break;
1686 +
1687 +         case IOCTL:
1688 +               if (request.len <= 0)
1689 +                        break; // PTB presumably nothing to do
1690 +               arg = (char *) slot->buffer + NBD_BUFFER_DATA_OFFSET;
1691 +               copy_to_user (arg, req->buffer, request.len);
1692 +               break;
1693 +
1694 +         case WRITE:
1695 +               arg = (char *) slot->buffer + NBD_BUFFER_DATA_OFFSET;
1696 +               err = copy_to_user_from_req (req, arg, request.len);
1697 +               if (err >= request.len)
1698 +                        break; // OK
1699 +               // PTB buffer had missing BHSs
1700 +               NBD_ERROR ("req %p offered %d bytes of %d for copy to user\n",
1701 +                       req, result, request.len);
1702 +               // PTB this request is badly damaged. We had better shoot it.
1703 +               if (req && req->errors == 0) {
1704 +                       req->errors++;
1705 +                       nbd_end_request_lock (req);
1706 +                        blk_put_request (req);
1707 +               }
1708 +               NBD_FAIL ("kernel failed to keep req while we copied from it");
1709 +               break;
1710 +          case MD5SUM:
1711 +                break;
1712 +          case SPECIAL:
1713 +                // PTB temporary. We do not treat specials at the moment.
1714 +               req->errors = 0;
1715 +                break;
1716 +          default:
1717 +               NBD_ERROR ("req %p was type %#x\n", req, rq_type(req));
1718 +               NBD_FAIL ("unknown req type");
1719 +                break;
1720 +       }
1721 +
1722 +       /*
1723 +         * PTB nbd_accept does not take spinlock and does not need to as
1724 +        * the req is already free of the shared queue and only needs
1725 +        * to be placed on the unique slot queue.
1726 +         */
1727 +
1728 +       nbd_accept (slot, req);
1729 +
1730 +       atomic_dec (&lo->cthreads);     // PTB - client thread leaves normally 
1731 +       slot->flags &= ~NBD_SLOT_RUNNING;
1732 +
1733 +       return 0;
1734 +
1735 +      error_out:
1736 +       // PTB accounting - a fail to get a request is not an errored request 
1737 +       atomic_dec (&lo->cthreads);     // PTB - client thread leaves abnormally 
1738 +       slot->flags &= ~NBD_SLOT_RUNNING;
1739 +       result = result < 0 ? result : -ENODEV;
1740 +
1741 +       return result;
1742 +}
1743 +
1744 +/*
1745 + * PTB error out the pending requests on the kernel queue
1746 + * We have to be called WITHOUT the io request lock held.
1747 + * We sleep imbetween clearing each request, for "safety".
1748 + *
1749 + *   @lo the nbd device to scan
1750 + */
1751 +static int
1752 +nbd_clr_kernel_queue (struct nbd_device *lo)
1753 +{
1754 +
1755 +       int count = 0;
1756 +       unsigned long flags;
1757 +        request_queue_t *q = lo->q;
1758 +
1759 +       spin_lock_irqsave (q->queue_lock, flags);
1760 +
1761 +       while (! blk_queue_empty(q) && count++ < 1000) {
1762 +               struct request *req;
1763 +                req = elv_next_request(q);
1764 +               if (!req) {     // PTB impossible
1765 +                       spin_unlock_irqrestore (q->queue_lock, flags);
1766 +                       NBD_ALERT
1767 +                        ("impossible! kernel queue empty after tested nonemty!\n");
1768 +                       goto fail;
1769 +               }
1770 +               blkdev_dequeue_request (req);
1771 +               spin_unlock_irqrestore (q->queue_lock, flags);
1772 +                if (!req->errors)
1773 +                       req->errors++;
1774 +               schedule ();
1775 +               nbd_end_request_lock (req);
1776 +                blk_put_request (req);
1777 +               spin_lock_irqsave (q->queue_lock, flags);
1778 +       }
1779 +       spin_unlock_irqrestore (q->queue_lock, flags);
1780 +       goto success;
1781 +
1782 +      fail:
1783 +       /* PTB fall thru */
1784 +      success:
1785 +       NBD_ALERT ("removed %d requests\n", count);
1786 +       return count;
1787 +
1788 +}
1789 +
1790 +/*
1791 + * PTB error out the pending requests on the nbd queue and kernel queue
1792 + * Note that we take the queue spinlock for this
1793 + *
1794 + *   @lo the nbd device to scan
1795 + */
1796 +static int
1797 +nbd_clr_queue (struct nbd_device *lo)
1798 +{
1799 +       int count = 0;
1800 +
1801 +       while (count < 1000) {
1802 +
1803 +               struct request *req;
1804 +               unsigned long req_blks = 1;
1805 +
1806 +                // PTB cannot allow new requests via interrupts
1807 +               write_lock (&lo->queue_lock);
1808 +               if (list_empty (&lo->queue)) {
1809 +                       write_unlock(&lo->queue_lock);
1810 +                       break;
1811 +               }
1812 +               req = list_head (&lo->queue, struct request, queuelist);
1813 +                if (!req) {
1814 +                       write_unlock(&lo->queue_lock);
1815 +                       break;
1816 +                }
1817 +
1818 +               req_blks = nr_blks (req);
1819 +
1820 +               req->errors += req_blks + 1;
1821 +               atomic_add (req_blks, &lo->requests_err);
1822 +
1823 +               /* PTB - must succeed as have the spinlock */
1824 +               nbd_remove (lo, req);
1825 +               /* PTB now hold irqs off in nbd_remove */
1826 +               write_unlock(&lo->queue_lock);
1827 +               count++;
1828 +
1829 +               nbd_end_request_lock (req);
1830 +                blk_put_request (req);
1831 +
1832 +       }
1833 +       NBD_ALERT ("unqueued %d reqs\n", count);
1834 +       return count;
1835 +}
1836 +
1837 +/*
1838 + * PTB do under alt spinlock - we take the lo queue_lock oursekves.
1839 + * We take all requests off the alt queue to which they've been
1840 + * diverted and put them on the devices normal queue, where they will
1841 + * then be treated in the normal course of events. They were diverted
1842 + * to the alt queue after we received a SPECIAL, and they're being
1843 + * released now that we've treated all the extant reqs.
1844 + *
1845 + *   @lo the nbd device being treated
1846 + */ 
1847 +static int
1848 +nbd_requeue (struct nbd_device *lo)
1849 +{
1850 +       int count = 0;
1851 +
1852 +       while (count < 1000) {
1853 +
1854 +               struct request *req;
1855 +
1856 +               // PTB cannot allow new requests via interrupts
1857 +               if (list_empty (&lo->altqueue)) {
1858 +                       break;
1859 +               }
1860 +               req = list_tail (&lo->altqueue, struct request, queuelist);
1861 +               if (!req)
1862 +                       break;
1863 +
1864 +               // PTB heisenbug? without these list_del oopses on null deref
1865 +               if (req->queuelist.prev == NULL) {
1866 +                       NBD_ALERT ("req %p has 0 prev ptr! Abort\n", req);
1867 +                       break;
1868 +               }
1869 +               if (req->queuelist.next == NULL) {
1870 +                       NBD_ALERT ("req %p has 0 next ptr! Abort\n", req);
1871 +                       break;
1872 +               }
1873 +               /* PTB - must succeed as have the spinlock */
1874 +               list_del_init (&req->queuelist);
1875 +               /* PTB now hold irqs off in nbd_remove */
1876 +               count++;
1877 +
1878 +               nbd_enqueue (lo, req);
1879 +
1880 +       }
1881 +       return count;
1882 +}
1883 +
1884 +
1885 +#undef NBD_FAIL
1886 +#define NBD_FAIL( s... ) { \
1887 +  NBD_ERROR( s); printk("\n"); \
1888 +  goto error_out; \
1889 +}
1890 +
1891 +#ifndef NO_BUFFERED_WRITES
1892 +  /*
1893 +   * Magic function from rd.c that we hope saves a buffer head
1894 +   * permanently somewhere in the kernel VM system.
1895 +   */
1896 +static int
1897 +buffered_write_pagecache_IO (struct buffer_head *sbh, int nbd)
1898 +{
1899 +       struct address_space *mapping;
1900 +       unsigned long index;
1901 +       int offset, size, err;
1902 +       struct nbd_device *lo = &nbd_dev[nbd];
1903 +       err = 0;
1904 +
1905 +       // PTB we need to save the /dev/nda inode
1906 +       if (!lo->inode) {
1907 +               err = -ENODEV;
1908 +               goto out;
1909 +       }
1910 +       mapping = lo->inode->i_mapping;
1911 +
1912 +       // PTB index appears to be the page number
1913 +       index = sbh->b_rsector >> (PAGE_CACHE_SHIFT - 9);
1914 +       // PTB offset is in bytes, and says where in the page the sector starts
1915 +       offset = (sbh->b_rsector << 9) & ~PAGE_CACHE_MASK;
1916 +       // PTB well, an abbreviation for the buffer size, in bytes
1917 +       size = sbh->b_size;
1918 +
1919 +       do {
1920 +               // PTB we mark each page that we should write to Uptodate
1921 +
1922 +               int count;
1923 +               struct page **hash;
1924 +               struct page *page;
1925 +               char *src, *dst;
1926 +
1927 +               int unlock = 0;
1928 +
1929 +               // PTB ummm, how much of the page is left to traverse
1930 +               count = PAGE_CACHE_SIZE - offset;
1931 +               // PTB reduce it to how much we actually need to traverse
1932 +               if (count > size)
1933 +                       count = size;
1934 +               // PTB say NOW? that we have traversed what we want of the page
1935 +               size -= count;
1936 +
1937 +               hash = page_hash (mapping, index);
1938 +               page = __find_get_page (mapping, index, hash);
1939 +
1940 +               if (!page) {
1941 +                       // PTB we get to make a new page
1942 +                       page = grab_cache_page (mapping, index);
1943 +                       if (!page) {
1944 +                               // PTB failed to get new page
1945 +                               err = -ENOMEM;
1946 +                               goto out;
1947 +                       }
1948 +                       // PTB magic
1949 +                       if (!Page_Uptodate (page)) {
1950 +                               memset (kmap (page), 0, PAGE_CACHE_SIZE);
1951 +                               kunmap (page);
1952 +                               SetPageUptodate (page);
1953 +                       }
1954 +                       // PTB the new page is locked. We need to unlock it later
1955 +                       unlock = 1;
1956 +               }
1957 +
1958 +               // PTB prepare already for next page
1959 +               index++;
1960 +
1961 +               // PTB set up for copy
1962 +               dst = kmap (page);
1963 +               dst += offset;
1964 +               src = bh_kmap (sbh);
1965 +
1966 +               // PTB prepare for next round
1967 +               offset = 0;
1968 +
1969 +               // PTB do a copy
1970 +               memcpy (dst, src, count);
1971 +
1972 +               kunmap (page);
1973 +               bh_kunmap (sbh);
1974 +
1975 +               if (unlock) {
1976 +                       UnlockPage (page);
1977 +               }
1978 +               SetPageDirty (page);
1979 +               __free_page (page);
1980 +
1981 +       } while (size > 0);
1982 +
1983 +      out:
1984 +       return err;
1985 +
1986 +}
1987 +static int
1988 +buffered_write (struct request *req)
1989 +{
1990 +
1991 +       struct buffer_head *bh;
1992 +       int dev = minor (req->rq_dev);
1993 +       int nbd = dev >> NBD_SHIFT;
1994 +       int err = 0;
1995 +
1996 +       // PTB go through and copy and protect the written buffers
1997 +       for (bh = req->bh; bh; bh = bh->b_reqnext) {
1998 +               struct buffer_head *rbh;
1999 +               rbh =
2000 +                getblk (bh->b_rdev, bh->b_rsector / (bh->b_size >> 9),
2001 +                        bh->b_size);
2002 +               if (bh != rbh) {
2003 +                       char *bdata = bh_kmap (bh);
2004 +                       memcpy (rbh->b_data, bdata, rbh->b_size);
2005 +                       NBD_ALERT ("got new bh sector %lu on write\n",
2006 +                                  bh->b_rsector);
2007 +               }
2008 +               bh_kunmap (bh);
2009 +               mark_buffer_protected (rbh);    // PTB equals dirty, uptodate
2010 +               err = buffered_write_pagecache_IO (bh, nbd);
2011 +               if (err < 0) {
2012 +                       break;
2013 +               }
2014 +               brelse (rbh);
2015 +       }
2016 +       return err;
2017 +}
2018 +
2019 +#endif         /* NO_BUFFERED_WRITES */
2020 +
2021 +/* 
2022 + * PTB check if the device is read only according to int flags
2023 + *
2024 + *   @lo the nbd device to be checked
2025 + */
2026 +static int
2027 +nbd_read_only(struct nbd_device *lo) {
2028 +        return (atomic_read(&lo->flags) & NBD_READ_ONLY) != 0;
2029 +}
2030 +/*
2031 + * PTB set the device readonly (or not)
2032 + *
2033 + *   @lo the nbd device to be set up
2034 + *   @ro 1 for read only, 0 for read write.
2035 + */
2036 +static void
2037 +nbd_set_read_only(struct nbd_device * lo, int ro) {
2038 +
2039 +        if (ro != 0) {
2040 +                atomic_set_mask (NBD_READ_ONLY, &lo->flags);
2041 +        } else {
2042 +               atomic_clear_mask (NBD_READ_ONLY, &lo->flags);
2043 +       }
2044 +
2045 +        // PTB which device really does not matter. We do the checking.
2046 +        set_disk_ro (lo->disk, ro != 0);
2047 +}
2048 +
2049 +/*
2050 + * PTB - kernel function to take reqs off the kernel queue. Runs with
2051 + * io lock held. This is the "request function".
2052 + */
2053 +static void
2054 +do_nbd_request (request_queue_t * q)
2055 +{
2056 +       struct request *req;
2057 +       unsigned long flags;
2058 +
2059 +       while (! blk_queue_empty(q)) {
2060 +
2061 +               struct nbd_device *lo;
2062 +
2063 +                req = elv_next_request(q);
2064 +
2065 +               lo = req->rq_disk->private_data;
2066 +
2067 +                /* PTB - one kernel thread enters */
2068 +               atomic_inc (&lo->kthreads);
2069 +
2070 +               if (atomic_read (&lo->kthreads) > atomic_read (&lo->kmax))
2071 +                       atomic_set (&lo->kmax, atomic_read (&lo->kthreads));
2072 +
2073 +               if (!lo->inode || !lo->file) {
2074 +                       NBD_FAIL ("Request when device not ready.");
2075 +               }
2076 +
2077 +               if (rq_data_dir (req) == WRITE && nbd_read_only(lo)) {
2078 +                       NBD_FAIL ("write on read-only device");
2079 +               }
2080 +               flags = atomic_read (&lo->flags);
2081 +               if (!(flags & NBD_INITIALISED)) {
2082 +                       NBD_FAIL ("device not initialised.");
2083 +               }
2084 +               if (!(flags & NBD_ENABLED)) {
2085 +                       NBD_FAIL ("device not enabled.");
2086 +               }
2087 +               if (flags & NBD_REMOTE_INVALID) {
2088 +                       NBD_FAIL ("remote device invalidated.");
2089 +               }
2090 +               if (req->sector + req->nr_sectors > lo->sectors) {
2091 +                       NBD_FAIL ("overrange request");
2092 +               }
2093 +               if (req->sector < 0) {
2094 +                       NBD_FAIL ("underrange request");
2095 +               }
2096 +               if (req->rq_disk->major != major) {
2097 +                       NBD_FAIL ("request for wrong major");
2098 +               }
2099 +               req->errors = 0;
2100 +               blkdev_dequeue_request (req);
2101 +
2102 +                // PTB in 2.5 we can release the iolock briefly here
2103 +                spin_unlock_irq(q->queue_lock);
2104 +
2105 +                if (req->flags & REQ_SPECIAL) {
2106 +                        // PTB temporary successful end here for SPECIALS
2107 +
2108 +                        // PTB we want to attach it to the device and ack later
2109 +                       nbd_enqueue (lo, req);
2110 +                        // PTB block further reqs until these have drained
2111 +                        write_lock(&lo->altqueue_lock);
2112 +                        // PTB do not touch this flag without this lock
2113 +                        if (atomic_read(&lo->countq[READ])
2114 +                          + atomic_read(&lo->countq[WRITE]) > 0) {
2115 +                            atomic_set_mask(NBD_QBLOCKED, &lo->flags);
2116 +                        }
2117 +                        write_unlock(&lo->altqueue_lock);
2118 +                       goto accounting;
2119 +                }
2120 +
2121 +               // PTB we are the only reader and writer of lo->seqno
2122 +               if (rq_data_dir (req) == WRITE && rq_seqno (req) == 0) {
2123 +                       // PTB it is a new request never seen before
2124 +                        struct nbd_seqno * seqno_out = &lo->seqno_out;
2125 +                        seqno_out->inc(seqno_out);
2126 +                       /*
2127 +                         * PTB we have to be careful to change this back before
2128 +                        * giving it back to the kernel, as the kernel uses it.
2129 +                        * We patch it back again in nbd_end_request.
2130 +                         */
2131 +                       rq_set_seqno (req, seqno_out->get(seqno_out));
2132 +               }
2133 +
2134 +                // if BLOCK is set divert requests to alt queue
2135 +                write_lock(&lo->altqueue_lock);
2136 +                if (atomic_read(&lo->flags) & NBD_QBLOCKED) {
2137 +                        list_add (&req->queuelist, &lo->altqueue);
2138 +                        write_unlock(&lo->altqueue_lock);
2139 +                       goto accounting;
2140 +                }
2141 +                write_unlock(&lo->altqueue_lock);
2142 +
2143 +               // PTB normal sequence is to queue request locally
2144 +               nbd_enqueue (lo, req);
2145 +               goto accounting;
2146 +
2147 +             accounting:
2148 +               atomic_dec (&lo->kthreads);
2149 +                // PTB regain the iolock for another turn
2150 +                spin_lock_irq(q->queue_lock);
2151 +               continue;       // PTB next request
2152 +
2153 +             error_out:
2154 +               // PTB can rely on req being nonnull here
2155 +               NBD_ALERT ("ending req %p with prejudice\n", req);
2156 +               req->errors++;
2157 +               blkdev_dequeue_request (req);
2158 +                spin_unlock_irq(q->queue_lock);
2159 +
2160 +               nbd_end_request_lock (req);
2161 +                blk_put_request (req);
2162 +
2163 +                // PTB more accounting
2164 +               if (lo) {
2165 +                       int req_blks = nr_blks (req);
2166 +                       atomic_add (req_blks, &lo->requests_err);
2167 +                       atomic_dec (&lo->kthreads);
2168 +               } else {
2169 +                        NBD_ALERT("failed to account one orphan errored req\n");
2170 +                }
2171 +                // PTB regain the queue lock for another turn
2172 +                spin_lock_irq(q->queue_lock);
2173 +                continue;
2174 +       }
2175 +        return;
2176 +}
2177 +
2178 +/*
2179 + * PTB pair of helpful additional functions, only good for 1 bit in the
2180 + * mask, however. Modify if you want more.
2181 + *
2182 + *   @a the atomic element's address
2183 + *   @mask the integer with one bit set in the position that we want to test
2184 + *         and set, or clear
2185 + */
2186 +static int
2187 +atomic_test_and_set_mask (atomic_t * a, unsigned mask)
2188 +{
2189 +       int i = ffs (mask);
2190 +       if (!i)
2191 +               return -EINVAL;
2192 +                // PTB gahhhh ...
2193 +        #ifdef __LITTLE_ENDIAN
2194 +               return test_and_set_bit (i - 1, (unsigned long *)&a->counter);
2195 +        #else
2196 +                #ifndef __BIGENDIAN
2197 +                #error help, I only know about bigendian or littlendian machines
2198 +                #endif
2199 +               return test_and_set_bit
2200 +                    (i - 1 + (sizeof(long)-sizeof(a->counter))*8,
2201 +                        (unsigned long *)&a->counter);
2202 +        #endif
2203 +}
2204 +static int
2205 +atomic_test_and_clear_mask (atomic_t * a, unsigned mask)
2206 +{
2207 +       int i = ffs (mask);
2208 +       if (!i)
2209 +               return 0;
2210 +                // PTB gahhhh ...
2211 +        #ifdef __LITTLE_ENDIAN
2212 +               return test_and_clear_bit (i - 1, (unsigned long *)&a->counter);
2213 +        #else
2214 +                #ifndef __BIGENDIAN
2215 +                #error help, I only know about bigendian or littlendian machines
2216 +                #endif
2217 +               return test_and_clear_bit
2218 +                    (i - 1 + (sizeof(long)-sizeof(a->counter))*8,
2219 +                        (unsigned long *)&a->counter);
2220 +        #endif
2221 +}
2222 +
2223 +
2224 +/*
2225 + * PTB - set the enabled flag on a device (call without the spinlock held) 
2226 + *
2227 + *   @lo the nbd device being treated
2228 + */
2229 +static void
2230 +nbd_enable (struct nbd_device *lo) {
2231 +       unsigned long flags;
2232 +        int did_enabled = 0;
2233 +        struct nbd_md *md = &nbd_md;
2234 +
2235 +       // PTB reenable part
2236 +       write_lock_irqsave (&lo->meta_lock, flags);
2237 +       if (!atomic_test_and_set_mask (&lo->flags, NBD_ENABLED)) {
2238 +                // PTB was not enabled before
2239 +               atomic_clear_mask (NBD_VALIDATED, &lo->flags);
2240 +               lo->lives++;
2241 +                did_enabled = 1;
2242 +       } 
2243 +       write_unlock_irqrestore (&lo->meta_lock, flags);
2244 +
2245 +        if (did_enabled)
2246 +                md->notify(&nbd_md, mk_kdev (major, lo->nbd << NBD_SHIFT));
2247 +}
2248 +
2249 +
2250 +/*
2251 + * PTB rollback all requests on a given slot and then invalidate it
2252 + * (so the requests can't go back until somebody reactivates the slot)
2253 + * At least rollback (which we call takes both the io spinlock and our
2254 + * spinlock, so we can hold neither when we are called. Soft_reset
2255 + * (which we call) also calls rollback, so has the same problem.
2256 + *
2257 + *   @slot the nbd slot being treated
2258 + */
2259 +static int
2260 +nbd_clr_sock (struct nbd_slot *slot)
2261 +{
2262 +       int i = 0;
2263 +       struct nbd_device *lo = slot->lo;
2264 +       int islot = slot->i;
2265 +       unsigned long flags;
2266 +        int do_reset = 0;
2267 +        int do_enable = 0;
2268 +       static int nbd_soft_reset (struct nbd_device*);
2269 +
2270 +       nbd_rollback_all (slot);
2271 +
2272 +       slot->file = NULL;
2273 +       slot->bufsiz = 0;
2274 +       slot->flags = 0;
2275 +       slot->buffer = NULL;
2276 +
2277 +       write_lock_irqsave (&lo->meta_lock, flags);
2278 +
2279 +       /* PTB reset lo->aslot */
2280 +
2281 +       if (lo->aslot > 0) {
2282 +
2283 +               /* PTB grr .. do this the hard way */
2284 +               int aslot = 0;
2285 +               for (i = 0; i < lo->nslot; i++) {
2286 +                       struct nbd_slot *sloti = &lo->slots[i];
2287 +                       if (sloti->file)
2288 +                               aslot++;
2289 +               }
2290 +                lo->aslot = aslot;
2291 +
2292 +               if (lo->aslot <= 0) {
2293 +                       // PTB we were the last client alive, diasable device
2294 +                       if (atomic_read (&lo->flags) & NBD_SHOW_ERRS) {
2295 +                               // PTB soft_reset will invalidate_buffers
2296 +                               atomic_clear_mask (NBD_ENABLED, &lo->flags);
2297 +                                do_reset = 1;
2298 +                       }
2299 +               } else if (!(atomic_read (&lo->flags) & NBD_ENABLED)) {
2300 +                       // PTB must not call reenable as that clears the queue
2301 +                        do_enable = 1;
2302 +               }
2303 +
2304 +       }
2305 +
2306 +        // PTB lift the lock temporarily
2307 +       write_unlock_irqrestore(&lo->meta_lock, flags);
2308 +        if (do_reset) {
2309 +               nbd_soft_reset (lo);
2310 +        }
2311 +        if (do_enable) {
2312 +                nbd_enable (lo);
2313 +               NBD_ALERT ("enabled device nd%s\n", lo->devnam);
2314 +        }
2315 +       write_lock_irqsave(&lo->meta_lock, flags);
2316 +
2317 +       /* PTB reset lo->islot, for no good reason */
2318 +
2319 +       if (atomic_read (&lo->islot) == islot) {
2320 +               for (i = 0; i++ < lo->nslot;) {
2321 +                       atomic_inc (&lo->islot);
2322 +                       if (atomic_read (&lo->islot) >= lo->nslot)
2323 +                               atomic_set (&lo->islot, 0);
2324 +                       if (lo->slots[atomic_read (&lo->islot)].file)
2325 +                               break;
2326 +               }
2327 +       }
2328 +       lo->harderror = 0;
2329 +       write_unlock_irqrestore (&lo->meta_lock, flags);
2330 +
2331 +       /* PTB don't clear whole device queue as we might still be open */
2332 +
2333 +       return 0;
2334 +}
2335 +
2336 +/*
2337 + * PTB - check all slots for old requests and roll them back. 
2338 + * At least rollback (which we call takes both the io spinlock and our
2339 + * spinlock, so we can hold neither when we are called.
2340 + *
2341 + *   @lo the nbd device to scan
2342 + */
2343 +static void
2344 +nbd_rollback_old (struct nbd_device *lo)
2345 +{
2346 +
2347 +       int islot;
2348 +
2349 +       for (islot = 0; islot < lo->nslot; islot++) {
2350 +               struct nbd_slot *slot = &lo->slots[islot];
2351 +               if (slot->req_age > 0
2352 +                   && slot->req_age < jiffies - lo->req_timeo * HZ) {
2353 +                       nbd_rollback_all (slot);
2354 +               }
2355 +       }
2356 +
2357 +}
2358 +
2359 +/*
2360 + * PTB - register a socket to a slot.
2361 + *     - Return 0 for success and -ve for failure.
2362 + *       Nowadays this doesn't do very much! Just finalizes things.
2363 + *
2364 + *       @slot  the nbd slot being registered
2365 + */
2366 +static int
2367 +nbd_set_sock (struct nbd_slot *slot, int arg)
2368 +{
2369 +
2370 +       struct nbd_device *lo = slot->lo;
2371 +       int islot = slot->i;
2372 +       unsigned long flags;
2373 +        int do_enable = 0;
2374 +
2375 +       if (!(atomic_read (&lo->flags) & NBD_INITIALISED)) {
2376 +               NBD_ALERT ("(%d) device nd%s not initialised yet!\n",
2377 +                          islot, lo->devnam);
2378 +               return -ENODEV;
2379 +       }
2380 +       if (!(atomic_read (&lo->flags) & NBD_SIZED)) {
2381 +               NBD_ALERT ("(%d) device nd%s not sized yet!\n", islot,
2382 +                        lo->devnam);
2383 +               return -EINVAL;
2384 +       }
2385 +       if (!(atomic_read (&lo->flags) & NBD_BLKSIZED)) {
2386 +               NBD_ALERT ("(%d) device nd%s not blksized yet!\n", islot,
2387 +                        lo->devnam);
2388 +               return -EINVAL;
2389 +       }
2390 +       if (!(atomic_read (&lo->flags) & NBD_SIGNED)) {
2391 +               NBD_ALERT ("(%d) setting unsigned device nd%s! But harmless.\n",
2392 +                          islot, lo->devnam);
2393 +               return -EINVAL;
2394 +       }
2395 +
2396 +       down (&lo->pid_sem);
2397 +
2398 +       if (slot->pid != current->pid) {
2399 +                if (jiffies > slot->cli_age + 2 * HZ * lo->req_timeo) {
2400 +                       NBD_ALERT
2401 +                       ("(%d) dead client process %d has nd%s%d, erasing pid!\n",
2402 +                         islot, slot->pid, lo->devnam, islot + 1);
2403 +                        slot->pid = 0;
2404 +                } else {
2405 +                       NBD_ALERT
2406 +                       ("(%d) other live client process %d has nd%s%d!\n",
2407 +                         islot, slot->pid, lo->devnam, islot + 1);
2408 +                }
2409 +               up (&lo->pid_sem);
2410 +               return -EINVAL;
2411 +       }
2412 +       up (&lo->pid_sem);
2413 +
2414 +       slot = &lo->slots[islot];
2415 +
2416 +       // PTB this is a queue critical code region for the flags business
2417 +       write_lock_irqsave (&lo->meta_lock, flags);
2418 +
2419 +       // PTB file has to be nonzero to indicate we are all set up. 
2420 +        slot->file = (void *) (unsigned long) (arg+1 > 0 ? arg+1 : 1);
2421 +
2422 +       if (islot >= lo->nslot) {
2423 +               lo->nslot = islot + 1;
2424 +               NBD_INFO ("increased socket count to %d\n", lo->nslot);
2425 +       }
2426 +
2427 +       lo->harderror = 0;
2428 +
2429 +        if (lo->disk && !get_capacity(lo->disk)) {
2430 +                set_capacity(lo->disk, lo->sectors);
2431 +        }
2432 +       if (++lo->aslot > 0) {
2433 +                do_enable = 1;
2434 +        }
2435 +       // PTB end of queue critical region
2436 +       write_unlock_irqrestore (&lo->meta_lock, flags);
2437 +
2438 +        /*
2439 +        * PTB if this is the first slot, we might call reenable and
2440 +        * thus clr queue too, but reenable takes the spinlock
2441 +         */
2442 +        if (do_enable)
2443 +                nbd_enable(lo);
2444 +        
2445 +       return 0;
2446 +}
2447 +
2448 +/*
2449 + * PTB - return the index i of 2^i + j, 0 <= j < 2^i
2450 + */
2451 +static inline unsigned
2452 +log2 (unsigned arg)
2453 +{
2454 +       unsigned log = 0;
2455 +       while ((arg >>= 1) > 0)
2456 +               log++;
2457 +       return log;
2458 +}
2459 +
2460 +/*
2461 + * PTB - set the blksize in bytes of the block device. Return 0 for
2462 + *     - success and -ve for failure.
2463 + */
2464 +static int
2465 +nbd_set_blksize (struct nbd_device *lo, unsigned int arg)
2466 +{
2467 +       int nbd = lo->nbd;
2468 +       if (arg > PAGE_SIZE || arg < 512 || (arg & (arg - 1))) {
2469 +               NBD_ERROR ("blksize too big (%u)\n", arg);
2470 +               return -EINVAL;
2471 +       }
2472 +       lo->blksize = nbd_blksizes[nbd << NBD_SHIFT] = arg;
2473 +       lo->logblksize = log2 (lo->blksize);
2474 +        set_blocksize(lo->inode->i_bdev, lo->blksize);
2475 +       atomic_set_mask (NBD_BLKSIZED, &lo->flags);
2476 +       return 0;
2477 +}
2478 +
2479 +/*
2480 + * PTB - set the size in bytes of the block device. Return 0 for
2481 + *     - success and -ve for failure.
2482 + */
2483 +static int
2484 +nbd_set_size (struct nbd_device *lo, __u64 arg)
2485 +{
2486 +       int nbd = lo->nbd;
2487 +       lo->bytesize = nbd_bytesizes[nbd << NBD_SHIFT] = arg;
2488 +       lo->size     = nbd_sizes[nbd << NBD_SHIFT] = arg >> 10;
2489 +       lo->sectors  = lo->size << 1;
2490 +        if (lo->inode && lo->inode->i_bdev && lo->inode->i_bdev->bd_inode)
2491 +                lo->inode->i_bdev->bd_inode->i_size = arg;
2492 +        if (lo->disk)
2493 +                set_capacity (lo->disk, arg >> 9);
2494 +       atomic_set_mask (NBD_SIZED, &lo->flags);
2495 +       return 0;
2496 +}
2497 +
2498 +/* WG */
2499 +static int
2500 +nbd_set_intvl (struct nbd_device *lo, int arg)
2501 +{
2502 +       if (arg <= 0) {
2503 +               NBD_ERROR ("bad pulse interval/req timeout value (%d)\n", arg);
2504 +               return -EINVAL;
2505 +       }
2506 +       lo->req_timeo = arg;
2507 +       return 0;
2508 +}
2509 +
2510 +static int
2511 +nbd_set_spid (struct nbd_slot *slot, int arg)
2512 +{
2513 +       short spid = arg;
2514 +       if (arg < 0 || arg >= (1 << (sizeof (short) * 8))) {
2515 +               NBD_ERROR ("bad spid value (%d)\n", arg);
2516 +               return -EINVAL;
2517 +       }
2518 +       slot->spid = spid;
2519 +       return 0;
2520 +}
2521 +
2522 +static int
2523 +nbd_set_bufferwr (struct nbd_device *lo, int arg)
2524 +{
2525 +       if (arg) {
2526 +               atomic_set_mask (NBD_BUFFERWR, &lo->flags);
2527 +       } else {
2528 +               atomic_clear_mask (NBD_BUFFERWR, &lo->flags);
2529 +       }
2530 +       return 0;
2531 +}
2532 +
2533 +static int
2534 +nbd_set_remote_invalid (struct nbd_device *lo, int arg)
2535 +{
2536 +       /*
2537 +         * PTB we handle the event ourself exactly when it happens
2538 +        * instead of letting the kernel have check_media defined
2539 +        * and doing it there (and reporting 0 to the kernel)
2540 +         */
2541 +       unsigned long flags;
2542 +        int do_invalidate = 0;
2543 +       kdev_t dev = mk_kdev (major, lo->nbd << NBD_SHIFT);
2544 +
2545 +       if (arg == 0) {
2546 +               atomic_clear_mask (NBD_REMOTE_INVALID, &lo->flags);
2547 +               return 0;
2548 +       }
2549 +
2550 +       write_lock_irqsave (&lo->meta_lock, flags);
2551 +       if (!(atomic_test_and_set_mask (&lo->flags, NBD_REMOTE_INVALID))) {
2552 +               /*
2553 +                 * PTB this tells the kernel that next open
2554 +                * should cause recheck .. we'll agree not to
2555 +                * say we're happy until VALID is set again
2556 +                 */
2557 +               atomic_clear_mask (NBD_VALIDATED, &lo->flags);
2558 +               // PTB test removing partitions
2559 +                do_invalidate = 1;
2560 +        }
2561 +       write_unlock_irqrestore (&lo->meta_lock, flags);
2562 +
2563 +        if (do_invalidate) {
2564 +               // PTB destroy buffers
2565 +               __invalidate_buffers (dev, 1);
2566 +               NBD_ALERT ("invalidating remote on nd%s\n", lo->devnam);
2567 +               // PTB - clear buffers now instead of waiting for kernel
2568 +               // PTB that will cause requests to start being errored
2569 +               invalidate_device (dev, 0);
2570 +       } 
2571 +
2572 +       return 0;
2573 +}
2574 +/*
2575 + * Return the first slot index free when asking for n new ones.
2576 + * If there s no such gap, then NBD_MAXCONN will be returned.
2577 + * The return is always in the same argument address.
2578 + */
2579 +static int
2580 +nbd_get_nport (struct nbd_device *lo, int *arg)
2581 +{
2582 +       int err, nslot, i;
2583 +
2584 +       if (arg == NULL) {
2585 +               return -EINVAL;
2586 +       }
2587 +
2588 +       nslot = *arg;
2589 +       err = copy_from_user ((char *) &nslot, arg, sizeof (int));
2590 +       if (err < 0) {
2591 +               return err;
2592 +       }
2593 +
2594 +       for (i = 0; i < NBD_MAXCONN; i++) {
2595 +               struct nbd_slot *sloti = &lo->slots[i];
2596 +               int j;
2597 +               if (sloti->file) {
2598 +                       continue;
2599 +               }
2600 +
2601 +               for (j = i; j < NBD_MAXCONN && j < i + nslot; j++) {
2602 +                       if (sloti->file)
2603 +                               break;
2604 +               }
2605 +               if (j == i + nslot) {
2606 +
2607 +                       break;
2608 +               }
2609 +       }
2610 +
2611 +       err = copy_to_user (arg, (char *) &i, sizeof (int));
2612 +       return err;
2613 +}
2614 +
2615 +
2616 +/*
2617 + * PTB - if we're not signed, accept new sig and return success.
2618 + *     - if we are signed, compare the offer and return success if equal,
2619 + *     - and -ve for failure.
2620 + *
2621 + *       @slot the slot we're working on
2622 + *       @sig  the string of signature chars (accessed as int *)
2623 + */
2624 +static int
2625 +nbd_set_sig (struct nbd_slot *slot, int *sig)
2626 +{
2627 +       int err = 0;
2628 +       int buf[NBD_SIGLEN / sizeof (int)];
2629 +       int islot = slot->i;
2630 +       struct nbd_device *lo = slot->lo;
2631 +
2632 +       if (!access_ok (VERIFY_READ, (char *) sig, NBD_SIGLEN)) {
2633 +               NBD_ALERT ("(%d): failed sigcheck with bad user address %p\n",
2634 +                          islot, sig);
2635 +               err = -EINVAL;
2636 +               return err;
2637 +       }
2638 +       down (&lo->pid_sem);
2639 +
2640 +       if (slot->pid == 0) {
2641 +               slot->pid = current->pid;
2642 +               slot->cli_age = jiffies;
2643 +       }
2644 +       if (slot->pid != current->pid) {
2645 +                if (jiffies > slot->cli_age + 2 * HZ * lo->req_timeo) {
2646 +                       NBD_ALERT
2647 +                       ("(%d): dead process %d was setting sig, erasing pid\n",
2648 +                       islot, slot->pid);
2649 +                        slot->pid = 0;
2650 +                } else {
2651 +                       NBD_ALERT
2652 +                       ("(%d): live process %d is trying to set sig\n",
2653 +                       islot, slot->pid);
2654 +                }
2655 +               up (&lo->pid_sem);
2656 +               return -EINVAL;
2657 +       }
2658 +
2659 +       if (!(atomic_read (&lo->flags) & NBD_SIGNED)) {
2660 +               /* PTB first time grab sig */
2661 +               copy_from_user ((char *) lo->signature, (char *) &sig[0],
2662 +                               NBD_SIGLEN);
2663 +               atomic_set_mask (NBD_SIGNED, &lo->flags);
2664 +               up (&lo->pid_sem);
2665 +               return 0;
2666 +       }
2667 +       copy_from_user ((char *) buf, (char *) &sig[0], NBD_SIGLEN);
2668 +
2669 +       /* PTB test for equality */
2670 +
2671 +       if (memcmp (&buf[0], &lo->signature[0], NBD_SIGLEN / sizeof (int))
2672 +           != 0) {
2673 +               err = -EINVAL;
2674 +               up (&lo->pid_sem);
2675 +               NBD_ALERT ("(%d): failed sigcheck wth %d\n", islot, err);
2676 +               return err;
2677 +       }
2678 +       up (&lo->pid_sem);
2679 +       err = 0;
2680 +       return err;
2681 +}
2682 +
2683 +/*
2684 + * PTB - register a userspace buffer to a slot. Return 0 for success
2685 + *     - and -ve for failure. Null arg acts as erase.
2686 + */
2687 +static int
2688 +nbd_reg_buf (struct nbd_slot *slot, char *buffer)
2689 +{
2690 +
2691 +       int err = 0, siz;
2692 +       struct nbd_device *lo = slot->lo;
2693 +
2694 +       if (!buffer) {
2695 +               slot->flags &= ~NBD_SLOT_BUFFERED;
2696 +               slot->buffer = NULL;
2697 +               slot->bufsiz = 0;
2698 +               return 0;
2699 +       }
2700 +
2701 +       siz = lo->max_sectors << 9;
2702 +
2703 +       /* verify the buffer is in the process space */
2704 +       if (!access_ok (VERIFY_WRITE, buffer, siz)) {
2705 +               err = -EINVAL;
2706 +               return err;
2707 +       }
2708 +       /* PTB hope the buffer is as big as it should be - FIXME */
2709 +       slot->buffer = buffer;
2710 +       slot->bufsiz = siz;
2711 +
2712 +       /* PTB let the device bufsiz be min of registered nonzero bufsizes */
2713 +       if (!lo->bufsiz) {
2714 +               // PTB first time
2715 +               lo->bufsiz = siz;
2716 +       } else {
2717 +               if (lo->bufsiz > siz)
2718 +                       lo->bufsiz = siz;
2719 +       }
2720 +
2721 +       // PTB just in case the buffer really is small, we reset all the
2722 +       //     kernels request maxima if we have to adjust the device max
2723 +       if (lo->max_sectors < (lo->bufsiz >> 9)) {
2724 +               int j;
2725 +               lo->max_sectors = lo->bufsiz >> 9;
2726 +               for (j = 0; j < NBD_MAXCONN; j++) {
2727 +                       nbd_max_sectors[(lo->nbd << NBD_SHIFT) + j] =
2728 +                        lo->max_sectors;
2729 +               }
2730 +       }
2731 +
2732 +       slot->flags |= NBD_SLOT_BUFFERED;
2733 +       return 0;
2734 +}
2735 +
2736 +/*
2737 + * PTB - this unsets the enabled flag on the device and then clears the
2738 + *     - queue for the device.. Call without spinlock.
2739 + *
2740 + *       @lo the nbd device to scan
2741 + */
2742 +static int
2743 +nbd_disable (struct nbd_device *lo)
2744 +{
2745 +        struct nbd_md * md = &nbd_md;
2746 +
2747 +       if (!lo || !(atomic_read (&lo->flags) & NBD_INITIALISED)) {
2748 +               NBD_ALERT("nbd_disable called on bad device\n");
2749 +               return 0;
2750 +       }
2751 +
2752 +        if (atomic_test_and_clear_mask (&lo->flags, NBD_ENABLED)) {
2753 +                NBD_ALERT ("disabled device nd%s\n", lo->devnam);
2754 +        }
2755 +
2756 +        md->unnotify(md, mk_kdev (major, lo->nbd << NBD_SHIFT));
2757 +
2758 +        // PTB have to recheck partitions on next open
2759 +        if (atomic_test_and_clear_mask (&lo->flags, NBD_VALIDATED)) {
2760 +               NBD_ALERT ("invalidated device nd%s\n", lo->devnam);
2761 +        }
2762 +        return 0;
2763 +}
2764 +
2765 +
2766 +/*
2767 + * PTB - reset the enabled flag on a device and then clear all queues
2768 + * ( call without the spinlock held )  and then enable again.
2769 + */
2770 +static void
2771 +nbd_reenable (struct nbd_device *lo)
2772 +{
2773 +
2774 +       int m, n;
2775 +
2776 +       if (!(atomic_read (&lo->flags) & NBD_INITIALISED))
2777 +               return;
2778 +       if (lo->aslot <= 0)
2779 +               return;
2780 +        if ((atomic_read (&lo->flags) & NBD_ENABLED))
2781 +                return;
2782 +
2783 +       m = nbd_clr_queue (lo);
2784 +       // PTB - have to call clr_kernel_queue without the io_spinlock held
2785 +       n = nbd_clr_kernel_queue (lo);
2786 +
2787 +        nbd_enable(lo);
2788 +}
2789 +
2790 +/*
2791 + *  This function launches a thread which wakes for a signal to reenable
2792 + *  the device, and then sets the timer to deleiver the signal.
2793 + */
2794 +static int
2795 +nbd_reenable_delay (struct nbd_device *lo, int delay)
2796 +{
2797 +       write_lock (&lo->meta_lock);
2798 +       if (lo->reenable_time == 0)
2799 +               lo->reenable_time = jiffies + delay * HZ;
2800 +       write_unlock (&lo->meta_lock);
2801 +       return 0;
2802 +}
2803 +
2804 +
2805 +
2806 +/*
2807 + * PTB - drains device queue. Disables device.
2808 + * At least rollback (which we call takes both the io spinlock and our
2809 + * spinlock, so we can hold neither when we are called. Also
2810 + * invalidate buffers, on request of Rogier Wolff.
2811 + */
2812 +static int
2813 +nbd_soft_reset (struct nbd_device *lo)
2814 +{
2815 +       int j;
2816 +        const int max_clrq_retries = 100;
2817 +       if (!(atomic_read (&lo->flags) & NBD_INITIALISED) || lo->nslot <= 0) {
2818 +               return -EINVAL;
2819 +       }
2820 +       /*
2821 +         * PTB We push back the requests in the slot, in order to be able to
2822 +        * vamoosh them in a moment. This is a race, surely? We ought to
2823 +        * do this atomically or dsiable the slots first.
2824 +         */
2825 +       for (j = 0; j < lo->nslot; j++) {
2826 +               struct nbd_slot *slot = &lo->slots[j];
2827 +               nbd_rollback_all (slot);
2828 +       }
2829 +       // PTB disable unsets the nabled flag and clears the queue
2830 +       nbd_disable (lo);
2831 +        for (j = 0; j < max_clrq_retries; j++) {
2832 +               int m = nbd_clr_queue (lo);
2833 +                if (m <= 0)
2834 +                        break;
2835 +        }
2836 +       // PTB this would unsign the device: lo->flags &= ~NBD_SIGNED;
2837 +
2838 +       /*
2839 +         * PTB put back invalidate buffers for use when called from
2840 +        * clr_sock from nbd_release on request of Rogier Wolff.
2841 +         */
2842 +       for (j = 0; j < lo->nslot; j++) {
2843 +               invalidate_buffers (mk_kdev(major, (lo->nbd << NBD_SHIFT) + j));
2844 +       }
2845 +       return 0;
2846 +}
2847 +
2848 +/*
2849 + * PTB - added a device/module reset for tidyness in face of rampant hacking
2850 + *     - this does a soft_reset of all devices, followed bu a clr sock
2851 + *     - on each, and then clears the kernel queue. It unsets the
2852 + *     - enabled flag on each device.
2853 + *       We have to be called without either the spinlock or the
2854 + *       spinlock held, as we call soft_reset which takes both, as
2855 + *       does clr_sock
2856 + */
2857 +int
2858 +nbd_hard_reset (struct nbd_device *lo)
2859 +{
2860 +       int i;
2861 +       int err = 0;
2862 +
2863 +       for (i = 0; i < MAX_NBD; i++) {
2864 +               struct nbd_device *lo = &nbd_dev[i];
2865 +               int j;
2866 +                if (!lo->file || !lo->inode)
2867 +                      continue;
2868 +                if (!(atomic_read(&lo->flags)&NBD_INITIALISED))
2869 +                      continue;
2870 +               nbd_soft_reset (lo);
2871 +               for (j = 0; j < lo->nslot; j++) {
2872 +                       struct nbd_slot *slot = &lo->slots[j];
2873 +                       //  PTB this takes the io spinlock and our spinlock.
2874 +                       nbd_clr_sock (slot);
2875 +               }
2876 +               // PTB - call clr_kernel_queue without the io_spinlock held
2877 +               nbd_clr_kernel_queue (lo);
2878 +       }
2879 +
2880 +       return err;
2881 +}
2882 +
2883 +static int
2884 +indirect_ioctl_load (struct request *req, int cmd, char * buf)
2885 +{
2886 +
2887 +        int size;
2888 +        int err;
2889 +        struct nbd_ioctl *remote_ioctl = nbd_remote_ioctl.remote;
2890 +
2891 +        if (!remote_ioctl)
2892 +                return -EINVAL;
2893 +
2894 +       size = remote_ioctl->size_user (cmd, buf);
2895 +
2896 +       if (size < 0) {
2897 +                // PTB unauthorized ioctl
2898 +                err = -EINVAL;
2899 +                goto error_out;
2900 +       }
2901 +
2902 +        if (size == 0) {
2903 +                 // PTB we never use the nbd devices small buffer now
2904 +                 req->nr_sectors = 0;
2905 +                 req->buffer = NULL;
2906 +                 return size;
2907 +        }
2908 +
2909 +        // PTB we have to use an extra buffer or else block
2910 +       // here and rendezvous directly with the get_req call
2911 +        req->nr_sectors = (size + 511) >> 9;
2912 +        req->buffer = kmalloc(req->nr_sectors << 9, GFP_KERNEL);
2913 +
2914 +       if (!req->buffer) {
2915 +                 err = -ENOMEM;
2916 +                 goto error_out;
2917 +       }
2918 +
2919 +       if (_IOC_DIR (cmd) & _IOC_WRITE) {
2920 +               err =
2921 +                remote_ioctl->cp_from_user (cmd, req->buffer, buf, size);
2922 +               if (err < 0) {
2923 +                       kfree (req->buffer);
2924 +                        goto error_out;
2925 +               }
2926 +       }
2927 +        return size;
2928 +
2929 +error_out:
2930 +        req->buffer = NULL;
2931 +        req->nr_sectors =0;
2932 +        return err;
2933 +}
2934 +
2935 +static int
2936 +indirect_ioctl_store (struct request *req, int cmd, char * buf,
2937 +                     int size)
2938 +{
2939 +        int err;
2940 +        struct nbd_ioctl * remote_ioctl = nbd_remote_ioctl.remote;
2941 +
2942 +        if (!remote_ioctl)
2943 +                return -EINVAL;
2944 +
2945 +        if (size <= 0)
2946 +                return size;
2947 +
2948 +       // PTB if we are reading, it should be to the local buffer
2949 +       // PTB the buffer points at a kmalloced area
2950 +        
2951 +        if (!req->buffer)
2952 +                return -ENOMEM;
2953 +       err = remote_ioctl->cp_to_user (cmd, buf, req->buffer, size);
2954 +       kfree (req->buffer);
2955 +       if (err < size)
2956 +               return -ENOMEM;
2957 +       return size;
2958 +}
2959 +
2960 +static int
2961 +do_nbd_remote_ioctl(struct nbd_device *lo, int minor, int cmd, unsigned long arg) {
2962 +
2963 +       unsigned start_time, timeout;
2964 +       size_t size;
2965 +        int err;
2966 +        struct request * req;
2967 +        struct completion x;
2968 +
2969 +       /*
2970 +         * PTB here we have to treat remote ioctls. We should probably make
2971 +        * a request and put it on the local queue, but where can we get
2972 +        * the request from? We might have to keep one in reserve.
2973 +        * That's not a bad idea, because
2974 +        * we generate it here and we delete it here, and the daemon code
2975 +        * is all set up to read that sort of thing. So that's what we do ...
2976 +         */
2977 +
2978 +       timeout = lo->req_timeo * HZ;
2979 +       start_time = jiffies;
2980 +
2981 +        while (!(req = blk_get_request(lo->q,WRITE,0))) {
2982 +               if (jiffies >= start_time + timeout) {
2983 +                       // PTB it takes too long
2984 +                       NBD_ALERT
2985 +                        ("took too long to get a spare ioctl req: TIMEOUT\n");
2986 +                       return -ETIME;
2987 +               }
2988 +               err = interruptible_sleep_on_timeout (&lo->req_wq,
2989 +                                                     start_time +
2990 +                                                     timeout - jiffies);
2991 +       }
2992 +
2993 +       set_rq_type(req, IOCTL);
2994 +
2995 +       req->errors = 0;
2996 +
2997 +       // PTB this is the fixed-up command
2998 +       req->special = (void *) cmd;
2999 +
3000 +       /*
3001 +         * PTB this is (arg if it is direct, else) the address of a local buffer
3002 +        * PTB we need to store the arg or its dereference somewhere local
3003 +        * for a while until the cnb-client thread can enter and pick it
3004 +        * up. The alternative is to block the ioctl here until it is
3005 +        * picked up, which IS possible.
3006 +         */
3007 +        
3008 +       if (_IOC_DIR (cmd) & _IOC_READ) {
3009 +               // PTB indirect
3010 +                size = indirect_ioctl_load (req, cmd, (char *)arg);
3011 +                if (size < 0) {
3012 +                    goto end;
3013 +                }
3014 +       } else {
3015 +               // PTB direct - we just need to remember the value
3016 +               size = 0;
3017 +               req->buffer = (char *) arg;
3018 +       }
3019 +
3020 +       // PTB point the request buffer vaguely in the direction of where
3021 +       // the data is, but it does not matter.
3022 +       req->rq_disk = lo->disk;
3023 +
3024 +       // PTB we queue the request for treatment and wait till treated
3025 +        init_completion(&x);
3026 +        req->waiting = &x;
3027 +       nbd_enqueue (lo, req);
3028 +
3029 +        for (err = 0; err <= 0; err = wait_for_completion_timeout(&x, 1)) {
3030 +
3031 +                /*
3032 +                 * PTB on slot or queue? Don't know.  Only want
3033 +                 * to vamoosh it if its on queue, not slot
3034 +                 */
3035 +               struct list_head *pos;
3036 +                int time_left = start_time + timeout - jiffies;
3037 +                // PTB del_req will be run with queue_lock held
3038 +                static void delete_req(void) {
3039 +
3040 +                        // PTB change countq only under this lock
3041 +                        if (! (req->flags & REQ_SPECIAL)) {
3042 +                                write_lock(&lo->altqueue_lock);
3043 +                                // PTB reverse inadvertent accounting in enqueue
3044 +                                atomic_dec (&lo->countq[rq_data_dir(req)]);
3045 +                                write_unlock(&lo->altqueue_lock);
3046 +                        }
3047 +
3048 +                       list_del_init (&req->queuelist);
3049 +
3050 +                       req->errors = -ETIME;
3051 +                       if (req->nr_sectors > 0 && req->buffer) {
3052 +                               kfree (req->buffer);
3053 +                                req->buffer = NULL;
3054 +                       }
3055 +                };
3056 +
3057 +               if (time_left > 0)
3058 +                        continue;
3059 +
3060 +                // PTB find req on list and delete it
3061 +                write_lock (&lo->queue_lock);
3062 +               list_for_each (pos, &lo->queue) {
3063 +
3064 +                       if (req != list_entry (pos, struct request, queuelist)) 
3065 +                                continue;
3066 +
3067 +                        delete_req ();
3068 +                       write_unlock (&lo->queue_lock);
3069 +                       NBD_ALERT
3070 +                         ("took too long to treat queued ioctl: TIMEOUT\n");
3071 +                       err = -ETIME;
3072 +                        goto end;
3073 +                }
3074 +               write_unlock (&lo->queue_lock);
3075 +
3076 +       } // end while loop
3077 +
3078 +
3079 +       if (_IOC_DIR (cmd) & _IOC_READ) {
3080 +                err = indirect_ioctl_store(req, cmd, (char *)arg, size);
3081 +                if (err < 0) {
3082 +                    goto end;
3083 +                }
3084 +       }
3085 +
3086 +       if (req->errors != 0) {
3087 +                err = req->errors;
3088 +               err = err < 0 ? err : -EINVAL;
3089 +       } else {
3090 +                err = 0;
3091 +        }
3092 +end:
3093 +        blk_put_request(req);
3094 +       return err;
3095 +
3096 +}
3097 +
3098 +static int
3099 +find_slot (struct nbd_device *lo, int pid)
3100 +{
3101 +        int i;
3102 +       // go search
3103 +       for (i = 0; i < NBD_MAXCONN; i++) {
3104 +                struct nbd_slot * slot =  &lo->slots[i];
3105 +               if (slot->pid == pid)
3106 +                       break;
3107 +       }
3108 +       if (i < NBD_MAXCONN)
3109 +               return i;               // found it
3110 +       // not found
3111 +       return -1;
3112 +}
3113 +
3114 +static int
3115 +fixup_slot (struct nbd_device *lo, int islot, unsigned int cmd, unsigned long *arg)
3116 +{
3117 +       int intval;
3118 +
3119 +       switch (cmd) {
3120 +
3121 +               // PTB get slot info from parameter if not given
3122 +         case NBD_CLEAR_SOCK:
3123 +         case MY_NBD_CLR_REQ:
3124 +         case MY_NBD_ERR_REQ:
3125 +               // see if we match a known slot pid
3126 +               if (arg && *arg == 0) {
3127 +                       islot = find_slot (lo, current->pid);
3128 +                       if (islot >= 0)
3129 +                               return islot;
3130 +               }
3131 +               NBD_ALERT
3132 +                ("failed to find slot for pid %d for ioctl %x arg %lx\n",
3133 +                 current->pid, cmd, *arg);
3134 +               return islot = -1;
3135 +               break;
3136 +
3137 +               // PTB get the slot from the 16 high bits
3138 +         case NBD_SET_SOCK:
3139 +         case MY_NBD_SET_SPID:
3140 +               intval = *arg >> ((sizeof (int) - sizeof (short)) * 8);
3141 +               intval &= (1 << (sizeof (short) * 8)) - 1;
3142 +               if (intval == 0) {
3143 +                       // no clue in the pid high bits. Search
3144 +                       islot = find_slot (lo, current->pid);
3145 +                       if (islot >= 0) {
3146 +                               // PTB change arg !!
3147 +                               *arg &= (1 << (sizeof (short) * 8)) - 1;
3148 +                               return islot; // found it
3149 +                       }
3150 +                       // not found
3151 +               }
3152 +               NBD_ALERT
3153 +                    ("failed to find slot for pid %d for ioctl %x arg %lx\n",
3154 +                   current->pid, cmd, *arg);
3155 +               return islot = -1;
3156 +               break;
3157 +
3158 +         case MY_NBD_GET_REQ:
3159 +         case MY_NBD_ACK:
3160 +               islot = find_slot (lo, current->pid);
3161 +               if (islot >= 0)
3162 +                       return islot;
3163 +               NBD_ALERT
3164 +                ("failed to find slot for pid %d for ioctl %x arg %lx\n",
3165 +                 current->pid, cmd, *arg);
3166 +               return islot;
3167 +               break;
3168 +
3169 +         case MY_NBD_REG_BUF:
3170 +         case MY_NBD_SET_SIG:
3171 +               islot = find_slot (lo, current->pid);
3172 +               if (islot >= 0)
3173 +                       return islot;
3174 +               /*
3175 +                 * PTB Otherwise they passed a buffer
3176 +                * and the slot number is in the first 4B
3177 +                * We need some magic here for safety!
3178 +                * set sig is the only call that really needs
3179 +                * to send its pid!
3180 +                 */
3181 +
3182 +                intval = -1;
3183 +               if (!arg || !*arg || get_user (intval, (int *) *arg)
3184 +               || intval <= 0
3185 +                || intval > NBD_MAXCONN) {
3186 +                       NBD_ALERT
3187 +                        ("failed to find slot for pid %d ioctl %x arg %lx\n",
3188 +                               current->pid, cmd, *arg);
3189 +                       return islot = -1;
3190 +               }
3191 +               islot = intval - 1;
3192 +
3193 +               // PTB CHANGE ARG !!!!
3194 +               *arg += sizeof (int);
3195 +               return islot;
3196 +               break;
3197 +       }
3198 +
3199 +       return islot = -1;
3200 +}
3201 +
3202 +/*
3203 + * PTB - generic ioctl handling
3204 + */
3205 +static int
3206 +nbd_ioctl (struct inode *inode, struct file *file,
3207 +          unsigned int cmd, unsigned long arg)
3208 +{
3209 +       struct nbd_device *lo
3210 +                  = NULL;      // PTB device pointer
3211 +       int minor = -1;         // PTB minor on which we got the ioctl
3212 +       int islot = -1;         // PTB slot number 0, 1, ...
3213 +       int nbd   = -1;         // PTB the count for the device group
3214 +       struct nbd_slot *slot
3215 +                  = NULL;      // PTB slot pointer
3216 +        int err;
3217 +
3218 +       if (!capable(CAP_SYS_ADMIN)) {
3219 +               NBD_ERROR ("caller must be root.\n");
3220 +               return -EPERM;
3221 +       }
3222 +       if (!inode) {
3223 +               NBD_ERROR ("given bad inode.\n");
3224 +               return -EINVAL;
3225 +       }
3226 +       if (major (inode->i_rdev) != major) {
3227 +               NBD_ERROR ("pseudo-major %d != %d\n",
3228 +                          major (inode->i_rdev), major);
3229 +               return -ENODEV;
3230 +       }
3231 +       minor = minor (inode->i_rdev);
3232 +       nbd = minor >> NBD_SHIFT;
3233 +       if (nbd >= MAX_NBD) {
3234 +               NBD_ERROR ("tried to open too many devices, %d\n", minor);
3235 +               return -ENODEV;
3236 +       }
3237 +       lo = &nbd_dev[nbd];
3238 +       lo->harderror = 0;
3239 +       islot = minor % NBD_MAXCONN - 1;
3240 +
3241 +        /*
3242 +         * PTB fixup breakage >= 2.5.44 caused by not being allowed to talk to
3243 +         * minors. We deduce the slot number from hints in the call.
3244 +         * Or we match against the known pids.
3245 +         */
3246 +        if (islot < 0) {
3247 +                islot = fixup_slot(lo, islot, cmd, &arg);
3248 +        }
3249 +        if (islot >= 0)
3250 +                slot = & lo->slots[islot];
3251 +      
3252 +
3253 +       // PTB these are all always local ioctls
3254 +       switch (cmd) {
3255 +               int err;
3256 +               int intval;
3257 +                int do_reenable;
3258 +
3259 +         case NBD_CLEAR_SOCK:
3260 +               if (islot < 0) {
3261 +                       NBD_ALERT ("CLEAR_SOCK called on full device nd%s arg %lx\n",
3262 +                                  lo->devnam, arg);
3263 +                       return -EINVAL;
3264 +                }
3265 +               err = nbd_clr_sock (slot);
3266 +               return err;
3267 +
3268 +         case NBD_SET_SOCK:
3269 +               if (islot < 0) {
3270 +                       NBD_ALERT ("SET_SOCK called on full device nd%s arg %lx\n",
3271 +                               lo->devnam, arg);
3272 +                       return -EINVAL;
3273 +                }
3274 +               err = nbd_set_sock (slot, arg);
3275 +               return err;
3276 +
3277 +         case BLKBSZGET:
3278 +                // PTB The kernel should intercept this
3279 +               NBD_ALERT ("attempted get_blksize with BLKBSZGET\n");
3280 +                return -EINVAL;
3281 +
3282 +          case NBD_GET_BLKSIZE:
3283 +               if (!(atomic_read (&lo->flags) & NBD_BLKSIZED)) {
3284 +                       return -EINVAL;
3285 +               }
3286 +               err = put_user (lo->blksize, (long *) arg);
3287 +               return err;
3288 +
3289 +         case BLKBSZSET:
3290 +                // PTB The kernel should have intercepted this
3291 +               NBD_ALERT ("attempted set_blksize with BLKBSZSET\n");
3292 +                return -EINVAL;
3293 +
3294 +          case NBD_SET_BLKSIZE:
3295 +                if (!arg)
3296 +                        return -EINVAL;
3297 +               intval = -1;
3298 +                if (get_user (intval, (int *)arg))
3299 +                        return -EFAULT;
3300 +               if (intval == -1) {
3301 +                       NBD_ALERT ("BLKBSZSET got %d from user\n", intval);
3302 +               }
3303 +               err = nbd_set_blksize (lo, intval);
3304 +               return err;
3305 +
3306 +         case NBD_SET_SIZE:
3307 +               err = nbd_set_size (lo, (__u64) arg);
3308 +               return err;
3309 +
3310 +         case NBD_SET_SECTORS:
3311 +               err = nbd_set_size (lo, ((__u64) arg) << 9);
3312 +               return err;
3313 +
3314 +         case MY_NBD_SET_INTVL:        /* WG */
3315 +               err = nbd_set_intvl (lo, arg);
3316 +               return err;
3317 +
3318 +         case MY_NBD_SET_SPID:
3319 +               if (islot < 0) {
3320 +                       NBD_ALERT ("SET_SPID called on full device nd%s\n",
3321 +                                       lo->devnam);
3322 +                       return -EINVAL;
3323 +               }
3324 +               err = nbd_set_spid (slot, arg);
3325 +               return err;
3326 +
3327 +         case MY_NBD_SET_BUFFERWR:
3328 +               err = nbd_set_bufferwr (lo, arg);
3329 +               return err;
3330 +
3331 +         case MY_NBD_REG_BUF:  /* PTB register your buffer per socket here */
3332 +               if (!arg) {
3333 +                       /* PTB serves as existence check for this ioctl */
3334 +                       return 0;
3335 +               }
3336 +               if (islot < 0) {
3337 +                       NBD_ALERT ("REG_BUF called on full device nd%s\n",
3338 +                                       lo->devnam);
3339 +                       return -EINVAL;
3340 +               }
3341 +               err = nbd_reg_buf (slot, (char *) arg);
3342 +               return err;
3343 +
3344 +         case MY_NBD_SET_SIG:
3345 +               if (islot < 0) {
3346 +                      NBD_ALERT ("SET_SIG called on full device nd%s\n",
3347 +                          lo->devnam);
3348 +                      return -EINVAL;
3349 +               }
3350 +               err = nbd_set_sig (slot, (int *) arg);
3351 +               return err;
3352 +
3353 +         case MY_NBD_GET_REQ:
3354 +               if (islot < 0) {
3355 +                       NBD_ALERT ("GET_REQ called on full device nd%s\n",
3356 +                           lo->devnam);
3357 +                       return -EINVAL;
3358 +               }
3359 +                if (arg < 4096) {
3360 +                    arg = (unsigned)slot->buffer;
3361 +                    if (!arg)
3362 +                        return -EINVAL;
3363 +                }
3364 +               err = nbd_get_req (slot);
3365 +               return err;
3366 +
3367 +         case MY_NBD_GET_NPORT:
3368 +               err = nbd_get_nport (lo, (int *) arg);
3369 +               return err;
3370 +
3371 +         case MY_NBD_CLR_REQ:
3372 +               if (islot < 0) {
3373 +                       NBD_ALERT ("CLR_REQ called on full device nd%s\n",
3374 +                                  lo->devnam);
3375 +                       return -EINVAL;
3376 +               }
3377 +               nbd_rollback_all (slot);
3378 +               return 0;
3379 +
3380 +         case MY_NBD_ERR_REQ:
3381 +               if (islot < 0) {
3382 +                       NBD_ALERT ("ERR_REQ called on full device nd%s\n",
3383 +                                  lo->devnam);
3384 +                       return -EINVAL;
3385 +               }
3386 +               nbd_error_all (slot);
3387 +               return 0;
3388 +
3389 +         case MY_NBD_SYNC:
3390 +
3391 +                // PTB maybe run the reenable function
3392 +                do_reenable = 0;
3393 +                write_lock(&lo->meta_lock);
3394 +                if (lo->reenable_time != 0
3395 +                        && time_before(lo->reenable_time,jiffies)) {
3396 +                        lo->reenable_time = 0;
3397 +                        do_reenable = 1;
3398 +                }
3399 +                write_unlock(&lo->meta_lock);
3400 +                if (do_reenable)
3401 +                        nbd_reenable(lo);
3402 +
3403 +               // PTB error too old reqs if show_errs set, else roll them back
3404 +               nbd_rollback_old (lo);
3405 +
3406 +                // PTB opportunity to calculate speed
3407 +               nbd_set_speed (lo);
3408 +
3409 +               return 0;
3410 +
3411 +         case MY_NBD_ACK:
3412 +               if (islot < 0) {
3413 +                       NBD_ALERT ("NBD_ACK called on full device nd%s\n",
3414 +                                  lo->devnam);
3415 +                       return -EINVAL;
3416 +               }
3417 +               err = nbd_ack (slot);
3418 +               return err;
3419 +
3420 +               /* let this be compiled in always - it's useful. PTB */
3421 +         case NBD_PRINT_DEBUG:
3422 +               NBD_INFO("device %d: hd = %p, tl = %p, in = %d, out = %d\n",
3423 +                 minor,
3424 +                  list_head (&lo->queue, struct request, queuelist),
3425 +                 list_tail (&lo->queue, struct request, queuelist),
3426 +                 atomic_read (&lo->requests_in[READ]) +
3427 +                   atomic_read (&lo->requests_in[WRITE]),
3428 +                 atomic_read (&lo->requests_out[READ]) +
3429 +                   atomic_read (&lo->requests_out[WRITE])
3430 +                  );
3431 +               err = 0;
3432 +               return err;
3433 +         case NBD_HARD_RESET:  /* PTB - debugging */
3434 +               err = nbd_hard_reset (lo);
3435 +               return err;
3436 +
3437 +         case NBD_RESET:       /* PTB - debugging */
3438 +               err = nbd_soft_reset (lo);
3439 +               // PTB we reenable in 5s
3440 +                nbd_reenable_delay(lo, 5);
3441 +               return err;
3442 +
3443 +         case NBD_SET_MD5SUM:  /* PTB - change to do/plead md5summing */
3444 +               if (arg) {
3445 +                       atomic_set_mask (NBD_MD5SUM, &lo->flags);
3446 +               } else {
3447 +                       atomic_clear_mask (NBD_MD5SUM, &lo->flags);
3448 +               }
3449 +               err = 0;
3450 +               return err;
3451 +
3452 +         case MY_NBD_SET_SHOW_ERRS:    /* PTB/WG - change show error status */
3453 +               if (arg) {
3454 +                       atomic_set_mask (NBD_SHOW_ERRS, &lo->flags);
3455 +               } else {
3456 +                       atomic_clear_mask (NBD_SHOW_ERRS, &lo->flags);
3457 +               }
3458 +               return 0;
3459 +
3460 +          case MY_NBD_SET_DIRECT:      /* PTB - change o_direct status */
3461 +               if (arg) {
3462 +                       atomic_set_mask (NBD_DIRECT, &lo->flags);
3463 +               } else {
3464 +                       atomic_clear_mask (NBD_DIRECT, &lo->flags);
3465 +               }
3466 +               return 0;
3467 +
3468 +         case MY_NBD_INVALIDATE:
3469 +               err = nbd_set_remote_invalid (lo, (int) arg);
3470 +               return err;
3471 +
3472 +         case NBD_SET_PF_MEMALLOC:
3473 +               if (arg) {
3474 +                       current->flags |= PF_MEMALLOC;
3475 +               } else {
3476 +                       current->flags &= ~PF_MEMALLOC;
3477 +               }
3478 +               return 0;
3479 +        } // PTB endsw
3480 +
3481 +       // PTB these are the standard ioctls, and we might get them from
3482 +       // the other side
3483 +
3484 +       switch (cmd) {
3485 +               int err;
3486 +                int intval;
3487 +
3488 +          case BLKROSET:               /* PTB - change ro status */
3489 +                if (get_user(intval, (int*)arg))
3490 +                        return -EFAULT;
3491 +                // PTB local flags
3492 +                nbd_set_read_only(lo, intval);
3493 +               return 0;
3494 +
3495 +          case BLKROGET:
3496 +                intval =  nbd_read_only(lo);
3497 +                return put_user(intval, (int*)arg);
3498 +
3499 +         case BLKFLSBUF:
3500 +               nbd_maybe_sync_sync (lo);       // PTB normally fsync_dev
3501 +               // PTB device likely has buffers or caches in kernel
3502 +               invalidate_buffers (inode->i_rdev);
3503 +#ifndef NO_BUFFERED_WRITES
3504 +               if (atomic_read (&lo->flags) & NBD_BUFFERWR) {
3505 +                       // PTB got this from rd.c
3506 +                        // PTB destroy buffers
3507 +                       __invalidate_buffers (inode->i_rdev, 1);
3508 +               }
3509 +#endif         /* NO_BUFFERED_WRITES */
3510 +               return 0;
3511 +
3512 +         case HDIO_GETGEO:
3513 +               if (!arg) {
3514 +                       return -EINVAL;
3515 +               } else {
3516 +                       struct hd_geometry *geo =
3517 +                        (struct hd_geometry *) arg;
3518 +                       int sectors = nbd_sizes[nbd << NBD_SHIFT] << 1;
3519 +                       unsigned short c;
3520 +                       unsigned char h, s;
3521 +                       if (sectors < (1 << 22)) {
3522 +                               h = 4;
3523 +                               s = 16;
3524 +                               c = sectors >> 6;
3525 +                       } else {
3526 +                               h = 255;
3527 +                               s = 63;
3528 +                               c = (sectors / h) / s;
3529 +                       }
3530 +                       err = 0;
3531 +                       if ((err = put_user (c, &geo->cylinders), err < 0)
3532 +                           || (err = put_user (h, &geo->heads), err < 0)
3533 +                           || (err = put_user (s, &geo->sectors), err < 0)
3534 +                           || (err = put_user (h, &geo->start), err < 0)) {
3535 +                               return err;
3536 +                       }
3537 +               } 
3538 +               return 0;
3539 +
3540 +#ifndef BLKMDNTFY
3541 +#define BLKMDNTFY _IOW(0x12,133,sizeof(int))
3542 +#endif
3543 +              case BLKMDNTFY:
3544 +                NBD_INFO ("received BLKMDNTFY, am now in raid %x\n",
3545 +                        (unsigned) arg);
3546 +                nbd_md.inc(&nbd_md);
3547 +                return 0;
3548 +
3549 +#ifndef BLKMDUNTFY
3550 +#define BLKMDUNTFY _IOW(0x12,134,sizeof(int))
3551 +#endif
3552 +              case BLKMDUNTFY:
3553 +                NBD_INFO ("received BLKMDUNTFY, now out of raid %x\n",
3554 +                        (unsigned) arg);
3555 +                nbd_md.dec(&nbd_md);
3556 +                return 0;
3557 +
3558 +#ifndef BLKMDRGTR
3559 +#define BLKMDRGTR _IOW(0x12,135,sizeof(unsigned long))
3560 +#endif
3561 +              case BLKMDRGTR:
3562 +                nbd_md.reg(&nbd_md, (int(*)(kdev_t, int))arg);
3563 +                return 0;
3564 +
3565 +       } // PTB endsw
3566 +
3567 +        if (nbd_remote_ioctl.remote != NULL) {
3568 +                struct nbd_ioctl *remote_ioctl = nbd_remote_ioctl.remote;
3569 +
3570 +               if (remote_ioctl->convert_inplace (&cmd) < 0) {
3571 +                       NBD_ALERT ("unauthorized ioctl %#x\n", cmd);
3572 +                       return -EINVAL;
3573 +               }
3574 +
3575 +                err = do_nbd_remote_ioctl(lo, minor, cmd, arg);
3576 +                return err;
3577 +        } 
3578 +        return -EINVAL;
3579 +}
3580 +
3581 +/*
3582 + * PTB - release the device. This happens when the last process closes
3583 + * or dies.
3584 + */
3585 +static int
3586 +nbd_release (struct inode *inode, struct file *file)
3587 +{
3588 +       struct nbd_device *lo;
3589 +       int dev;
3590 +       int nbd;
3591 +       int islot;
3592 +
3593 +       if (!inode) {
3594 +               NBD_ALERT ("null inode.\n");
3595 +               return -ENODEV;
3596 +       }
3597 +       dev = minor (inode->i_rdev);
3598 +       nbd = dev >> NBD_SHIFT;
3599 +
3600 +       if (nbd >= MAX_NBD) {
3601 +                // PTB impossible
3602 +               NBD_ALERT ("too many open devices.\n");
3603 +               return -ENODEV;
3604 +       }
3605 +
3606 +       lo = &nbd_dev[nbd];
3607 +
3608 +       islot = dev % NBD_MAXCONN - 1;
3609 +
3610 +       // PTB it is a daemon closing the slot?
3611 +        if (islot >= 0 || (islot = find_slot(lo, current->pid), islot >= 0)) {
3612 +               struct nbd_slot *slot = &lo->slots[islot];
3613 +               --slot->refcnt;
3614 +               if (slot->pid == current->pid) {
3615 +
3616 +                       nbd_clr_sock (slot);
3617 +                       NBD_ALERT ("(%d): erasing slot pid %d\n", islot, slot->pid);
3618 +                       slot->pid = 0;
3619 +                       if (slot->refcnt > 0) {
3620 +                               NBD_ALERT
3621 +                                ("slot owner process %d released slot nd%s%d while not last\n",
3622 +                                 slot->pid, lo->devnam, islot + 1);
3623 +                       }
3624 +               }
3625 +       }
3626 +
3627 +       /* POSSIBLE change socket here PTB */
3628 +
3629 +       atomic_dec (&lo->refcnt);
3630 +
3631 +       // PTB invalidate buffers on last close if show_err set
3632 +       if (atomic_read (&lo->refcnt) <= 0 || !module_is_live(THIS_MODULE)) {
3633 +                struct nbd_seqno * seqno_out = &lo->seqno_out;
3634 +               //invalidate_buffers (lo->inode->i_rdev);     
3635 +                if (atomic_read (&lo->flags) & NBD_SHOW_ERRS) {
3636 +                       invalidate_buffers (mk_kdev (major, nbd << NBD_SHIFT));
3637 +                }
3638 +                // PTB in any case the daemons are dead!
3639 +               lo->bufsiz = 0;
3640 +               seqno_out->reset(seqno_out);
3641 +       }
3642 +
3643 +        if (file
3644 +        && (file->f_flags & O_DIRECT)
3645 +        // PTB we set this to show we made iobuf
3646 +        && (file->f_flags & O_NOFOLLOW))  {
3647 +                file->f_flags &= ~(O_DIRECT|O_NOFOLLOW);
3648 +        }
3649 +
3650 +        return 0;
3651 +}
3652 +
3653 +static int
3654 +nbd_media_changed(struct gendisk *disk) {
3655 +        struct nbd_device *lo = disk->private_data;
3656 +        if (!lo || lo->magic != NBD_DEV_MAGIC)
3657 +                return 0;
3658 +        NBD_ALERT("nbd_media_changed called on nd%s\n", lo->devnam);
3659 +        return (atomic_read (&lo->flags) & NBD_VALIDATED) == 0;
3660 +}
3661 +
3662 +static int
3663 +nbd_revalidate(struct gendisk *disk) {
3664 +        struct nbd_device *lo = disk->private_data;
3665 +       unsigned long flags;
3666 +        int err = -EINVAL;
3667 +
3668 +        if (!lo || lo->magic != NBD_DEV_MAGIC){
3669 +                return -EINVAL;
3670 +        }
3671 +               // PTB reenable part
3672 +        NBD_ALERT("revalidate called on nd%s\n", lo->devnam);
3673 +        write_lock_irqsave (&lo->meta_lock, flags);
3674 +        if (! (atomic_read (&lo->flags) & NBD_REMOTE_INVALID)
3675 +                &&    (atomic_read (&lo->flags) & NBD_ENABLED)) {
3676 +                atomic_set_mask (NBD_VALIDATED, &lo->flags);
3677 +                err = 0;
3678 +        }
3679 +       write_unlock_irqrestore (&lo->meta_lock, flags);
3680 +
3681 +        return err;
3682 +}
3683 +
3684 +static struct block_device_operations nbd_blkops = {
3685 +        owner:                  THIS_MODULE,
3686 +       open:                   nbd_open,
3687 +       release:                nbd_release,
3688 +       ioctl:                  nbd_ioctl,
3689 +        media_changed:          nbd_media_changed,
3690 +        revalidate_disk:        nbd_revalidate,
3691 +};
3692 +
3693 +static struct gendisk *
3694 +nbd_find (dev_t dev, int *part, void *data)
3695 +{
3696 +       struct nbd_device *lo = data;
3697 +        if (!lo)
3698 +                return NULL;
3699 +       if (lo->magic != NBD_DEV_MAGIC)
3700 +                return NULL;
3701 +        if (!lo->disk)
3702 +                return NULL;
3703 +        if (part)
3704 +                NBD_ALERT("nbd_find called with part = %#x\n", (unsigned)*part);
3705 +        if (part && (*part < 0 || *part >= NBD_MAXCONN))
3706 +                return NULL;
3707 +       return get_disk (lo->disk);
3708 +}
3709 +
3710 +
3711 +static int
3712 +nbd_set_disk (struct nbd_device *lo, unsigned first_minor, unsigned npart)
3713 +{
3714 +        struct gendisk * disk = lo->disk;
3715 +       if (!disk)
3716 +               lo->disk = disk = alloc_disk (npart);
3717 +       if (disk) {
3718 +               disk->major        = major;
3719 +               disk->first_minor  = first_minor;
3720 +               disk->fops         = &nbd_blkops;
3721 +               disk->private_data = lo;
3722 +               disk->queue        = lo->q;
3723 +               sprintf (disk->disk_name, "nd%s", lo->devnam);
3724 +                // have to set minors (or capacity) to 1 (0) to avoid check disk
3725 +                set_capacity (disk, 0);
3726 +               add_disk (disk);
3727 +                blk_register_region(MKDEV(major, first_minor),
3728 +                        npart, THIS_MODULE, nbd_find, NULL, lo);
3729 +               set_capacity (disk, lo->bytesize >> 9);
3730 +                // we should rescan later. From userland?
3731 +                return 0;
3732 +       }
3733 +
3734 +       NBD_ERROR ("Insufficient memory for partition structs\n");
3735 +        return -ENOMEM;
3736 +}
3737 +
3738 +/*
3739 + * Pavel - And here should be modules and kernel interface 
3740 + *  (Just smiley confuses emacs :-)
3741 + */
3742 +
3743 +
3744 +static void
3745 +nbd_reset(struct nbd_device *lo, int i) {
3746 +
3747 +        int j;
3748 +
3749 +        if (i < 0 || i >= MAX_NBD)
3750 +            return;
3751 +       lo->magic = NBD_DEV_MAGIC;
3752 +       strncpy (lo->devnam, device_letter (i), 4);
3753 +       for (j = 0; j < NBD_MAXCONN; j++) {     /* PTB */
3754 +               struct nbd_slot *slot = &lo->slots[j];
3755 +               slot->lo = lo;
3756 +               slot->i = j;
3757 +               INIT_LIST_HEAD (&slot->queue);
3758 +       }
3759 +       lo->blksize = 1024;     /* PTB 132 */
3760 +       lo->logblksize = 10;    /* PTB */
3761 +       lo->bytesize = 0x7fffffff00000; /* PTB 132 */
3762 +       lo->size = 0x7fffffff;  /* PTB (bytesizes >> 10) */
3763 +       lo->sectors = 0xfffffffe;       /* PTB sectors */
3764 +       lo->nbd = i;
3765 +       lo->req_timeo = NBD_REQ_TIMEO;  /* PTB default pulse intvl */
3766 +       lo->max_sectors = buf_sectors;
3767 +
3768 +        lo->enable = nbd_enable;
3769 +        lo->reset = nbd_reset;
3770 +        lo->disable = nbd_disable;
3771 +        lo->read_only = nbd_read_only;
3772 +        lo->set_speed = nbd_set_speed;
3773 +        lo->hard_reset = nbd_hard_reset;
3774 +        lo->soft_reset = nbd_soft_reset;
3775 +        lo->reenable_delay = nbd_reenable_delay;
3776 +
3777 +       INIT_LIST_HEAD (&lo->queue);
3778 +       INIT_LIST_HEAD (&lo->altqueue);
3779 +       init_waitqueue_head (&lo->wq);
3780 +       init_waitqueue_head (&lo->req_wq);
3781 +        init_MUTEX(&lo->pid_sem);
3782 +       rwlock_init (&lo->queue_lock);
3783 +       rwlock_init (&lo->altqueue_lock);
3784 +       rwlock_init (&lo->meta_lock);
3785 +       for (j = 0; j < NBD_MAXCONN; j++) {
3786 +               nbd_blksizes[i * NBD_MAXCONN + j] = lo->blksize;
3787 +               nbd_bytesizes[i * NBD_MAXCONN + j] = lo->bytesize;
3788 +               nbd_sizes[i * NBD_MAXCONN + j] = lo->size;
3789 +               nbd_max_sectors[i * NBD_MAXCONN + j] = lo->max_sectors;
3790 +       }
3791 +        nbd_init_seqno(&lo->seqno_out);
3792 +        nbd_init_speed(&lo->rspeed);
3793 +        nbd_init_speed(&lo->wspeed);
3794 +        nbd_init_speed(&lo->tspeed);
3795 +
3796 +        // PTB queuue has alreay been initialized, or will be
3797 +        lo->q = nbd_queue;
3798 +
3799 +       if (md5sum) {
3800 +               atomic_set_mask (NBD_MD5SUM, &lo->flags);
3801 +       }
3802 +       if (sync_intvl) {
3803 +               atomic_set_mask (NBD_SYNC, &lo->flags);
3804 +       }
3805 +       if (show_errs) {
3806 +               atomic_set_mask (NBD_SHOW_ERRS, &lo->flags);
3807 +       }
3808 +        if (direct) {
3809 +                atomic_set_mask (NBD_DIRECT, &lo->flags);
3810 +        }
3811 +       if (buffer_writes) {
3812 +               atomic_set_mask (NBD_BUFFERWR, &lo->flags);
3813 +       }
3814 +        if (merge_requests) {
3815 +                atomic_set(&lo->merge_requests, merge_requests);
3816 +        }
3817 +}
3818 +
3819 +#ifdef MODULE
3820 +MODULE_AUTHOR ("Peter T. Breuer, Andres Marin");
3821 +MODULE_DESCRIPTION ("Enhanced Network Block Device " NBD_VERSION);
3822 +MODULE_LICENSE ("GPL");
3823 +#endif         /* MODULE */
3824 +
3825 +// PTB we steal these from the queue struct at init
3826 +static merge_requests_fn *ll_merge_requests_fn;
3827 +static merge_request_fn *ll_front_merge_fn;
3828 +static merge_request_fn *ll_back_merge_fn;
3829 +
3830 +/* PTB -
3831 + * These functions are needed when the kernel does request merging in
3832 + * order to stop it making requests that are bigger than our buffer.
3833 + *
3834 + * To turn OFF merging (once these functions are in place), set
3835 + * merge_requests=0.
3836 + */
3837 +static int
3838 +nbd_merge_requests_fn (request_queue_t * q, struct request *req,
3839 +                      struct request *req2)
3840 +{
3841 +       struct nbd_device *lo = req->rq_disk->private_data;
3842 +
3843 +       if (!atomic_read(&lo->merge_requests))
3844 +               return 0;
3845 +
3846 +       if (!ll_merge_requests_fn)
3847 +               return 0;
3848 +
3849 +       if (req->nr_sectors + req2->nr_sectors > lo->max_sectors)
3850 +               return 0;
3851 +
3852 +       if (req->nr_sectors + req2->nr_sectors >
3853 +           ((atomic_read(&lo->merge_requests) + 1) << (lo->logblksize - 9)))
3854 +               return 0;
3855 +
3856 +       return ll_merge_requests_fn (q, req, req2);
3857 +}
3858 +static int
3859 +nbd_front_merge_fn (request_queue_t * q, struct request *req, struct bio * bio)
3860 +{
3861 +       struct nbd_device *lo = req->rq_disk->private_data;
3862 +
3863 +       if (!atomic_read(&lo->merge_requests))
3864 +               return 0;
3865 +
3866 +       if (!ll_front_merge_fn)
3867 +               return 0;
3868 +
3869 +       if (req->nr_sectors > lo->max_sectors)
3870 +               return 0;
3871 +
3872 +       if (req->nr_sectors > ((atomic_read(&lo->merge_requests) + 1) << (lo->logblksize - 9)))
3873 +                return 0;
3874 +
3875 +       return ll_front_merge_fn (q, req, bio);
3876 +}
3877 +static int
3878 +nbd_back_merge_fn (request_queue_t * q, struct request *req,
3879 +                  struct bio * bio)
3880 +{
3881 +       struct nbd_device *lo = req->rq_disk->private_data;
3882 +
3883 +       if (!atomic_read(&lo->merge_requests))
3884 +               return 0;
3885 +
3886 +       if (!ll_back_merge_fn)
3887 +               return 0;
3888 +
3889 +       if (req->nr_sectors > lo->max_sectors)
3890 +               return 0;
3891 +
3892 +       if (req->nr_sectors >
3893 +           ((atomic_read(&lo->merge_requests) + 1) << (lo->logblksize - 9))) return 0;
3894 +
3895 +        return ll_back_merge_fn (q, req, bio);
3896 +}
3897 +
3898 +// PTB - and now to play with the sysctl interface ...
3899 +static struct ctl_table_header *nbd_table_header;
3900 +// the above was set by the register call of the root table
3901 +static ctl_table nbd_table[] = {
3902 +       {1, "rahead",
3903 +        &rahead, sizeof (int), 0644, NULL, &proc_dointvec},
3904 +       {2, "plug",
3905 +        &plug, sizeof (int), 0644, NULL, &proc_dointvec},
3906 +       {3, "sync_intvl",
3907 +        &sync_intvl, sizeof (int), 0644, NULL, &proc_dointvec},
3908 +       {4, "merge_requests",
3909 +        &merge_requests, sizeof (int), 0644, NULL, &proc_dointvec},
3910 +       {5, "md5sum",
3911 +        &md5sum, sizeof (int), 0644, NULL, &proc_dointvec},
3912 +       {8, "md5_on_threshold",
3913 +        &md5_on_threshold, sizeof (int), 0644, NULL, &proc_dointvec},
3914 +       {9, "md5_off_threshold",
3915 +        &md5_off_threshold, sizeof (int), 0644, NULL, &proc_dointvec},
3916 +       {0}
3917 +};
3918 +static ctl_table nbd_dir_table[] = {
3919 +       {6, "enbd", NULL, 0, 0555, nbd_table},
3920 +       {0}
3921 +};
3922 +static ctl_table nbd_root_table[] = {
3923 +       {CTL_DEV, "dev", NULL, 0, 0555, nbd_dir_table},
3924 +       {0}
3925 +};
3926 +
3927 +#ifdef CONFIG_DEVFS_FS
3928 +static devfs_handle_t devfs_handle;
3929 +static devfs_handle_t devfs_handles[MAX_NBD];
3930 +#endif
3931 +
3932 +
3933 +int __init
3934 +nbd_init (void)
3935 +{
3936 +       int i;
3937 +       int err = 0;
3938 +       struct proc_dir_entry *res;
3939 +
3940 +       NBD_INFO ("Network Block Device originally by pavel@elf.mj.gts.cz\n");
3941 +       NBD_INFO ("Network Block Device port to 2.0 by ptb@it.uc3m.es\n");
3942 +       NBD_INFO ("Network Block Device move networking to user space by "
3943 +                 "amarin@it.uc3m.es\n");
3944 +       NBD_INFO ("Enhanced Network Block Device " NBD_VERSION " by "
3945 +                 "ptb@it.uc3m.es\n");
3946 +
3947 +        nbd_queue = kmalloc(sizeof(*nbd_queue), GFP_KERNEL);
3948 +        if (!nbd_queue)
3949 +            return -ENOMEM;
3950 +
3951 +        for (i = 0; i < MAX_NBD; i++) {
3952 +               struct nbd_device *lo = &nbd_dev[i];
3953 +                struct gendisk *disk = alloc_disk(NBD_MAXCONN);
3954 +               memset (lo, 0, sizeof (*lo));
3955 +                if (disk)
3956 +                    lo->disk = disk;
3957 +        }
3958 +
3959 +       if (register_blkdev (major, "nbd", &nbd_blkops)) {
3960 +               NBD_ERROR ("Unable to register major number %d for NBD\n",
3961 +                          major);
3962 +               return -EIO;
3963 +       }
3964 +#ifdef MODULE
3965 +       NBD_INFO ("registered device at major %d\n", major);
3966 +#endif
3967 +
3968 +
3969 +// PTB - set up kernel queue struct with default methods
3970 +       blk_init_queue (nbd_queue, do_nbd_request, &nbd_lock);
3971 +
3972 +        blk_queue_max_sectors(nbd_queue, buf_sectors); /* max per request */
3973 +
3974 +/*
3975 + * PTB - I think that put:
3976 + *     - q->plug_device_fn    = generic_plug_device    (static ll_rw_blk)
3977 + *     - q->plug_tq.routine   = generic_unplug_device  (static ll_rw_blk)
3978 + *     - q->back_merge_fn     = ll_back_merge_fn       (static ll_rw_blk)
3979 + *     - q->front_merge_fn    = ll_front_merge_fn      (static ll_rw_blk)
3980 + *     - q->merge_requests_fn = ll_merge_requests_fn   (static ll_rw_blk)
3981 + *     - q->request_fn        = do_nbd_request         (param)
3982 + */
3983 +
3984 +/*
3985 + * PTB - we have to do some more init magic in 2.4.*. This says that we
3986 + *     - take all stuff off the kernel queue before processing it, so in
3987 + *     - particular iti s OK for kernel to do merges with the queue head.
3988 + *       blk_queue_headactive (nbd_queue, 0);
3989 + */
3990 +
3991 +/*
3992 + * LA - moved the next #if higher;
3993 + *    - kernel 2.2.* doesn't know about plug_device_fn
3994 + */
3995 +
3996 +       // PTB control merge attempts so we do not overflow our buffer
3997 +       ll_merge_requests_fn = nbd_queue->merge_requests_fn;
3998 +       ll_front_merge_fn    = nbd_queue->front_merge_fn;
3999 +       ll_back_merge_fn     = nbd_queue->back_merge_fn;
4000 +
4001 +// JSA - Add this line because under >=2.4.1, merge optimizations are in flux
4002 +/*
4003 + * PTB - however it's not this which does damage, I believe. Data: plugging
4004 + *     - simply has to be enabled in these kernels. Without it, requests just
4005 + *     - sit on the kernel queue and never come off and into our request_fn.
4006 + * PTB - commented the ifdef again after talks with Jens Axboe.
4007 + *     - Apparently plug_fn will disappear in 2.4.4 and merge functions are
4008 + *       the only way to control merges, so they MUST be included.
4009 + */
4010 +
4011 +/*
4012 + * PTB - The functions below just impose our own stricter size limit before
4013 + *     - calling the defaults if all seems OK sizewise.
4014 + */
4015 +       nbd_queue->merge_requests_fn = &nbd_merge_requests_fn;
4016 +       nbd_queue->front_merge_fn    = &nbd_front_merge_fn;
4017 +       nbd_queue->back_merge_fn     = &nbd_back_merge_fn;
4018 +
4019 +        nbd_init_md(&nbd_md);
4020 +        nbd_init_ioctl_stub(&nbd_remote_ioctl);
4021 +
4022 +        for (i = 0; i < MAX_NBD; i++) {
4023 +               struct nbd_device *lo = &nbd_dev[i];
4024 +                nbd_reset(lo, i);
4025 +        }
4026 +
4027 +        /*
4028 +         * PTB we do the disk and partition stuff after we have
4029 +         * contact, when nbd_open is called for the first time?
4030 +         */
4031 +
4032 +        res = create_proc_read_entry ("nbdinfo", 0, NULL, NULL, NULL);
4033 +       if (!res) {
4034 +               NBD_ALERT ("creation of proc entry failed\n");
4035 +               return -EINVAL;
4036 +       }
4037 +       // PTB additional write_proc entry in struct
4038 +        nbd_init_proc(res);
4039 +
4040 +        // PTB make the gendisk structs very late.
4041 +        for (i = 0; i < MAX_NBD; i++) {
4042 +               struct nbd_device *lo = &nbd_dev[i];
4043 +                nbd_set_disk(lo, i * NBD_MAXCONN, NBD_MAXCONN);
4044 +        }
4045 +
4046 +#ifdef CONFIG_DEVFS_FS
4047 +
4048 +       devfs_handle = devfs_mk_dir (NULL, "nd", NULL);
4049 +       if (devfs_handle) {
4050 +               for (i = 0; i < MAX_NBD; i++) {
4051 +                       struct nbd_device *lo = &nbd_dev[i];
4052 +                       int j;
4053 +                       // PTB make the subdirectory "a","b" etc.
4054 +                       devfs_handles[i] =
4055 +                        devfs_mk_dir (devfs_handle, lo->devnam, NULL);
4056 +                       // PTB add the blk specials, "0","1" to NBD_MAXCONN-1
4057 +                       if (!devfs_handles[i])
4058 +                                continue;
4059 +                       for (j = 0; j < MAX_NBD; j++) {
4060 +                               char name[4];
4061 +                               sprintf (name, "%u", j);
4062 +                                devfs_register(devfs_handles[i], name,
4063 +                                        DEVFS_FL_DEFAULT,
4064 +                                        major, i * NBD_MAXCONN + j,
4065 +                                        S_IFBLK | S_IRUSR | S_IWUSR,
4066 +                                        &nbd_blkops, NULL);
4067 +                        }
4068 +                       // PTB do the whole disk symlink ..
4069 +                       devfs_mk_symlink (devfs_handles[i], "disk",
4070 +                                         DEVFS_FL_DEFAULT, "0",
4071 +                                         NULL, NULL);
4072 +                       // PTB .. and the channel symlinks
4073 +                       for (j = 1; j < MAX_NBD; j++) {
4074 +                               char link[4];
4075 +                               char name[8];
4076 +                               sprintf (link, "%u", j);
4077 +                               sprintf (name, "chan%u", j);
4078 +                               devfs_mk_symlink (devfs_handles[i],
4079 +                                                 name,
4080 +                                                 DEVFS_FL_DEFAULT,
4081 +                                                 link, NULL, NULL);
4082 +                       }
4083 +               }
4084 +       }
4085 +#endif         /* CONFIG_DEVFS_FS */
4086 +
4087 +       // PTB - sysctl interface
4088 +       nbd_table_header = register_sysctl_table (nbd_root_table, 1);
4089 +
4090 +        // PTB we have to wait for the open to complete init with inode val
4091 +
4092 +       return err;
4093 +}
4094 +
4095 +void __exit
4096 +nbd_cleanup (void)
4097 +{
4098 +       int i;
4099 +
4100 +       for (i = 0; i < MAX_NBD; i++) {
4101 +
4102 +               struct nbd_device *lo = &nbd_dev[i];
4103 +               int j;
4104 +
4105 +               if (!(atomic_read (&lo->flags) & NBD_INITIALISED))
4106 +                       continue;
4107 +
4108 +               NBD_INFO ("invalidating buffers on device nd%s%d-%d\n",
4109 +                         lo->devnam, 0, NBD_MAXCONN);
4110 +
4111 +               for (j = 0; j < NBD_MAXCONN; j++) {
4112 +                       int minor = i * NBD_MAXCONN + j;
4113 +                       invalidate_buffers (mk_kdev (major, minor));
4114 +               }
4115 +
4116 +               NBD_INFO ("destroying buffers on device nd%s%d-%d\n",
4117 +                         lo->devnam, 0, NBD_MAXCONN);
4118 +
4119 +               for (j = 0; j < NBD_MAXCONN; j++) {
4120 +                       int minor = i * NBD_MAXCONN + j;
4121 +                       __invalidate_buffers (mk_kdev (major, minor), 1);
4122 +               }
4123 +       }
4124 +
4125 +       unregister_sysctl_table (nbd_table_header);
4126 +
4127 +#ifdef CONFIG_DEVFS_FS
4128 +       if (devfs_handle) {
4129 +               for (i = 0; i < MAX_NBD; i++) {
4130 +                       int j;
4131 +                       if (!devfs_handles[i])
4132 +                               continue;
4133 +                       for (j = 0; j < NBD_MAXCONN; j++) {
4134 +                               char s[3];
4135 +                               s[0] = '0' + j;
4136 +                               s[1] = 0;
4137 +                               if (j >= 10) {
4138 +                                       s[0] = '1';
4139 +                                       s[1] = '0' + (j - 10);
4140 +                                       s[2] = 0;
4141 +                               }
4142 +                               devfs_remove("nd/%s/%u", device_letter(i), j);
4143 +                                if (j == 0) {
4144 +                                       devfs_remove("nd/%s/disk", device_letter(i));
4145 +                                } else {
4146 +                                       devfs_remove("nd/%s/chan%u",device_letter(i),j);
4147 +                                }
4148 +                       }
4149 +                       devfs_remove("nd/%s", device_letter(i));
4150 +               }
4151 +               devfs_remove("nd");
4152 +       }
4153 +#endif
4154 +
4155 +       remove_proc_entry ("nbdinfo", &proc_root);
4156 +
4157 +       for (i = 0; i < MAX_NBD; i++) {
4158 +               struct nbd_device *lo = &nbd_dev[i];
4159 +               atomic_clear_mask (NBD_ENABLED, &lo->flags);
4160 +                if (lo->disk) {
4161 +                    del_gendisk(lo->disk);
4162 +                    put_disk(lo->disk);
4163 +                }
4164 +               if (lo->blockmap) {
4165 +                       kfree (lo->blockmap);
4166 +                       lo->blockmap = NULL;
4167 +               }
4168 +               nbd_sync_sync (lo);
4169 +       }
4170 +
4171 +       blk_cleanup_queue (nbd_queue);
4172 +
4173 +       if (unregister_blkdev (major, "nbd") != 0) {
4174 +               NBD_ALERT ("cleanup_module failed\n");
4175 +       } else {
4176 +               NBD_INFO ("module cleaned up.\n");
4177 +       }
4178 +        kfree(nbd_queue);
4179 +        
4180 +}
4181 +
4182 +module_init (nbd_init);
4183 +module_exit (nbd_cleanup);
4184 +
4185 +EXPORT_SYMBOL(nbd_remote_ioctl);
4186 +
4187 +/* Compile line:
4188 +
4189 + *  gcc -O2 -D__KERNEL__ -DMODULE -DEXPORT_SYMTAB -xc -c enbd.c -o enbd.o
4190 + *
4191 + *  (possibly with -DMODVERSIONS also). PTB
4192 + *  (possibly with -I/usr/src/linux-x.y.z/include also). PTB
4193 + */
4194 --- linux-2.5.64/drivers/block/enbd/enbd_ioctl.c.pre-enbd       Mon Mar 24 18:55:25 2003
4195 +++ linux-2.5.64/drivers/block/enbd/enbd_ioctl.c        Tue Mar 25 15:45:03 2003
4196 @@ -0,0 +1,405 @@
4197 +#ifndef __KERNEL__
4198 +#include <sys/time.h>
4199 +#include <unistd.h>
4200 +#endif
4201 +
4202 +#include <linux/ioctl.h>
4203 +#include <linux/fs.h>
4204 +#include <linux/fd.h>
4205 +#ifndef _CADDR_T
4206 +#define caddr_t char*
4207 +#endif
4208 +#include <linux/cdrom.h>
4209 +#include <asm/uaccess.h>
4210 +#include <linux/module.h>
4211 +#include <linux/version.h>
4212 +#include <linux/init.h>
4213 +#ifndef KERNEL_VERSION
4214 +#define KERNEL_VERSION(a,b,c)  (((a) << 16) + ((b) << 8) + (c))
4215 +#endif
4216 +#include <linux/blk.h>
4217 +#include <linux/enbd.h>
4218 +#include <linux/enbd_ioctl.h>
4219 +
4220 +
4221 +/*
4222 + * This is the whitelist of remote ioctls - an entry here tells the
4223 + * driver that it's OK to send this ioctl out over the net, because we
4224 + * have the right info on it.
4225 + *
4226 + * "The right info" is what is on the right hand side of the table (a 0
4227 + * stands for a repetition of the LHS info). We have to fixup something
4228 + * that a lot of kernel authors forgot to do or got worng - namely
4229 + * declare their ioctls in a way that conveys information about their
4230 + * intended mode of use (see iotcl.h in the kernel sources).
4231 + *
4232 + * We need all ioctls to be delared as either
4233 + *
4234 + *    _IO(class,id)         -- default. Means no args. The call is enough.
4235 + *    _IOW(class,id,type)   -- we write a value to kernel that is sizeof(type)
4236 + *    _IOR(class,id,type)   -- we read a value from kernel sizeof(type)
4237 + *    _IOWR(class,id,type)  -- ibid, but both ways
4238 + *
4239 + *  The "R" bit is crucial because it lets us know that the data is
4240 + *  _indirected_. I.e. it's an address of somewhere in userspace where
4241 + *  we want to read data from or write data to. 
4242 + *
4243 + *  The "type" part should be the type of the indirected argument, NOT
4244 + *  the type of its address!
4245 + *
4246 + *  Kernel authors typically make two mistakes:
4247 + *
4248 + *     1) they write _IO instead of _IOR or IOWR, and hence forget the
4249 + *        type info. Well, not telling me if the argument data is
4250 + *        direct or indirectly accessible was already bad enough!
4251 + *     2) they get the type argument _wrong_ when they do remember to
4252 + *        put it. They write "int *" instead  of "int", for example,
4253 + *        when the argument to the ioctl is a pointer to an integer.
4254 + *        OK, so it's a natural mistake to make! But in that case the
4255 + *        argument should be "int" so that the kernel macro picks up
4256 + *        sizeof(int) instead of sizeof(int*).
4257 + *
4258 + *  Those "errors" have to be repaired via this table. Wrong at left,
4259 + *  corrected at right. A 0 for the new entry indicates that the old
4260 + *  was alright. If there isn't an entry, the ioctl won't be treated.
4261 + *  If the size info works out at the max for the field  (2^14 - 1)
4262 + *  then a extra table is consulted for size and copy methods.
4263 + */
4264 +
4265 +
4266 +/*
4267 + * PTB the space before the final comma is important as the ##
4268 + * discards the preceding token when D is empty
4269 + */
4270 +#define _NEW_IO_(B,C,D...) C(_IOC_TYPE(B), _IOC_NR(B) , ## D)
4271 +#define _NEW_IO(B,D...)   _IO(_IOC_TYPE(B), _IOC_NR(B) , ## D)
4272 +#define _NEW_IOW(B,D...)  _IOW(_IOC_TYPE(B), _IOC_NR(B) , ## D)
4273 +#define _NEW_IOR(B,D...)  _IOR(_IOC_TYPE(B), _IOC_NR(B) , ## D)
4274 +#define _NEW_IOWR(B,D...) _IOWR(_IOC_TYPE(B), _IOC_NR(B) , ## D)
4275 +#define _NEW_IORS(B) _IOC(_IOC_READ,_IOC_TYPE(B), _IOC_NR(B), _IOC_SIZEMASK)
4276 +#define _NEW_IOWRS(B) _IOC(_IOC_READ|_IOC_WRITE,_IOC_TYPE(B), _IOC_NR(B), _IOC_SIZEMASK)
4277 +
4278 +static struct ioctl_conv ioctl_conv_tab[] = {
4279 +// fs.h
4280 +   { BLKROSET, _NEW_IOW(BLKROSET,int), },
4281 +   { BLKROGET, _NEW_IOR(BLKROGET,int), },
4282 +//#define BLKRRPART  _IO(0x12,95) /* re-read partition table */
4283 +   { BLKRRPART,  0, },
4284 +   { BLKGETSIZE, _NEW_IOR(BLKGETSIZE,int), },
4285 +//#define BLKFLSBUF  _IO(0x12,97) /* flush buffer cache */
4286 +   { BLKFLSBUF,  0, },
4287 +   { BLKRASET,   _NEW_IOW(BLKRASET,int), },
4288 +   { BLKRAGET,   _NEW_IOR(BLKRAGET,int), },
4289 +   { BLKFRASET,  _NEW_IOW(BLKFRASET,int), },
4290 +   { BLKFRAGET,  _NEW_IOR(BLKFRAGET,int), },
4291 +   { BLKSECTSET, _NEW_IOW(BLKSECTSET,int), },
4292 +   { BLKSECTGET, _NEW_IOR(BLKSECTGET,int), },
4293 +   { BLKSSZGET,  _NEW_IOR(BLKSSZGET,int), },
4294 +//  fd.h
4295 +   { FDCLRPRM,  0, },
4296 +   { FDSETPRM, _NEW_IOWR(FDSETPRM, struct floppy_struct), },
4297 +   { FDDEFPRM, _NEW_IOWR(FDDEFPRM, struct floppy_struct), }, 
4298 +   { FDGETPRM, _NEW_IOR(FDGETPRM, struct floppy_struct), }, 
4299 +   { FDMSGON,   0, }, 
4300 +   { FDMSGOFF,  0, }, 
4301 +   { FDFMTBEG,  0, }, 
4302 +   { FDFMTTRK, _NEW_IOWR(FDFMTTRK, struct format_descr), }, 
4303 +   { FDFMTEND,  0, }, 
4304 +   { FDSETEMSGTRESH, _NEW_IOW(FDSETEMSGTRESH, unsigned), }, 
4305 +   { FDFLUSH,  0, }, 
4306 +   { FDSETMAXERRS, _NEW_IOWR(FDSETMAXERRS, struct floppy_max_errors), }, 
4307 +   { FDGETMAXERRS, _NEW_IOR(FDGETMAXERRS, struct floppy_max_errors), }, 
4308 +   { FDGETDRVTYP, _NEW_IOR(FDGETDRVTYP, floppy_drive_name), }, // 16 bytes
4309 +   { FDSETDRVPRM, _NEW_IOWR(FDSETDRVPRM, struct floppy_drive_params), }, 
4310 +   { FDGETDRVPRM, _NEW_IOR(FDGETDRVPRM, struct floppy_drive_params), }, 
4311 +   { FDGETDRVSTAT, _NEW_IOR(FDGETDRVSTAT, struct floppy_drive_struct), }, 
4312 +   { FDPOLLDRVSTAT, _NEW_IOR(FDPOLLDRVSTAT, struct floppy_drive_struct), }, 
4313 +   { FDRESET,  0, }, 
4314 +   { FDGETFDCSTAT, _NEW_IOR(FDGETFDCSTAT, struct floppy_fdc_state), }, 
4315 +   { FDWERRORCLR,  0, }, 
4316 +   { FDWERRORGET, _NEW_IOR(FDWERRORGET, struct floppy_write_errors), }, 
4317 +   { FDRAWCMD, _NEW_IOWR(FDRAWCMD, struct floppy_raw_cmd[1]) },  // FIXME linked list
4318 +   { FDTWADDLE,  0, }, 
4319 +   { FDEJECT,  0, }, 
4320 +// cdrom.h
4321 +   { CDROMPAUSE, _NEW_IO(CDROMPAUSE), }, 
4322 +   { CDROMRESUME, _NEW_IO(CDROMRESUME), }, 
4323 +   { CDROMPLAYMSF, _NEW_IOR(CDROMPLAYMSF, struct cdrom_msf), }, 
4324 +   { CDROMPLAYTRKIND, _NEW_IOR(CDROMPLAYTRKIND, struct cdrom_ti), }, 
4325 +   { CDROMREADTOCHDR, _NEW_IOWR(CDROMREADTOCHDR, struct cdrom_tochdr), }, 
4326 +   { CDROMREADTOCENTRY, _NEW_IOWR(CDROMREADTOCENTRY, struct cdrom_tocentry), }, 
4327 +   { CDROMSTOP, _NEW_IO(CDROMSTOP), }, 
4328 +   { CDROMSTART, _NEW_IO(CDROMSTART), }, 
4329 +   { CDROMEJECT, _NEW_IO(CDROMEJECT), }, 
4330 +   { CDROMVOLCTRL, _NEW_IOR(CDROMVOLCTRL, struct cdrom_volctrl), }, 
4331 +   { CDROMSUBCHNL, _NEW_IOWR(CDROMSUBCHNL, struct cdrom_subchnl), }, 
4332 +   { CDROMREADMODE2, _NEW_IOR(CDROMREADMODE2, struct cdrom_read), },  // INDIRECT 2336B
4333 +   { CDROMREADMODE1, _NEW_IOR(CDROMREADMODE1, struct cdrom_read), },  // INDIRECT 2048B
4334 +   { CDROMREADAUDIO, _NEW_IOR(CDROMREADAUDIO, struct cdrom_read_audio), }, 
4335 +   { CDROMEJECT_SW, _NEW_IO(CDROMEJECT_SW), }, 
4336 +   { CDROMMULTISESSION, _NEW_IOWR(CDROMMULTISESSION, struct cdrom_multisession), }, 
4337 +   { CDROM_GET_MCN, _NEW_IOWR(CDROM_GET_MCN, struct cdrom_mcn), }, 
4338 +   { CDROMRESET, _NEW_IO(CDROMRESET), }, 
4339 +   { CDROMVOLREAD, _NEW_IOWR(CDROMVOLREAD, struct cdrom_volctrl), }, 
4340 +   { CDROMREADRAW, _NEW_IOR(CDROMREADRAW, struct cdrom_read), },  // INDIRECT 2352B
4341 +   // aztcd.c optcd.c
4342 +   { CDROMREADCOOKED, _NEW_IOR(CDROMREADCOOKED, struct cdrom_msf), }, // INDIRECT FIXME
4343 +   { CDROMSEEK, _NEW_IOR(CDROMSEEK, struct cdrom_msf), }, 
4344 +   // scsi-cd.c
4345 +   { CDROMPLAYBLK, _NEW_IOWR(CDROMPLAYBLK, struct cdrom_blk), }, 
4346 +   // optcd.c
4347 +   { CDROMREADALL, _NEW_IOR(CDROMREADALL, char[2646]), }, 
4348 +   // ide-cd.c
4349 +   { CDROMGETSPINDOWN, _NEW_IOWR(CDROMGETSPINDOWN, char), },  // one byte
4350 +   { CDROMSETSPINDOWN, _NEW_IOWR(CDROMSETSPINDOWN, char), },  // one byte
4351 +   // cdrom.c
4352 +   { CDROMCLOSETRAY, _NEW_IO(CDROMCLOSETRAY), },
4353 +   { CDROM_SET_OPTIONS, _NEW_IOW(CDROM_SET_OPTIONS, int), },
4354 +   { CDROM_CLEAR_OPTIONS, _NEW_IOW(CDROM_CLEAR_OPTIONS, int), },
4355 +   { CDROM_SELECT_SPEED, _NEW_IOW(CDROM_SELECT_SPEED, int), }, // FIXME 
4356 +   { CDROM_SELECT_DISC, _NEW_IOW(CDROM_SELECT_DISC, int), },
4357 +   { CDROM_MEDIA_CHANGED, _NEW_IOW(CDROM_MEDIA_CHANGED, int), },
4358 +   { CDROM_DRIVE_STATUS, _NEW_IOW(CDROM_DRIVE_STATUS, int), },
4359 +   { CDROM_DISC_STATUS, _NEW_IO(CDROM_DISC_STATUS), },
4360 +   { CDROM_CHANGER_NSLOTS, _NEW_IO(CDROM_CHANGER_NSLOTS), },
4361 +   { CDROM_LOCKDOOR, _NEW_IOW(CDROM_LOCKDOOR, int), },
4362 +   { CDROM_DEBUG, _NEW_IOW(CDROM_DEBUG, int), },
4363 +   { CDROM_GET_CAPABILITY, _NEW_IO(CDROM_GET_CAPABILITY), },
4364 +   // sbpcd
4365 +   { CDROMAUDIOBUFSIZ, _NEW_IOW(CDROMAUDIOBUFSIZ, int), },
4366 +   // dvd
4367 +   { DVD_READ_STRUCT, _NEW_IOR(DVD_READ_STRUCT, dvd_struct), },
4368 +   { DVD_WRITE_STRUCT, _NEW_IOWR(DVD_WRITE_STRUCT, dvd_struct), },
4369 +   { DVD_AUTH, _NEW_IOWR(DVD_AUTH, dvd_authinfo), },
4370 +   { CDROM_SEND_PACKET, _NEW_IOR(CDROM_SEND_PACKET, struct cdrom_generic_command), },
4371 +   { CDROM_NEXT_WRITABLE, _NEW_IOWR(CDROM_NEXT_WRITABLE, long), },
4372 +   { CDROM_LAST_WRITTEN, _NEW_IOWR(CDROM_LAST_WRITTEN, long), },
4373 +   // PTB local test ioctls
4374 +   { NBD_TEST_IOCTL1, 0, },   // write an int
4375 +   { NBD_TEST_IOCTL2, 0, },   // read an int
4376 +   { NBD_TEST_IOCTL3, 0, },   // write and read an int
4377 +   { NBD_TEST_IOCTL4, 0, },   // read 256B
4378 +   { NBD_TEST_IOCTL5, 0, },   // r/w 256B
4379 +   { NBD_TEST_IOCTL6, _NEW_IORS(NBD_TEST_IOCTL6), },    // read special
4380 +   { NBD_TEST_IOCTL7, _NEW_IORS(NBD_TEST_IOCTL7), },    // r/w special
4381 +   // PTB we must terminate with a 0,0 entry.
4382 +   {0 , 0, },
4383 +};
4384 +
4385 +/*
4386 + * This should be the table of special methods for certain ioctls.
4387 + * The "new" code is the real index. It will have a size count of
4388 + * _IOC_SIZEMASK but the rest of it should be meaningful. The size is
4389 + * gotten by dynamic lookup using the size() function.
4390 + */
4391 +static struct ioctl_special ioctl_special_tab[] = {
4392 +    // PTB last entry must be all zeros
4393 +    { 0, NULL, NULL, NULL, NULL, },
4394 +};
4395 +
4396 +
4397 +static struct ioctl_conv *
4398 +ioctl_lookup_old (int ioctl)
4399 +{
4400 +       int i;
4401 +        unsigned old;
4402 +        if (ioctl == -1)
4403 +            return NULL;
4404 +       for (i = 0; old = ioctl_conv_tab[i].old, old; i++) {
4405 +               if (old == ioctl)
4406 +                       return &ioctl_conv_tab[i];
4407 +       }
4408 +       // PTB not there
4409 +       return NULL;
4410 +}
4411 +
4412 +int
4413 +nbd_ioctl_convert (int ioctl)
4414 +{
4415 +       struct ioctl_conv *conv = ioctl_lookup_old (ioctl);
4416 +       if (!conv)
4417 +               // PTB not there
4418 +               return -1;
4419 +        return conv->new ? : ioctl;
4420 +}
4421 +
4422 +int
4423 +nbd_ioctl_convert_inplace(int *ioctl) {
4424 +
4425 +       int new_ioctl;
4426 +       if (!ioctl)
4427 +           return -EINVAL;
4428 +       new_ioctl = nbd_ioctl_convert(*ioctl);
4429 +       if (new_ioctl == -1)
4430 +           return -EINVAL;
4431 +       *ioctl = new_ioctl;
4432 +       return 0;
4433 +}
4434 +
4435 +static struct ioctl_conv *
4436 +ioctl_lookup_new (int ioctl)
4437 +{
4438 +       int i = 0;
4439 +       unsigned old;
4440 +       for (i = 0; old = ioctl_conv_tab[i].old, old; i++) {
4441 +               unsigned new = ioctl_conv_tab[i].new;
4442 +               if (new == ioctl || (new == 0 && old == ioctl)) 
4443 +                       return &ioctl_conv_tab[i];
4444 +       }
4445 +       // PTB not there
4446 +       return NULL;
4447 +}
4448 +
4449 +int
4450 +nbd_ioctl_revert (int ioctl)
4451 +{
4452 +       struct ioctl_conv *conv = ioctl_lookup_new (ioctl);
4453 +       if (!conv)
4454 +               // PTB not there
4455 +               return -1;
4456 +       return conv->old;
4457 +}
4458 +
4459 +static struct ioctl_special *
4460 +ioctl_special_lookup_new (int ioctl)
4461 +{
4462 +       int i;
4463 +        unsigned new;
4464 +       for (i = 0; new = ioctl_special_tab[i].new, new; i++) {
4465 +               if (new == ioctl) 
4466 +                       return &ioctl_special_tab[i];
4467 +       }
4468 +       // PTB not there
4469 +       return NULL;
4470 +}
4471 +
4472 +int
4473 +nbd_ioctl_size (int cmd, char *arg)
4474 +{
4475 +       int size = _IOC_SIZE (cmd);
4476 +       if (size == _IOC_SIZEMASK) {
4477 +               // PTB special hadling required. 
4478 +                struct ioctl_special *special = ioctl_special_lookup_new(cmd);
4479 +                if (!special)
4480 +                        return -1;
4481 +               return special->size (arg);
4482 +       }
4483 +       return size;
4484 +}
4485 +
4486 +int
4487 +nbd_ioctl_size_user (int cmd, char *arg)
4488 +{
4489 +       int size = _IOC_SIZE (cmd);
4490 +       if (size == _IOC_SIZEMASK) {
4491 +               // PTB special hadling required. 
4492 +                struct ioctl_special *special = ioctl_special_lookup_new(cmd);
4493 +                if (!special)
4494 +                        return -1;
4495 +               return special->size_user (arg);
4496 +       }
4497 +       return size;
4498 +}
4499 +
4500 +
4501 +#ifdef __KERNEL__
4502 +int
4503 +nbd_ioctl_copy_to_user (int cmd, char *arg, char *buf, int size)
4504 +{
4505 +
4506 +       if (_IOC_SIZE (cmd) == _IOC_SIZEMASK) {
4507 +                struct ioctl_special *special = ioctl_special_lookup_new(cmd);
4508 +                if (!special)
4509 +                        return -1;
4510 +               return special->ioctl_copy_to_user (arg, buf, size);
4511 +       }
4512 +
4513 +       if (_IOC_DIR (cmd) & _IOC_READ) {
4514 +               // indirect
4515 +               copy_to_user (arg, buf, size);
4516 +               return size;
4517 +       }
4518 +
4519 +       return -1;
4520 +}
4521 +
4522 +
4523 +
4524 +int
4525 +nbd_ioctl_copy_from_user (int cmd, char *buf, char *arg, int size)
4526 +{
4527 +
4528 +       if (_IOC_SIZE (cmd) == _IOC_SIZEMASK) {
4529 +                struct ioctl_special *special = ioctl_special_lookup_new(cmd);
4530 +                if (!special)
4531 +                        return -1;
4532 +               return special->ioctl_copy_from_user (buf, arg, size);
4533 +       }
4534 +
4535 +       if (_IOC_DIR (cmd) & _IOC_READ) {
4536 +               // indirect
4537 +               copy_from_user (buf, arg, size);
4538 +               return size;
4539 +       }
4540 +
4541 +       // direct
4542 +       if (size > sizeof (arg)) {
4543 +               return -1;
4544 +       }
4545 +
4546 +       memcpy (buf, &arg, size);
4547 +       return size;
4548 +}
4549 +
4550 +static struct nbd_ioctl struct_ioctl = {
4551 +        convert : nbd_ioctl_convert,
4552 +        convert_inplace : nbd_ioctl_convert_inplace,
4553 +        revert  : nbd_ioctl_revert,
4554 +        size    : nbd_ioctl_size,
4555 +        size_user : nbd_ioctl_size_user,
4556 +        cp_to_user : nbd_ioctl_copy_to_user,
4557 +        cp_from_user : nbd_ioctl_copy_from_user,
4558 +};
4559 +
4560 +static int __init
4561 +nbd_ioctl_init (void)
4562 +{
4563 +    struct nbd_ioctl_stub * remote_ioctl = &nbd_remote_ioctl;
4564 +    remote_ioctl->reg(remote_ioctl, &struct_ioctl);
4565 +    return 0;
4566 +}
4567 +
4568 +static void __exit
4569 +nbd_ioctl_cleanup (void) {
4570 +    struct nbd_ioctl_stub * remote_ioctl = &nbd_remote_ioctl;
4571 +    remote_ioctl->unreg(remote_ioctl, &struct_ioctl);
4572 +}
4573 +
4574 +module_init (nbd_ioctl_init);
4575 +module_exit (nbd_ioctl_cleanup);
4576 +
4577 +int linux_version_code = LINUX_VERSION_CODE;
4578 +
4579 +#ifdef MODULE
4580 +  #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
4581 +    MODULE_AUTHOR ("Peter T. Breuer");
4582 +    MODULE_DESCRIPTION ("Enhanced Network Block Device Remote Ioctl");
4583 +    #ifdef MODULE_LICENSE
4584 +      MODULE_LICENSE("GPL");
4585 +    #endif
4586 +  #endif
4587 +#endif         /* MODULE */
4588 +
4589 +#endif /* __KERNEL__ */
4590 +
4591 +
4592 +/*
4593 +static
4594 +int ioctl_init(struct ioctl_conv *self, int old, int new) {
4595 +    self->old = old;
4596 +    self->new = new;
4597 +    self->serialize = ioctl_serialize;
4598 +    self->deserialize = ioctl_deserialize;
4599 +    self->size = ioctl_size;
4600 +}
4601 +*/
4602 --- linux-2.5.64/drivers/block/enbd/enbd_ioctl_stub.c.pre-enbd  Mon Mar 24 18:55:25 2003
4603 +++ linux-2.5.64/drivers/block/enbd/enbd_ioctl_stub.c   Mon Mar 24 22:51:59 2003
4604 @@ -0,0 +1,30 @@
4605 +
4606 +#include <linux/stddef.h>
4607 +#include <linux/errno.h>
4608 +#include <linux/enbd.h>
4609 +#include <linux/enbd_ioctl.h>
4610 +
4611 +  /*
4612 +   * PTB this is the hook for the enbd_ioctl extra module
4613 +   */
4614 +  static int register_remote_ioctl(struct nbd_ioctl_stub *remote_ioctl, struct nbd_ioctl *x) {
4615 +          if (!remote_ioctl->remote) {
4616 +                remote_ioctl->remote = x;
4617 +                return 0;
4618 +          }
4619 +          return -EINVAL;
4620 +  }
4621 +  static int unregister_remote_ioctl(struct nbd_ioctl_stub *remote_ioctl, struct nbd_ioctl *x) {
4622 +        if (remote_ioctl->remote != x)
4623 +                return -EINVAL;
4624 +        remote_ioctl->remote = NULL;
4625 +        return 0;
4626 +  }
4627 +
4628 +int nbd_init_ioctl_stub(struct nbd_ioctl_stub *remote_ioctl) {
4629 +        memset(remote_ioctl, 0, sizeof(*remote_ioctl));
4630 +        remote_ioctl->reg = register_remote_ioctl;
4631 +        remote_ioctl->unreg = unregister_remote_ioctl;
4632 +        return 0;
4633 +}
4634 +
4635 --- linux-2.5.64/drivers/block/enbd/enbd_md.c.pre-enbd  Mon Mar 24 18:55:25 2003
4636 +++ linux-2.5.64/drivers/block/enbd/enbd_md.c   Mon Mar 24 22:51:59 2003
4637 @@ -0,0 +1,99 @@
4638 +#include <linux/enbd.h>
4639 +#include <linux/enbd_ioctl.h>
4640 +
4641 +/*
4642 + * PTB small driver wide support database for MDRGTR ioctl
4643 + */
4644 +
4645 +
4646 +
4647 +#ifndef HOT_ADD_DISK
4648 +  #define HOT_ADD_DISK          _IO (MD_MAJOR, 0x28)
4649 +#endif
4650 +#ifndef SET_DISK_FAULTY
4651 +  #define SET_DISK_FAULTY       _IO (MD_MAJOR, 0x29)
4652 +#endif
4653 +
4654 +static void
4655 +nbd_md_dec (struct nbd_md *md) {
4656 +        down(&md->access_sem);
4657 +        if (--md->count <= 0)
4658 +                md->notify_fn = NULL;
4659 +        up(&md->access_sem);
4660 +}
4661 +static void
4662 +nbd_md_inc (struct nbd_md *md) {
4663 +        down(&md->access_sem);
4664 +        md->count++;
4665 +        up(&md->access_sem);
4666 +}
4667 +static void
4668 +nbd_md_reg (struct nbd_md *md, int(*fn)(kdev_t, int)) {
4669 +        down(&md->access_sem);
4670 +        if (!md->notify_fn) {
4671 +                md->notify_fn = fn;
4672 +                md->count++;
4673 +        }
4674 +        up(&md->access_sem);
4675 +}
4676 +
4677 +/*
4678 + * PTB tell md devices in which we are embedded that we are alright
4679 + *
4680 + *   @lo the nbd device to tell them about
4681 + */
4682 +static int
4683 +nbd_notify_md_devices (struct nbd_md *md, kdev_t nbd_dev)
4684 +{
4685 +       //kdev_t nbd_dev = mk_kdev (major, nbd << NBD_SHIFT);
4686 +        int err;
4687 +
4688 +       down (&md->access_sem);
4689 +       if (md->count > 0 && md->notify_fn) {
4690 +               NBD_ALERT ("adding %x:%x to raid devices via fn\n",
4691 +                        major(nbd_dev), minor(nbd_dev));
4692 +               err = md->notify_fn (nbd_dev, HOT_ADD_DISK);
4693 +               if (err < 0) {
4694 +                       NBD_ALERT ("HOT_ADD to raid devices returned %d\n",
4695 +                                err);
4696 +               }
4697 +       }
4698 +       up (&md->access_sem);
4699 +
4700 +       return 0;
4701 +}
4702 +
4703 +static int
4704 +nbd_unnotify_md_devices (struct nbd_md *md, kdev_t nbd_dev)
4705 +{
4706 +
4707 +       // kdev_t nbd_dev = mk_kdev (major, lo->nbd << NBD_SHIFT);
4708 +        int err;
4709 +
4710 +       down (&md->access_sem);
4711 +       if (md->count > 0 && md->notify_fn) {
4712 +               NBD_ALERT ("erasing %x:%x from raid devices via fn\n",
4713 +                          major(nbd_dev), minor(nbd_dev));
4714 +               err = md->notify_fn (nbd_dev, SET_DISK_FAULTY);
4715 +               if (err < 0) {
4716 +                       NBD_ALERT
4717 +                        ("SETFAULTY to raid devices returned %d\n", err);
4718 +               }
4719 +       }
4720 +       up (&md->access_sem);
4721 +        return 0;
4722 +}
4723 +
4724 +void
4725 +nbd_init_md(struct nbd_md *md)
4726 +{
4727 +        md->notify_fn = NULL;
4728 +        md->count = 0;
4729 +        init_MUTEX(&md->access_sem);
4730 +        md->notify = nbd_notify_md_devices;
4731 +        md->unnotify = nbd_unnotify_md_devices;
4732 +        md->dec = nbd_md_dec;
4733 +        md->inc = nbd_md_inc;
4734 +        md->reg = nbd_md_reg;
4735 +}
4736 +
4737 --- linux-2.5.64/drivers/block/enbd/enbd_seqno.c.pre-enbd       Mon Mar 24 18:55:25 2003
4738 +++ linux-2.5.64/drivers/block/enbd/enbd_seqno.c        Mon Mar 24 23:28:41 2003
4739 @@ -0,0 +1,75 @@
4740 +#include <linux/enbd.h>
4741 +
4742 +
4743 +#define _NBD_GENERATION (8*sizeof(int) - __REQ_NBDSEQNO)
4744 +/*
4745 + * PTB increment the devices seqno
4746 + *
4747 + *  @lo the nbd device to increment the seqno of
4748 + */
4749 +static void
4750 +seqno_inc(struct nbd_seqno *nseqno)
4751 +{
4752 +       if (nseqno->seqno < (1 << _NBD_GENERATION)) {
4753 +               ++nseqno->seqno;
4754 +                return;
4755 +        } 
4756 +        // PTB next generation !
4757 +       nseqno->seqno = 0;
4758 +       atomic_inc (&nseqno->seqno_gen);
4759 +}
4760 +static int
4761 +seqno_get (struct nbd_seqno *nseqno)
4762 +{
4763 +        return nseqno->seqno;
4764 +}
4765 +static void
4766 +seqno_reset (struct nbd_seqno *nseqno)
4767 +{
4768 +        nseqno->seqno = 0;
4769 +       atomic_set(&nseqno->seqno_gen,0);
4770 +}
4771 +/*
4772 + * PTB convert a seqno number into one with an extra generation number
4773 + * in the msb, so that it can be compared with others. return the
4774 + * result.
4775 + *
4776 + * We add the current generation no. to small seqnos, and we add the
4777 + * previous generation no. to large seqnos.
4778 + *
4779 + *   @lo the nbd device to look at
4780 + *   @seqno the small sequence number to return the full seq number for
4781 + */
4782 +static unsigned int
4783 +seqno_calc (struct nbd_seqno *nseqno, unsigned int seqno)
4784 +{
4785 +        unsigned int genno;
4786 +        static unsigned int absdiff(unsigned int x, unsigned int y) {
4787 +            if (x > y) {
4788 +                return x - y;
4789 +            } else {
4790 +                return y - x;
4791 +            }
4792 +        };
4793 +        genno = atomic_read (&nseqno->seqno_gen);
4794 +       if (absdiff(seqno,nseqno->seqno) < (1 << (_NBD_GENERATION - 1))) {
4795 +               return seqno + (genno << _NBD_GENERATION);
4796 +       }
4797 +        if (seqno < nseqno->seqno) {
4798 +               return seqno + ((genno + 1) << _NBD_GENERATION);
4799 +        } 
4800 +        return seqno + ((genno - 1) << _NBD_GENERATION);
4801 +}
4802 +
4803 +void nbd_init_seqno (struct nbd_seqno *nseqno) {
4804 +
4805 +        seqno_reset(nseqno);
4806 +
4807 +        nseqno->inc   = seqno_inc;
4808 +        nseqno->get   = seqno_get;
4809 +        nseqno->reset = seqno_reset;
4810 +        nseqno->calc  = seqno_calc;
4811 +}
4812 +
4813 +
4814 +
4815 --- linux-2.5.64/drivers/block/enbd/enbd_speed.c.pre-enbd       Mon Mar 24 18:55:25 2003
4816 +++ linux-2.5.64/drivers/block/enbd/enbd_speed.c        Mon Mar 24 23:28:50 2003
4817 @@ -0,0 +1,64 @@
4818 +#include <linux/enbd.h>
4819 +#include <linux/enbd_ioctl.h>
4820 +
4821 +/*
4822 + * PTB - update speed counters (if at least 5s has passed)
4823 + *
4824 + *  @spd the speed struct to update
4825 + */
4826 +static void
4827 +spd_update (struct nbd_speed *spd, int distance)
4828 +{
4829 +
4830 +       // last time we measured
4831 +       int lastjiffy = atomic_read (&spd->jiffy);
4832 +       // jiffies since last time
4833 +       int djiffy = jiffies - lastjiffy;
4834 +
4835 +       // previous no we measured
4836 +       int lastdist = atomic_read (&spd->distance);
4837 +       // blocks since last time
4838 +       int ddistance = distance - lastdist;
4839 +
4840 +       // write every 5 second in time
4841 +       if (djiffy > 5 * HZ) {
4842 +
4843 +               // jiffies since first time
4844 +               int tjiffy = jiffies - atomic_read (&spd->frstj);
4845 +
4846 +               // max tot speed measured so far
4847 +               int speedmax = atomic_read (&spd->speedmax);
4848 +
4849 +               // last instantaneous speed we measured
4850 +               int lastspeed = atomic_read (&spd->speed);
4851 +
4852 +               // instantaneous read blocks/s
4853 +               int speed = djiffy ? (ddistance * HZ) / djiffy : 0;
4854 +
4855 +               // smoothed KB/s
4856 +               int speedsmoothed =
4857 +                (djiffy * speed + HZ * lastspeed) / (djiffy + HZ);
4858 +
4859 +               // average speed to now in KB/s
4860 +               int speedav = tjiffy ? (distance * HZ) / tjiffy : 0;
4861 +
4862 +               // smoothing count for max
4863 +               int speedhi =
4864 +                (speedav > speedsmoothed) ? speedav : speedsmoothed;
4865 +
4866 +               // doing settings
4867 +               atomic_set (&spd->speed, speedsmoothed);
4868 +               if (speedhi > speedmax)
4869 +                       atomic_set (&spd->speedmax, speedhi);
4870 +               atomic_set (&spd->distance, distance);
4871 +               atomic_set (&spd->speedav, speedav);
4872 +               atomic_set (&spd->jiffy, jiffies);
4873 +       }
4874 +}
4875 +
4876 +void
4877 +nbd_init_speed(struct nbd_speed *spd) {
4878 +        memset(spd, 0, sizeof(*spd));
4879 +        spd->update = spd_update;
4880 +}
4881 +
4882 --- linux-2.5.64/drivers/block/enbd/enbd_proc.c.pre-enbd        Tue Mar 25 15:16:33 2003
4883 +++ linux-2.5.64/drivers/block/enbd/enbd_proc.c Mon Mar 24 22:52:00 2003
4884 @@ -0,0 +1,1059 @@
4885 +
4886 +#include <linux/enbd.h>
4887 +#include <linux/proc_fs.h>
4888 +
4889 +extern struct nbd_device * nbd_get(int i);
4890 +
4891 +static void
4892 +do_reset (int reset, int i) {
4893 +
4894 +       void do_r (void) {
4895 +               struct nbd_device *lo = nbd_get(i);
4896 +               if (reset != 0) {
4897 +                       lo->reset (lo, i);
4898 +                       return;
4899 +               };
4900 +       };
4901 +       if (i >= 0 && i < MAX_NBD) {
4902 +               do_r ();
4903 +               return;
4904 +       }
4905 +}
4906 +
4907 +/*
4908 + * PTB This is just to get a nice limited width integer printout in proc!
4909 + * use endpos (<= 8) spaces at most. We serve from a static buffer size 16.
4910 + */
4911 +char *
4912 +display (unsigned n, int endpos)
4913 +{
4914 +       // PTB  use endpos (<= 8) spaces at most
4915 +       static char buf[16];
4916 +       int units = 0;
4917 +       int decimals = 0;
4918 +       int decpos = endpos;
4919 +       int wholepart = n, fractionpart = 0;
4920 +       buf[endpos--] = 0;
4921 +       // PTB  find the right units to display. U or K or M or G.
4922 +       while (n >= 1 << 10) {
4923 +               decimals = n & ((1 << 10) - 1);
4924 +               n >>= 10;
4925 +               units++;
4926 +       }
4927 +       switch (units) {
4928 +         case 0:
4929 +               break;
4930 +         case 1:
4931 +               buf[endpos--] = 'K';
4932 +               break;
4933 +         case 2:
4934 +               buf[endpos--] = 'M';
4935 +               break;
4936 +         case 3:
4937 +               buf[endpos--] = 'G';
4938 +               break;
4939 +         case 4:
4940 +               buf[endpos--] = 'T';
4941 +               break;
4942 +       }
4943 +       // after this wholepart = n && fractionpart = decimals
4944 +       fractionpart = wholepart & ((1 << (units * 10)) - 1);
4945 +       wholepart >>= units * 10;
4946 +       // PTB  write the whole digits (something between 0 and 1023 inclusive)
4947 +       if (n == 0) {
4948 +               buf[endpos--] = '0';
4949 +       } else {
4950 +               while (endpos >= 0 && n > 0) {
4951 +                       buf[endpos--] = '0' + n % 10;
4952 +                       n /= 10;
4953 +               }
4954 +       }
4955 +       // PTB if there is space and cause, add decimal digits
4956 +       if (endpos >= 1 && units > 0) {
4957 +               int k = 0;
4958 +               char unitchar = buf[--decpos];
4959 +               buf[decpos + k++] = '.';
4960 +               while (endpos >= k) {
4961 +                       int digit = (decimals * 10) >> 10;
4962 +                       buf[decpos + k++] = '0' + digit;
4963 +                       decimals -= (digit << 10) / 10;
4964 +                       decimals *= 10;
4965 +               }
4966 +               buf[decpos + k++] = unitchar;
4967 +               buf[decpos + k] = 0;
4968 +       }
4969 +       // PTB report the start position
4970 +       return buf + endpos + 1;
4971 +}
4972 +
4973 +
4974 +static void
4975 +set_generic (int x, int i, int X)
4976 +{
4977 +       void set_x (void) {
4978 +               struct nbd_device *lo = nbd_get(i);
4979 +                if (lo->magic != NBD_DEV_MAGIC)
4980 +                        return;
4981 +               if (x != 0) {
4982 +                       atomic_set_mask (X, &lo->flags);
4983 +                       return;
4984 +               };
4985 +                atomic_clear_mask (X, &lo->flags);
4986 +       };
4987 +
4988 +       if (i >= 0 && i < MAX_NBD) {
4989 +               set_x ();
4990 +               return;
4991 +       }
4992 +       for (i = 0; i < MAX_NBD; i++) {
4993 +               set_x ();
4994 +       }
4995 +}
4996 +
4997 +static void
4998 +set_sync_intvl (int sync_intvl, int i)
4999 +{
5000 +    set_generic(sync_intvl, i, NBD_SYNC);
5001 +}
5002 +
5003 +
5004 +static void
5005 +set_show_errs (int show_errs, int i)
5006 +{
5007 +    set_generic(show_errs, i, NBD_SHOW_ERRS);
5008 +}
5009 +
5010 +static void
5011 +set_md5sum (int md5sum, int i)
5012 +{
5013 +    set_generic(md5sum, i, NBD_MD5SUM);
5014 +}
5015 +
5016 +
5017 +static void
5018 +set_enable (int enable, int i)
5019 +{
5020 +       void set_e (void) {
5021 +               struct nbd_device *lo = nbd_get(i);
5022 +                if (!lo || lo->magic != NBD_DEV_MAGIC)
5023 +                        return;
5024 +               if (enable != 0) {
5025 +                        if (!(atomic_read (&lo->flags) & NBD_ENABLED)) {
5026 +                               lo->enable (lo);
5027 +                               return;
5028 +                        }
5029 +               };
5030 +                lo->disable (lo);
5031 +       };
5032 +
5033 +       if (i >= 0 && i < MAX_NBD) {
5034 +               set_e ();
5035 +               return;
5036 +       }
5037 +       for (i = 0; i < MAX_NBD; i++) {
5038 +               set_e ();
5039 +       }
5040 +}
5041 +
5042 +static void
5043 +set_direct (int direct, int i)
5044 +{
5045 +        set_generic(direct, i, NBD_DIRECT);
5046 +}
5047 +
5048 +#ifndef NO_BUFFERED_WRITES
5049 +static void
5050 +set_buffer_writes (int buffer_writes, int i)
5051 +{
5052 +        set_generic(buffer_writes, i, NBD_BUFFERWR);
5053 +}
5054 +#endif
5055 +
5056 +static void
5057 +set_merge_requests (int mr, int i)
5058 +{
5059 +       void set_mr (void) {
5060 +               struct nbd_device *lo = nbd_get(i);
5061 +               if (lo->magic != NBD_DEV_MAGIC)
5062 +                        return;
5063 +                atomic_set (&lo->merge_requests, mr);
5064 +       }
5065 +        
5066 +        if (i >= 0 && i < MAX_NBD) {
5067 +               set_mr ();
5068 +               return;
5069 +       }
5070 +       for (i = 0; i < MAX_NBD; i++) {
5071 +               set_mr ();
5072 +       }
5073 +}
5074 +
5075 +int
5076 +nbd_read_proc (char *buf, char **start, off_t offset, int len, int *eof,
5077 +              void *data)
5078 +{
5079 +
5080 +#ifndef MIN
5081 +#define MIN(x,y) ((x)<(y)?(x):(y))
5082 +#endif
5083 +
5084 +       const int limit = MIN (PAGE_SIZE, len) - 80;
5085 +       static int i;
5086 +       struct nbd_device *lo;
5087 +       static int last;
5088 +       static void *next_label;
5089 +       static char *next_label_name;
5090 +       static int total;
5091 +       unsigned long flags;
5092 +
5093 +       if (offset > 0 && !next_label) {
5094 +               *eof = 1;
5095 +               *start = buf;
5096 +               return 0;
5097 +       }
5098 +
5099 +       if (offset <= 0) {
5100 +               // PTB do static inits first time through
5101 +               last = -1;
5102 +               i = 0;
5103 +               next_label = NULL;
5104 +               next_label_name = NULL;
5105 +               total = 0;
5106 +       }
5107 +
5108 +       // PTB  start this bytecount
5109 +       len = 0;
5110 +
5111 +#define NBD_PROC_LABEL(n) \
5112 +        next_label = &&label_##n; \
5113 +        next_label_name = "label_" #n; \
5114 +        if (len > limit) { \
5115 +            *start = (char *) (unsigned long) len; \
5116 +            total += len; \
5117 +            return len;\
5118 +        } \
5119 +        label_##n:
5120 +
5121 +       for ( /* static init */ ; i < MAX_NBD; i++) {
5122 +
5123 +               char *devnam;
5124 +
5125 +               lo = nbd_get(i);
5126 +               devnam = lo->devnam;
5127 +               if (lo->nslot <= 0) {
5128 +                       next_label = NULL;
5129 +                       continue;
5130 +               }
5131 +
5132 +               // PTB computed goto next not-done
5133 +               if (next_label) {
5134 +                       void *label = next_label;
5135 +                       next_label = NULL;
5136 +                       next_label_name = NULL;
5137 +                       len = 0;
5138 +                       goto *label;
5139 +               }
5140 +
5141 +               NBD_PROC_LABEL (1);
5142 +
5143 +               if (last == i - 2) {
5144 +                        struct nbd_device * lo = nbd_get (i - 1);
5145 +                       char *prevdevnam = lo->devnam;
5146 +                       len +=
5147 +                        sprintf (buf + len, "Device %s:\tClosed\n",
5148 +                                 prevdevnam);
5149 +               }
5150 +               if (last < i - 2) {
5151 +                        struct nbd_device * llo = nbd_get (last + 1);
5152 +                        struct nbd_device * plo = nbd_get (i - 1);
5153 +                       char lastdevnam[3];
5154 +                       char prevdevnam[3];
5155 +                       strncpy (lastdevnam, llo->devnam, 3);
5156 +                       strncpy (prevdevnam, plo->devnam, 3);
5157 +                       len +=
5158 +                        sprintf (buf + len, "Device %s-%s:\tClosed\n",
5159 +                                 lastdevnam, prevdevnam);
5160 +               }
5161 +
5162 +               NBD_PROC_LABEL (2);
5163 +
5164 +               len +=
5165 +                sprintf (buf + len, "Device %s:\tOpen " "\n", devnam);
5166 +
5167 +               NBD_PROC_LABEL (3);
5168 +
5169 +               len += sprintf (buf + len,
5170 +                               "[%s] State:\t%s%s%s%s%s%s%s%s%s%s%s%slast error %d, lives %d, bp %d\n",
5171 +                               devnam, atomic_read (&lo->flags)
5172 +                               & NBD_INITIALISED ? "" : "uninitialized, ",
5173 +                               atomic_read (&lo->flags)
5174 +                               & NBD_WRITE_NOCHK ? "noverify, " :
5175 +                               "verify, ", lo->read_only(lo) ? "ro, " : "rw, ",
5176 +                               atomic_read(&lo->merge_requests) ? "merge requests, " : "",
5177 +#ifndef NO_BUFFERED_WRITES
5178 +                               atomic_read (&lo->flags)
5179 +                               & NBD_BUFFERWR ? "buffer writes, " : "",
5180 +#else
5181 +                               "",
5182 +#endif         /* NO_BUFFERED_WRITES */
5183 +                               atomic_read (&lo->flags)
5184 +                               & NBD_ENABLED ? "enabled, " : "disabled, ",
5185 +                               atomic_read (&lo->flags)
5186 +                               & NBD_VALIDATED ? "validated, " : "",
5187 +                                atomic_read (&lo->flags)
5188 +                               & NBD_REMOTE_INVALID ? "remote invalid, " : "",
5189 +                               atomic_read (&lo->flags)
5190 +                               & NBD_SHOW_ERRS ? "show_errs, " : "",
5191 +                               atomic_read (&lo->flags)
5192 +                                & NBD_DIRECT ? "direct, " : "",
5193 +                               atomic_read (&lo->flags)
5194 +                               & NBD_SYNC ? "sync, " : "",
5195 +                               atomic_read (&lo->flags)
5196 +                               & NBD_MD5SUM ? "md5sum, " : "",
5197 +                               lo->harderror,
5198 +                               lo->lives -
5199 +                               ((atomic_read (&lo->flags) & NBD_ENABLED) ?
5200 +                                1 : 0), 0      //atomic_read(&buffermem_pages)
5201 +                );
5202 +
5203 +               NBD_PROC_LABEL (4);
5204 +
5205 +               do {            // PTB begin long do once block
5206 +                       int countq[2] = { 0, 0 };
5207 +                       int cmd;
5208 +
5209 +                       struct list_head *pos;
5210 +
5211 +                       read_lock_irqsave (&lo->queue_lock, flags);
5212 +
5213 +                       list_for_each (pos, &lo->queue) {
5214 +                               struct request *req =
5215 +                                list_entry (pos, struct request, queuelist);
5216 +                               if (countq[READ] + countq[WRITE] > 1000)
5217 +                                       break;
5218 +
5219 +                               cmd = rq_data_dir (req);
5220 +                               countq[cmd]++;
5221 +                       }
5222 +
5223 +                       read_unlock_irqrestore (&lo->queue_lock, flags);
5224 +
5225 +                       len += sprintf (buf + len,
5226 +                                       "[%s] Queued:\t+%dR/%dW curr (check %dR/%dW) +%dR/%dW max\n",
5227 +                                       devnam,
5228 +                                       atomic_read (&lo->countq[READ]),
5229 +                                       atomic_read (&lo->countq[WRITE]),
5230 +                                       countq[READ], countq[WRITE],
5231 +                                       atomic_read (&lo->maxq[READ]),
5232 +                                       atomic_read (&lo->maxq[WRITE]));
5233 +               } while (0);    // PTB end long do once block
5234 +
5235 +               NBD_PROC_LABEL (5);
5236 +
5237 +               len += sprintf (buf + len,
5238 +                               "[%s] Buffersize:\t%d\t(sectors=%d, blocks=%d)\n",
5239 +                               devnam, lo->bufsiz, lo->max_sectors,
5240 +                               lo->max_sectors / (lo->blksize >> 9));
5241 +               len +=
5242 +                sprintf (buf + len, "[%s] Blocksize:\t%d\t(log=%d)\n",
5243 +                         devnam, lo->blksize, lo->logblksize);
5244 +               len +=
5245 +                sprintf (buf + len, "[%s] Size:\t%luKB\n", devnam,
5246 +                         (unsigned long) (lo->bytesize >> 10));
5247 +               len +=
5248 +                sprintf (buf + len, "[%s] Blocks:\t%u\n", devnam,
5249 +                         lo->size >> (lo->logblksize - 10));
5250 +
5251 +               NBD_PROC_LABEL (6);
5252 +
5253 +               len +=
5254 +                sprintf (buf + len, "[%s] Sockets:\t%d", devnam,
5255 +                         lo->nslot);
5256 +
5257 +               NBD_PROC_LABEL (7);
5258 +
5259 +               do {            // PTB begin short do once block
5260 +                       int j;
5261 +                       for (j = 0; j < lo->nslot; j++) {
5262 +                               struct nbd_slot *slotj = &lo->slots[j];
5263 +                               if (j != atomic_read (&lo->islot)) {
5264 +                                       len +=
5265 +                                        sprintf (buf + len, "\t(%s)",
5266 +                                                 slotj->file ? "+" : "-");
5267 +                                } else {
5268 +                                       len +=
5269 +                                        sprintf (buf + len, "\t(%s)",
5270 +                                                 slotj->file ? "*" : ".");
5271 +                                }
5272 +                       }
5273 +               } while (0);    // PTB end short do once block
5274 +
5275 +               len += sprintf (buf + len, "\n");
5276 +
5277 +               NBD_PROC_LABEL (8);
5278 +
5279 +               len += sprintf (buf + len, "[%s] Requested:\t%s", devnam,
5280 +                               display (atomic_read
5281 +                                        (&lo->requests_in[READ]) +
5282 +                                        atomic_read (&lo->requests_in
5283 +                                                     [WRITE]), 7));
5284 +
5285 +               NBD_PROC_LABEL (9);
5286 +
5287 +               do {            // PTB begin short do once block
5288 +                       int j;
5289 +                       char buff[2][8];
5290 +                       for (j = 0; j < lo->nslot; j++) {
5291 +                               struct nbd_slot *slotj = &lo->slots[j];
5292 +                               len +=
5293 +                                sprintf (buf + len, "\t(%s)",
5294 +                                         display (slotj->in, 5));
5295 +                       }
5296 +                       strncpy (buff[0],
5297 +                                display (atomic_read
5298 +                                         (&lo->requests_in[READ]), 6), 7);
5299 +                       strncpy (buff[1],
5300 +                                display (atomic_read
5301 +                                         (&lo->requests_in[WRITE]), 6),
5302 +                                7);
5303 +                       len +=
5304 +                        sprintf (buf + len, "\t%sR/%sW", buff[0],
5305 +                                 buff[1]);
5306 +                       lo->set_speed (lo);
5307 +                       len += sprintf (buf + len, "\tmax %d",
5308 +                                       atomic_read (&lo->maxreqblks));
5309 +               } while (0);    // PTB end short do once block
5310 +
5311 +               len += sprintf (buf + len, "\n");
5312 +               len += sprintf (buf + len, "[%s] Despatched:\t%s", devnam,
5313 +                               display (atomic_read
5314 +                                        (&lo->requests_out[READ]) +
5315 +                                        atomic_read (&lo->requests_out
5316 +                                                     [WRITE]), 7));
5317 +
5318 +               NBD_PROC_LABEL (10);
5319 +
5320 +               do {            // PTB begin short do once block
5321 +                       int j;
5322 +                       char buff[2][8];
5323 +                       for (j = 0; j < lo->nslot; j++) {
5324 +                               struct nbd_slot *slotj = &lo->slots[j];
5325 +                               len +=
5326 +                                sprintf (buf + len, "\t(%s)",
5327 +                                         display (slotj->out, 5));
5328 +                       }
5329 +                       strncpy (buff[0],
5330 +                                display (atomic_read
5331 +                                         (&lo->requests_out[READ]), 6),
5332 +                                7);
5333 +                       strncpy (buff[1],
5334 +                                display (atomic_read
5335 +                                         (&lo->requests_out[WRITE]), 6),
5336 +                                7);
5337 +                       len +=
5338 +                        sprintf (buf + len, "\t%sR/%sW", buff[0],
5339 +                                 buff[1]);
5340 +                       len +=
5341 +                        sprintf (buf + len, "\tmd5 %sW",
5342 +                                 display (atomic_read
5343 +                                          (&lo->wrequests_5to), 5));
5344 +                       len +=
5345 +                        sprintf (buf + len, " (%s eq,",
5346 +                                 display (atomic_read
5347 +                                          (&lo->wrequests_5so), 5));
5348 +                       len +=
5349 +                        sprintf (buf + len, " %s ne,",
5350 +                                 display (atomic_read
5351 +                                          (&lo->wrequests_5wo), 5));
5352 +                       len +=
5353 +                        sprintf (buf + len, " %s dn)",
5354 +                                 display (atomic_read
5355 +                                          (&lo->wrequests_5eo), 5));
5356 +               } while (0);    // PTB end short do once block
5357 +
5358 +               len += sprintf (buf + len, "\n");
5359 +               len += sprintf (buf + len, "[%s] Errored:\t%s", devnam,
5360 +                               display (atomic_read (&lo->requests_err),
5361 +                                        7));
5362 +
5363 +               NBD_PROC_LABEL (11);
5364 +
5365 +               do {            // PTB begin short do once block
5366 +                       int j;
5367 +                       char buff[2][8];
5368 +                       int toterrs = 0;
5369 +
5370 +                       for (j = 0; j < lo->nslot; j++) {
5371 +                               struct nbd_slot *slotj = &lo->slots[j];
5372 +                               len +=
5373 +                                sprintf (buf + len, "\t(%s)",
5374 +                                         display (slotj->err, 5));
5375 +                               toterrs += slotj->err;
5376 +                       }
5377 +                       strncpy (buff[0], display (toterrs, 6), 7);
5378 +                       strncpy (buff[1],
5379 +                                display (atomic_read (&lo->requests_err) -
5380 +                                         toterrs, 6), 7);
5381 +                       len +=
5382 +                        sprintf (buf + len, "\t%s+%s\n", buff[0],
5383 +                                 buff[1]);
5384 +               } while (0);    // PTB end short do once block
5385 +
5386 +               NBD_PROC_LABEL (12);
5387 +
5388 +               do {            // PTB begin long do once block
5389 +                       int pending_rblks = 0;  /* PTB  reads not reached the slots yet */
5390 +                       int pending_wblks = 0;  /* PTB  writes not reached the slots yet */
5391 +                       int blks = 0;
5392 +
5393 +                       read_lock_irqsave (&lo->queue_lock, flags);
5394 +
5395 +                       do {    // PTB begin short do once block
5396 +                               struct list_head *pos;
5397 +
5398 +                               int count = 0;
5399 +                               struct request *req;
5400 +
5401 +                               list_for_each (pos, &lo->queue) {
5402 +                                       req =
5403 +                                        list_entry (pos, struct request,
5404 +                                                    queuelist);
5405 +                                       if (count++ > 1000)
5406 +                                               break;
5407 +                                       blks = req->nr_sectors / lo->blksize;
5408 +                                       if (blks > 0) {
5409 +                                               switch (rq_data_dir (req)) {
5410 +                                                 case READ:
5411 +                                                       pending_rblks +=
5412 +                                                        blks;
5413 +                                                       break;
5414 +                                                 case WRITE:
5415 +                                                       pending_wblks +=
5416 +                                                        blks;
5417 +                                                       break;
5418 +                                               }
5419 +                                       }
5420 +                               }
5421 +                       } while (0);    // PTB end short do once block
5422 +
5423 +                       read_unlock_irqrestore (&lo->queue_lock, flags);
5424 +                       len +=
5425 +                        sprintf (buf + len, "[%s] Pending:\t%d", devnam,
5426 +                                 atomic_read (&lo->requests_req[READ]) +
5427 +                                 atomic_read (&lo->requests_req[WRITE]));
5428 +
5429 +                       do {    // PTB begin short do once block
5430 +                               int j;
5431 +                               for (j = 0; j < lo->nslot; j++) {
5432 +                                       struct nbd_slot *slotj =
5433 +                                        &lo->slots[j];
5434 +                                       len +=
5435 +                                        sprintf (buf + len, "\t(%d)",
5436 +                                                 slotj->req);
5437 +                               }
5438 +                       } while (0);    // PTB end short do once block
5439 +
5440 +                       len += sprintf (buf + len,
5441 +                                       "\t%dR/%dW+%dR/%dW\n",
5442 +                                       atomic_read (&lo->requests_req[READ]),
5443 +                                       atomic_read (&lo->requests_req[WRITE]),
5444 +                                       pending_rblks, pending_wblks);
5445 +
5446 +               } while (0);    // PTB end long do once block
5447 +
5448 +               NBD_PROC_LABEL (13);
5449 +
5450 +               do {            // PTB begin long do once block
5451 +                       char buff[10][8];
5452 +                       int shift = lo->logblksize;
5453 +
5454 +                       strncpy (buff[0],
5455 +                                display (atomic_read (&lo->wspeed.speed)
5456 +                                         << shift, 5), 7);
5457 +                       strncpy (buff[1],
5458 +                                display (atomic_read (&lo->wspeed.speedav)
5459 +                                         << shift, 5), 7);
5460 +                       strncpy (buff[2],
5461 +                                display (atomic_read
5462 +                                         (&lo->wspeed.speedmax) << shift,
5463 +                                         5), 7);
5464 +
5465 +                       strncpy (buff[3],
5466 +                                display (atomic_read (&lo->rspeed.speed)
5467 +                                         << shift, 5), 7);
5468 +                       strncpy (buff[4],
5469 +                                display (atomic_read (&lo->rspeed.speedav)
5470 +                                         << shift, 5), 7);
5471 +                       strncpy (buff[5],
5472 +                                display (atomic_read
5473 +                                         (&lo->rspeed.speedmax) << shift,
5474 +                                         5), 7);
5475 +
5476 +                       strncpy (buff[6],
5477 +                                display (atomic_read (&lo->tspeed.speed)
5478 +                                         << shift, 5), 7);
5479 +                       strncpy (buff[7],
5480 +                                display (atomic_read (&lo->tspeed.speedav)
5481 +                                         << shift, 5), 7);
5482 +                       strncpy (buff[8],
5483 +                                display (atomic_read
5484 +                                         (&lo->tspeed.speedmax) << shift,
5485 +                                         5), 7);
5486 +
5487 +                       len +=
5488 +                        sprintf (buf + len, "[%s] B/s now:", devnam);
5489 +                       len +=
5490 +                        sprintf (buf + len, "\t%s\t(%sR+%sW)\n", buff[6],
5491 +                                 buff[3], buff[0]);
5492 +                       len +=
5493 +                        sprintf (buf + len, "[%s] B/s ave:", devnam);
5494 +                       len +=
5495 +                        sprintf (buf + len, "\t%s\t(%sR+%sW)\n", buff[7],
5496 +                                 buff[4], buff[1]);
5497 +                       len +=
5498 +                        sprintf (buf + len, "[%s] B/s max:", devnam);
5499 +                       len +=
5500 +                        sprintf (buf + len, "\t%s\t(%sR+%sW)\n", buff[8],
5501 +                                 buff[5], buff[2]);
5502 +               } while (0);    // PTB end long do once block
5503 +
5504 +               do {            // PTB begin short do once block
5505 +                       int blks;
5506 +                       int tot_reqs = 0;
5507 +
5508 +                       len +=
5509 +                        sprintf (buf + len, "[%s] Spectrum:", devnam);
5510 +                       for (blks = 0;
5511 +                            blks <= atomic_read (&lo->maxreqblks); blks++) {
5512 +                               tot_reqs +=
5513 +                                atomic_read (&lo->req_in[READ][blks]) +
5514 +                                atomic_read (&lo->req_in[WRITE][blks]);
5515 +                       }
5516 +
5517 +                       for (blks = 0;
5518 +                            blks <= atomic_read (&lo->maxreqblks); blks++) {
5519 +                               int req_blks =
5520 +                                atomic_read (&lo->req_in[READ][blks])
5521 +                                + atomic_read (&lo->req_in[WRITE][blks]);
5522 +                               int percent =
5523 +                                tot_reqs >
5524 +                                0 ? (100 * req_blks) / tot_reqs : 0;
5525 +                               if (percent <= 0)
5526 +                                       continue;
5527 +                               len +=
5528 +                                sprintf (buf + len, "\t%u%%%d", percent,
5529 +                                         blks);
5530 +                       }
5531 +                       len += sprintf (buf + len, "\n");
5532 +               } while (0);    // PTB end short do once block
5533 +
5534 +               NBD_PROC_LABEL (14);
5535 +
5536 +               len += sprintf (buf + len, "[%s] Kthreads:\t%d", devnam,
5537 +                               atomic_read (&lo->kthreads));
5538 +               len +=
5539 +                sprintf (buf + len, "\t(%d waiting/%d running/%d max)\n",
5540 +                         atomic_read (&lo->kwaiters),
5541 +                         atomic_read (&lo->kthreads) -
5542 +                         atomic_read (&lo->kwaiters),
5543 +                         atomic_read (&lo->kmax));
5544 +
5545 +               NBD_PROC_LABEL (15);
5546 +
5547 +               len += sprintf (buf + len, "[%s] Cthreads:\t%d", devnam,
5548 +                               atomic_read (&lo->cthreads));
5549 +
5550 +               NBD_PROC_LABEL (16);
5551 +
5552 +               do {
5553 +                       int j;
5554 +                       for (j = 0; j < lo->nslot; j++) {
5555 +                               struct nbd_slot *slotj = &lo->slots[j];
5556 +                               int state =
5557 +                                ((slotj->flags & NBD_SLOT_RUNNING) ? 1 :
5558 +                                 0) +
5559 +                                ((slotj->flags & NBD_SLOT_WAITING) ? 2 :
5560 +                                 0);
5561 +                               char *desc = "?";
5562 +                               switch (state) {
5563 +                                 case 0:
5564 +                                       desc = "-";
5565 +                                       break;  /* PTB not in */
5566 +                                 case 1:
5567 +                                       desc = "*";
5568 +                                       break;  /* PTB in and not waiting */
5569 +                                 case 2:
5570 +                                       desc = "?";
5571 +                                       break;  /* PTB impossible */
5572 +                                 case 3:
5573 +                                       desc = "+";
5574 +                                       break;  /* PTB in and waiting */
5575 +                               }
5576 +                               len += sprintf (buf + len, "\t(%s)", desc);
5577 +                       }
5578 +               } while (0);
5579 +
5580 +               len += sprintf (buf + len, "\n");
5581 +
5582 +               NBD_PROC_LABEL (17);
5583 +
5584 +               last = i;
5585 +               len += sprintf (buf + len, "[%s] Cpids:\t%d", devnam,
5586 +                               atomic_read (&lo->cthreads));
5587 +
5588 +               do {
5589 +                       int j;
5590 +                       for (j = 0; j < lo->nslot; j++) {
5591 +                               struct nbd_slot *slotj = &lo->slots[j];
5592 +                               len +=
5593 +                                sprintf (buf + len, "\t(%u)", slotj->pid);
5594 +                       }
5595 +                       len += sprintf (buf + len, "\n");
5596 +               } while (0);
5597 +
5598 +               do {
5599 +                       int j, k;
5600 +                       for (j = 0; j < lo->nslot; j++) {
5601 +                               struct nbd_slot *slotj = &lo->slots[j];
5602 +                               if (slotj->spid != 0)
5603 +                                       break;
5604 +                       }
5605 +                       if (j < lo->nslot) {
5606 +                               len +=
5607 +                                sprintf (buf + len, "[%s] Kpids:\t%d",
5608 +                                         devnam,
5609 +                                         atomic_read (&lo->cthreads));
5610 +                               for (k = 0; k < lo->nslot; k++) {
5611 +                                       struct nbd_slot *slotk =
5612 +                                        &lo->slots[k];
5613 +                                       len +=
5614 +                                        sprintf (buf + len, "\t(%u)",
5615 +                                                 slotk->spid);
5616 +                               }
5617 +                               len += sprintf (buf + len, "\n");
5618 +                       }
5619 +               } while (0);
5620 +
5621 +               NBD_PROC_LABEL (18);
5622 +
5623 +               NBD_PROC_LABEL (19);
5624 +
5625 +               // PTB have to tell loop head that we are not reentering 
5626 +               next_label = NULL;
5627 +               next_label_name = NULL;
5628 +       }
5629 +
5630 +       NBD_PROC_LABEL (20);
5631 +
5632 +       if (last == i - 2) {
5633 +                struct nbd_device * lo = nbd_get (i - 1);
5634 +               char *prevnam = lo->devnam;
5635 +               len +=
5636 +                sprintf (buf + len, "Device %s:\tClosed\n", prevnam);
5637 +       }
5638 +
5639 +       if (last < i - 2) {
5640 +               char lastnam[3];
5641 +               char prevnam[3];
5642 +                struct nbd_device * llo = nbd_get (last + 1);
5643 +                struct nbd_device * plo = nbd_get (i - 1);
5644 +               strncpy (lastnam, llo->devnam, 3);
5645 +               strncpy (prevnam, plo->devnam, 3);
5646 +               len += sprintf (buf + len, "Device %s-%s:\tClosed\n",
5647 +                               lastnam, prevnam);
5648 +       }
5649 +
5650 +       NBD_PROC_LABEL (21);
5651 +
5652 +       // PTB re-init vital statistics for next time 
5653 +       next_label = NULL;
5654 +       next_label_name = NULL;
5655 +
5656 +       *eof = 1;
5657 +       *start = buf;
5658 +       total += len;
5659 +
5660 +       return len;
5661 +}
5662 +
5663 +/*
5664 + * PTB read an int from a string. Return number of ints read (0 or 1).
5665 + */
5666 +static int
5667 +sscani (char *buf, int len, int *n)
5668 +{
5669 +
5670 +       int i, a = 0;
5671 +       short has_digits = 0;
5672 +       short is_signed = 0;
5673 +
5674 +       // PTB look for first significant character
5675 +       for (i = 0; i < len; i++) {
5676 +               char c = buf[i];
5677 +               if (c == ' ' || c == '\t') {
5678 +                       if (is_signed)
5679 +                               return 0;
5680 +               } else if (c == '-') {
5681 +                       if (is_signed)
5682 +                               return 0;
5683 +                       is_signed = -1;
5684 +               } else if (c == '+') {
5685 +                       if (is_signed)
5686 +                               return 0;
5687 +                       is_signed = 1;
5688 +               } else if (c >= '0' && c <= '9') {
5689 +                       is_signed = 1;
5690 +                       has_digits = 1;
5691 +                       break;
5692 +               } else {
5693 +                       return 0;
5694 +               }
5695 +       }
5696 +       // PTB i now points at first digit if there is one
5697 +       if (!has_digits)
5698 +               return 0;
5699 +       for (; i < len; i++) {
5700 +               char c = buf[i];
5701 +               if (c < '0' || c > '9')
5702 +                       break;
5703 +               a *= 10;
5704 +               a += c - '0';
5705 +       }
5706 +       if (is_signed >= 0) {
5707 +               *n = a;
5708 +        } else {
5709 +               *n = -a;
5710 +        }
5711 +       return 1;
5712 +}
5713 +
5714 +/*
5715 + * look for a 1 or 2 letter device code ("a" or "aa") and save the
5716 + * device number to which it refers. Return number of device letter
5717 + * codes found (0 or 1).
5718 + */
5719 +static int
5720 +sscana (char *buf, int len, int *n)
5721 +{
5722 +
5723 +       int i, a = 0;
5724 +       short has_letters = 0;
5725 +
5726 +       for (i = 0; i < len; i++) {
5727 +               char c = buf[i];
5728 +               if (c >= 'a' && c <= 'z') {
5729 +                       has_letters = 1;
5730 +                       break;
5731 +               } else if (c == ' ') {
5732 +                       if (has_letters)
5733 +                               return 0;
5734 +               } else {
5735 +                       return 0;
5736 +               }
5737 +       }
5738 +       if (!has_letters)
5739 +               return 0;
5740 +       for (; i < len; i++) {
5741 +               char c = buf[i];
5742 +               if (c < 'a' || c > 'z')
5743 +                       break;
5744 +               a *= 26;
5745 +               a += c - 'a';
5746 +       }
5747 +       *n = a;
5748 +       return 1;
5749 +}
5750 +
5751 +/*
5752 + * read an integer (or 2-letter ascii) arg into an int. Return numner
5753 + * of integers read (0 or 1) and -1 for no keymatch. The first arg is a
5754 + * preceding key.
5755 + * @i is the integer value that results
5756 + * @j is an index if one one supplied (foo[j] = i ), else -1
5757 + */
5758 +static int
5759 +getarg (const char *buffer, int buflen, const char *key, int *i, int *j)
5760 +{
5761 +
5762 +       int keylen;
5763 +
5764 +       void skip_ws (void) {
5765 +               while (buflen > 0) {
5766 +                       if (*buffer != ' ' && *buffer != '\t')
5767 +                               break;
5768 +                       buffer++;
5769 +                       buflen--;
5770 +               }
5771 +        };
5772 +
5773 +        skip_ws ();
5774 +
5775 +       keylen = strlen (key);
5776 +       if (strncmp (buffer, key, keylen))
5777 +               return -1;
5778 +
5779 +       buffer += keylen;
5780 +       buflen -= keylen;
5781 +
5782 +       skip_ws ();
5783 +
5784 +       *j = -1;
5785 +       if (*buffer == '[') {
5786 +               char *closing;
5787 +               int indexlen;
5788 +
5789 +               buffer++;
5790 +               buflen--;
5791 +
5792 +               skip_ws ();
5793 +
5794 +               closing = strchr (buffer, ']');
5795 +               if (!closing)
5796 +                       return -1;
5797 +               indexlen = closing - buffer;
5798 +               *closing = 0;
5799 +
5800 +               if (sscani ((char *) buffer, indexlen, j) < 1)
5801 +                       return 0;
5802 +               if (sscana ((char *) buffer, buflen, j) < 1)
5803 +                       return 0;
5804 +
5805 +               buffer = closing;
5806 +               buflen -= indexlen;
5807 +
5808 +               buffer++;
5809 +               buflen--;
5810 +
5811 +               skip_ws ();
5812 +       }
5813 +
5814 +       if (*buffer != '=')
5815 +               return -1;
5816 +
5817 +       buffer++;
5818 +       buflen--;
5819 +
5820 +       skip_ws ();
5821 +
5822 +       if (sscani ((char *) buffer, buflen, i) < 1)
5823 +               return 0;
5824 +       if (sscana ((char *) buffer, buflen, i) < 1)
5825 +               return 0;
5826 +       return 1;
5827 +}
5828 +
5829 +/*  
5830 + * PTB - write a 0 with echo -n 0 to /proc/nbdinfo to do a hard reset.
5831 + */
5832 +static int
5833 +nbd_write_proc (struct file *file, const char *buffer, unsigned long count,
5834 +               void *data)
5835 +{
5836 +
5837 +       switch (count) {
5838 +
5839 +               int i;
5840 +
5841 +         case 2:
5842 +               if (buffer[1] != '\n')
5843 +                       break;
5844 +               /* else fallthru to case 1 */
5845 +         case 1:
5846 +               switch (*buffer) {
5847 +                 case '1':
5848 +                       for (i = 0; i < MAX_NBD; i++) {
5849 +                               struct nbd_device *lo = nbd_get(i);
5850 +                               lo->hard_reset (lo);
5851 +                       }
5852 +                       break;
5853 +                 case '0':
5854 +                       for (i = 0; i < MAX_NBD; i++) {
5855 +                               //  PTB this takes the io spinlock and our spinlock.
5856 +                               struct nbd_device *lo = nbd_get(i);
5857 +                               lo->soft_reset (lo);
5858 +                                lo->reenable_delay(lo, 5);
5859 +                       }
5860 +                       break;
5861 +               }
5862 +               break;
5863 +         default:
5864 +               do {
5865 +                       int index;
5866 +                        int merge_requests;
5867 +                        int sync_intvl;
5868 +                        int show_errs;
5869 +                        int md5sum;
5870 +#ifndef NO_BUFFERED_WRITES
5871 +                        int buffer_writes;
5872 +#endif
5873 +                        int enable;
5874 +                        int direct;
5875 +                        int reset;
5876 +
5877 +                       if (getarg (buffer, count, "merge_requests",
5878 +                                   &merge_requests, &index) >= 0) {
5879 +                               // merge_requests
5880 +                               set_merge_requests (merge_requests, index);
5881 +                               break;
5882 +                       }
5883 +                       if (getarg (buffer, count, "sync_intvl",
5884 +                                   &sync_intvl, &index) >= 0
5885 +                           || getarg (buffer, count, "sync",
5886 +                                      &sync_intvl, &index) >= 0) {
5887 +                               // sync_intvl
5888 +                               set_sync_intvl (sync_intvl, index);
5889 +                               break;
5890 +                       }
5891 +                       if (getarg (buffer, count, "show_errs",
5892 +                                   &show_errs, &index) >= 0) {
5893 +                               // show_errs
5894 +                               set_show_errs (show_errs, index);
5895 +                               break;
5896 +                       }
5897 +                       if (getarg (buffer, count, "md5sum",
5898 +                                   &md5sum, &index) >= 0) {
5899 +                               // md5sum
5900 +                               set_md5sum (md5sum, index);
5901 +                               break;
5902 +                       }
5903 +#ifndef NO_BUFFERED_WRITES
5904 +                       if (getarg (buffer, count, "buffer_writes",
5905 +                                   &buffer_writes, &index) >= 0) {
5906 +                               // buffer_writes
5907 +                               set_buffer_writes (buffer_writes, index);
5908 +                               break;
5909 +                       }
5910 +#endif         /* NO_BUFFERED_WRITES */
5911 +                       if (getarg (buffer, count, "enable",
5912 +                                   &enable, &index) >= 0) {
5913 +                               // enable
5914 +                               set_enable (enable, index);
5915 +                               break;
5916 +                       }
5917 +                       if (getarg (buffer, count, "direct",
5918 +                                   &direct, &index) >= 0) {
5919 +                               // enable
5920 +                                set_direct(direct, index);
5921 +                               break;
5922 +                        }
5923 +                       if (getarg (buffer, count, "reset",
5924 +                                   &reset, &index) >= 0) {
5925 +                               // reset
5926 +                               do_reset(reset, index);
5927 +                               break;
5928 +                       }
5929 +                       NBD_ERROR ("illegal %ld character command\n",
5930 +                                  count);
5931 +                       return -EINVAL;
5932 +               } while (0);
5933 +               break;
5934 +       }
5935 +       return count;
5936 +}
5937 +
5938 +void
5939 +nbd_init_proc(struct proc_dir_entry *res) {
5940 +        res->read_proc = nbd_read_proc;
5941 +        res->write_proc = nbd_write_proc;
5942 +}
5943 +
5944 --- linux-2.5.64/drivers/Makefile.pre-enbd      Wed Mar  5 04:29:33 2003
5945 +++ linux-2.5.64/drivers/Makefile       Mon Mar 24 17:44:04 2003
5946 @@ -30,6 +30,7 @@
5947  obj-$(CONFIG_SBUS)             += sbus/
5948  obj-$(CONFIG_ZORRO)            += zorro/
5949  obj-$(CONFIG_MAC)              += macintosh/
5950 +obj-$(CONFIG_ENBD)             += block/enbd/
5951  obj-$(CONFIG_PARIDE)           += block/paride/
5952  obj-$(CONFIG_TC)               += tc/
5953  obj-$(CONFIG_USB)              += usb/
5954 --- linux-2.5.64/include/linux/enbd.h.pre-enbd  Tue Mar 25 15:20:38 2003
5955 +++ linux-2.5.64/include/linux/enbd.h   Tue Mar 25 14:17:37 2003
5956 @@ -0,0 +1,517 @@
5957 +#ifndef LINUX_ENBD_H
5958 +#define LINUX_ENBD_H
5959 +
5960 +/* unsigned comments are Pavel's originals for 2.1.*
5961 + *   pavel@atrey.karlin.mff.cuni.cz (Pavel Machek)
5962 + * comments marked PTB are from
5963 + *   ptb@it.uc3m.es (Peter T. Breuer)
5964 + * comments marked AMARIN are from
5965 + *   amarin@it.uc3m.es (Andres Marin Lopez)
5966 + */
5967 +
5968 +#include <asm/types.h>
5969 +
5970 +#ifndef NBD_VERSION
5971 +#define NBD_VERSION "2.4.30 $Date$"
5972 +#endif /*NBD_VERSION*/
5973 +
5974 +  /*
5975 +   * Third type of request apart from READ or WRITE
5976 +   */
5977 +  #ifndef IOCTL
5978 +  # define IOCTL 2
5979 +  #endif
5980 +  /*
5981 +   * and fourth ..
5982 +   */
5983 +  #ifndef MD5SUM
5984 +  # define MD5SUM 3
5985 +  #endif
5986 +  /*
5987 +   * and fifth ..
5988 +   */
5989 +  #ifndef SPECIAL
5990 +  # define SPECIAL 4
5991 +  #endif
5992 +
5993 +  /*
5994 +   * We need extra bits of req->flags
5995 +   * */
5996 +  # define __REQ_NBD       __REQ_NR_BITS
5997 +  # define REQ_NBD         (1 << __REQ_NBD)
5998 +  # define __REQ_NBDSEQNO  (__REQ_NR_BITS + 1)
5999 +  # define REQ_NBDSEQNO    (1 << __REQ_NBDSEQNO)
6000 +  // PTB ... and all the other bits are seqno too!
6001 +
6002 +/* PTB - new style ioctl assignments */
6003 +  #define NBD_SET_SOCK         _IOW(0xab, 0x00, int)
6004 +  #define NBD_TEST_IOCTL1      _IOW(0xab, 0x01, int)
6005 +  #define NBD_SET_SIZE         _IOW(0xab, 0x02, int)
6006 +  #define NBD_DO_IT            _IOW(0xab, 0x03, int)
6007 +  #define NBD_CLEAR_SOCK       _IOW(0xab, 0x04, int)
6008 +  #define NBD_CLEAR_QUE        _IO (0xab, 0x05)
6009 +  #define NBD_PRINT_DEBUG      _IO (0xab, 0x06)
6010 +  #define NBD_TEST_IOCTL2      _IOR(0xab, 0x07, int)
6011 +  #define NBD_HARD_RESET       _IO (0xab, 0x09)
6012 +  #define NBD_DEC_USE_COUNT    _IO (0xab, 0x09)
6013 +  #define MY_NBD_ACK           _IOW(0xab, 0x0a, char *)
6014 +  #define MY_NBD_GET_REQ       _IOW(0xab, 0x0b, char *)
6015 +  #define MY_NBD_REG_BUF       _IOW(0xab, 0x0c, char *)
6016 +  #define MY_NBD_CLR_REQ       _IOW(0xab, 0x0d, int)
6017 +  #define MY_NBD_SYNC          _IOW(0xab, 0x0e, int)
6018 +  #define NBD_SET_SECTORS      _IOW(0xab, 0x0f, int)
6019 +  #define MY_NBD_SET_SIG       _IOW(0xab, 0x10, int *)
6020 +  #define NBD_RESET            _IO (0xab, 0x11)
6021 +  #define NBD_TEST_IOCTL3      _IOWR(0xab, 0x12, int)
6022 +  #define MY_NBD_ERR_REQ       _IOW(0xab, 0x13, int)
6023 +  #define MY_NBD_SET_INTVL     _IOW(0xab, 0x14, int)
6024 +  #define MY_NBD_SET_SHOW_ERRS _IOW(0xab, 0x15, int) 
6025 +  #define NBD_SET_MD5SUM       _IOW(0xab, 0x16, int) 
6026 +  #define MY_NBD_SET_BUFFERWR  _IOW(0xab, 0x17, int) 
6027 +  #define MY_NBD_INVALIDATE    _IOW(0xab, 0x18, int)
6028 +  #define MY_NBD_SET_SPID      _IOW(0xab, 0x19, int) 
6029 +  #define MY_NBD_SET_RQ_HANDLE _IOW(0xab, 0x1a, void*) 
6030 +  #define MY_NBD_SET_RQ_SEQNO  _IOW(0xab, 0x1b, int) 
6031 +  #define MY_NBD_SET_RQ_DIGEST _IOWR(0xab, 0x1d, nbd_digest_t) 
6032 +  #define NBD_TEST_IOCTL4      _IOR(0xab, 0x1e, char[256])
6033 +  #define NBD_TEST_IOCTL5      _IOWR(0xab, 0x1f, char[256])
6034 +  #define NBD_TEST_IOCTL6      _IO(0xab, 0x20) // special r 256B
6035 +  #define NBD_TEST_IOCTL7      _IO(0xab, 0x21) // special rw 256B
6036 +  #define NBD_SET_BLKSIZE      _IOW(0xab, 0x22, int)
6037 +  #define NBD_GET_BLKSIZE      _IOR(0xab, 0x23, long)
6038 +  #define NBD_SET_PF_MEMALLOC  _IOW(0xab, 0x24, int)
6039 +  #define MY_NBD_SET_DIRECT    _IOW(0xab, 0x25, int) 
6040 +  #define MY_NBD_GET_NPORT     _IOR(0xab, 0x26, int)
6041 +
6042 +#define MAX_NBD 16          /* PTB MAX was 128, but that's a lot */
6043 +#define NBD_SHIFT 4         /* PTB 16 partitions/sockets/slots per device */
6044 +                            /* PTB number of socket slots per device */
6045 +#define NBD_MAXCONN (1<<NBD_SHIFT)
6046 +#define NBD_SIGLEN 128      /* PTB length of sig on device */
6047 +#define NBD_MAX_SECTORS 512 /* PTB max number of 512B sectors in a buffer */
6048 +
6049 +
6050 +#if defined(MAJOR_NR) || defined(__KERNEL__)
6051 +  /* PTB we are included from the kernel nbd.c file so put kernel stuff here */
6052 +
6053 +  #include <linux/config.h>
6054 +
6055 +  #define ENDREQ_NOCURRENT
6056 +  #define LOCAL_END_REQUEST
6057 +  #include <linux/blk.h>
6058 +
6059 +
6060 +  /* PTB various defaults */
6061 +  #define NBD_RAHEAD_DFLT    24 /* PTB slow medium                  */
6062 +  #define NBD_SYNC_INTVL      0 /* PTB sync every nK reqs (default disable) */
6063 +  #define NBD_REQ_TIMEO       5 /* PTB client inactivity chk intvl (rollback) */
6064 +  #define NBD_SPEED_LIM  100000 /* PTB limit to 100M write reqs/s */
6065 +  #define NBD_MERGE_REQ_DFLT  0 /* PTB until accounting fixed! */
6066 +   /* PTB Jens Axboe says that plug should always be set in 2.4.* */
6067 +  #define NBD_PLUG_DFLT       1 
6068 +  #define NBD_MD5SUM_DFLT     0 
6069 +
6070 +/*
6071 + * PTB User messaging defs.
6072 + */
6073 +
6074 +  #define NBD_ID "NBD #%d[%d]: %s "
6075 +
6076 +  #define NBD_DEBUG(level, s...) \
6077 +  { static int icnt; printk( KERN_DEBUG NBD_ID, __LINE__, icnt++, __FUNCTION__); printk(s);}
6078 +  #define NBD_ERROR( s...) \
6079 +  { static int icnt; printk( KERN_ERR   NBD_ID, __LINE__, icnt++, __FUNCTION__); printk(s);}
6080 +  #define NBD_ALERT( s...) \
6081 +  { static int icnt; printk( KERN_ALERT NBD_ID, __LINE__, icnt++, __FUNCTION__); printk(s);}
6082 +  #define NBD_INFO( s...)  \
6083 +  { static int icnt; printk( KERN_INFO  NBD_ID, __LINE__, icnt++, __FUNCTION__); printk(s);}
6084 +
6085 +
6086 +
6087 +    struct nbd_slot {
6088 +      struct file * file;      /* PTB add - for refcnt, NULL if slot empty */
6089 +      struct socket * sock;    /* PTB add                          */
6090 +      int in;                  /* PTB add - tot blocks entered     */
6091 +      int out;                 /* PTB add - tot blocks released    */
6092 +      int err;                 /* PTB add - tot blocks errored     */
6093 +      int req;                 /* PTB add - tot blocks pending     */
6094 +      char * buffer;           /* PTB add - user space buffer      */
6095 +      int  bufsiz;             /* PTB add - user space buffer size */
6096 +      struct list_head queue;
6097 +      unsigned long req_age;   /* PTB add - age of pending req     */
6098 +      unsigned long cli_age;   /* PTB add - age of client          */
6099 +      struct nbd_device *lo;   /* PTB add - parent device          */
6100 +    #define NBD_SLOT_RUNNING   0x0001
6101 +    #define NBD_SLOT_WAITING   0x0002
6102 +    #define NBD_SLOT_BUFFERED  0x0004
6103 +    #define NBD_SLOT_MD5SUM    0x8000 /* slot reply has a digest in it ..*/
6104 +    #define NBD_SLOT_MD5_OK   0x10000 /* .. and equaled req's */
6105 +      int flags;               /* PTB add */
6106 +      int i;                   /* PTB add - slot number */
6107 +      int buflen;              /* PTB add - buffer byte count */
6108 +      int pid;                 /* PTB add - client process */
6109 +      int refcnt;              /* PTB add - so can set_sock/clr_sock ourself */
6110 +      int nerrs;               /* PTB add - local error count */
6111 +      int spid;                /* PTB add - server pid */
6112 +    };
6113 +
6114 +  struct nbd_md;
6115 +  struct nbd_md {
6116 +    int count;
6117 +    struct semaphore access_sem;
6118 +    int (*notify_fn)(kdev_t, int);
6119 +    int (*notify)(struct nbd_md *,kdev_t);
6120 +    int (*unnotify)(struct nbd_md *,kdev_t);
6121 +    void (*dec)(struct nbd_md *);
6122 +    void (*inc)(struct nbd_md *);
6123 +    void (*reg)(struct nbd_md *, int(*)(kdev_t, int));
6124 +  };
6125 +
6126 +  struct nbd_speed {
6127 +    atomic_t speed;                      /* PTB add - current speed in KB/s */
6128 +    atomic_t speedmax;                   /* PTB add - max speed */
6129 +    atomic_t speedav;                    /* PTB add - average speed */
6130 +    atomic_t distance;                   /* PTB add - last distance measure */
6131 +    atomic_t jiffy;                      /* PTB add - last jiffies speed set */
6132 +    atomic_t frstj;                      /* PTB add - first jiffies */
6133 +    void (*update)(struct nbd_speed*, int);
6134 +  };
6135 +
6136 +  struct nbd_md_list {
6137 +    struct list_head list;
6138 +    kdev_t dev;
6139 +  };
6140 +
6141 +  struct nbd_seqno;  // forward decl
6142 +  struct nbd_seqno {
6143 +      unsigned int seqno;                  /* PTB add - sequence number */
6144 +      atomic_t seqno_gen;                  /* PTB add - seqno genration */
6145 +      void (*inc)(struct nbd_seqno *);
6146 +      int  (*get)(struct nbd_seqno *);
6147 +      void (*reset)(struct nbd_seqno *);
6148 +      unsigned (*calc)(struct nbd_seqno *, unsigned);
6149 +  };
6150 +
6151 +  struct nbd_device {
6152 +      atomic_t refcnt; 
6153 +
6154 +    #define NBD_READ_ONLY   0x0001
6155 +    #define NBD_WRITE_NOCHK 0x0002
6156 +    #define NBD_INITIALISED 0x0004
6157 +    #define NBD_SIGNED      0x0008
6158 +
6159 +    #define NBD_ENABLED     0x0010
6160 +    #define NBD_SIZED       0x0020
6161 +    #define NBD_BLKSIZED    0x0040
6162 +
6163 +    #define NBD_QBLOCKED    0x0100
6164 +    #define NBD_SHOW_ERRS   0x0200
6165 +    #define NBD_SYNC        0x0400
6166 +    #define NBD_VALIDATED   0x0800         /* read partition table */
6167 +
6168 +    #define NBD_BUFFERWR    0x1000         /* buffer writes to device */
6169 +    #define NBD_REMOTE_INVALID \
6170 +                            0x2000         /* remote resource vanished */
6171 +    #define NBD_DIRECT      0x4000         /* convert opens to O_DIRECT */
6172 +    #define NBD_MD5SUM      0x8000
6173 +
6174 +
6175 +      atomic_t flags;
6176 +      int harderror;                      /* Code of hard error            */
6177 +      int magic;                          /* FIXME: not if debugging is off  */
6178 +      struct list_head queue;
6179 +      rwlock_t queue_lock;                 /* PTB add - spinlock */
6180 +      int nslot;                           /* PTB add - total slots */
6181 +      atomic_t islot;                      /* PTB add - current slot */
6182 +      int aslot;                           /* PTB add - total active slots*/
6183 +      atomic_t requests_in[2];             /* PTB add - blocks put on queue */
6184 +      atomic_t requests_out[2];            /* PTB add - blocks out from queue */
6185 +      atomic_t requests_err;               /* PTB add - blocks erred on queue */
6186 +      atomic_t wrequests_5so;              /* PTB add - write blocks md5 skip */
6187 +      atomic_t wrequests_5wo;              /* PTB add - write blocks md5 wr */
6188 +      atomic_t wrequests_5eo;              /* PTB add - write blocks md5 refus*/
6189 +      atomic_t wrequests_5to;              /* PTB add - write blocks md5sum */
6190 +      atomic_t wrequests_5co;              /* PTB add - write blocks md5 tot */
6191 +      atomic_t wrequests_5no;              /* PTB add - write blocks not md5 */
6192 +      atomic_t requests_req[2];            /* PTB add - read blocks pending */
6193 +      atomic_t kwaiters;                   /* PTB add - kernel thrds waiting */
6194 +      atomic_t kthreads;                   /* PTB add - kernel threads in */
6195 +      atomic_t maxq[2];                    /* PTB add - max req queue depth */
6196 +      atomic_t countq[2];                  /* PTB add - request queue depth */
6197 +      atomic_t errors;                     /* PTB add - tot requests errored */
6198 +      struct nbd_seqno seqno_out;          /* PTB add - seq number */
6199 +      atomic_t cwaiters;                   /* PTB add - client thrds waiting */
6200 +      atomic_t cthreads;                   /* PTB add - client threads in */
6201 +      atomic_t req_in[2][1 + NBD_MAX_SECTORS/2];
6202 +      wait_queue_head_t wq;                /* PTB add */
6203 +      struct nbd_slot slots[NBD_MAXCONN];  /* PTB add - client array */
6204 +      unsigned blksize;                    /* PTB add - device blksize in B */
6205 +      u64 bytesize;                        /* PTB add - device size in B */
6206 +      u64 sectors;                         /* PTB add - device size (sectors) */
6207 +      unsigned size;                       /* PTB add - device size in blks */
6208 +      unsigned logblksize;                 /* PTB add - log2 blksize */
6209 +      unsigned nbd;                        /* PTB add - this array index */
6210 +      int signature[NBD_SIGLEN/sizeof(int)];
6211 +                                           /* PTB add - server sig */
6212 +      struct file * file;                  /* PTB add - for ref */
6213 +      struct inode * inode;                /* PTB add - for ref */
6214 +      int  bufsiz;                         /* PTB add - userspace buffer size */
6215 +      atomic_t kmax;                       /* PTB add - max kernel threads */
6216 +      char *blockmap;                      /* PTB add - map of block states */
6217 +      unsigned long disabled;              /* PTB add - when was it disabled */
6218 +      int req_timeo;                       /* PTB add - inactivity timeout */
6219 +      struct timer_list run_queue;         /* PTB add - run queue */
6220 +      struct work_struct task_queue;       /* PTB add - task queue */
6221 +      char devnam[4];                      /* PTB add - drive letters */
6222 +      atomic_t maxreqblks;                 /* PTB add - maximum req size seen */
6223 +      int max_sectors;                     /* PTB add - max req size allowed! */
6224 +      int lives;                           /* PTB add - # times enabled */
6225 +      // PTB speed measurement settings
6226 +      struct nbd_speed tspeed;
6227 +      struct nbd_speed wspeed;
6228 +      struct nbd_speed rspeed;
6229 +      int dummy;                           /* PTB add - unused */
6230 +      struct request *req;                 /* PTB fake request for ioctls */
6231 +      wait_queue_head_t req_wq;            /* PTB req done notifications */
6232 +      struct request *rq;                  /* PTB special request ptr */
6233 +      struct list_head altqueue;           /* PTB diverted requests */
6234 +      rwlock_t altqueue_lock;              /* PTB add - diverted reqs lock */
6235 +      atomic_t seqno_in;                   /* PTB add - unacked reqs */
6236 +      struct semaphore pid_sem;            /* PTB control setting pid */
6237 +      struct gendisk *disk;                /* PTB for partitions */
6238 +      struct request_queue *q;             /* PTB make queue internal */
6239 +      rwlock_t meta_lock;                  /* PTB add - spinlock meta data */
6240 +      atomic_t merge_requests;             /* PTB local req blks limit - 1 */
6241 +      unsigned long reenable_time;         /* PTB time to delayed reenable */
6242 +      void (*enable)    (struct nbd_device *lo);
6243 +      void (*reset)     (struct nbd_device *lo, int i);
6244 +      int  (*disable)   (struct nbd_device *lo);
6245 +      int  (*read_only) (struct nbd_device *lo);
6246 +      void (*set_speed) (struct nbd_device *lo);
6247 +      int  (*hard_reset)(struct nbd_device *lo);
6248 +      int  (*soft_reset)(struct nbd_device *lo);
6249 +      int  (*reenable_delay) (struct nbd_device *lo, int delay);
6250 +    };
6251 +
6252 +#endif  /* MAJOR_NR */
6253 +
6254 +
6255 +
6256 +/* Pavel - This now IS in some kind of include file... */
6257 +
6258 +/* PTB 132 */ 
6259 +#define NBD_INIT_MAGIC 0x12345678       /* AMARIN */
6260 +#define NBD_REQUEST_MAGIC 0x25609513
6261 +#define NBD_REPLY_MAGIC 0x67446698     
6262 +/* Pavel - Do *not* use magics: 0x12560953 0x96744668. 
6263 + */
6264 +
6265 +#define NBD_DEV_MAGIC 0x68797548
6266 +
6267 +#define NBD_REQUEST_MAGIC_T  __u32
6268 +#define NBD_REQUEST_TYPE_T   __u32
6269 +#define NBD_REQUEST_FROM_T   __u64
6270 +#define NBD_REQUEST_LEN_T    __u32
6271 +#define NBD_REQUEST_FLAGS_T  __u32
6272 +#define NBD_REQUEST_TIME_T   __u64
6273 +#define NBD_REQUEST_ZONE_T   __u64
6274 +#define NBD_REQUEST_SPECIAL_T  __u32
6275 +
6276 +#define NBD_REPLY_MAGIC_T    __u32
6277 +#define NBD_REPLY_ERROR_T    __s32
6278 +#define NBD_REPLY_FLAGS_T    __u32
6279 +#define NBD_REPLY_TIME_T     __u64
6280 +#define NBD_REPLY_ZONE_T     __u64
6281 +
6282 +#define NBD_REQUEST_HANDLE_T __u32
6283 +#define NBD_REPLY_HANDLE_T   __u32
6284 +
6285 +  typedef __u32 nbd_digest_t[4];
6286 +
6287 +  #define NBD_DIGEST_T   nbd_digest_t
6288 +
6289 +#define NBD_REQUEST_DIGEST_T nbd_digest_t
6290 +#define NBD_REPLY_DIGEST_T   nbd_digest_t
6291 +
6292 +
6293 +#define NBD_DIGEST_BITS      128
6294 +#define NBD_DIGEST_LENGTH    ((NBD_DIGEST_BITS)/8)
6295 +#define NBD_REQUEST_SEQNO_T  __u32
6296 +
6297 +struct nbd_request {
6298 +  NBD_REQUEST_MAGIC_T  magic;
6299 +  NBD_REQUEST_TYPE_T   type;                   /* == READ || == WRITE  */
6300 +  NBD_REQUEST_HANDLE_T handle;
6301 +  NBD_REQUEST_FROM_T   from;                    /* 64 bit PTB 132 */
6302 +  NBD_REQUEST_LEN_T    len;
6303 +
6304 +
6305 +
6306 +#define NBD_REQUEST_ERRORED    0x0800
6307 +#define NBD_REQUEST_MD5SUM     0x8000         /* has a digest in it ..*/
6308 +#define NBD_REQUEST_MD5_OK    0x10000         /* .. and equaled req's */
6309 +#define NBD_REQUEST_IOCTL     0x40000         /* ioctl in len, arg in from */
6310 +#define NBD_REQUEST_SPECIALRW 0x80000         /* 1 for w 0 for r on special */
6311 +  NBD_REQUEST_FLAGS_T  flags;
6312 +  NBD_REQUEST_TIME_T   time;
6313 +  NBD_REQUEST_ZONE_T   zone;
6314 +  NBD_REQUEST_SEQNO_T  seqno;
6315 +  union {
6316 +       NBD_REQUEST_DIGEST_T digest;
6317 +  } data;
6318 +  NBD_REQUEST_SPECIAL_T special;
6319 +  char dummy0[0];
6320 +  char dummy1[0] __attribute__ ((aligned (64)));
6321 +} __attribute__ ((packed)) ;
6322 +
6323 +  #define NBD_REQUEST_LENGTH sizeof(struct nbd_request)
6324 +
6325 +struct nbd_reply {
6326 +  NBD_REPLY_MAGIC_T    magic;
6327 +  NBD_REPLY_ERROR_T    error;                /* 0 = ok, else error     */
6328 +  NBD_REPLY_HANDLE_T   handle;               /* handle you got from request */
6329 +
6330 +
6331 +
6332 +#define NBD_REPLY_ERRORED      0x0800
6333 +#define NBD_REPLY_MD5SUM       0x8000         /* has a digest in it .. */
6334 +#define NBD_REPLY_MD5_OK      0x10000         /* .. and equaled req's  */
6335 +#define NBD_REPLY_CLOSE       0x20000         /* close cmd from server */
6336 +#define NBD_REPLY_IOCTL       0x40000         /* ioctl in len, arg in from */
6337 +  NBD_REPLY_FLAGS_T    flags;
6338 +  NBD_REPLY_TIME_T     time;
6339 +  NBD_REPLY_ZONE_T     zone;
6340 +  union {
6341 +       NBD_REPLY_DIGEST_T digest;
6342 +  } data;
6343 +  char dummy0[0];
6344 +  char dummy1[0] __attribute__ ((aligned (64)));
6345 +} __attribute__ ((packed)) ;
6346 +
6347 +  #define NBD_REPLY_LENGTH sizeof(struct nbd_reply)
6348 +
6349 +  #define NBD_BUFFER_DATA_OFFSET \
6350 +   ((NBD_REQUEST_LENGTH>NBD_REPLY_LENGTH)?NBD_REQUEST_LENGTH:NBD_REPLY_LENGTH)
6351 +
6352 +  #ifdef MAJOR_NR
6353 +
6354 +  // PTB forward declaration
6355 +  static struct nbd_device nbd_dev[];
6356 +
6357 +
6358 +  static long wait_for_completion_timeout(struct completion *x, long timeout)
6359 +  {
6360 +       spin_lock_irq(&x->wait.lock);
6361 +       if (!x->done && timeout > 0) {
6362 +               DECLARE_WAITQUEUE(wait, current);
6363 +
6364 +               wait.flags |= WQ_FLAG_EXCLUSIVE;
6365 +               __add_wait_queue_tail(&x->wait, &wait);
6366 +               do {
6367 +                       __set_current_state(TASK_UNINTERRUPTIBLE);
6368 +                       spin_unlock_irq(&x->wait.lock);
6369 +                       timeout = schedule_timeout(timeout);
6370 +                       spin_lock_irq(&x->wait.lock);
6371 +               } while (!x->done && timeout > 0);
6372 +               __remove_wait_queue(&x->wait, &wait);
6373 +       }
6374 +        if (x->done) {
6375 +               x->done--;
6376 +                if (timeout <= 0)
6377 +                        timeout = 1;
6378 +        }
6379 +       spin_unlock_irq(&x->wait.lock);
6380 +        return timeout;
6381 +  }
6382 +
6383 +  static void end_request(struct request *req, int uptodate) {  
6384 +
6385 +     struct bio *bio;
6386 +     struct nbd_device *lo = req->rq_disk->private_data;
6387 +     static int rq_type(struct request *);
6388 +
6389 +     if (rq_type(req) == IOCTL) {
6390 +            // PTB this is the devices ioctl request 
6391 +            complete(req->waiting);
6392 +            // PTB let the driver code return the req, etc.
6393 +            return;
6394 +     }
6395 +
6396 +     /* unlock chained buffers */
6397 +     while ((bio = req->bio) != NULL) {
6398 +            unsigned nsect = bio_sectors(bio);
6399 +            blk_finished_io(nsect);
6400 +            req->bio = bio->bi_next;
6401 +            bio->bi_next = NULL;
6402 +            bio_endio(bio, nsect << 9, uptodate ? 0 : -EIO);
6403 +     }
6404 +
6405 +     if (req->flags & REQ_SPECIAL)
6406 +            // don't account specials
6407 +            return;
6408 +
6409 +     write_lock(&lo->altqueue_lock);
6410 +     if (atomic_read(&lo->countq[READ])
6411 +       + atomic_read(&lo->countq[WRITE]) == 0) {
6412 +            if (atomic_read(&lo->flags) & NBD_QBLOCKED) {
6413 +                    static int nbd_requeue(struct nbd_device *);
6414 +                    nbd_requeue(lo);
6415 +                    atomic_clear_mask(NBD_QBLOCKED, &lo->flags);
6416 +            } 
6417 +     } 
6418 +     write_unlock(&lo->altqueue_lock);
6419 +  }
6420 +     
6421 + /* 
6422 +  * PTB This takes the spinlock itself! So call it with the io spinlock
6423 +  * not held.
6424 +  */
6425 +  static void end_request_lock(struct request *req, int uptodate) {  
6426 +
6427 +     unsigned long flags;
6428 +     request_queue_t *q = req->q;
6429 +
6430 +     spin_lock_irqsave(q->queue_lock, flags);
6431 +     end_request(req, uptodate);
6432 +     spin_unlock_irqrestore(q->queue_lock, flags);
6433 +  }
6434 +
6435 + /*
6436 +  * PTB Call this only with the io spinlock * held.
6437 +  */
6438 +  static inline void nbd_end_request(struct request *req) {
6439 +
6440 +    // PTB the kernel has only 2 queues, read and write, and it uses
6441 +    // the cmd field to determine to which the req belongs. We add a
6442 +    // seqno to it in nbd_do_req, so we reestablish it here.
6443 +    static void rq_set_seqno(struct request *, int);
6444 +
6445 +    rq_set_seqno(req, 0); // PTB Zero extra seqno info
6446 +    end_request( req, (req->errors == 0) ? 1 : 0 );
6447 +  }
6448 +
6449 + /* 
6450 +  * PTB This takes the spinlock itself! So call it with the io spinlock
6451 +  * not held.
6452 +  */
6453 +  static void nbd_end_request_lock(struct request *req) {  
6454 +
6455 +    // PTB the kernel has only 2 queues, read and write, and it uses
6456 +    // the cmd field to determine to which the req belongs. We add a
6457 +    // seqno to it in nbd_do_req, so we reestablish it here.
6458 +    static void rq_set_seqno(struct request *, int);
6459 +
6460 +    rq_set_seqno(req, 0); // PTB Zero extra seqno info
6461 +    end_request_lock( req, !req->errors );
6462 +  }
6463 +
6464 +  extern int nbd_init_seqno(struct nbd_seqno *);
6465 +  extern int nbd_init_speed(struct nbd_speed *);
6466 +  extern int nbd_init_md(struct nbd_md *);
6467 +  extern void nbd_init_proc(struct proc_dir_entry *res);
6468 +
6469 +  #endif /* MAJOR_NR */
6470 +
6471 +#endif /* LINUX_ENBD_H */
6472 +
6473 +
6474 --- linux-2.5.64/include/linux/enbd_ioctl.h.pre-enbd    Tue Mar 25 15:20:45 2003
6475 +++ linux-2.5.64/include/linux/enbd_ioctl.h     Mon Mar 24 22:52:26 2003
6476 @@ -0,0 +1,56 @@
6477 +#ifndef NBD_IOCTL_H
6478 +#define NBD_IOCTL_H 1
6479 +
6480 +int nbd_ioctl_convert(int ioctl);
6481 +int nbd_ioctl_convert_inplace(int *ioctl);
6482 +int nbd_ioctl_revert(int ioctl);
6483 +int nbd_ioctl_size (int cmd, char *arg);
6484 +int nbd_ioctl_size_user (int cmd, char *arg);
6485 +#ifdef __KERNEL__
6486 +int nbd_ioctl_copy_to_user (int cmd, char *arg, char *buf, int size);
6487 +int nbd_ioctl_copy_from_user (int cmd, char *buf, char *arg, int size);
6488 +
6489 +/*
6490 + * PTB object containing all the above methods, to be registered with
6491 + * the enbd.o module
6492 + */
6493 +struct nbd_ioctl {
6494 +#define NBD_REMOTE_IOCTL_ENABLED 0x01
6495 +        unsigned long flags;
6496 +        int (*convert)        (int ioctl);
6497 +        int (*convert_inplace)(int *ioctl);
6498 +        int (*revert)         (int ioctl);
6499 +        int (*size)           (int cmd, char *arg);
6500 +        int (*size_user)      (int cmd, char *arg);
6501 +        int (*cp_to_user)     (int cmd, char *arg, char *buf, int size);
6502 +        int (*cp_from_user)   (int cmd, char *buf, char *arg, int size);
6503 +};
6504 +
6505 +struct nbd_ioctl_stub {
6506 +        struct nbd_ioctl *    remote;
6507 +        int (*reg)       (struct nbd_ioctl_stub *,struct nbd_ioctl *);
6508 +        int (*unreg)     (struct nbd_ioctl_stub *,struct nbd_ioctl *);
6509 +};
6510 +
6511 +extern struct nbd_ioctl_stub nbd_remote_ioctl;
6512 +extern int nbd_init_ioctl_stub(struct nbd_ioctl_stub *);
6513 +#endif
6514 +
6515 +// PTB conversion table entries
6516 +struct ioctl_conv {
6517 +   unsigned int old; // ioctl id, _IO or _IOR or _IOW or _IOWR
6518 +   unsigned int new; // ioctl id
6519 +};
6520 +
6521 +// PTB extended conversion table entries
6522 +struct ioctl_special {
6523 +    int new;
6524 +    int (*size) (char *arg);
6525 +    int (*size_user) (char *arg);
6526 +    int (*ioctl_copy_from_user)(char *buf, char*arg, int size);
6527 +    int (*ioctl_copy_to_user)(char *arg, char*buf, int size);
6528 +};
6529 +
6530 +extern int nbd_init_ioctl_stub(struct nbd_ioctl_stub *);
6531 +
6532 +#endif /* NBD_IOCTL_H */
This page took 0.630619 seconds and 3 git commands to generate.