X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=lib%2Flibzfs%2Flibzfs_dataset.c;h=44fdadd17277f88fd3dfddb70c0e5e6b3b5cf125;hb=a38718a63d79116d6cb614dd2821e2a3955e5c8c;hp=d876e5d1fc425b99cf77bd7af4688edbf944c931;hpb=d603ed6c278f9c25b17ba8e75e9bce6e5d715ac0;p=zfs.git diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index d876e5d..44fdadd 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -21,6 +21,8 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2011 by Delphix. All rights reserved. */ #include @@ -94,6 +96,7 @@ zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type, namecheck_err_t why; char what; + (void) zfs_prop_get_table(); if (dataset_namecheck(path, &why, &what) != 0) { if (hdl != NULL) { switch (why) { @@ -995,7 +998,6 @@ badlabel: /*FALLTHRU*/ -#ifdef HAVE_ZPL case ZFS_PROP_SHARESMB: case ZFS_PROP_SHARENFS: /* @@ -1106,7 +1108,6 @@ badlabel: } break; -#endif /* HAVE_ZPL */ case ZFS_PROP_UTF8ONLY: chosen_utf = (int)intval; break; @@ -1315,6 +1316,25 @@ zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err, } } +static boolean_t +zfs_is_namespace_prop(zfs_prop_t prop) +{ + switch (prop) { + + case ZFS_PROP_ATIME: + case ZFS_PROP_DEVICES: + case ZFS_PROP_EXEC: + case ZFS_PROP_SETUID: + case ZFS_PROP_READONLY: + case ZFS_PROP_XATTR: + case ZFS_PROP_NBMAND: + return (B_TRUE); + + default: + return (B_FALSE); + } +} + /* * Given a property name and value, set the property for the given dataset. */ @@ -1410,12 +1430,22 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) if (do_prefix) ret = changelist_postfix(cl); - /* - * Refresh the statistics so the new property value - * is reflected. - */ - if (ret == 0) + if (ret == 0) { + /* + * Refresh the statistics so the new property + * value is reflected. + */ (void) get_stats(zhp); + + /* + * Remount the filesystem to propagate the change + * if one of the options handled by the generic + * Linux namespace layer has been modified. + */ + if (zfs_is_namespace_prop(prop) && + zfs_is_mounted(zhp, NULL)) + ret = zfs_mount(zhp, MNTOPT_REMOUNT, 0); + } } error: @@ -1532,7 +1562,7 @@ error: * True DSL properties are stored in an nvlist. The following two functions * extract them appropriately. */ -static uint64_t +uint64_t getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) { nvlist_t *nv; @@ -1600,7 +1630,7 @@ zfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) * zfs_prop_get_int() are built using this interface. * * Certain properties can be overridden using 'mount -o'. In this case, scan - * the contents of the /etc/mnttab entry, searching for the appropriate options. + * the contents of the /etc/mtab entry, searching for the appropriate options. * If they differ from the on-disk values, report the current values and mark * the source "temporary". */ @@ -1658,7 +1688,7 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, /* * Because looking up the mount options is potentially expensive - * (iterating over all of /etc/mnttab), we defer its calculation until + * (iterating over all of /etc/mtab), we defer its calculation until * we're looking up a property which requires its presence. */ if (!zhp->zfs_mntcheck && @@ -1998,6 +2028,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, } break; + case ZFS_PROP_REFRATIO: case ZFS_PROP_COMPRESSRATIO: if (get_numeric_property(zhp, prop, src, &source, &val) != 0) return (-1); @@ -2218,15 +2249,19 @@ out: * convert the propname into parameters needed by kernel * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829 * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789 + * Eg: groupquota@staff -> ZFS_PROP_GROUPQUOTA, "", 1234 + * Eg: groupused@staff -> ZFS_PROP_GROUPUSED, "", 1234 */ static int userquota_propname_decode(const char *propname, boolean_t zoned, zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp) { zfs_userquota_prop_t type; - char *cp, *end; - char *numericsid = NULL; + char *cp; boolean_t isuser; + boolean_t isgroup; + struct passwd *pw; + struct group *gr; domain[0] = '\0'; @@ -2240,18 +2275,29 @@ userquota_propname_decode(const char *propname, boolean_t zoned, return (EINVAL); *typep = type; - isuser = (type == ZFS_PROP_USERQUOTA || - type == ZFS_PROP_USERUSED); + isuser = (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_USERUSED); + isgroup = (type == ZFS_PROP_GROUPQUOTA || type == ZFS_PROP_GROUPUSED); cp = strchr(propname, '@') + 1; - if (strchr(cp, '@')) { + if (isuser && (pw = getpwnam(cp)) != NULL) { + if (zoned && getzoneid() == GLOBAL_ZONEID) + return (ENOENT); + *ridp = pw->pw_uid; + } else if (isgroup && (gr = getgrnam(cp)) != NULL) { + if (zoned && getzoneid() == GLOBAL_ZONEID) + return (ENOENT); + *ridp = gr->gr_gid; + } else if (strchr(cp, '@')) { #ifdef HAVE_IDMAP /* * It's a SID name (eg "user@domain") that needs to be * turned into S-1-domainID-RID. */ directory_error_t e; + char *numericsid = NULL; + char *end; + if (zoned && getzoneid() == GLOBAL_ZONEID) return (ENOENT); if (isuser) { @@ -2268,14 +2314,6 @@ userquota_propname_decode(const char *propname, boolean_t zoned, if (numericsid == NULL) return (ENOENT); cp = numericsid; - /* will be further decoded below */ -#else - return (ENOSYS); -#endif /* HAVE_IDMAP */ - } - - if (strncmp(cp, "S-1-", 4) == 0) { - /* It's a numeric SID (eg "S-1-234-567-89") */ (void) strlcpy(domain, cp, domainlen); cp = strrchr(domain, '-'); *cp = '\0'; @@ -2283,39 +2321,22 @@ userquota_propname_decode(const char *propname, boolean_t zoned, errno = 0; *ridp = strtoull(cp, &end, 10); - if (numericsid) { - free(numericsid); - numericsid = NULL; - } + free(numericsid); + if (errno != 0 || *end != '\0') return (EINVAL); - } else if (!isdigit(*cp)) { - /* - * It's a user/group name (eg "user") that needs to be - * turned into a uid/gid - */ - if (zoned && getzoneid() == GLOBAL_ZONEID) - return (ENOENT); - if (isuser) { - struct passwd *pw; - pw = getpwnam(cp); - if (pw == NULL) - return (ENOENT); - *ridp = pw->pw_uid; - } else { - struct group *gr; - gr = getgrnam(cp); - if (gr == NULL) - return (ENOENT); - *ridp = gr->gr_gid; - } +#else + return (ENOSYS); +#endif /* HAVE_IDMAP */ } else { #ifdef HAVE_IDMAP /* It's a user/group ID (eg "12345"). */ - uid_t id = strtoul(cp, &end, 10); + uid_t id; idmap_rid_t rid; char *mapdomain; + char *end; + id = strtoul(cp, &end, 10); if (*end != '\0') return (EINVAL); if (id > MAXUID) { @@ -2333,7 +2354,6 @@ userquota_propname_decode(const char *propname, boolean_t zoned, #endif /* HAVE_IDMAP */ } - ASSERT3P(numericsid, ==, NULL); return (0); } @@ -2745,7 +2765,6 @@ create_parents(libzfs_handle_t *hdl, char *target, int prefixlen) goto ancestorerr; } -#ifdef HAVE_ZPL if (zfs_mount(h, NULL, 0) != 0) { opname = dgettext(TEXT_DOMAIN, "mount"); goto ancestorerr; @@ -2755,7 +2774,6 @@ create_parents(libzfs_handle_t *hdl, char *target, int prefixlen) opname = dgettext(TEXT_DOMAIN, "share"); goto ancestorerr; } -#endif /* HAVE_ZPL */ zfs_close(h); } @@ -4037,28 +4055,6 @@ zfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received) return (0); } -#ifdef HAVE_ZPL -int -zfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path, - char *resource, void *export, void *sharetab, - int sharemax, zfs_share_op_t operation) -{ - zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 }; - int error; - - (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); - (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); - if (resource) - (void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string)); - zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab; - zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export; - zc.zc_share.z_sharetype = operation; - zc.zc_share.z_sharemax = sharemax; - error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc); - return (error); -} -#endif /* HAVE_ZPL */ - void zfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props) { @@ -4308,6 +4304,193 @@ zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag, return (0); } +int +zfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl) +{ + zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 }; + libzfs_handle_t *hdl = zhp->zfs_hdl; + int nvsz = 2048; + void *nvbuf; + int err = 0; + char errbuf[ZFS_MAXNAMELEN+32]; + + assert(zhp->zfs_type == ZFS_TYPE_VOLUME || + zhp->zfs_type == ZFS_TYPE_FILESYSTEM); + +tryagain: + + nvbuf = malloc(nvsz); + if (nvbuf == NULL) { + err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); + goto out; + } + + zc.zc_nvlist_dst_size = nvsz; + zc.zc_nvlist_dst = (uintptr_t)nvbuf; + + (void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN); + + if (zfs_ioctl(hdl, ZFS_IOC_GET_FSACL, &zc) != 0) { + (void) snprintf(errbuf, sizeof (errbuf), + dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"), + zc.zc_name); + switch (errno) { + case ENOMEM: + free(nvbuf); + nvsz = zc.zc_nvlist_dst_size; + goto tryagain; + + case ENOTSUP: + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "pool must be upgraded")); + err = zfs_error(hdl, EZFS_BADVERSION, errbuf); + break; + case EINVAL: + err = zfs_error(hdl, EZFS_BADTYPE, errbuf); + break; + case ENOENT: + err = zfs_error(hdl, EZFS_NOENT, errbuf); + break; + default: + err = zfs_standard_error_fmt(hdl, errno, errbuf); + break; + } + } else { + /* success */ + int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); + if (rc) { + (void) snprintf(errbuf, sizeof (errbuf), dgettext( + TEXT_DOMAIN, "cannot get permissions on '%s'"), + zc.zc_name); + err = zfs_standard_error_fmt(hdl, rc, errbuf); + } + } + + free(nvbuf); +out: + return (err); +} + +int +zfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl) +{ + zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 }; + libzfs_handle_t *hdl = zhp->zfs_hdl; + char *nvbuf; + char errbuf[ZFS_MAXNAMELEN+32]; + size_t nvsz; + int err; + + assert(zhp->zfs_type == ZFS_TYPE_VOLUME || + zhp->zfs_type == ZFS_TYPE_FILESYSTEM); + + err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE); + assert(err == 0); + + nvbuf = malloc(nvsz); + + err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0); + assert(err == 0); + + zc.zc_nvlist_src_size = nvsz; + zc.zc_nvlist_src = (uintptr_t)nvbuf; + zc.zc_perm_action = un; + + (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); + + if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) != 0) { + (void) snprintf(errbuf, sizeof (errbuf), + dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"), + zc.zc_name); + switch (errno) { + case ENOTSUP: + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "pool must be upgraded")); + err = zfs_error(hdl, EZFS_BADVERSION, errbuf); + break; + case EINVAL: + err = zfs_error(hdl, EZFS_BADTYPE, errbuf); + break; + case ENOENT: + err = zfs_error(hdl, EZFS_NOENT, errbuf); + break; + default: + err = zfs_standard_error_fmt(hdl, errno, errbuf); + break; + } + } + + free(nvbuf); + + return (err); +} + +int +zfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl) +{ + zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 }; + libzfs_handle_t *hdl = zhp->zfs_hdl; + int nvsz = 2048; + void *nvbuf; + int err = 0; + char errbuf[ZFS_MAXNAMELEN+32]; + + assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); + +tryagain: + + nvbuf = malloc(nvsz); + if (nvbuf == NULL) { + err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); + goto out; + } + + zc.zc_nvlist_dst_size = nvsz; + zc.zc_nvlist_dst = (uintptr_t)nvbuf; + + (void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN); + + if (zfs_ioctl(hdl, ZFS_IOC_GET_HOLDS, &zc) != 0) { + (void) snprintf(errbuf, sizeof (errbuf), + dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), + zc.zc_name); + switch (errno) { + case ENOMEM: + free(nvbuf); + nvsz = zc.zc_nvlist_dst_size; + goto tryagain; + + case ENOTSUP: + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "pool must be upgraded")); + err = zfs_error(hdl, EZFS_BADVERSION, errbuf); + break; + case EINVAL: + err = zfs_error(hdl, EZFS_BADTYPE, errbuf); + break; + case ENOENT: + err = zfs_error(hdl, EZFS_NOENT, errbuf); + break; + default: + err = zfs_standard_error_fmt(hdl, errno, errbuf); + break; + } + } else { + /* success */ + int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); + if (rc) { + (void) snprintf(errbuf, sizeof (errbuf), + dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), + zc.zc_name); + err = zfs_standard_error_fmt(hdl, rc, errbuf); + } + } + + free(nvbuf); +out: + return (err); +} + uint64_t zvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props) {