|
|
1.1 root 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 <mach/mach_types.h>
45: #include <mach/kern_return.h>
46: #include <mach/mig_errors.h>
47: #include <mach/port.h>
48: #include <mach/vm_param.h>
49: #include <mach/notify.h>
50:
51: #include <ipc/ipc_port.h>
52: #include <ipc/ipc_space.h>
53:
54: #include <vm/vm_map.h>
55: #include <vm/vm_kern.h>
56: #include <vm/vm_page.h>
57:
58: #include <device/device_types.h>
59: #include <device/device_port.h>
60: #include <device/disk_status.h>
61: #include "device_reply.h"
62:
63: #include <i386at/dev_hdr.h>
64: #include <i386at/device_emul.h>
65: #include <i386at/disk.h>
66:
67: #include <i386at/gpl/linux/linux_emul.h>
68:
69: #define MACH_INCLUDE
70: #include <linux/fs.h>
71: #include <linux/blk.h>
72: #include <linux/string.h>
73: #include <linux/errno.h>
74: #include <linux/fcntl.h>
75: #include <linux/major.h>
76: #include <linux/kdev_t.h>
77: #include <linux/delay.h>
78: #include <linux/malloc.h>
79:
80: /* Location of VTOC in units for sectors (512 bytes). */
81: #define PDLOCATION 29
82:
83: /* Linux kernel variables. */
84:
85: /* One of these exists for each
86: driver associated with a major number. */
87: struct device_struct
88: {
89: const char *name; /* device name */
90: struct file_operations *fops; /* operations vector */
91: int busy:1; /* driver is being opened/closed */
92: int want:1; /* someone wants to open/close driver */
93: struct gendisk *gd; /* DOS partition information */
94: int *default_slice; /* what slice to use when none is given */
95: struct disklabel **label; /* disklabels for each DOS partition */
96: };
97:
98: /* An entry in the Mach name to Linux major number conversion table. */
99: struct name_map
100: {
101: const char *name; /* Mach name for device */
102: unsigned major; /* Linux major number */
103: unsigned unit; /* Linux unit number */
104: int read_only; /* 1 if device is read only */
105: };
106:
107: /* Driver operation table. */
108: static struct device_struct blkdevs[MAX_BLKDEV];
109:
110: /* Driver request function table. */
111: struct blk_dev_struct blk_dev[MAX_BLKDEV] =
112: {
113: { NULL, NULL }, /* 0 no_dev */
114: { NULL, NULL }, /* 1 dev mem */
115: { NULL, NULL }, /* 2 dev fd */
116: { NULL, NULL }, /* 3 dev ide0 or hd */
117: { NULL, NULL }, /* 4 dev ttyx */
118: { NULL, NULL }, /* 5 dev tty */
119: { NULL, NULL }, /* 6 dev lp */
120: { NULL, NULL }, /* 7 dev pipes */
121: { NULL, NULL }, /* 8 dev sd */
122: { NULL, NULL }, /* 9 dev st */
123: { NULL, NULL }, /* 10 */
124: { NULL, NULL }, /* 11 */
125: { NULL, NULL }, /* 12 */
126: { NULL, NULL }, /* 13 */
127: { NULL, NULL }, /* 14 */
128: { NULL, NULL }, /* 15 */
129: { NULL, NULL }, /* 16 */
130: { NULL, NULL }, /* 17 */
131: { NULL, NULL }, /* 18 */
132: { NULL, NULL }, /* 19 */
133: { NULL, NULL }, /* 20 */
134: { NULL, NULL }, /* 21 */
135: { NULL, NULL } /* 22 dev ide1 */
136: };
137:
138: /*
139: * blk_size contains the size of all block-devices in units of 1024 byte
140: * sectors:
141: *
142: * blk_size[MAJOR][MINOR]
143: *
144: * if (!blk_size[MAJOR]) then no minor size checking is done.
145: */
146: int *blk_size[MAX_BLKDEV] = { NULL, NULL, };
147:
148: /*
149: * blksize_size contains the size of all block-devices:
150: *
151: * blksize_size[MAJOR][MINOR]
152: *
153: * if (!blksize_size[MAJOR]) then 1024 bytes is assumed.
154: */
155: int *blksize_size[MAX_BLKDEV] = { NULL, NULL, };
156:
157: /*
158: * hardsect_size contains the size of the hardware sector of a device.
159: *
160: * hardsect_size[MAJOR][MINOR]
161: *
162: * if (!hardsect_size[MAJOR])
163: * then 512 bytes is assumed.
164: * else
165: * sector_size is hardsect_size[MAJOR][MINOR]
166: * This is currently set by some scsi device and read by the msdos fs driver
167: * This might be a some uses later.
168: */
169: int *hardsect_size[MAX_BLKDEV] = { NULL, NULL, };
170:
171: /* This specifies how many sectors to read ahead on the disk.
172: This is unused in Mach. It is here to make drivers compile. */
173: int read_ahead[MAX_BLKDEV] = {0, };
174:
175: /* Use to wait on when there are no free requests.
176: This is unused in Mach. It is here to make drivers compile. */
177: struct wait_queue *wait_for_request = NULL;
178:
179: /* Initialize block drivers. */
180: void
181: blk_dev_init ()
182: {
183: #ifdef CONFIG_BLK_DEV_IDE
184: ide_init ();
185: #endif
186: #ifdef CONFIG_BLK_DEV_FD
187: floppy_init ();
188: #endif
189: }
190:
191: /* Return 1 if major number MAJOR corresponds to a disk device. */
192: static inline int
193: disk_major (int major)
194: {
195: return (major == IDE0_MAJOR
196: || major == IDE1_MAJOR
197: || major == IDE2_MAJOR
198: || major == IDE3_MAJOR
199: || major == SCSI_DISK_MAJOR);
200: }
201:
202: /* Linux kernel block support routines. */
203:
204: /* Register a driver for major number MAJOR,
205: with name NAME, and operations vector FOPS. */
206: int
207: register_blkdev (unsigned major, const char *name,
208: struct file_operations *fops)
209: {
210: int err = 0;
211:
212: if (major == 0)
213: {
214: for (major = MAX_BLKDEV - 1; major > 0; major--)
215: if (blkdevs[major].fops == NULL)
216: goto out;
217: return -LINUX_EBUSY;
218: }
219: if (major >= MAX_BLKDEV)
220: return -LINUX_EINVAL;
221: if (blkdevs[major].fops && blkdevs[major].fops != fops)
222: return -LINUX_EBUSY;
223:
224: out:
225: blkdevs[major].name = name;
226: blkdevs[major].fops = fops;
227: blkdevs[major].busy = 0;
228: blkdevs[major].want = 0;
229: blkdevs[major].gd = NULL;
230: blkdevs[major].default_slice = NULL;
231: blkdevs[major].label = NULL;
232: return 0;
233: }
234:
235: /* Unregister the driver associated with
236: major number MAJOR and having the name NAME. */
237: int
238: unregister_blkdev (unsigned major, const char *name)
239: {
240: int err;
241:
242: if (major >= MAX_BLKDEV)
243: return -LINUX_EINVAL;
244: if (! blkdevs[major].fops || strcmp (blkdevs[major].name, name))
245: return -LINUX_EINVAL;
246: blkdevs[major].fops = NULL;
247: if (blkdevs[major].default_slice)
248: {
249: assert (blkdevs[major].gd);
250: kfree ((vm_offset_t) blkdevs[major].default_slice,
251: sizeof (int) * blkdevs[major].gd->max_nr);
252: }
253: if (blkdevs[major].label)
254: {
255: assert (blkdevs[major].gd);
256: kfree ((vm_offset_t) blkdevs[major].label,
257: (sizeof (struct disklabel *)
258: * blkdevs[major].gd->max_p * blkdevs[major].gd->max_nr));
259: }
260: return 0;
261: }
262:
263: /* One of these is associated with
264: each page allocated by the buffer management routines. */
265: struct pagehdr
266: {
267: unsigned char busy; /* page header is in use */
268: unsigned char avail; /* number of blocks available in page */
269: unsigned short bitmap; /* free space bitmap */
270: void *blks; /* the actual page */
271: struct pagehdr *next; /* next header in list */
272: };
273:
274: /* This structure describes the different block sizes. */
275: struct bufsize
276: {
277: unsigned short size; /* size of block */
278: unsigned short avail; /* # available blocks */
279: struct pagehdr *pages; /* page list */
280: };
281:
282: /* List of supported block sizes. */
283: static struct bufsize bufsizes[] =
284: {
285: { 512, 0, NULL },
286: { 1024, 0, NULL },
287: { 2048, 0, NULL },
288: { 4096, 0, NULL },
289: };
290:
291: /* Page headers. */
292: static struct pagehdr pagehdrs[50]; /* XXX: needs to be dynamic */
293:
294: /* Find the block size that is greater than or equal to SIZE. */
295: static struct bufsize *
296: get_bufsize (int size)
297: {
298: struct bufsize *bs, *ebs;
299:
300: bs = &bufsizes[0];
301: ebs = &bufsizes[sizeof (bufsizes) / sizeof (bufsizes[0])];
302: while (bs < ebs)
303: {
304: if (bs->size >= size)
305: return bs;
306: bs++;
307: }
308:
309: panic ("%s:%d: alloc_buffer: bad buffer size %d", __FILE__, __LINE__, size);
310: }
311:
312: /* Free all pages that are not in use.
313: Called by __get_free_pages when pages are running low. */
314: void
315: collect_buffer_pages ()
316: {
317: struct bufsize *bs, *ebs;
318: struct pagehdr *ph, **prev_ph;
319:
320: bs = &bufsizes[0];
321: ebs = &bufsizes[sizeof (bufsizes) / sizeof (bufsizes[0])];
322: while (bs < ebs)
323: {
324: if (bs->avail >= PAGE_SIZE / bs->size)
325: {
326: ph = bs->pages;
327: prev_ph = &bs->pages;
328: while (ph)
329: if (ph->avail == PAGE_SIZE / bs->size)
330: {
331: bs->avail -= ph->avail;
332: ph->busy = 0;
333: *prev_ph = ph->next;
334: free_pages ((unsigned long) ph->blks, 0);
335: ph = *prev_ph;
336: }
337: else
338: {
339: prev_ph = &ph->next;
340: ph = ph->next;
341: }
342: }
343: bs++;
344: }
345: }
346:
347: /* Allocate a buffer of at least SIZE bytes. */
348: static void *
349: alloc_buffer (int size)
350: {
351: int i;
352: unsigned flags;
353: struct bufsize *bs;
354: struct pagehdr *ph, *eph;
355:
356: bs = get_bufsize (size);
357: save_flags (flags);
358: cli ();
359: if (bs->avail == 0)
360: {
361: ph = &pagehdrs[0];
362: eph = &pagehdrs[sizeof (pagehdrs) / sizeof (pagehdrs[0])];
363: while (ph < eph && ph->busy)
364: ph++;
365: if (ph == eph)
366: {
367: restore_flags (flags);
368: printf ("%s:%d: alloc_buffer: ran out of page headers\n",
369: __FILE__, __LINE__);
370: return NULL;
371: }
372: ph->blks = (void *) __get_free_pages (GFP_KERNEL, 0, ~0UL);
373: if (! ph->blks)
374: {
375: restore_flags (flags);
376: return NULL;
377: }
378: ph->busy = 1;
379: ph->avail = PAGE_SIZE / bs->size;
380: ph->bitmap = 0;
381: ph->next = bs->pages;
382: bs->pages = ph;
383: bs->avail += ph->avail;
384: }
385: for (ph = bs->pages; ph; ph = ph->next)
386: if (ph->avail)
387: for (i = 0; i < PAGE_SIZE / bs->size; i++)
388: if ((ph->bitmap & (1 << i)) == 0)
389: {
390: bs->avail--;
391: ph->avail--;
392: ph->bitmap |= 1 << i;
393: restore_flags (flags);
394: return ph->blks + i * bs->size;
395: }
396:
397: panic ("%s:%d: alloc_buffer: list destroyed", __FILE__, __LINE__);
398: }
399:
400: /* Free buffer P of SIZE bytes previously allocated by alloc_buffer. */
401: static void
402: free_buffer (void *p, int size)
403: {
404: int i;
405: unsigned flags;
406: struct bufsize *bs;
407: struct pagehdr *ph;
408:
409: bs = get_bufsize (size);
410: save_flags (flags);
411: cli ();
412: for (ph = bs->pages; ph; ph = ph->next)
413: if (p >= ph->blks && p < ph->blks + PAGE_SIZE)
414: break;
415: assert (ph);
416: i = (int) (p - ph->blks) / bs->size;
417: assert (ph->bitmap & (1 << i));
418: ph->bitmap &= ~(1 << i);
419: ph->avail++;
420: bs->avail++;
421: restore_flags (flags);
422: }
423:
424: /* Allocate a buffer of SIZE bytes and
425: associate it with block number BLOCK of device DEV. */
426: struct buffer_head *
427: getblk (kdev_t dev, int block, int size)
428: {
429: struct buffer_head *bh;
430:
431: assert (size <= PAGE_SIZE);
432:
433: bh = linux_kmalloc (sizeof (struct buffer_head), GFP_KERNEL);
434: if (! bh)
435: return NULL;
436: bh->b_data = alloc_buffer (size);
437: if (! bh->b_data)
438: {
439: linux_kfree (bh);
440: return NULL;
441: }
442: bh->b_dev = dev;
443: bh->b_size = size;
444: bh->b_state = 1 << BH_Lock;
445: bh->b_blocknr = block;
446: bh->b_page_list = NULL;
447: bh->b_request = NULL;
448: bh->b_reqnext = NULL;
449: bh->b_wait = NULL;
450: bh->b_sem = NULL;
451: return bh;
452: }
453:
454: /* Release buffer BH previously allocated by getblk. */
455: void
456: __brelse (struct buffer_head *bh)
457: {
458: if (bh->b_request)
459: linux_kfree (bh->b_request);
460: free_buffer (bh->b_data, bh->b_size);
461: linux_kfree (bh);
462: }
463:
464: /* Check for I/O errors upon completion of I/O operation RW
465: on the buffer list BH. The number of buffers is NBUF.
466: Copy any data from bounce buffers and free them. */
467: static int
468: check_for_error (int rw, int nbuf, struct buffer_head **bh)
469: {
470: int err;
471: struct request *req;
472:
473: req = bh[0]->b_request;
474: if (! req)
475: {
476: while (--nbuf >= 0)
477: if (bh[nbuf]->b_page_list)
478: {
479: bh[nbuf]->b_page_list = NULL;
480: free_buffer (bh[nbuf]->b_data, bh[nbuf]->b_size);
481: }
482: return -LINUX_ENOMEM;
483: }
484:
485: bh[0]->b_request = NULL;
486: err = 0;
487:
488: while (--nbuf >= 0)
489: {
490: struct buffer_head *bhp = bh[nbuf];
491:
492: if (bhp->b_page_list)
493: {
494: if (rw == READ && buffer_uptodate (bhp))
495: {
496: int amt;
497: vm_page_t *pages = bhp->b_page_list;
498:
499: amt = PAGE_SIZE - bhp->b_off;
500: if (amt > bhp->b_usrcnt)
501: amt = bhp->b_usrcnt;
502: memcpy ((void *) pages[bhp->b_index]->phys_addr + bhp->b_off,
503: bhp->b_data, amt);
504: if (amt < bhp->b_usrcnt)
505: memcpy ((void *) pages[bhp->b_index + 1]->phys_addr,
506: bhp->b_data + amt, bhp->b_usrcnt - amt);
507: }
508: bhp->b_page_list = NULL;
509: free_buffer (bhp->b_data, bhp->b_size);
510: }
511: if (! buffer_uptodate (bhp))
512: err = -LINUX_EIO;
513: }
514:
515: linux_kfree (req);
516: return err;
517: }
518:
519: /* Allocate a buffer of SIZE bytes and fill it with data
520: from device DEV starting at block number BLOCK. */
521: struct buffer_head *
522: bread (kdev_t dev, int block, int size)
523: {
524: int err;
525: struct buffer_head *bh;
526:
527: bh = getblk (dev, block, size);
528: if (! bh)
529: return NULL;
530: ll_rw_block (READ, 1, &bh);
531: wait_on_buffer (bh);
532: err = check_for_error (READ, 1, &bh);
533: if (err)
534: {
535: __brelse (bh);
536: return NULL;
537: }
538: return bh;
539: }
540:
541: /* Return the block size for device DEV in *BSIZE and
542: log2(block size) in *BSHIFT. */
543: static inline void
544: get_block_size (kdev_t dev, int *bsize, int *bshift)
545: {
546: int i, size, shift;
547:
548: size = BLOCK_SIZE;
549: if (blksize_size[MAJOR (dev)]
550: && blksize_size[MAJOR (dev)][MINOR (dev)])
551: size = blksize_size[MAJOR (dev)][MINOR (dev)];
552: for (i = size, shift = 0; i != 1; shift++, i >>= 1)
553: ;
554: *bsize = size;
555: *bshift = shift;
556: }
557:
558: /* Enqueue request REQ on a driver's queue. */
559: static inline void
560: enqueue_request (struct request *req)
561: {
562: struct request *tmp;
563: struct blk_dev_struct *dev;
564:
565: dev = blk_dev + MAJOR (req->rq_dev);
566: cli ();
567: tmp = dev->current_request;
568: if (! tmp)
569: {
570: dev->current_request = req;
571: (*dev->request_fn) ();
572: sti ();
573: return;
574: }
575: while (tmp->next)
576: {
577: if ((IN_ORDER (tmp, req) || ! IN_ORDER (tmp, tmp->next))
578: && IN_ORDER (req, tmp->next))
579: break;
580: tmp = tmp->next;
581: }
582: req->next = tmp->next;
583: tmp->next = req;
584: if (scsi_major (MAJOR (req->rq_dev)))
585: (*dev->request_fn) ();
586: sti ();
587: }
588:
589: /* Perform the I/O operation RW on the buffer list BH
590: containing NR buffers. */
591: void
592: ll_rw_block (int rw, int nr, struct buffer_head **bh)
593: {
594: int i, bsize, bshift;
595: unsigned major;
596: struct request *r;
597:
598: r = (struct request *) linux_kmalloc (sizeof (struct request), GFP_KERNEL);
599: if (! r)
600: {
601: bh[0]->b_request = NULL;
602: return;
603: }
604: bh[0]->b_request = r;
605:
606: major = MAJOR (bh[0]->b_dev);
607: assert (major < MAX_BLKDEV);
608:
609: get_block_size (bh[0]->b_dev, &bsize, &bshift);
610: assert (bsize <= PAGE_SIZE);
611:
612: for (i = 0, r->nr_sectors = 0; i < nr - 1; i++)
613: {
614: r->nr_sectors += bh[i]->b_size >> 9;
615: bh[i]->b_reqnext = bh[i + 1];
616: }
617: r->nr_sectors += bh[i]->b_size >> 9;
618: bh[i]->b_reqnext = NULL;
619:
620: r->rq_status = RQ_ACTIVE;
621: r->rq_dev = bh[0]->b_dev;
622: r->cmd = rw;
623: r->errors = 0;
624: r->sector = bh[0]->b_blocknr << (bshift - 9);
625: r->current_nr_sectors = bh[0]->b_size >> 9;
626: r->buffer = bh[0]->b_data;
627: r->sem = bh[0]->b_sem;
628: r->bh = bh[0];
629: r->bhtail = bh[nr - 1];
630: r->next = NULL;
631:
632: enqueue_request (r);
633: }
634:
635: /* Maximum amount of data to write per invocation of the driver. */
636: #define WRITE_MAXPHYS (VM_MAP_COPY_PAGE_LIST_MAX << PAGE_SHIFT)
637: #define WRITE_MAXPHYSPG (WRITE_MAXPHYS >> PAGE_SHIFT)
638:
639: int linux_block_write_trace = 0;
640:
641: /* Write COUNT bytes of data from user buffer BUF
642: to device specified by INODE at location specified by FILP. */
643: int
644: block_write (struct inode *inode, struct file *filp,
645: const char *buf, int count)
646: {
647: char *p;
648: int i, bsize, bmask, bshift;
649: int err = 0, have_page_list = 1;
650: int resid = count, unaligned;
651: int page_index, pages, amt, cnt, nbuf;
652: unsigned blk;
653: vm_map_copy_t copy;
654: struct request req;
655: struct semaphore sem;
656: struct name_map *np = filp->f_np;
657: struct buffer_head *bh, *bhp, **bhlist;
658:
659: /* Compute device block size. */
660: get_block_size (inode->i_rdev, &bsize, &bshift);
661: assert (bsize <= PAGE_SIZE);
662: bmask = bsize - 1;
663:
664: copy = (vm_map_copy_t) buf;
665: assert (copy);
666: assert (copy->type == VM_MAP_COPY_PAGE_LIST);
667:
668: p = (char *) copy->offset;
669: pages = copy->cpy_npages;
670: blk = (filp->f_pos + bmask) >> bshift;
671:
672: if (linux_block_write_trace)
673: printf ("block_write: at %d: f_pos 0x%x, count %d, blk 0x%x, p 0x%x\n",
674: __LINE__, (unsigned) filp->f_pos, count, blk, p);
675:
676: /* Allocate buffer headers. */
677: nbuf = ((round_page ((vm_offset_t) p + resid) - trunc_page ((vm_offset_t) p))
678: >> PAGE_SHIFT);
679: if (nbuf > WRITE_MAXPHYSPG)
680: nbuf = WRITE_MAXPHYSPG;
681: if ((filp->f_pos & bmask) || ((int) p & PAGE_MASK))
682: nbuf *= 2;
683: bh = (struct buffer_head *) kalloc ((sizeof (*bh) + sizeof (*bhlist))
684: * nbuf);
685: if (! bh)
686: {
687: err = -LINUX_ENOMEM;
688: goto out;
689: }
690: bhlist = (struct buffer_head **) (bh + nbuf);
691:
692: /* Write any partial block. */
693: if (filp->f_pos & bmask)
694: {
695: char *b, *q;
696: int use_req;
697:
698: use_req = (disk_major (MAJOR (inode->i_rdev)) && ! np->read_only);
699:
700: amt = bsize - (filp->f_pos & bmask);
701: if (amt > resid)
702: amt = resid;
703:
704: if (linux_block_write_trace)
705: printf ("block_write: at %d: amt %d, resid %d\n",
706: __LINE__, amt, resid);
707:
708: if (use_req)
709: {
710: i = (amt + 511) & ~511;
711: req.buffer = b = alloc_buffer (i);
712: if (! b)
713: {
714: printf ("%s:%d: block_write: ran out of buffers\n",
715: __FILE__, __LINE__);
716: err = -LINUX_ENOMEM;
717: goto out;
718: }
719: req.sector = filp->f_pos >> 9;
720: req.nr_sectors = i >> 9;
721: req.current_nr_sectors = i >> 9;
722: req.rq_status = RQ_ACTIVE;
723: req.rq_dev = inode->i_rdev;
724: req.cmd = READ;
725: req.errors = 0;
726: req.sem = &sem;
727: req.bh = NULL;
728: req.bhtail = NULL;
729: req.next = NULL;
730:
731: sem.count = 0;
732: sem.wait = NULL;
733:
734: enqueue_request (&req);
735: __down (&sem);
736:
737: if (req.errors)
738: {
739: free_buffer (b, i);
740: err = -LINUX_EIO;
741: goto out;
742: }
743: q = b + (filp->f_pos & 511);
744: }
745: else
746: {
747: i = bsize;
748: bhp = bh;
749: bhp->b_data = b = alloc_buffer (i);
750: if (! b)
751: {
752: err = -LINUX_ENOMEM;
753: goto out;
754: }
755: bhp->b_blocknr = filp->f_pos >> bshift;
756: bhp->b_dev = inode->i_rdev;
757: bhp->b_size = bsize;
758: bhp->b_state = 1 << BH_Lock;
759: bhp->b_page_list = NULL;
760: bhp->b_request = NULL;
761: bhp->b_reqnext = NULL;
762: bhp->b_wait = NULL;
763: bhp->b_sem = NULL;
764:
765: ll_rw_block (READ, 1, &bhp);
766: wait_on_buffer (bhp);
767: err = check_for_error (READ, 1, &bhp);
768: if (err)
769: {
770: free_buffer (b, i);
771: goto out;
772: }
773: q = b + (filp->f_pos & bmask);
774: }
775:
776: cnt = PAGE_SIZE - ((int) p & PAGE_MASK);
777: if (cnt > amt)
778: cnt = amt;
779: memcpy (q, ((void *) copy->cpy_page_list[0]->phys_addr
780: + ((int) p & PAGE_MASK)),
781: cnt);
782: if (cnt < amt)
783: {
784: assert (copy->cpy_npages >= 2);
785: memcpy (q + cnt,
786: (void *) copy->cpy_page_list[1]->phys_addr, amt - cnt);
787: }
788: else
789: assert (copy->cpy_npages >= 1);
790:
791: if (use_req)
792: {
793: req.buffer = b;
794: req.sector = filp->f_pos >> 9;
795: req.nr_sectors = i >> 9;
796: req.current_nr_sectors = i >> 9;
797: req.rq_status = RQ_ACTIVE;
798: req.rq_dev = inode->i_rdev;
799: req.cmd = WRITE;
800: req.errors = 0;
801: req.sem = &sem;
802: req.bh = NULL;
803: req.bhtail = NULL;
804: req.next = NULL;
805:
806: sem.count = 0;
807: sem.wait = NULL;
808:
809: enqueue_request (&req);
810: __down (&sem);
811:
812: if (req.errors)
813: err = -LINUX_EIO;
814: }
815: else
816: {
817: bhp->b_state = (1 << BH_Dirty) | (1 << BH_Lock);
818: ll_rw_block (WRITE, 1, &bhp);
819: err = check_for_error (WRITE, 1, &bhp);
820: }
821: free_buffer (b, i);
822: if (err)
823: {
824: if (linux_block_write_trace)
825: printf ("block_write: at %d\n", __LINE__);
826:
827: goto out;
828: }
829: resid -= amt;
830: if (resid == 0)
831: goto out;
832: p += amt;
833: }
834:
835: unaligned = (int) p & 511;
836:
837: /* Write full blocks. */
838: while (resid > bsize)
839: {
840: assert (have_page_list == 1);
841:
842: /* Construct buffer list. */
843: for (i = 0, bhp = bh; resid > bsize && i < nbuf; i++, bhp++)
844: {
845: page_index = ((trunc_page ((vm_offset_t) p)
846: - trunc_page (copy->offset))
847: >> PAGE_SHIFT);
848:
849: if (page_index == pages)
850: break;
851:
852: bhlist[i] = bhp;
853: bhp->b_dev = inode->i_rdev;
854: bhp->b_state = (1 << BH_Dirty) | (1 << BH_Lock);
855: bhp->b_blocknr = blk;
856: bhp->b_wait = NULL;
857: bhp->b_page_list = NULL;
858: bhp->b_sem = &sem;
859:
860: cnt = PAGE_SIZE - ((int) p & PAGE_MASK);
861: if (! unaligned && cnt >= bsize)
862: {
863: if (cnt > resid)
864: cnt = resid;
865: bhp->b_size = cnt & ~bmask;
866: bhp->b_data = (((char *)
867: copy->cpy_page_list[page_index]->phys_addr)
868: + ((int) p & PAGE_MASK));
869: }
870: else
871: {
872: if (cnt < bsize)
873: {
874: if (page_index == pages - 1)
875: break;
876: bhp->b_size = bsize;
877: }
878: else
879: {
880: bhp->b_size = cnt;
881: if (bhp->b_size > resid)
882: bhp->b_size = resid;
883: bhp->b_size &= ~bmask;
884: }
885: bhp->b_data = alloc_buffer (bhp->b_size);
886: if (! bhp->b_data)
887: {
888: printf ("%s:%d: block_write: ran out of buffers\n",
889: __FILE__, __LINE__);
890: while (--i >= 0)
891: if (bhlist[i]->b_page_list)
892: free_buffer (bhlist[i]->b_data, bhlist[i]->b_size);
893: err = -LINUX_ENOMEM;
894: goto out;
895: }
896: bhp->b_page_list = (void *) 1;
897: if (cnt > bhp->b_size)
898: cnt = bhp->b_size;
899: memcpy (bhp->b_data,
900: ((void *) copy->cpy_page_list[page_index]->phys_addr
901: + ((int) p & PAGE_MASK)),
902: cnt);
903: if (cnt < bhp->b_size)
904: memcpy (bhp->b_data + cnt,
905: ((void *)
906: copy->cpy_page_list[page_index + 1]->phys_addr),
907: bhp->b_size - cnt);
908: }
909:
910: p += bhp->b_size;
911: resid -= bhp->b_size;
912: blk += bhp->b_size >> bshift;
913: }
914:
915: assert (i > 0);
916:
917: sem.count = 0;
918: sem.wait = NULL;
919:
920: /* Do the write. */
921: ll_rw_block (WRITE, i, bhlist);
922: __down (&sem);
923: err = check_for_error (WRITE, i, bhlist);
924: if (err || resid == 0)
925: goto out;
926:
927: /* Discard current page list. */
928: vm_map_copy_discard (copy);
929: have_page_list = 0;
930:
931: /* Compute # pages to wire down. */
932: pages = ((round_page ((vm_offset_t) p + resid)
933: - trunc_page ((vm_offset_t) p))
934: >> PAGE_SHIFT);
935: if (pages > WRITE_MAXPHYSPG)
936: pages = WRITE_MAXPHYSPG;
937:
938: /* Wire down user pages and get page list. */
939: err = vm_map_copyin_page_list (current_map (),
940: trunc_page ((vm_offset_t) p),
941: pages << PAGE_SHIFT, FALSE,
942: FALSE, ©, FALSE);
943: if (err)
944: {
945: if (err == KERN_INVALID_ADDRESS || err == KERN_PROTECTION_FAILURE)
946: err = -LINUX_EINVAL;
947: else
948: err = -LINUX_ENOMEM;
949: goto out;
950: }
951:
952: assert (pages == copy->cpy_npages);
953: assert (! vm_map_copy_has_cont (copy));
954:
955: have_page_list = 1;
956: }
957:
958: /* Write any partial count. */
959: if (resid > 0)
960: {
961: char *b;
962: int use_req;
963:
964: assert (have_page_list);
965: assert (pages >= 1);
966:
967: use_req = (disk_major (MAJOR (inode->i_rdev)) && ! np->read_only);
968:
969: if (linux_block_write_trace)
970: printf ("block_write: at %d: resid %d\n", __LINE__, resid);
971:
972: if (use_req)
973: {
974: i = (resid + 511) & ~511;
975: req.buffer = b = alloc_buffer (i);
976: if (! b)
977: {
978: printf ("%s:%d: block_write: ran out of buffers\n",
979: __FILE__, __LINE__);
980: err = -LINUX_ENOMEM;
981: goto out;
982: }
983: req.sector = blk << (bshift - 9);
984: req.nr_sectors = i >> 9;
985: req.current_nr_sectors = i >> 9;
986: req.rq_status = RQ_ACTIVE;
987: req.rq_dev = inode->i_rdev;
988: req.cmd = READ;
989: req.errors = 0;
990: req.sem = &sem;
991: req.bh = NULL;
992: req.bhtail = NULL;
993: req.next = NULL;
994:
995: sem.count = 0;
996: sem.wait = NULL;
997:
998: enqueue_request (&req);
999: __down (&sem);
1000:
1001: if (req.errors)
1002: {
1003: free_buffer (b, i);
1004: err = -LINUX_EIO;
1005: goto out;
1006: }
1007: }
1008: else
1009: {
1010: i = bsize;
1011: bhp = bh;
1012: bhp->b_data = b = alloc_buffer (i);
1013: if (! b)
1014: {
1015: err = -LINUX_ENOMEM;
1016: goto out;
1017: }
1018: bhp->b_blocknr = blk;
1019: bhp->b_dev = inode->i_rdev;
1020: bhp->b_size = bsize;
1021: bhp->b_state = 1 << BH_Lock;
1022: bhp->b_page_list = NULL;
1023: bhp->b_request = NULL;
1024: bhp->b_reqnext = NULL;
1025: bhp->b_wait = NULL;
1026: bhp->b_sem = NULL;
1027:
1028: ll_rw_block (READ, 1, &bhp);
1029: wait_on_buffer (bhp);
1030: err = check_for_error (READ, 1, &bhp);
1031: if (err)
1032: {
1033: free_buffer (b, i);
1034: goto out;
1035: }
1036: }
1037:
1038: page_index = ((trunc_page ((vm_offset_t) p) - trunc_page (copy->offset))
1039: >> PAGE_SHIFT);
1040: cnt = PAGE_SIZE - ((int) p & PAGE_MASK);
1041: if (cnt > resid)
1042: cnt = resid;
1043: memcpy (b, ((void *) copy->cpy_page_list[page_index]->phys_addr
1044: + ((int) p & PAGE_MASK)),
1045: cnt);
1046: if (cnt < resid)
1047: {
1048: assert (copy->cpy_npages >= 2);
1049: memcpy (b + cnt,
1050: (void *) copy->cpy_page_list[page_index + 1]->phys_addr,
1051: resid - cnt);
1052: }
1053: else
1054: assert (copy->cpy_npages >= 1);
1055:
1056: if (use_req)
1057: {
1058: req.buffer = b;
1059: req.sector = blk << (bshift - 9);
1060: req.nr_sectors = i >> 9;
1061: req.current_nr_sectors = i >> 9;
1062: req.rq_status = RQ_ACTIVE;
1063: req.rq_dev = inode->i_rdev;
1064: req.cmd = WRITE;
1065: req.errors = 0;
1066: req.sem = &sem;
1067: req.bh = NULL;
1068: req.bhtail = NULL;
1069: req.next = NULL;
1070:
1071: sem.count = 0;
1072: sem.wait = NULL;
1073:
1074: enqueue_request (&req);
1075: __down (&sem);
1076:
1077: if (req.errors)
1078: err = -LINUX_EIO;
1079: }
1080: else
1081: {
1082: bhp->b_state = (1 << BH_Dirty) | (1 << BH_Lock);
1083: ll_rw_block (WRITE, 1, &bhp);
1084: err = check_for_error (WRITE, 1, &bhp);
1085: }
1086: free_buffer (b, i);
1087: if (! err)
1088: resid = 0;
1089: }
1090:
1091: out:
1092: if (have_page_list)
1093: vm_map_copy_discard (copy);
1094: if (bh)
1095: kfree ((vm_offset_t) bh,
1096: (sizeof (*bh) + sizeof (*bhlist)) * nbuf);
1097: filp->f_resid = resid;
1098: return err;
1099: }
1100:
1101: int linux_block_read_trace = 0;
1102: #define LINUX_BLOCK_READ_TRACE (linux_block_read_trace == -1 \
1103: || linux_block_read_trace == inode->i_rdev)
1104:
1105: /* Maximum amount of data to read per driver invocation. */
1106: #define READ_MAXPHYS (64*1024)
1107: #define READ_MAXPHYSPG (READ_MAXPHYS >> PAGE_SHIFT)
1108:
1109: /* Read COUNT bytes of data into user buffer BUF
1110: from device specified by INODE from location specified by FILP. */
1111: int
1112: block_read (struct inode *inode, struct file *filp, char *buf, int count)
1113: {
1114: int err = 0, resid = count;
1115: int i, bsize, bmask, bshift;
1116: int pages, amt, unaligned;
1117: int page_index, nbuf;
1118: int have_page_list = 0;
1119: unsigned blk;
1120: vm_offset_t off, wire_offset, offset;
1121: vm_object_t object;
1122: vm_page_t *page_list;
1123: struct request req;
1124: struct semaphore sem;
1125: struct name_map *np = filp->f_np;
1126: struct buffer_head *bh, *bhp, **bhlist;
1127:
1128: /* Get device block size. */
1129: get_block_size (inode->i_rdev, &bsize, &bshift);
1130: assert (bsize <= PAGE_SIZE);
1131: bmask = bsize - 1;
1132:
1133: off = 0;
1134: blk = (filp->f_pos + bmask) >> bshift;
1135:
1136: /* Allocate buffer headers. */
1137: nbuf = round_page (count) >> PAGE_SHIFT;
1138: if (nbuf > READ_MAXPHYSPG)
1139: nbuf = READ_MAXPHYSPG;
1140: if (filp->f_pos & bmask)
1141: nbuf *= 2;
1142: bh = (struct buffer_head *) kalloc ((sizeof (*bh) + sizeof (*bhlist)) * nbuf
1143: + sizeof (*page_list) * READ_MAXPHYSPG);
1144: if (! bh)
1145: return -LINUX_ENOMEM;
1146: bhlist = (struct buffer_head **) (bh + nbuf);
1147: page_list = (vm_page_t *) (bhlist + nbuf);
1148:
1149: /* Allocate an object to hold the data. */
1150: object = vm_object_allocate (round_page (count));
1151: if (! object)
1152: {
1153: err = -LINUX_ENOMEM;
1154: goto out;
1155: }
1156:
1157: /* Compute number of pages to be wired at a time. */
1158: pages = round_page (count) >> PAGE_SHIFT;
1159: if (pages > READ_MAXPHYSPG)
1160: pages = READ_MAXPHYSPG;
1161:
1162: /* Allocate and wire down pages in the object. */
1163: for (i = 0, wire_offset = offset = 0; i < pages; i++, offset += PAGE_SIZE)
1164: {
1165: while (1)
1166: {
1167: page_list[i] = vm_page_grab ();
1168: if (page_list[i])
1169: {
1170: assert (page_list[i]->busy);
1171: assert (! page_list[i]->wanted);
1172: break;
1173: }
1174: vm_page_wait (NULL);
1175: }
1176: vm_object_lock (object);
1177: vm_page_lock_queues ();
1178: assert (! vm_page_lookup (object, offset));
1179: vm_page_insert (page_list[i], object, offset);
1180: assert (page_list[i]->wire_count == 0);
1181: vm_page_wire (page_list[i]);
1182: vm_page_unlock_queues ();
1183: vm_object_unlock (object);
1184: }
1185: have_page_list = 1;
1186:
1187: /* Read any partial block. */
1188: if (filp->f_pos & bmask)
1189: {
1190: char *b, *q;
1191: int use_req;
1192:
1193: use_req = (disk_major (MAJOR (inode->i_rdev)) && ! np->read_only);
1194:
1195: amt = bsize - (filp->f_pos & bmask);
1196: if (amt > resid)
1197: amt = resid;
1198:
1199: if (LINUX_BLOCK_READ_TRACE)
1200: printf ("block_read: at %d: amt %d, resid %d\n",
1201: __LINE__, amt, resid);
1202:
1203: if (use_req)
1204: {
1205: i = (amt + 511) & ~511;
1206: req.buffer = b = alloc_buffer (i);
1207: if (! b)
1208: {
1209: printf ("%s:%d: block_read: ran out of buffers\n",
1210: __FILE__, __LINE__);
1211: err = -LINUX_ENOMEM;
1212: goto out;
1213: }
1214: req.sector = filp->f_pos >> 9;
1215: req.nr_sectors = i >> 9;
1216: req.current_nr_sectors = i >> 9;
1217: req.rq_status = RQ_ACTIVE;
1218: req.rq_dev = inode->i_rdev;
1219: req.cmd = READ;
1220: req.errors = 0;
1221: req.sem = &sem;
1222: req.bh = NULL;
1223: req.bhtail = NULL;
1224: req.next = NULL;
1225:
1226: sem.count = 0;
1227: sem.wait = NULL;
1228:
1229: enqueue_request (&req);
1230: __down (&sem);
1231:
1232: if (req.errors)
1233: {
1234: free_buffer (b, i);
1235: err = -LINUX_EIO;
1236: goto out;
1237: }
1238: q = b + (filp->f_pos & 511);
1239: }
1240: else
1241: {
1242: i = bsize;
1243: bhp = bh;
1244: bhp->b_data = b = alloc_buffer (i);
1245: if (! b)
1246: {
1247: err = -LINUX_ENOMEM;
1248: goto out;
1249: }
1250: bhp->b_blocknr = filp->f_pos >> bshift;
1251: bhp->b_dev = inode->i_rdev;
1252: bhp->b_size = bsize;
1253: bhp->b_state = 1 << BH_Lock;
1254: bhp->b_page_list = NULL;
1255: bhp->b_request = NULL;
1256: bhp->b_reqnext = NULL;
1257: bhp->b_wait = NULL;
1258: bhp->b_sem = NULL;
1259:
1260: ll_rw_block (READ, 1, &bhp);
1261: wait_on_buffer (bhp);
1262: err = check_for_error (READ, 1, &bhp);
1263: if (err)
1264: {
1265: free_buffer (b, i);
1266: goto out;
1267: }
1268: q = b + (filp->f_pos & bmask);
1269: }
1270:
1271: memcpy ((void *) page_list[0]->phys_addr, q, amt);
1272:
1273: free_buffer (b, i);
1274: resid -= amt;
1275: if (resid == 0)
1276: {
1277: if (LINUX_BLOCK_READ_TRACE)
1278: printf ("block_read: at %d\n", __LINE__);
1279:
1280: assert (pages == 1);
1281: goto out;
1282: }
1283: off += amt;
1284: }
1285:
1286: unaligned = off & 511;
1287:
1288: /* Read full blocks. */
1289: while (resid > bsize)
1290: {
1291: /* Construct buffer list to hand to the driver. */
1292: for (i = 0, bhp = bh; resid > bsize && i < nbuf; bhp++, i++)
1293: {
1294: if (off == wire_offset + (pages << PAGE_SHIFT))
1295: break;
1296:
1297: bhlist[i] = bhp;
1298: bhp->b_dev = inode->i_rdev;
1299: bhp->b_state = 1 << BH_Lock;
1300: bhp->b_blocknr = blk;
1301: bhp->b_wait = NULL;
1302: bhp->b_sem = &sem;
1303:
1304: page_index = (trunc_page (off) - wire_offset) >> PAGE_SHIFT;
1305: amt = PAGE_SIZE - (off & PAGE_MASK);
1306: if (! unaligned && amt >= bsize)
1307: {
1308: if (amt > resid)
1309: amt = resid;
1310: bhp->b_size = amt & ~bmask;
1311: bhp->b_data = ((char *) page_list[page_index]->phys_addr
1312: + (off & PAGE_MASK));
1313: bhp->b_page_list = NULL;
1314: }
1315: else
1316: {
1317: if (amt < bsize)
1318: {
1319: if (page_index == pages - 1)
1320: {
1321: assert (round_page (count) - off >= resid);
1322: break;
1323: }
1324: bhp->b_size = bsize;
1325: }
1326: else
1327: {
1328: if (amt > resid)
1329: amt = resid;
1330: bhp->b_size = amt & ~bmask;
1331: }
1332: bhp->b_data = alloc_buffer (bhp->b_size);
1333: if (! bhp->b_data)
1334: {
1335: printf ("%s:%d: block_read: ran out of buffers\n",
1336: __FILE__, __LINE__);
1337:
1338: while (--i >= 0)
1339: if (bhp->b_page_list)
1340: free_buffer (bhp->b_data, bhp->b_size);
1341: err = -LINUX_ENOMEM;
1342: goto out;
1343: }
1344: bhp->b_page_list = page_list;
1345: bhp->b_index = page_index;
1346: bhp->b_off = off & PAGE_MASK;
1347: bhp->b_usrcnt = bhp->b_size;
1348: }
1349:
1350: resid -= bhp->b_size;
1351: off += bhp->b_size;
1352: blk += bhp->b_size >> bshift;
1353: }
1354:
1355: assert (i > 0);
1356:
1357: sem.count = 0;
1358: sem.wait = NULL;
1359:
1360: /* Do the read. */
1361: ll_rw_block (READ, i, bhlist);
1362: __down (&sem);
1363: err = check_for_error (READ, i, bhlist);
1364: if (err || resid == 0)
1365: goto out;
1366:
1367: /* Unwire the pages and mark them dirty. */
1368: offset = trunc_page (off);
1369: for (i = 0; wire_offset < offset; i++, wire_offset += PAGE_SIZE)
1370: {
1371: vm_object_lock (object);
1372: vm_page_lock_queues ();
1373: assert (vm_page_lookup (object, wire_offset) == page_list[i]);
1374: assert (page_list[i]->wire_count == 1);
1375: assert (! page_list[i]->active && ! page_list[i]->inactive);
1376: assert (! page_list[i]->reference);
1377: page_list[i]->dirty = TRUE;
1378: page_list[i]->reference = TRUE;
1379: page_list[i]->busy = FALSE;
1380: vm_page_unwire (page_list[i]);
1381: vm_page_unlock_queues ();
1382: vm_object_unlock (object);
1383: }
1384:
1385: assert (i <= pages);
1386:
1387: /* Wire down the next chunk of the object. */
1388: if (i == pages)
1389: {
1390: i = 0;
1391: offset = wire_offset;
1392: have_page_list = 0;
1393: }
1394: else
1395: {
1396: int j;
1397:
1398: for (j = 0; i < pages; page_list[j++] = page_list[i++])
1399: offset += PAGE_SIZE;
1400: i = j;
1401: }
1402: pages = (round_page (count) - wire_offset) >> PAGE_SHIFT;
1403: if (pages > READ_MAXPHYSPG)
1404: pages = READ_MAXPHYSPG;
1405: while (i < pages)
1406: {
1407: while (1)
1408: {
1409: page_list[i] = vm_page_grab ();
1410: if (page_list[i])
1411: {
1412: assert (page_list[i]->busy);
1413: assert (! page_list[i]->wanted);
1414: break;
1415: }
1416: vm_page_wait (NULL);
1417: }
1418: vm_object_lock (object);
1419: vm_page_lock_queues ();
1420: assert (! vm_page_lookup (object, offset));
1421: vm_page_insert (page_list[i], object, offset);
1422: assert (page_list[i]->wire_count == 0);
1423: vm_page_wire (page_list[i]);
1424: vm_page_unlock_queues ();
1425: vm_object_unlock (object);
1426: i++;
1427: offset += PAGE_SIZE;
1428: }
1429: have_page_list = 1;
1430: }
1431:
1432: /* Read any partial count. */
1433: if (resid > 0)
1434: {
1435: char *b;
1436: int use_req;
1437:
1438: assert (have_page_list);
1439: assert (pages >= 1);
1440:
1441: use_req = (disk_major (MAJOR (inode->i_rdev)) && ! np->read_only);
1442:
1443: amt = bsize - (filp->f_pos & bmask);
1444: if (amt > resid)
1445: amt = resid;
1446:
1447: if (LINUX_BLOCK_READ_TRACE)
1448: printf ("block_read: at %d: resid %d\n", __LINE__, amt, resid);
1449:
1450: if (use_req)
1451: {
1452: i = (resid + 511) & ~511;
1453: req.buffer = b = alloc_buffer (i);
1454: if (! b)
1455: {
1456: printf ("%s:%d: block_read: ran out of buffers\n",
1457: __FILE__, __LINE__);
1458: err = -LINUX_ENOMEM;
1459: goto out;
1460: }
1461: req.sector = blk << (bshift - 9);
1462: req.nr_sectors = i >> 9;
1463: req.current_nr_sectors = i >> 9;
1464: req.rq_status = RQ_ACTIVE;
1465: req.rq_dev = inode->i_rdev;
1466: req.cmd = READ;
1467: req.errors = 0;
1468: req.sem = &sem;
1469: req.bh = NULL;
1470: req.bhtail = NULL;
1471: req.next = NULL;
1472:
1473: sem.count = 0;
1474: sem.wait = NULL;
1475:
1476: enqueue_request (&req);
1477: __down (&sem);
1478:
1479: if (req.errors)
1480: {
1481: free_buffer (b, i);
1482: err = -LINUX_EIO;
1483: goto out;
1484: }
1485: }
1486: else
1487: {
1488: i = bsize;
1489: bhp = bh;
1490: bhp->b_data = b = alloc_buffer (i);
1491: if (! b)
1492: {
1493: err = -LINUX_ENOMEM;
1494: goto out;
1495: }
1496: bhp->b_blocknr = blk;
1497: bhp->b_dev = inode->i_rdev;
1498: bhp->b_size = bsize;
1499: bhp->b_state = 1 << BH_Lock;
1500: bhp->b_page_list = NULL;
1501: bhp->b_request = NULL;
1502: bhp->b_reqnext = NULL;
1503: bhp->b_wait = NULL;
1504: bhp->b_sem = NULL;
1505:
1506: ll_rw_block (READ, 1, &bhp);
1507: wait_on_buffer (bhp);
1508: err = check_for_error (READ, 1, &bhp);
1509: if (err)
1510: {
1511: free_buffer (b, i);
1512: goto out;
1513: }
1514: }
1515:
1516: page_index = (trunc_page (off) - wire_offset) >> PAGE_SHIFT;
1517: amt = PAGE_SIZE - (off & PAGE_MASK);
1518: if (amt > resid)
1519: amt = resid;
1520: memcpy (((void *) page_list[page_index]->phys_addr
1521: + (off & PAGE_MASK)),
1522: b, amt);
1523: if (amt < resid)
1524: {
1525: assert (pages >= 2);
1526: memcpy ((void *) page_list[page_index + 1]->phys_addr,
1527: b + amt, resid - amt);
1528: }
1529: else
1530: assert (pages >= 1);
1531:
1532: free_buffer (b, i);
1533: }
1534:
1535: out:
1536: if (have_page_list)
1537: {
1538: for (i = 0; i < pages; i++, wire_offset += PAGE_SIZE)
1539: {
1540: vm_object_lock (object);
1541: vm_page_lock_queues ();
1542: assert (vm_page_lookup (object, wire_offset) == page_list[i]);
1543: assert (page_list[i]->wire_count == 1);
1544: assert (! page_list[i]->active && ! page_list[i]->inactive);
1545: assert (! page_list[i]->reference);
1546: page_list[i]->dirty = TRUE;
1547: page_list[i]->reference = TRUE;
1548: page_list[i]->busy = FALSE;
1549: vm_page_unwire (page_list[i]);
1550: vm_page_unlock_queues ();
1551: vm_object_unlock (object);
1552: }
1553: }
1554: kfree ((vm_offset_t) bh,
1555: ((sizeof (*bh) + sizeof (*bhlist)) * nbuf
1556: + sizeof (*page_list) * READ_MAXPHYSPG));
1557: if (err)
1558: {
1559: if (object)
1560: {
1561: assert (object->ref_count == 1);
1562: vm_object_deallocate (object);
1563: }
1564: }
1565: else
1566: {
1567: assert (object);
1568: assert (object->ref_count == 1);
1569:
1570: filp->f_resid = 0;
1571: filp->f_object = object;
1572: }
1573:
1574: if (LINUX_BLOCK_READ_TRACE)
1575: printf ("block_read: at %d: err %d\n", __LINE__, err);
1576:
1577: return err;
1578: }
1579:
1580: /*
1581: * This routine checks whether a removable media has been changed,
1582: * and invalidates all buffer-cache-entries in that case. This
1583: * is a relatively slow routine, so we have to try to minimize using
1584: * it. Thus it is called only upon a 'mount' or 'open'. This
1585: * is the best way of combining speed and utility, I think.
1586: * People changing diskettes in the middle of an operation deserve
1587: * to loose :-)
1588: */
1589: int
1590: check_disk_change (kdev_t dev)
1591: {
1592: unsigned i;
1593: struct file_operations * fops;
1594:
1595: i = MAJOR(dev);
1596: if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL)
1597: return 0;
1598: if (fops->check_media_change == NULL)
1599: return 0;
1600: if (! (*fops->check_media_change) (dev))
1601: return 0;
1602:
1603: /* printf ("Disk change detected on device %s\n", kdevname(dev));*/
1604:
1605: if (fops->revalidate)
1606: (*fops->revalidate) (dev);
1607:
1608: return 1;
1609: }
1610:
1611: /* Mach device interface routines. */
1612:
1613: /* Mach name to Linux major/minor number mapping table. */
1614: static struct name_map name_to_major[] =
1615: {
1616: /* IDE disks */
1617: { "hd0", IDE0_MAJOR, 0, 0 },
1618: { "hd1", IDE0_MAJOR, 1, 0 },
1619: { "hd2", IDE1_MAJOR, 0, 0 },
1620: { "hd3", IDE1_MAJOR, 1, 0 },
1621: { "hd4", IDE2_MAJOR, 0, 0 },
1622: { "hd5", IDE2_MAJOR, 1, 0 },
1623: { "hd6", IDE3_MAJOR, 0, 0 },
1624: { "hd7", IDE3_MAJOR, 1, 0 },
1625:
1626: /* IDE CDROMs */
1627: { "wcd0", IDE0_MAJOR, 0, 1 },
1628: { "wcd1", IDE0_MAJOR, 1, 1 },
1629: { "wcd2", IDE1_MAJOR, 0, 1 },
1630: { "wcd3", IDE1_MAJOR, 1, 1 },
1631: { "wcd4", IDE2_MAJOR, 0, 1 },
1632: { "wcd5", IDE2_MAJOR, 1, 1 },
1633: { "wcd6", IDE3_MAJOR, 0, 1 },
1634: { "wcd7", IDE3_MAJOR, 1, 1 },
1635:
1636: /* SCSI disks */
1637: { "sd0", SCSI_DISK_MAJOR, 0, 0 },
1638: { "sd1", SCSI_DISK_MAJOR, 1, 0 },
1639: { "sd2", SCSI_DISK_MAJOR, 2, 0 },
1640: { "sd3", SCSI_DISK_MAJOR, 3, 0 },
1641: { "sd4", SCSI_DISK_MAJOR, 4, 0 },
1642: { "sd5", SCSI_DISK_MAJOR, 5, 0 },
1643: { "sd6", SCSI_DISK_MAJOR, 6, 0 },
1644: { "sd7", SCSI_DISK_MAJOR, 7, 0 },
1645:
1646: /* SCSI CDROMs */
1647: { "cd0", SCSI_CDROM_MAJOR, 0, 1 },
1648: { "cd1", SCSI_CDROM_MAJOR, 1, 1 },
1649:
1650: /* Floppy disks */
1651: { "fd0", FLOPPY_MAJOR, 0, 0 },
1652: { "fd1", FLOPPY_MAJOR, 1, 0 },
1653: };
1654:
1655: #define NUM_NAMES (sizeof (name_to_major) / sizeof (name_to_major[0]))
1656:
1657: /* One of these is associated with each open instance of a device. */
1658: struct block_data
1659: {
1660: const char *name; /* Mach name for device */
1661: int want:1; /* someone is waiting for I/O to complete */
1662: int open_count; /* number of opens */
1663: int iocount; /* number of pending I/O operations */
1664: int part; /* BSD partition number (-1 if none) */
1665: ipc_port_t port; /* port representing device */
1666: struct device_struct *ds; /* driver operation table entry */
1667: struct device device; /* generic device header */
1668: struct file file; /* Linux file structure */
1669: struct inode inode; /* Linux inode structure */
1670: struct name_map *np; /* name to inode map */
1671: struct block_data *next; /* forward link */
1672: };
1673:
1674: /* List of open devices. */
1675: static struct block_data *open_list;
1676:
1677: /* Forward declarations. */
1678:
1679: extern struct device_emulation_ops linux_block_emulation_ops;
1680:
1681: static io_return_t device_close (void *);
1682:
1683: /* Return a send right for block device BD. */
1684: static ipc_port_t
1685: dev_to_port (void *bd)
1686: {
1687: return (bd
1688: ? ipc_port_make_send (((struct block_data *) bd)->port)
1689: : IP_NULL);
1690: }
1691:
1692: /* Return 1 if C is a letter of the alphabet. */
1693: static inline int
1694: isalpha (int c)
1695: {
1696: return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
1697: }
1698:
1699: /* Return 1 if C is a digit. */
1700: static inline int
1701: isdigit (int c)
1702: {
1703: return c >= '0' && c <= '9';
1704: }
1705:
1706: int linux_device_open_trace = 0;
1707:
1708: static io_return_t
1709: device_open (ipc_port_t reply_port, mach_msg_type_name_t reply_port_type,
1710: dev_mode_t mode, char *name, device_t *devp)
1711: {
1712: char *p;
1713: int i, part = -1, slice = 0, err = 0;
1714: unsigned major, minor;
1715: kdev_t dev;
1716: ipc_port_t notify;
1717: struct file file;
1718: struct inode inode;
1719: struct name_map *np;
1720: struct device_struct *ds;
1721: struct block_data *bd = NULL, *bdp;
1722:
1723: if (linux_device_open_trace)
1724: printf ("device_open: at %d: name %s\n", __LINE__, name);
1725:
1726: /* Parse name into name, unit, DOS partition (slice) and partition. */
1727: for (p = name; isalpha (*p); p++)
1728: ;
1729: if (p == name || ! isdigit (*p))
1730: {
1731: if (linux_device_open_trace)
1732: printf ("device_open: at %d\n", __LINE__);
1733:
1734: return D_NO_SUCH_DEVICE;
1735: }
1736: do
1737: p++;
1738: while (isdigit (*p));
1739: if (*p)
1740: {
1741: char *q = p;
1742:
1743: if (! isalpha (*q))
1744: {
1745: if (linux_device_open_trace)
1746: printf ("device_open: at %d\n", __LINE__);
1747:
1748: return D_NO_SUCH_DEVICE;
1749: }
1750: if (*q == 's' && isdigit (*(q + 1)))
1751: {
1752: q++;
1753: slice = 0;
1754: do
1755: slice = slice * 10 + *q++ - '0';
1756: while (isdigit (*q));
1757: if (! *q)
1758: goto find_major;
1759: if (! isalpha (*q))
1760: {
1761: if (linux_device_open_trace)
1762: printf ("device_open: at %d\n", __LINE__);
1763:
1764: return D_NO_SUCH_DEVICE;
1765: }
1766: }
1767: if (*(q + 1))
1768: {
1769: if (linux_device_open_trace)
1770: printf ("device_open: at %d\n", __LINE__);
1771:
1772: return D_NO_SUCH_DEVICE;
1773: }
1774: part = *q - 'a';
1775: }
1776: else
1777: slice = -1;
1778:
1779: find_major:
1780: /* Convert name to major number. */
1781: for (i = 0, np = name_to_major; i < NUM_NAMES; i++, np++)
1782: {
1783: int len = strlen (np->name);
1784:
1785: if (len == p - name && ! strncmp (np->name, name, len))
1786: break;
1787: }
1788: if (i == NUM_NAMES)
1789: {
1790: if (linux_device_open_trace)
1791: printf ("device_open: at %d\n", __LINE__);
1792:
1793: return D_NO_SUCH_DEVICE;
1794: }
1795:
1796: major = np->major;
1797: ds = &blkdevs[major];
1798:
1799: /* Check that driver exists. */
1800: if (! ds->fops)
1801: {
1802: if (linux_device_open_trace)
1803: printf ("device_open: at %d\n", __LINE__);
1804:
1805: return D_NO_SUCH_DEVICE;
1806: }
1807:
1808: /* Slice and partition numbers are only used by disk drives.
1809: The test for read-only is for IDE CDROMs. */
1810: if (! disk_major (major) || np->read_only)
1811: {
1812: slice = -1;
1813: part = -1;
1814: }
1815:
1816: /* Wait for any other open/close calls to finish. */
1817: ds = &blkdevs[major];
1818: while (ds->busy)
1819: {
1820: ds->want = 1;
1821: assert_wait ((event_t) ds, FALSE);
1822: thread_block (0);
1823: }
1824: ds->busy = 1;
1825:
1826: /* Compute minor number. */
1827: if (disk_major (major) && ! ds->gd)
1828: {
1829: struct gendisk *gd;
1830:
1831: for (gd = gendisk_head; gd && gd->major != major; gd = gd->next)
1832: ;
1833: assert (gd);
1834: ds->gd = gd;
1835: }
1836: minor = np->unit;
1837: if (ds->gd)
1838: minor <<= ds->gd->minor_shift;
1839: dev = MKDEV (major, minor);
1840:
1841: /* If no DOS partition is specified, find one we can handle. */
1842: if (slice == 0 && (! ds->default_slice || ds->default_slice[np->unit] == 0))
1843: {
1844: int sysid, bsize, bshift;
1845: struct mboot *mp;
1846: struct ipart *pp;
1847: struct buffer_head *bhp;
1848:
1849: /* Open partition 0. */
1850: inode.i_rdev = dev;
1851: file.f_mode = O_RDONLY;
1852: file.f_flags = 0;
1853: if (ds->fops->open)
1854: {
1855: linux_intr_pri = SPL5;
1856: err = (*ds->fops->open) (&inode, &file);
1857: if (err)
1858: {
1859: if (linux_device_open_trace)
1860: printf ("device_open: at %d\n", __LINE__);
1861:
1862: err = linux_to_mach_error (err);
1863: goto out;
1864: }
1865: }
1866:
1867: /* Allocate a buffer for I/O. */
1868: get_block_size (inode.i_rdev, &bsize, &bshift);
1869: assert (bsize <= PAGE_SIZE);
1870: bhp = getblk (inode.i_rdev, 0, bsize);
1871: if (! bhp)
1872: {
1873: if (linux_device_open_trace)
1874: printf ("device_open: at %d\n", __LINE__);
1875:
1876: err = D_NO_MEMORY;
1877: goto slice_done;
1878: }
1879:
1880: /* Read DOS partition table. */
1881: ll_rw_block (READ, 1, &bhp);
1882: wait_on_buffer (bhp);
1883: err = check_for_error (READ, 1, &bhp);
1884: if (err)
1885: {
1886: printf ("%s: error reading boot sector\n", np->name);
1887: err = linux_to_mach_error (err);
1888: goto slice_done;
1889: }
1890:
1891: /* Check for valid partition table. */
1892: mp = (struct mboot *) bhp->b_data;
1893: if (mp->signature != BOOT_MAGIC)
1894: {
1895: printf ("%s: invalid partition table\n", np->name);
1896: err = D_NO_SUCH_DEVICE;
1897: goto slice_done;
1898: }
1899:
1900: /* Search for a Mach, BSD or Linux partition. */
1901: sysid = 0;
1902: pp = (struct ipart *) mp->parts;
1903: for (i = 0; i < FD_NUMPART; i++, pp++)
1904: {
1905: if ((pp->systid == UNIXOS
1906: || pp->systid == BSDOS
1907: || pp->systid == LINUXOS)
1908: && (! sysid || pp->bootid == ACTIVE))
1909: {
1910: sysid = pp->systid;
1911: slice = i + 1;
1912: }
1913: }
1914: if (! sysid)
1915: {
1916: printf ("%s: No Mach, BSD or Linux partition found\n", np->name);
1917: err = D_NO_SUCH_DEVICE;
1918: goto slice_done;
1919: }
1920:
1921: /* printf ("%s: default slice %d: %s OS\n", np->name, slice,
1922: (sysid == UNIXOS ? "Mach" : (sysid == BSDOS ? "BSD" : "LINUX")));*/
1923:
1924: slice_done:
1925: if (ds->fops->release)
1926: (*ds->fops->release) (&inode, &file);
1927: __brelse (bhp);
1928: if (err)
1929: goto out;
1930: if (! ds->default_slice)
1931: {
1932: ds->default_slice = (int *) kalloc (sizeof (int) * ds->gd->max_nr);
1933: if (! ds->default_slice)
1934: {
1935: if (linux_device_open_trace)
1936: printf ("device_open: at %d\n", __LINE__);
1937:
1938: err = D_NO_MEMORY;
1939: goto out;
1940: }
1941: memset (ds->default_slice, 0, sizeof (int) * ds->gd->max_nr);
1942: }
1943: ds->default_slice[np->unit] = slice;
1944: }
1945:
1946: /* Add slice to minor number. */
1947: if (slice == 0)
1948: slice = ds->default_slice[np->unit];
1949: if (slice > 0)
1950: {
1951: if (slice >= ds->gd->max_p)
1952: {
1953: if (linux_device_open_trace)
1954: printf ("device_open: at %d\n", __LINE__);
1955:
1956: err = D_NO_SUCH_DEVICE;
1957: goto out;
1958: }
1959: minor |= slice;
1960:
1961: if (linux_device_open_trace)
1962: printf ("device_open: at %d: start_sect 0x%x, nr_sects %d\n",
1963: __LINE__, ds->gd->part[minor].start_sect,
1964: ds->gd->part[minor].nr_sects);
1965: }
1966: dev = MKDEV (major, minor);
1967:
1968: /* Initialize file structure. */
1969: file.f_mode = (mode == D_READ || np->read_only) ? O_RDONLY : O_RDWR;
1970: file.f_flags = (mode & D_NODELAY) ? O_NDELAY : 0;
1971:
1972: /* Check if the device is currently open. */
1973: for (bdp = open_list; bdp; bdp = bdp->next)
1974: if (bdp->inode.i_rdev == dev
1975: && bdp->part == part
1976: && bdp->file.f_mode == file.f_mode
1977: && bdp->file.f_flags == file.f_flags)
1978: {
1979: bd = bdp;
1980: goto out;
1981: }
1982:
1983: /* Open the device. */
1984: if (ds->fops->open)
1985: {
1986: inode.i_rdev = dev;
1987: linux_intr_pri = SPL5;
1988: err = (*ds->fops->open) (&inode, &file);
1989: if (err)
1990: {
1991: if (linux_device_open_trace)
1992: printf ("device_open: at %d\n", __LINE__);
1993:
1994: err = linux_to_mach_error (err);
1995: goto out;
1996: }
1997: }
1998:
1999: /* Read disklabel. */
2000: if (part >= 0 && (! ds->label || ! ds->label[minor]))
2001: {
2002: int bsize, bshift;
2003: struct evtoc *evp;
2004: struct disklabel *lp, *dlp;
2005: struct buffer_head *bhp;
2006:
2007: assert (disk_major (major));
2008:
2009: /* Allocate a disklabel. */
2010: lp = (struct disklabel *) kalloc (sizeof (struct disklabel));
2011: if (! lp)
2012: {
2013: if (linux_device_open_trace)
2014: printf ("device_open: at %d\n", __LINE__);
2015:
2016: err = D_NO_MEMORY;
2017: goto bad;
2018: }
2019:
2020: /* Allocate a buffer for I/O. */
2021: get_block_size (dev, &bsize, &bshift);
2022: assert (bsize <= PAGE_SIZE);
2023: bhp = getblk (dev, LBLLOC >> (bshift - 9), bsize);
2024: if (! bhp)
2025: {
2026: if (linux_device_open_trace)
2027: printf ("device_open: at %d\n", __LINE__);
2028:
2029: err = D_NO_MEMORY;
2030: goto label_done;
2031: }
2032:
2033: /* Set up 'c' partition to span the entire DOS partition. */
2034: lp->d_npartitions = PART_DISK + 1;
2035: memset (lp->d_partitions, 0, MAXPARTITIONS * sizeof (struct partition));
2036: lp->d_partitions[PART_DISK].p_offset = ds->gd->part[minor].start_sect;
2037: lp->d_partitions[PART_DISK].p_size = ds->gd->part[minor].nr_sects;
2038:
2039: /* Try reading a BSD disklabel. */
2040: ll_rw_block (READ, 1, &bhp);
2041: wait_on_buffer (bhp);
2042: err = check_for_error (READ, 1, &bhp);
2043: if (err)
2044: {
2045: printf ("%s: error reading BSD label\n", np->name);
2046: err = 0;
2047: goto vtoc;
2048: }
2049: dlp = (struct disklabel *) (bhp->b_data + ((LBLLOC << 9) & (bsize - 1)));
2050: if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC)
2051: goto vtoc;
2052: /* printf ("%s: BSD LABEL\n", np->name);*/
2053: lp->d_npartitions = dlp->d_npartitions;
2054: memcpy (lp->d_partitions, dlp->d_partitions,
2055: MAXPARTITIONS * sizeof (struct partition));
2056:
2057: /* Check for NetBSD DOS partition bogosity. */
2058: for (i = 0; i < lp->d_npartitions; i++)
2059: if (lp->d_partitions[i].p_size > ds->gd->part[minor].nr_sects)
2060: ds->gd->part[minor].nr_sects = lp->d_partitions[i].p_size;
2061: goto label_done;
2062:
2063: vtoc:
2064: /* Try reading VTOC. */
2065: bhp->b_blocknr = PDLOCATION >> (bshift - 9);
2066: bhp->b_state = 1 << BH_Lock;
2067: ll_rw_block (READ, 1, &bhp);
2068: wait_on_buffer (bhp);
2069: err = check_for_error (READ, 1, &bhp);
2070: if (err)
2071: {
2072: printf ("%s: error reading evtoc\n", np->name);
2073: err = linux_to_mach_error (err);
2074: goto label_done;
2075: }
2076: evp = (struct evtoc *) (bhp->b_data + ((PDLOCATION << 9) & (bsize - 1)));
2077: if (evp->sanity != VTOC_SANE)
2078: {
2079: printf ("%s: No BSD or Mach label found\n", np->name);
2080: err = D_NO_SUCH_DEVICE;
2081: goto label_done;
2082: }
2083: /* printf ("%s: LOCAL LABEL\n", np->name);*/
2084: lp->d_npartitions = (evp->nparts > MAXPARTITIONS
2085: ? MAXPARTITIONS : evp->nparts);
2086: for (i = 0; i < lp->d_npartitions; i++)
2087: {
2088: lp->d_partitions[i].p_size = evp->part[i].p_size;
2089: lp->d_partitions[i].p_offset = evp->part[i].p_start;
2090: lp->d_partitions[i].p_fstype = FS_BSDFFS;
2091: }
2092:
2093: label_done:
2094: if (bhp)
2095: __brelse (bhp);
2096: if (err)
2097: {
2098: kfree ((vm_offset_t) lp, sizeof (struct disklabel));
2099: goto bad;
2100: }
2101: if (! ds->label)
2102: {
2103: ds->label = (struct disklabel **) kalloc (sizeof (struct disklabel *)
2104: * ds->gd->max_p
2105: * ds->gd->max_nr);
2106: if (! ds->label)
2107: {
2108: if (linux_device_open_trace)
2109: printf ("device_open: at %d\n", __LINE__);
2110:
2111: kfree ((vm_offset_t) lp, sizeof (struct disklabel));
2112: err = D_NO_MEMORY;
2113: goto bad;
2114: }
2115: memset (ds->label, 0,
2116: (sizeof (struct disklabel *)
2117: * ds->gd->max_p * ds->gd->max_nr));
2118: }
2119: ds->label[minor] = lp;
2120: }
2121:
2122: /* Check partition number. */
2123: if (part >= 0
2124: && (part >= ds->label[minor]->d_npartitions
2125: || ds->label[minor]->d_partitions[part].p_size == 0))
2126: {
2127: err = D_NO_SUCH_DEVICE;
2128: goto bad;
2129: }
2130:
2131: /* Allocate and initialize device data. */
2132: bd = (struct block_data *) kalloc (sizeof (struct block_data));
2133: if (! bd)
2134: {
2135: if (linux_device_open_trace)
2136: printf ("device_open: at %d\n", __LINE__);
2137:
2138: err = D_NO_MEMORY;
2139: goto bad;
2140: }
2141: bd->want = 0;
2142: bd->open_count = 0;
2143: bd->iocount = 0;
2144: bd->part = part;
2145: bd->ds = ds;
2146: bd->device.emul_data = bd;
2147: bd->device.emul_ops = &linux_block_emulation_ops;
2148: bd->inode.i_rdev = dev;
2149: bd->file.f_mode = file.f_mode;
2150: bd->file.f_np = np;
2151: bd->file.f_flags = file.f_flags;
2152: bd->port = ipc_port_alloc_kernel ();
2153: if (bd->port == IP_NULL)
2154: {
2155: if (linux_device_open_trace)
2156: printf ("device_open: at %d\n", __LINE__);
2157:
2158: err = KERN_RESOURCE_SHORTAGE;
2159: goto bad;
2160: }
2161: ipc_kobject_set (bd->port, (ipc_kobject_t) &bd->device, IKOT_DEVICE);
2162: notify = ipc_port_make_sonce (bd->port);
2163: ip_lock (bd->port);
2164: ipc_port_nsrequest (bd->port, 1, notify, ¬ify);
2165: assert (notify == IP_NULL);
2166:
2167: goto out;
2168:
2169: bad:
2170: if (ds->fops->release)
2171: (*ds->fops->release) (&inode, &file);
2172:
2173: out:
2174: ds->busy = 0;
2175: if (ds->want)
2176: {
2177: ds->want = 0;
2178: thread_wakeup ((event_t) ds);
2179: }
2180:
2181: if (bd && bd->open_count > 0)
2182: {
2183: if (err)
2184: *devp = NULL;
2185: else
2186: {
2187: *devp = &bd->device;
2188: bd->open_count++;
2189: }
2190: return err;
2191: }
2192:
2193: if (err)
2194: {
2195: if (bd)
2196: {
2197: if (bd->port != IP_NULL)
2198: {
2199: ipc_kobject_set (bd->port, IKO_NULL, IKOT_NONE);
2200: ipc_port_dealloc_kernel (bd->port);
2201: }
2202: kfree ((vm_offset_t) bd, sizeof (struct block_data));
2203: bd = NULL;
2204: }
2205: }
2206: else
2207: {
2208: bd->open_count = 1;
2209: bd->next = open_list;
2210: open_list = bd;
2211: }
2212:
2213: if (IP_VALID (reply_port))
2214: ds_device_open_reply (reply_port, reply_port_type, err, dev_to_port (bd));
2215: else if (! err)
2216: device_close (bd);
2217:
2218: return MIG_NO_REPLY;
2219: }
2220:
2221: static io_return_t
2222: device_close (void *d)
2223: {
2224: struct block_data *bd = d, *bdp, **prev;
2225: struct device_struct *ds = bd->ds;
2226:
2227: /* Wait for any other open/close to complete. */
2228: while (ds->busy)
2229: {
2230: ds->want = 1;
2231: assert_wait ((event_t) ds, FALSE);
2232: thread_block (0);
2233: }
2234: ds->busy = 1;
2235:
2236: if (--bd->open_count == 0)
2237: {
2238: /* Wait for pending I/O to complete. */
2239: while (bd->iocount > 0)
2240: {
2241: bd->want = 1;
2242: assert_wait ((event_t) bd, FALSE);
2243: thread_block (0);
2244: }
2245:
2246: /* Remove device from open list. */
2247: prev = &open_list;
2248: bdp = open_list;
2249: while (bdp)
2250: {
2251: if (bdp == bd)
2252: {
2253: *prev = bdp->next;
2254: break;
2255: }
2256: prev = &bdp->next;
2257: bdp = bdp->next;
2258: }
2259:
2260: assert (bdp == bd);
2261:
2262: if (ds->fops->release)
2263: (*ds->fops->release) (&bd->inode, &bd->file);
2264:
2265: ipc_kobject_set (bd->port, IKO_NULL, IKOT_NONE);
2266: ipc_port_dealloc_kernel (bd->port);
2267: kfree ((vm_offset_t) bd, sizeof (struct block_data));
2268: }
2269:
2270: ds->busy = 0;
2271: if (ds->want)
2272: {
2273: ds->want = 0;
2274: thread_wakeup ((event_t) ds);
2275: }
2276: return D_SUCCESS;
2277: }
2278:
2279: /* XXX: Assumes all drivers use block_write. */
2280: static io_return_t
2281: device_write (void *d, ipc_port_t reply_port,
2282: mach_msg_type_name_t reply_port_type, dev_mode_t mode,
2283: recnum_t bn, io_buf_ptr_t data, unsigned int count,
2284: int *bytes_written)
2285: {
2286: int major, minor;
2287: unsigned sz, maxsz, off;
2288: io_return_t err = 0;
2289: struct block_data *bd = d;
2290:
2291: if (! bd->ds->fops->write)
2292: {
2293: printf ("device_write: at %d\n", __LINE__);
2294: return D_INVALID_OPERATION;
2295: }
2296:
2297: if ((int) count <= 0)
2298: {
2299: printf ("device_write: at %d\n", __LINE__);
2300: return D_INVALID_SIZE;
2301: }
2302:
2303: major = MAJOR (bd->inode.i_rdev);
2304: minor = MINOR (bd->inode.i_rdev);
2305:
2306: if (disk_major (major))
2307: {
2308: assert (bd->ds->gd);
2309:
2310: if (bd->part >= 0)
2311: {
2312: struct disklabel *lp;
2313:
2314: assert (bd->ds->label);
2315: lp = bd->ds->label[minor];
2316: assert (lp);
2317: maxsz = lp->d_partitions[bd->part].p_size;
2318: off = (lp->d_partitions[bd->part].p_offset
2319: - bd->ds->gd->part[minor].start_sect);
2320:
2321: if (linux_block_write_trace)
2322: printf ("device_write: at %d: dev %s, part %d, "
2323: "offset 0x%x (%u), start_sect 0x%x (%u), "
2324: "maxsz 0x%x (%u)\n",
2325: __LINE__,
2326: kdevname (bd->inode.i_rdev),
2327: bd->part,
2328: lp->d_partitions[bd->part].p_offset,
2329: lp->d_partitions[bd->part].p_offset,
2330: bd->ds->gd->part[minor].start_sect,
2331: bd->ds->gd->part[minor].start_sect,
2332: maxsz, maxsz);
2333:
2334: assert (off < bd->ds->gd->part[minor].nr_sects);
2335: }
2336: else
2337: {
2338: maxsz = bd->ds->gd->part[minor].nr_sects;
2339: off = 0;
2340: }
2341: }
2342: else
2343: {
2344: assert (blk_size[major]);
2345: maxsz = blk_size[major][minor] << (BLOCK_SIZE_BITS - 9);
2346: off = 0;
2347: }
2348:
2349: if (bn >= maxsz)
2350: {
2351: if (linux_block_write_trace)
2352: printf ("device_write: at %d\n", __LINE__);
2353:
2354: return D_INVALID_SIZE;
2355: }
2356:
2357: bd->iocount++;
2358:
2359: sz = (count + 511) >> 9;
2360: if (sz > maxsz - bn)
2361: {
2362: sz = maxsz - bn;
2363: if (count > (sz << 9))
2364: count = sz << 9;
2365: }
2366:
2367: bd->file.f_pos = (loff_t) (bn + off) << 9;
2368:
2369: err = (*bd->ds->fops->write) (&bd->inode, &bd->file, (char *) data, count);
2370: if (err)
2371: err = linux_to_mach_error (err);
2372:
2373: if (linux_block_write_trace)
2374: printf ("device_write: at %d: err %d\n", __LINE__, err);
2375:
2376: if (IP_VALID (reply_port))
2377: ds_device_write_reply (reply_port, reply_port_type,
2378: err, count - bd->file.f_resid);
2379:
2380: if (--bd->iocount == 0 && bd->want)
2381: {
2382: bd->want = 0;
2383: thread_wakeup ((event_t) bd);
2384: }
2385: return MIG_NO_REPLY;
2386: }
2387:
2388: /* XXX: Assumes all drivers use block_read. */
2389: static io_return_t
2390: device_read (void *d, ipc_port_t reply_port,
2391: mach_msg_type_name_t reply_port_type, dev_mode_t mode,
2392: recnum_t bn, int count, io_buf_ptr_t *data,
2393: unsigned *bytes_read)
2394: {
2395: int major, minor;
2396: unsigned sz, maxsz, off;
2397: io_return_t err = 0;
2398: vm_offset_t addr;
2399: vm_object_t object;
2400: vm_map_copy_t copy;
2401: struct block_data *bd = d;
2402: struct inode *inode = &bd->inode;
2403:
2404: *data = 0;
2405: *bytes_read = 0;
2406:
2407: if (! bd->ds->fops->read)
2408: return D_INVALID_OPERATION;
2409:
2410: if (count <= 0)
2411: return D_INVALID_SIZE;
2412:
2413: major = MAJOR (bd->inode.i_rdev);
2414: minor = MINOR (bd->inode.i_rdev);
2415:
2416: if (LINUX_BLOCK_READ_TRACE)
2417: printf ("device_read: at %d: major %d, minor %d, count %d, recnum %u\n",
2418: __LINE__, major, minor, count, bn);
2419:
2420: if (disk_major (major))
2421: {
2422: assert (bd->ds->gd);
2423:
2424: if (bd->part >= 0)
2425: {
2426: struct disklabel *lp;
2427:
2428: assert (bd->ds->label);
2429: lp = bd->ds->label[minor];
2430: assert (lp);
2431: maxsz = lp->d_partitions[bd->part].p_size;
2432: off = (lp->d_partitions[bd->part].p_offset
2433: - bd->ds->gd->part[minor].start_sect);
2434:
2435: if (LINUX_BLOCK_READ_TRACE)
2436: printf ("device_read: at %d: dev %s, part %d, offset 0x%x, "
2437: "size %d, start_sect 0x%x, nr_sects %d\n",
2438: __LINE__, kdevname (major), bd->part, off, maxsz,
2439: bd->ds->gd->part[minor].start_sect,
2440: bd->ds->gd->part[minor].nr_sects);
2441:
2442: assert (off < bd->ds->gd->part[minor].nr_sects);
2443: }
2444: else
2445: {
2446: maxsz = bd->ds->gd->part[minor].nr_sects;
2447: off = 0;
2448: }
2449: }
2450: else
2451: {
2452: assert (blk_size[major]);
2453: maxsz = blk_size[major][minor] << (BLOCK_SIZE_BITS - 9);
2454: off = 0;
2455: }
2456:
2457: if (bn > maxsz)
2458: return D_INVALID_SIZE;
2459:
2460: /* Be backward compatible with Unix. */
2461: if (bn == maxsz)
2462: {
2463: if (LINUX_BLOCK_READ_TRACE)
2464: printf ("device_read: at %d\n", __LINE__);
2465: return 0;
2466: }
2467:
2468: sz = (count + 511) >> 9;
2469: if (sz > maxsz - bn)
2470: {
2471: sz = maxsz - bn;
2472: if (count > (sz << 9))
2473: count = sz << 9;
2474: }
2475:
2476: bd->file.f_pos = (loff_t) (bn + off) << 9;
2477: bd->file.f_object = NULL;
2478:
2479: if (LINUX_BLOCK_READ_TRACE)
2480: printf ("device_read: at %d: f_pos 0x%x\n",
2481: __LINE__, (unsigned) bd->file.f_pos);
2482:
2483: bd->iocount++;
2484:
2485: err = (*bd->ds->fops->read) (&bd->inode, &bd->file, (char *) data, count);
2486: if (err)
2487: err = linux_to_mach_error (err);
2488: else
2489: {
2490: object = bd->file.f_object;
2491: assert (object);
2492: assert (object->ref_count == 1);
2493: err = vm_map_copyin_object (object, 0, round_page (count), ©);
2494: assert (object->ref_count == 1);
2495: if (err)
2496: vm_object_deallocate (object);
2497: else
2498: {
2499: assert (copy->cpy_object->ref_count == 1);
2500: *data = (io_buf_ptr_t) copy;
2501: *bytes_read = count - bd->file.f_resid;
2502: }
2503: }
2504: if (--bd->iocount == 0 && bd->want)
2505: {
2506: bd->want = 0;
2507: thread_wakeup ((event_t) bd);
2508: }
2509: return err;
2510: }
2511:
2512: static io_return_t
2513: device_get_status (void *d, dev_flavor_t flavor, dev_status_t status,
2514: mach_msg_type_number_t *status_count)
2515: {
2516: struct block_data *bd = d;
2517:
2518: switch (flavor)
2519: {
2520: case DEV_GET_SIZE:
2521: if (*status_count != DEV_GET_SIZE_COUNT)
2522: return D_INVALID_SIZE;
2523: if (disk_major (MAJOR (bd->inode.i_rdev)))
2524: {
2525: assert (bd->ds->gd);
2526:
2527: if (bd->part >= 0)
2528: {
2529: struct disklabel *lp;
2530:
2531: assert (bd->ds->label);
2532: lp = bd->ds->label[MINOR (bd->inode.i_rdev)];
2533: assert (lp);
2534: (status[DEV_GET_SIZE_DEVICE_SIZE]
2535: = lp->d_partitions[bd->part].p_size << 9);
2536: }
2537: else
2538: (status[DEV_GET_SIZE_DEVICE_SIZE]
2539: = bd->ds->gd->part[MINOR (bd->inode.i_rdev)].nr_sects << 9);
2540: }
2541: else
2542: {
2543: assert (blk_size[MAJOR (bd->inode.i_rdev)]);
2544: (status[DEV_GET_SIZE_DEVICE_SIZE]
2545: = (blk_size[MAJOR (bd->inode.i_rdev)][MINOR (bd->inode.i_rdev)]
2546: << BLOCK_SIZE_BITS));
2547: }
2548: /* It would be nice to return the block size as reported by
2549: the driver, but a lot of user level code assumes the sector
2550: size to be 512. */
2551: status[DEV_GET_SIZE_RECORD_SIZE] = 512;
2552: break;
2553:
2554: default:
2555: return D_INVALID_OPERATION;
2556: }
2557:
2558: return D_SUCCESS;
2559: }
2560:
2561: struct device_emulation_ops linux_block_emulation_ops =
2562: {
2563: NULL,
2564: NULL,
2565: dev_to_port,
2566: device_open,
2567: device_close,
2568: device_write,
2569: NULL,
2570: device_read,
2571: NULL,
2572: NULL,
2573: device_get_status,
2574: NULL,
2575: NULL,
2576: NULL,
2577: NULL,
2578: NULL
2579: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.