rtems_status_code rtems_disk_delete(dev_t dev) { rtems_status_code sc = RTEMS_SUCCESSFUL; rtems_disk_device *dd = NULL; sc = disk_lock(); if (sc != RTEMS_SUCCESSFUL) { return sc; } dd = get_disk_entry(dev, true); if (dd == NULL) { disk_unlock(); return RTEMS_INVALID_ID; } dd->deleted = true; rtems_disk_cleanup(dd); disk_unlock(); return RTEMS_SUCCESSFUL; }
rtems_status_code rtems_disk_create_log( dev_t dev, dev_t phys, rtems_blkdev_bnum begin_block, rtems_blkdev_bnum block_count, const char *name ) { rtems_status_code sc = RTEMS_SUCCESSFUL; rtems_disk_device *physical_disk = NULL; rtems_disk_device *dd = NULL; rtems_blkdev_bnum end_block = begin_block + block_count; sc = disk_lock(); if (sc != RTEMS_SUCCESSFUL) { return sc; } physical_disk = get_disk_entry(phys, true); if (physical_disk == NULL || !is_physical_disk(physical_disk)) { disk_unlock(); return RTEMS_INVALID_ID; } if ( begin_block >= physical_disk->size || end_block <= begin_block || end_block > physical_disk->size ) { disk_unlock(); return RTEMS_INVALID_NUMBER; } sc = create_disk(dev, name, &dd); if (sc != RTEMS_SUCCESSFUL) { disk_unlock(); return sc; } dd->phys_dev = physical_disk; dd->start = begin_block; dd->size = block_count; dd->block_size = physical_disk->block_size; dd->media_block_size = physical_disk->media_block_size; dd->block_to_media_block_shift = physical_disk->block_to_media_block_shift; dd->bds_per_group = physical_disk->bds_per_group; dd->ioctl = physical_disk->ioctl; dd->driver_data = physical_disk->driver_data; ++physical_disk->uses; disk_unlock(); return RTEMS_SUCCESSFUL; }
rtems_disk_device * rtems_disk_next(dev_t dev) { rtems_status_code sc = RTEMS_SUCCESSFUL; rtems_disk_device_table *dtab = NULL; rtems_device_major_number major = 0; rtems_device_minor_number minor = 0; if (dev != (dev_t) -1) { rtems_filesystem_split_dev_t(dev, major, minor); /* If minor wraps around */ if ((minor + 1) < minor) { /* If major wraps around */ if ((major + 1) < major) { return NULL; } ++major; minor = 0; } else { ++minor; } } sc = disk_lock(); if (sc != RTEMS_SUCCESSFUL) { return NULL; } if (major >= disktab_size) { disk_unlock(); return NULL; } dtab = disktab + major; while (true) { if (dtab->minor == NULL || minor >= dtab->size) { minor = 0; ++major; if (major >= disktab_size) { disk_unlock(); return NULL; } dtab = disktab + major; } else if (dtab->minor [minor] == NULL) { ++minor; } else { ++dtab->minor [minor]->uses; disk_unlock(); return dtab->minor [minor]; } } }
rtems_status_code rtems_disk_create_log( dev_t dev, dev_t phys, rtems_blkdev_bnum block_begin, rtems_blkdev_bnum block_count, const char *name ) { rtems_status_code sc = RTEMS_SUCCESSFUL; rtems_disk_device *phys_dd = NULL; rtems_disk_device *dd = NULL; char *alloc_name = NULL; sc = disk_lock(); if (sc != RTEMS_SUCCESSFUL) { return sc; } phys_dd = get_disk_entry(phys, true); if (phys_dd == NULL) { disk_unlock(); return RTEMS_INVALID_ID; } sc = create_disk(dev, name, &dd, &alloc_name); if (sc != RTEMS_SUCCESSFUL) { disk_unlock(); return sc; } sc = rtems_disk_init_log( dd, phys_dd, block_begin, block_count ); dd->dev = dev; dd->name = alloc_name; ++phys_dd->uses; if (sc != RTEMS_SUCCESSFUL) { dd->ioctl = null_handler; rtems_disk_delete(dev); disk_unlock(); return sc; } disk_unlock(); return RTEMS_SUCCESSFUL; }
rtems_status_code rtems_disk_create_phys( dev_t dev, uint32_t block_size, rtems_blkdev_bnum block_count, rtems_block_device_ioctl handler, void *driver_data, const char *name ) { rtems_disk_device *dd = NULL; rtems_status_code sc = RTEMS_SUCCESSFUL; if (handler == NULL) { return RTEMS_INVALID_ADDRESS; } sc = disk_lock(); if (sc != RTEMS_SUCCESSFUL) { return sc; } sc = create_disk(dev, name, &dd); if (sc != RTEMS_SUCCESSFUL) { disk_unlock(); return sc; } dd->phys_dev = dd; dd->start = 0; dd->size = block_count; dd->media_block_size = block_size; dd->ioctl = handler; dd->driver_data = driver_data; if ((*handler)(dd, RTEMS_BLKIO_CAPABILITIES, &dd->capabilities) < 0) { dd->capabilities = 0; } sc = rtems_bdbuf_set_block_size(dd, block_size); if (sc != RTEMS_SUCCESSFUL) { dd->ioctl = null_handler; rtems_disk_delete(dev); disk_unlock(); return sc; } disk_unlock(); return RTEMS_SUCCESSFUL; }
rtems_status_code rtems_disk_create_phys( dev_t dev, uint32_t block_size, rtems_blkdev_bnum block_count, rtems_block_device_ioctl handler, void *driver_data, const char *name ) { rtems_disk_device *dd = NULL; rtems_status_code sc = RTEMS_SUCCESSFUL; char *alloc_name = NULL; if (handler == NULL) { return RTEMS_INVALID_ADDRESS; } sc = disk_lock(); if (sc != RTEMS_SUCCESSFUL) { return sc; } sc = create_disk(dev, name, &dd, &alloc_name); if (sc != RTEMS_SUCCESSFUL) { disk_unlock(); return sc; } sc = rtems_disk_init_phys( dd, block_size, block_count, handler, driver_data ); dd->dev = dev; dd->name = alloc_name; if (sc != RTEMS_SUCCESSFUL) { dd->ioctl = null_handler; rtems_disk_delete(dev); disk_unlock(); return sc; } disk_unlock(); return RTEMS_SUCCESSFUL; }
int rdopen(dev_t dev, int flag, int fmt, struct proc *p) { struct rd_softc *sc; u_int unit, part; int error; unit = DISKUNIT(dev); part = DISKPART(dev); sc = rdlookup(unit); if (sc == NULL) return (ENXIO); if ((error = disk_lock(&sc->sc_dk)) != 0) goto unref; if (sc->sc_dk.dk_openmask == 0) { /* Load the partition info if not already loaded. */ if ((error = rdgetdisklabel(dev, sc, sc->sc_dk.dk_label, 0)) != 0) goto unlock; } error = disk_openpart(&sc->sc_dk, part, fmt, 1); unlock: disk_unlock(&sc->sc_dk); unref: device_unref(&sc->sc_dev); return (error); }
int vndclose(dev_t dev, int flags, int mode, struct proc *p) { int unit = DISKUNIT(dev); struct vnd_softc *sc; int part; DNPRINTF(VDB_FOLLOW, "vndclose(%x, %x, %x, %p)\n", dev, flags, mode, p); if (unit >= numvnd) return (ENXIO); sc = &vnd_softc[unit]; disk_lock_nointr(&sc->sc_dk); part = DISKPART(dev); disk_closepart(&sc->sc_dk, part, mode); #if 0 if (sc->sc_dk.dk_openmask == 0) sc->sc_flags &= ~VNF_HAVELABEL; #endif disk_unlock(&sc->sc_dk); return (0); }
int wdclose(dev_t dev, int flag, int fmt, struct proc *p) { struct wd_softc *wd; int part = DISKPART(dev); wd = wdlookup(DISKUNIT(dev)); if (wd == NULL) return ENXIO; WDCDEBUG_PRINT(("wdclose\n"), DEBUG_FUNCS); disk_lock_nointr(&wd->sc_dk); disk_closepart(&wd->sc_dk, part, fmt); if (wd->sc_dk.dk_openmask == 0) { wd_flushcache(wd, 0); /* XXXX Must wait for I/O to complete! */ } disk_unlock(&wd->sc_dk); device_unref(&wd->sc_dev); return (0); }
int rdioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p) { struct rd_softc *sc; struct disklabel *lp; int error = 0; sc = rdlookup(DISKUNIT(dev)); if (sc == NULL) return (ENXIO); switch (cmd) { case DIOCRLDINFO: lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK); rdgetdisklabel(dev, sc, lp, 0); bcopy(lp, sc->sc_dk.dk_label, sizeof(*lp)); free(lp, M_TEMP); goto done; case DIOCGPDINFO: rdgetdisklabel(dev, sc, (struct disklabel *)data, 1); goto done; case DIOCGDINFO: *(struct disklabel *)data = *(sc->sc_dk.dk_label); goto done; case DIOCGPART: ((struct partinfo *)data)->disklab = sc->sc_dk.dk_label; ((struct partinfo *)data)->part = &sc->sc_dk.dk_label->d_partitions[DISKPART(dev)]; goto done; case DIOCWDINFO: case DIOCSDINFO: if ((fflag & FWRITE) == 0) { error = EBADF; goto done; } if ((error = disk_lock(&sc->sc_dk)) != 0) goto done; error = setdisklabel(sc->sc_dk.dk_label, (struct disklabel *)data, sc->sc_dk.dk_openmask); if (error == 0) { if (cmd == DIOCWDINFO) error = writedisklabel(DISKLABELDEV(dev), rdstrategy, sc->sc_dk.dk_label); } disk_unlock(&sc->sc_dk); goto done; } done: device_unref(&sc->sc_dev); return (error); }
static void disk_close(struct disk_data *dd) { disk_unlock(dd); if (close(dd->dd_fd)) { smoke("disk: slot %d: close: %s", dd->dd_slot, strerror(errno)); } }
/* * Close the device. Only called if we are the last occurrence of an open * device. Convenient now but usually a pain. */ int sdclose(dev_t dev, int flag, int fmt, struct proc *p) { struct sd_softc *sc; int part = DISKPART(dev); sc = sdlookup(DISKUNIT(dev)); if (sc == NULL) return (ENXIO); if (sc->flags & SDF_DYING) { device_unref(&sc->sc_dev); return (ENXIO); } disk_lock_nointr(&sc->sc_dk); disk_closepart(&sc->sc_dk, part, fmt); if (sc->sc_dk.dk_openmask == 0) { if ((sc->flags & SDF_DIRTY) != 0) sd_flush(sc, 0); if ((sc->sc_link->flags & SDEV_REMOVABLE) != 0) scsi_prevent(sc->sc_link, PR_ALLOW, SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_NOT_READY | SCSI_SILENT); sc->sc_link->flags &= ~(SDEV_OPEN | SDEV_MEDIA_LOADED); if (sc->sc_link->flags & SDEV_EJECTING) { scsi_start(sc->sc_link, SSS_STOP|SSS_LOEJ, 0); sc->sc_link->flags &= ~SDEV_EJECTING; } timeout_del(&sc->sc_timeout); scsi_xsh_del(&sc->sc_xsh); } disk_unlock(&sc->sc_dk); device_unref(&sc->sc_dev); return 0; }
int rdclose(dev_t dev, int flag, int fmt, struct proc *p) { struct rd_softc *sc; u_int unit, part; unit = DISKUNIT(dev); part = DISKPART(dev); sc = rdlookup(unit); if (sc == NULL) return (ENXIO); disk_lock_nointr(&sc->sc_dk); disk_closepart(&sc->sc_dk, part, fmt); disk_unlock(&sc->sc_dk); device_unref(&sc->sc_dev); return (0); }
rtems_disk_device * rtems_disk_obtain(dev_t dev) { rtems_status_code sc = RTEMS_SUCCESSFUL; rtems_disk_device *dd = NULL; rtems_interrupt_level level; rtems_interrupt_disable(level); if (!diskdevs_protected) { /* Frequent and quickest case */ dd = get_disk_entry(dev, false); rtems_interrupt_enable(level); } else { rtems_interrupt_enable(level); sc = disk_lock(); if (sc == RTEMS_SUCCESSFUL) { dd = get_disk_entry(dev, false); disk_unlock(); } } return dd; }
int vndopen(dev_t dev, int flags, int mode, struct proc *p) { int unit = DISKUNIT(dev); struct vnd_softc *sc; int error = 0, part; DNPRINTF(VDB_FOLLOW, "vndopen(%x, %x, %x, %p)\n", dev, flags, mode, p); if (unit >= numvnd) return (ENXIO); sc = &vnd_softc[unit]; if ((error = disk_lock(&sc->sc_dk)) != 0) return (error); if ((flags & FWRITE) && (sc->sc_flags & VNF_READONLY)) { error = EROFS; goto bad; } if ((sc->sc_flags & VNF_INITED) && (sc->sc_flags & VNF_HAVELABEL) == 0 && sc->sc_dk.dk_openmask == 0) { sc->sc_flags |= VNF_HAVELABEL; vndgetdisklabel(dev, sc, sc->sc_dk.dk_label, 0); } part = DISKPART(dev); error = disk_openpart(&sc->sc_dk, part, mode, (sc->sc_flags & VNF_HAVELABEL) != 0); bad: disk_unlock(&sc->sc_dk); return (error); }
/* * Perform special action on behalf of the user * Knows about the internals of this device */ int sdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) { struct sd_softc *sc; struct disklabel *lp; int error = 0; int part = DISKPART(dev); sc = sdlookup(DISKUNIT(dev)); if (sc == NULL) return (ENXIO); if (sc->flags & SDF_DYING) { device_unref(&sc->sc_dev); return (ENXIO); } SC_DEBUG(sc->sc_link, SDEV_DB2, ("sdioctl 0x%lx\n", cmd)); /* * If the device is not valid.. abandon ship */ if ((sc->sc_link->flags & SDEV_MEDIA_LOADED) == 0) { switch (cmd) { case DIOCLOCK: case DIOCEJECT: case SCIOCIDENTIFY: case SCIOCCOMMAND: case SCIOCDEBUG: if (part == RAW_PART) break; /* FALLTHROUGH */ default: if ((sc->sc_link->flags & SDEV_OPEN) == 0) { error = ENODEV; goto exit; } else { error = EIO; goto exit; } } } switch (cmd) { case DIOCRLDINFO: lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK); sdgetdisklabel(dev, sc, lp, 0); bcopy(lp, sc->sc_dk.dk_label, sizeof(*lp)); free(lp, M_TEMP); goto exit; case DIOCGPDINFO: sdgetdisklabel(dev, sc, (struct disklabel *)addr, 1); goto exit; case DIOCGDINFO: *(struct disklabel *)addr = *(sc->sc_dk.dk_label); goto exit; case DIOCGPART: ((struct partinfo *)addr)->disklab = sc->sc_dk.dk_label; ((struct partinfo *)addr)->part = &sc->sc_dk.dk_label->d_partitions[DISKPART(dev)]; goto exit; case DIOCWDINFO: case DIOCSDINFO: if ((flag & FWRITE) == 0) { error = EBADF; goto exit; } if ((error = disk_lock(&sc->sc_dk)) != 0) goto exit; error = setdisklabel(sc->sc_dk.dk_label, (struct disklabel *)addr, sc->sc_dk.dk_openmask); if (error == 0) { if (cmd == DIOCWDINFO) error = writedisklabel(DISKLABELDEV(dev), sdstrategy, sc->sc_dk.dk_label); } disk_unlock(&sc->sc_dk); goto exit; case DIOCLOCK: error = scsi_prevent(sc->sc_link, (*(int *)addr) ? PR_PREVENT : PR_ALLOW, 0); goto exit; case MTIOCTOP: if (((struct mtop *)addr)->mt_op != MTOFFL) { error = EIO; goto exit; } /* FALLTHROUGH */ case DIOCEJECT: if ((sc->sc_link->flags & SDEV_REMOVABLE) == 0) { error = ENOTTY; goto exit; } sc->sc_link->flags |= SDEV_EJECTING; goto exit; case DIOCINQ: error = scsi_do_ioctl(sc->sc_link, cmd, addr, flag); if (error == ENOTTY) error = sd_ioctl_inquiry(sc, (struct dk_inquiry *)addr); goto exit; case DIOCSCACHE: if (!ISSET(flag, FWRITE)) { error = EBADF; goto exit; } /* FALLTHROUGH */ case DIOCGCACHE: error = sd_ioctl_cache(sc, cmd, (struct dk_cache *)addr); goto exit; case DIOCCACHESYNC: if (!ISSET(flag, FWRITE)) { error = EBADF; goto exit; } if ((sc->flags & SDF_DIRTY) != 0 || *(int *)addr != 0) error = sd_flush(sc, 0); return (error); default: if (part != RAW_PART) { error = ENOTTY; goto exit; } error = scsi_do_ioctl(sc->sc_link, cmd, addr, flag); } exit: device_unref(&sc->sc_dev); return (error); }
/* * Open the device. Make sure the partition info is as up-to-date as can be. */ int sdopen(dev_t dev, int flag, int fmt, struct proc *p) { struct scsi_link *sc_link; struct sd_softc *sc; int error = 0, part, rawopen, unit; unit = DISKUNIT(dev); part = DISKPART(dev); rawopen = (part == RAW_PART) && (fmt == S_IFCHR); sc = sdlookup(unit); if (sc == NULL) return (ENXIO); sc_link = sc->sc_link; if (sc->flags & SDF_DYING) { device_unref(&sc->sc_dev); return (ENXIO); } if (ISSET(flag, FWRITE) && ISSET(sc_link->flags, SDEV_READONLY)) { device_unref(&sc->sc_dev); return (EACCES); } SC_DEBUG(sc_link, SDEV_DB1, ("sdopen: dev=0x%x (unit %d (of %d), partition %d)\n", dev, unit, sd_cd.cd_ndevs, part)); if ((error = disk_lock(&sc->sc_dk)) != 0) { device_unref(&sc->sc_dev); return (error); } if (sc->sc_dk.dk_openmask != 0) { /* * If any partition is open, but the disk has been invalidated, * disallow further opens of non-raw partition. */ if ((sc_link->flags & SDEV_MEDIA_LOADED) == 0) { if (rawopen) goto out; error = EIO; goto bad; } } else { /* Spin up non-UMASS devices ready or not. */ if ((sc->sc_link->flags & SDEV_UMASS) == 0) scsi_start(sc_link, SSS_START, (rawopen ? SCSI_SILENT : 0) | SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE); /* Use sd_interpret_sense() for sense errors. * * But only after spinning the disk up! Just in case a broken * device returns "Initialization command required." and causes * a loop of scsi_start() calls. */ sc_link->flags |= SDEV_OPEN; /* * Try to prevent the unloading of a removable device while * it's open. But allow the open to proceed if the device can't * be locked in. */ if ((sc_link->flags & SDEV_REMOVABLE) != 0) { scsi_prevent(sc_link, PR_PREVENT, SCSI_SILENT | SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE); } /* Check that it is still responding and ok. */ error = scsi_test_unit_ready(sc_link, TEST_READY_RETRIES, SCSI_SILENT | SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE); if (error) { if (rawopen) { error = 0; goto out; } else goto bad; } /* Load the physical device parameters. */ sc_link->flags |= SDEV_MEDIA_LOADED; if (sd_get_parms(sc, &sc->params, (rawopen ? SCSI_SILENT : 0)) == SDGP_RESULT_OFFLINE) { sc_link->flags &= ~SDEV_MEDIA_LOADED; error = ENXIO; goto bad; } SC_DEBUG(sc_link, SDEV_DB3, ("Params loaded\n")); /* Load the partition info if not already loaded. */ if (sdgetdisklabel(dev, sc, sc->sc_dk.dk_label, 0) == EIO) { error = EIO; goto bad; } SC_DEBUG(sc_link, SDEV_DB3, ("Disklabel loaded\n")); } out: if ((error = disk_openpart(&sc->sc_dk, part, fmt, 1)) != 0) goto bad; SC_DEBUG(sc_link, SDEV_DB3, ("open complete\n")); /* It's OK to fall through because dk_openmask is now non-zero. */ bad: if (sc->sc_dk.dk_openmask == 0) { if ((sc->sc_link->flags & SDEV_REMOVABLE) != 0) scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT | SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE); sc_link->flags &= ~(SDEV_OPEN | SDEV_MEDIA_LOADED); } disk_unlock(&sc->sc_dk); device_unref(&sc->sc_dev); return (error); }
int wdioctl(dev_t dev, u_long xfer, caddr_t addr, int flag, struct proc *p) { struct wd_softc *wd; struct disklabel *lp; int error = 0; WDCDEBUG_PRINT(("wdioctl\n"), DEBUG_FUNCS); wd = wdlookup(DISKUNIT(dev)); if (wd == NULL) return ENXIO; if ((wd->sc_flags & WDF_LOADED) == 0) { error = EIO; goto exit; } switch (xfer) { case DIOCRLDINFO: lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK); wdgetdisklabel(dev, wd, lp, 0); bcopy(lp, wd->sc_dk.dk_label, sizeof(*lp)); free(lp, M_TEMP, 0); goto exit; case DIOCGPDINFO: wdgetdisklabel(dev, wd, (struct disklabel *)addr, 1); goto exit; case DIOCGDINFO: *(struct disklabel *)addr = *(wd->sc_dk.dk_label); goto exit; case DIOCGPART: ((struct partinfo *)addr)->disklab = wd->sc_dk.dk_label; ((struct partinfo *)addr)->part = &wd->sc_dk.dk_label->d_partitions[DISKPART(dev)]; goto exit; case DIOCWDINFO: case DIOCSDINFO: if ((flag & FWRITE) == 0) { error = EBADF; goto exit; } if ((error = disk_lock(&wd->sc_dk)) != 0) goto exit; error = setdisklabel(wd->sc_dk.dk_label, (struct disklabel *)addr, wd->sc_dk.dk_openmask); if (error == 0) { if (wd->drvp->state > RECAL) wd->drvp->drive_flags |= DRIVE_RESET; if (xfer == DIOCWDINFO) error = writedisklabel(DISKLABELDEV(dev), wdstrategy, wd->sc_dk.dk_label); } disk_unlock(&wd->sc_dk); goto exit; #ifdef notyet case DIOCWFORMAT: if ((flag & FWRITE) == 0) return EBADF; { struct format_op *fop; struct iovec aiov; struct uio auio; fop = (struct format_op *)addr; aiov.iov_base = fop->df_buf; aiov.iov_len = fop->df_count; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_resid = fop->df_count; auio.uio_segflg = 0; auio.uio_offset = fop->df_startblk * wd->sc_dk.dk_label->d_secsize; auio.uio_procp = p; error = physio(wdformat, dev, B_WRITE, minphys, &auio); fop->df_count -= auio.uio_resid; fop->df_reg[0] = wdc->sc_status; fop->df_reg[1] = wdc->sc_error; goto exit; } #endif default: error = wdc_ioctl(wd->drvp, xfer, addr, flag, p); goto exit; } #ifdef DIAGNOSTIC panic("wdioctl: impossible"); #endif exit: device_unref(&wd->sc_dev); return (error); }
int wdopen(dev_t dev, int flag, int fmt, struct proc *p) { struct wd_softc *wd; struct channel_softc *chnl; int unit, part; int error; WDCDEBUG_PRINT(("wdopen\n"), DEBUG_FUNCS); unit = DISKUNIT(dev); wd = wdlookup(unit); if (wd == NULL) return ENXIO; chnl = (struct channel_softc *)(wd->drvp->chnl_softc); if (chnl->dying) return (ENXIO); /* * If this is the first open of this device, add a reference * to the adapter. */ if ((error = disk_lock(&wd->sc_dk)) != 0) goto bad4; if (wd->sc_dk.dk_openmask != 0) { /* * If any partition is open, but the disk has been invalidated, * disallow further opens. */ if ((wd->sc_flags & WDF_LOADED) == 0) { error = EIO; goto bad3; } } else { if ((wd->sc_flags & WDF_LOADED) == 0) { wd->sc_flags |= WDF_LOADED; /* Load the physical device parameters. */ wd_get_params(wd, AT_WAIT, &wd->sc_params); /* Load the partition info if not already loaded. */ if (wdgetdisklabel(dev, wd, wd->sc_dk.dk_label, 0) == EIO) { error = EIO; goto bad; } } } part = DISKPART(dev); if ((error = disk_openpart(&wd->sc_dk, part, fmt, 1)) != 0) goto bad; disk_unlock(&wd->sc_dk); device_unref(&wd->sc_dev); return 0; bad: if (wd->sc_dk.dk_openmask == 0) { } bad3: disk_unlock(&wd->sc_dk); bad4: device_unref(&wd->sc_dev); return error; }
/* ARGSUSED */ int vndioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) { int unit = DISKUNIT(dev); struct disklabel *lp; struct vnd_softc *sc; struct vnd_ioctl *vio; struct vnd_user *vnu; struct vattr vattr; struct nameidata nd; int error, part, pmask; DNPRINTF(VDB_FOLLOW, "vndioctl(%x, %lx, %p, %x, %p): unit %d\n", dev, cmd, addr, flag, p, unit); error = suser(p, 0); if (error) return (error); if (unit >= numvnd) return (ENXIO); sc = &vnd_softc[unit]; vio = (struct vnd_ioctl *)addr; switch (cmd) { case VNDIOCSET: if (sc->sc_flags & VNF_INITED) return (EBUSY); /* Geometry eventually has to fit into label fields */ if (vio->vnd_secsize > UINT_MAX || vio->vnd_ntracks > UINT_MAX || vio->vnd_nsectors > UINT_MAX) return (EINVAL); if ((error = disk_lock(&sc->sc_dk)) != 0) return (error); if ((error = copyinstr(vio->vnd_file, sc->sc_file, sizeof(sc->sc_file), NULL))) { disk_unlock(&sc->sc_dk); return (error); } /* Set geometry for device. */ sc->sc_secsize = vio->vnd_secsize; sc->sc_ntracks = vio->vnd_ntracks; sc->sc_nsectors = vio->vnd_nsectors; /* * Open for read and write first. This lets vn_open() weed out * directories, sockets, etc. so we don't have to worry about * them. */ NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vnd_file, p); sc->sc_flags &= ~VNF_READONLY; error = vn_open(&nd, FREAD|FWRITE, 0); if (error == EROFS) { sc->sc_flags |= VNF_READONLY; error = vn_open(&nd, FREAD, 0); } if (error) { disk_unlock(&sc->sc_dk); return (error); } if (nd.ni_vp->v_type == VBLK) sc->sc_size = vndbdevsize(nd.ni_vp, p); else { error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p); if (error) { VOP_UNLOCK(nd.ni_vp, 0, p); vn_close(nd.ni_vp, VNDRW(sc), p->p_ucred, p); disk_unlock(&sc->sc_dk); return (error); } sc->sc_size = vattr.va_size / sc->sc_secsize; } VOP_UNLOCK(nd.ni_vp, 0, p); sc->sc_vp = nd.ni_vp; if ((error = vndsetcred(sc, p->p_ucred)) != 0) { (void) vn_close(nd.ni_vp, VNDRW(sc), p->p_ucred, p); disk_unlock(&sc->sc_dk); return (error); } if (vio->vnd_keylen > 0) { char key[BLF_MAXUTILIZED]; if (vio->vnd_keylen > sizeof(key)) vio->vnd_keylen = sizeof(key); if ((error = copyin(vio->vnd_key, key, vio->vnd_keylen)) != 0) { (void) vn_close(nd.ni_vp, VNDRW(sc), p->p_ucred, p); disk_unlock(&sc->sc_dk); return (error); } sc->sc_keyctx = malloc(sizeof(*sc->sc_keyctx), M_DEVBUF, M_WAITOK); blf_key(sc->sc_keyctx, key, vio->vnd_keylen); explicit_bzero(key, vio->vnd_keylen); } else sc->sc_keyctx = NULL; vio->vnd_size = sc->sc_size * sc->sc_secsize; sc->sc_flags |= VNF_INITED; DNPRINTF(VDB_INIT, "vndioctl: SET vp %p size %llx\n", sc->sc_vp, (unsigned long long)sc->sc_size); /* Attach the disk. */ sc->sc_dk.dk_name = sc->sc_dev.dv_xname; disk_attach(&sc->sc_dev, &sc->sc_dk); disk_unlock(&sc->sc_dk); break; case VNDIOCCLR: if ((sc->sc_flags & VNF_INITED) == 0) return (ENXIO); if ((error = disk_lock(&sc->sc_dk)) != 0) return (error); /* * Don't unconfigure if any other partitions are open * or if both the character and block flavors of this * partition are open. */ part = DISKPART(dev); pmask = (1 << part); if ((sc->sc_dk.dk_openmask & ~pmask) || ((sc->sc_dk.dk_bopenmask & pmask) && (sc->sc_dk.dk_copenmask & pmask))) { disk_unlock(&sc->sc_dk); return (EBUSY); } vndclear(sc); DNPRINTF(VDB_INIT, "vndioctl: CLRed\n"); /* Free crypto key */ if (sc->sc_keyctx) { explicit_bzero(sc->sc_keyctx, sizeof(*sc->sc_keyctx)); free(sc->sc_keyctx, M_DEVBUF, sizeof(*sc->sc_keyctx)); } /* Detach the disk. */ disk_detach(&sc->sc_dk); disk_unlock(&sc->sc_dk); break; case VNDIOCGET: vnu = (struct vnd_user *)addr; if (vnu->vnu_unit == -1) vnu->vnu_unit = unit; if (vnu->vnu_unit >= numvnd) return (ENXIO); if (vnu->vnu_unit < 0) return (EINVAL); sc = &vnd_softc[vnu->vnu_unit]; if (sc->sc_flags & VNF_INITED) { error = VOP_GETATTR(sc->sc_vp, &vattr, p->p_ucred, p); if (error) return (error); strlcpy(vnu->vnu_file, sc->sc_file, sizeof(vnu->vnu_file)); vnu->vnu_dev = vattr.va_fsid; vnu->vnu_ino = vattr.va_fileid; } else { vnu->vnu_dev = 0; vnu->vnu_ino = 0; } break; case DIOCRLDINFO: if ((sc->sc_flags & VNF_HAVELABEL) == 0) return (ENOTTY); lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK); vndgetdisklabel(dev, sc, lp, 0); *(sc->sc_dk.dk_label) = *lp; free(lp, M_TEMP, sizeof(*lp)); return (0); case DIOCGPDINFO: if ((sc->sc_flags & VNF_HAVELABEL) == 0) return (ENOTTY); vndgetdisklabel(dev, sc, (struct disklabel *)addr, 1); return (0); case DIOCGDINFO: if ((sc->sc_flags & VNF_HAVELABEL) == 0) return (ENOTTY); *(struct disklabel *)addr = *(sc->sc_dk.dk_label); return (0); case DIOCGPART: if ((sc->sc_flags & VNF_HAVELABEL) == 0) return (ENOTTY); ((struct partinfo *)addr)->disklab = sc->sc_dk.dk_label; ((struct partinfo *)addr)->part = &sc->sc_dk.dk_label->d_partitions[DISKPART(dev)]; return (0); case DIOCWDINFO: case DIOCSDINFO: if ((sc->sc_flags & VNF_HAVELABEL) == 0) return (ENOTTY); if ((flag & FWRITE) == 0) return (EBADF); if ((error = disk_lock(&sc->sc_dk)) != 0) return (error); error = setdisklabel(sc->sc_dk.dk_label, (struct disklabel *)addr, /* sc->sc_dk.dk_openmask */ 0); if (error == 0) { if (cmd == DIOCWDINFO) error = writedisklabel(DISKLABELDEV(dev), vndstrategy, sc->sc_dk.dk_label); } disk_unlock(&sc->sc_dk); return (error); default: return (ENOTTY); } return (0); }