File: | obj-scan-build/../linux/dev/glue/block.c |
Location: | line 563, column 1 |
Description: | Address of stack memory associated with local variable 'bhead' is still referred to by the global variable 'req' upon returning to the caller. This will be a dangling reference |
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. */ | |||
87 | DECLARE_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. */ | |||
95 | struct 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. */ | |||
105 | struct 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. */ | |||
117 | struct 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. */ | |||
126 | static struct device_struct blkdevs[MAX_BLKDEV128]; | |||
127 | ||||
128 | /* Driver request function table. */ | |||
129 | struct 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 | */ | |||
164 | int *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 | */ | |||
173 | int *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 | */ | |||
187 | int *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. */ | |||
191 | int 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. */ | |||
195 | struct wait_queue *wait_for_request = NULL((void *) 0); | |||
196 | ||||
197 | /* Initialize block drivers. */ | |||
198 | int | |||
199 | blk_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. */ | |||
213 | static inlineinline __attribute__((always_inline)) int | |||
214 | disk_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. */ | |||
227 | int | |||
228 | register_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 | ||||
243 | out: | |||
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. */ | |||
256 | int | |||
257 | unregister_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 | ||||
274 | void | |||
275 | set_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. */ | |||
295 | static void * | |||
296 | alloc_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. */ | |||
316 | static void | |||
317 | free_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. */ | |||
344 | struct buffer_head * | |||
345 | getblk (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. */ | |||
370 | void | |||
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. */ | |||
379 | struct buffer_head * | |||
380 | bread (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. */ | |||
400 | static void | |||
401 | get_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. */ | |||
414 | static inlineinline __attribute__((always_inline)) void | |||
415 | enqueue_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. */ | |||
446 | void | |||
447 | ll_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); | |||
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. */ | |||
500 | static int | |||
501 | rdwr_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; | |||
560 | out: | |||
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. */ | |||
574 | static int | |||
575 | rdwr_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++) | |||
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) | |||
626 | { | |||
627 | ll_rw_block (rw, i, bhp, 0); | |||
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. */ | |||
652 | static int | |||
653 | do_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)) | |||
659 | err = rdwr_partial (rw, dev, off, &buf, &resid, bshift); | |||
660 | while (resid >= bsize && ! err) | |||
661 | err = rdwr_full (rw, dev, off, &buf, &resid, bshift); | |||
662 | if (! err && resid) | |||
663 | err = rdwr_partial (rw, dev, off, &buf, &resid, bshift); | |||
664 | return err ? err : count - resid; | |||
665 | } | |||
666 | ||||
667 | int | |||
668 | block_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 | ||||
674 | int | |||
675 | block_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); | |||
| ||||
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 | */ | |||
689 | int | |||
690 | check_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. */ | |||
714 | static 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. */ | |||
758 | struct 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. */ | |||
776 | static struct block_data *open_list; | |||
777 | ||||
778 | /* Forward declarations. */ | |||
779 | ||||
780 | extern struct device_emulation_ops linux_block_emulation_ops; | |||
781 | ||||
782 | static io_return_t device_close (void *); | |||
783 | static io_return_t device_close_forced (void *, int); | |||
784 | ||||
785 | /* Return a send right for block device BD. */ | |||
786 | static ipc_port_t | |||
787 | dev_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. */ | |||
795 | static inlineinline __attribute__((always_inline)) int | |||
796 | isalpha (int c) | |||
797 | { | |||
798 | return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); | |||
799 | } | |||
800 | ||||
801 | /* Return 1 if C is a digit. */ | |||
802 | static inlineinline __attribute__((always_inline)) int | |||
803 | isdigit (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. */ | |||
811 | static struct name_map * | |||
812 | find_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 | ||||
843 | find_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. */ | |||
855 | static struct disklabel * | |||
856 | read_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. */ | |||
879 | static struct disklabel * | |||
880 | read_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. */ | |||
913 | static kern_return_t | |||
914 | init_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 | ||||
969 | check: | |||
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 | ||||
1001 | static io_return_t | |||
1002 | device_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, ¬ify); | |||
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 | ||||
1127 | bad: | |||
1128 | if (ds->fops->release) | |||
1129 | (*ds->fops->release) (&td.inode, &td.file); | |||
1130 | ||||
1131 | out: | |||
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 | ||||
1178 | static io_return_t | |||
1179 | device_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 | ||||
1239 | static io_return_t | |||
1240 | device_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. */ | |||
1251 | static int | |||
1252 | check_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 | ||||
1295 | static io_return_t | |||
1296 | device_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), ©, 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 | ||||
1399 | out: | |||
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 | ||||
1410 | static io_return_t | |||
1411 | device_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 | ||||
1561 | out: | |||
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))), ©); | |||
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 | ||||
1579 | static io_return_t | |||
1580 | device_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 | ||||
1705 | static io_return_t | |||
1706 | device_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 | ||||
1725 | static void | |||
1726 | device_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 | ||||
1735 | struct 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 | }; |