⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 block.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Perform read/write operation RW on device DEV   starting at *off to/from buffer *BUF of size *RESID.   The device block size is given by BSHIFT.  *OFF and   *RESID must be multiples of the block size.   *OFF, *BUF and *RESID are updated if the operation   completed successfully.  */static intrdwr_full (int rw, kdev_t dev, loff_t *off, char **buf, int *resid, int bshift){  int cc, err = 0, i, j, nb, nbuf;  long blk;  struct buffer_head bhead[MAX_BUF], *bh, *bhp[MAX_BUF];  assert ((*off & BMASK) == 0);  nbuf = *resid >> bshift;  blk = *off >> bshift;  for (i = nb = 0, bh = bhead; nb < nbuf; bh++)    {      memset (bh, 0, sizeof (*bh));      bh->b_dev = dev;      bh->b_blocknr = blk;      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 &= ~BMASK;      else	{	  cc = PAGE_SIZE;	  set_bit (BH_Bounce, &bh->b_state);	}      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),					    (((vm_offset_t) *buf)					     + (nb << bshift)));      else	{	  bh->b_data = alloc_buffer (cc);	  if (! bh->b_data)	    {	      err = -LINUX_ENOMEM;	      break;	    }	  if (rw == WRITE)	    memcpy (bh->b_data, *buf + (nb << bshift), cc);	}      bh->b_size = cc;      bhp[i] = bh;      nb += cc >> bshift;      blk += nb;      if (++i == MAX_BUF)	break;    }  if (! err)    {      ll_rw_block (rw, i, bhp);      wait_on_buffer (bhp[i - 1]);    }  for (bh = bhead, cc = 0, j = 0; j < i; cc += bh->b_size, bh++, j++)    {      if (! err && buffer_uptodate (bh)	  && 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;      if (test_bit (BH_Bounce, &bh->b_state))	free_buffer (bh->b_data, bh->b_size);    }  if (! err)    {      *buf += cc;      *resid -= cc;      *off += cc;    }  return err;}/* Perform read/write operation RW on device DEV   starting at *off to/from buffer BUF of size COUNT.   *OFF is updated if the operation completed successfully.  */static intdo_rdwr (int rw, kdev_t dev, loff_t *off, char *buf, int count){  int bsize, bshift, err = 0, resid = count;  get_block_size (dev, &bsize, &bshift);  if (*off & BMASK)    err = rdwr_partial (rw, dev, off, &buf, &resid, bshift);  while (resid >= bsize && ! err)    err = rdwr_full (rw, dev, off, &buf, &resid, bshift);  if (! err && resid)    err = rdwr_partial (rw, dev, off, &buf, &resid, bshift);  return err ? err : count - resid;}intblock_write (struct inode *inode, struct file *filp,	     const char *buf, int count){  return do_rdwr (WRITE, inode->i_rdev, &filp->f_pos, (char *) buf, count);}intblock_read (struct inode *inode, struct file *filp, char *buf, int count){  return do_rdwr (READ, inode->i_rdev, &filp->f_pos, buf, count);}/* * This routine checks whether a removable media has been changed, * and invalidates all buffer-cache-entries in that case. This * is a relatively slow routine, so we have to try to minimize using * it. Thus it is called only upon a 'mount' or 'open'. This * is the best way of combining speed and utility, I think. * People changing diskettes in the middle of an operation deserve * to loose :-) */intcheck_disk_change (kdev_t dev){  unsigned i;  struct file_operations * fops;  i = MAJOR(dev);  if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL)    return 0;  if (fops->check_media_change == NULL)    return 0;  if (! (*fops->check_media_change) (dev))    return 0;  /*  printf ("Disk change detected on device %s\n", kdevname(dev));*/  if (fops->revalidate)    (*fops->revalidate) (dev);  return 1;}/* Mach device interface routines.  *//* Mach name to Linux major/minor number mapping table.  */static struct name_map name_to_major[] ={  /* IDE disks */  { "hd0", IDE0_MAJOR, 0, 0 },  { "hd1", IDE0_MAJOR, 1, 0 },  { "hd2", IDE1_MAJOR, 0, 0 },  { "hd3", IDE1_MAJOR, 1, 0 },  { "hd4", IDE2_MAJOR, 0, 0 },  { "hd5", IDE2_MAJOR, 1, 0 },  { "hd6", IDE3_MAJOR, 0, 0 },  { "hd7", IDE3_MAJOR, 1, 0 },  /* IDE CDROMs */  { "wcd0", IDE0_MAJOR, 0, 1 },  { "wcd1", IDE0_MAJOR, 1, 1 },  { "wcd2", IDE1_MAJOR, 0, 1 },  { "wcd3", IDE1_MAJOR, 1, 1 },  { "wcd4", IDE2_MAJOR, 0, 1 },  { "wcd5", IDE2_MAJOR, 1, 1 },  { "wcd6", IDE3_MAJOR, 0, 1 },  { "wcd7", IDE3_MAJOR, 1, 1 },  /* SCSI disks */  { "sd0", SCSI_DISK_MAJOR, 0, 0 },  { "sd1", SCSI_DISK_MAJOR, 1, 0 },  { "sd2", SCSI_DISK_MAJOR, 2, 0 },  { "sd3", SCSI_DISK_MAJOR, 3, 0 },  { "sd4", SCSI_DISK_MAJOR, 4, 0 },  { "sd5", SCSI_DISK_MAJOR, 5, 0 },  { "sd6", SCSI_DISK_MAJOR, 6, 0 },  { "sd7", SCSI_DISK_MAJOR, 7, 0 },  /* SCSI CDROMs */  { "cd0", SCSI_CDROM_MAJOR, 0, 1 },  { "cd1", SCSI_CDROM_MAJOR, 1, 1 },  /* Floppy disks */  { "fd0", FLOPPY_MAJOR, 0, 0 },  { "fd1", FLOPPY_MAJOR, 1, 0 },};#define NUM_NAMES (sizeof (name_to_major) / sizeof (name_to_major[0]))/* One of these is associated with each open instance of a device.  */struct block_data{  const char *name;		/* Mach name for device */  int want:1;			/* someone is waiting for I/O to complete */  int open_count;		/* number of opens */  int iocount;			/* number of pending I/O operations */  int part;			/* BSD partition number (-1 if none) */  int flags;			/* Linux file flags */  int mode;			/* Linux file mode */  kdev_t dev;			/* Linux device number */  ipc_port_t port;		/* port representing device */  struct device_struct *ds;	/* driver operation table entry */  struct device device;		/* generic device header */  struct name_map *np;		/* name to inode map */  struct block_data *next;	/* forward link */};/* List of open devices.  */static struct block_data *open_list;/* Forward declarations.  */extern struct device_emulation_ops linux_block_emulation_ops;static io_return_t device_close (void *);/* Return a send right for block device BD.  */static ipc_port_tdev_to_port (void *bd){  return (bd	  ? ipc_port_make_send (((struct block_data *) bd)->port)	  : IP_NULL);}/* Return 1 if C is a letter of the alphabet.  */static inline intisalpha (int c){  return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');}/* Return 1 if C is a digit.  */static inline intisdigit (int c){  return c >= '0' && c <= '9';}/* Find the name map entry for device NAME.   Set *SLICE to be the DOS partition and   *PART the BSD/Mach partition, if any.  */static struct name_map *find_name (char *name, int *slice, int *part){  char *p, *q;  int i, len;  struct name_map *np;  /* Parse name into name, unit, DOS partition (slice) and partition.  */  for (*slice = 0, *part = -1, p = name; isalpha (*p); p++)    ;  if (p == name || ! isdigit (*p))    return NULL;  do    p++;  while (isdigit (*p));  if (*p)    {      q = p;      if (*q == 's' && isdigit (*(q + 1)))	{	  q++;	  do	    *slice = *slice * 10 + *q++ - '0';	  while (isdigit (*q));	  if (! *q)	    goto find_major;	}      if (! isalpha (*q) || *(q + 1))	return NULL;      *part = *q - 'a';    }find_major:  /* Convert name to major number.  */  for (i = 0, np = name_to_major; i < NUM_NAMES; i++, np++)    {      len = strlen (np->name);      if (len == (p - name) && ! strncmp (np->name, name, len))	return np;    }  return NULL;}/* Attempt to read a BSD disklabel from device DEV.  */static struct disklabel *read_bsd_label (kdev_t dev){  int bsize, bshift;  struct buffer_head *bh;  struct disklabel *dlp, *lp = NULL;  get_block_size (dev, &bsize, &bshift);  bh = bread (dev, LBLLOC >> (bshift - 9), bsize);  if (bh)    {      dlp = (struct disklabel *) (bh->b_data + ((LBLLOC << 9) & (bsize - 1)));      if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC)	{	  lp = (struct disklabel *) kalloc (sizeof (*lp));	  assert (lp);	  memcpy (lp, dlp, sizeof (*lp));	}      __brelse (bh);    }  return lp;}/* Attempt to read a VTOC from device DEV.  */static struct disklabel *read_vtoc (kdev_t dev){  int bshift, bsize, i;  struct buffer_head *bh;  struct evtoc *evp;  struct disklabel *lp = NULL;  get_block_size (dev, &bsize, &bshift);  bh = bread (dev, PDLOCATION >> (bshift - 9), bsize);  if (bh)    {      evp = (struct evtoc *) (bh->b_data + ((PDLOCATION << 9) & (bsize - 1)));      if (evp->sanity == VTOC_SANE)	{	  lp = (struct disklabel *) kalloc (sizeof (*lp));	  assert (lp);	  lp->d_npartitions = evp->nparts;	  if (lp->d_npartitions > MAXPARTITIONS)	    lp->d_npartitions = MAXPARTITIONS;	  for (i = 0; i < lp->d_npartitions; i++)	    {	      lp->d_partitions[i].p_size = evp->part[i].p_size;	      lp->d_partitions[i].p_offset = evp->part[i].p_start;	      lp->d_partitions[i].p_fstype = FS_BSDFFS;	    }	}      __brelse (bh);    }  return lp;}/* Initialize BSD/Mach partition table for device   specified by NP, DS and *DEV.  Check SLICE and *PART for validity.  */static kern_return_tinit_partition (struct name_map *np, kdev_t *dev,		struct device_struct *ds, int slice, int *part){  int err, i, j;  struct disklabel *lp;  struct gendisk *gd = ds->gd;  struct partition *p;  struct temp_data *d = current_thread ()->pcb->data;  if (! gd)    {      *part = -1;      return 0;    }  if (ds->labels)    goto check;  ds->labels = (struct disklabel **) kalloc (sizeof (struct disklabel *)					     * gd->max_nr * gd->max_p);  if (! ds->labels)    return D_NO_MEMORY;  memset ((void *) ds->labels, 0,	  sizeof (struct disklabel *) * gd->max_nr * gd->max_p);  for (i = 1; i < gd->max_p; i++)    {      d->inode.i_rdev = *dev | i;      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;      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 && 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);      if (lp)	{	  if (ds->default_slice == 0)	    ds->default_slice = i;	  for (j = 0, p = lp->d_partitions; j < lp->d_npartitions; j++, p++)	    {	      if (p->p_offset < 0 || p->p_size <= 0)		continue;	      /* Sanity check.  */	      if (p->p_size > gd->part[MINOR (d->inode.i_rdev)].nr_sects)		p->p_size = gd->part[MINOR (d->inode.i_rdev)].nr_sects;	    }	}      ds->labels[MINOR (d->inode.i_rdev)] = lp;    }check:  if (*part >= 0 && slice == 0)    slice = ds->default_slice;  if (*part >= 0 && slice == 0)    return D_NO_SUCH_DEVICE;  *dev = MKDEV (MAJOR (*dev), MINOR (*dev) | slice);  if (slice >= gd->max_p      || gd->part[MINOR (*dev)].start_sect < 0      || gd->part[MINOR (*dev)].nr_sects <= 0)    return D_NO_SUCH_DEVICE;  if (*part >= 0)    {      lp = ds->labels[MINOR (*dev)];      if (! lp	  || *part >= lp->d_npartitions	  || lp->d_partitions[*part].p_offset < 0	  || lp->d_partitions[*part].p_size <= 0)	return D_NO_SUCH_DEVICE;    }  return 0;}#define DECL_DATA	struct temp_data td#define INIT_DATA()			\{					\  queue_init (&td.pages);		\  td.inode.i_rdev = bd->dev;		\  td.file.f_mode = bd->mode;		\  td.file.f_flags = bd->flags;		\  current_thread ()->pcb->data = &td;	\}static io_return_tdevice_open (ipc_port_t reply_port, mach_msg_type_name_t reply_port_type,	     dev_mode_t mode, char *name, device_t *devp){  int part, slice, err;  unsigned major, minor;  kdev_t dev;  ipc_port_t notify;  struct block_data *bd = NULL, *bdp;  struct device_struct *ds;  struct gendisk *gd;  struct name_map *np;  DECL_DATA;  np = find_name (name, &slice, &part);  if (! np)    return D_NO_SUCH_DEVICE;  major = np->major;  ds = &blkdevs[major];  /* Check that driver exists.  */  if (! ds->fops)    return D_NO_SUCH_DEVICE;  /* Wait for any other open/close calls to finish.  */  ds = &blkdevs[major];  while (ds->busy)    {      ds->want = 1;      assert_wait ((event_t) ds, FALSE);      schedule ();    }  ds->busy = 1;  /* Compute minor number.  */  if (! ds->gd)    {      for (gd = gendisk_head; gd && gd->major != major; gd = gd->next)	;      ds->gd = gd;    }  minor = np->unit;  gd = ds->gd;  if (gd)    minor <<= gd->minor_shift;  dev = MKDEV (major, minor);  queue_init (&td.pages);  current_thread ()->pcb->data = &td;  /* Check partition.  */  err = init_partition (np, &dev, ds, slice, &part);  if (err)    goto out;  /* Initialize file structure.  */  switch (mode & (D_READ|D_WRITE))    {    case D_WRITE:      td.file.f_mode = O_WRONLY;      break;    case D_READ|D_WRITE:      td.file.f_mode = O_RDWR;      break;    default:      td.file.f_mode = O_RDONLY;      break;    }  td.file.f_flags = (mode & D_NODELAY) ? O_NDELAY : 0;  /* Check if the device is currently open.  */  for (bdp = open_list; bdp; bdp = bdp->next)    if (bdp->dev == dev	&& bdp->part == part	&& bdp->mode == td.file.f_mode	&& bdp->flags == td.file.f_flags)      {	bd = bdp;	goto out;      }  /* Open the device.  */  if (ds->fops->open)    {      td.inode.i_rdev = dev;      linux_intr_pri = SPL5;      err = (*ds->fops->open) (&td.inode, &td.file);      if (err)	{	  err = linux_to_mach_error (err);	  goto out;	}    }  /* Allocate and initialize device data.  */  bd = (struct block_data *) kalloc (sizeof (struct block_data));  if (! bd)    {      err = D_NO_MEMORY;      goto bad;    }  bd->want = 0;  bd->open_count = 0;  bd->iocount = 0;  bd->part = part;  bd->ds = ds;  bd->device.emul_data = bd;  bd->device.emul_ops = &linux_block_emulation_ops;  bd->dev = dev;  bd->mode = td.file.f_mode;  bd->flags = td.file.f_flags;  bd->port = ipc_port_alloc_kernel ();  if (bd->port == IP_NULL)    {      err = KERN_RESOURCE_SHORTAGE;      goto bad;    }  ipc_kobject_set (bd->port, (ipc_kobject_t) &bd->device, IKOT_DEVICE);  notify = ipc_port_make_sonce (bd->port);  ip_lock (bd->port);  ipc_port_nsrequest (bd->port, 1, notify, &notify);  assert (notify == IP_NULL);  goto out;bad:  if (ds->fops->release)    (*ds->fops->release) (&td.inode, &td.file);out:  ds->busy = 0;  if (ds->want)    {      ds->want = 0;      thread_wakeup ((event_t) ds);    }  if (bd && bd->open_count > 0)    {      if (err)	*devp = NULL;      else	{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -