X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=lib%2Flibzfs%2Flibzfs_pool.c;h=f61e6cf45c78790a1469b045bb0fc3cf6096b831;hb=fc24f7c887a040b6dc9f2a3dd3d5ae0c03a5d639;hp=607e2e865fd3042ba324b14b84e4ecdd1d968b8f;hpb=83c62c939938ca5915a61022208a31c4ab3faa1c;p=zfs.git diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c index 607e2e8..f61e6cf 100644 --- a/lib/libzfs/libzfs_pool.c +++ b/lib/libzfs/libzfs_pool.c @@ -21,6 +21,8 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2011 by Delphix. All rights reserved. */ #include @@ -233,6 +235,7 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, case ZPOOL_PROP_ALTROOT: case ZPOOL_PROP_CACHEFILE: + case ZPOOL_PROP_COMMENT: if (zhp->zpool_props != NULL || zpool_get_all_props(zhp) == 0) { (void) strlcpy(buf, @@ -270,6 +273,7 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, case ZPOOL_PROP_SIZE: case ZPOOL_PROP_ALLOCATED: case ZPOOL_PROP_FREE: + case ZPOOL_PROP_ASHIFT: (void) zfs_nicenum(intval, buf, len); break; @@ -382,7 +386,7 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, zpool_prop_t prop; char *strval; uint64_t intval; - char *slash; + char *slash, *check; struct stat64 statbuf; zpool_handle_t *zhp; nvlist_t *nvroot; @@ -433,6 +437,24 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, } break; + case ZPOOL_PROP_ASHIFT: + if (!flags.create) { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "property '%s' can only be set at " + "creation time"), propname); + (void) zfs_error(hdl, EZFS_BADPROP, errbuf); + goto error; + } + + if (intval != 0 && (intval < 9 || intval > 13)) { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "property '%s' number %d is invalid."), + propname, intval); + (void) zfs_error(hdl, EZFS_BADPROP, errbuf); + goto error; + } + break; + case ZPOOL_PROP_BOOTFS: if (flags.create || flags.import) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, @@ -471,6 +493,7 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); +#if defined(__sun__) || defined(__sun) /* * bootfs property cannot be set on a disk which has * been EFI labeled. @@ -483,6 +506,7 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, zpool_close(zhp); goto error; } +#endif zpool_close(zhp); break; @@ -543,6 +567,26 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, *slash = '/'; break; + case ZPOOL_PROP_COMMENT: + for (check = strval; *check != '\0'; check++) { + if (!isprint(*check)) { + zfs_error_aux(hdl, + dgettext(TEXT_DOMAIN, + "comment may only have printable " + "characters")); + (void) zfs_error(hdl, EZFS_BADPROP, + errbuf); + goto error; + } + } + if (strlen(strval) > ZPROP_MAX_COMMENT) { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "comment must not exceed %d characters"), + ZPROP_MAX_COMMENT); + (void) zfs_error(hdl, EZFS_BADPROP, errbuf); + goto error; + } + break; case ZPOOL_PROP_READONLY: if (!flags.import) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, @@ -651,10 +695,12 @@ zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp) * Don't start the slice at the default block of 34; many storage * devices will use a stripe width of 128k, other vendors prefer a 1m * alignment. It is best to play it safe and ensure a 1m alignment - * give 512b blocks. When the block size is larger by a power of 2 - * we will still be 1m aligned. + * given 512B blocks. When the block size is larger by a power of 2 + * we will still be 1m aligned. Some devices are sensitive to the + * partition ending alignment as well. */ -#define NEW_START_BLOCK 2048 +#define NEW_START_BLOCK 2048 +#define PARTITION_END_ALIGNMENT 2048 /* * Validate the given pool name, optionally putting an extended error message in @@ -1562,6 +1608,12 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, (void) zpool_standard_error(hdl, error, desc); break; + case EBUSY: + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "one or more devices are already in use\n")); + (void) zfs_error(hdl, EZFS_BADDEV, desc); + break; + default: (void) zpool_standard_error(hdl, error, desc); zpool_explain_recover(hdl, @@ -1645,38 +1697,6 @@ zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func) } /* - * This provides a very minimal check whether a given string is likely a - * c#t#d# style string. Users of this are expected to do their own - * verification of the s# part. - */ -#define CTD_CHECK(str) (str && str[0] == 'c' && isdigit(str[1])) - -/* - * More elaborate version for ones which may start with "/dev/dsk/" - * and the like. - */ -static int -ctd_check_path(char *str) { - /* - * If it starts with a slash, check the last component. - */ - if (str && str[0] == '/') { - char *tmp = strrchr(str, '/'); - - /* - * If it ends in "/old", check the second-to-last - * component of the string instead. - */ - if (tmp != str && strcmp(tmp, "/old") == 0) { - for (tmp--; *tmp != '/'; tmp--) - ; - } - str = tmp + 1; - } - return (CTD_CHECK(str)); -} - -/* * Find a vdev that matches the search criteria specified. We use the * the nvpair name to determine how we should look for the device. * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL @@ -1723,47 +1743,24 @@ vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare, /* * Search for the requested value. Special cases: * - * - ZPOOL_CONFIG_PATH for whole disk entries. These end in - * "s0" or "s0/old". The "s0" part is hidden from the user, - * but included in the string, so this matches around it. + * - ZPOOL_CONFIG_PATH for whole disk entries. These end in with a + * partition suffix "1", "-part1", or "p1". The suffix is hidden + * from the user, but included in the string, so this matches around + * it. * - looking for a top-level vdev name (i.e. ZPOOL_CONFIG_TYPE). * * Otherwise, all other searches are simple string compares. */ - if (strcmp(srchkey, ZPOOL_CONFIG_PATH) == 0 && - ctd_check_path(val)) { + if (strcmp(srchkey, ZPOOL_CONFIG_PATH) == 0) { uint64_t wholedisk = 0; (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, &wholedisk); if (wholedisk) { - int slen = strlen(srchval); - int vlen = strlen(val); - - if (slen != vlen - 2) - break; - - /* - * make_leaf_vdev() should only set - * wholedisk for ZPOOL_CONFIG_PATHs which - * will include "/dev/dsk/", giving plenty of - * room for the indices used next. - */ - ASSERT(vlen >= 6); - - /* - * strings identical except trailing "s0" - */ - if (strcmp(&val[vlen - 2], "s0") == 0 && - strncmp(srchval, val, slen) == 0) - return (nv); + char buf[MAXPATHLEN]; - /* - * strings identical except trailing "s0/old" - */ - if (strcmp(&val[vlen - 6], "s0/old") == 0 && - strcmp(&srchval[slen - 4], "/old") == 0 && - strncmp(srchval, val, slen - 4) == 0) + zfs_append_partition(srchval, buf, sizeof (buf)); + if (strcmp(val, buf) == 0) return (nv); break; @@ -1931,7 +1928,10 @@ zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, } else if (zpool_vdev_is_interior(path)) { verify(nvlist_add_string(search, ZPOOL_CONFIG_TYPE, path) == 0); } else if (path[0] != '/') { - (void) snprintf(buf, sizeof (buf), "%s/%s", DISK_ROOT, path); + if (zfs_resolve_shortname(path, buf, sizeof (buf)) < 0) { + nvlist_free(search); + return (NULL); + } verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, buf) == 0); } else { verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, path) == 0); @@ -2104,28 +2104,30 @@ zpool_get_physpath(zpool_handle_t *zhp, char *physpath, size_t phypath_size) * the disk to use the new unallocated space. */ static int -zpool_relabel_disk(libzfs_handle_t *hdl, const char *path) +zpool_relabel_disk(libzfs_handle_t *hdl, const char *path, const char *msg) { - char errbuf[1024]; int fd, error; if ((fd = open(path, O_RDWR|O_DIRECT)) < 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " - "relabel '%s': unable to open device"), path); - return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); + "relabel '%s': unable to open device: %d"), path, errno); + return (zfs_error(hdl, EZFS_OPENFAILED, msg)); } /* * It's possible that we might encounter an error if the device * does not have any unallocated space left. If so, we simply * ignore that error and continue on. + * + * Also, we don't call efi_rescan() - that would just return EBUSY. + * The module will do it for us in vdev_disk_open(). */ error = efi_use_whole_disk(fd); (void) close(fd); if (error && error != VT_ENOSPC) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " "relabel '%s': unable to read disk capacity"), path); - return (zfs_error(hdl, EZFS_NOCAP, errbuf)); + return (zfs_error(hdl, EZFS_NOCAP, msg)); } return (0); } @@ -2143,6 +2145,7 @@ zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags, nvlist_t *tgt; boolean_t avail_spare, l2cache, islog; libzfs_handle_t *hdl = zhp->zpool_hdl; + int error; if (flags & ZFS_ONLINE_EXPAND) { (void) snprintf(msg, sizeof (msg), @@ -2164,13 +2167,10 @@ zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags, if (flags & ZFS_ONLINE_EXPAND || zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) { - char *pathname = NULL; uint64_t wholedisk = 0; (void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK, &wholedisk); - verify(nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, - &pathname) == 0); /* * XXX - L2ARC 1.0 devices can't support expansion. @@ -2182,8 +2182,22 @@ zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags, } if (wholedisk) { - pathname += strlen(DISK_ROOT) + 1; - (void) zpool_relabel_disk(hdl, pathname); + const char *fullpath = path; + char buf[MAXPATHLEN]; + + if (path[0] != '/') { + error = zfs_resolve_shortname(path, buf, + sizeof(buf)); + if (error != 0) + return (zfs_error(hdl, EZFS_NODEVICE, + msg)); + + fullpath = buf; + } + + error = zpool_relabel_disk(hdl, fullpath, msg); + if (error != 0) + return (error); } } @@ -2972,6 +2986,26 @@ zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid) } /* + * Change the GUID for a pool. + */ +int +zpool_reguid(zpool_handle_t *zhp) +{ + char msg[1024]; + libzfs_handle_t *hdl = zhp->zpool_hdl; + zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 }; + + (void) snprintf(msg, sizeof (msg), + dgettext(TEXT_DOMAIN, "cannot reguid '%s'"), zhp->zpool_name); + + (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); + if (zfs_ioctl(hdl, ZFS_IOC_POOL_REGUID, &zc) == 0) + return (0); + + return (zpool_standard_error(hdl, errno, msg)); +} + +/* * Convert from a devid string to a path. */ static char * @@ -3100,6 +3134,7 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv, char *path, *devid, *type; uint64_t value; char buf[PATH_BUF_LEN]; + char tmpbuf[PATH_BUF_LEN]; vdev_stat_t *vs; uint_t vsc; @@ -3172,13 +3207,12 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv, * If it's a raidz device, we need to stick in the parity level. */ if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) { - char tmpbuf[PATH_BUF_LEN]; verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY, &value) == 0); - (void) snprintf(tmpbuf, sizeof (tmpbuf), "%s%llu", path, + (void) snprintf(buf, sizeof (buf), "%s%llu", path, (u_longlong_t)value); - path = tmpbuf; + path = buf; } /* @@ -3190,9 +3224,9 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv, verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, &id) == 0); - (void) snprintf(buf, sizeof (buf), "%s-%llu", path, - (u_longlong_t)id); - path = buf; + (void) snprintf(tmpbuf, sizeof (tmpbuf), "%s-%llu", + path, (u_longlong_t)id); + path = tmpbuf; } } @@ -3792,8 +3826,8 @@ zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name) * This shouldn't happen. We've long since verified that this * is a valid device. */ - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "unable to open device '%s': %d"), path, errno); + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " + "label '%s': unable to open device: %d"), path, errno); return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); } @@ -3806,8 +3840,8 @@ zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name) (void) no_memory(hdl); (void) close(fd); - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "unable to read disk capacity"), name); + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " + "label '%s': unable to read disk capacity"), path); return (zfs_error(hdl, EZFS_NOCAP, errbuf)); } @@ -3817,6 +3851,7 @@ zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name) if (start_block == MAXOFFSET_T) start_block = NEW_START_BLOCK; slice_size -= start_block; + slice_size = P2ALIGN(slice_size, PARTITION_END_ALIGNMENT); vtoc->efi_parts[0].p_start = start_block; vtoc->efi_parts[0].p_size = slice_size; @@ -3836,7 +3871,7 @@ zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name) vtoc->efi_parts[8].p_size = resv; vtoc->efi_parts[8].p_tag = V_RESERVED; - if ((rval = efi_write(fd, vtoc)) != 0) { + if ((rval = efi_write(fd, vtoc)) != 0 || (rval = efi_rescan(fd)) != 0) { /* * Some block drivers (like pcata) may not support EFI * GPT labels. Print out a helpful error message dir-