Avoid issuing spa config updates for physical path when not necessary

ZFS's configuration needs to be updated whenever the physical path for a
device changes, but not when a new device is introduced. This is because new
devices necessarily cause config updates, but only if they are actually
accepted into the pool.

sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c
	Split vdev_geom_set_physpath out of vdev_geom_attrchanged.  When
	setting the vdev's physical path, only request a config update if
	the physical path has changed.  Don't request it when opening a
	device for the first time, because the config sync will happen
	anyway upstack.

sys/geom/geom_dev.c
	Split g_dev_set_physpath and g_dev_set_media out of
	g_dev_attrchanged

Submitted by:	will, asomers
MFC after:	4 weeks
Sponsored by:	Spectra Logic Corp
Differential Revision:	https://reviews.freebsd.org/D6428
This commit is contained in:
Alan Somers 2016-05-27 22:32:44 +00:00
parent 583febf416
commit 151746b244
2 changed files with 91 additions and 57 deletions

View File

@ -85,32 +85,17 @@ vdev_geom_set_rotation_rate(vdev_t *vd, struct g_consumer *cp)
}
static void
vdev_geom_attrchanged(struct g_consumer *cp, const char *attr)
vdev_geom_set_physpath(struct g_consumer *cp, boolean_t do_null_update)
{
boolean_t needs_update;
vdev_t *vd;
spa_t *spa;
char *physpath;
int error, physpath_len;
vd = cp->private;
if (vd == NULL)
return;
if (strcmp(attr, "GEOM::rotation_rate") == 0) {
vdev_geom_set_rotation_rate(vd, cp);
return;
}
if (strcmp(attr, "GEOM::physpath") != 0)
return;
if (g_access(cp, 1, 0, 0) != 0)
return;
/*
* Record/Update physical path information for this device.
*/
spa = vd->vdev_spa;
vd = cp->private;
physpath_len = MAXPATHLEN;
physpath = g_malloc(physpath_len, M_WAITOK|M_ZERO);
error = g_io_getattr("GEOM::physpath", cp, &physpath_len, physpath);
@ -122,12 +107,46 @@ vdev_geom_attrchanged(struct g_consumer *cp, const char *attr)
g_topology_assert();
old_physpath = vd->vdev_physpath;
vd->vdev_physpath = spa_strdup(physpath);
spa_async_request(spa, SPA_ASYNC_CONFIG_UPDATE);
if (old_physpath != NULL)
if (old_physpath != NULL) {
needs_update = (strcmp(old_physpath,
vd->vdev_physpath) != 0);
spa_strfree(old_physpath);
} else
needs_update = do_null_update;
}
g_free(physpath);
/*
* If the physical path changed, update the config.
* Only request an update for previously unset physpaths if
* requested by the caller.
*/
if (needs_update)
spa_async_request(vd->vdev_spa, SPA_ASYNC_CONFIG_UPDATE);
}
static void
vdev_geom_attrchanged(struct g_consumer *cp, const char *attr)
{
vdev_t *vd;
char *old_physpath;
int error;
vd = cp->private;
if (vd == NULL)
return;
if (strcmp(attr, "GEOM::rotation_rate") == 0) {
vdev_geom_set_rotation_rate(vd, cp);
return;
}
if (strcmp(attr, "GEOM::physpath") == 0) {
vdev_geom_set_physpath(cp, /*do_null_update*/B_TRUE);
return;
}
}
static void
@ -257,8 +276,10 @@ vdev_geom_attach(struct g_provider *pp, vdev_t *vd)
* 2) Set it to a linked list of vdevs, not just a single vdev
*/
cp->private = vd;
if (vd != NULL)
if (vd != NULL) {
vd->vdev_tsd = cp;
vdev_geom_set_physpath(cp, /*do_null_update*/B_FALSE);
}
cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
return (cp);

View File

@ -222,55 +222,68 @@ g_dev_print(void)
}
static void
g_dev_attrchanged(struct g_consumer *cp, const char *attr)
g_dev_set_physpath(struct g_consumer *cp)
{
struct g_dev_softc *sc;
char *physpath;
int error, physpath_len;
if (g_access(cp, 1, 0, 0) != 0)
return;
sc = cp->private;
physpath_len = MAXPATHLEN;
physpath = g_malloc(physpath_len, M_WAITOK|M_ZERO);
error = g_io_getattr("GEOM::physpath", cp, &physpath_len, physpath);
g_access(cp, -1, 0, 0);
if (error == 0 && strlen(physpath) != 0) {
struct cdev *dev, *old_alias_dev;
struct cdev **alias_devp;
dev = sc->sc_dev;
old_alias_dev = sc->sc_alias;
alias_devp = (struct cdev **)&sc->sc_alias;
make_dev_physpath_alias(MAKEDEV_WAITOK, alias_devp, dev,
old_alias_dev, physpath);
} else if (sc->sc_alias) {
destroy_dev((struct cdev *)sc->sc_alias);
sc->sc_alias = NULL;
}
g_free(physpath);
}
static void
g_dev_set_media(struct g_consumer *cp)
{
struct g_dev_softc *sc;
struct cdev *dev;
char buf[SPECNAMELEN + 6];
sc = cp->private;
if (strcmp(attr, "GEOM::media") == 0) {
dev = sc->sc_dev;
dev = sc->sc_dev;
snprintf(buf, sizeof(buf), "cdev=%s", dev->si_name);
devctl_notify_f("DEVFS", "CDEV", "MEDIACHANGE", buf, M_WAITOK);
devctl_notify_f("GEOM", "DEV", "MEDIACHANGE", buf, M_WAITOK);
dev = sc->sc_alias;
if (dev != NULL) {
snprintf(buf, sizeof(buf), "cdev=%s", dev->si_name);
devctl_notify_f("DEVFS", "CDEV", "MEDIACHANGE", buf, M_WAITOK);
devctl_notify_f("GEOM", "DEV", "MEDIACHANGE", buf, M_WAITOK);
dev = sc->sc_alias;
if (dev != NULL) {
snprintf(buf, sizeof(buf), "cdev=%s", dev->si_name);
devctl_notify_f("DEVFS", "CDEV", "MEDIACHANGE", buf,
M_WAITOK);
devctl_notify_f("GEOM", "DEV", "MEDIACHANGE", buf,
M_WAITOK);
}
}
}
static void
g_dev_attrchanged(struct g_consumer *cp, const char *attr)
{
if (strcmp(attr, "GEOM::media") == 0) {
g_dev_set_media(cp);
return;
}
if (strcmp(attr, "GEOM::physpath") != 0)
if (strcmp(attr, "GEOM::physpath") == 0) {
g_dev_set_physpath(cp);
return;
if (g_access(cp, 1, 0, 0) == 0) {
char *physpath;
int error, physpath_len;
physpath_len = MAXPATHLEN;
physpath = g_malloc(physpath_len, M_WAITOK|M_ZERO);
error =
g_io_getattr("GEOM::physpath", cp, &physpath_len, physpath);
g_access(cp, -1, 0, 0);
if (error == 0 && strlen(physpath) != 0) {
struct cdev *old_alias_dev;
struct cdev **alias_devp;
dev = sc->sc_dev;
old_alias_dev = sc->sc_alias;
alias_devp = (struct cdev **)&sc->sc_alias;
make_dev_physpath_alias(MAKEDEV_WAITOK, alias_devp,
dev, old_alias_dev, physpath);
} else if (sc->sc_alias) {
destroy_dev((struct cdev *)sc->sc_alias);
sc->sc_alias = NULL;
}
g_free(physpath);
}
}