diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c --- a/sys/cam/ata/ata_da.c +++ b/sys/cam/ata/ata_da.c @@ -1845,9 +1845,11 @@ TASK_INIT(&softc->sysctl_task, 0, adasysctlinit, periph); /* - * Register this media as a disk + * Take a reference on the periph while adastart is called to finish + * the probe. The reference will be dropped in adaprobedone at the + * end of probe. */ - (void)cam_periph_hold(periph, PRIBIO); + (void)cam_periph_acquire(periph); cam_periph_unlock(periph); snprintf(announce_buf, ADA_ANNOUNCETMP_SZ, "kern.cam.ada.%d.quirks", periph->unit_number); @@ -1905,19 +1907,6 @@ softc->disk->d_name = "ada"; softc->disk->d_drv1 = periph; softc->disk->d_unit = periph->unit_number; - - /* - * Acquire a reference to the periph before we register with GEOM. - * We'll release this reference once GEOM calls us back (via - * adadiskgonecb()) telling us that our provider has been freed. - */ - if (cam_periph_acquire(periph) != 0) { - xpt_print(periph->path, "%s: lost periph during " - "registration!\n", __func__); - cam_periph_lock(periph); - return (CAM_REQ_CMP_ERR); - } - disk_create(softc->disk, DISK_VERSION); cam_periph_lock(periph); dp = &softc->params; @@ -1960,6 +1949,9 @@ SBT_1S / ADA_ORDEREDTAG_INTERVAL * ada_default_timeout, 0, adasendorderedtag, softc, C_PREL(1)); + /* Released after probe when disk_create() call pass it to GEOM. */ + cam_periph_hold_boot(periph); + if (ADA_RA >= 0 && softc->flags & ADA_FLAG_CAN_RAHEAD) { softc->state = ADA_STATE_RAHEAD; } else if (ADA_WC >= 0 && softc->flags & ADA_FLAG_CAN_WCACHE) { @@ -1977,7 +1969,6 @@ } xpt_schedule(periph, CAM_PRIORITY_DEV); - return(CAM_REQ_CMP); } @@ -2705,10 +2696,17 @@ adaschedule(periph); if ((softc->flags & ADA_FLAG_ANNOUNCED) == 0) { softc->flags |= ADA_FLAG_ANNOUNCED; - cam_periph_unhold(periph); - } else { - cam_periph_release_locked(periph); + + /* + * We'll release this reference once GEOM calls us back via + * adadiskgonecb(), telling us that our provider has been freed. + */ + if (cam_periph_acquire(periph) == 0) + disk_create(softc->disk, DISK_VERSION); + + cam_periph_release_boot(periph); } + cam_periph_release_locked(periph); } static void diff --git a/sys/cam/cam_periph.h b/sys/cam/cam_periph.h --- a/sys/cam/cam_periph.h +++ b/sys/cam/cam_periph.h @@ -150,6 +150,7 @@ ac_code deferred_ac; struct task periph_run_task; uma_zone_t ccb_zone; + struct root_hold_token periph_rootmount; }; #define CAM_PERIPH_MAXMAPS 2 @@ -175,6 +176,8 @@ void cam_periph_release_locked_buses(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_hold_boot(struct cam_periph *periph); +void cam_periph_release_boot(struct cam_periph *periph); void cam_periph_invalidate(struct cam_periph *periph); int cam_periph_mapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo, diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c --- a/sys/cam/cam_periph.c +++ b/sys/cam/cam_periph.c @@ -530,6 +530,20 @@ cam_periph_release_locked(periph); } +void +cam_periph_hold_boot(struct cam_periph *periph) +{ + + root_mount_hold_token(periph->periph_name, &periph->periph_rootmount); +} + +void +cam_periph_release_boot(struct cam_periph *periph) +{ + + root_mount_rel(&periph->periph_rootmount); +} + /* * Look for the next unit number that is not currently in use for this * peripheral type starting at "newunit". Also exclude unit numbers that diff --git a/sys/cam/nvme/nvme_da.c b/sys/cam/nvme/nvme_da.c --- a/sys/cam/nvme/nvme_da.c +++ b/sys/cam/nvme/nvme_da.c @@ -886,7 +886,7 @@ /* * Register this media as a disk */ - (void)cam_periph_hold(periph, PRIBIO); + (void)cam_periph_acquire(periph); cam_periph_unlock(periph); snprintf(announce_buf, sizeof(announce_buf), "kern.cam.nda.%d.quirks", periph->unit_number); @@ -964,20 +964,7 @@ if (nda_nvd_compat) disk_add_alias(disk, "nvd"); - /* - * Acquire a reference to the periph before we register with GEOM. - * We'll release this reference once GEOM calls us back (via - * ndadiskgonecb()) telling us that our provider has been freed. - */ - if (cam_periph_acquire(periph) != 0) { - xpt_print(periph->path, "%s: lost periph during " - "registration!\n", __func__); - cam_periph_lock(periph); - return (CAM_REQ_CMP_ERR); - } - disk_create(softc->disk, DISK_VERSION); cam_periph_lock(periph); - cam_periph_unhold(periph); snprintf(announce_buf, sizeof(announce_buf), "%juMB (%ju %u byte sectors)", @@ -1002,6 +989,15 @@ ndaasync, periph, periph->path); softc->state = NDA_STATE_NORMAL; + + /* + * We'll release this reference once GEOM calls us back via + * ndadiskgonecb(), telling us that our provider has been freed. + */ + if (cam_periph_acquire(periph) == 0) + disk_create(softc->disk, DISK_VERSION); + + cam_periph_release_locked(periph); return(CAM_REQ_CMP); } diff --git a/sys/cam/scsi/scsi_cd.c b/sys/cam/scsi/scsi_cd.c --- a/sys/cam/scsi/scsi_cd.c +++ b/sys/cam/scsi/scsi_cd.c @@ -650,10 +650,10 @@ softc->minimum_command_size = 6; /* - * Refcount and block open attempts until we are setup - * Can't block + * Take a reference on the periph while cdstart is called to finish the + * probe. The reference will be dropped in cddone at the end of probe. */ - (void)cam_periph_hold(periph, PRIBIO); + (void)cam_periph_acquire(periph); cam_periph_unlock(periph); /* * Load the user's default, if any. @@ -714,20 +714,6 @@ softc->disk->d_hba_subdevice = cpi.hba_subdevice; snprintf(softc->disk->d_attachment, sizeof(softc->disk->d_attachment), "%s%d", cpi.dev_name, cpi.unit_number); - - /* - * Acquire a reference to the periph before we register with GEOM. - * We'll release this reference once GEOM calls us back (via - * dadiskgonecb()) telling us that our provider has been freed. - */ - if (cam_periph_acquire(periph) != 0) { - xpt_print(periph->path, "%s: lost periph during " - "registration!\n", __func__); - cam_periph_lock(periph); - return (CAM_REQ_CMP_ERR); - } - - disk_create(softc->disk, DISK_VERSION); cam_periph_lock(periph); /* @@ -748,6 +734,9 @@ 0, cdmediapoll, periph, C_PREL(1)); } + /* Released after probe when disk_create() call pass it to GEOM. */ + cam_periph_hold_boot(periph); + xpt_schedule(periph, CAM_PRIORITY_DEV); return(CAM_REQ_CMP); } @@ -1385,7 +1374,16 @@ * operation. */ xpt_release_ccb(done_ccb); - cam_periph_unhold(periph); + + /* + * We'll release this reference once GEOM calls us back via + * cddiskgonecb(), telling us that our provider has been freed. + */ + if (cam_periph_acquire(periph) == 0) + disk_create(softc->disk, DISK_VERSION); + + cam_periph_release_boot(periph); + cam_periph_release_locked(periph); return; } case CD_CCB_TUR: diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -329,7 +329,6 @@ DA_REF_OPEN = 1, DA_REF_OPEN_HOLD, DA_REF_CLOSE_HOLD, - DA_REF_PROBE_HOLD, DA_REF_TUR, DA_REF_GEOM, DA_REF_SYSCTL, @@ -2602,9 +2601,17 @@ wakeup(&softc->disk->d_mediasize); if ((softc->flags & DA_FLAG_ANNOUNCED) == 0) { softc->flags |= DA_FLAG_ANNOUNCED; - da_periph_unhold(periph, DA_REF_PROBE_HOLD); - } else - da_periph_release_locked(periph, DA_REF_REPROBE); + + /* + * We'll release this reference once GEOM calls us back via + * dadiskgonecb(), telling us that our provider has been freed. + */ + if (da_periph_acquire(periph, DA_REF_GEOM) == 0) + disk_create(softc->disk, DISK_VERSION); + + cam_periph_release_boot(periph); + } + da_periph_release_locked(periph, DA_REF_REPROBE); } static void @@ -2864,14 +2871,10 @@ } /* - * Take an exclusive section lock on the periph while dastart is called - * to finish the probe. The lock will be dropped in dadone at the end - * of probe. This locks out daopen and daclose from racing with the - * probe. - * - * XXX if cam_periph_hold returns an error, we don't hold a refcount. + * Take a reference on the periph while dastart is called to finish the + * probe. The reference will be dropped in dadone at the end of probe. */ - (void)da_periph_hold(periph, PRIBIO, DA_REF_PROBE_HOLD); + (void)da_periph_acquire(periph, DA_REF_REPROBE); /* * Schedule a periodic event to occasionally send an @@ -2967,20 +2970,6 @@ softc->disk->d_hba_subdevice = cpi.hba_subdevice; snprintf(softc->disk->d_attachment, sizeof(softc->disk->d_attachment), "%s%d", cpi.dev_name, cpi.unit_number); - - /* - * Acquire a reference to the periph before we register with GEOM. - * We'll release this reference once GEOM calls us back (via - * dadiskgonecb()) telling us that our provider has been freed. - */ - if (da_periph_acquire(periph, DA_REF_GEOM) != 0) { - xpt_print(periph->path, "%s: lost periph during " - "registration!\n", __func__); - cam_periph_lock(periph); - return (CAM_REQ_CMP_ERR); - } - - disk_create(softc->disk, DISK_VERSION); cam_periph_lock(periph); /* @@ -2994,14 +2983,6 @@ AC_ADVINFO_CHANGED | AC_SCSI_AEN | AC_UNIT_ATTENTION | AC_INQ_CHANGED, daasync, periph, periph->path); - /* - * Emit an attribute changed notification just in case - * physical path information arrived before our async - * event handler was registered, but after anyone attaching - * to our disk device polled it. - */ - disk_attr_changed(softc->disk, "GEOM::physpath", M_NOWAIT); - /* * Schedule a periodic media polling events. */ @@ -3013,8 +2994,10 @@ 0, damediapoll, periph, C_PREL(1)); } - xpt_schedule(periph, CAM_PRIORITY_DEV); + /* Released after probe when disk_create() call pass it to GEOM. */ + cam_periph_hold_boot(periph); + xpt_schedule(periph, CAM_PRIORITY_DEV); return(CAM_REQ_CMP); } diff --git a/sys/cam/scsi/scsi_enc.c b/sys/cam/scsi/scsi_enc.c --- a/sys/cam/scsi/scsi_enc.c +++ b/sys/cam/scsi/scsi_enc.c @@ -205,7 +205,7 @@ if (enc->enc_vec.softc_cleanup != NULL) enc->enc_vec.softc_cleanup(enc); - root_mount_rel(&enc->enc_rootmount); + cam_periph_release_boot(periph); ENC_FREE(enc); } @@ -842,7 +842,7 @@ * We've been through our state machine at least * once. Allow the transition to userland. */ - root_mount_rel(&enc->enc_rootmount); + cam_periph_release_boot(enc->periph); callout_reset_sbt(&enc->status_updater, 60 * SBT_1S, 0, enc_status_updater, enc, C_PREL(1)); @@ -937,9 +937,8 @@ * through our state machine so that physical path data is * present. */ - if (enc->enc_vec.poll_status != NULL) { - root_mount_hold_token(periph->periph_name, &enc->enc_rootmount); - } + if (enc->enc_vec.poll_status != NULL) + cam_periph_hold_boot(periph); /* * The softc field is set only once the enc is fully initialized diff --git a/sys/cam/scsi/scsi_enc_internal.h b/sys/cam/scsi/scsi_enc_internal.h --- a/sys/cam/scsi/scsi_enc_internal.h +++ b/sys/cam/scsi/scsi_enc_internal.h @@ -161,8 +161,6 @@ struct enc_fsm_state *enc_fsm_states; - struct root_hold_token enc_rootmount; - #define ENC_ANNOUNCE_SZ 400 char announce_buf[ENC_ANNOUNCE_SZ]; }; diff --git a/sys/geom/geom_disk.h b/sys/geom/geom_disk.h --- a/sys/geom/geom_disk.h +++ b/sys/geom/geom_disk.h @@ -69,6 +69,7 @@ typedef enum { DISK_INIT_NONE, + DISK_INIT_CREATE, DISK_INIT_START, DISK_INIT_DONE } disk_init_level; @@ -125,7 +126,8 @@ /* Fields private to geom_disk, to be moved on next version bump */ LIST_HEAD(,disk_alias) d_aliases; - struct g_event *d_event; + struct g_event *d_cevent; + struct g_event *d_devent; }; #define DISKFLAG_RESERVED 0x0001 /* Was NEEDSGIANT */ diff --git a/sys/geom/geom_disk.c b/sys/geom/geom_disk.c --- a/sys/geom/geom_disk.c +++ b/sys/geom/geom_disk.c @@ -721,6 +721,11 @@ sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO); mtx_init(&sc->done_mtx, "g_disk_done", NULL, MTX_DEF); sc->dp = dp; + if (dp->d_devstat == NULL) { + dp->d_devstat = devstat_new_entry(dp->d_name, dp->d_unit, + dp->d_sectorsize, DEVSTAT_ALL_SUPPORTED, + DEVSTAT_TYPE_DIRECT, DEVSTAT_PRIORITY_MAX); + } sc->d_devstat = dp->d_devstat; gp = g_new_geomf(&g_disk_class, "%s%d", dp->d_name, dp->d_unit); gp->softc = sc; @@ -862,6 +867,9 @@ dp = g_malloc(sizeof(struct disk), M_WAITOK | M_ZERO); LIST_INIT(&dp->d_aliases); + dp->d_init_level = DISK_INIT_NONE; + dp->d_cevent = g_alloc_event(M_WAITOK); + dp->d_devent = g_alloc_event(M_WAITOK); return (dp); } @@ -888,31 +896,40 @@ KASSERT(dp->d_name != NULL, ("disk_create need d_name")); KASSERT(*dp->d_name != 0, ("disk_create need d_name")); KASSERT(strlen(dp->d_name) < SPECNAMELEN - 4, ("disk name too long")); - if (dp->d_devstat == NULL) - dp->d_devstat = devstat_new_entry(dp->d_name, dp->d_unit, - dp->d_sectorsize, DEVSTAT_ALL_SUPPORTED, - DEVSTAT_TYPE_DIRECT, DEVSTAT_PRIORITY_MAX); - dp->d_geom = NULL; - dp->d_event = g_alloc_event(M_WAITOK); + g_disk_ident_adjust(dp->d_ident, sizeof(dp->d_ident)); - dp->d_init_level = DISK_INIT_NONE; + dp->d_init_level = DISK_INIT_CREATE; - g_disk_ident_adjust(dp->d_ident, sizeof(dp->d_ident)); - g_post_event(g_disk_create, dp, M_WAITOK, dp, NULL); + KASSERT(dp->d_cevent != NULL, + ("Disk create for %p with event NULL", dp)); + g_post_event_ep(g_disk_create, dp, dp->d_cevent, dp, NULL); } void disk_destroy(struct disk *dp) { + struct disk_alias *dap, *daptmp; - KASSERT(dp->d_event != NULL, + /* If disk_create() was never called, just free the resources. */ + if (dp->d_init_level < DISK_INIT_CREATE) { + if (dp->d_devstat != NULL) + devstat_remove_entry(dp->d_devstat); + LIST_FOREACH_SAFE(dap, &dp->d_aliases, da_next, daptmp) + g_free(dap); + g_free(dp->d_cevent); + g_free(dp->d_devent); + g_free(dp); + return; + } + + KASSERT(dp->d_devent != NULL, ("Disk destroy for %p with event NULL", dp)); disk_gone(dp); dp->d_destroyed = 1; g_cancel_event(dp); if (dp->d_devstat != NULL) devstat_remove_entry(dp->d_devstat); - g_post_event_ep(g_disk_destroy, dp, dp->d_event, NULL); + g_post_event_ep(g_disk_destroy, dp, dp->d_devent, NULL); } void @@ -979,14 +996,14 @@ void disk_attr_changed(struct disk *dp, const char *attr, int flag) { - struct g_geom *gp; + struct g_geom *gp = dp->d_geom; struct g_provider *pp; char devnamebuf[128]; - gp = dp->d_geom; - if (gp != NULL) - LIST_FOREACH(pp, &gp->provider, provider) - (void)g_attr_changed(pp, attr, flag); + if (gp == NULL) + return; + LIST_FOREACH(pp, &gp->provider, provider) + (void)g_attr_changed(pp, attr, flag); snprintf(devnamebuf, sizeof(devnamebuf), "devname=%s%d", dp->d_name, dp->d_unit); devctl_notify("GEOM", "disk", attr, devnamebuf); @@ -995,34 +1012,32 @@ void disk_media_changed(struct disk *dp, int flag) { - struct g_geom *gp; + struct g_geom *gp = dp->d_geom; struct g_provider *pp; - gp = dp->d_geom; - if (gp != NULL) { - pp = LIST_FIRST(&gp->provider); - if (pp != NULL) { - KASSERT(LIST_NEXT(pp, provider) == NULL, - ("geom %p has more than one provider", gp)); - g_media_changed(pp, flag); - } + if (gp == NULL) + return; + pp = LIST_FIRST(&gp->provider); + if (pp != NULL) { + KASSERT(LIST_NEXT(pp, provider) == NULL, + ("geom %p has more than one provider", gp)); + g_media_changed(pp, flag); } } void disk_media_gone(struct disk *dp, int flag) { - struct g_geom *gp; + struct g_geom *gp = dp->d_geom; struct g_provider *pp; - gp = dp->d_geom; - if (gp != NULL) { - pp = LIST_FIRST(&gp->provider); - if (pp != NULL) { - KASSERT(LIST_NEXT(pp, provider) == NULL, - ("geom %p has more than one provider", gp)); - g_media_gone(pp, flag); - } + if (gp == NULL) + return; + pp = LIST_FIRST(&gp->provider); + if (pp != NULL) { + KASSERT(LIST_NEXT(pp, provider) == NULL, + ("geom %p has more than one provider", gp)); + g_media_gone(pp, flag); } }