--- Gnu-Mach/linux/dev/glue/block.c 2020/09/02 04:41:39 1.1 +++ Gnu-Mach/linux/dev/glue/block.c 2020/09/02 04:48:33 1.1.1.4 @@ -49,6 +49,8 @@ #include #include +#include + #include #include @@ -59,9 +61,12 @@ #include #include #include -#include "device_reply.h" +#include +#include +#include -#include +/* TODO. This should be fixed to not be i386 specific. */ +#include #define MACH_INCLUDE #include @@ -76,9 +81,7 @@ #include #include -extern int linux_auto_config; -extern int linux_intr_pri; -extern int linux_to_mach_error (int); +#include /* This task queue is not used in Mach: just for fixing undefined symbols. */ DECLARE_TASK_QUEUE (tq_disk); @@ -191,9 +194,6 @@ int read_ahead[MAX_BLKDEV] = {0, }; This is unused in Mach. It is here to make drivers compile. */ struct wait_queue *wait_for_request = NULL; -/* Map for allocating device memory. */ -extern vm_map_t device_io_map; - /* Initialize block drivers. */ int blk_dev_init () @@ -228,19 +228,17 @@ int register_blkdev (unsigned major, const char *name, struct file_operations *fops) { - int err = 0; - if (major == 0) { for (major = MAX_BLKDEV - 1; major > 0; major--) if (blkdevs[major].fops == NULL) goto out; - return -LINUX_EBUSY; + return -EBUSY; } if (major >= MAX_BLKDEV) - return -LINUX_EINVAL; + return -EINVAL; if (blkdevs[major].fops && blkdevs[major].fops != fops) - return -LINUX_EBUSY; + return -EBUSY; out: blkdevs[major].name = name; @@ -258,12 +256,10 @@ out: int unregister_blkdev (unsigned major, const char *name) { - int err; - if (major >= MAX_BLKDEV) - return -LINUX_EINVAL; + return -EINVAL; if (! blkdevs[major].fops || strcmp (blkdevs[major].name, name)) - return -LINUX_EINVAL; + return -EINVAL; blkdevs[major].fops = NULL; if (blkdevs[major].labels) { @@ -278,8 +274,6 @@ unregister_blkdev (unsigned major, const void set_blocksize (kdev_t dev, int size) { - extern int *blksize_size[]; - if (! blksize_size[MAJOR (dev)]) return; @@ -308,12 +302,12 @@ alloc_buffer (int size) if (! linux_auto_config) { - while ((m = vm_page_grab ()) == 0) + while ((m = vm_page_grab (FALSE)) == 0) VM_PAGE_WAIT (0); d = current_thread ()->pcb->data; assert (d); queue_enter (&d->pages, m, vm_page_t, pageq); - return (void *) m->phys_addr; + return (void *) phystokv(m->phys_addr); } return (void *) __get_free_pages (GFP_KERNEL, 0, ~0UL); } @@ -322,7 +316,6 @@ alloc_buffer (int size) static void free_buffer (void *p, int size) { - int i; struct temp_data *d; vm_page_t m; @@ -333,13 +326,11 @@ free_buffer (void *p, int size) d = current_thread ()->pcb->data; assert (d); queue_iterate (&d->pages, m, vm_page_t, pageq) - { - if (m->phys_addr == (vm_offset_t) p) + { + if (phystokv(m->phys_addr) == (vm_offset_t) p) { queue_remove (&d->pages, m, vm_page_t, pageq); - vm_page_lock_queues (); - vm_page_free (m); - vm_page_lock_queues (); + VM_PAGE_FREE (m); return; } } @@ -354,22 +345,17 @@ struct buffer_head * getblk (kdev_t dev, int block, int size) { struct buffer_head *bh; - static struct buffer_head bhead; assert (size <= PAGE_SIZE); - if (! linux_auto_config) - bh = (struct buffer_head *) kalloc (sizeof (struct buffer_head)); - else - bh = &bhead; + bh = (struct buffer_head *) kalloc (sizeof (struct buffer_head)); if (bh) { memset (bh, 0, sizeof (struct buffer_head)); bh->b_data = alloc_buffer (size); if (! bh->b_data) { - if (! linux_auto_config) - kfree ((vm_offset_t) bh, sizeof (struct buffer_head)); + kfree ((vm_offset_t) bh, sizeof (struct buffer_head)); return NULL; } bh->b_dev = dev; @@ -385,8 +371,7 @@ void __brelse (struct buffer_head *bh) { free_buffer (bh->b_data, bh->b_size); - if (! linux_auto_config) - kfree ((vm_offset_t) bh, sizeof (*bh)); + kfree ((vm_offset_t) bh, sizeof (*bh)); } /* Allocate a buffer of SIZE bytes and fill it with data @@ -394,13 +379,12 @@ __brelse (struct buffer_head *bh) struct buffer_head * bread (kdev_t dev, int block, int size) { - int err; struct buffer_head *bh; bh = getblk (dev, block, size); if (bh) { - ll_rw_block (READ, 1, &bh); + ll_rw_block (READ, 1, &bh, 0); wait_on_buffer (bh); if (! buffer_uptodate (bh)) { @@ -460,7 +444,7 @@ enqueue_request (struct request *req) /* Perform the I/O operation RW on the buffer list BH containing NR buffers. */ void -ll_rw_block (int rw, int nr, struct buffer_head **bh) +ll_rw_block (int rw, int nr, struct buffer_head **bh, int quiet) { int i, bshift, bsize; unsigned major; @@ -492,6 +476,7 @@ ll_rw_block (int rw, int nr, struct buff r->rq_dev = bh[0]->b_dev; r->cmd = rw; r->errors = 0; + r->quiet = quiet; r->sector = bh[0]->b_blocknr << (bshift - 9); r->current_nr_sectors = bh[0]->b_size >> 9; r->buffer = bh[0]->b_data; @@ -543,14 +528,13 @@ rdwr_partial (int rw, kdev_t dev, loff_t } bh->b_data = alloc_buffer (bh->b_size); if (! bh->b_data) - return -LINUX_ENOMEM; - ll_rw_block (READ, 1, &bh); + return -ENOMEM; + ll_rw_block (READ, 1, &bh, 0); wait_on_buffer (bh); if (buffer_uptodate (bh)) { o = *off & BMASK; c = bh->b_size - o; - assert (*resid <= c); if (c > *resid) c = *resid; if (rw == READ) @@ -559,11 +543,11 @@ rdwr_partial (int rw, kdev_t dev, loff_t { memcpy (bh->b_data + o, *buf, c); bh->b_state = (1 << BH_Dirty) | (1 << BH_Lock); - ll_rw_block (WRITE, 1, &bh); + ll_rw_block (WRITE, 1, &bh, 0); wait_on_buffer (bh); if (! buffer_uptodate (bh)) { - err = -LINUX_EIO; + err = -EIO; goto out; } } @@ -572,14 +556,14 @@ rdwr_partial (int rw, kdev_t dev, loff_t *off += c; } else - err = -LINUX_EIO; + err = -EIO; out: free_buffer (bh->b_data, bh->b_size); return err; } #define BH_Bounce 16 -#define MAX_BUF VM_MAP_COPY_PAGE_LIST_MAX +#define MAX_BUF 8 /* Perform read/write operation RW on device DEV starting at *off to/from buffer *BUF of size *RESID. @@ -595,7 +579,6 @@ rdwr_full (int rw, kdev_t dev, loff_t *o struct buffer_head bhead[MAX_BUF], *bh, *bhp[MAX_BUF]; assert ((*off & BMASK) == 0); - assert (*resid >= bsize); nbuf = *resid >> bshift; blk = *off >> bshift; @@ -607,8 +590,8 @@ rdwr_full (int rw, kdev_t dev, loff_t *o set_bit (BH_Lock, &bh->b_state); if (rw == WRITE) set_bit (BH_Dirty, &bh->b_state); - cc = PAGE_SIZE - (((int) *buf) & PAGE_MASK); - if (cc >= BSIZE && ((int) *buf & 511) == 0) + cc = PAGE_SIZE - (((int) *buf + (nb << bshift)) & PAGE_MASK); + if (cc >= BSIZE && (((int) *buf + (nb << bshift)) & 511) == 0) cc &= ~BMASK; else { @@ -618,15 +601,15 @@ rdwr_full (int rw, kdev_t dev, loff_t *o if (cc > ((nbuf - nb) << bshift)) cc = (nbuf - nb) << bshift; if (! test_bit (BH_Bounce, &bh->b_state)) - bh->b_data = (char *) pmap_extract (vm_map_pmap (device_io_map), + bh->b_data = (char *) phystokv(pmap_extract (vm_map_pmap (device_io_map), (((vm_offset_t) *buf) - + (nb << bshift))); + + (nb << bshift)))); else { bh->b_data = alloc_buffer (cc); if (! bh->b_data) { - err = -LINUX_ENOMEM; + err = -ENOMEM; break; } if (rw == WRITE) @@ -635,13 +618,14 @@ rdwr_full (int rw, kdev_t dev, loff_t *o bh->b_size = cc; bhp[i] = bh; nb += cc >> bshift; - blk += nb; + blk += cc >> bshift; if (++i == MAX_BUF) break; } if (! err) { - ll_rw_block (rw, i, bhp); + assert (i > 0); + ll_rw_block (rw, i, bhp, 0); wait_on_buffer (bhp[i - 1]); } for (bh = bhead, cc = 0, j = 0; j < i; cc += bh->b_size, bh++, j++) @@ -650,7 +634,7 @@ rdwr_full (int rw, kdev_t dev, loff_t *o && rw == READ && test_bit (BH_Bounce, &bh->b_state)) memcpy (*buf + cc, bh->b_data, bh->b_size); else if (! err && ! buffer_uptodate (bh)) - err = -LINUX_EIO; + err = -EIO; if (test_bit (BH_Bounce, &bh->b_state)) free_buffer (bh->b_data, bh->b_size); } @@ -797,6 +781,7 @@ static struct block_data *open_list; extern struct device_emulation_ops linux_block_emulation_ops; static io_return_t device_close (void *); +static io_return_t device_close_forced (void *, int); /* Return a send right for block device BD. */ static ipc_port_t @@ -930,7 +915,7 @@ static kern_return_t init_partition (struct name_map *np, kdev_t *dev, struct device_struct *ds, int slice, int *part) { - int err, i, j; + int i, j; struct disklabel *lp; struct gendisk *gd = ds->gd; struct partition *p; @@ -955,13 +940,13 @@ init_partition (struct name_map *np, kde if (gd->part[MINOR (d->inode.i_rdev)].nr_sects <= 0 || gd->part[MINOR (d->inode.i_rdev)].start_sect < 0) continue; - linux_intr_pri = SPL5; + linux_intr_pri = SPL6; d->file.f_flags = 0; d->file.f_mode = O_RDONLY; if (ds->fops->open && (*ds->fops->open) (&d->inode, &d->file)) continue; lp = read_bsd_label (d->inode.i_rdev); - if (! lp) + if (! lp && gd->part[MINOR (d->inode.i_rdev)].nr_sects > PDLOCATION) lp = read_vtoc (d->inode.i_rdev); if (ds->fops->release) (*ds->fops->release) (&d->inode, &d->file); @@ -1101,7 +1086,7 @@ device_open (ipc_port_t reply_port, mach if (ds->fops->open) { td.inode.i_rdev = dev; - linux_intr_pri = SPL5; + linux_intr_pri = SPL6; err = (*ds->fops->open) (&td.inode, &td.file); if (err) { @@ -1172,6 +1157,7 @@ out: { ipc_kobject_set (bd->port, IKO_NULL, IKOT_NONE); ipc_port_dealloc_kernel (bd->port); + *devp = IP_NULL; } kfree ((vm_offset_t) bd, sizeof (struct block_data)); bd = NULL; @@ -1182,18 +1168,16 @@ out: bd->open_count = 1; bd->next = open_list; open_list = bd; + *devp = &bd -> device; } - if (IP_VALID (reply_port)) - ds_device_open_reply (reply_port, reply_port_type, err, dev_to_port (bd)); - else if (! err) + if (!IP_VALID (reply_port) && ! err) device_close (bd); - - return MIG_NO_REPLY; + return err; } static io_return_t -device_close (void *d) +device_close_forced (void *d, int force) { struct block_data *bd = d, *bdp, **prev; struct device_struct *ds = bd->ds; @@ -1210,7 +1194,7 @@ device_close (void *d) } ds->busy = 1; - if (--bd->open_count == 0) + if (force || --bd->open_count == 0) { /* Wait for pending I/O to complete. */ while (bd->iocount > 0) @@ -1253,6 +1237,13 @@ device_close (void *d) return D_SUCCESS; } +static io_return_t +device_close (void *d) +{ + return device_close_forced (d, 0); +} + + #define MAX_COPY (VM_MAP_COPY_PAGE_LIST_MAX << PAGE_SHIFT) /* Check block BN and size COUNT for I/O validity @@ -1492,7 +1483,7 @@ device_read (void *d, ipc_port_t reply_p /* Allocate and map pages. */ while (alloc_offset < trunc_page (offset) + len) { - while ((m = vm_page_grab ()) == 0) + while ((m = vm_page_grab (FALSE)) == 0) VM_PAGE_WAIT (0); assert (! m->active && ! m->inactive); m->busy = TRUE; @@ -1632,6 +1623,44 @@ device_get_status (void *d, dev_flavor_t *status_count = DEV_GET_SIZE_COUNT; break; + case DEV_GET_RECORDS: + if (disk_major (MAJOR (bd->dev))) + { + assert (bd->ds->gd); + + if (bd->part >= 0) + { + struct disklabel *lp; + + assert (bd->ds->labels); + lp = bd->ds->labels[MINOR (bd->dev)]; + assert (lp); + (status[DEV_GET_RECORDS_DEVICE_RECORDS] + = lp->d_partitions[bd->part].p_size); + } + else + (status[DEV_GET_RECORDS_DEVICE_RECORDS] + = bd->ds->gd->part[MINOR (bd->dev)].nr_sects); + } + else + { + assert (blk_size[MAJOR (bd->dev)]); + status[DEV_GET_RECORDS_DEVICE_RECORDS] + = (blk_size[MAJOR (bd->dev)][MINOR (bd->dev)] + << (BLOCK_SIZE_BITS - 9)); + } + /* It would be nice to return the block size as reported by + the driver, but a lot of user level code assumes the sector + size to be 512. */ + status[DEV_GET_RECORDS_RECORD_SIZE] = 512; + /* Always return DEV_GET_RECORDS_COUNT. This is what all native + Mach drivers do, and makes it possible to detect the absence + of the call by setting it to a different value on input. MiG + makes sure that we will never return more integers than the + user asked for. */ + *status_count = DEV_GET_RECORDS_COUNT; + break; + case V_GETPARMS: if (*status_count < (sizeof (struct disk_parms) / sizeof (int))) return D_INVALID_OPERATION; @@ -1644,7 +1673,7 @@ device_get_status (void *d, dev_flavor_t INIT_DATA(); if ((*bd->ds->fops->ioctl) (&td.inode, &td.file, - HDIO_GETGEO, &hg)) + HDIO_GETGEO, (unsigned long)&hg)) return D_INVALID_OPERATION; dp->dp_type = DPT_WINI; /* XXX: It may be a floppy... */ @@ -1657,16 +1686,16 @@ device_get_status (void *d, dev_flavor_t dp->dp_secsiz = 512; /* XXX */ dp->dp_ptag = 0; dp->dp_pflag = 0; - + /* XXX */ dp->dp_pstartsec = -1; dp->dp_pnumsec = -1; *status_count = sizeof (struct disk_parms) / sizeof (int); } - + break; - + default: return D_INVALID_OPERATION; } @@ -1674,6 +1703,36 @@ device_get_status (void *d, dev_flavor_t return D_SUCCESS; } +static io_return_t +device_set_status (void *d, dev_flavor_t flavor, dev_status_t status, + mach_msg_type_number_t status_count) +{ + struct block_data *bd = d; + + switch (flavor) + { + case BLKRRPART: + { + DECL_DATA; + INIT_DATA(); + return (*bd->ds->fops->ioctl) (&td.inode, &td.file, flavor, 0); + } + } + + return D_INVALID_OPERATION; +} + + +static void +device_no_senders (mach_no_senders_notification_t *ns) +{ + device_t dev; + + dev = dev_port_lookup((ipc_port_t) ns->not_header.msgh_remote_port); + assert(dev); + device_close_forced (dev->emul_data, 1); +} + struct device_emulation_ops linux_block_emulation_ops = { NULL, @@ -1685,11 +1744,11 @@ struct device_emulation_ops linux_block_ NULL, device_read, NULL, - NULL, + device_set_status, device_get_status, NULL, NULL, - NULL, + device_no_senders, NULL, NULL };