diff options
Diffstat (limited to 'usr/src/lib/libzfs/common')
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs.h | 4 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_import.c | 71 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_pool.c | 138 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_util.c | 2 |
4 files changed, 154 insertions, 61 deletions
diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h index e2ebae01f4..f4ef8adbe5 100644 --- a/usr/src/lib/libzfs/common/libzfs.h +++ b/usr/src/lib/libzfs/common/libzfs.h @@ -113,6 +113,7 @@ enum { EZFS_UNSHARESMBFAILED, /* failed to unshare over smb */ EZFS_SHARESMBFAILED, /* failed to share over smb */ EZFS_BADCACHE, /* bad cache file */ + EZFS_ISL2CACHE, /* device is for the level 2 ARC */ EZFS_UNKNOWN }; @@ -216,7 +217,8 @@ extern int zpool_vdev_fault(zpool_handle_t *, uint64_t); extern int zpool_vdev_degrade(zpool_handle_t *, uint64_t); extern int zpool_vdev_clear(zpool_handle_t *, uint64_t); -extern nvlist_t *zpool_find_vdev(zpool_handle_t *, const char *, boolean_t *); +extern nvlist_t *zpool_find_vdev(zpool_handle_t *, const char *, boolean_t *, + boolean_t *); extern int zpool_label_disk(libzfs_handle_t *, zpool_handle_t *, char *); /* diff --git a/usr/src/lib/libzfs/common/libzfs_import.c b/usr/src/lib/libzfs/common/libzfs_import.c index 50e9ddf97e..a8ae241f88 100644 --- a/usr/src/lib/libzfs/common/libzfs_import.c +++ b/usr/src/lib/libzfs/common/libzfs_import.c @@ -213,11 +213,13 @@ add_config(libzfs_handle_t *hdl, pool_list_t *pl, const char *path, name_entry_t *ne; /* - * If this is a hot spare not currently in use, add it to the list of - * names to translate, but don't do anything else. + * If this is a hot spare not currently in use or level 2 cache + * device, add it to the list of names to translate, but don't do + * anything else. */ if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, - &state) == 0 && state == POOL_STATE_SPARE && + &state) == 0 && + (state == POOL_STATE_SPARE || state == POOL_STATE_L2CACHE) && nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID, &vdev_guid) == 0) { if ((ne = zfs_alloc(hdl, sizeof (name_entry_t))) == NULL) return (-1); @@ -415,8 +417,8 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl) vdev_entry_t *ve; config_entry_t *ce; nvlist_t *ret = NULL, *config = NULL, *tmp, *nvtop, *nvroot; - nvlist_t **spares; - uint_t i, nspares; + nvlist_t **spares, **l2cache; + uint_t i, nspares, nl2cache; boolean_t config_seen; uint64_t best_txg; char *name, *hostname; @@ -647,6 +649,17 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl) } /* + * Update the paths for l2cache devices. + */ + if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, + &l2cache, &nl2cache) == 0) { + for (i = 0; i < nl2cache; i++) { + if (fix_paths(l2cache[i], pl->names) != 0) + goto nomem; + } + } + + /* * Restore the original information read from the actual label. */ (void) nvlist_remove(config, ZPOOL_CONFIG_HOSTID, @@ -728,12 +741,12 @@ zpool_read_label(int fd, nvlist_t **config) continue; if (nvlist_lookup_uint64(*config, ZPOOL_CONFIG_POOL_STATE, - &state) != 0 || state > POOL_STATE_SPARE) { + &state) != 0 || state > POOL_STATE_L2CACHE) { nvlist_free(*config); continue; } - if (state != POOL_STATE_SPARE && + if (state != POOL_STATE_SPARE && state != POOL_STATE_L2CACHE && (nvlist_lookup_uint64(*config, ZPOOL_CONFIG_POOL_TXG, &txg) != 0 || txg == 0)) { nvlist_free(*config); @@ -1001,27 +1014,28 @@ find_guid(nvlist_t *nv, uint64_t guid) return (B_FALSE); } -typedef struct spare_cbdata { +typedef struct aux_cbdata { + const char *cb_type; uint64_t cb_guid; zpool_handle_t *cb_zhp; -} spare_cbdata_t; +} aux_cbdata_t; static int -find_spare(zpool_handle_t *zhp, void *data) +find_aux(zpool_handle_t *zhp, void *data) { - spare_cbdata_t *cbp = data; - nvlist_t **spares; - uint_t i, nspares; + aux_cbdata_t *cbp = data; + nvlist_t **list; + uint_t i, count; uint64_t guid; nvlist_t *nvroot; verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); - if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, - &spares, &nspares) == 0) { - for (i = 0; i < nspares; i++) { - verify(nvlist_lookup_uint64(spares[i], + if (nvlist_lookup_nvlist_array(nvroot, cbp->cb_type, + &list, &count) == 0) { + for (i = 0; i < count; i++) { + verify(nvlist_lookup_uint64(list[i], ZPOOL_CONFIG_GUID, &guid) == 0); if (guid == cbp->cb_guid) { cbp->cb_zhp = zhp; @@ -1050,7 +1064,7 @@ zpool_in_use(libzfs_handle_t *hdl, int fd, pool_state_t *state, char **namestr, zpool_handle_t *zhp; nvlist_t *pool_config; uint64_t stateval, isspare; - spare_cbdata_t cb = { 0 }; + aux_cbdata_t cb = { 0 }; boolean_t isactive; *inuse = B_FALSE; @@ -1068,7 +1082,7 @@ zpool_in_use(libzfs_handle_t *hdl, int fd, pool_state_t *state, char **namestr, verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID, &vdev_guid) == 0); - if (stateval != POOL_STATE_SPARE) { + if (stateval != POOL_STATE_SPARE && stateval != POOL_STATE_L2CACHE) { verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, &name) == 0); verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, @@ -1147,7 +1161,24 @@ zpool_in_use(libzfs_handle_t *hdl, int fd, pool_state_t *state, char **namestr, */ cb.cb_zhp = NULL; cb.cb_guid = vdev_guid; - if (zpool_iter(hdl, find_spare, &cb) == 1) { + cb.cb_type = ZPOOL_CONFIG_SPARES; + if (zpool_iter(hdl, find_aux, &cb) == 1) { + name = (char *)zpool_get_name(cb.cb_zhp); + ret = TRUE; + } else { + ret = FALSE; + } + break; + + case POOL_STATE_L2CACHE: + + /* + * Check if any pool is currently using this l2cache device. + */ + cb.cb_zhp = NULL; + cb.cb_guid = vdev_guid; + cb.cb_type = ZPOOL_CONFIG_L2CACHE; + if (zpool_iter(hdl, find_aux, &cb) == 1) { name = (char *)zpool_get_name(cb.cb_zhp); ret = TRUE; } else { diff --git a/usr/src/lib/libzfs/common/libzfs_pool.c b/usr/src/lib/libzfs/common/libzfs_pool.c index 7320378e6f..75c1ce7492 100644 --- a/usr/src/lib/libzfs/common/libzfs_pool.c +++ b/usr/src/lib/libzfs/common/libzfs_pool.c @@ -815,6 +815,11 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, "one or more devices is out of space")); return (zfs_error(hdl, EZFS_BADDEV, msg)); + case ENOTBLK: + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "cache device must be a disk or disk slice")); + return (zfs_error(hdl, EZFS_BADDEV, msg)); + default: return (zpool_standard_error(hdl, errno, msg)); } @@ -898,14 +903,14 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) int ret; libzfs_handle_t *hdl = zhp->zpool_hdl; char msg[1024]; - nvlist_t **spares; - uint_t nspares; + nvlist_t **spares, **l2cache; + uint_t nspares, nl2cache; (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, "cannot add to '%s'"), zhp->zpool_name); - if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) - < SPA_VERSION_SPARES && + if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < + SPA_VERSION_SPARES && nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " @@ -913,6 +918,15 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) return (zfs_error(hdl, EZFS_BADVERSION, msg)); } + if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < + SPA_VERSION_L2CACHE && + nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, + &l2cache, &nl2cache) == 0) { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " + "upgraded to add cache devices")); + return (zfs_error(hdl, EZFS_BADVERSION, msg)); + } + if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) return (-1); (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); @@ -963,6 +977,12 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) (void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg); break; + case ENOTBLK: + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "cache device must be a disk or disk slice")); + (void) zfs_error(hdl, EZFS_BADDEV, msg); + break; + default: (void) zpool_standard_error(hdl, errno, msg); } @@ -1172,7 +1192,7 @@ zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type) */ static nvlist_t * vdev_to_nvlist_iter(nvlist_t *nv, const char *search, uint64_t guid, - boolean_t *avail_spare) + boolean_t *avail_spare, boolean_t *l2cache) { uint_t c, children; nvlist_t **child; @@ -1214,25 +1234,37 @@ vdev_to_nvlist_iter(nvlist_t *nv, const char *search, uint64_t guid, for (c = 0; c < children; c++) if ((ret = vdev_to_nvlist_iter(child[c], search, guid, - avail_spare)) != NULL) + avail_spare, l2cache)) != NULL) return (ret); if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child, &children) == 0) { for (c = 0; c < children; c++) { if ((ret = vdev_to_nvlist_iter(child[c], search, guid, - avail_spare)) != NULL) { + avail_spare, l2cache)) != NULL) { *avail_spare = B_TRUE; return (ret); } } } + if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, + &child, &children) == 0) { + for (c = 0; c < children; c++) { + if ((ret = vdev_to_nvlist_iter(child[c], search, guid, + avail_spare, l2cache)) != NULL) { + *l2cache = B_TRUE; + return (ret); + } + } + } + return (NULL); } nvlist_t * -zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare) +zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, + boolean_t *l2cache) { char buf[MAXPATHLEN]; const char *search; @@ -1254,29 +1286,32 @@ zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare) &nvroot) == 0); *avail_spare = B_FALSE; - return (vdev_to_nvlist_iter(nvroot, search, guid, avail_spare)); + *l2cache = B_FALSE; + return (vdev_to_nvlist_iter(nvroot, search, guid, avail_spare, + l2cache)); } /* - * Returns TRUE if the given guid corresponds to a spare (INUSE or not). + * Returns TRUE if the given guid corresponds to the given type. + * This is used to check for hot spares (INUSE or not), and level 2 cache + * devices. */ static boolean_t -is_spare(zpool_handle_t *zhp, uint64_t guid) +is_guid_type(zpool_handle_t *zhp, uint64_t guid, const char *type) { - uint64_t spare_guid; + uint64_t target_guid; nvlist_t *nvroot; - nvlist_t **spares; - uint_t nspares; + nvlist_t **list; + uint_t count; int i; verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); - if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, - &spares, &nspares) == 0) { - for (i = 0; i < nspares; i++) { - verify(nvlist_lookup_uint64(spares[i], - ZPOOL_CONFIG_GUID, &spare_guid) == 0); - if (guid == spare_guid) + if (nvlist_lookup_nvlist_array(nvroot, type, &list, &count) == 0) { + for (i = 0; i < count; i++) { + verify(nvlist_lookup_uint64(list[i], ZPOOL_CONFIG_GUID, + &target_guid) == 0); + if (guid == target_guid) return (B_TRUE); } } @@ -1295,21 +1330,26 @@ zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags, zfs_cmd_t zc = { 0 }; char msg[1024]; nvlist_t *tgt; - boolean_t avail_spare; + boolean_t avail_spare, l2cache; libzfs_handle_t *hdl = zhp->zpool_hdl; (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, "cannot online %s"), path); (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); - if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == NULL) + if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache)) == NULL) return (zfs_error(hdl, EZFS_NODEVICE, msg)); verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); - if (avail_spare || is_spare(zhp, zc.zc_guid) == B_TRUE) + if (avail_spare || + is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_SPARES) == B_TRUE) return (zfs_error(hdl, EZFS_ISSPARE, msg)); + if (l2cache || + is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_L2CACHE) == B_TRUE) + return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); + zc.zc_cookie = VDEV_STATE_ONLINE; zc.zc_obj = flags; @@ -1330,21 +1370,26 @@ zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp) zfs_cmd_t zc = { 0 }; char msg[1024]; nvlist_t *tgt; - boolean_t avail_spare; + boolean_t avail_spare, l2cache; libzfs_handle_t *hdl = zhp->zpool_hdl; (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, "cannot offline %s"), path); (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); - if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == NULL) + if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache)) == NULL) return (zfs_error(hdl, EZFS_NODEVICE, msg)); verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); - if (avail_spare || is_spare(zhp, zc.zc_guid) == B_TRUE) + if (avail_spare || + is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_SPARES) == B_TRUE) return (zfs_error(hdl, EZFS_ISSPARE, msg)); + if (l2cache || + is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_L2CACHE) == B_TRUE) + return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); + zc.zc_cookie = VDEV_STATE_OFFLINE; zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0; @@ -1461,7 +1506,7 @@ zpool_vdev_attach(zpool_handle_t *zhp, char msg[1024]; int ret; nvlist_t *tgt; - boolean_t avail_spare; + boolean_t avail_spare, l2cache; uint64_t val, is_log; char *path; nvlist_t **child; @@ -1477,12 +1522,15 @@ zpool_vdev_attach(zpool_handle_t *zhp, "cannot attach %s to %s"), new_disk, old_disk); (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); - if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare)) == 0) + if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache)) == 0) return (zfs_error(hdl, EZFS_NODEVICE, msg)); if (avail_spare) return (zfs_error(hdl, EZFS_ISSPARE, msg)); + if (l2cache) + return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); + verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); zc.zc_cookie = replacing; @@ -1503,7 +1551,7 @@ zpool_vdev_attach(zpool_handle_t *zhp, if (replacing && nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 && nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 && - (zpool_find_vdev(zhp, path, &avail_spare) == NULL || + (zpool_find_vdev(zhp, path, &avail_spare, &l2cache) == NULL || !avail_spare) && is_replacing_spare(config_root, tgt, 1)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "can only be replaced by another hot spare")); @@ -1516,8 +1564,8 @@ zpool_vdev_attach(zpool_handle_t *zhp, */ if (replacing && nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 && - zpool_find_vdev(zhp, path, &avail_spare) != NULL && avail_spare && - is_replacing_spare(config_root, tgt, 0)) { + zpool_find_vdev(zhp, path, &avail_spare, &l2cache) != NULL && + avail_spare && is_replacing_spare(config_root, tgt, 0)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "device has already been replaced with a spare")); return (zfs_error(hdl, EZFS_BADTARGET, msg)); @@ -1612,19 +1660,22 @@ zpool_vdev_detach(zpool_handle_t *zhp, const char *path) zfs_cmd_t zc = { 0 }; char msg[1024]; nvlist_t *tgt; - boolean_t avail_spare; + boolean_t avail_spare, l2cache; libzfs_handle_t *hdl = zhp->zpool_hdl; (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, "cannot detach %s"), path); (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); - if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0) + if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache)) == 0) return (zfs_error(hdl, EZFS_NODEVICE, msg)); if (avail_spare) return (zfs_error(hdl, EZFS_ISSPARE, msg)); + if (l2cache) + return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); + verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0) @@ -1656,7 +1707,8 @@ zpool_vdev_detach(zpool_handle_t *zhp, const char *path) } /* - * Remove the given device. Currently, this is supported only for hot spares. + * Remove the given device. Currently, this is supported only for hot spares + * and level 2 cache devices. */ int zpool_vdev_remove(zpool_handle_t *zhp, const char *path) @@ -1664,19 +1716,20 @@ zpool_vdev_remove(zpool_handle_t *zhp, const char *path) zfs_cmd_t zc = { 0 }; char msg[1024]; nvlist_t *tgt; - boolean_t avail_spare; + boolean_t avail_spare, l2cache; libzfs_handle_t *hdl = zhp->zpool_hdl; (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, "cannot remove %s"), path); (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); - if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0) + if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache)) == 0) return (zfs_error(hdl, EZFS_NODEVICE, msg)); - if (!avail_spare) { + if (!avail_spare && !l2cache) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "only inactive hot spares can be removed")); + "only inactive hot spares or cache devices " + "can be removed")); return (zfs_error(hdl, EZFS_NODEVICE, msg)); } @@ -1697,7 +1750,7 @@ zpool_clear(zpool_handle_t *zhp, const char *path) zfs_cmd_t zc = { 0 }; char msg[1024]; nvlist_t *tgt; - boolean_t avail_spare; + boolean_t avail_spare, l2cache; libzfs_handle_t *hdl = zhp->zpool_hdl; if (path) @@ -1711,9 +1764,14 @@ zpool_clear(zpool_handle_t *zhp, const char *path) (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); if (path) { - if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0) + if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, + &l2cache)) == 0) return (zfs_error(hdl, EZFS_NODEVICE, msg)); + /* + * Don't allow error clearing for hot spares. Do allow + * error clearing for l2cache devices. + */ if (avail_spare) return (zfs_error(hdl, EZFS_ISSPARE, msg)); diff --git a/usr/src/lib/libzfs/common/libzfs_util.c b/usr/src/lib/libzfs/common/libzfs_util.c index d2005867e3..b58da2c0bf 100644 --- a/usr/src/lib/libzfs/common/libzfs_util.c +++ b/usr/src/lib/libzfs/common/libzfs_util.c @@ -201,6 +201,8 @@ libzfs_error_description(libzfs_handle_t *hdl) " modified")); case EZFS_BADCACHE: return (dgettext(TEXT_DOMAIN, "invalid or missing cache file")); + case EZFS_ISL2CACHE: + return (dgettext(TEXT_DOMAIN, "device is in use as a cache")); case EZFS_UNKNOWN: return (dgettext(TEXT_DOMAIN, "unknown error")); default: |