Bug Summary

File:obj-scan-build/../linux/dev/glue/block.c
Location:line 454, column 11
Description:Dereference of undefined pointer value

Annotated Source Code

1/*
2 * Linux block driver support.
3 *
4 * Copyright (C) 1996 The University of Utah and the Computer Systems
5 * Laboratory at the University of Utah (CSL)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 * Author: Shantanu Goel, University of Utah CSL
22 */
23
24/*
25 * linux/drivers/block/ll_rw_blk.c
26 *
27 * Copyright (C) 1991, 1992 Linus Torvalds
28 * Copyright (C) 1994, Karl Keyte: Added support for disk statistics
29 */
30
31/*
32 * linux/fs/block_dev.c
33 *
34 * Copyright (C) 1991, 1992 Linus Torvalds
35 */
36
37/*
38 * linux/fs/buffer.c
39 *
40 * Copyright (C) 1991, 1992 Linus Torvalds
41 */
42
43#include <sys/types.h>
44#include <machine/spl.h>
45#include <mach/mach_types.h>
46#include <mach/kern_return.h>
47#include <mach/mig_errors.h>
48#include <mach/port.h>
49#include <mach/vm_param.h>
50#include <mach/notify.h>
51
52#include <kern/kalloc.h>
53
54#include <ipc/ipc_port.h>
55#include <ipc/ipc_space.h>
56
57#include <vm/vm_map.h>
58#include <vm/vm_kern.h>
59#include <vm/vm_page.h>
60
61#include <device/device_types.h>
62#include <device/device_port.h>
63#include <device/disk_status.h>
64#include <device/device_reply.user.h>
65#include <device/device_emul.h>
66#include <device/ds_routines.h>
67
68/* TODO. This should be fixed to not be i386 specific. */
69#include <i386at/disk.h>
70
71#define MACH_INCLUDE
72#include <linux/fs.h>
73#include <linux/blk.h>
74#include <linux/string.h>
75#include <linux/errno.h>
76#include <linux/fcntl.h>
77#include <linux/major.h>
78#include <linux/kdev_t.h>
79#include <linux/delay.h>
80#include <linux/malloc.h>
81#include <linux/hdreg.h>
82#include <asm/io.h>
83
84#include <linux/dev/glue/glue.h>
85
86/* This task queue is not used in Mach: just for fixing undefined symbols. */
87DECLARE_TASK_QUEUE (tq_disk)task_queue tq_disk = ((void *) 0);
88
89/* Location of VTOC in units for sectors (512 bytes). */
90#define PDLOCATION29 29
91
92/* Linux kernel variables. */
93
94/* Temporary data allocated on the stack. */
95struct temp_data
96{
97 struct inode inode;
98 struct file file;
99 struct request req;
100 queue_head_t pages;
101};
102
103/* One of these exists for each
104 driver associated with a major number. */
105struct device_struct
106{
107 const char *name; /* device name */
108 struct file_operations *fops; /* operations vector */
109 int busy:1; /* driver is being opened/closed */
110 int want:1; /* someone wants to open/close driver */
111 struct gendisk *gd; /* DOS partition information */
112 int default_slice; /* what slice to use when none is given */
113 struct disklabel **labels; /* disklabels for each DOS partition */
114};
115
116/* An entry in the Mach name to Linux major number conversion table. */
117struct name_map
118{
119 const char *name; /* Mach name for device */
120 unsigned major; /* Linux major number */
121 unsigned unit; /* Linux unit number */
122 int read_only; /* 1 if device is read only */
123};
124
125/* Driver operation table. */
126static struct device_struct blkdevs[MAX_BLKDEV128];
127
128/* Driver request function table. */
129struct blk_dev_struct blk_dev[MAX_BLKDEV128] =
130{
131 { NULL((void *) 0), NULL((void *) 0) }, /* 0 no_dev */
132 { NULL((void *) 0), NULL((void *) 0) }, /* 1 dev mem */
133 { NULL((void *) 0), NULL((void *) 0) }, /* 2 dev fd */
134 { NULL((void *) 0), NULL((void *) 0) }, /* 3 dev ide0 or hd */
135 { NULL((void *) 0), NULL((void *) 0) }, /* 4 dev ttyx */
136 { NULL((void *) 0), NULL((void *) 0) }, /* 5 dev tty */
137 { NULL((void *) 0), NULL((void *) 0) }, /* 6 dev lp */
138 { NULL((void *) 0), NULL((void *) 0) }, /* 7 dev pipes */
139 { NULL((void *) 0), NULL((void *) 0) }, /* 8 dev sd */
140 { NULL((void *) 0), NULL((void *) 0) }, /* 9 dev st */
141 { NULL((void *) 0), NULL((void *) 0) }, /* 10 */
142 { NULL((void *) 0), NULL((void *) 0) }, /* 11 */
143 { NULL((void *) 0), NULL((void *) 0) }, /* 12 */
144 { NULL((void *) 0), NULL((void *) 0) }, /* 13 */
145 { NULL((void *) 0), NULL((void *) 0) }, /* 14 */
146 { NULL((void *) 0), NULL((void *) 0) }, /* 15 */
147 { NULL((void *) 0), NULL((void *) 0) }, /* 16 */
148 { NULL((void *) 0), NULL((void *) 0) }, /* 17 */
149 { NULL((void *) 0), NULL((void *) 0) }, /* 18 */
150 { NULL((void *) 0), NULL((void *) 0) }, /* 19 */
151 { NULL((void *) 0), NULL((void *) 0) }, /* 20 */
152 { NULL((void *) 0), NULL((void *) 0) }, /* 21 */
153 { NULL((void *) 0), NULL((void *) 0) } /* 22 dev ide1 */
154};
155
156/*
157 * blk_size contains the size of all block-devices in units of 1024 byte
158 * sectors:
159 *
160 * blk_size[MAJOR][MINOR]
161 *
162 * if (!blk_size[MAJOR]) then no minor size checking is done.
163 */
164int *blk_size[MAX_BLKDEV128] = { NULL((void *) 0), NULL((void *) 0), };
165
166/*
167 * blksize_size contains the size of all block-devices:
168 *
169 * blksize_size[MAJOR][MINOR]
170 *
171 * if (!blksize_size[MAJOR]) then 1024 bytes is assumed.
172 */
173int *blksize_size[MAX_BLKDEV128] = { NULL((void *) 0), NULL((void *) 0), };
174
175/*
176 * hardsect_size contains the size of the hardware sector of a device.
177 *
178 * hardsect_size[MAJOR][MINOR]
179 *
180 * if (!hardsect_size[MAJOR])
181 * then 512 bytes is assumed.
182 * else
183 * sector_size is hardsect_size[MAJOR][MINOR]
184 * This is currently set by some scsi device and read by the msdos fs driver
185 * This might be a some uses later.
186 */
187int *hardsect_size[MAX_BLKDEV128] = { NULL((void *) 0), NULL((void *) 0), };
188
189/* This specifies how many sectors to read ahead on the disk.
190 This is unused in Mach. It is here to make drivers compile. */
191int read_ahead[MAX_BLKDEV128] = {0, };
192
193/* Use to wait on when there are no free requests.
194 This is unused in Mach. It is here to make drivers compile. */
195struct wait_queue *wait_for_request = NULL((void *) 0);
196
197/* Initialize block drivers. */
198int
199blk_dev_init ()
200{
201#ifdef CONFIG_BLK_DEV_IDE1
202 ide_init ();
203#endif
204#ifdef CONFIG_BLK_DEV_FD1
205 floppy_init ();
206#else
207 outb_p (0xc, 0x3f2)((__builtin_constant_p((0x3f2)) && (0x3f2) < 256) ?
__outbc_p((0xc),(0x3f2)) : __outb_p((0xc),(0x3f2)))
;
208#endif
209 return 0;
210}
211
212/* Return 1 if major number MAJOR corresponds to a disk device. */
213static inlineinline __attribute__((always_inline)) int
214disk_major (int major)
215{
216 return (major == IDE0_MAJOR3
217 || major == IDE1_MAJOR22
218 || major == IDE2_MAJOR33
219 || major == IDE3_MAJOR34
220 || major == SCSI_DISK_MAJOR8);
221}
222
223/* Linux kernel block support routines. */
224
225/* Register a driver for major number MAJOR,
226 with name NAME, and operations vector FOPS. */
227int
228register_blkdev (unsigned major, const char *name,
229 struct file_operations *fops)
230{
231 if (major == 0)
232 {
233 for (major = MAX_BLKDEV128 - 1; major > 0; major--)
234 if (blkdevs[major].fops == NULL((void *) 0))
235 goto out;
236 return -EBUSY16;
237 }
238 if (major >= MAX_BLKDEV128)
239 return -EINVAL22;
240 if (blkdevs[major].fops && blkdevs[major].fops != fops)
241 return -EBUSY16;
242
243out:
244 blkdevs[major].name = name;
245 blkdevs[major].fops = fops;
246 blkdevs[major].busy = 0;
247 blkdevs[major].want = 0;
248 blkdevs[major].gd = NULL((void *) 0);
249 blkdevs[major].default_slice = 0;
250 blkdevs[major].labels = NULL((void *) 0);
251 return 0;
252}
253
254/* Unregister the driver associated with
255 major number MAJOR and having the name NAME. */
256int
257unregister_blkdev (unsigned major, const char *name)
258{
259 if (major >= MAX_BLKDEV128)
260 return -EINVAL22;
261 if (! blkdevs[major].fops || strcmp (blkdevs[major].name, name))
262 return -EINVAL22;
263 blkdevs[major].fops = NULL((void *) 0);
264 if (blkdevs[major].labels)
265 {
266 assert (blkdevs[major].gd)({ if (!(blkdevs[major].gd)) Assert("blkdevs[major].gd", "../linux/dev/glue/block.c"
, 266); })
;
267 kfree ((vm_offset_t) blkdevs[major].labels,
268 (sizeof (struct disklabel *)
269 * blkdevs[major].gd->max_p * blkdevs[major].gd->max_nr));
270 }
271 return 0;
272}
273
274void
275set_blocksize (kdev_t dev, int size)
276{
277 if (! blksize_size[MAJOR (dev)((dev) >> 8)])
278 return;
279
280 switch (size)
281 {
282 case 512:
283 case 1024:
284 case 2048:
285 case 4096:
286 break;
287 default:
288 panic ("Invalid blocksize passed to set_blocksize");
289 break;
290 }
291 blksize_size[MAJOR (dev)((dev) >> 8)][MINOR (dev)((dev) & ((1<<8) - 1))] = size;
292}
293
294/* Allocate a buffer SIZE bytes long. */
295static void *
296alloc_buffer (int size)
297{
298 vm_page_t m;
299 struct temp_data *d;
300
301 assert (size <= PAGE_SIZE)({ if (!(size <= (1 << 12))) Assert("size <= PAGE_SIZE"
, "../linux/dev/glue/block.c", 301); })
;
302
303 if (! linux_auto_config)
304 {
305 while ((m = vm_page_grab (FALSE((boolean_t) 0))) == 0)
306 VM_PAGE_WAIT (0)vm_page_wait(0);
307 d = current_thread ()(active_threads[(0)])->pcb->data;
308 assert (d)({ if (!(d)) Assert("d", "../linux/dev/glue/block.c", 308); }
)
;
309 queue_enter (&d->pages, m, vm_page_t, pageq){ queue_entry_t prev; prev = (&d->pages)->prev; if (
(&d->pages) == prev) { (&d->pages)->next = (
queue_entry_t) (m); } else { ((vm_page_t)prev)->pageq.next
= (queue_entry_t)(m); } (m)->pageq.prev = prev; (m)->pageq
.next = &d->pages; (&d->pages)->prev = (queue_entry_t
) m; }
;
310 return (void *) phystokv(m->phys_addr)((vm_offset_t)(m->phys_addr) + 0xC0000000UL);
311 }
312 return (void *) __get_free_pages (GFP_KERNEL0x03, 0, ~0UL);
313}
314
315/* Free buffer P which is SIZE bytes long. */
316static void
317free_buffer (void *p, int size)
318{
319 struct temp_data *d;
320 vm_page_t m;
321
322 assert (size <= PAGE_SIZE)({ if (!(size <= (1 << 12))) Assert("size <= PAGE_SIZE"
, "../linux/dev/glue/block.c", 322); })
;
323
324 if (! linux_auto_config)
325 {
326 d = current_thread ()(active_threads[(0)])->pcb->data;
327 assert (d)({ if (!(d)) Assert("d", "../linux/dev/glue/block.c", 327); }
)
;
328 queue_iterate (&d->pages, m, vm_page_t, pageq)for ((m) = (vm_page_t) ((&d->pages)->next); !(((&
d->pages)) == ((queue_entry_t)(m))); (m) = (vm_page_t) ((&
(m)->pageq)->next))
329 {
330 if (phystokv(m->phys_addr)((vm_offset_t)(m->phys_addr) + 0xC0000000UL) == (vm_offset_t) p)
331 {
332 queue_remove (&d->pages, m, vm_page_t, pageq){ queue_entry_t next, prev; next = (m)->pageq.next; prev =
(m)->pageq.prev; if ((&d->pages) == next) (&d->
pages)->prev = prev; else ((vm_page_t)next)->pageq.prev
= prev; if ((&d->pages) == prev) (&d->pages)->
next = next; else ((vm_page_t)prev)->pageq.next = next; }
;
333 VM_PAGE_FREE (m)({ ; vm_page_free(m); ((void)(&vm_page_queue_lock)); });
334 return;
335 }
336 }
337 panic ("free_buffer");
338 }
339 free_pages ((unsigned long) p, 0);
340}
341
342/* Allocate a buffer of SIZE bytes and
343 associate it with block number BLOCK of device DEV. */
344struct buffer_head *
345getblk (kdev_t dev, int block, int size)
346{
347 struct buffer_head *bh;
348
349 assert (size <= PAGE_SIZE)({ if (!(size <= (1 << 12))) Assert("size <= PAGE_SIZE"
, "../linux/dev/glue/block.c", 349); })
;
350
351 bh = (struct buffer_head *) kalloc (sizeof (struct buffer_head));
352 if (bh)
353 {
354 memset (bh, 0, sizeof (struct buffer_head))(__builtin_constant_p(0) ? (__builtin_constant_p((sizeof (struct
buffer_head))) ? __constant_c_and_count_memset(((bh)),((0x01010101UL
*(unsigned char)(0))),((sizeof (struct buffer_head)))) : __constant_c_memset
(((bh)),((0x01010101UL*(unsigned char)(0))),((sizeof (struct buffer_head
))))) : (__builtin_constant_p((sizeof (struct buffer_head))) ?
__memset_generic((((bh))),(((0))),(((sizeof (struct buffer_head
))))) : __memset_generic(((bh)),((0)),((sizeof (struct buffer_head
))))))
;
355 bh->b_data = alloc_buffer (size);
356 if (! bh->b_data)
357 {
358 kfree ((vm_offset_t) bh, sizeof (struct buffer_head));
359 return NULL((void *) 0);
360 }
361 bh->b_dev = dev;
362 bh->b_size = size;
363 bh->b_state = 1 << BH_Lock2;
364 bh->b_blocknr = block;
365 }
366 return bh;
367}
368
369/* Release buffer BH previously allocated by getblk. */
370void
371__brelse (struct buffer_head *bh)
372{
373 free_buffer (bh->b_data, bh->b_size);
374 kfree ((vm_offset_t) bh, sizeof (*bh));
375}
376
377/* Allocate a buffer of SIZE bytes and fill it with data
378 from device DEV starting at block number BLOCK. */
379struct buffer_head *
380bread (kdev_t dev, int block, int size)
381{
382 struct buffer_head *bh;
383
384 bh = getblk (dev, block, size);
385 if (bh)
386 {
387 ll_rw_block (READ0, 1, &bh, 0);
388 wait_on_buffer (bh);
389 if (! buffer_uptodate (bh))
390 {
391 __brelse (bh);
392 return NULL((void *) 0);
393 }
394 }
395 return bh;
396}
397
398/* Return the block size for device DEV in *BSIZE and
399 log2(block size) in *BSHIFT. */
400static void
401get_block_size (kdev_t dev, int *bsize, int *bshift)
402{
403 int i;
404
405 *bsize = BLOCK_SIZE1024;
406 if (blksize_size[MAJOR (dev)((dev) >> 8)]
407 && blksize_size[MAJOR (dev)((dev) >> 8)][MINOR (dev)((dev) & ((1<<8) - 1))])
408 *bsize = blksize_size[MAJOR (dev)((dev) >> 8)][MINOR (dev)((dev) & ((1<<8) - 1))];
409 for (i = *bsize, *bshift = 0; i != 1; i >>= 1, (*bshift)++)
410 ;
411}
412
413/* Enqueue request REQ on a driver's queue. */
414static inlineinline __attribute__((always_inline)) void
415enqueue_request (struct request *req)
416{
417 struct request *tmp;
418 struct blk_dev_struct *dev;
419
420 dev = blk_dev + MAJOR (req->rq_dev)((req->rq_dev) >> 8);
421 cli ()__asm__ __volatile__ ("cli": : :"memory");
422 tmp = dev->current_request;
423 if (! tmp)
424 {
425 dev->current_request = req;
426 (*dev->request_fn) ();
427 sti ()__asm__ __volatile__ ("sti": : :"memory");
428 return;
429 }
430 while (tmp->next)
431 {
432 if ((IN_ORDER (tmp, req)((tmp)->rq_dev < (req)->rq_dev || (((tmp)->rq_dev
== (req)->rq_dev && (tmp)->sector < (req)->
sector)))
|| ! IN_ORDER (tmp, tmp->next)((tmp)->rq_dev < (tmp->next)->rq_dev || (((tmp)->
rq_dev == (tmp->next)->rq_dev && (tmp)->sector
< (tmp->next)->sector)))
)
433 && IN_ORDER (req, tmp->next)((req)->rq_dev < (tmp->next)->rq_dev || (((req)->
rq_dev == (tmp->next)->rq_dev && (req)->sector
< (tmp->next)->sector)))
)
434 break;
435 tmp = tmp->next;
436 }
437 req->next = tmp->next;
438 tmp->next = req;
439 if (scsi_blk_major (MAJOR (req->rq_dev)((req->rq_dev) >> 8)))
440 (*dev->request_fn) ();
441 sti ()__asm__ __volatile__ ("sti": : :"memory");
442}
443
444/* Perform the I/O operation RW on the buffer list BH
445 containing NR buffers. */
446void
447ll_rw_block (int rw, int nr, struct buffer_head **bh, int quiet)
448{
449 int i, bshift, bsize;
450 unsigned major;
451 struct request *r;
452 static struct request req;
453
454 major = MAJOR (bh[0]->b_dev)((bh[0]->b_dev) >> 8);
9
Within the expansion of the macro 'MAJOR':
a
Dereference of undefined pointer value
455 assert (major < MAX_BLKDEV)({ if (!(major < 128)) Assert("major < MAX_BLKDEV", "../linux/dev/glue/block.c"
, 455); })
;
456
457 get_block_size (bh[0]->b_dev, &bsize, &bshift);
458
459 if (! linux_auto_config)
460 {
461 assert (current_thread ()->pcb->data)({ if (!((active_threads[(0)])->pcb->data)) Assert("current_thread ()->pcb->data"
, "../linux/dev/glue/block.c", 461); })
;
462 r = &((struct temp_data *) current_thread ()(active_threads[(0)])->pcb->data)->req;
463 }
464 else
465 r = &req;
466
467 for (i = 0, r->nr_sectors = 0; i < nr - 1; i++)
468 {
469 r->nr_sectors += bh[i]->b_size >> 9;
470 bh[i]->b_reqnext = bh[i + 1];
471 }
472 r->nr_sectors += bh[i]->b_size >> 9;
473 bh[i]->b_reqnext = NULL((void *) 0);
474
475 r->rq_status = RQ_ACTIVE1;
476 r->rq_dev = bh[0]->b_dev;
477 r->cmd = rw;
478 r->errors = 0;
479 r->quiet = quiet;
480 r->sector = bh[0]->b_blocknr << (bshift - 9);
481 r->current_nr_sectors = bh[0]->b_size >> 9;
482 r->buffer = bh[0]->b_data;
483 r->bh = bh[0];
484 r->bhtail = bh[nr - 1];
485 r->sem = NULL((void *) 0);
486 r->next = NULL((void *) 0);
487
488 enqueue_request (r);
489}
490
491#define BSIZE(1 << bshift) (1 << bshift)
492#define BMASK((1 << bshift) - 1) (BSIZE(1 << bshift) - 1)
493
494/* Perform read/write operation RW on device DEV
495 starting at *off to/from buffer *BUF of size *RESID.
496 The device block size is given by BSHIFT. *OFF and
497 *RESID may be non-multiples of the block size.
498 *OFF, *BUF and *RESID are updated if the operation
499 completed successfully. */
500static int
501rdwr_partial (int rw, kdev_t dev, loff_t *off,
502 char **buf, int *resid, int bshift)
503{
504 int c, err = 0, o;
505 long sect, nsect;
506 struct buffer_head bhead, *bh = &bhead;
507 struct gendisk *gd;
508
509 memset (bh, 0, sizeof (struct buffer_head))(__builtin_constant_p(0) ? (__builtin_constant_p((sizeof (struct
buffer_head))) ? __constant_c_and_count_memset(((bh)),((0x01010101UL
*(unsigned char)(0))),((sizeof (struct buffer_head)))) : __constant_c_memset
(((bh)),((0x01010101UL*(unsigned char)(0))),((sizeof (struct buffer_head
))))) : (__builtin_constant_p((sizeof (struct buffer_head))) ?
__memset_generic((((bh))),(((0))),(((sizeof (struct buffer_head
))))) : __memset_generic(((bh)),((0)),((sizeof (struct buffer_head
))))))
;
510 bh->b_state = 1 << BH_Lock2;
511 bh->b_dev = dev;
512 bh->b_blocknr = *off >> bshift;
513 bh->b_size = BSIZE(1 << bshift);
514
515 /* Check if this device has non even number of blocks. */
516 for (gd = gendisk_head, nsect = -1; gd; gd = gd->next)
517 if (gd->major == MAJOR (dev)((dev) >> 8))
518 {
519 nsect = gd->part[MINOR (dev)((dev) & ((1<<8) - 1))].nr_sects;
520 break;
521 }
522 if (nsect > 0)
523 {
524 sect = bh->b_blocknr << (bshift - 9);
525 assert ((nsect - sect) > 0)({ if (!((nsect - sect) > 0)) Assert("(nsect - sect) > 0"
, "../linux/dev/glue/block.c", 525); })
;
526 if (nsect - sect < (BSIZE(1 << bshift) >> 9))
527 bh->b_size = (nsect - sect) << 9;
528 }
529 bh->b_data = alloc_buffer (bh->b_size);
530 if (! bh->b_data)
531 return -ENOMEM12;
532 ll_rw_block (READ0, 1, &bh, 0);
533 wait_on_buffer (bh);
534 if (buffer_uptodate (bh))
535 {
536 o = *off & BMASK((1 << bshift) - 1);
537 c = bh->b_size - o;
538 if (c > *resid)
539 c = *resid;
540 if (rw == READ0)
541 memcpy (*buf, bh->b_data + o, c)(__builtin_constant_p(c) ? __constant_memcpy((*buf),(bh->b_data
+ o),(c)) : __memcpy((*buf),(bh->b_data + o),(c)))
;
542 else
543 {
544 memcpy (bh->b_data + o, *buf, c)(__builtin_constant_p(c) ? __constant_memcpy((bh->b_data +
o),(*buf),(c)) : __memcpy((bh->b_data + o),(*buf),(c)))
;
545 bh->b_state = (1 << BH_Dirty1) | (1 << BH_Lock2);
546 ll_rw_block (WRITE1, 1, &bh, 0);
547 wait_on_buffer (bh);
548 if (! buffer_uptodate (bh))
549 {
550 err = -EIO5;
551 goto out;
552 }
553 }
554 *buf += c;
555 *resid -= c;
556 *off += c;
557 }
558 else
559 err = -EIO5;
560out:
561 free_buffer (bh->b_data, bh->b_size);
562 return err;
563}
564
565#define BH_Bounce16 16
566#define MAX_BUF8 8
567
568/* Perform read/write operation RW on device DEV
569 starting at *off to/from buffer *BUF of size *RESID.
570 The device block size is given by BSHIFT. *OFF and
571 *RESID must be multiples of the block size.
572 *OFF, *BUF and *RESID are updated if the operation
573 completed successfully. */
574static int
575rdwr_full (int rw, kdev_t dev, loff_t *off, char **buf, int *resid, int bshift)
576{
577 int cc, err = 0, i, j, nb, nbuf;
578 long blk;
579 struct buffer_head bhead[MAX_BUF8], *bh, *bhp[MAX_BUF8];
580
581 assert ((*off & BMASK) == 0)({ if (!((*off & ((1 << bshift) - 1)) == 0)) Assert
("(*off & BMASK) == 0", "../linux/dev/glue/block.c", 581)
; })
;
582
583 nbuf = *resid >> bshift;
584 blk = *off >> bshift;
585 for (i = nb = 0, bh = bhead; nb < nbuf; bh++)
5
Assuming 'nb' is >= 'nbuf'
6
Loop condition is false. Execution continues on line 625
586 {
587 memset (bh, 0, sizeof (*bh))(__builtin_constant_p(0) ? (__builtin_constant_p((sizeof (*bh
))) ? __constant_c_and_count_memset(((bh)),((0x01010101UL*(unsigned
char)(0))),((sizeof (*bh)))) : __constant_c_memset(((bh)),((
0x01010101UL*(unsigned char)(0))),((sizeof (*bh))))) : (__builtin_constant_p
((sizeof (*bh))) ? __memset_generic((((bh))),(((0))),(((sizeof
(*bh))))) : __memset_generic(((bh)),((0)),((sizeof (*bh)))))
)
;
588 bh->b_dev = dev;
589 bh->b_blocknr = blk;
590 set_bit (BH_Lock2, &bh->b_state);
591 if (rw == WRITE1)
592 set_bit (BH_Dirty1, &bh->b_state);
593 cc = PAGE_SIZE(1 << 12) - (((int) *buf + (nb << bshift)) & PAGE_MASK((1 << 12)-1));
594 if (cc >= BSIZE(1 << bshift) && (((int) *buf + (nb << bshift)) & 511) == 0)
595 cc &= ~BMASK((1 << bshift) - 1);
596 else
597 {
598 cc = PAGE_SIZE(1 << 12);
599 set_bit (BH_Bounce16, &bh->b_state);
600 }
601 if (cc > ((nbuf - nb) << bshift))
602 cc = (nbuf - nb) << bshift;
603 if (! test_bit (BH_Bounce16, &bh->b_state))
604 bh->b_data = (char *) phystokv(pmap_extract (vm_map_pmap (device_io_map),((vm_offset_t)(pmap_extract (((device_io_map)->pmap), (((vm_offset_t
) *buf) + (nb << bshift)))) + 0xC0000000UL)
605 (((vm_offset_t) *buf)((vm_offset_t)(pmap_extract (((device_io_map)->pmap), (((vm_offset_t
) *buf) + (nb << bshift)))) + 0xC0000000UL)
606 + (nb << bshift))))((vm_offset_t)(pmap_extract (((device_io_map)->pmap), (((vm_offset_t
) *buf) + (nb << bshift)))) + 0xC0000000UL)
;
607 else
608 {
609 bh->b_data = alloc_buffer (cc);
610 if (! bh->b_data)
611 {
612 err = -ENOMEM12;
613 break;
614 }
615 if (rw == WRITE1)
616 memcpy (bh->b_data, *buf + (nb << bshift), cc)(__builtin_constant_p(cc) ? __constant_memcpy((bh->b_data)
,(*buf + (nb << bshift)),(cc)) : __memcpy((bh->b_data
),(*buf + (nb << bshift)),(cc)))
;
617 }
618 bh->b_size = cc;
619 bhp[i] = bh;
620 nb += cc >> bshift;
621 blk += cc >> bshift;
622 if (++i == MAX_BUF8)
623 break;
624 }
625 if (! err)
7
Taking true branch
626 {
627 ll_rw_block (rw, i, bhp, 0);
8
Calling 'll_rw_block'
628 wait_on_buffer (bhp[i - 1]);
629 }
630 for (bh = bhead, cc = 0, j = 0; j < i; cc += bh->b_size, bh++, j++)
631 {
632 if (! err && buffer_uptodate (bh)
633 && rw == READ0 && test_bit (BH_Bounce16, &bh->b_state))
634 memcpy (*buf + cc, bh->b_data, bh->b_size)(__builtin_constant_p(bh->b_size) ? __constant_memcpy((*buf
+ cc),(bh->b_data),(bh->b_size)) : __memcpy((*buf + cc
),(bh->b_data),(bh->b_size)))
;
635 else if (! err && ! buffer_uptodate (bh))
636 err = -EIO5;
637 if (test_bit (BH_Bounce16, &bh->b_state))
638 free_buffer (bh->b_data, bh->b_size);
639 }
640 if (! err)
641 {
642 *buf += cc;
643 *resid -= cc;
644 *off += cc;
645 }
646 return err;
647}
648
649/* Perform read/write operation RW on device DEV
650 starting at *off to/from buffer BUF of size COUNT.
651 *OFF is updated if the operation completed successfully. */
652static int
653do_rdwr (int rw, kdev_t dev, loff_t *off, char *buf, int count)
654{
655 int bsize, bshift, err = 0, resid = count;
656
657 get_block_size (dev, &bsize, &bshift);
658 if (*off & BMASK((1 << bshift) - 1))
2
Taking false branch
659 err = rdwr_partial (rw, dev, off, &buf, &resid, bshift);
660 while (resid >= bsize && ! err)
3
Loop condition is true. Entering loop body
661 err = rdwr_full (rw, dev, off, &buf, &resid, bshift);
4
Calling 'rdwr_full'
662 if (! err && resid)
663 err = rdwr_partial (rw, dev, off, &buf, &resid, bshift);
664 return err ? err : count - resid;
665}
666
667int
668block_write (struct inode *inode, struct file *filp,
669 const char *buf, int count)
670{
671 return do_rdwr (WRITE1, inode->i_rdev, &filp->f_pos, (char *) buf, count);
672}
673
674int
675block_read (struct inode *inode, struct file *filp, char *buf, int count)
676{
677 return do_rdwr (READ0, inode->i_rdev, &filp->f_pos, buf, count);
1
Calling 'do_rdwr'
678}
679
680/*
681 * This routine checks whether a removable media has been changed,
682 * and invalidates all buffer-cache-entries in that case. This
683 * is a relatively slow routine, so we have to try to minimize using
684 * it. Thus it is called only upon a 'mount' or 'open'. This
685 * is the best way of combining speed and utility, I think.
686 * People changing diskettes in the middle of an operation deserve
687 * to loose :-)
688 */
689int
690check_disk_change (kdev_t dev)
691{
692 unsigned i;
693 struct file_operations * fops;
694
695 i = MAJOR(dev)((dev) >> 8);
696 if (i >= MAX_BLKDEV128 || (fops = blkdevs[i].fops) == NULL((void *) 0))
697 return 0;
698 if (fops->check_media_change == NULL((void *) 0))
699 return 0;
700 if (! (*fops->check_media_change) (dev))
701 return 0;
702
703 /* printf ("Disk change detected on device %s\n", kdevname(dev));*/
704
705 if (fops->revalidate)
706 (*fops->revalidate) (dev);
707
708 return 1;
709}
710
711/* Mach device interface routines. */
712
713/* Mach name to Linux major/minor number mapping table. */
714static struct name_map name_to_major[] =
715{
716 /* IDE disks */
717 { "hd0", IDE0_MAJOR3, 0, 0 },
718 { "hd1", IDE0_MAJOR3, 1, 0 },
719 { "hd2", IDE1_MAJOR22, 0, 0 },
720 { "hd3", IDE1_MAJOR22, 1, 0 },
721 { "hd4", IDE2_MAJOR33, 0, 0 },
722 { "hd5", IDE2_MAJOR33, 1, 0 },
723 { "hd6", IDE3_MAJOR34, 0, 0 },
724 { "hd7", IDE3_MAJOR34, 1, 0 },
725
726 /* IDE CDROMs */
727 { "wcd0", IDE0_MAJOR3, 0, 1 },
728 { "wcd1", IDE0_MAJOR3, 1, 1 },
729 { "wcd2", IDE1_MAJOR22, 0, 1 },
730 { "wcd3", IDE1_MAJOR22, 1, 1 },
731 { "wcd4", IDE2_MAJOR33, 0, 1 },
732 { "wcd5", IDE2_MAJOR33, 1, 1 },
733 { "wcd6", IDE3_MAJOR34, 0, 1 },
734 { "wcd7", IDE3_MAJOR34, 1, 1 },
735
736 /* SCSI disks */
737 { "sd0", SCSI_DISK_MAJOR8, 0, 0 },
738 { "sd1", SCSI_DISK_MAJOR8, 1, 0 },
739 { "sd2", SCSI_DISK_MAJOR8, 2, 0 },
740 { "sd3", SCSI_DISK_MAJOR8, 3, 0 },
741 { "sd4", SCSI_DISK_MAJOR8, 4, 0 },
742 { "sd5", SCSI_DISK_MAJOR8, 5, 0 },
743 { "sd6", SCSI_DISK_MAJOR8, 6, 0 },
744 { "sd7", SCSI_DISK_MAJOR8, 7, 0 },
745
746 /* SCSI CDROMs */
747 { "cd0", SCSI_CDROM_MAJOR11, 0, 1 },
748 { "cd1", SCSI_CDROM_MAJOR11, 1, 1 },
749
750 /* Floppy disks */
751 { "fd0", FLOPPY_MAJOR2, 0, 0 },
752 { "fd1", FLOPPY_MAJOR2, 1, 0 },
753};
754
755#define NUM_NAMES(sizeof (name_to_major) / sizeof (name_to_major[0])) (sizeof (name_to_major) / sizeof (name_to_major[0]))
756
757/* One of these is associated with each open instance of a device. */
758struct block_data
759{
760 const char *name; /* Mach name for device */
761 int want:1; /* someone is waiting for I/O to complete */
762 int open_count; /* number of opens */
763 int iocount; /* number of pending I/O operations */
764 int part; /* BSD partition number (-1 if none) */
765 int flags; /* Linux file flags */
766 int mode; /* Linux file mode */
767 kdev_t dev; /* Linux device number */
768 ipc_port_t port; /* port representing device */
769 struct device_struct *ds; /* driver operation table entry */
770 struct device device; /* generic device header */
771 struct name_map *np; /* name to inode map */
772 struct block_data *next; /* forward link */
773};
774
775/* List of open devices. */
776static struct block_data *open_list;
777
778/* Forward declarations. */
779
780extern struct device_emulation_ops linux_block_emulation_ops;
781
782static io_return_t device_close (void *);
783static io_return_t device_close_forced (void *, int);
784
785/* Return a send right for block device BD. */
786static ipc_port_t
787dev_to_port (void *bd)
788{
789 return (bd
790 ? ipc_port_make_send (((struct block_data *) bd)->port)
791 : IP_NULL((ipc_port_t) ((ipc_object_t) 0)));
792}
793
794/* Return 1 if C is a letter of the alphabet. */
795static inlineinline __attribute__((always_inline)) int
796isalpha (int c)
797{
798 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
799}
800
801/* Return 1 if C is a digit. */
802static inlineinline __attribute__((always_inline)) int
803isdigit (int c)
804{
805 return c >= '0' && c <= '9';
806}
807
808/* Find the name map entry for device NAME.
809 Set *SLICE to be the DOS partition and
810 *PART the BSD/Mach partition, if any. */
811static struct name_map *
812find_name (char *name, int *slice, int *part)
813{
814 char *p, *q;
815 int i, len;
816 struct name_map *np;
817
818 /* Parse name into name, unit, DOS partition (slice) and partition. */
819 for (*slice = 0, *part = -1, p = name; isalpha (*p); p++)
820 ;
821 if (p == name || ! isdigit (*p))
822 return NULL((void *) 0);
823 do
824 p++;
825 while (isdigit (*p));
826 if (*p)
827 {
828 q = p;
829 if (*q == 's' && isdigit (*(q + 1)))
830 {
831 q++;
832 do
833 *slice = *slice * 10 + *q++ - '0';
834 while (isdigit (*q));
835 if (! *q)
836 goto find_major;
837 }
838 if (! isalpha (*q) || *(q + 1))
839 return NULL((void *) 0);
840 *part = *q - 'a';
841 }
842
843find_major:
844 /* Convert name to major number. */
845 for (i = 0, np = name_to_major; i < NUM_NAMES(sizeof (name_to_major) / sizeof (name_to_major[0])); i++, np++)
846 {
847 len = strlen (np->name);
848 if (len == (p - name) && ! strncmp (np->name, name, len))
849 return np;
850 }
851 return NULL((void *) 0);
852}
853
854/* Attempt to read a BSD disklabel from device DEV. */
855static struct disklabel *
856read_bsd_label (kdev_t dev)
857{
858 int bsize, bshift;
859 struct buffer_head *bh;
860 struct disklabel *dlp, *lp = NULL((void *) 0);
861
862 get_block_size (dev, &bsize, &bshift);
863 bh = bread (dev, LBLLOC1 >> (bshift - 9), bsize);
864 if (bh)
865 {
866 dlp = (struct disklabel *) (bh->b_data + ((LBLLOC1 << 9) & (bsize - 1)));
867 if (dlp->d_magic == DISKMAGIC((unsigned int) 0x82564557U) && dlp->d_magic2 == DISKMAGIC((unsigned int) 0x82564557U))
868 {
869 lp = (struct disklabel *) kalloc (sizeof (*lp));
870 assert (lp)({ if (!(lp)) Assert("lp", "../linux/dev/glue/block.c", 870);
})
;
871 memcpy (lp, dlp, sizeof (*lp))(__builtin_constant_p(sizeof (*lp)) ? __constant_memcpy((lp),
(dlp),(sizeof (*lp))) : __memcpy((lp),(dlp),(sizeof (*lp))))
;
872 }
873 __brelse (bh);
874 }
875 return lp;
876}
877
878/* Attempt to read a VTOC from device DEV. */
879static struct disklabel *
880read_vtoc (kdev_t dev)
881{
882 int bshift, bsize, i;
883 struct buffer_head *bh;
884 struct evtoc *evp;
885 struct disklabel *lp = NULL((void *) 0);
886
887 get_block_size (dev, &bsize, &bshift);
888 bh = bread (dev, PDLOCATION29 >> (bshift - 9), bsize);
889 if (bh)
890 {
891 evp = (struct evtoc *) (bh->b_data + ((PDLOCATION29 << 9) & (bsize - 1)));
892 if (evp->sanity == VTOC_SANE0x600DDEEE)
893 {
894 lp = (struct disklabel *) kalloc (sizeof (*lp));
895 assert (lp)({ if (!(lp)) Assert("lp", "../linux/dev/glue/block.c", 895);
})
;
896 lp->d_npartitions = evp->nparts;
897 if (lp->d_npartitions > MAXPARTITIONS8)
898 lp->d_npartitions = MAXPARTITIONS8;
899 for (i = 0; i < lp->d_npartitions; i++)
900 {
901 lp->d_partitions[i].p_size = evp->part[i].p_size;
902 lp->d_partitions[i].p_offset = evp->part[i].p_start;
903 lp->d_partitions[i].p_fstype = FS_BSDFFS7;
904 }
905 }
906 __brelse (bh);
907 }
908 return lp;
909}
910
911/* Initialize BSD/Mach partition table for device
912 specified by NP, DS and *DEV. Check SLICE and *PART for validity. */
913static kern_return_t
914init_partition (struct name_map *np, kdev_t *dev,
915 struct device_struct *ds, int slice, int *part)
916{
917 int i, j;
918 struct disklabel *lp;
919 struct gendisk *gd = ds->gd;
920 struct partition *p;
921 struct temp_data *d = current_thread ()(active_threads[(0)])->pcb->data;
922
923 if (! gd)
924 {
925 *part = -1;
926 return 0;
927 }
928 if (ds->labels)
929 goto check;
930 ds->labels = (struct disklabel **) kalloc (sizeof (struct disklabel *)
931 * gd->max_nr * gd->max_p);
932 if (! ds->labels)
933 return D_NO_MEMORY2508;
934 memset ((void *) ds->labels, 0,(__builtin_constant_p(0) ? (__builtin_constant_p((sizeof (struct
disklabel *) * gd->max_nr * gd->max_p)) ? __constant_c_and_count_memset
((((void *) ds->labels)),((0x01010101UL*(unsigned char)(0)
)),((sizeof (struct disklabel *) * gd->max_nr * gd->max_p
))) : __constant_c_memset((((void *) ds->labels)),((0x01010101UL
*(unsigned char)(0))),((sizeof (struct disklabel *) * gd->
max_nr * gd->max_p)))) : (__builtin_constant_p((sizeof (struct
disklabel *) * gd->max_nr * gd->max_p)) ? __memset_generic
(((((void *) ds->labels))),(((0))),(((sizeof (struct disklabel
*) * gd->max_nr * gd->max_p)))) : __memset_generic((((
void *) ds->labels)),((0)),((sizeof (struct disklabel *) *
gd->max_nr * gd->max_p)))))
935 sizeof (struct disklabel *) * gd->max_nr * gd->max_p)(__builtin_constant_p(0) ? (__builtin_constant_p((sizeof (struct
disklabel *) * gd->max_nr * gd->max_p)) ? __constant_c_and_count_memset
((((void *) ds->labels)),((0x01010101UL*(unsigned char)(0)
)),((sizeof (struct disklabel *) * gd->max_nr * gd->max_p
))) : __constant_c_memset((((void *) ds->labels)),((0x01010101UL
*(unsigned char)(0))),((sizeof (struct disklabel *) * gd->
max_nr * gd->max_p)))) : (__builtin_constant_p((sizeof (struct
disklabel *) * gd->max_nr * gd->max_p)) ? __memset_generic
(((((void *) ds->labels))),(((0))),(((sizeof (struct disklabel
*) * gd->max_nr * gd->max_p)))) : __memset_generic((((
void *) ds->labels)),((0)),((sizeof (struct disklabel *) *
gd->max_nr * gd->max_p)))))
;
936 for (i = 1; i < gd->max_p; i++)
937 {
938 d->inode.i_rdev = *dev | i;
939 if (gd->part[MINOR (d->inode.i_rdev)((d->inode.i_rdev) & ((1<<8) - 1))].nr_sects <= 0
940 || gd->part[MINOR (d->inode.i_rdev)((d->inode.i_rdev) & ((1<<8) - 1))].start_sect < 0)
941 continue;
942 linux_intr_pri = SPL66;
943 d->file.f_flags = 0;
944 d->file.f_mode = O_RDONLY00;
945 if (ds->fops->open && (*ds->fops->open) (&d->inode, &d->file))
946 continue;
947 lp = read_bsd_label (d->inode.i_rdev);
948 if (! lp && gd->part[MINOR (d->inode.i_rdev)((d->inode.i_rdev) & ((1<<8) - 1))].nr_sects > PDLOCATION29)
949 lp = read_vtoc (d->inode.i_rdev);
950 if (ds->fops->release)
951 (*ds->fops->release) (&d->inode, &d->file);
952 if (lp)
953 {
954 if (ds->default_slice == 0)
955 ds->default_slice = i;
956 for (j = 0, p = lp->d_partitions; j < lp->d_npartitions; j++, p++)
957 {
958 if (p->p_offset < 0 || p->p_size <= 0)
959 continue;
960
961 /* Sanity check. */
962 if (p->p_size > gd->part[MINOR (d->inode.i_rdev)((d->inode.i_rdev) & ((1<<8) - 1))].nr_sects)
963 p->p_size = gd->part[MINOR (d->inode.i_rdev)((d->inode.i_rdev) & ((1<<8) - 1))].nr_sects;
964 }
965 }
966 ds->labels[MINOR (d->inode.i_rdev)((d->inode.i_rdev) & ((1<<8) - 1))] = lp;
967 }
968
969check:
970 if (*part >= 0 && slice == 0)
971 slice = ds->default_slice;
972 if (*part >= 0 && slice == 0)
973 return D_NO_SUCH_DEVICE2502;
974 *dev = MKDEV (MAJOR (*dev), MINOR (*dev) | slice)(((((*dev) >> 8)) << 8) | (((*dev) & ((1<<
8) - 1)) | slice))
;
975 if (slice >= gd->max_p
976 || gd->part[MINOR (*dev)((*dev) & ((1<<8) - 1))].start_sect < 0
977 || gd->part[MINOR (*dev)((*dev) & ((1<<8) - 1))].nr_sects <= 0)
978 return D_NO_SUCH_DEVICE2502;
979 if (*part >= 0)
980 {
981 lp = ds->labels[MINOR (*dev)((*dev) & ((1<<8) - 1))];
982 if (! lp
983 || *part >= lp->d_npartitions
984 || lp->d_partitions[*part].p_offset < 0
985 || lp->d_partitions[*part].p_size <= 0)
986 return D_NO_SUCH_DEVICE2502;
987 }
988 return 0;
989}
990
991#define DECL_DATAstruct temp_data td struct temp_data td
992#define INIT_DATA(){ ((&td.pages)->next = (&td.pages)->prev = &
td.pages); td.inode.i_rdev = bd->dev; td.file.f_mode = bd->
mode; td.file.f_flags = bd->flags; (active_threads[(0)])->
pcb->data = &td; }
\
993{ \
994 queue_init (&td.pages)((&td.pages)->next = (&td.pages)->prev = &td
.pages)
; \
995 td.inode.i_rdev = bd->dev; \
996 td.file.f_mode = bd->mode; \
997 td.file.f_flags = bd->flags; \
998 current_thread ()(active_threads[(0)])->pcb->data = &td; \
999}
1000
1001static io_return_t
1002device_open (ipc_port_t reply_port, mach_msg_type_name_t reply_port_type,
1003 dev_mode_t mode, char *name, device_t *devp)
1004{
1005 int part, slice, err;
1006 unsigned major, minor;
1007 kdev_t dev;
1008 ipc_port_t notify;
1009 struct block_data *bd = NULL((void *) 0), *bdp;
1010 struct device_struct *ds;
1011 struct gendisk *gd;
1012 struct name_map *np;
1013 DECL_DATAstruct temp_data td;
1014
1015 np = find_name (name, &slice, &part);
1016 if (! np)
1017 return D_NO_SUCH_DEVICE2502;
1018 major = np->major;
1019 ds = &blkdevs[major];
1020
1021 /* Check that driver exists. */
1022 if (! ds->fops)
1023 return D_NO_SUCH_DEVICE2502;
1024
1025 /* Wait for any other open/close calls to finish. */
1026 ds = &blkdevs[major];
1027 while (ds->busy)
1028 {
1029 ds->want = 1;
1030 assert_wait ((event_t) ds, FALSE((boolean_t) 0));
1031 schedule ();
1032 }
1033 ds->busy = 1;
1034
1035 /* Compute minor number. */
1036 if (! ds->gd)
1037 {
1038 for (gd = gendisk_head; gd && gd->major != major; gd = gd->next)
1039 ;
1040 ds->gd = gd;
1041 }
1042 minor = np->unit;
1043 gd = ds->gd;
1044 if (gd)
1045 minor <<= gd->minor_shift;
1046 dev = MKDEV (major, minor)(((major) << 8) | (minor));
1047
1048 queue_init (&td.pages)((&td.pages)->next = (&td.pages)->prev = &td
.pages)
;
1049 current_thread ()(active_threads[(0)])->pcb->data = &td;
1050
1051 /* Check partition. */
1052 err = init_partition (np, &dev, ds, slice, &part);
1053 if (err)
1054 goto out;
1055
1056 /* Initialize file structure. */
1057 switch (mode & (D_READ0x1|D_WRITE0x2))
1058 {
1059 case D_WRITE0x2:
1060 td.file.f_mode = O_WRONLY01;
1061 break;
1062
1063 case D_READ0x1|D_WRITE0x2:
1064 td.file.f_mode = O_RDWR02;
1065 break;
1066
1067 default:
1068 td.file.f_mode = O_RDONLY00;
1069 break;
1070 }
1071 td.file.f_flags = (mode & D_NODELAY0x4) ? O_NDELAY04000 : 0;
1072
1073 /* Check if the device is currently open. */
1074 for (bdp = open_list; bdp; bdp = bdp->next)
1075 if (bdp->dev == dev
1076 && bdp->part == part
1077 && bdp->mode == td.file.f_mode
1078 && bdp->flags == td.file.f_flags)
1079 {
1080 bd = bdp;
1081 goto out;
1082 }
1083
1084 /* Open the device. */
1085 if (ds->fops->open)
1086 {
1087 td.inode.i_rdev = dev;
1088 linux_intr_pri = SPL66;
1089 err = (*ds->fops->open) (&td.inode, &td.file);
1090 if (err)
1091 {
1092 err = linux_to_mach_error (err);
1093 goto out;
1094 }
1095 }
1096
1097 /* Allocate and initialize device data. */
1098 bd = (struct block_data *) kalloc (sizeof (struct block_data));
1099 if (! bd)
1100 {
1101 err = D_NO_MEMORY2508;
1102 goto bad;
1103 }
1104 bd->want = 0;
1105 bd->open_count = 0;
1106 bd->iocount = 0;
1107 bd->part = part;
1108 bd->ds = ds;
1109 bd->device.emul_data = bd;
1110 bd->device.emul_ops = &linux_block_emulation_ops;
1111 bd->dev = dev;
1112 bd->mode = td.file.f_mode;
1113 bd->flags = td.file.f_flags;
1114 bd->port = ipc_port_alloc_kernel ()ipc_port_alloc_special(ipc_space_kernel);
1115 if (bd->port == IP_NULL((ipc_port_t) ((ipc_object_t) 0)))
1116 {
1117 err = KERN_RESOURCE_SHORTAGE6;
1118 goto bad;
1119 }
1120 ipc_kobject_set (bd->port, (ipc_kobject_t) &bd->device, IKOT_DEVICE10);
1121 notify = ipc_port_make_sonce (bd->port);
1122 ip_lock (bd->port);
1123 ipc_port_nsrequest (bd->port, 1, notify, &notify);
1124 assert (notify == IP_NULL)({ if (!(notify == ((ipc_port_t) ((ipc_object_t) 0)))) Assert
("notify == IP_NULL", "../linux/dev/glue/block.c", 1124); })
;
1125 goto out;
1126
1127bad:
1128 if (ds->fops->release)
1129 (*ds->fops->release) (&td.inode, &td.file);
1130
1131out:
1132 ds->busy = 0;
1133 if (ds->want)
1134 {
1135 ds->want = 0;
1136 thread_wakeup ((event_t) ds)thread_wakeup_prim(((event_t) ds), ((boolean_t) 0), 0);
1137 }
1138
1139 if (bd && bd->open_count > 0)
1140 {
1141 if (err)
1142 *devp = NULL((void *) 0);
1143 else
1144 {
1145 *devp = &bd->device;
1146 bd->open_count++;
1147 }
1148 return err;
1149 }
1150
1151 if (err)
1152 {
1153 if (bd)
1154 {
1155 if (bd->port != IP_NULL((ipc_port_t) ((ipc_object_t) 0)))
1156 {
1157 ipc_kobject_set (bd->port, IKO_NULL((ipc_kobject_t) 0), IKOT_NONE0);
1158 ipc_port_dealloc_kernel (bd->port)ipc_port_dealloc_special((bd->port), ipc_space_kernel);
1159 *devp = IP_NULL((ipc_port_t) ((ipc_object_t) 0));
1160 }
1161 kfree ((vm_offset_t) bd, sizeof (struct block_data));
1162 bd = NULL((void *) 0);
1163 }
1164 }
1165 else
1166 {
1167 bd->open_count = 1;
1168 bd->next = open_list;
1169 open_list = bd;
1170 *devp = &bd -> device;
1171 }
1172
1173 if (!IP_VALID (reply_port)(((&(reply_port)->ip_target.ipt_object) != ((ipc_object_t
) 0)) && ((&(reply_port)->ip_target.ipt_object
) != ((ipc_object_t) -1)))
&& ! err)
1174 device_close (bd);
1175 return err;
1176}
1177
1178static io_return_t
1179device_close_forced (void *d, int force)
1180{
1181 struct block_data *bd = d, *bdp, **prev;
1182 struct device_struct *ds = bd->ds;
1183 DECL_DATAstruct temp_data td;
1184
1185 INIT_DATA (){ ((&td.pages)->next = (&td.pages)->prev = &
td.pages); td.inode.i_rdev = bd->dev; td.file.f_mode = bd->
mode; td.file.f_flags = bd->flags; (active_threads[(0)])->
pcb->data = &td; }
;
1186
1187 /* Wait for any other open/close to complete. */
1188 while (ds->busy)
1189 {
1190 ds->want = 1;
1191 assert_wait ((event_t) ds, FALSE((boolean_t) 0));
1192 schedule ();
1193 }
1194 ds->busy = 1;
1195
1196 if (force || --bd->open_count == 0)
1197 {
1198 /* Wait for pending I/O to complete. */
1199 while (bd->iocount > 0)
1200 {
1201 bd->want = 1;
1202 assert_wait ((event_t) bd, FALSE((boolean_t) 0));
1203 schedule ();
1204 }
1205
1206 /* Remove device from open list. */
1207 prev = &open_list;
1208 bdp = open_list;
1209 while (bdp)
1210 {
1211 if (bdp == bd)
1212 {
1213 *prev = bdp->next;
1214 break;
1215 }
1216 prev = &bdp->next;
1217 bdp = bdp->next;
1218 }
1219
1220 assert (bdp == bd)({ if (!(bdp == bd)) Assert("bdp == bd", "../linux/dev/glue/block.c"
, 1220); })
;
1221
1222 if (ds->fops->release)
1223 (*ds->fops->release) (&td.inode, &td.file);
1224
1225 ipc_kobject_set (bd->port, IKO_NULL((ipc_kobject_t) 0), IKOT_NONE0);
1226 ipc_port_dealloc_kernel (bd->port)ipc_port_dealloc_special((bd->port), ipc_space_kernel);
1227 kfree ((vm_offset_t) bd, sizeof (struct block_data));
1228 }
1229
1230 ds->busy = 0;
1231 if (ds->want)
1232 {
1233 ds->want = 0;
1234 thread_wakeup ((event_t) ds)thread_wakeup_prim(((event_t) ds), ((boolean_t) 0), 0);
1235 }
1236 return D_SUCCESS0;
1237}
1238
1239static io_return_t
1240device_close (void *d)
1241{
1242 return device_close_forced (d, 0);
1243}
1244
1245
1246#define MAX_COPY(64 << 12) (VM_MAP_COPY_PAGE_LIST_MAX64 << PAGE_SHIFT12)
1247
1248/* Check block BN and size COUNT for I/O validity
1249 to from device BD. Set *OFF to the byte offset
1250 where I/O is to begin and return the size of transfer. */
1251static int
1252check_limit (struct block_data *bd, loff_t *off, long bn, int count)
1253{
1254 int major, minor;
1255 long maxsz, sz;
1256 struct disklabel *lp = NULL((void *) 0);
1257
1258 if (count <= 0)
1259 return count;
1260
1261 major = MAJOR (bd->dev)((bd->dev) >> 8);
1262 minor = MINOR (bd->dev)((bd->dev) & ((1<<8) - 1));
1263
1264 if (bd->ds->gd)
1265 {
1266 if (bd->part >= 0)
1267 {
1268 assert (bd->ds->labels)({ if (!(bd->ds->labels)) Assert("bd->ds->labels"
, "../linux/dev/glue/block.c", 1268); })
;
1269 assert (bd->ds->labels[minor])({ if (!(bd->ds->labels[minor])) Assert("bd->ds->labels[minor]"
, "../linux/dev/glue/block.c", 1269); })
;
1270 lp = bd->ds->labels[minor];
1271 maxsz = lp->d_partitions[bd->part].p_size;
1272 }
1273 else
1274 maxsz = bd->ds->gd->part[minor].nr_sects;
1275 }
1276 else
1277 {
1278 assert (blk_size[major])({ if (!(blk_size[major])) Assert("blk_size[major]", "../linux/dev/glue/block.c"
, 1278); })
;
1279 maxsz = blk_size[major][minor] << (BLOCK_SIZE_BITS10 - 9);
1280 }
1281 assert (maxsz > 0)({ if (!(maxsz > 0)) Assert("maxsz > 0", "../linux/dev/glue/block.c"
, 1281); })
;
1282 sz = maxsz - bn;
1283 if (sz <= 0)
1284 return sz;
1285 if (sz < ((count + 511) >> 9))
1286 count = sz << 9;
1287 if (lp)
1288 bn += (lp->d_partitions[bd->part].p_offset
1289 - bd->ds->gd->part[minor].start_sect);
1290 *off = (loff_t) bn << 9;
1291 bd->iocount++;
1292 return count;
1293}
1294
1295static io_return_t
1296device_write (void *d, ipc_port_t reply_port,
1297 mach_msg_type_name_t reply_port_type, dev_mode_t mode,
1298 recnum_t bn, io_buf_ptr_t data, unsigned int orig_count,
1299 int *bytes_written)
1300{
1301 int resid, amt, i;
1302 int count = (int) orig_count;
1303 io_return_t err = 0;
1304 vm_map_copy_t copy;
1305 vm_offset_t addr, uaddr;
1306 vm_size_t len, size;
1307 struct block_data *bd = d;
1308 DECL_DATAstruct temp_data td;
1309
1310 INIT_DATA (){ ((&td.pages)->next = (&td.pages)->prev = &
td.pages); td.inode.i_rdev = bd->dev; td.file.f_mode = bd->
mode; td.file.f_flags = bd->flags; (active_threads[(0)])->
pcb->data = &td; }
;
1311
1312 *bytes_written = 0;
1313
1314 if (bd->mode == O_RDONLY00)
1315 return D_INVALID_OPERATION2505;
1316 if (! bd->ds->fops->write)
1317 return D_READ_ONLY2509;
1318 count = check_limit (bd, &td.file.f_pos, bn, count);
1319 if (count < 0)
1320 return D_INVALID_SIZE2507;
1321 if (count == 0)
1322 {
1323 vm_map_copy_discard (copy);
1324 return 0;
1325 }
1326
1327 resid = count;
1328 copy = (vm_map_copy_t) data;
1329 uaddr = copy->offset;
1330
1331 /* Allocate a kernel buffer. */
1332 size = round_page (uaddr + count)((vm_offset_t)((((vm_offset_t)(uaddr + count)) + ((1 <<
12)-1)) & ~((1 << 12)-1)))
- trunc_page (uaddr)((vm_offset_t)(((vm_offset_t)(uaddr)) & ~((1 << 12)
-1)))
;
1333 if (size > MAX_COPY(64 << 12))
1334 size = MAX_COPY(64 << 12);
1335 addr = vm_map_min (device_io_map)((device_io_map)->hdr.links.start);
1336 err = vm_map_enter (device_io_map, &addr, size, 0, TRUE((boolean_t) 1),
1337 NULL((void *) 0), 0, FALSE((boolean_t) 0), VM_PROT_READ((vm_prot_t) 0x01)|VM_PROT_WRITE((vm_prot_t) 0x02),
1338 VM_PROT_READ((vm_prot_t) 0x01)|VM_PROT_WRITE((vm_prot_t) 0x02), VM_INHERIT_NONE((vm_inherit_t) 2));
1339 if (err)
1340 {
1341 vm_map_copy_discard (copy);
1342 goto out;
1343 }
1344
1345 /* Determine size of I/O this time around. */
1346 len = size - (uaddr & PAGE_MASK((1 << 12)-1));
1347 if (len > resid)
1348 len = resid;
1349
1350 while (1)
1351 {
1352 /* Map user pages. */
1353 for (i = 0; i < copy->cpy_npagesc_u.c_p.npages; i++)
1354 pmap_enter (vm_map_pmap (device_io_map)((device_io_map)->pmap),
1355 addr + (i << PAGE_SHIFT12),
1356 copy->cpy_page_listc_u.c_p.page_list[i]->phys_addr,
1357 VM_PROT_READ((vm_prot_t) 0x01)|VM_PROT_WRITE((vm_prot_t) 0x02), TRUE((boolean_t) 1));
1358
1359 /* Do the write. */
1360 amt = (*bd->ds->fops->write) (&td.inode, &td.file,
1361 (char *) addr + (uaddr & PAGE_MASK((1 << 12)-1)), len);
1362
1363 /* Unmap pages and deallocate copy. */
1364 pmap_remove (vm_map_pmap (device_io_map)((device_io_map)->pmap),
1365 addr, addr + (copy->cpy_npagesc_u.c_p.npages << PAGE_SHIFT12));
1366 vm_map_copy_discard (copy);
1367
1368 /* Check result of write. */
1369 if (amt > 0)
1370 {
1371 resid -= amt;
1372 if (resid == 0)
1373 break;
1374 uaddr += amt;
1375 }
1376 else
1377 {
1378 if (amt < 0)
1379 err = linux_to_mach_error (amt);
1380 break;
1381 }
1382
1383 /* Determine size of I/O this time around and copy in pages. */
1384 len = round_page (uaddr + resid)((vm_offset_t)((((vm_offset_t)(uaddr + resid)) + ((1 <<
12)-1)) & ~((1 << 12)-1)))
- trunc_page (uaddr)((vm_offset_t)(((vm_offset_t)(uaddr)) & ~((1 << 12)
-1)))
;
1385 if (len > MAX_COPY(64 << 12))
1386 len = MAX_COPY(64 << 12);
1387 len -= uaddr & PAGE_MASK((1 << 12)-1);
1388 if (len > resid)
1389 len = resid;
1390 err = vm_map_copyin_page_list (current_map ()(((active_threads[(0)])->task)->map), uaddr, len,
1391 FALSE((boolean_t) 0), FALSE((boolean_t) 0), &copy, FALSE((boolean_t) 0));
1392 if (err)
1393 break;
1394 }
1395
1396 /* Delete kernel buffer. */
1397 vm_map_remove (device_io_map, addr, addr + size);
1398
1399out:
1400 if (--bd->iocount == 0 && bd->want)
1401 {
1402 bd->want = 0;
1403 thread_wakeup ((event_t) bd)thread_wakeup_prim(((event_t) bd), ((boolean_t) 0), 0);
1404 }
1405 if (IP_VALID (reply_port)(((&(reply_port)->ip_target.ipt_object) != ((ipc_object_t
) 0)) && ((&(reply_port)->ip_target.ipt_object
) != ((ipc_object_t) -1)))
)
1406 ds_device_write_reply (reply_port, reply_port_type, err, count - resid);
1407 return MIG_NO_REPLY-305;
1408}
1409
1410static io_return_t
1411device_read (void *d, ipc_port_t reply_port,
1412 mach_msg_type_name_t reply_port_type, dev_mode_t mode,
1413 recnum_t bn, int count, io_buf_ptr_t *data,
1414 unsigned *bytes_read)
1415{
1416 boolean_t dirty;
1417 int resid, amt;
1418 io_return_t err = 0;
1419 queue_head_t pages;
1420 vm_map_copy_t copy;
1421 vm_offset_t addr, offset, alloc_offset, o;
1422 vm_object_t object;
1423 vm_page_t m;
1424 vm_size_t len, size;
1425 struct block_data *bd = d;
1426 DECL_DATAstruct temp_data td;
1427
1428 INIT_DATA (){ ((&td.pages)->next = (&td.pages)->prev = &
td.pages); td.inode.i_rdev = bd->dev; td.file.f_mode = bd->
mode; td.file.f_flags = bd->flags; (active_threads[(0)])->
pcb->data = &td; }
;
1429
1430 *data = 0;
1431 *bytes_read = 0;
1432
1433 if (! bd->ds->fops->read)
1434 return D_INVALID_OPERATION2505;
1435 count = check_limit (bd, &td.file.f_pos, bn, count);
1436 if (count < 0)
1437 return D_INVALID_SIZE2507;
1438 if (count == 0)
1439 return 0;
1440
1441 /* Allocate an object to hold the data. */
1442 size = round_page (count)((vm_offset_t)((((vm_offset_t)(count)) + ((1 << 12)-1))
& ~((1 << 12)-1)))
;
1443 object = vm_object_allocate (size);
1444 if (! object)
1445 {
1446 err = D_NO_MEMORY2508;
1447 goto out;
1448 }
1449 alloc_offset = offset = 0;
1450 resid = count;
1451
1452 /* Allocate a kernel buffer. */
1453 addr = vm_map_min (device_io_map)((device_io_map)->hdr.links.start);
1454 if (size > MAX_COPY(64 << 12))
1455 size = MAX_COPY(64 << 12);
1456 err = vm_map_enter (device_io_map, &addr, size, 0, TRUE((boolean_t) 1), NULL((void *) 0),
1457 0, FALSE((boolean_t) 0), VM_PROT_READ((vm_prot_t) 0x01)|VM_PROT_WRITE((vm_prot_t) 0x02),
1458 VM_PROT_READ((vm_prot_t) 0x01)|VM_PROT_WRITE((vm_prot_t) 0x02), VM_INHERIT_NONE((vm_inherit_t) 2));
1459 if (err)
1460 goto out;
1461
1462 queue_init (&pages)((&pages)->next = (&pages)->prev = &pages);
1463
1464 while (resid)
1465 {
1466 /* Determine size of I/O this time around. */
1467 len = round_page (offset + resid)((vm_offset_t)((((vm_offset_t)(offset + resid)) + ((1 <<
12)-1)) & ~((1 << 12)-1)))
- trunc_page (offset)((vm_offset_t)(((vm_offset_t)(offset)) & ~((1 << 12
)-1)))
;
1468 if (len > MAX_COPY(64 << 12))
1469 len = MAX_COPY(64 << 12);
1470
1471 /* Map any pages left from previous operation. */
1472 o = trunc_page (offset)((vm_offset_t)(((vm_offset_t)(offset)) & ~((1 << 12
)-1)))
;
1473 queue_iterate (&pages, m, vm_page_t, pageq)for ((m) = (vm_page_t) ((&pages)->next); !(((&pages
)) == ((queue_entry_t)(m))); (m) = (vm_page_t) ((&(m)->
pageq)->next))
1474 {
1475 pmap_enter (vm_map_pmap (device_io_map)((device_io_map)->pmap),
1476 addr + o - trunc_page (offset)((vm_offset_t)(((vm_offset_t)(offset)) & ~((1 << 12
)-1)))
,
1477 m->phys_addr, VM_PROT_READ((vm_prot_t) 0x01)|VM_PROT_WRITE((vm_prot_t) 0x02), TRUE((boolean_t) 1));
1478 o += PAGE_SIZE(1 << 12);
1479 }
1480 assert (o == alloc_offset)({ if (!(o == alloc_offset)) Assert("o == alloc_offset", "../linux/dev/glue/block.c"
, 1480); })
;
1481
1482 /* Allocate and map pages. */
1483 while (alloc_offset < trunc_page (offset)((vm_offset_t)(((vm_offset_t)(offset)) & ~((1 << 12
)-1)))
+ len)
1484 {
1485 while ((m = vm_page_grab (FALSE((boolean_t) 0))) == 0)
1486 VM_PAGE_WAIT (0)vm_page_wait(0);
1487 assert (! m->active && ! m->inactive)({ if (!(! m->active && ! m->inactive)) Assert(
"! m->active && ! m->inactive", "../linux/dev/glue/block.c"
, 1487); })
;
1488 m->busy = TRUE((boolean_t) 1);
1489 queue_enter (&pages, m, vm_page_t, pageq){ queue_entry_t prev; prev = (&pages)->prev; if ((&
pages) == prev) { (&pages)->next = (queue_entry_t) (m)
; } else { ((vm_page_t)prev)->pageq.next = (queue_entry_t)
(m); } (m)->pageq.prev = prev; (m)->pageq.next = &pages
; (&pages)->prev = (queue_entry_t) m; }
;
1490 pmap_enter (vm_map_pmap (device_io_map)((device_io_map)->pmap),
1491 addr + alloc_offset - trunc_page (offset)((vm_offset_t)(((vm_offset_t)(offset)) & ~((1 << 12
)-1)))
,
1492 m->phys_addr, VM_PROT_READ((vm_prot_t) 0x01)|VM_PROT_WRITE((vm_prot_t) 0x02), TRUE((boolean_t) 1));
1493 alloc_offset += PAGE_SIZE(1 << 12);
1494 }
1495
1496 /* Do the read. */
1497 amt = len - (offset & PAGE_MASK((1 << 12)-1));
1498 if (amt > resid)
1499 amt = resid;
1500 amt = (*bd->ds->fops->read) (&td.inode, &td.file,
1501 (char *) addr + (offset & PAGE_MASK((1 << 12)-1)), amt);
1502
1503 /* Compute number of pages to insert in object. */
1504 o = trunc_page (offset)((vm_offset_t)(((vm_offset_t)(offset)) & ~((1 << 12
)-1)))
;
1505 if (amt > 0)
1506 {
1507 dirty = TRUE((boolean_t) 1);
1508 resid -= amt;
1509 if (resid == 0)
1510 {
1511 /* Zero any unused space. */
1512 if (offset + amt < o + len)
1513 memset ((void *) (addr + offset - o + amt),(__builtin_constant_p(0) ? (__builtin_constant_p((o + len - offset
- amt)) ? __constant_c_and_count_memset((((void *) (addr + offset
- o + amt))),((0x01010101UL*(unsigned char)(0))),((o + len -
offset - amt))) : __constant_c_memset((((void *) (addr + offset
- o + amt))),((0x01010101UL*(unsigned char)(0))),((o + len -
offset - amt)))) : (__builtin_constant_p((o + len - offset -
amt)) ? __memset_generic(((((void *) (addr + offset - o + amt
)))),(((0))),(((o + len - offset - amt)))) : __memset_generic
((((void *) (addr + offset - o + amt))),((0)),((o + len - offset
- amt)))))
1514 0, o + len - offset - amt)(__builtin_constant_p(0) ? (__builtin_constant_p((o + len - offset
- amt)) ? __constant_c_and_count_memset((((void *) (addr + offset
- o + amt))),((0x01010101UL*(unsigned char)(0))),((o + len -
offset - amt))) : __constant_c_memset((((void *) (addr + offset
- o + amt))),((0x01010101UL*(unsigned char)(0))),((o + len -
offset - amt)))) : (__builtin_constant_p((o + len - offset -
amt)) ? __memset_generic(((((void *) (addr + offset - o + amt
)))),(((0))),(((o + len - offset - amt)))) : __memset_generic
((((void *) (addr + offset - o + amt))),((0)),((o + len - offset
- amt)))))
;
1515 offset = o + len;
1516 }
1517 else
1518 offset += amt;
1519 }
1520 else
1521 {
1522 dirty = FALSE((boolean_t) 0);
1523 offset = o + len;
1524 }
1525
1526 /* Unmap pages and add them to the object. */
1527 pmap_remove (vm_map_pmap (device_io_map)((device_io_map)->pmap), addr, addr + len);
1528 vm_object_lock (object);
1529 while (o < trunc_page (offset)((vm_offset_t)(((vm_offset_t)(offset)) & ~((1 << 12
)-1)))
)
1530 {
1531 m = (vm_page_t) queue_first (&pages)((&pages)->next);
1532 assert (! queue_end (&pages, (queue_entry_t) m))({ if (!(! ((&pages) == ((queue_entry_t) m)))) Assert("! queue_end (&pages, (queue_entry_t) m)"
, "../linux/dev/glue/block.c", 1532); })
;
1533 queue_remove (&pages, m, vm_page_t, pageq){ queue_entry_t next, prev; next = (m)->pageq.next; prev =
(m)->pageq.prev; if ((&pages) == next) (&pages)->
prev = prev; else ((vm_page_t)next)->pageq.prev = prev; if
((&pages) == prev) (&pages)->next = next; else ((
vm_page_t)prev)->pageq.next = next; }
;
1534 assert (m->busy)({ if (!(m->busy)) Assert("m->busy", "../linux/dev/glue/block.c"
, 1534); })
;
1535 vm_page_lock_queues ();
1536 if (dirty)
1537 {
1538 PAGE_WAKEUP_DONE (m)({ (m)->busy = ((boolean_t) 0); if ((m)->wanted) { (m)->
wanted = ((boolean_t) 0); thread_wakeup_prim((((event_t) m)),
((boolean_t) 0), 0); } })
;
1539 m->dirty = TRUE((boolean_t) 1);
1540 vm_page_insert (m, object, o);
1541 }
1542 else
1543 vm_page_free (m);
1544 vm_page_unlock_queues ()((void)(&vm_page_queue_lock));
1545 o += PAGE_SIZE(1 << 12);
1546 }
1547 vm_object_unlock (object)((void)(&(object)->Lock));
1548 if (amt <= 0)
1549 {
1550 if (amt < 0)
1551 err = linux_to_mach_error (amt);
1552 break;
1553 }
1554 }
1555
1556 /* Delete kernel buffer. */
1557 vm_map_remove (device_io_map, addr, addr + size);
1558
1559 assert (queue_empty (&pages))({ if (!((((&pages)) == (((&pages)->next))))) Assert
("queue_empty (&pages)", "../linux/dev/glue/block.c", 1559
); })
;
1560
1561out:
1562 if (! err)
1563 err = vm_map_copyin_object (object, 0, round_page (count)((vm_offset_t)((((vm_offset_t)(count)) + ((1 << 12)-1))
& ~((1 << 12)-1)))
, &copy);
1564 if (! err)
1565 {
1566 *data = (io_buf_ptr_t) copy;
1567 *bytes_read = count - resid;
1568 }
1569 else
1570 vm_object_deallocate (object);
1571 if (--bd->iocount == 0 && bd->want)
1572 {
1573 bd->want = 0;
1574 thread_wakeup ((event_t) bd)thread_wakeup_prim(((event_t) bd), ((boolean_t) 0), 0);
1575 }
1576 return err;
1577}
1578
1579static io_return_t
1580device_get_status (void *d, dev_flavor_t flavor, dev_status_t status,
1581 mach_msg_type_number_t *status_count)
1582{
1583 struct block_data *bd = d;
1584
1585 switch (flavor)
1586 {
1587 case DEV_GET_SIZE0:
1588 if (disk_major (MAJOR (bd->dev)((bd->dev) >> 8)))
1589 {
1590 assert (bd->ds->gd)({ if (!(bd->ds->gd)) Assert("bd->ds->gd", "../linux/dev/glue/block.c"
, 1590); })
;
1591
1592 if (bd->part >= 0)
1593 {
1594 struct disklabel *lp;
1595
1596 assert (bd->ds->labels)({ if (!(bd->ds->labels)) Assert("bd->ds->labels"
, "../linux/dev/glue/block.c", 1596); })
;
1597 lp = bd->ds->labels[MINOR (bd->dev)((bd->dev) & ((1<<8) - 1))];
1598 assert (lp)({ if (!(lp)) Assert("lp", "../linux/dev/glue/block.c", 1598)
; })
;
1599 (status[DEV_GET_SIZE_DEVICE_SIZE0]
1600 = lp->d_partitions[bd->part].p_size << 9);
1601 }
1602 else
1603 (status[DEV_GET_SIZE_DEVICE_SIZE0]
1604 = bd->ds->gd->part[MINOR (bd->dev)((bd->dev) & ((1<<8) - 1))].nr_sects << 9);
1605 }
1606 else
1607 {
1608 assert (blk_size[MAJOR (bd->dev)])({ if (!(blk_size[((bd->dev) >> 8)])) Assert("blk_size[MAJOR (bd->dev)]"
, "../linux/dev/glue/block.c", 1608); })
;
1609 (status[DEV_GET_SIZE_DEVICE_SIZE0]
1610 = (blk_size[MAJOR (bd->dev)((bd->dev) >> 8)][MINOR (bd->dev)((bd->dev) & ((1<<8) - 1))]
1611 << BLOCK_SIZE_BITS10));
1612 }
1613 /* It would be nice to return the block size as reported by
1614 the driver, but a lot of user level code assumes the sector
1615 size to be 512. */
1616 status[DEV_GET_SIZE_RECORD_SIZE1] = 512;
1617 /* Always return DEV_GET_SIZE_COUNT. This is what all native
1618 Mach drivers do, and makes it possible to detect the absence
1619 of the call by setting it to a different value on input. MiG
1620 makes sure that we will never return more integers than the
1621 user asked for. */
1622 *status_count = DEV_GET_SIZE_COUNT2;
1623 break;
1624
1625 case DEV_GET_RECORDS1:
1626 if (disk_major (MAJOR (bd->dev)((bd->dev) >> 8)))
1627 {
1628 assert (bd->ds->gd)({ if (!(bd->ds->gd)) Assert("bd->ds->gd", "../linux/dev/glue/block.c"
, 1628); })
;
1629
1630 if (bd->part >= 0)
1631 {
1632 struct disklabel *lp;
1633
1634 assert (bd->ds->labels)({ if (!(bd->ds->labels)) Assert("bd->ds->labels"
, "../linux/dev/glue/block.c", 1634); })
;
1635 lp = bd->ds->labels[MINOR (bd->dev)((bd->dev) & ((1<<8) - 1))];
1636 assert (lp)({ if (!(lp)) Assert("lp", "../linux/dev/glue/block.c", 1636)
; })
;
1637 (status[DEV_GET_RECORDS_DEVICE_RECORDS0]
1638 = lp->d_partitions[bd->part].p_size);
1639 }
1640 else
1641 (status[DEV_GET_RECORDS_DEVICE_RECORDS0]
1642 = bd->ds->gd->part[MINOR (bd->dev)((bd->dev) & ((1<<8) - 1))].nr_sects);
1643 }
1644 else
1645 {
1646 assert (blk_size[MAJOR (bd->dev)])({ if (!(blk_size[((bd->dev) >> 8)])) Assert("blk_size[MAJOR (bd->dev)]"
, "../linux/dev/glue/block.c", 1646); })
;
1647 status[DEV_GET_RECORDS_DEVICE_RECORDS0]
1648 = (blk_size[MAJOR (bd->dev)((bd->dev) >> 8)][MINOR (bd->dev)((bd->dev) & ((1<<8) - 1))]
1649 << (BLOCK_SIZE_BITS10 - 9));
1650 }
1651 /* It would be nice to return the block size as reported by
1652 the driver, but a lot of user level code assumes the sector
1653 size to be 512. */
1654 status[DEV_GET_RECORDS_RECORD_SIZE1] = 512;
1655 /* Always return DEV_GET_RECORDS_COUNT. This is what all native
1656 Mach drivers do, and makes it possible to detect the absence
1657 of the call by setting it to a different value on input. MiG
1658 makes sure that we will never return more integers than the
1659 user asked for. */
1660 *status_count = DEV_GET_RECORDS_COUNT2;
1661 break;
1662
1663 case V_GETPARMS(((2U) << (((0 +8)+8)+14)) | ((('v')) << (0 +8)) |
(((4)) << 0) | ((sizeof(struct disk_parms)) << (
(0 +8)+8)))
:
1664 if (*status_count < (sizeof (struct disk_parms) / sizeof (int)))
1665 return D_INVALID_OPERATION2505;
1666 else
1667 {
1668 struct disk_parms *dp = status;
1669 struct hd_geometry hg;
1670 DECL_DATAstruct temp_data td;
1671
1672 INIT_DATA(){ ((&td.pages)->next = (&td.pages)->prev = &
td.pages); td.inode.i_rdev = bd->dev; td.file.f_mode = bd->
mode; td.file.f_flags = bd->flags; (active_threads[(0)])->
pcb->data = &td; }
;
1673
1674 if ((*bd->ds->fops->ioctl) (&td.inode, &td.file,
1675 HDIO_GETGEO0x0301, (unsigned long)&hg))
1676 return D_INVALID_OPERATION2505;
1677
1678 dp->dp_type = DPT_WINI1; /* XXX: It may be a floppy... */
1679 dp->dp_heads = hg.heads;
1680 dp->dp_cyls = hg.cylinders;
1681 dp->dp_sectors = hg.sectors;
1682 dp->dp_dosheads = hg.heads;
1683 dp->dp_doscyls = hg.cylinders;
1684 dp->dp_dossectors = hg.sectors;
1685 dp->dp_secsiz = 512; /* XXX */
1686 dp->dp_ptag = 0;
1687 dp->dp_pflag = 0;
1688
1689 /* XXX */
1690 dp->dp_pstartsec = -1;
1691 dp->dp_pnumsec = -1;
1692
1693 *status_count = sizeof (struct disk_parms) / sizeof (int);
1694 }
1695
1696 break;
1697
1698 default:
1699 return D_INVALID_OPERATION2505;
1700 }
1701
1702 return D_SUCCESS0;
1703}
1704
1705static io_return_t
1706device_set_status (void *d, dev_flavor_t flavor, dev_status_t status,
1707 mach_msg_type_number_t *status_count)
1708{
1709 struct block_data *bd = d;
1710
1711 switch (flavor)
1712 {
1713 case BLKRRPART(((0U) << (((0 +8)+8)+14)) | (((0x12)) << (0 +8))
| (((95)) << 0) | ((0) << ((0 +8)+8)))
:
1714 {
1715 DECL_DATAstruct temp_data td;
1716 INIT_DATA(){ ((&td.pages)->next = (&td.pages)->prev = &
td.pages); td.inode.i_rdev = bd->dev; td.file.f_mode = bd->
mode; td.file.f_flags = bd->flags; (active_threads[(0)])->
pcb->data = &td; }
;
1717 return (*bd->ds->fops->ioctl) (&td.inode, &td.file, flavor, 0);
1718 }
1719 }
1720
1721 return D_INVALID_OPERATION2505;
1722}
1723
1724
1725static void
1726device_no_senders (mach_no_senders_notification_t *ns)
1727{
1728 device_t dev;
1729
1730 dev = dev_port_lookup((ipc_port_t) ns->not_header.msgh_remote_port);
1731 assert(dev)({ if (!(dev)) Assert("dev", "../linux/dev/glue/block.c", 1731
); })
;
1732 device_close_forced (dev->emul_data, 1);
1733}
1734
1735struct device_emulation_ops linux_block_emulation_ops =
1736{
1737 NULL((void *) 0),
1738 NULL((void *) 0),
1739 dev_to_port,
1740 device_open,
1741 device_close,
1742 device_write,
1743 NULL((void *) 0),
1744 device_read,
1745 NULL((void *) 0),
1746 device_set_status,
1747 device_get_status,
1748 NULL((void *) 0),
1749 NULL((void *) 0),
1750 device_no_senders,
1751 NULL((void *) 0),
1752 NULL((void *) 0)
1753};