--- subr_diskslice.c.orig +++ subr_diskslice.c @@ -769,6 +769,8 @@ ssp = *sspp; dev->si_bsize_phys = info->d_media_blksize; slice = dkslice(dev); + if (slice >= ssp->dss_nslices) + return (EINVAL); part = dkpart(dev); sp = &ssp->dss_slices[slice]; dssetmask(sp, part); @@ -857,6 +859,12 @@ dev_dclose(dev, FREAD, S_IFCHR, NULL); ssp = *sspp; } + /* + * The re-open above may have serialized with a reprobe; the + * reloaded (or original) ssp must be revalidated before use. + */ + if (slice >= ssp->dss_nslices) + return (-1); lp = ssp->dss_slices[slice].ds_label; if (part == WHOLE_SLICE_PART) { blocks = ssp->dss_slices[slice].ds_size; --- subr_disk.c.orig +++ subr_disk.c @@ -1265,12 +1265,33 @@ if (dp == NULL) return(ENODEV); + /* + * dssize() walks dp->d_slice (and the per-slice disklabel) with no + * internal serialization while disk_probe()/disk_msg_core replace + * and dsgone() those structures under ds_token (DF-2831). Run the + * whole walk under ds_token like diskopen/diskclose/diskioctl do. + * Token acquisition is recursive for the dev_dopen() path inside + * dssize() (diskopen takes ds_token itself), and blocking inside + * the token (sync reprobe messages) releases/reacquires it. + */ + lwkt_gettoken(&ds_token); ap->a_result = dssize(dev, &dp->d_slice); + lwkt_reltoken(&ds_token); if ((ap->a_result == -1) && (dp->d_info.d_dsflags & DSO_RAWPSIZE)) { - ap->a_head.a_dev = dp->d_rawdev; - return dev_doperate(&ap->a_head); + /* + * The raw size describes the whole disk. Substituting it + * for a partition (label-dependent) device silently lies + * about the geometry (DF-2831: swapon on a transiently + * labelless partition installed whole-disk-sized swap). + * Only fall back for whole-disk or whole-slice devices. + */ + if (dkslice(dev) == WHOLE_DISK_SLICE || + dkpart(dev) == WHOLE_SLICE_PART) { + ap->a_head.a_dev = dp->d_rawdev; + return dev_doperate(&ap->a_head); + } } return(0); }