Fix a bug that caused some /dev entries to continue to exist after

the underlying drive had been hot-unplugged from the system.  Here
is a specific example.  Filesystem code had opened /dev/da1s1e.
Subsequently, the drive was hot-unplugged.  This (correctly) caused
all of the associated /dev/da1* entries to be deleted.  When the
filesystem later realized that the drive was gone it closed the
device, reducing the write-access counts to 0 on the geom providers
for da1s1e, da1s1, and da1.  This caused geom to re-taste the
providers, resulting in the devices being created again.  When the
drive was hot-plugged back in, it resulted in duplicate /dev entries
for da1s1e, da1s1, and da1.

This fix adds a new disk_gone() function which is called by CAM when a
drive goes away.  It orphans all of the providers associated with the
drive, setting an error condition of ENXIO in each one.  In addition,
we prevent a re-taste on last close for writing if an error condition
has been set in the provider.

Sponsored by:   Isilon Systems
Reviewed by:    phk
MFC after:      1 week
This commit is contained in:
jdp 2005-11-18 02:43:49 +00:00
parent 1f2553e461
commit 536960dbba
5 changed files with 18 additions and 2 deletions

View File

@ -407,6 +407,7 @@ cdoninvalidate(struct cam_periph *periph)
&& (softc->pinfo.index != CAM_UNQUEUED_INDEX))
camq_remove(&softc->changer->devq, softc->pinfo.index);
disk_gone(softc->disk);
xpt_print_path(periph->path);
printf("lost device\n");
}

View File

@ -801,6 +801,7 @@ daoninvalidate(struct cam_periph *periph)
SLIST_REMOVE(&softc_list, softc, da_softc, links);
disk_gone(softc->disk);
xpt_print_path(periph->path);
printf("lost device\n");
}

View File

@ -419,6 +419,18 @@ disk_destroy(struct disk *dp)
g_post_event(g_disk_destroy, dp, M_WAITOK, NULL);
}
void
disk_gone(struct disk *dp)
{
struct g_geom *gp;
struct g_provider *pp;
gp = dp->d_geom;
if (gp != NULL)
LIST_FOREACH(pp, &gp->provider, provider)
g_orphan_provider(pp, ENXIO);
}
static void
g_kern_disks(void *p, int flag __unused)
{

View File

@ -95,6 +95,7 @@ struct disk {
struct disk *disk_alloc(void);
void disk_create(struct disk *disk, int version);
void disk_destroy(struct disk *disk);
void disk_gone(struct disk *disk);
#define DISK_VERSION_00 0x58561059
#define DISK_VERSION DISK_VERSION_00

View File

@ -734,11 +734,12 @@ g_access(struct g_consumer *cp, int dcr, int dcw, int dce)
if (!error) {
/*
* If we open first write, spoil any partner consumers.
* If we close last write, trigger re-taste.
* If we close last write and provider is not errored,
* trigger re-taste.
*/
if (pp->acw == 0 && dcw != 0)
g_spoil(pp, cp);
else if (pp->acw != 0 && pp->acw == -dcw &&
else if (pp->acw != 0 && pp->acw == -dcw && pp->error == 0 &&
!(pp->geom->flags & G_GEOM_WITHER))
g_post_event(g_new_provider_event, pp, M_WAITOK,
pp, NULL);