DF-4900 / fix.diff
--- a/sys/dev/disk/dm/dm_dev.c +++ b/sys/dev/disk/dm/dm_dev.c @@ -231,7 +231,18 @@ if ((dmv = dm_dev_alloc(name, uuid)) == NULL) return ENOMEM; - dm_minor = devfs_clone_bitmap_get(&dm_minor_bitmap, 0); + /* + * The dev_t minor encoding (dkmakeminor in <sys/diskslice.h>) only + * has room for DKMAXUNITS (512) distinct units. Handing out unit + * numbers beyond that aliases the minor numbers of live dm devices + * (duplicate device numbers, KKASSERT panic in dm_dev_insert, and + * dkunit() truncation corrupts the clone bitmap on destroy). + */ + dm_minor = devfs_clone_bitmap_get(&dm_minor_bitmap, DKMAXUNITS - 1); + if (dm_minor < 0) { + dm_dev_free(dmv); + return ENOSPC; + } dm_table_head_init(&dmv->table_head); @@ -287,7 +298,8 @@ devstat_remove_entry(&dmv->stats); release_dev(dmv->devt); - devfs_clone_bitmap_put(&dm_minor_bitmap, minor); + /* dkunit() only decodes DKMAXUNITS worth of unit bits */ + devfs_clone_bitmap_put(&dm_minor_bitmap, minor & (DKMAXUNITS - 1)); lockuninit(&dmv->dev_mtx); cv_destroy(&dmv->dev_cv); |