summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorAlex Wilson <alex.wilson@joyent.com>2018-09-17 01:38:51 +0000
committerJason King <jason.king@joyent.com>2020-03-20 06:21:16 +0000
commit08a0f5ea09ca188edbadd95cfdfddc2160992ba4 (patch)
tree1aba48089fd03bd513180ee100343b01bf4e610f /usr/src
parent9f9bdc6d9964c15e63aa7abeb78eff3f478b0cfc (diff)
downloadillumos-joyent-08a0f5ea09ca188edbadd95cfdfddc2160992ba4.tar.gz
OS-4278 delegated datasets could have better in-zone names
(in progress)
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/zoneadmd/Makefile.com2
-rw-r--r--usr/src/cmd/zoneadmd/vplat.c92
-rw-r--r--usr/src/cmd/zonecfg/zonecfg.c32
-rw-r--r--usr/src/cmd/zonecfg/zonecfg.h5
-rw-r--r--usr/src/cmd/zonecfg/zonecfg_grammar.y7
-rw-r--r--usr/src/cmd/zonecfg/zonecfg_lex.l4
-rw-r--r--usr/src/common/nvpair/nvpair.c12
-rw-r--r--usr/src/head/libzonecfg.h1
-rw-r--r--usr/src/lib/brand/lx/zone/platform.xml3
-rw-r--r--usr/src/lib/libzonecfg/common/libzonecfg.c38
-rw-r--r--usr/src/lib/libzonecfg/dtd/zonecfg.dtd.13
-rw-r--r--usr/src/lib/libzpool/common/sys/zfs_context.h2
-rw-r--r--usr/src/uts/common/brand/lx/os/lx_brand.c9
-rw-r--r--usr/src/uts/common/fs/dev/sdev_zvolops.c47
-rw-r--r--usr/src/uts/common/fs/zfs/spa_config.c2
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_ioctl.c830
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vfsops.c26
-rw-r--r--usr/src/uts/common/fs/zfs/zvol.c24
-rw-r--r--usr/src/uts/common/os/zone.c352
-rw-r--r--usr/src/uts/common/sys/nvpair.h3
-rw-r--r--usr/src/uts/common/sys/zone.h15
21 files changed, 1374 insertions, 135 deletions
diff --git a/usr/src/cmd/zoneadmd/Makefile.com b/usr/src/cmd/zoneadmd/Makefile.com
index 9725021b17..5ac034922b 100644
--- a/usr/src/cmd/zoneadmd/Makefile.com
+++ b/usr/src/cmd/zoneadmd/Makefile.com
@@ -35,7 +35,7 @@ OBJS= zoneadmd.o zcons.o zfd.o vplat.o log.o
CFLAGS += $(CCVERBOSE)
LDLIBS += -lsocket -lzonecfg -lnsl -ldevinfo -ldevice -lnvpair \
-lgen -lbsm -lcontract -lzfs -luuid -lbrand -ldladm -ltsnet -ltsol \
- -linetutil -lscf -lppt
+ -linetutil -lproc -lscf -lppt -lcustr
CSTD= $(CSTD_GNU99)
diff --git a/usr/src/cmd/zoneadmd/vplat.c b/usr/src/cmd/zoneadmd/vplat.c
index 01332d43e8..5372d9dc34 100644
--- a/usr/src/cmd/zoneadmd/vplat.c
+++ b/usr/src/cmd/zoneadmd/vplat.c
@@ -131,6 +131,8 @@
#include <sys/priv.h>
#include <libinetutil.h>
+#include <libcustr.h>
+
#define V4_ADDR_LEN 32
#define V6_ADDR_LEN 128
@@ -3508,17 +3510,16 @@ get_implicit_datasets(zlog_t *zlogp, char **retstr)
}
static int
-get_datasets(zlog_t *zlogp, char **bufp, size_t *bufsizep)
+get_datasets(zlog_t *zlogp, custr_t **datasetsp)
{
struct zone_dstab dstab;
- size_t total, offset, len;
int error = -1;
- char *str = NULL;
char *implicit_datasets = NULL;
int implicit_len = 0;
+ custr_t *cu = NULL;
+ int count = 0;
- *bufp = NULL;
- *bufsizep = 0;
+ *datasetsp = NULL;
if (get_implicit_datasets(zlogp, &implicit_datasets) != 0) {
zerror(zlogp, B_FALSE, "getting implicit datasets failed");
@@ -3530,22 +3531,7 @@ get_datasets(zlog_t *zlogp, char **bufp, size_t *bufsizep)
goto out;
}
- total = 0;
- while (zonecfg_getdsent(snap_hndl, &dstab) == Z_OK)
- total += strlen(dstab.zone_dataset_name) + 1;
- (void) zonecfg_enddsent(snap_hndl);
-
- if (implicit_datasets != NULL)
- implicit_len = strlen(implicit_datasets);
- if (implicit_len > 0)
- total += implicit_len + 1;
-
- if (total == 0) {
- error = 0;
- goto out;
- }
-
- if ((str = malloc(total)) == NULL) {
+ if (custr_alloc(&cu) != 0) {
zerror(zlogp, B_TRUE, "memory allocation failed");
goto out;
}
@@ -3554,29 +3540,48 @@ get_datasets(zlog_t *zlogp, char **bufp, size_t *bufsizep)
zerror(zlogp, B_FALSE, "%s failed", "zonecfg_setdsent");
goto out;
}
- offset = 0;
while (zonecfg_getdsent(snap_hndl, &dstab) == Z_OK) {
- len = strlen(dstab.zone_dataset_name);
- (void) strlcpy(str + offset, dstab.zone_dataset_name,
- total - offset);
- offset += len;
- if (offset < total - 1)
- str[offset++] = ',';
+ const char *alias = dstab.zone_dataset_alias[0] != '\0' ?
+ dstab.zone_dataset_alias : NULL;
+
+ if (count++ > 0 && custr_appendc(cu, ',') != 0) {
+ zerror(zlogp, B_TRUE, "memory allocation failed");
+ goto out;
+ }
+
+ if (custr_append(cu, dstab.zone_dataset_name) != 0) {
+ zerror(zlogp, B_TRUE, "memory allocation failed");
+ goto out;
+ }
+
+ if (alias != NULL && custr_append_printf(cu, "|%s",
+ alias) != 0) {
+ zerror(zlogp, B_TRUE, "memory allocation failed");
+ goto out;
+ }
}
(void) zonecfg_enddsent(snap_hndl);
- if (implicit_len > 0)
- (void) strlcpy(str + offset, implicit_datasets, total - offset);
+ if (implicit_len > 0) {
+ if (count++ > 0 && custr_appendc(cu, ',') != 0) {
+ zerror(zlogp, B_TRUE, "memory allocation failed");
+ goto out;
+ }
+ if (custr_append(cu, implicit_datasets) != 0) {
+ zerror(zlogp, B_TRUE, "memory allocation failed");
+ goto out;
+ }
+ }
error = 0;
- *bufp = str;
- *bufsizep = total;
out:
- if (error != 0 && str != NULL)
- free(str);
- if (implicit_datasets != NULL)
- free(implicit_datasets);
+ if (error != 0) {
+ custr_free(cu);
+ } else {
+ *datasetsp = cu;
+ }
+ free(implicit_datasets);
return (error);
}
@@ -4707,8 +4712,9 @@ vplat_create(zlog_t *zlogp, zone_mnt_t mount_cmd, zoneid_t zone_did)
char rootpath[MAXPATHLEN];
char *rctlbuf = NULL;
size_t rctlbufsz = 0;
- char *zfsbuf = NULL;
+ const char *zfsbuf = NULL;
size_t zfsbufsz = 0;
+ custr_t *datasets = NULL;
zoneid_t zoneid = -1;
int xerr;
char *kzone;
@@ -4755,10 +4761,14 @@ vplat_create(zlog_t *zlogp, zone_mnt_t mount_cmd, zoneid_t zone_did)
goto error;
}
- if (get_datasets(zlogp, &zfsbuf, &zfsbufsz) != 0) {
+ if (get_datasets(zlogp, &datasets) != 0) {
zerror(zlogp, B_FALSE, "Unable to get list of ZFS datasets");
goto error;
}
+ if (datasets != NULL) {
+ zfsbuf = custr_cstr(datasets);
+ zfsbufsz = custr_len(datasets);
+ }
if (mount_cmd == Z_MNT_BOOT && is_system_labeled()) {
zcent = get_zone_label(zlogp, privs);
@@ -4945,10 +4955,8 @@ error:
(void) zone_shutdown(zoneid);
(void) zone_destroy(zoneid);
}
- if (rctlbuf != NULL)
- free(rctlbuf);
- if (zfsbuf != NULL)
- free(zfsbuf);
+ free(rctlbuf);
+ custr_free(datasets);
priv_freeset(privs);
if (fp != NULL)
zonecfg_close_scratch(fp);
diff --git a/usr/src/cmd/zonecfg/zonecfg.c b/usr/src/cmd/zonecfg/zonecfg.c
index 20f30e6e0c..154fd71492 100644
--- a/usr/src/cmd/zonecfg/zonecfg.c
+++ b/usr/src/cmd/zonecfg/zonecfg.c
@@ -249,6 +249,7 @@ char *prop_types[] = {
"default",
"lower",
"upper",
+ "alias",
NULL
};
@@ -1234,6 +1235,8 @@ usage(boolean_t verbose, uint_t flags)
(void) fprintf(fp, gettext("Valid commands:\n"));
(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
pt_to_str(PT_NAME), gettext("<name>"));
+ (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
+ pt_to_str(PT_ALIAS), gettext("<alias>"));
break;
case RT_DCPU:
(void) fprintf(fp, gettext("The '%s' resource scope "
@@ -1437,8 +1440,8 @@ usage(boolean_t verbose, uint_t flags)
(void) fprintf(fp, "\t%s\t\t%s, %s, %s\n", rt_to_str(RT_ATTR),
pt_to_str(PT_NAME), pt_to_str(PT_TYPE),
pt_to_str(PT_VALUE));
- (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DATASET),
- pt_to_str(PT_NAME));
+ (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_DATASET),
+ pt_to_str(PT_NAME), pt_to_str(PT_ALIAS));
(void) fprintf(fp, "\t%s\t%s, %s\n", rt_to_str(RT_DCPU),
pt_to_str(PT_NCPUS), pt_to_str(PT_IMPORTANCE));
(void) fprintf(fp, "\t%s\t%s\n", rt_to_str(RT_PCAP),
@@ -2170,6 +2173,9 @@ export_func(cmd_t *cmd)
(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
rt_to_str(RT_DATASET));
export_prop(of, PT_NAME, dstab.zone_dataset_name);
+ if (dstab.zone_dataset_alias[0] != '\0') {
+ export_prop(of, PT_ALIAS, dstab.zone_dataset_alias);
+ }
(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
}
(void) zonecfg_enddsent(handle);
@@ -3171,6 +3177,7 @@ fill_in_dstab(cmd_t *cmd, struct zone_dstab *dstab, boolean_t fill_in_only)
return (err);
dstab->zone_dataset_name[0] = '\0';
+ dstab->zone_dataset_alias[0] = '\0';
for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
pp = cmd->cmd_property_ptr[i];
if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
@@ -3183,6 +3190,10 @@ fill_in_dstab(cmd_t *cmd, struct zone_dstab *dstab, boolean_t fill_in_only)
(void) strlcpy(dstab->zone_dataset_name, pp->pv_simple,
sizeof (dstab->zone_dataset_name));
break;
+ case PT_ALIAS:
+ (void) strlcpy(dstab->zone_dataset_alias, pp->pv_simple,
+ sizeof (dstab->zone_dataset_alias));
+ break;
default:
zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
Z_NO_PROPERTY_TYPE, B_TRUE);
@@ -4071,6 +4082,13 @@ clear_property(cmd_t *cmd)
return;
}
break;
+ case RT_DATASET:
+ if (prop_type == PT_ALIAS) {
+ in_progress_dstab.zone_dataset_alias[0] = '\0';
+ need_to_commit = B_TRUE;
+ return;
+ }
+ break;
case RT_DCPU:
if (prop_type == PT_IMPORTANCE) {
in_progress_psettab.zone_importance[0] = '\0';
@@ -5177,6 +5195,11 @@ set_func(cmd_t *cmd)
prop_id,
sizeof (in_progress_dstab.zone_dataset_name));
return;
+ case PT_ALIAS:
+ (void) strlcpy(in_progress_dstab.zone_dataset_alias,
+ prop_id,
+ sizeof (in_progress_dstab.zone_dataset_alias));
+ return;
default:
break;
}
@@ -5883,6 +5906,7 @@ output_ds(FILE *fp, struct zone_dstab *dstab)
{
(void) fprintf(fp, "%s:\n", rt_to_str(RT_DATASET));
output_prop(fp, PT_NAME, dstab->zone_dataset_name, B_TRUE);
+ output_prop(fp, PT_ALIAS, dstab->zone_dataset_alias, B_TRUE);
}
static void
@@ -5904,6 +5928,10 @@ info_ds(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
strcmp(user.zone_dataset_name,
lookup.zone_dataset_name) != 0)
continue; /* no match */
+ if (strlen(user.zone_dataset_alias) > 0 &&
+ strcmp(user.zone_dataset_alias,
+ lookup.zone_dataset_alias) != 0)
+ continue; /* no match */
output_ds(fp, &lookup);
output = B_TRUE;
}
diff --git a/usr/src/cmd/zonecfg/zonecfg.h b/usr/src/cmd/zonecfg/zonecfg.h
index e4ae4d4d61..426aed7331 100644
--- a/usr/src/cmd/zonecfg/zonecfg.h
+++ b/usr/src/cmd/zonecfg/zonecfg.h
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, Joyent Inc. All rights reserved.
+ * Copyright (c) 2018, Joyent Inc. All rights reserved.
*/
#ifndef _ZONECFG_H
@@ -150,9 +150,10 @@ extern "C" {
#define PT_DEFAULT 48
#define PT_LOWER 49
#define PT_UPPER 50
+#define PT_ALIAS 51
#define PT_MIN PT_UNKNOWN
-#define PT_MAX PT_UPPER
+#define PT_MAX PT_ALIAS
#define MAX_EQ_PROP_PAIRS 3
diff --git a/usr/src/cmd/zonecfg/zonecfg_grammar.y b/usr/src/cmd/zonecfg/zonecfg_grammar.y
index d8b2fadb2f..019f2fd989 100644
--- a/usr/src/cmd/zonecfg/zonecfg_grammar.y
+++ b/usr/src/cmd/zonecfg/zonecfg_grammar.y
@@ -22,7 +22,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013, Joyent Inc. All rights reserved.
+ * Copyright 2018, Joyent Inc. All rights reserved.
*/
/*
@@ -137,7 +137,7 @@ complex_piece_func(int cp_type, const char *str, complex_property_ptr_t cp_next)
%token OPEN_PAREN CLOSE_PAREN COMMA DATASET LIMITPRIV BOOTARGS BRAND PSET PCAP
%token MCAP NCPUS IMPORTANCE SHARES MAXLWPS MAXSHMMEM MAXSHMIDS MAXMSGIDS
%token MAXSEMIDS LOCKED SWAP SCHED CLEAR DEFROUTER ADMIN USER AUTHS MAXPROCS
-%token ZFSPRI MAC VLANID GNIC NPROP UUID SECFLAGS
+%token ZFSPRI MAC VLANID GNIC NPROP UUID SECFLAGS ALIAS
%token DEFAULT UPPER LOWER
%type <strval> TOKEN EQUAL OPEN_SQ_BRACKET CLOSE_SQ_BRACKET
@@ -148,7 +148,7 @@ complex_piece_func(int cp_type, const char *str, complex_property_ptr_t cp_next)
%type <ival> property_name SPECIAL RAW DIR OPTIONS TYPE ADDRESS PHYSICAL NAME
MATCH ZONENAME ZONEPATH AUTOBOOT POOL LIMITPRIV BOOTARGS VALUE PRIV LIMIT
ACTION BRAND SCHED IPTYPE DEFROUTER HOSTID USER AUTHS FS_ALLOWED
- ALLOWED_ADDRESS MAC VLANID GNIC NPROP UUID DEFAULT UPPER LOWER
+ ALLOWED_ADDRESS MAC VLANID GNIC NPROP UUID DEFAULT UPPER LOWER ALIAS
%type <cmd> command
%type <cmd> add_command ADD
%type <cmd> cancel_command CANCEL
@@ -1091,6 +1091,7 @@ property_name: SPECIAL { $$ = PT_SPECIAL; }
| DEFAULT { $$ = PT_DEFAULT; }
| UPPER { $$ = PT_UPPER; }
| LOWER { $$ = PT_LOWER; }
+ | ALIAS { $$ = PT_ALIAS; }
/*
* The grammar builds data structures from the bottom up. Thus various
diff --git a/usr/src/cmd/zonecfg/zonecfg_lex.l b/usr/src/cmd/zonecfg/zonecfg_lex.l
index 05b41df48b..db6da387e5 100644
--- a/usr/src/cmd/zonecfg/zonecfg_lex.l
+++ b/usr/src/cmd/zonecfg/zonecfg_lex.l
@@ -22,7 +22,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, Joyent Inc. All rights reserved.
+ * Copyright (c) 2018, Joyent Inc. All rights reserved.
*/
#include <assert.h>
@@ -330,6 +330,8 @@ static char *create_token(char *s);
<TSTATE>zfs-io-priority { return ZFSPRI; }
<CSTATE>zfs-io-priority { return ZFSPRI; }
+<TSTATE>alias { return ALIAS; }
+
<TSTATE>default { return DEFAULT; }
<CSTATE>default { return DEFAULT; }
diff --git a/usr/src/common/nvpair/nvpair.c b/usr/src/common/nvpair/nvpair.c
index 0e1ec15d61..d2bab7a723 100644
--- a/usr/src/common/nvpair/nvpair.c
+++ b/usr/src/common/nvpair/nvpair.c
@@ -2253,6 +2253,18 @@ nvlist_add_nvpair(nvlist_t *nvl, nvpair_t *nvp)
NVP_NELEM(nvp), NVP_VALUE(nvp)));
}
+#if defined(_KERNEL)
+int
+nvlist_add_named_nvpair(nvlist_t *nvl, const char *name, nvpair_t *nvp)
+{
+ if (nvl == NULL || nvp == NULL || name == NULL)
+ return (EINVAL);
+
+ return (nvlist_add_common(nvl, name, NVP_TYPE(nvp),
+ NVP_NELEM(nvp), NVP_VALUE(nvp)));
+}
+#endif
+
/*
* Merge the supplied nvlists and put the result in dst.
* The merged list will contain all names specified in both lists,
diff --git a/usr/src/head/libzonecfg.h b/usr/src/head/libzonecfg.h
index 4121b6a490..fc9506a093 100644
--- a/usr/src/head/libzonecfg.h
+++ b/usr/src/head/libzonecfg.h
@@ -253,6 +253,7 @@ struct zone_attrtab {
struct zone_dstab {
char zone_dataset_name[MAXNAMELEN];
+ char zone_dataset_alias[MAXNAMELEN];
};
struct zone_psettab {
diff --git a/usr/src/lib/brand/lx/zone/platform.xml b/usr/src/lib/brand/lx/zone/platform.xml
index 060343e38f..7097ae8e1c 100644
--- a/usr/src/lib/brand/lx/zone/platform.xml
+++ b/usr/src/lib/brand/lx/zone/platform.xml
@@ -98,8 +98,7 @@
<device match="urandom" />
<device match="zero" />
<device match="zfs" />
- <device match="zvol/dsk/%P/%z/*" />
- <device match="zvol/rdsk/%P/%z/*" />
+ <device match="zvol/*" />
<!-- Devices to create in exclusive IP zone only -->
<device match="dld" ip-type="exclusive" />
diff --git a/usr/src/lib/libzonecfg/common/libzonecfg.c b/usr/src/lib/libzonecfg/common/libzonecfg.c
index e709b7dba8..0e7525882e 100644
--- a/usr/src/lib/libzonecfg/common/libzonecfg.c
+++ b/usr/src/lib/libzonecfg/common/libzonecfg.c
@@ -107,6 +107,7 @@
#define DTD_ATTR_ACTION (const xmlChar *) "action"
#define DTD_ATTR_ADDRESS (const xmlChar *) "address"
+#define DTD_ATTR_ALIAS (const xmlChar *) "alias"
#define DTD_ATTR_ALLOWED_ADDRESS (const xmlChar *) "allowed-address"
#define DTD_ATTR_AUTOBOOT (const xmlChar *) "autoboot"
#define DTD_ATTR_IPTYPE (const xmlChar *) "ip-type"
@@ -7021,6 +7022,11 @@ zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
if ((err = newprop(newnode, DTD_ATTR_NAME,
tabptr->zone_dataset_name)) != Z_OK)
return (err);
+ if (tabptr->zone_dataset_alias[0] != '\0') {
+ if ((err = newprop(newnode, DTD_ATTR_ALIAS,
+ tabptr->zone_dataset_alias)) != Z_OK)
+ return (err);
+ }
return (Z_OK);
}
@@ -7051,7 +7057,9 @@ zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
continue;
if (match_prop(cur, DTD_ATTR_NAME,
- tabptr->zone_dataset_name)) {
+ tabptr->zone_dataset_name) &&
+ match_prop(cur, DTD_ATTR_ALIAS,
+ tabptr->zone_dataset_alias)) {
xmlUnlinkNode(cur);
xmlFreeNode(cur);
return (Z_OK);
@@ -7106,6 +7114,7 @@ zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
xmlNodePtr cur, firstmatch;
int err;
char dataset[MAXNAMELEN];
+ char alias[MAXNAMELEN];
if (tabptr == NULL)
return (Z_INVAL);
@@ -7129,6 +7138,25 @@ zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
return (Z_INSUFFICIENT_SPEC);
}
}
+ if (strlen(tabptr->zone_dataset_alias) > 0) {
+ if ((fetchprop(cur, DTD_ATTR_ALIAS, alias,
+ sizeof (alias)) == Z_OK)) {
+ if (strcmp(tabptr->zone_dataset_alias,
+ alias) == 0) {
+ if (firstmatch == NULL)
+ firstmatch = cur;
+ else if (firstmatch != cur)
+ return (Z_INSUFFICIENT_SPEC);
+ } else {
+ /*
+ * If another property matched but this
+ * one doesn't then reset firstmatch.
+ */
+ if (firstmatch == cur)
+ firstmatch = NULL;
+ }
+ }
+ }
}
if (firstmatch == NULL)
return (Z_NO_RESOURCE_ID);
@@ -7138,6 +7166,9 @@ zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
sizeof (tabptr->zone_dataset_name))) != Z_OK)
return (err);
+ if ((err = fetchprop(cur, DTD_ATTR_ALIAS, tabptr->zone_dataset_alias,
+ sizeof (tabptr->zone_dataset_alias))) != Z_OK)
+ return (err);
return (Z_OK);
}
@@ -7173,6 +7204,11 @@ zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr)
handle->zone_dh_cur = handle->zone_dh_top;
return (err);
}
+ if ((err = fetchprop(cur, DTD_ATTR_ALIAS, tabptr->zone_dataset_alias,
+ sizeof (tabptr->zone_dataset_alias))) != Z_OK) {
+ handle->zone_dh_cur = handle->zone_dh_top;
+ return (err);
+ }
handle->zone_dh_cur = cur->next;
return (Z_OK);
diff --git a/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1 b/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1
index 228bb8ace2..ee72fa0759 100644
--- a/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1
+++ b/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1
@@ -100,7 +100,8 @@
<!ELEMENT dataset EMPTY>
-<!ATTLIST dataset name CDATA #REQUIRED>
+<!ATTLIST dataset name CDATA #REQUIRED
+ alias CDATA "">
<!ELEMENT package EMPTY>
diff --git a/usr/src/lib/libzpool/common/sys/zfs_context.h b/usr/src/lib/libzpool/common/sys/zfs_context.h
index 3c7d304d65..91cceb0f63 100644
--- a/usr/src/lib/libzpool/common/sys/zfs_context.h
+++ b/usr/src/lib/libzpool/common/sys/zfs_context.h
@@ -324,7 +324,7 @@ typedef struct callb_cpr {
mutex_exit((cp)->cc_lockp); \
}
-#define zone_dataset_visible(x, y) (1)
+#define zone_dataset_visible(x, y, z) (1)
#define INGLOBALZONE(z) (1)
extern uint32_t zone_get_hostid(void *zonep);
diff --git a/usr/src/uts/common/brand/lx/os/lx_brand.c b/usr/src/uts/common/brand/lx/os/lx_brand.c
index fed6be37cf..34f2f4f945 100644
--- a/usr/src/uts/common/brand/lx/os/lx_brand.c
+++ b/usr/src/uts/common/brand/lx/os/lx_brand.c
@@ -1018,7 +1018,8 @@ lx_zone_get_zvols(zone_t *zone, ldi_handle_t lh, minor_t *emul_minor)
strchr(zc->zc_name, '%') != NULL)
continue;
- if (!zone_dataset_visible_inzone(zone, zc->zc_name, &w))
+ if (!zone_dataset_visible_inzone(zone, zc->zc_name, &w,
+ B_TRUE))
continue;
if (zc->zc_objset_stats.dds_type == DMU_OST_ZVOL) {
@@ -1029,6 +1030,12 @@ lx_zone_get_zvols(zone_t *zone, ldi_handle_t lh, minor_t *emul_minor)
/* Create a virtual disk entry for the zvol */
vd = kmem_zalloc(sizeof (lx_virt_disk_t),
KM_SLEEP);
+
+ rc = zone_dataset_alias_inzone(zc->zc_name,
+ zv->lzd_name, MAXPATHLEN, zone);
+ if (rc != 0)
+ continue;
+
vd->lxvd_type = LXVD_ZVOL;
(void) snprintf(vd->lxvd_name,
sizeof (vd->lxvd_name),
diff --git a/usr/src/uts/common/fs/dev/sdev_zvolops.c b/usr/src/uts/common/fs/dev/sdev_zvolops.c
index e236eb3f72..ae35638836 100644
--- a/usr/src/uts/common/fs/dev/sdev_zvolops.c
+++ b/usr/src/uts/common/fs/dev/sdev_zvolops.c
@@ -447,6 +447,8 @@ devzvol_create_pool_dirs(struct vnode *dvp)
nvlist_t *nv = NULL;
nvpair_t *elem = NULL;
int pools = 0;
+ zone_t *zone = curzone;
+ zone_dataset_t *zd;
int rc;
sdcmn_err13(("devzvol_create_pool_dirs"));
@@ -480,6 +482,17 @@ devzvol_create_pool_dirs(struct vnode *dvp)
VN_RELE(vp);
pools++;
}
+ for (zd = list_head(&zone->zone_datasets); zd != NULL;
+ zd = list_next(&zone->zone_datasets, zd)) {
+ struct vnode *vp;
+ if (zd->zd_alias == NULL)
+ continue;
+ rc = VOP_LOOKUP(dvp, zd->zd_alias, &vp, NULL, 0,
+ NULL, kcred, NULL, 0, NULL);
+ if (rc == 0)
+ VN_RELE(vp);
+ pools++;
+ }
nvlist_free(nv);
mutex_enter(&devzvol_mtx);
if (devzvol_isopen && pools == 0) {
@@ -734,12 +747,31 @@ devzvol_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
* but prof_lookup will also find it via sdev_cache_lookup.
*/
if (res == ENOENT) {
- /*
- * We have to create the sdev node for the dymamically
- * created zvol.
- */
- if (devzvol_mk_ngz_node(parent, nm) != 0)
- return (ENOENT);
+ if (strcmp(parent->sdev_path, ZVOL_DIR) == 0) {
+ /*
+ * If this is the top-level dir, make sure
+ * that dsk/rdsk dirs have been created.
+ *
+ * devzvol_mk_ngz_node doesn't work on these,
+ * and if we do a lookup through here having
+ * never done a readdir() before on /dev/zvol,
+ * these nodes won't exist yet.
+ */
+ struct vnode *vp;
+ (void) devname_lookup_func(parent, "dsk", &vp,
+ cred, devzvol_create_dir, SDEV_VATTR);
+ VN_RELE(vp);
+ (void) devname_lookup_func(parent, "rdsk", &vp,
+ cred, devzvol_create_dir, SDEV_VATTR);
+ VN_RELE(vp);
+ } else {
+ /*
+ * We have to create the sdev node for the
+ * dynamically created zvol.
+ */
+ if (devzvol_mk_ngz_node(parent, nm) != 0)
+ return (ENOENT);
+ }
res = prof_lookup(dvp, nm, vpp, cred);
}
@@ -863,6 +895,9 @@ sdev_iter_datasets(struct vnode *dvp, int arg, char *name)
sdcmn_err13((" name %s", zc->zc_name));
if (strchr(zc->zc_name, '$') || strchr(zc->zc_name, '%'))
goto skip;
+ if (strrchr(zc->zc_name, '/') == NULL) {
+ goto skip;
+ }
ptr = strrchr(zc->zc_name, '/') + 1;
rc = devzvol_lookup(dvp, ptr, &vpp, NULL, 0, NULL,
kcred, NULL, NULL, NULL);
diff --git a/usr/src/uts/common/fs/zfs/spa_config.c b/usr/src/uts/common/fs/zfs/spa_config.c
index 4719696ca4..25383f0059 100644
--- a/usr/src/uts/common/fs/zfs/spa_config.c
+++ b/usr/src/uts/common/fs/zfs/spa_config.c
@@ -330,7 +330,7 @@ spa_all_configs(uint64_t *generation)
mutex_enter(&spa_namespace_lock);
while ((spa = spa_next(spa)) != NULL) {
if (INGLOBALZONE(curproc) ||
- zone_dataset_visible(spa_name(spa), NULL)) {
+ zone_dataset_visible(spa_name(spa), NULL, B_TRUE)) {
mutex_enter(&spa->spa_props_lock);
fnvlist_add_nvlist(pools, spa_name(spa),
spa->spa_config);
diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
index 153dcf1502..94cbe34d9f 100644
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
@@ -222,6 +222,8 @@ static uint_t zfs_allow_log_key;
typedef int zfs_ioc_legacy_func_t(zfs_cmd_t *);
typedef int zfs_ioc_func_t(const char *, nvlist_t *, nvlist_t *);
typedef int zfs_secpolicy_func_t(zfs_cmd_t *, nvlist_t *, cred_t *);
+typedef int zfs_alias_func_t(zfs_cmd_t *, nvlist_t **, nvlist_t **, cred_t *);
+typedef int zfs_unalias_func_t(zfs_cmd_t *, nvlist_t **, cred_t *);
typedef enum {
NO_NAME,
@@ -240,6 +242,8 @@ typedef struct zfs_ioc_vec {
zfs_ioc_func_t *zvec_func;
zfs_secpolicy_func_t *zvec_secpolicy;
zfs_ioc_namecheck_t zvec_namecheck;
+ zfs_alias_func_t *zvec_alias;
+ zfs_unalias_func_t *zvec_unalias;
boolean_t zvec_allow_log;
zfs_ioc_poolcheck_t zvec_pool_check;
boolean_t zvec_smush_outnvlist;
@@ -311,6 +315,449 @@ __dprintf(const char *file, const char *func, int line, const char *fmt, ...)
char *, newfile, char *, func, int, line, char *, buf);
}
+/* ARGSUSED */
+static int
+zfs_unalias_noop(zfs_cmd_t *zc, nvlist_t **innvl, cred_t *cr)
+{
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+zfs_alias_noop(zfs_cmd_t *zc, nvlist_t **innvl, nvlist_t **outnvl, cred_t *cr)
+{
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+zfs_unalias_dsname(zfs_cmd_t *zc, nvlist_t **innvl, cred_t *cr)
+{
+ char *oname;
+ int error;
+
+ oname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+ (void) strcpy(oname, zc->zc_name);
+ error = zone_dataset_unalias(oname, zc->zc_name, MAXPATHLEN);
+ kmem_free(oname, MAXPATHLEN);
+ return (error);
+}
+
+/* ARGSUSED */
+static int
+zfs_unalias_value(zfs_cmd_t *zc, nvlist_t **innvl, cred_t *cr)
+{
+ char *oname;
+ int error;
+
+ oname = kmem_zalloc(MAXPATHLEN * 2, KM_SLEEP);
+ (void) strcpy(oname, zc->zc_value);
+ error = zone_dataset_unalias(oname, zc->zc_value, MAXPATHLEN * 2);
+ kmem_free(oname, MAXPATHLEN * 2);
+
+ if (error != 0)
+ return (error);
+
+ error = zfs_unalias_dsname(zc, innvl, cr);
+
+ return (error);
+}
+
+/* ARGSUSED */
+static int
+zfs_unalias_poolname(zfs_cmd_t *zc, nvlist_t **innvl, cred_t *cr)
+{
+ zone_t *zone = curzone;
+ zone_dataset_t *zd = NULL;
+ char *ptr;
+ size_t len;
+
+ if (zc->zc_name[0] == '\0')
+ return (0);
+
+ zc->zc_action_handle = 0;
+
+ /*
+ * First look for any straight-through zone dataset entries that mean
+ * that this poolname should not be aliased.
+ */
+ for (zd = list_head(&zone->zone_datasets); zd != NULL;
+ zd = list_next(&zone->zone_datasets, zd)) {
+ if (zd->zd_alias != NULL)
+ continue;
+
+ len = strlen(zd->zd_dataset);
+ ptr = strchr(zd->zd_dataset, '/');
+ if (ptr != NULL)
+ len = (ptr - zd->zd_dataset);
+ if (bcmp(zc->zc_name, zd->zd_dataset, len) == 0 &&
+ strlen(zc->zc_name) == len) {
+ /*
+ * Stash the zone_dataset_t that matches in the
+ * zfs_cmd_t, so that we can pull it back out later in
+ * zfs_alias_poolname. The zc_action_handle field is
+ * never used by any pool-related ioctls (only by
+ * IOC_RECV), so overwriting it should be ok.
+ */
+ zc->zc_action_handle = (uint64_t)((uintptr_t)zd);
+ return (0);
+ }
+ }
+ /* Now try to find an alias. */
+ for (zd = list_head(&zone->zone_datasets); zd != NULL;
+ zd = list_next(&zone->zone_datasets, zd)) {
+ if (zd->zd_alias == NULL)
+ continue;
+
+ len = strlen(zd->zd_alias);
+ if (bcmp(zc->zc_name, zd->zd_alias, len) == 0
+ && strlen(zc->zc_name) == len) {
+ zc->zc_action_handle = (uint64_t)((uintptr_t)zd);
+ (void) strcpy(zc->zc_name, zd->zd_dataset);
+ ptr = strchr(zc->zc_name, '/');
+ if (ptr != NULL)
+ *ptr = '\0';
+ break;
+ }
+ }
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+zfs_unalias_oneprop_common(zfs_cmd_t *zc, nvlist_t **innvl, cred_t *cr,
+ const char *key)
+{
+ char *firstsnap;
+ char *nfirstsnap = NULL;
+ int error;
+ size_t len;
+
+ if (nvlist_lookup_string(*innvl, key, &firstsnap) != 0)
+ return (EINVAL);
+
+ nfirstsnap = kmem_zalloc(MAXPATHLEN * 2, KM_SLEEP);
+ error = zone_dataset_unalias(firstsnap, nfirstsnap, MAXPATHLEN * 2);
+ if (error != 0)
+ goto out;
+ error = nvlist_add_string(*innvl, key, nfirstsnap);
+ if (error != 0)
+ goto out;
+ error = zfs_unalias_dsname(zc, innvl, cr);
+
+out:
+ if (nfirstsnap != NULL)
+ kmem_free(nfirstsnap, MAXPATHLEN * 2);
+ return (error);
+}
+
+/* ARGSUSED */
+static int
+zfs_unalias_origin(zfs_cmd_t *zc, nvlist_t **innvl, cred_t *cr)
+{
+ return (zfs_unalias_oneprop_common(zc, innvl, cr, "origin"));
+}
+
+/* ARGSUSED */
+static int
+zfs_unalias_from(zfs_cmd_t *zc, nvlist_t **innvl, cred_t *cr)
+{
+ return (zfs_unalias_oneprop_common(zc, innvl, cr, "from"));
+}
+
+/* ARGSUSED */
+static int
+zfs_unalias_fromsnap(zfs_cmd_t *zc, nvlist_t **innvl, cred_t *cr)
+{
+ return (zfs_unalias_oneprop_common(zc, innvl, cr, "fromsnap"));
+}
+
+/* ARGSUSED */
+static int
+zfs_unalias_firstsnap(zfs_cmd_t *zc, nvlist_t **innvl, cred_t *cr)
+{
+ return (zfs_unalias_oneprop_common(zc, innvl, cr, "firstsnap"));
+}
+
+/* ARGSUSED */
+static int
+zfs_alias_dsname(zfs_cmd_t *zc, nvlist_t **innvl, nvlist_t **outnvl, cred_t *cr)
+{
+ char *oname;
+ int error;
+ if (zc->zc_name[0] == '\0')
+ return (0);
+
+ /* Otherwise, try to alias as if it's a dataset. */
+ oname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+ (void) strcpy(oname, zc->zc_name);
+ error = zone_dataset_alias(oname, zc->zc_name, MAXPATHLEN);
+ kmem_free(oname, MAXPATHLEN);
+ /* But ignore EINVAL, in case it's not actually one. */
+ if (error == EINVAL)
+ error = 0;
+ return (error);
+}
+
+/* ARGSUSED */
+static int
+zfs_alias_value(zfs_cmd_t *zc, nvlist_t **innvl, nvlist_t **outnvl, cred_t *cr)
+{
+ char *oname;
+ int error;
+ if (zc->zc_value[0] == '\0')
+ return (0);
+
+ oname = kmem_zalloc(MAXPATHLEN * 2, KM_SLEEP);
+ (void) strcpy(oname, zc->zc_value);
+ error = zone_dataset_alias(oname, zc->zc_value, MAXPATHLEN * 2);
+ kmem_free(oname, MAXPATHLEN * 2);
+
+ if (error != 0)
+ return (error);
+
+ error = zfs_alias_dsname(zc, innvl, outnvl, cr);
+
+ return (error);
+}
+
+/* ARGSUSED */
+static int
+zfs_alias_string_value(zfs_cmd_t *zc, nvlist_t **innvl, nvlist_t **outnvl,
+ cred_t *cr)
+{
+ char *oname;
+ int error;
+ if (zc->zc_string[0] == '\0')
+ return (0);
+
+ oname = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
+ (void) strcpy(oname, zc->zc_string);
+ error = zone_dataset_alias(oname, zc->zc_string, MAXNAMELEN);
+ kmem_free(oname, MAXNAMELEN);
+
+ if (error != 0)
+ return (error);
+
+ error = zfs_alias_value(zc, innvl, outnvl, cr);
+
+ return (error);
+}
+
+/* ARGSUSED */
+static int
+zfs_alias_poolname(zfs_cmd_t *zc, nvlist_t **innvl, nvlist_t **outnvl,
+ cred_t *cr)
+{
+ zone_dataset_t *zd;
+
+ if (zc->zc_name[0] == '\0')
+ return (0);
+
+ /*
+ * We stashed the pointer to the zone_dataset_t in the zc_action_handle
+ * member back in zfs_unalias_poolname.
+ */
+ zd = (zone_dataset_t *)((uintptr_t)zc->zc_action_handle);
+ VERIFY(zd != NULL);
+
+ /* Zero it so we don't leak the pointer back to userland. */
+ zc->zc_action_handle = 0;
+
+ if (zd->zd_alias == NULL)
+ return (0);
+
+ (void) strcpy(zc->zc_name, zd->zd_alias);
+
+ return (0);
+}
+
+static int
+zfs_map_nvlist_kv_str(nvlist_t *nvl, nvlist_t *innvl, boolean_t dovalues,
+ int (*func)(const char *, char *, size_t))
+{
+ nvpair_t *pair;
+ int error = 0;
+ char *nname = NULL, *nvalue = NULL;
+
+ for (pair = nvlist_next_nvpair(innvl, NULL); pair != NULL;
+ pair = nvlist_next_nvpair(innvl, pair)) {
+ const char *name = nvpair_name(pair);
+ char *value;
+
+ if (dovalues) {
+ if (nvpair_type(pair) != DATA_TYPE_STRING) {
+ error = EINVAL;
+ goto out;
+ }
+ error = nvpair_value_string(pair, &value);
+ if (error != 0)
+ goto out;
+ }
+
+ if (nname == NULL)
+ nname = kmem_zalloc(MAXPATHLEN * 2, KM_SLEEP);
+ error = (*func)(name, nname, MAXPATHLEN * 2);
+ if (error != 0)
+ goto out;
+
+ if (dovalues) {
+ if (nvalue == NULL)
+ nvalue = kmem_zalloc(MAXPATHLEN * 2, KM_SLEEP);
+ error = (*func)(value, nvalue, MAXPATHLEN * 2);
+ if (error != 0)
+ goto out;
+
+ error = nvlist_add_string(nvl, nname, nvalue);
+ if (error != 0)
+ goto out;
+ } else {
+ error = nvlist_add_named_nvpair(nvl, nname, pair);
+ if (error != 0)
+ goto out;
+ }
+ }
+
+out:
+ if (nname != NULL)
+ kmem_free(nname, MAXPATHLEN * 2);
+ if (nvalue != NULL)
+ kmem_free(nvalue, MAXPATHLEN * 2);
+ return (error);
+}
+
+static int
+zfs_unalias_nvl_common(nvlist_t **innvl, boolean_t dovalues)
+{
+ nvlist_t *nvl = NULL;
+ int error;
+
+ if (*innvl == NULL)
+ return (EINVAL);
+
+ error = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP);
+ if (error != 0)
+ goto out;
+
+ error = zfs_map_nvlist_kv_str(nvl, *innvl, dovalues,
+ zone_dataset_unalias);
+ if (error != 0)
+ goto out;
+
+ nvlist_free(*innvl);
+ *innvl = nvl;
+ nvl = NULL;
+
+out:
+ nvlist_free(nvl);
+ return (error);
+}
+
+/* ARGSUSED */
+static int
+zfs_unalias_nvlkeys(zfs_cmd_t *zc, nvlist_t **innvl, cred_t *cr)
+{
+ int error;
+ error = zfs_unalias_poolname(zc, innvl, cr);
+ if (error)
+ return (error);
+ error = zfs_unalias_nvl_common(innvl, B_FALSE);
+ return (error);
+}
+
+/* ARGSUSED */
+static int
+zfs_unalias_nvl(zfs_cmd_t *zc, nvlist_t **innvl, cred_t *cr)
+{
+ int error;
+ error = zfs_unalias_poolname(zc, innvl, cr);
+ if (error)
+ return (error);
+ error = zfs_unalias_nvl_common(innvl, B_TRUE);
+ return (error);
+}
+
+static int
+zfs_alias_nvl_common(nvlist_t **outnvl, boolean_t dovalues)
+{
+ nvlist_t *nvl = NULL;
+ int error;
+
+ if (*outnvl == NULL)
+ return (EINVAL);
+
+ error = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP);
+ if (error != 0)
+ goto out;
+
+ error = zfs_map_nvlist_kv_str(nvl, *outnvl, dovalues,
+ zone_dataset_alias);
+ if (error != 0)
+ goto out;
+
+ nvlist_free(*outnvl);
+ *outnvl = nvl;
+ nvl = NULL;
+
+out:
+ nvlist_free(nvl);
+ return (error);
+}
+
+/* ARGSUSED */
+static int
+zfs_alias_nvlkeys(zfs_cmd_t *zc, nvlist_t **innvl, nvlist_t **outnvl,
+ cred_t *cr)
+{
+ int error;
+ error = zfs_alias_poolname(zc, innvl, outnvl, cr);
+ if (error)
+ return (error);
+ error = zfs_alias_nvl_common(outnvl, B_FALSE);
+ return (error);
+}
+
+/* ARGSUSED */
+static int
+zfs_unalias_subnvl_common(zfs_cmd_t *zc, nvlist_t **innvl, cred_t *cr,
+ const char *key, boolean_t dovalues)
+{
+ nvlist_t *snaps;
+ int error;
+
+ error = zfs_unalias_poolname(zc, innvl, cr);
+ if (error)
+ return (error);
+
+ if (*innvl == NULL)
+ return (EINVAL);
+ if (nvlist_lookup_nvlist(*innvl, key, &snaps) != 0)
+ return (EINVAL);
+
+ error = zfs_unalias_nvl_common(&snaps, dovalues);
+ if (error != 0)
+ return (error);
+
+ error = nvlist_add_nvlist(*innvl, key, snaps);
+ nvlist_free(snaps);
+ return (error);
+}
+
+/* ARGSUSED */
+static int
+zfs_unalias_holds(zfs_cmd_t *zc, nvlist_t **innvl, cred_t *cr)
+{
+ return (zfs_unalias_subnvl_common(zc, innvl, cr, "holds", B_FALSE));
+}
+
+/* ARGSUSED */
+static int
+zfs_unalias_snaps(zfs_cmd_t *zc, nvlist_t **innvl, cred_t *cr)
+{
+ return (zfs_unalias_subnvl_common(zc, innvl, cr, "snaps", B_FALSE));
+}
+
static void
history_str_free(char *buf)
{
@@ -433,7 +880,18 @@ static int
zfs_secpolicy_read(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
if (INGLOBALZONE(curproc) ||
- zone_dataset_visible(zc->zc_name, NULL))
+ zone_dataset_visible(zc->zc_name, NULL, B_FALSE))
+ return (0);
+
+ return (SET_ERROR(ENOENT));
+}
+
+/* ARGSUSED */
+static int
+zfs_secpolicy_read_pool(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+ if (INGLOBALZONE(curproc) ||
+ zone_dataset_visible(zc->zc_name, NULL, B_TRUE))
return (0);
return (SET_ERROR(ENOENT));
@@ -449,7 +907,7 @@ zfs_dozonecheck_impl(const char *dataset, uint64_t zoned, cred_t *cr)
* so they don't see EPERM on something they shouldn't know about.
*/
if (!INGLOBALZONE(curproc) &&
- !zone_dataset_visible(dataset, &writable))
+ !zone_dataset_visible(dataset, &writable, B_FALSE))
return (SET_ERROR(ENOENT));
if (INGLOBALZONE(curproc)) {
@@ -1669,6 +2127,92 @@ zfs_ioc_pool_export(zfs_cmd_t *zc)
return (error);
}
+static boolean_t
+zfs_zone_ds_matches_alias(const char *dataset, zone_dataset_t *zd)
+{
+ size_t len;
+
+ len = strlen(zd->zd_dataset);
+ if (strlen(dataset) >= len &&
+ bcmp(dataset, zd->zd_dataset, len) == 0 &&
+ (dataset[len] == '\0' || dataset[len] == '/' ||
+ dataset[len] == '@')) {
+ return (B_TRUE);
+ }
+
+ len = strlen(dataset);
+ if (dataset[len - 1] == '/')
+ len--; /* Ignore trailing slash */
+ if (len < strlen(zd->zd_dataset) &&
+ bcmp(dataset, zd->zd_dataset, len) == 0 &&
+ zd->zd_dataset[len] == '/') {
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
+static int
+zfs_alias_pool_configs(nvlist_t **configs)
+{
+ nvlist_t *all = *configs;
+ nvlist_t *pool = NULL;
+ nvpair_t *elem = NULL;
+ const char *name;
+ zone_dataset_t *zd;
+ boolean_t found;
+ int error = 0;
+ zone_t *zone = curzone;
+
+ *configs = NULL;
+ VERIFY(nvlist_alloc(configs, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+ /*
+ * For each pool, we want to create an entry in the final list,
+ * and possibly rename it to reflect an alias. It's also possible
+ * we will need to do both (for two delegated datasets under the
+ * same pool, one aliased and one not).
+ *
+ * Since we made configs with NV_UNIQUE_NAME, re-adding the same
+ * pool multiple times is not really a problem, so we just do a
+ * naive nested loop over all of the possible combinations.
+ */
+ while ((elem = nvlist_next_nvpair(all, elem)) != NULL) {
+ name = nvpair_name(elem);
+ VERIFY(nvpair_value_nvlist(elem, &pool) == 0);
+
+ found = B_FALSE;
+ for (zd = list_head(&zone->zone_datasets); zd != NULL;
+ zd = list_next(&zone->zone_datasets, zd)) {
+ if (zfs_zone_ds_matches_alias(name, zd) == B_TRUE) {
+ if (zd->zd_alias == NULL) {
+ VERIFY(nvlist_add_string(pool,
+ "name", name) == 0);
+ VERIFY(nvlist_add_nvlist(*configs,
+ name, pool) == 0);
+ } else {
+ VERIFY(nvlist_add_string(pool,
+ "name", zd->zd_alias) == 0);
+ VERIFY(nvlist_add_nvlist(*configs,
+ zd->zd_alias, pool) == 0);
+ }
+ found = B_TRUE;
+ }
+ }
+ /*
+ * If we found no zone_dataset_t, it was a VFS-style pass-
+ * through into the zone. This kind has no aliasing, so
+ * add the pool under its usual name.
+ */
+ if (found == B_FALSE)
+ VERIFY(nvlist_add_nvlist(*configs, name, pool) == 0);
+ }
+
+out:
+ nvlist_free(all);
+ return (error);
+}
+
static int
zfs_ioc_pool_configs(zfs_cmd_t *zc)
{
@@ -1678,6 +2222,14 @@ zfs_ioc_pool_configs(zfs_cmd_t *zc)
if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL)
return (SET_ERROR(EEXIST));
+ if (!INGLOBALZONE(curproc)) {
+ error = zfs_alias_pool_configs(&configs);
+ if (error != 0) {
+ nvlist_free(configs);
+ return (SET_ERROR(error));
+ }
+ }
+
error = put_nvlist(zc, configs);
nvlist_free(configs);
@@ -1698,12 +2250,31 @@ static int
zfs_ioc_pool_stats(zfs_cmd_t *zc)
{
nvlist_t *config;
+ zone_dataset_t *zd;
int error;
int ret = 0;
error = spa_get_stats(zc->zc_name, &config, zc->zc_value,
sizeof (zc->zc_value));
+ /*
+ * If we're returning the name property to a non-global zone, apply
+ * aliases as needed.
+ */
+ if (config != NULL && !INGLOBALZONE(curproc)) {
+ /*
+ * We stashed the pointer to the zone_dataset_t in the
+ * zc_action_handle member back in zfs_unalias_poolname.
+ */
+ zd = (zone_dataset_t *)((uintptr_t)zc->zc_action_handle);
+ if (zd == NULL)
+ return (EINVAL);
+
+ if (zd->zd_alias != NULL)
+ VERIFY0(nvlist_add_string(config, "name",
+ zd->zd_alias));
+ }
+
if (config != NULL) {
ret = put_nvlist(zc, config);
nvlist_free(config);
@@ -2140,6 +2711,90 @@ zfs_ioc_vdev_setfru(zfs_cmd_t *zc)
}
static int
+zfs_alias_propsrcs(nvlist_t **outnvl)
+{
+ nvlist_t *prop;
+ nvpair_t *pair;
+ int error = 0;
+ boolean_t remorigin = B_FALSE;
+ char *src;
+ char *newsrc = kmem_zalloc(MAXPATHLEN * 2, KM_SLEEP);
+
+ if (*outnvl == NULL)
+ goto out;
+
+ for (pair = nvlist_next_nvpair(*outnvl, NULL); pair != NULL;
+ pair = nvlist_next_nvpair(*outnvl, pair)) {
+ const char *name = nvpair_name(pair);
+ if (nvpair_type(pair) != DATA_TYPE_NVLIST) {
+ error = EINVAL;
+ goto out;
+ }
+ if ((error = nvpair_value_nvlist(pair, &prop)) != 0)
+ goto out;
+
+ if (strcmp(name, "origin") == 0 ||
+ strcmp(name, "prevsnap") == 0) {
+ error = nvlist_lookup_string(prop, "value", &src);
+ if (error != 0)
+ goto out;
+ error = zone_dataset_alias(src, newsrc, MAXPATHLEN * 2);
+ if (error == EINVAL) {
+ remorigin = B_TRUE;
+ } else if (error != 0) {
+ goto out;
+ }
+ error = nvlist_add_string(prop, "value", newsrc);
+ if (error != 0)
+ goto out;
+ }
+ if (strcmp(name, "clones") == 0) {
+ nvlist_t *clones;
+ error = nvlist_lookup_nvlist(prop, "value", &clones);
+ if (error != 0)
+ goto out;
+ error = zfs_alias_nvl_common(&clones, B_FALSE);
+ if (error != 0)
+ goto out;
+ error = nvlist_add_nvlist(prop, "value", clones);
+ nvlist_free(clones);
+ if (error != 0)
+ goto out;
+ }
+
+ if (nvlist_lookup_string(prop, "source", &src) != 0)
+ continue;
+ if (strlen(src) == 0)
+ continue;
+
+ error = zone_dataset_alias(src, newsrc, MAXPATHLEN * 2);
+ if (error == EINVAL) {
+ /*
+ * This is a parent of an aliased dataset and has no
+ * representation in the zone.
+ */
+ (void) strcpy(newsrc, "global zone");
+ } else if (error != 0) {
+ goto out;
+ }
+
+ if ((error = nvlist_add_string(prop, "source", newsrc)) != 0)
+ goto out;
+ }
+
+ /*
+ * If the dataset has an origin that's outside the namespace available
+ * to this zone, just drop the origin property.
+ */
+ if (remorigin)
+ error = nvlist_remove_all(*outnvl, "origin");
+
+out:
+ kmem_free(newsrc, MAXPATHLEN * 2);
+ return (error);
+}
+
+static int
zfs_ioc_objset_stats_impl(zfs_cmd_t *zc, objset_t *os,
boolean_t cachedpropsonly)
{
@@ -2166,7 +2821,10 @@ zfs_ioc_objset_stats_impl(zfs_cmd_t *zc, objset_t *os,
return (error);
VERIFY0(error);
}
- error = put_nvlist(zc, nv);
+ if (!INGLOBALZONE(curproc))
+ error = zfs_alias_propsrcs(&nv);
+ if (error == 0)
+ error = put_nvlist(zc, nv);
nvlist_free(nv);
}
@@ -2320,8 +2978,10 @@ dataset_name_hidden(const char *name)
return (B_TRUE);
if (strchr(name, '%') != NULL)
return (B_TRUE);
- if (!INGLOBALZONE(curproc) && !zone_dataset_visible(name, NULL))
+ if (!INGLOBALZONE(curproc) && !zone_dataset_visible(name, NULL,
+ B_FALSE)) {
return (B_TRUE);
+ }
return (B_FALSE);
}
@@ -3021,6 +3681,7 @@ zfs_ioc_pool_get_props(zfs_cmd_t *zc)
spa_t *spa;
int error;
nvlist_t *nvp = NULL;
+ nvlist_t *prop;
if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) {
/*
@@ -3037,6 +3698,25 @@ zfs_ioc_pool_get_props(zfs_cmd_t *zc)
spa_close(spa, FTAG);
}
+ /* Apply aliases to pool info given to non-global zones. */
+ if (error == 0 && zc->zc_nvlist_dst != 0 &&
+ !INGLOBALZONE(curproc) &&
+ nvlist_lookup_nvlist(nvp, "name", &prop) == 0) {
+ zone_dataset_t *zd;
+
+ /*
+ * We stashed the pointer to the zone_dataset_t in the
+ * zc_action_handle member back in zfs_unalias_poolname.
+ */
+ zd = (zone_dataset_t *)((uintptr_t)zc->zc_action_handle);
+ if (zd == NULL)
+ return (EINVAL);
+
+ if (zd->zd_alias != NULL)
+ VERIFY0(nvlist_add_string(prop, "value",
+ zd->zd_alias));
+ }
+
if (error == 0 && zc->zc_nvlist_dst != 0)
error = put_nvlist(zc, nvp);
else
@@ -3652,6 +4332,7 @@ zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
nvlist_t *snaps;
nvpair_t *pair;
boolean_t defer;
+ int error;
if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0)
return (SET_ERROR(EINVAL));
@@ -3662,7 +4343,9 @@ zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
zfs_unmount_snap(nvpair_name(pair));
}
- return (dsl_destroy_snapshots_nvl(snaps, defer, outnvl));
+ error = dsl_destroy_snapshots_nvl(snaps, defer, outnvl);
+
+ return (error);
}
/*
@@ -6442,6 +7125,7 @@ static void
zfs_ioctl_register_legacy(const char *name, zfs_ioc_t ioc,
zfs_ioc_legacy_func_t *func,
zfs_secpolicy_func_t *secpolicy, zfs_ioc_namecheck_t namecheck,
+ zfs_unalias_func_t *unalias, zfs_alias_func_t *alias,
boolean_t log_history, zfs_ioc_poolcheck_t pool_check)
{
zfs_ioc_vec_t *vec = &zfs_ioc_vec[ioc - ZFS_IOC_FIRST];
@@ -6455,6 +7139,8 @@ zfs_ioctl_register_legacy(const char *name, zfs_ioc_t ioc,
vec->zvec_legacy_func = func;
vec->zvec_secpolicy = secpolicy;
vec->zvec_namecheck = namecheck;
+ vec->zvec_unalias = unalias;
+ vec->zvec_alias = alias;
vec->zvec_allow_log = log_history;
vec->zvec_pool_check = pool_check;
}
@@ -6466,6 +7152,7 @@ zfs_ioctl_register_legacy(const char *name, zfs_ioc_t ioc,
static void
zfs_ioctl_register(const char *name, zfs_ioc_t ioc, zfs_ioc_func_t *func,
zfs_secpolicy_func_t *secpolicy, zfs_ioc_namecheck_t namecheck,
+ zfs_unalias_func_t *unalias, zfs_alias_func_t *alias,
zfs_ioc_poolcheck_t pool_check, boolean_t smush_outnvlist,
boolean_t allow_log)
{
@@ -6483,6 +7170,8 @@ zfs_ioctl_register(const char *name, zfs_ioc_t ioc, zfs_ioc_func_t *func,
vec->zvec_func = func;
vec->zvec_secpolicy = secpolicy;
vec->zvec_namecheck = namecheck;
+ vec->zvec_unalias = unalias;
+ vec->zvec_alias = alias;
vec->zvec_pool_check = pool_check;
vec->zvec_smush_outnvlist = smush_outnvlist;
vec->zvec_allow_log = allow_log;
@@ -6493,40 +7182,45 @@ zfs_ioctl_register_pool(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func,
zfs_secpolicy_func_t *secpolicy, boolean_t log_history,
zfs_ioc_poolcheck_t pool_check)
{
- zfs_ioctl_register_legacy(NULL, ioc, func, secpolicy,
- POOL_NAME, log_history, pool_check);
+ zfs_ioctl_register_legacy(ioc, func, secpolicy,
+ POOL_NAME, zfs_unalias_poolname, zfs_alias_poolname,
+ log_history, pool_check);
}
static void
zfs_ioctl_register_dataset_nolog(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func,
zfs_secpolicy_func_t *secpolicy, zfs_ioc_poolcheck_t pool_check)
{
- zfs_ioctl_register_legacy(NULL, ioc, func, secpolicy,
- DATASET_NAME, B_FALSE, pool_check);
+ zfs_ioctl_register_legacy(ioc, func, secpolicy,
+ DATASET_NAME, zfs_unalias_dsname, zfs_alias_dsname,
+ B_FALSE, pool_check);
}
static void
zfs_ioctl_register_pool_modify(const char *name, zfs_ioc_t ioc,
zfs_ioc_legacy_func_t *func)
{
- zfs_ioctl_register_legacy(name, ioc, func, zfs_secpolicy_config,
- POOL_NAME, B_TRUE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY);
+ zfs_ioctl_register_legacy(ioc, func, zfs_secpolicy_config,
+ POOL_NAME, zfs_unalias_poolname, zfs_alias_poolname,
+ B_TRUE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY);
}
static void
zfs_ioctl_register_pool_meta(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func,
zfs_secpolicy_func_t *secpolicy)
{
- zfs_ioctl_register_legacy(NULL, ioc, func, secpolicy,
- NO_NAME, B_FALSE, POOL_CHECK_NONE);
+ zfs_ioctl_register_legacy(ioc, func, secpolicy,
+ NO_NAME, zfs_unalias_poolname, zfs_alias_poolname,
+ B_FALSE, POOL_CHECK_NONE);
}
static void
zfs_ioctl_register_dataset_read_secpolicy(zfs_ioc_t ioc,
zfs_ioc_legacy_func_t *func, zfs_secpolicy_func_t *secpolicy)
{
- zfs_ioctl_register_legacy(NULL, ioc, func, secpolicy,
- DATASET_NAME, B_FALSE, POOL_CHECK_SUSPENDED);
+ zfs_ioctl_register_legacy(ioc, func, secpolicy,
+ DATASET_NAME, zfs_unalias_dsname, zfs_alias_dsname, B_FALSE,
+ POOL_CHECK_SUSPENDED);
}
static void
@@ -6540,8 +7234,9 @@ static void
zfs_ioctl_register_dataset_modify(const char *name, zfs_ioc_t ioc,
zfs_ioc_legacy_func_t *func, zfs_secpolicy_func_t *secpolicy)
{
- zfs_ioctl_register_legacy(name, ioc, func, secpolicy,
- DATASET_NAME, B_TRUE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY);
+ zfs_ioctl_register_legacy(ioc, func, secpolicy,
+ DATASET_NAME, zfs_unalias_dsname, zfs_alias_dsname, B_TRUE,
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY);
}
static void
@@ -6549,30 +7244,37 @@ zfs_ioctl_init(void)
{
zfs_ioctl_register("snapshot", ZFS_IOC_SNAPSHOT,
zfs_ioc_snapshot, zfs_secpolicy_snapshot, POOL_NAME,
+ zfs_unalias_snaps, zfs_alias_nvlkeys,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
zfs_ioctl_register("log_history", ZFS_IOC_LOG_HISTORY,
zfs_ioc_log_history, zfs_secpolicy_log_history, NO_NAME,
+ zfs_unalias_noop, zfs_alias_noop,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_FALSE);
zfs_ioctl_register("space_snaps", ZFS_IOC_SPACE_SNAPS,
zfs_ioc_space_snaps, zfs_secpolicy_read, DATASET_NAME,
+ zfs_unalias_firstsnap, zfs_alias_dsname,
POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE);
zfs_ioctl_register("send", ZFS_IOC_SEND_NEW,
zfs_ioc_send_new, zfs_secpolicy_send_new, DATASET_NAME,
+ zfs_unalias_fromsnap, zfs_alias_dsname,
POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE);
zfs_ioctl_register("send_space", ZFS_IOC_SEND_SPACE,
zfs_ioc_send_space, zfs_secpolicy_read, DATASET_NAME,
+ zfs_unalias_from, zfs_alias_dsname,
POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE);
zfs_ioctl_register("create", ZFS_IOC_CREATE,
zfs_ioc_create, zfs_secpolicy_create_clone, DATASET_NAME,
+ zfs_unalias_dsname, zfs_alias_dsname,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
zfs_ioctl_register("clone", ZFS_IOC_CLONE,
zfs_ioc_clone, zfs_secpolicy_create_clone, DATASET_NAME,
+ zfs_unalias_origin, zfs_alias_dsname,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
zfs_ioctl_register("remap", ZFS_IOC_REMAP,
@@ -6581,34 +7283,41 @@ zfs_ioctl_init(void)
zfs_ioctl_register("destroy_snaps", ZFS_IOC_DESTROY_SNAPS,
zfs_ioc_destroy_snaps, zfs_secpolicy_destroy_snaps, POOL_NAME,
+ zfs_unalias_snaps, zfs_alias_nvlkeys,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
zfs_ioctl_register("hold", ZFS_IOC_HOLD,
zfs_ioc_hold, zfs_secpolicy_hold, POOL_NAME,
+ zfs_unalias_holds, zfs_alias_nvlkeys,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
zfs_ioctl_register("release", ZFS_IOC_RELEASE,
zfs_ioc_release, zfs_secpolicy_release, POOL_NAME,
+ zfs_unalias_nvlkeys, zfs_alias_nvlkeys,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
zfs_ioctl_register("get_holds", ZFS_IOC_GET_HOLDS,
zfs_ioc_get_holds, zfs_secpolicy_read, DATASET_NAME,
+ zfs_unalias_dsname, zfs_alias_dsname,
POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE);
zfs_ioctl_register("rollback", ZFS_IOC_ROLLBACK,
zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME,
+ zfs_unalias_dsname, zfs_alias_dsname,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_TRUE);
zfs_ioctl_register("bookmark", ZFS_IOC_BOOKMARK,
zfs_ioc_bookmark, zfs_secpolicy_bookmark, POOL_NAME,
+ zfs_unalias_nvl, zfs_alias_nvlkeys,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
zfs_ioctl_register("get_bookmarks", ZFS_IOC_GET_BOOKMARKS,
zfs_ioc_get_bookmarks, zfs_secpolicy_read, DATASET_NAME,
+ zfs_unalias_dsname, zfs_alias_dsname,
POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE);
zfs_ioctl_register("destroy_bookmarks", ZFS_IOC_DESTROY_BOOKMARKS,
zfs_ioc_destroy_bookmarks, zfs_secpolicy_destroy_bookmarks,
- POOL_NAME,
+ POOL_NAME, zfs_unalias_nvlkeys, zfs_alias_nvlkeys,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
zfs_ioctl_register("channel_program", ZFS_IOC_CHANNEL_PROGRAM,
@@ -6650,9 +7359,9 @@ zfs_ioctl_init(void)
/* IOCTLS that use the legacy function signature */
- zfs_ioctl_register_legacy("pool_freeze", ZFS_IOC_POOL_FREEZE,
- zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE,
- POOL_CHECK_READONLY);
+ zfs_ioctl_register_legacy(ZFS_IOC_POOL_FREEZE, zfs_ioc_pool_freeze,
+ zfs_secpolicy_config, NO_NAME, zfs_unalias_poolname,
+ zfs_alias_poolname, B_FALSE, POOL_CHECK_READONLY);
zfs_ioctl_register_pool(ZFS_IOC_POOL_CREATE, zfs_ioc_pool_create,
zfs_secpolicy_config, B_TRUE, POOL_CHECK_NONE);
@@ -6703,9 +7412,9 @@ zfs_ioctl_init(void)
zfs_secpolicy_config, B_FALSE, POOL_CHECK_NONE);
zfs_ioctl_register_pool(ZFS_IOC_POOL_STATS, zfs_ioc_pool_stats,
- zfs_secpolicy_read, B_FALSE, POOL_CHECK_NONE);
+ zfs_secpolicy_read_pool, B_FALSE, POOL_CHECK_NONE);
zfs_ioctl_register_pool(ZFS_IOC_POOL_GET_PROPS, zfs_ioc_pool_get_props,
- zfs_secpolicy_read, B_FALSE, POOL_CHECK_NONE);
+ zfs_secpolicy_read_pool, B_FALSE, POOL_CHECK_NONE);
zfs_ioctl_register_pool(ZFS_IOC_ERROR_LOG, zfs_ioc_error_log,
zfs_secpolicy_inject, B_FALSE, POOL_CHECK_SUSPENDED);
@@ -6724,8 +7433,10 @@ zfs_ioctl_init(void)
zfs_ioctl_register_pool(ZFS_IOC_POOL_REOPEN, zfs_ioc_pool_reopen,
zfs_secpolicy_config, B_TRUE, POOL_CHECK_SUSPENDED);
- zfs_ioctl_register_dataset_read(ZFS_IOC_SPACE_WRITTEN,
- zfs_ioc_space_written);
+ zfs_ioctl_register_legacy(ZFS_IOC_SPACE_WRITTEN,
+ zfs_ioc_space_written, zfs_secpolicy_read, DATASET_NAME,
+ zfs_unalias_value, zfs_alias_value, B_FALSE,
+ POOL_CHECK_SUSPENDED);
zfs_ioctl_register_dataset_read(ZFS_IOC_OBJSET_RECVD_PROPS,
zfs_ioc_objset_recvd_props);
zfs_ioctl_register_dataset_read(ZFS_IOC_NEXT_OBJ,
@@ -6743,8 +7454,10 @@ zfs_ioctl_init(void)
zfs_ioctl_register_dataset_read(ZFS_IOC_SEND_PROGRESS,
zfs_ioc_send_progress);
- zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_DIFF,
- zfs_ioc_diff, zfs_secpolicy_diff);
+ zfs_ioctl_register_legacy(ZFS_IOC_DIFF,
+ zfs_ioc_diff, zfs_secpolicy_diff, DATASET_NAME,
+ zfs_unalias_value, zfs_alias_value, B_FALSE,
+ POOL_CHECK_SUSPENDED);
zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_OBJ_TO_STATS,
zfs_ioc_obj_to_stats, zfs_secpolicy_diff);
zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_OBJ_TO_PATH,
@@ -6756,17 +7469,23 @@ zfs_ioctl_init(void)
zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_SEND,
zfs_ioc_send, zfs_secpolicy_send);
- zfs_ioctl_register_dataset_modify("set_prop", ZFS_IOC_SET_PROP,
- zfs_ioc_set_prop, zfs_secpolicy_none);
- zfs_ioctl_register_dataset_modify("destroy", ZFS_IOC_DESTROY,
- zfs_ioc_destroy, zfs_secpolicy_destroy);
- zfs_ioctl_register_dataset_modify("rename", ZFS_IOC_RENAME,
- zfs_ioc_rename, zfs_secpolicy_rename);
- zfs_ioctl_register_dataset_modify("recv", ZFS_IOC_RECV, zfs_ioc_recv,
- zfs_secpolicy_recv);
- zfs_ioctl_register_dataset_modify("promote", ZFS_IOC_PROMOTE,
- zfs_ioc_promote, zfs_secpolicy_promote);
- zfs_ioctl_register_dataset_modify("inherit_prop", ZFS_IOC_INHERIT_PROP,
+ zfs_ioctl_register_dataset_modify(ZFS_IOC_SET_PROP, zfs_ioc_set_prop,
+ zfs_secpolicy_none);
+ zfs_ioctl_register_dataset_modify(ZFS_IOC_DESTROY, zfs_ioc_destroy,
+ zfs_secpolicy_destroy);
+ zfs_ioctl_register_legacy(ZFS_IOC_RENAME, zfs_ioc_rename,
+ zfs_secpolicy_rename, DATASET_NAME,
+ zfs_unalias_value, zfs_alias_value,
+ B_TRUE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY);
+ zfs_ioctl_register_legacy(ZFS_IOC_RECV, zfs_ioc_recv,
+ zfs_secpolicy_recv, DATASET_NAME,
+ zfs_unalias_value, zfs_alias_value,
+ B_TRUE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY);
+ zfs_ioctl_register_legacy(ZFS_IOC_PROMOTE, zfs_ioc_promote,
+ zfs_secpolicy_promote, DATASET_NAME,
+ zfs_unalias_value, zfs_alias_string_value,
+ B_TRUE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY);
+ zfs_ioctl_register_dataset_modify(ZFS_IOC_INHERIT_PROP,
zfs_ioc_inherit_prop, zfs_secpolicy_inherit_prop);
zfs_ioctl_register_dataset_modify("set_fsacl", ZFS_IOC_SET_FSACL,
zfs_ioc_set_fsacl, zfs_secpolicy_set_fsacl);
@@ -6952,11 +7671,22 @@ zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
goto out;
}
+ /* Make certain zc_name is NULL-terminated. */
+ zc->zc_name[sizeof (zc->zc_name) - 1] = '\0';
+
/*
- * Ensure that all pool/dataset names are valid before we pass down to
- * the lower layers.
+ * Non-global zones can have dataset aliases which need to be applied
+ * before we pass down to lower layers.
+ */
+ if (!INGLOBALZONE(curproc)) {
+ error = (*vec->zvec_unalias)(zc, &innvl, cr);
+ if (error != 0)
+ goto out;
+ }
+
+ /*
+ * Ensure that all pool/dataset names are valid.
*/
- zc->zc_name[sizeof (zc->zc_name) - 1] = '\0';
switch (vec->zvec_namecheck) {
case POOL_NAME:
if (pool_namecheck(zc->zc_name, NULL, NULL) != 0)
@@ -7037,6 +7767,14 @@ zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
}
fnvlist_free(lognv);
+ /*
+ * Successful return in non-global zone: alias anything in the
+ * zc or outnvl that we need to before smush + copyout.
+ */
+ if (error == 0 && !INGLOBALZONE(curproc)) {
+ error = (*vec->zvec_alias)(zc, &innvl, &outnvl, cr);
+ }
+
if (!nvlist_empty(outnvl) || zc->zc_nvlist_dst_size != 0) {
int smusherror = 0;
if (vec->zvec_smush_outnvlist) {
@@ -7078,6 +7816,16 @@ zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
fnvlist_free(lognv);
kmem_free(msg, len);
}
+
+ /*
+ * On successful returns to a non-global zone, make sure any
+ * necessary un-aliasing we applied earlier to zc_name is
+ * returned to the way it was before.
+ */
+ if (error == 0 && !INGLOBALZONE(curproc)) {
+ nvlist_t *outnvl = NULL;
+ error = (*vec->zvec_alias)(zc, &innvl, &outnvl, cr);
+ }
}
out:
diff --git a/usr/src/uts/common/fs/zfs/zfs_vfsops.c b/usr/src/uts/common/fs/zfs/zfs_vfsops.c
index 6b61cd7a84..3711f906e1 100644
--- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c
+++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c
@@ -1819,6 +1819,7 @@ out:
static int
zfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
{
+ boolean_t free_osname = B_FALSE;
char *osname;
pathname_t spn;
int error = 0;
@@ -1853,7 +1854,23 @@ zfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
if (error = pn_get(uap->spec, fromspace, &spn))
return (error);
- osname = spn.pn_path;
+
+ /*
+ * Non-global zones can be configured to know a delegated dataset by
+ * an alias, rather than the full objset name.
+ */
+ if (!INGLOBALZONE(curproc)) {
+ free_osname = B_TRUE;
+ osname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+
+ if (zone_dataset_unalias(spn.pn_path, osname,
+ MAXPATHLEN) != 0) {
+ error = SET_ERROR(EINVAL);
+ goto out;
+ }
+ } else {
+ osname = spn.pn_path;
+ }
/*
* Check for mount privilege?
@@ -1891,8 +1908,8 @@ zfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
* Refuse to mount a filesystem if we are in a local zone and the
* dataset is not visible.
*/
- if (!INGLOBALZONE(curproc) &&
- (!zone_dataset_visible(osname, &canwrite) || !canwrite)) {
+ if (!INGLOBALZONE(curproc) && (!zone_dataset_visible(osname,
+ &canwrite, B_FALSE) || !canwrite)) {
error = SET_ERROR(EPERM);
goto out;
}
@@ -1922,6 +1939,9 @@ zfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
VFS_HOLD(mvp->v_vfsp);
out:
+ if (free_osname) {
+ kmem_free(osname, MAXPATHLEN);
+ }
pn_free(&spn);
return (error);
}
diff --git a/usr/src/uts/common/fs/zfs/zvol.c b/usr/src/uts/common/fs/zfs/zvol.c
index 3ed5977c20..742a0b9c40 100644
--- a/usr/src/uts/common/fs/zfs/zvol.c
+++ b/usr/src/uts/common/fs/zfs/zvol.c
@@ -475,9 +475,19 @@ zil_replay_func_t *zvol_replay_vector[TX_MAX_TYPE] = {
};
int
-zvol_name2minor(const char *name, minor_t *minor)
+zvol_name2minor(const char *iname, minor_t *minor)
{
zvol_state_t *zv;
+ int error;
+ const char *name = iname;
+ char namebuf[MAXPATHLEN];
+
+ if (!INGLOBALZONE(curproc)) {
+ error = zone_dataset_unalias(iname, namebuf, MAXPATHLEN);
+ if (error != 0)
+ return (error);
+ name = namebuf;
+ }
mutex_enter(&zfsdev_state_lock);
zv = zvol_minor_lookup(name);
@@ -491,8 +501,9 @@ zvol_name2minor(const char *name, minor_t *minor)
* Create a minor node (plus a whole lot more) for the specified volume.
*/
int
-zvol_create_minor(const char *name)
+zvol_create_minor(const char *iname)
{
+
zfs_soft_state_t *zs;
zvol_state_t *zv;
objset_t *os;
@@ -500,6 +511,15 @@ zvol_create_minor(const char *name)
minor_t minor = 0;
char chrbuf[30], blkbuf[30];
int error;
+ char namebuf[MAXPATHLEN];
+ const char *name = iname;
+
+ if (!INGLOBALZONE(curproc)) {
+ error = zone_dataset_unalias(iname, namebuf, MAXPATHLEN);
+ if (error != 0)
+ return (error);
+ name = namebuf;
+ }
mutex_enter(&zfsdev_state_lock);
diff --git a/usr/src/uts/common/os/zone.c b/usr/src/uts/common/os/zone.c
index fa841df9ff..8293ff6ea3 100644
--- a/usr/src/uts/common/os/zone.c
+++ b/usr/src/uts/common/os/zone.c
@@ -1378,6 +1378,9 @@ zone_free_datasets(zone_t *zone)
next = list_next(&zone->zone_datasets, t);
list_remove(&zone->zone_datasets, t);
kmem_free(t->zd_dataset, strlen(t->zd_dataset) + 1);
+ if (t->zd_alias != NULL) {
+ kmem_free(t->zd_alias, strlen(t->zd_alias) + 1);
+ }
kmem_free(t, sizeof (*t));
}
list_destroy(&zone->zone_datasets);
@@ -4985,15 +4988,67 @@ zone_set_label(zone_t *zone, const bslabel_t *lab, uint32_t doi)
}
/*
- * Parses a comma-separated list of ZFS datasets into a per-zone dictionary.
+ * Check for a valid ZFS dataset name. This function mirrors the rules
+ * for ZFS dataset names checked by "dataset_namecheck()".
+ */
+
+static boolean_t
+parse_zfs_valid_char(char c)
+{
+ return ((c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') ||
+ c == '-' || c == '_' || c == '.' || c == ':' || c == ' ');
+}
+
+static void
+parse_zfs_insert(zone_t *zone, const char *dataset, size_t dataset_len,
+ const char *alias, size_t alias_len)
+{
+ zone_dataset_t *zd = kmem_zalloc(sizeof (zone_dataset_t), KM_SLEEP);
+
+ VERIFY(dataset != NULL);
+ VERIFY(dataset_len > 0);
+ zd->zd_dataset = kmem_alloc(dataset_len + 1, KM_SLEEP);
+ bcopy(dataset, zd->zd_dataset, dataset_len);
+ zd->zd_dataset[dataset_len] = '\0';
+
+ if (alias != NULL) {
+ VERIFY(alias_len > 0);
+ zd->zd_alias = kmem_alloc(alias_len + 1, KM_SLEEP);
+ bcopy(alias, zd->zd_alias, alias_len);
+ zd->zd_alias[alias_len] = '\0';
+ } else {
+ VERIFY(alias_len == 0);
+ }
+
+ list_insert_head(&zone->zone_datasets, zd);
+}
+
+/*
+ * Parses a list of ZFS datasets into a per-zone dictionary. Each dataset
+ * in the list is separated by a comma. If a dataset should be known by
+ * an alias from within the zone, that alias is specified after a pipe.
+ * The alias must be a valid dataset name with exactly one component.
+ * A trailing comma at the end of the list is allowed.
+ *
+ * For example:
+ *
+ * Without any aliases: "one,two/a/b/c,three"
+ * With an alias: "long/dataset/name|tank,another,athird"
*/
static int
parse_zfs(zone_t *zone, caddr_t ubuf, size_t buflen)
{
+ int ret = 0;
char *kbuf;
- char *dataset, *next;
- zone_dataset_t *zd;
- size_t len;
+ enum parse_zfs_state {
+ PZS_REST,
+ PZS_DATASET,
+ PZS_ALIAS
+ } pzs = PZS_REST;
+ const char *dataset = NULL, *alias = NULL;
+ size_t dataset_len = 0, alias_len = 0;
if (ubuf == NULL || buflen == 0)
return (0);
@@ -5006,31 +5061,127 @@ parse_zfs(zone_t *zone, caddr_t ubuf, size_t buflen)
return (EFAULT);
}
- dataset = next = kbuf;
- for (;;) {
- zd = kmem_alloc(sizeof (zone_dataset_t), KM_SLEEP);
+ for (size_t i = 0; i < buflen; i++) {
+ char c = kbuf[i];
- next = strchr(dataset, ',');
+ switch (pzs) {
+ case PZS_REST:
+ if (c == '\0') {
+ goto out;
- if (next == NULL)
- len = strlen(dataset);
- else
- len = next - dataset;
+ } else if (parse_zfs_valid_char(c)) {
+ /*
+ * This is the beginning of a valid dataset
+ * name.
+ */
+ dataset = &kbuf[i];
+ dataset_len = 1;
+ alias = NULL;
+ alias_len = 0;
+ pzs = PZS_DATASET;
+
+ } else if (c != ',') {
+ /*
+ * A trailing comma is allowed.
+ */
+ ret = EINVAL;
+ goto out;
+ }
+ break;
- zd->zd_dataset = kmem_alloc(len + 1, KM_SLEEP);
- bcopy(dataset, zd->zd_dataset, len);
- zd->zd_dataset[len] = '\0';
+ case PZS_DATASET:
+ if (c == '\0' || c == ',') {
+ /*
+ * End of dataset name, without an alias.
+ * Commit to dictionary.
+ */
+ parse_zfs_insert(zone, dataset, dataset_len,
+ alias, alias_len);
- list_insert_head(&zone->zone_datasets, zd);
+ pzs = PZS_REST;
+ if (c == '\0') {
+ goto out;
+ }
+
+ } else if (c == '|') {
+ /*
+ * The pipe separates this dataset name from
+ * its alias name.
+ */
+ pzs = PZS_ALIAS;
- if (next == NULL)
+ } else if (parse_zfs_valid_char(c) || c == '/') {
+ /*
+ * The slash ('/') character is allowed within
+ * a dataset name, but not an alias name,
+ * so we mention it explicitly here.
+ */
+ dataset_len++;
+
+ } else {
+ ret = EINVAL;
+ goto out;
+ }
+ break;
+
+ case PZS_ALIAS:
+ if (c == '\0' || c == ',') {
+ if (alias == NULL) {
+ /*
+ * If there was an alias separator,
+ * there must then be an alias string.
+ */
+ ret = EINVAL;
+ goto out;
+ }
+
+ /*
+ * End of dataset name with an alias. Commit
+ * to dictionary.
+ */
+ parse_zfs_insert(zone, dataset, dataset_len,
+ alias, alias_len);
+
+ pzs = PZS_REST;
+ if (c == '\0') {
+ goto out;
+ }
+
+ } else if (parse_zfs_valid_char(c)) {
+ if (alias == NULL) {
+ alias = &kbuf[i];
+ alias_len = 1;
+ } else {
+ alias_len++;
+ }
+
+ } else {
+ ret = EINVAL;
+ goto out;
+ }
break;
- dataset = next + 1;
+ default:
+ panic("parse_zfs(): unexpected state");
+ }
+ }
+
+out:
+ if (ret == 0) {
+ if ((pzs == PZS_ALIAS && alias != NULL) ||
+ pzs == PZS_DATASET) {
+ parse_zfs_insert(zone, dataset, dataset_len,
+ alias, alias_len);
+ } else if (pzs != PZS_REST) {
+ /*
+ * The string ended unexpectedly.
+ */
+ ret = EINVAL;
+ }
}
kmem_free(kbuf, buflen);
- return (0);
+ return (ret);
}
/*
@@ -7542,11 +7693,157 @@ zone_shutdown_global(void)
}
/*
+ * Gets the un-aliased system name for an aliased dataset within a zone.
+ *
+ * Returns 0 upon success and fills out the provided 'dataset' buffer.
+ */
+int
+zone_dataset_unalias_inzone(const char *alias, char *dataset, size_t sz,
+ zone_t *zone)
+{
+ zone_dataset_t *zd;
+ size_t len, alen;
+ boolean_t found = B_FALSE;
+ char *suffix;
+ const char *asuffix;
+
+ VERIFY(alias != NULL);
+ VERIFY(dataset != NULL);
+
+ if (alias[0] == '\0') {
+ dataset[0] = '\0';
+ return (0);
+ }
+
+ /*
+ * Walk the list once, looking for datasets which match exactly, or
+ * specify a dataset underneath an exported dataset. If found, exit
+ * the loop after unsetting 'ret', so we can process it further.
+ */
+ for (zd = list_head(&zone->zone_datasets); zd != NULL;
+ zd = list_next(&zone->zone_datasets, zd)) {
+ if (zd->zd_alias == NULL)
+ continue;
+
+ alen = strlen(zd->zd_alias);
+ if (strlen(alias) >= alen &&
+ bcmp(alias, zd->zd_alias, alen) == 0 &&
+ (alias[alen] == '\0' || alias[alen] == '/' ||
+ alias[alen] == '@' || alias[alen] == '#')) {
+ found = B_TRUE;
+ break;
+ }
+ }
+
+ /*
+ * If we didn't find any zone_dataset_t that matched, assume the
+ * dataset's system name is the same as the name the zone used
+ * (ie, assume no aliasing is in effect).
+ */
+ if (found == B_FALSE) {
+ len = strlen(alias);
+ if (len >= sz - 1)
+ return (ENOSPC);
+ bcopy(alias, dataset, len);
+ dataset[len] = '\0';
+ return (0);
+ }
+
+ /* If aliased: place dataset name, then suffix in buffer. */
+ len = strlen(zd->zd_dataset);
+ asuffix = &alias[alen];
+ if (strlen(asuffix) + len >= sz - 1)
+ return (ENOSPC);
+ bcopy(zd->zd_dataset, dataset, len);
+ suffix = &dataset[len];
+ (void) strcpy(suffix, asuffix);
+
+ return (0);
+}
+
+int
+zone_dataset_unalias(const char *alias, char *dataset, size_t sz)
+{
+ return (zone_dataset_unalias_inzone(alias, dataset, sz, curzone));
+}
+
+/*
+ * Gets the aliased name for a dataset within a zone.
+ *
+ * Returns 0 upon success and fills out the provided 'alias' buffer.
+ */
+int
+zone_dataset_alias_inzone(const char *dataset, char *alias, size_t sz,
+ zone_t *zone)
+{
+ zone_dataset_t *zd;
+ size_t len, alen;
+ boolean_t found = B_FALSE;
+ const char *suffix;
+ char *asuffix;
+
+ VERIFY(alias != NULL);
+ VERIFY(dataset != NULL);
+
+ if (dataset[0] == '\0') {
+ alias[0] = '\0';
+ return (0);
+ }
+
+ /*
+ * Walk the list once, looking for datasets which match exactly, or
+ * specify a dataset underneath an exported dataset. If found, exit
+ * the loop after unsetting 'ret', so we can process it further.
+ */
+ for (zd = list_head(&zone->zone_datasets); zd != NULL;
+ zd = list_next(&zone->zone_datasets, zd)) {
+ len = strlen(zd->zd_dataset);
+ if (strlen(dataset) >= len &&
+ bcmp(dataset, zd->zd_dataset, len) == 0 &&
+ (dataset[len] == '\0' || dataset[len] == '/' ||
+ dataset[len] == '@' || dataset[len] == '#')) {
+ found = B_TRUE;
+ break;
+ }
+ }
+
+ if (found == B_FALSE)
+ return (EINVAL);
+
+ if (zd->zd_alias == NULL) {
+ /* Simple case: just copy the whole name. */
+ alen = strlen(dataset);
+ if (alen >= sz - 1)
+ return (ENOSPC);
+ bcopy(dataset, alias, alen);
+ alias[alen] = '\0';
+ } else {
+ /* If aliased: place alias, then suffix in buffer. */
+ alen = strlen(zd->zd_alias);
+ suffix = &dataset[len];
+ if (strlen(suffix) + alen >= sz - 1)
+ return (ENOSPC);
+ bcopy(zd->zd_alias, alias, alen);
+ asuffix = &alias[alen];
+ (void) strcpy(asuffix, suffix);
+ }
+
+ return (0);
+}
+
+int
+zone_dataset_alias(const char *dataset, char *alias, size_t sz)
+{
+ return (zone_dataset_alias_inzone(dataset, alias, sz, curzone));
+}
+
+/*
* Returns true if the named dataset is visible in the specified zone.
* The 'write' parameter is set to 1 if the dataset is also writable.
*/
int
-zone_dataset_visible_inzone(zone_t *zone, const char *dataset, int *write)
+zone_dataset_visible_inzone(zone_t *zone, const char *dataset, int *write,
+ boolean_t with_aliased_parents)
{
static int zfstype = -1;
zone_dataset_t *zd;
@@ -7564,7 +7861,6 @@ zone_dataset_visible_inzone(zone_t *zone, const char *dataset, int *write)
*/
for (zd = list_head(&zone->zone_datasets); zd != NULL;
zd = list_next(&zone->zone_datasets, zd)) {
-
len = strlen(zd->zd_dataset);
if (strlen(dataset) >= len &&
bcmp(dataset, zd->zd_dataset, len) == 0 &&
@@ -7586,6 +7882,14 @@ zone_dataset_visible_inzone(zone_t *zone, const char *dataset, int *write)
for (zd = list_head(&zone->zone_datasets); zd != NULL;
zd = list_next(&zone->zone_datasets, zd)) {
+ if (!with_aliased_parents && zd->zd_alias != NULL) {
+ /*
+ * Ignore parent datasets when the exported dataset
+ * has an alias.
+ */
+ continue;
+ }
+
len = strlen(dataset);
if (dataset[len - 1] == '/')
len--; /* Ignore trailing slash */
@@ -7660,11 +7964,13 @@ zone_dataset_visible_inzone(zone_t *zone, const char *dataset, int *write)
* The 'write' parameter is set to 1 if the dataset is also writable.
*/
int
-zone_dataset_visible(const char *dataset, int *write)
+zone_dataset_visible(const char *dataset, int *write,
+ boolean_t with_aliased_parents)
{
zone_t *zone = curproc->p_zone;
- return (zone_dataset_visible_inzone(zone, dataset, write));
+ return (zone_dataset_visible_inzone(zone, dataset, write,
+ with_aliased_parents));
}
/*
diff --git a/usr/src/uts/common/sys/nvpair.h b/usr/src/uts/common/sys/nvpair.h
index cf3f761c8c..80a2a47400 100644
--- a/usr/src/uts/common/sys/nvpair.h
+++ b/usr/src/uts/common/sys/nvpair.h
@@ -169,6 +169,9 @@ int nvlist_xdup(nvlist_t *, nvlist_t **, nv_alloc_t *);
nv_alloc_t *nvlist_lookup_nv_alloc(nvlist_t *);
int nvlist_add_nvpair(nvlist_t *, nvpair_t *);
+#if defined(_KERNEL)
+int nvlist_add_named_nvpair(nvlist_t *, const char *, nvpair_t *);
+#endif
int nvlist_add_boolean(nvlist_t *, const char *);
int nvlist_add_boolean_value(nvlist_t *, const char *, boolean_t);
int nvlist_add_byte(nvlist_t *, const char *, uchar_t);
diff --git a/usr/src/uts/common/sys/zone.h b/usr/src/uts/common/sys/zone.h
index f6bfe6626d..11d85b2865 100644
--- a/usr/src/uts/common/sys/zone.h
+++ b/usr/src/uts/common/sys/zone.h
@@ -412,6 +412,7 @@ typedef struct zone_ref {
*/
typedef struct zone_dataset {
char *zd_dataset;
+ char *zd_alias;
list_node_t zd_linkage;
} zone_dataset_t;
@@ -1015,8 +1016,18 @@ extern int zone_ncpus_online_get(zone_t *);
/*
* Returns true if the named pool/dataset is visible in the current zone.
*/
-extern int zone_dataset_visible(const char *, int *);
-extern int zone_dataset_visible_inzone(zone_t *, const char *, int *);
+extern int zone_dataset_visible(const char *, int *, boolean_t);
+extern int zone_dataset_visible_inzone(zone_t *, const char *, int *,
+ boolean_t);
+
+/*
+ * Used to convert between a zone's local alias name for a dataset and
+ * the system's name.
+ */
+extern int zone_dataset_alias(const char *, char *, size_t);
+extern int zone_dataset_unalias(const char *, char *, size_t);
+extern int zone_dataset_alias_inzone(const char *, char *, size_t, zone_t *);
+extern int zone_dataset_unalias_inzone(const char *, char *, size_t, zone_t *);
/*
* zone version of kadmin()