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