Index: share/man/man4/geom.4 =================================================================== --- share/man/man4/geom.4 (revision 189063) +++ share/man/man4/geom.4 (working copy) @@ -249,7 +249,7 @@ It will explicitly close (i.e.: zero the access co which will propagate all the way down through the mesh. It will then detach and destroy its geom. .It -The geom whose provider is now attached will destroy the provider, +The geom whose provider is now detached will destroy the provider, detach and destroy its consumer and destroy its geom. .It This process percolates all the way down through the mesh, until @@ -431,6 +431,18 @@ This is unused at this time. .It 0x80 Pq Dv G_F_CTLDUMP Dump contents of gctl requests. .El +.Sh SEE ALSO +.Xr disk 9 , +.Xr DECLARE_GEOM_CLASS 9 , +.Xr g_access 9 , +.Xr g_attach 9 , +.Xr g_bio 9 , +.Xr g_consumer 9 , +.Xr g_data 9 , +.Xr g_event 9 , +.Xr g_geom 9 , +.Xr g_provider 9 , +.Xr g_provider_by_name 9 .Sh HISTORY This software was developed for the .Fx Index: share/man/man9/Makefile =================================================================== --- share/man/man9/Makefile (revision 189063) +++ share/man/man9/Makefile (working copy) @@ -559,7 +559,9 @@ MLINKS+=devstat.9 devicestat.9 \ devstat.9 devstat_end_transaction.9 \ devstat.9 devstat_remove_entry.9 \ devstat.9 devstat_start_transaction.9 -MLINKS+=disk.9 disk_create.9 \ +MLINKS+=disk.9 disk_alloc.9 \ + disk.9 disk_create.9 \ + disk.9 disk_gone.9 \ disk.9 disk_destroy.9 MLINKS+=domain.9 DOMAIN_SET.9 \ domain.9 net_add_domain.9 \ Index: share/man/man9/VOP_STRATEGY.9 =================================================================== --- share/man/man9/VOP_STRATEGY.9 (revision 189063) +++ share/man/man9/VOP_STRATEGY.9 (working copy) @@ -53,7 +53,9 @@ This call either reads or writes data from a file, .Pp The call may block. .Sh RETURN VALUES -Zero is returned on success, otherwise an error is returned. +Always zero. +Errors should be signalled by setting BIO_ERROR on b_ioflags field in struct buf, +and setting b_error to the appropriate errno value. .Sh SEE ALSO .\" .Xr buf 9 , .Xr vnode 9 Index: share/man/man9/disk.9 =================================================================== --- share/man/man9/disk.9 (revision 189063) +++ share/man/man9/disk.9 (working copy) @@ -40,6 +40,8 @@ .Ft void .Fn disk_create "struct disk *disk" "int version" .Ft void +.Fn disk_gone "struct disk *disk" +.Ft void .Fn disk_destroy "struct disk *disk" .Sh DESCRIPTION The disk storage API permits kernel device drivers providing access to @@ -65,6 +67,11 @@ function, fill in the fields and call .Fn disk_create when the device is ready to service requests. +.Fn disk_gone +orphans all of the providers associated with the drive, setting an error +condition of ENXIO in each one. +In addition, it prevents a re-taste on last close for writing if an error +condition has been set in the provider. After calling .Fn disk_destroy , the device driver is not allowed to access the contents of Index: sys/gnu/fs/xfs/FreeBSD/xfs_vnops.c =================================================================== --- sys/gnu/fs/xfs/FreeBSD/xfs_vnops.c (revision 189063) +++ sys/gnu/fs/xfs/FreeBSD/xfs_vnops.c (working copy) @@ -1138,7 +1138,7 @@ _xfs_strategy( bp->b_error = error; bp->b_ioflags |= BIO_ERROR; bufdone(bp); - return (error); + return (0); } if ((long)bp->b_blkno == -1) vfs_bio_clrbuf(bp); Index: sys/gnu/fs/reiserfs/reiserfs_vnops.c =================================================================== --- sys/gnu/fs/reiserfs/reiserfs_vnops.c (revision 189063) +++ sys/gnu/fs/reiserfs/reiserfs_vnops.c (working copy) @@ -350,8 +350,13 @@ reiserfs_strategy(struct vop_strategy_args /* { bp->b_ioflags |= BIO_ERROR; } + if (error) { + bp->b_ioflags |= BIO_ERROR; + bp->b_error = error; + } + bufdone(bp); - return (error); + return (0); } /* Index: sys/gnu/fs/ext2fs/ext2_vnops.c =================================================================== --- sys/gnu/fs/ext2fs/ext2_vnops.c (revision 189063) +++ sys/gnu/fs/ext2fs/ext2_vnops.c (working copy) @@ -1408,7 +1408,7 @@ ext2_strategy(ap) bp->b_error = error; bp->b_ioflags |= BIO_ERROR; bufdone(bp); - return (error); + return (0); } if ((long)bp->b_blkno == -1) vfs_bio_clrbuf(bp); Index: sys/ufs/ufs/ufs_vnops.c =================================================================== --- sys/ufs/ufs/ufs_vnops.c (revision 189063) +++ sys/ufs/ufs/ufs_vnops.c (working copy) @@ -2015,7 +2015,7 @@ ufs_strategy(ap) bp->b_error = error; bp->b_ioflags |= BIO_ERROR; bufdone(bp); - return (error); + return (0); } if ((long)bp->b_blkno == -1) vfs_bio_clrbuf(bp); Index: sys/ufs/ffs/ffs_vfsops.c =================================================================== --- sys/ufs/ffs/ffs_vfsops.c (revision 189063) +++ sys/ufs/ffs/ffs_vfsops.c (working copy) @@ -641,6 +641,7 @@ ffs_mountfs(devvp, mp, td) VOP_UNLOCK(devvp, 0, td); if (error) return (error); + dev_ref(dev); if (devvp->v_rdev->si_iosize_max != 0) mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max; if (mp->mnt_iosize_max > MAXPHYS) @@ -921,6 +922,7 @@ out: free(ump, M_UFSMNT); mp->mnt_data = (qaddr_t)0; } + dev_rel(dev); return (error); } @@ -1107,6 +1109,7 @@ ffs_unmount(mp, mntflags, td) g_topology_unlock(); PICKUP_GIANT(); vrele(ump->um_devvp); + dev_rel(ump->um_dev); mtx_destroy(UFS_MTX(ump)); if (mp->mnt_gjprovider != NULL) { free(mp->mnt_gjprovider, M_UFSMNT); Index: sys/ufs/ffs/ffs_alloc.c =================================================================== --- sys/ufs/ffs/ffs_alloc.c (revision 189063) +++ sys/ufs/ffs/ffs_alloc.c (working copy) @@ -1858,7 +1858,7 @@ ffs_blkfree(ump, fs, devvp, bno, size, inum) struct cdev *dev; cg = dtog(fs, bno); - if (devvp->v_type != VCHR) { + if (devvp->v_type == VREG) { /* devvp is a snapshot */ dev = VTOI(devvp)->i_devvp->v_rdev; cgblkno = fragstoblks(fs, cgtod(fs, cg)); @@ -1903,7 +1903,7 @@ ffs_blkfree(ump, fs, devvp, bno, size, inum) if (size == fs->fs_bsize) { fragno = fragstoblks(fs, cgbno); if (!ffs_isfreeblock(fs, blksfree, fragno)) { - if (devvp->v_type != VCHR) { + if (devvp->v_type == VREG) { UFS_UNLOCK(ump); /* devvp is a snapshot */ brelse(bp); @@ -2056,7 +2056,7 @@ ffs_freefile(ump, fs, devvp, ino, mode) struct cdev *dev; cg = ino_to_cg(fs, ino); - if (devvp->v_type != VCHR) { + if (devvp->v_type == VREG) { /* devvp is a snapshot */ dev = VTOI(devvp)->i_devvp->v_rdev; cgbno = fragstoblks(fs, cgtod(fs, cg)); @@ -2122,7 +2122,7 @@ ffs_checkfreefile(fs, devvp, ino) u_int8_t *inosused; cg = ino_to_cg(fs, ino); - if (devvp->v_type != VCHR) { + if (devvp->v_type == VREG) { /* devvp is a snapshot */ cgbno = fragstoblks(fs, cgtod(fs, cg)); } else { Index: sys/cam/cam_periph.c =================================================================== --- sys/cam/cam_periph.c (revision 189063) +++ sys/cam/cam_periph.c (working copy) @@ -171,6 +171,10 @@ cam_periph_alloc(periph_ctor_t *periph_ctor, break; } xpt_unlock_buses(); + if (p_drv == NULL) { + printf("cam_periph_alloc: invalid periph name '%s'\n", name); + return (CAM_REQ_INVALID); + } sim = xpt_path_sim(path); path_id = xpt_path_path_id(path); @@ -290,7 +294,7 @@ cam_periph_acquire(struct cam_periph *periph) } void -cam_periph_release(struct cam_periph *periph) +cam_periph_release_locked(struct cam_periph *periph) { if (periph == NULL) @@ -302,7 +306,21 @@ void camperiphfree(periph); } xpt_unlock_buses(); +} +void +cam_periph_release(struct cam_periph *periph) +{ + struct cam_sim *sim; + + if (periph == NULL) + return; + + sim = periph->sim; + mtx_assert(sim->mtx, MA_NOTOWNED); + mtx_lock(sim->mtx); + cam_periph_release_locked(periph); + mtx_unlock(sim->mtx); } int @@ -311,8 +329,6 @@ cam_periph_hold(struct cam_periph *periph, int pri struct mtx *mtx; int error; - mtx_assert(periph->sim->mtx, MA_OWNED); - /* * Increment the reference count on the peripheral * while we wait for our lock attempt to succeed @@ -324,13 +340,14 @@ cam_periph_hold(struct cam_periph *periph, int pri return (ENXIO); mtx = periph->sim->mtx; + mtx_assert(mtx, MA_OWNED); if (mtx == &Giant) mtx = NULL; while ((periph->flags & CAM_PERIPH_LOCKED) != 0) { periph->flags |= CAM_PERIPH_LOCK_WANTED; if ((error = msleep(periph, mtx, priority, "caplck", 0)) != 0) { - cam_periph_release(periph); + cam_periph_release_locked(periph); return (error); } } @@ -351,7 +368,7 @@ cam_periph_unhold(struct cam_periph *periph) wakeup(periph); } - cam_periph_release(periph); + cam_periph_release_locked(periph); } /* Index: sys/cam/cam_sim.c =================================================================== --- sys/cam/cam_sim.c (revision 189063) +++ sys/cam/cam_sim.c (working copy) @@ -84,6 +84,7 @@ cam_sim_alloc(sim_action_func sim_action, sim_poll sim->max_tagged_dev_openings = max_tagged_dev_transactions; sim->max_dev_openings = max_dev_transactions; sim->flags = 0; + sim->refcount = 1; sim->devq = queue; sim->mtx = mtx; if (mtx == &Giant) { @@ -103,12 +104,42 @@ cam_sim_alloc(sim_action_func sim_action, sim_poll void cam_sim_free(struct cam_sim *sim, int free_devq) { + int error; + + sim->refcount--; + if (sim->refcount > 0) { + error = msleep(sim, sim->mtx, PRIBIO, "simfree", 0); + KASSERT(error == 0, ("invalid error value for msleep(9)")); + } + + KASSERT(sim->refcount == 0, ("sim->refcount == 0")); + if (free_devq) cam_simq_free(sim->devq); free(sim, M_CAMSIM); } void +cam_sim_release(struct cam_sim *sim) +{ + KASSERT(sim->refcount >= 1, ("sim->refcount >= 1")); + mtx_assert(sim->mtx, MA_OWNED); + + sim->refcount--; + if (sim->refcount == 0) + wakeup(sim); +} + +void +cam_sim_hold(struct cam_sim *sim) +{ + KASSERT(sim->refcount >= 1, ("sim->refcount >= 1")); + mtx_assert(sim->mtx, MA_OWNED); + + sim->refcount++; +} + +void cam_sim_set_path(struct cam_sim *sim, u_int32_t path_id) { sim->path_id = path_id; Index: sys/cam/cam_xpt_sim.h =================================================================== --- sys/cam/cam_xpt_sim.h (revision 189063) +++ sys/cam/cam_xpt_sim.h (working copy) @@ -45,6 +45,7 @@ void xpt_release_simq(struct cam_sim *sim, int ru u_int32_t xpt_freeze_devq(struct cam_path *path, u_int count); void xpt_release_devq(struct cam_path *path, u_int count, int run_queue); +int xpt_sim_opened(struct cam_sim *sim); void xpt_done(union ccb *done_ccb); #endif Index: sys/cam/cam_periph.h =================================================================== --- sys/cam/cam_periph.h (revision 189063) +++ sys/cam/cam_periph.h (working copy) @@ -141,6 +141,7 @@ cam_status cam_periph_alloc(periph_ctor_t *periph_ struct cam_periph *cam_periph_find(struct cam_path *path, char *name); cam_status cam_periph_acquire(struct cam_periph *periph); void cam_periph_release(struct cam_periph *periph); +void cam_periph_release_locked(struct cam_periph *periph); int cam_periph_hold(struct cam_periph *periph, int priority); void cam_periph_unhold(struct cam_periph *periph); void cam_periph_invalidate(struct cam_periph *periph); Index: sys/cam/cam_sim.h =================================================================== --- sys/cam/cam_sim.h (revision 189063) +++ sys/cam/cam_sim.h (working copy) @@ -61,6 +61,8 @@ struct cam_sim * cam_sim_alloc(sim_action_func si int max_tagged_dev_transactions, struct cam_devq *queue); void cam_sim_free(struct cam_sim *sim, int free_devq); +void cam_sim_hold(struct cam_sim *sim); +void cam_sim_release(struct cam_sim *sim); /* Optional sim attributes may be set with these. */ void cam_sim_set_path(struct cam_sim *sim, u_int32_t path_id); @@ -105,6 +107,7 @@ struct cam_sim { #define CAM_SIM_ON_DONEQ 0x04 struct callout callout; struct cam_devq *devq; /* Device Queue to use for this SIM */ + int refcount; /* References to the SIM. */ /* "Pool" of inactive ccbs managed by xpt_alloc_ccb and xpt_free_ccb */ SLIST_HEAD(,ccb_hdr) ccb_freeq; Index: sys/cam/scsi/scsi_pt.c =================================================================== --- sys/cam/scsi/scsi_pt.c (revision 189063) +++ sys/cam/scsi/scsi_pt.c (working copy) @@ -342,11 +342,11 @@ ptdtor(struct cam_periph *periph) softc = (struct pt_softc *)periph->softc; + xpt_print(periph->path, "removing device entry\n"); devstat_remove_entry(softc->device_stats); - + cam_periph_unlock(periph); destroy_dev(softc->dev); - - xpt_print(periph->path, "removing device entry\n"); + cam_periph_lock(periph); free(softc, M_DEVBUF); } Index: sys/cam/scsi/scsi_da.c =================================================================== --- sys/cam/scsi/scsi_da.c (revision 189063) +++ sys/cam/scsi/scsi_da.c (working copy) @@ -771,8 +771,8 @@ daclose(struct disk *dp) softc->flags &= ~DA_FLAG_OPEN; cam_periph_unhold(periph); - cam_periph_release(periph); cam_periph_unlock(periph); + cam_periph_release(periph); return (0); } @@ -1012,7 +1012,6 @@ daasync(void *callback_arg, u_int32_t code, case AC_FOUND_DEVICE: { struct ccb_getdev *cgd; - struct cam_sim *sim; cam_status status; cgd = (struct ccb_getdev *)arg; @@ -1029,7 +1028,6 @@ daasync(void *callback_arg, u_int32_t code, * this device and start the probe * process. */ - sim = xpt_path_sim(cgd->ccb_h.path); status = cam_periph_alloc(daregister, daoninvalidate, dacleanup, dastart, "da", CAM_PERIPH_BIO, Index: sys/cam/scsi/scsi_ses.c =================================================================== --- sys/cam/scsi/scsi_ses.c (revision 189063) +++ sys/cam/scsi/scsi_ses.c (working copy) @@ -227,9 +227,10 @@ sescleanup(struct cam_periph *periph) softc = (struct ses_softc *)periph->softc; + xpt_print(periph->path, "removing device entry\n"); + cam_periph_unlock(periph); destroy_dev(softc->ses_dev); - - xpt_print(periph->path, "removing device entry\n"); + cam_periph_lock(periph); free(softc, M_SCSISES); } Index: sys/cam/scsi/scsi_ch.c =================================================================== --- sys/cam/scsi/scsi_ch.c (revision 189063) +++ sys/cam/scsi/scsi_ch.c (working copy) @@ -262,9 +262,11 @@ chcleanup(struct cam_periph *periph) softc = (struct ch_softc *)periph->softc; + xpt_print(periph->path, "removing device entry\n"); devstat_remove_entry(softc->device_stats); + cam_periph_unlock(periph); destroy_dev(softc->dev); - xpt_print(periph->path, "removing device entry\n"); + cam_periph_lock(periph); free(softc, M_DEVBUF); } Index: sys/cam/scsi/scsi_low.c =================================================================== --- sys/cam/scsi/scsi_low.c (revision 189063) +++ sys/cam/scsi/scsi_low.c (working copy) @@ -966,16 +966,16 @@ scsi_low_rescan_bus_cam(slp) struct scsi_low_softc *slp; { struct cam_path *path; - union ccb *ccb = xpt_alloc_ccb(); + union ccb *ccb; cam_status status; - bzero(ccb, sizeof(union ccb)); - status = xpt_create_path(&path, xpt_periph, cam_sim_path(slp->sl_si.sim), -1, 0); if (status != CAM_REQ_CMP) return; + ccb = xpt_alloc_ccb(); + bzero(ccb, sizeof(union ccb)); xpt_setup_ccb(&ccb->ccb_h, path, 5); ccb->ccb_h.func_code = XPT_SCAN_BUS; ccb->ccb_h.cbfcnp = scsi_low_cam_rescan_callback; Index: sys/cam/scsi/scsi_sa.c =================================================================== --- sys/cam/scsi/scsi_sa.c (revision 189063) +++ sys/cam/scsi/scsi_sa.c (working copy) @@ -1377,17 +1377,16 @@ sacleanup(struct cam_periph *periph) softc = (struct sa_softc *)periph->softc; + xpt_print(periph->path, "removing device entry\n"); devstat_remove_entry(softc->device_stats); - + cam_periph_unlock(periph); destroy_dev(softc->devs.ctl_dev); - for (i = 0; i < SA_NUM_MODES; i++) { destroy_dev(softc->devs.mode_devs[i].r_dev); destroy_dev(softc->devs.mode_devs[i].nr_dev); destroy_dev(softc->devs.mode_devs[i].er_dev); } - - xpt_print(periph->path, "removing device entry\n"); + cam_periph_lock(periph); free(softc, M_SCSISA); } Index: sys/cam/scsi/scsi_pass.c =================================================================== --- sys/cam/scsi/scsi_pass.c (revision 189063) +++ sys/cam/scsi/scsi_pass.c (working copy) @@ -165,13 +165,12 @@ passcleanup(struct cam_periph *periph) softc = (struct pass_softc *)periph->softc; + if (bootverbose) + xpt_print(periph->path, "removing device entry\n"); devstat_remove_entry(softc->device_stats); - + cam_periph_unlock(periph); destroy_dev(softc->dev); - - if (bootverbose) { - xpt_print(periph->path, "removing device entry\n"); - } + cam_periph_lock(periph); free(softc, M_DEVBUF); } Index: sys/cam/scsi/scsi_all.c =================================================================== --- sys/cam/scsi/scsi_all.c (revision 189063) +++ sys/cam/scsi/scsi_all.c (working copy) @@ -2263,6 +2263,7 @@ scsi_print_inquiry(struct scsi_inquiry_data *inq_d break; case T_NODEVICE: dtype = "Uninstalled"; + break; default: dtype = "unknown"; break; Index: sys/cam/scsi/scsi_sg.c =================================================================== --- sys/cam/scsi/scsi_sg.c (revision 189063) +++ sys/cam/scsi/scsi_sg.c (working copy) @@ -200,11 +200,12 @@ sgcleanup(struct cam_periph *periph) struct sg_softc *softc; softc = (struct sg_softc *)periph->softc; + if (bootverbose) + xpt_print(periph->path, "removing device entry\n"); devstat_remove_entry(softc->device_stats); + cam_periph_unlock(periph); destroy_dev(softc->dev); - if (bootverbose) { - xpt_print(periph->path, "removing device entry\n"); - } + cam_periph_lock(periph); free(softc, M_DEVBUF); } @@ -940,6 +941,7 @@ sg_scsiio_status(struct ccb_scsiio *csio, u_short case CAM_DEV_NOT_THERE: *hoststat = DID_BAD_TARGET; *drvstat = 0; + break; case CAM_SEL_TIMEOUT: *hoststat = DID_NO_CONNECT; *drvstat = 0; Index: sys/cam/cam_xpt.c =================================================================== --- sys/cam/cam_xpt.c (revision 189063) +++ sys/cam/cam_xpt.c (working copy) @@ -698,19 +698,6 @@ static struct cdevsw xpt_cdevsw = { }; -static void dead_sim_action(struct cam_sim *sim, union ccb *ccb); -static void dead_sim_poll(struct cam_sim *sim); - -/* Dummy SIM that is used when the real one has gone. */ -static struct cam_sim cam_dead_sim = { - .sim_action = dead_sim_action, - .sim_poll = dead_sim_poll, - .sim_name = "dead_sim", -}; - -#define SIM_DEAD(sim) ((sim) == &cam_dead_sim) - - /* Storage for debugging datastructures */ #ifdef CAMDEBUG struct cam_path *cam_dpath; @@ -2655,6 +2642,39 @@ xptbustraverse(struct cam_eb *start_bus, xpt_busfu return(retval); } +int +xpt_sim_opened(struct cam_sim *sim) +{ + struct cam_eb *bus; + struct cam_et *target; + struct cam_ed *device; + struct cam_periph *periph; + + KASSERT(sim->refcount >= 1, ("sim->refcount >= 1")); + mtx_assert(sim->mtx, MA_OWNED); + + mtx_lock(&xsoftc.xpt_topo_lock); + TAILQ_FOREACH(bus, &xsoftc.xpt_busses, links) { + if (bus->sim != sim) + continue; + + TAILQ_FOREACH(target, &bus->et_entries, links) { + TAILQ_FOREACH(device, &target->ed_entries, links) { + SLIST_FOREACH(periph, &device->periphs, + periph_links) { + if (periph->refcount > 0) { + mtx_unlock(&xsoftc.xpt_topo_lock); + return (1); + } + } + } + } + } + + mtx_unlock(&xsoftc.xpt_topo_lock); + return (0); +} + static int xpttargettraverse(struct cam_eb *bus, struct cam_et *start_target, xpt_targetfunc_t *tr_func, void *arg) @@ -3023,19 +3043,10 @@ xpt_action(union ccb *start_ccb) case XPT_ENG_EXEC: { struct cam_path *path; - struct cam_sim *sim; int runq; path = start_ccb->ccb_h.path; - sim = path->bus->sim; - if (SIM_DEAD(sim)) { - /* The SIM has gone; just execute the CCB directly. */ - cam_ccbq_send_ccb(&path->device->ccbq, start_ccb); - (*(sim->sim_action))(sim, start_ccb); - break; - } - cam_ccbq_insert_ccb(&path->device->ccbq, start_ccb); if (path->device->qfrozen_cnt == 0) runq = xpt_schedule_dev_sendq(path->bus, path->device); @@ -3623,7 +3634,6 @@ void xpt_schedule(struct cam_periph *perph, u_int32_t new_priority) { struct cam_ed *device; - union ccb *work_ccb; int runq; mtx_assert(perph->sim->mtx, MA_OWNED); @@ -3640,15 +3650,6 @@ xpt_schedule(struct cam_periph *perph, u_int32_t n new_priority); } runq = 0; - } else if (SIM_DEAD(perph->path->bus->sim)) { - /* The SIM is gone so just call periph_start directly. */ - work_ccb = xpt_get_ccb(perph->path->device); - if (work_ccb == NULL) - return; /* XXX */ - xpt_setup_ccb(&work_ccb->ccb_h, perph->path, new_priority); - perph->pinfo.priority = new_priority; - perph->periph_start(perph, work_ccb); - return; } else { /* New entry on the queue */ CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE, @@ -4176,7 +4177,10 @@ xpt_path_string(struct cam_path *path, char *str, { struct sbuf sb; - mtx_assert(path->bus->sim->mtx, MA_OWNED); +#ifdef INVARIANTS + if (path != NULL && path->bus != NULL) + mtx_assert(path->bus->sim->mtx, MA_OWNED); +#endif sbuf_new(&sb, str, str_len, 0); @@ -4309,7 +4313,7 @@ xpt_release_ccb(union ccb *free_ccb) * for this new bus and places it in the array of busses and assigns * it a path_id. The path_id may be influenced by "hard wiring" * information specified by the user. Once interrupt services are - * availible, the bus will be probed. + * available, the bus will be probed. */ int32_t xpt_bus_register(struct cam_sim *sim, device_t parent, u_int32_t bus) @@ -4336,6 +4340,7 @@ xpt_bus_register(struct cam_sim *sim, device_t par TAILQ_INIT(&new_bus->et_entries); new_bus->path_id = sim->path_id; + cam_sim_hold(sim); new_bus->sim = sim; timevalclear(&new_bus->last_reset); new_bus->flags = 0; @@ -4372,15 +4377,8 @@ int32_t xpt_bus_deregister(path_id_t pathid) { struct cam_path bus_path; - struct cam_ed *device; - struct cam_ed_qinfo *qinfo; - struct cam_devq *devq; - struct cam_periph *periph; - struct cam_sim *ccbsim; - union ccb *work_ccb; cam_status status; - status = xpt_compile_path(&bus_path, NULL, pathid, CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); if (status != CAM_REQ_CMP) @@ -4389,42 +4387,6 @@ xpt_bus_deregister(path_id_t pathid) xpt_async(AC_LOST_DEVICE, &bus_path, NULL); xpt_async(AC_PATH_DEREGISTERED, &bus_path, NULL); - /* The SIM may be gone, so use a dummy SIM for any stray operations. */ - devq = bus_path.bus->sim->devq; - ccbsim = bus_path.bus->sim; - bus_path.bus->sim = &cam_dead_sim; - - /* Execute any pending operations now. */ - while ((qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->send_queue, - CAMQ_HEAD)) != NULL || - (qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->alloc_queue, - CAMQ_HEAD)) != NULL) { - do { - device = qinfo->device; - work_ccb = cam_ccbq_peek_ccb(&device->ccbq, CAMQ_HEAD); - if (work_ccb != NULL) { - devq->active_dev = device; - cam_ccbq_remove_ccb(&device->ccbq, work_ccb); - cam_ccbq_send_ccb(&device->ccbq, work_ccb); - (*(ccbsim->sim_action))(ccbsim, work_ccb); - } - - periph = (struct cam_periph *)camq_remove(&device->drvq, - CAMQ_HEAD); - if (periph != NULL) - xpt_schedule(periph, periph->pinfo.priority); - } while (work_ccb != NULL || periph != NULL); - } - - /* Make sure all completed CCBs are processed. */ - while (!TAILQ_EMPTY(&ccbsim->sim_doneq)) { - camisr_runqueue(&ccbsim->sim_doneq); - - /* Repeat the async's for the benefit of any new devices. */ - xpt_async(AC_LOST_DEVICE, &bus_path, NULL); - xpt_async(AC_PATH_DEREGISTERED, &bus_path, NULL); - } - /* Release the reference count held while registered. */ xpt_release_bus(bus_path.bus); xpt_release_path(&bus_path); @@ -4921,6 +4883,7 @@ xpt_release_bus(struct cam_eb *bus) TAILQ_REMOVE(&xsoftc.xpt_busses, bus, links); xsoftc.bus_generation++; mtx_unlock(&xsoftc.xpt_topo_lock); + cam_sim_release(bus->sim); free(bus, M_CAMXPT); } } @@ -4982,9 +4945,6 @@ xpt_alloc_device(struct cam_eb *bus, struct cam_et struct cam_devq *devq; cam_status status; - if (SIM_DEAD(bus->sim)) - return (NULL); - /* Make space for us in the device queue on our bus */ devq = bus->sim->devq; status = cam_devq_resize(devq, devq->alloc_queue.array_size + 1); @@ -5094,11 +5054,9 @@ xpt_release_device(struct cam_eb *bus, struct cam_ TAILQ_REMOVE(&target->ed_entries, device,links); target->generation++; bus->sim->max_ccbs -= device->ccbq.devq_openings; - if (!SIM_DEAD(bus->sim)) { - /* Release our slot in the devq */ - devq = bus->sim->devq; - cam_devq_resize(devq, devq->alloc_queue.array_size - 1); - } + /* Release our slot in the devq */ + devq = bus->sim->devq; + cam_devq_resize(devq, devq->alloc_queue.array_size - 1); camq_fini(&device->drvq); camq_fini(&device->ccbq.queue); free(device, M_CAMXPT); @@ -5236,6 +5194,11 @@ xpt_scan_bus(struct cam_periph *periph, union ccb /* Save some state for use while we probe for devices */ scan_info = (xpt_scan_bus_info *) malloc(sizeof(xpt_scan_bus_info), M_CAMXPT, M_NOWAIT); + if (scan_info == NULL) { + request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + xpt_done(request_ccb); + return; + } scan_info->request_ccb = request_ccb; scan_info->cpi = &work_ccb->cpi; @@ -6182,7 +6145,7 @@ probedone(struct cam_periph *periph, union ccb *do } xpt_release_ccb(done_ccb); softc->action = PROBE_TUR_FOR_NEGOTIATION; - xpt_schedule(periph, done_ccb->ccb_h.pinfo.priority); + xpt_schedule(periph, priority); return; } @@ -6392,7 +6355,7 @@ probedone(struct cam_periph *periph, union ccb *do xpt_done(done_ccb); if (TAILQ_FIRST(&softc->request_ccbs) == NULL) { cam_periph_invalidate(periph); - cam_periph_release(periph); + cam_periph_release_locked(periph); } else { probeschedule(periph); } @@ -7269,12 +7232,9 @@ camisr_runqueue(void *V_queue) dev = ccb_h->path->device; cam_ccbq_ccb_done(&dev->ccbq, (union ccb *)ccb_h); + ccb_h->path->bus->sim->devq->send_active--; + ccb_h->path->bus->sim->devq->send_openings++; - if (!SIM_DEAD(ccb_h->path->bus->sim)) { - ccb_h->path->bus->sim->devq->send_active--; - ccb_h->path->bus->sim->devq->send_openings++; - } - if (((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0 && (ccb_h->status&CAM_STATUS_MASK) != CAM_REQUEUE_REQ) || ((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0 @@ -7317,15 +7277,3 @@ camisr_runqueue(void *V_queue) } } -static void -dead_sim_action(struct cam_sim *sim, union ccb *ccb) -{ - - ccb->ccb_h.status = CAM_DEV_NOT_THERE; - xpt_done(ccb); -} - -static void -dead_sim_poll(struct cam_sim *sim) -{ -} Index: sys/fs/hpfs/hpfs_vnops.c =================================================================== --- sys/fs/hpfs/hpfs_vnops.c (revision 189063) +++ sys/fs/hpfs/hpfs_vnops.c (working copy) @@ -663,7 +663,7 @@ hpfs_strategy(ap) bp->b_error = error; bp->b_ioflags |= BIO_ERROR; bufdone(bp); - return (error); + return (0); } if ((long)bp->b_blkno == -1) vfs_bio_clrbuf(bp); Index: sys/fs/devfs/devfs_vnops.c =================================================================== --- sys/fs/devfs/devfs_vnops.c (revision 189063) +++ sys/fs/devfs/devfs_vnops.c (working copy) @@ -481,12 +481,28 @@ devfs_close_f(struct file *fp, struct thread *td) return (error); } -/* ARGSUSED */ static int devfs_fsync(struct vop_fsync_args *ap) { - if (!vn_isdisk(ap->a_vp, NULL)) + int error; + struct bufobj *bo; + struct devfs_dirent *de; + + if (!vn_isdisk(ap->a_vp, &error)) { + bo = &ap->a_vp->v_bufobj; + de = ap->a_vp->v_data; + if (error == ENXIO && bo->bo_dirty.bv_cnt > 0) { + printf("Device %s went missing before all of the data " + "could be written to it; expect data loss.\n", + de->de_dirent->d_name); + + error = vop_stdfsync(ap); + if (bo->bo_dirty.bv_cnt != 0 || error != 0) + panic("devfs_fsync: vop_stdfsync failed."); + } + return (0); + } return (vop_stdfsync(ap)); } Index: sys/fs/smbfs/smbfs_vnops.c =================================================================== --- sys/fs/smbfs/smbfs_vnops.c (revision 189063) +++ sys/fs/smbfs/smbfs_vnops.c (working copy) @@ -864,7 +864,7 @@ smbfs_strategy (ap) if ((bp->b_flags & B_ASYNC) == 0 ) error = smbfs_doio(ap->a_vp, bp, cr, td); - return error; + return (0); } int Index: sys/fs/ntfs/ntfs_vnops.c =================================================================== --- sys/fs/ntfs/ntfs_vnops.c (revision 189063) +++ sys/fs/ntfs/ntfs_vnops.c (working copy) @@ -339,7 +339,7 @@ ntfs_strategy(ap) } } bufdone(bp); - return (error); + return (0); } static int Index: sys/fs/nwfs/nwfs_vnops.c =================================================================== --- sys/fs/nwfs/nwfs_vnops.c (revision 189063) +++ sys/fs/nwfs/nwfs_vnops.c (working copy) @@ -807,7 +807,7 @@ static int nwfs_strategy (ap) */ if ((bp->b_flags & B_ASYNC) == 0 ) error = nwfs_doio(ap->a_vp, bp, cr, td); - return (error); + return (0); } Index: sys/fs/msdosfs/msdosfs_conv.c =================================================================== --- sys/fs/msdosfs/msdosfs_conv.c (revision 189063) +++ sys/fs/msdosfs/msdosfs_conv.c (working copy) @@ -1060,8 +1060,11 @@ mbnambuf_write(struct mbnambuf *nbp, char *name, i char *slot; size_t count, newlen; - KASSERT(nbp->nb_len == 0 || id == nbp->nb_last_id - 1, - ("non-decreasing id: id %d, last id %d", id, nbp->nb_last_id)); + if (nbp->nb_len != 0 && id != nbp->nb_last_id - 1) { + printf("msdosfs: non-decreasing id: id %d, last id %d\n", + id, nbp->nb_last_id); + return; + } /* Will store this substring in a WIN_CHARS-aligned slot. */ slot = &nbp->nb_buf[id * WIN_CHARS]; Index: sys/fs/msdosfs/msdosfs_vnops.c =================================================================== --- sys/fs/msdosfs/msdosfs_vnops.c (revision 189063) +++ sys/fs/msdosfs/msdosfs_vnops.c (working copy) @@ -1880,7 +1880,7 @@ msdosfs_strategy(ap) bp->b_error = error; bp->b_ioflags |= BIO_ERROR; bufdone(bp); - return (error); + return (0); } if ((long)bp->b_blkno == -1) vfs_bio_clrbuf(bp); Index: sys/fs/msdosfs/msdosfs_denode.c =================================================================== --- sys/fs/msdosfs/msdosfs_denode.c (revision 189063) +++ sys/fs/msdosfs/msdosfs_denode.c (working copy) @@ -169,6 +169,7 @@ deget(pmp, dirclust, diroffset, depp) ldep->de_dirclust = dirclust; ldep->de_diroffset = diroffset; ldep->de_inode = inode; + ldep->de_dev = pmp->pm_devvp->v_rdev; fc_purge(ldep, 0); /* init the fat cache for this denode */ td = curthread; Index: sys/dev/ata/atapi-cam.c =================================================================== --- sys/dev/ata/atapi-cam.c (revision 189063) +++ sys/dev/ata/atapi-cam.c (working copy) @@ -254,6 +254,10 @@ atapi_cam_detach(device_t dev) struct atapi_xpt_softc *scp = device_get_softc(dev); mtx_lock(&scp->state_lock); + if (xpt_sim_opened(scp->sim)) { + mtx_unlock(&scp->state_lock); + return (EBUSY); + } xpt_freeze_simq(scp->sim, 1 /*count*/); scp->flags |= DETACHING; mtx_unlock(&scp->state_lock); Index: sys/geom/geom_vfs.c =================================================================== --- sys/geom/geom_vfs.c (revision 189063) +++ sys/geom/geom_vfs.c (working copy) @@ -71,6 +71,16 @@ g_vfs_done(struct bio *bip) struct buf *bp; int vfslocked; + /* + * Provider ('bio_to') could have withered away sometime + * between incrementing the 'nend' in g_io_deliver() and now, + * making 'bio_to' a dangling pointer. We cannot do that + * in g_wither_geom(), as it would require going over + * the 'g_bio_run_up' list, resetting the pointer. + */ + if (bip->bio_from->provider == NULL) + bip->bio_to = NULL; + if (bip->bio_error) { printf("g_vfs_done():"); g_print_bio(bip); @@ -93,10 +103,23 @@ g_vfs_strategy(struct bufobj *bo, struct buf *bp) { struct g_consumer *cp; struct bio *bip; + int vfslocked; cp = bo->bo_private; G_VALID_CONSUMER(cp); + /* + * If the the provider has orphaned us, just return EXIO. + */ + if (cp->provider == NULL) { + bp->b_error = ENXIO; + bp->b_ioflags |= BIO_ERROR; + vfslocked = VFS_LOCK_GIANT(((struct mount *)NULL)); + bufdone(bp); + VFS_UNLOCK_GIANT(vfslocked); + return; + } + bip = g_alloc_bio(); bip->bio_cmd = bp->b_iocmd; bip->bio_offset = bp->b_iooffset; @@ -110,18 +133,20 @@ g_vfs_strategy(struct bufobj *bo, struct buf *bp) static void g_vfs_orphan(struct g_consumer *cp) { + struct g_geom *gp; + struct bufobj *bo; + g_topology_assert(); + + gp = cp->geom; + bo = gp->softc; + g_trace(G_T_TOPOLOGY, "g_vfs_orphan(%p(%s))", cp, gp->name); + if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) + g_access(cp, -cp->acr, -cp->acw, -cp->ace); + g_detach(cp); + /* - * Don't do anything here yet. - * - * Ideally we should detach the consumer already now, but that - * leads to a locking requirement in the I/O path to see if we have - * a consumer or not. Considering how ugly things are going to get - * anyway as none of our filesystems are graceful about i/o errors, - * this is not important right now. - * - * Down the road, this is the place where we could give the user - * a "Abort, Retry or Ignore" option to replace the media again. + * Do not destroy the geom. Filesystem will do that during unmount. */ }