diff options
Diffstat (limited to 'usr/src/cmd/zonecfg/zonecfg.c')
| -rw-r--r-- | usr/src/cmd/zonecfg/zonecfg.c | 1505 |
1 files changed, 1441 insertions, 64 deletions
diff --git a/usr/src/cmd/zonecfg/zonecfg.c b/usr/src/cmd/zonecfg/zonecfg.c index ea745cbb61..34d6b99480 100644 --- a/usr/src/cmd/zonecfg/zonecfg.c +++ b/usr/src/cmd/zonecfg/zonecfg.c @@ -101,6 +101,8 @@ extern int lex_lineno; #define MAX_CMD_HIST 1024 #define MAX_CMD_LEN 1024 +#define ONE_MB 1048576 + /* * Each SHELP_ should be a simple string. */ @@ -108,6 +110,7 @@ extern int lex_lineno; #define SHELP_ADD "add <resource-type>\n\t(global scope)\n" \ "add <property-name> <property-value>\n\t(resource scope)" #define SHELP_CANCEL "cancel" +#define SHELP_CLEAR "clear <property-name>" #define SHELP_COMMIT "commit" #define SHELP_CREATE "create [-F] [ -a <path> | -b | -t <template> ]" #define SHELP_DELETE "delete [-F]" @@ -116,9 +119,11 @@ extern int lex_lineno; #define SHELP_EXPORT "export [-f output-file]" #define SHELP_HELP "help [commands] [syntax] [usage] [<command-name>]" #define SHELP_INFO "info [<resource-type> [property-name=property-value]*]" -#define SHELP_REMOVE "remove <resource-type> { <property-name>=<property-" \ - "value> }\n\t(global scope)\nremove <property-name> <property-value>" \ - "\n\t(resource scope)" +#define SHELP_REMOVE "remove [-F] <resource-type> " \ + "[ <property-name>=<property-value> ]*\n" \ + "\t(global scope)\n" \ + "remove <property-name> <property-value>\n" \ + "\t(resource scope)" #define SHELP_REVERT "revert [-F]" #define SHELP_SELECT "select <resource-type> { <property-name>=" \ "<property-value> }" @@ -128,6 +133,7 @@ extern int lex_lineno; static struct help helptab[] = { { CMD_ADD, "add", HELP_RES_PROPS, SHELP_ADD, }, { CMD_CANCEL, "cancel", 0, SHELP_CANCEL, }, + { CMD_CLEAR, "clear", HELP_PROPS, SHELP_CLEAR, }, { CMD_COMMIT, "commit", 0, SHELP_COMMIT, }, { CMD_CREATE, "create", 0, SHELP_CREATE, }, { CMD_DELETE, "delete", 0, SHELP_DELETE, }, @@ -163,6 +169,15 @@ static char *res_types[] = { "limitpriv", "bootargs", "brand", + "dedicated-cpu", + "capped-memory", + ALIAS_MAXLWPS, + ALIAS_MAXSHMMEM, + ALIAS_MAXSHMIDS, + ALIAS_MAXMSGIDS, + ALIAS_MAXSEMIDS, + ALIAS_SHARES, + "scheduling-class", NULL }; @@ -189,6 +204,19 @@ static char *prop_types[] = { "limitpriv", "bootargs", "brand", + "ncpus", + "importance", + "swap", + "locked", + ALIAS_SHARES, + ALIAS_MAXLWPS, + ALIAS_MAXSHMMEM, + ALIAS_MAXSHMIDS, + ALIAS_MAXMSGIDS, + ALIAS_MAXSEMIDS, + ALIAS_MAXLOCKEDMEM, + ALIAS_MAXSWAP, + "scheduling-class", NULL }; @@ -205,11 +233,12 @@ static char *prop_val_types[] = { /* * remove has a space afterwards because it has qualifiers; the other commands - * that have qualifiers (add, select and set) don't need a space here because + * that have qualifiers (add, select, etc.) don't need a space here because * they have their own _cmds[] lists below. */ static const char *global_scope_cmds[] = { "add", + "clear", "commit", "create", "delete", @@ -233,6 +262,23 @@ static const char *add_cmds[] = { "add rctl", "add attr", "add dataset", + "add dedicated-cpu", + "add capped-memory", + NULL +}; + +static const char *clear_cmds[] = { + "clear autoboot", + "clear pool", + "clear limitpriv", + "clear bootargs", + "clear scheduling-class", + "clear " ALIAS_MAXLWPS, + "clear " ALIAS_MAXSHMMEM, + "clear " ALIAS_MAXSHMIDS, + "clear " ALIAS_MAXMSGIDS, + "clear " ALIAS_MAXSEMIDS, + "clear " ALIAS_SHARES, NULL }; @@ -244,6 +290,8 @@ static const char *remove_cmds[] = { "remove rctl ", "remove attr ", "remove dataset ", + "remove dedicated-cpu ", + "remove capped-memory ", NULL }; @@ -255,6 +303,8 @@ static const char *select_cmds[] = { "select rctl ", "select attr ", "select dataset ", + "select dedicated-cpu", + "select capped-memory", NULL }; @@ -266,6 +316,13 @@ static const char *set_cmds[] = { "set pool=", "set limitpriv=", "set bootargs=", + "set scheduling-class=", + "set " ALIAS_MAXLWPS "=", + "set " ALIAS_MAXSHMMEM "=", + "set " ALIAS_MAXSHMIDS "=", + "set " ALIAS_MAXMSGIDS "=", + "set " ALIAS_MAXSEMIDS "=", + "set " ALIAS_SHARES "=", NULL }; @@ -277,12 +334,22 @@ static const char *info_cmds[] = { "info rctl ", "info attr ", "info dataset ", + "info capped-memory", + "info dedicated-cpu", "info zonename", "info zonepath", "info autoboot", "info pool", "info limitpriv", "info bootargs", + "info brand", + "info scheduling-class", + "info max-lwps", + "info max-shm-memory", + "info max-shm-ids", + "info max-msg-ids", + "info max-sem-ids", + "info cpu-shares", NULL }; @@ -298,6 +365,7 @@ static const char *fs_res_scope_cmds[] = { "set raw=", "set special=", "set type=", + "clear raw", NULL }; @@ -366,6 +434,33 @@ static const char *dataset_res_scope_cmds[] = { NULL }; +static const char *pset_res_scope_cmds[] = { + "cancel", + "end", + "exit", + "help", + "info", + "set ncpus=", + "set importance=", + "clear importance", + NULL +}; + +static const char *mcap_res_scope_cmds[] = { + "cancel", + "end", + "exit", + "help", + "info", + "set physical=", + "set swap=", + "set locked=", + "clear physical", + "clear swap", + "clear locked", + NULL +}; + /* Global variables */ /* set early in main(), never modified thereafter, used all over the place */ @@ -406,6 +501,9 @@ static bool got_handle = FALSE; /* initialized in do_interactive(), checked in initialize() */ static bool interactive_mode; +/* set if configuring the global zone */ +static bool global_zone = FALSE; + /* set in main(), checked in multiple places */ static bool read_only_mode; @@ -427,9 +525,13 @@ static struct zone_devtab old_devtab, in_progress_devtab; static struct zone_rctltab old_rctltab, in_progress_rctltab; static struct zone_attrtab old_attrtab, in_progress_attrtab; static struct zone_dstab old_dstab, in_progress_dstab; +static struct zone_psettab old_psettab, in_progress_psettab; +static struct zone_mcaptab old_mcaptab, in_progress_mcaptab; static GetLine *gl; /* The gl_get_line() resource object */ +static void bytes_to_units(char *str, char *buf, int bufsize); + /* Functions begin here */ static bool @@ -469,6 +571,8 @@ CPL_MATCH_FN(cmd_cpl_fn) */ if (strncmp(line, "add ", MAX(MIN(word_end, 4), 1)) == 0) return (add_stuff(cpl, line, add_cmds, word_end)); + if (strncmp(line, "clear ", MAX(MIN(word_end, 6), 2)) == 0) + return (add_stuff(cpl, line, clear_cmds, word_end)); if (strncmp(line, "select ", MAX(MIN(word_end, 7), 3)) == 0) return (add_stuff(cpl, line, select_cmds, word_end)); if (strncmp(line, "set ", MAX(MIN(word_end, 4), 3)) == 0) @@ -494,6 +598,10 @@ CPL_MATCH_FN(cmd_cpl_fn) return (add_stuff(cpl, line, attr_res_scope_cmds, word_end)); case RT_DATASET: return (add_stuff(cpl, line, dataset_res_scope_cmds, word_end)); + case RT_DCPU: + return (add_stuff(cpl, line, pset_res_scope_cmds, word_end)); + case RT_MCAP: + return (add_stuff(cpl, line, mcap_res_scope_cmds, word_end)); } return (0); } @@ -669,9 +777,8 @@ long_help(int cmd_num) "flag can be used to force the\n\taction.")); case CMD_REMOVE: return (gettext("Remove specified resource from " - "configuration. Note that the curly\n\tbraces " - "('{', '}') mean one or more of whatever " - "is between them.")); + "configuration. The -F flag can be used\n\tto " + "force the action.")); case CMD_SELECT: (void) snprintf(line, sizeof (line), gettext("Selects a resource to modify. " @@ -684,6 +791,8 @@ long_help(int cmd_num) return (line); case CMD_SET: return (gettext("Sets property values.")); + case CMD_CLEAR: + return (gettext("Clears property values.")); case CMD_INFO: return (gettext("Displays information about the " "current configuration. If resource\n\ttype is " @@ -870,6 +979,37 @@ usage(bool verbose, uint_t flags) (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), pt_to_str(PT_NAME), gettext("<name>")); break; + case RT_DCPU: + (void) fprintf(fp, gettext("The '%s' resource scope " + "configures the 'pools' facility to dedicate\na " + "subset of the system's processors to this zone " + "while it is running.\n"), + rt_to_str(resource_scope)); + (void) fprintf(fp, gettext("Valid commands:\n")); + (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), + pt_to_str(PT_NCPUS), + gettext("<unsigned integer | range>")); + (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), + pt_to_str(PT_IMPORTANCE), + gettext("<unsigned integer>")); + break; + case RT_MCAP: + (void) fprintf(fp, gettext("The '%s' resource scope is " + "used to set an upper limit (a cap) on the\n" + "amount of physical memory, swap space and locked " + "memory that can be used by\nthis zone.\n"), + rt_to_str(resource_scope)); + (void) fprintf(fp, gettext("Valid commands:\n")); + (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), + pt_to_str(PT_PHYSICAL), + gettext("<qualified unsigned decimal>")); + (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), + pt_to_str(PT_SWAP), + gettext("<qualified unsigned decimal>")); + (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET), + pt_to_str(PT_LOCKED), + gettext("<qualified unsigned decimal>")); + break; } (void) fprintf(fp, gettext("And from any resource scope, you " "can:\n")); @@ -928,11 +1068,12 @@ usage(bool verbose, uint_t flags) } if (flags & HELP_RESOURCES) { (void) fprintf(fp, "<%s> := %s | %s | %s | %s | %s | %s |\n\t" - "%s\n\n", + "%s | %s | %s\n\n", gettext("resource type"), rt_to_str(RT_FS), rt_to_str(RT_IPD), rt_to_str(RT_NET), rt_to_str(RT_DEVICE), rt_to_str(RT_RCTL), rt_to_str(RT_ATTR), - rt_to_str(RT_DATASET)); + rt_to_str(RT_DATASET), rt_to_str(RT_DCPU), + rt_to_str(RT_MCAP)); } if (flags & HELP_PROPS) { (void) fprintf(fp, gettext("For resource type ... there are " @@ -951,6 +1092,20 @@ usage(bool verbose, uint_t flags) pt_to_str(PT_POOL)); (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), pt_to_str(PT_LIMITPRIV)); + (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), + pt_to_str(PT_SCHED)); + (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), + pt_to_str(PT_MAXLWPS)); + (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), + pt_to_str(PT_MAXSHMMEM)); + (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), + pt_to_str(PT_MAXSHMIDS)); + (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), + pt_to_str(PT_MAXMSGIDS)); + (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), + pt_to_str(PT_MAXSEMIDS)); + (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"), + pt_to_str(PT_SHARES)); (void) fprintf(fp, "\t%s\t\t%s, %s, %s, %s\n", rt_to_str(RT_FS), pt_to_str(PT_DIR), pt_to_str(PT_SPECIAL), pt_to_str(PT_RAW), pt_to_str(PT_TYPE), @@ -968,6 +1123,11 @@ usage(bool verbose, uint_t flags) 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%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, %s, %s\n", rt_to_str(RT_MCAP), + pt_to_str(PT_PHYSICAL), pt_to_str(PT_SWAP), + pt_to_str(PT_LOCKED)); } if (need_to_close) (void) pclose(fp); @@ -1040,6 +1200,33 @@ initialize(bool handle_expected) " Unable to continue", zone, brandname); exit(Z_ERR); } + } else if (global_zone && err == Z_NO_ZONE && !got_handle && + !read_only_mode) { + /* + * We implicitly create the global zone config if it + * doesn't exist. + */ + zone_dochandle_t tmphandle; + + if ((tmphandle = zonecfg_init_handle()) == NULL) { + zone_perror(execname, Z_NOMEM, TRUE); + exit(Z_ERR); + } + + err = zonecfg_get_template_handle("SUNWblank", zone, + tmphandle); + + if (err != Z_OK) { + zonecfg_fini_handle(tmphandle); + zone_perror("SUNWblank", err, TRUE); + return (err); + } + + need_to_commit = TRUE; + zonecfg_fini_handle(handle); + handle = tmphandle; + got_handle = TRUE; + } else { zone_perror(zone, err, handle_expected || got_handle); if (err == Z_NO_ZONE && !got_handle && @@ -1373,10 +1560,13 @@ export_func(cmd_t *cmd) struct zone_attrtab attrtab; struct zone_rctltab rctltab; struct zone_dstab dstab; + struct zone_psettab psettab; + struct zone_mcaptab mcaptab; struct zone_rctlvaltab *valptr; int err, arg; char zonepath[MAXPATHLEN], outfile[MAXPATHLEN], pool[MAXNAMELEN]; char bootargs[BOOTARGS_MAX]; + char sched[MAXNAMELEN]; char brand[MAXNAMELEN]; char *limitpriv; FILE *of; @@ -1456,6 +1646,10 @@ export_func(cmd_t *cmd) free(limitpriv); } + if (zonecfg_get_sched_class(handle, sched, sizeof (sched)) == Z_OK && + strlen(sched) > 0) + (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), + pt_to_str(PT_SCHED), sched); if ((err = zonecfg_setipdent(handle)) != Z_OK) { zone_perror(zone, err, FALSE); @@ -1576,6 +1770,33 @@ export_func(cmd_t *cmd) } (void) zonecfg_enddsent(handle); + if (zonecfg_getpsetent(handle, &psettab) == Z_OK) { + (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), + rt_to_str(RT_DCPU)); + if (strcmp(psettab.zone_ncpu_min, psettab.zone_ncpu_max) == 0) + (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), + pt_to_str(PT_NCPUS), psettab.zone_ncpu_max); + else + (void) fprintf(of, "%s %s=%s-%s\n", cmd_to_str(CMD_SET), + pt_to_str(PT_NCPUS), psettab.zone_ncpu_min, + psettab.zone_ncpu_max); + if (psettab.zone_importance[0] != '\0') + (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), + pt_to_str(PT_IMPORTANCE), psettab.zone_importance); + (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); + } + + if (zonecfg_getmcapent(handle, &mcaptab) == Z_OK) { + char buf[128]; + + (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD), + rt_to_str(RT_MCAP)); + bytes_to_units(mcaptab.zone_physmem_cap, buf, sizeof (buf)); + (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET), + pt_to_str(PT_PHYSICAL), buf); + (void) fprintf(of, "%s\n", cmd_to_str(CMD_END)); + } + done: if (need_to_close) (void) fclose(of); @@ -1641,6 +1862,10 @@ static void add_resource(cmd_t *cmd) { int type; + struct zone_psettab tmp_psettab; + struct zone_mcaptab tmp_mcaptab; + uint64_t tmp_mcap; + char pool[MAXNAMELEN]; if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { long_usage(CMD_ADD, TRUE); @@ -1667,6 +1892,12 @@ add_resource(cmd_t *cmd) bzero(&in_progress_devtab, sizeof (in_progress_devtab)); return; case RT_RCTL: + if (global_zone) + zerr(gettext("WARNING: Setting a global zone resource " + "control too low could deny\nservice " + "to even the root user; " + "this could render the system impossible\n" + "to administer. Please use caution.")); bzero(&in_progress_rctltab, sizeof (in_progress_rctltab)); return; case RT_ATTR: @@ -1675,6 +1906,48 @@ add_resource(cmd_t *cmd) case RT_DATASET: bzero(&in_progress_dstab, sizeof (in_progress_dstab)); return; + case RT_DCPU: + /* Make sure there isn't already a cpu-set entry. */ + if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) { + zerr(gettext("The %s resource already exists."), + rt_to_str(RT_DCPU)); + goto bad; + } + + /* Make sure the pool property isn't set. */ + if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK && + strlen(pool) > 0) { + zerr(gettext("The %s property is already set. " + "A persistent pool is incompatible with\nthe %s " + "resource."), + pt_to_str(PT_POOL), rt_to_str(RT_DCPU)); + goto bad; + } + + bzero(&in_progress_psettab, sizeof (in_progress_psettab)); + return; + case RT_MCAP: + /* + * Make sure there isn't already a mem-cap entry or max-swap + * or max-locked rctl. + */ + if (zonecfg_lookup_mcap(handle, &tmp_mcaptab) == Z_OK || + zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp_mcap) + == Z_OK || + zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, + &tmp_mcap) == Z_OK) { + zerr(gettext("The %s resource or a related resource " + "control already exists."), rt_to_str(RT_MCAP)); + goto bad; + } + if (global_zone) + zerr(gettext("WARNING: Setting a global zone memory " + "cap too low could deny\nservice " + "to even the root user; " + "this could render the system impossible\n" + "to administer. Please use caution.")); + bzero(&in_progress_mcaptab, sizeof (in_progress_mcaptab)); + return; default: zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, TRUE); long_usage(CMD_ADD, TRUE); @@ -1871,6 +2144,30 @@ add_property(cmd_t *cmd) } } +static boolean_t +gz_invalid_resource(int type) +{ + return (global_zone && (type == RT_FS || type == RT_IPD || + type == RT_NET || type == RT_DEVICE || type == RT_ATTR || + type == RT_DATASET)); +} + +static boolean_t +gz_invalid_rt_property(int type) +{ + return (global_zone && (type == RT_ZONENAME || type == RT_ZONEPATH || + type == RT_AUTOBOOT || type == RT_LIMITPRIV || + type == RT_BOOTARGS || type == RT_BRAND || type == RT_SCHED)); +} + +static boolean_t +gz_invalid_property(int type) +{ + return (global_zone && (type == PT_ZONENAME || type == PT_ZONEPATH || + type == PT_AUTOBOOT || type == PT_LIMITPRIV || + type == PT_BOOTARGS || type == PT_BRAND || type == PT_SCHED)); +} + void add_func(cmd_t *cmd) { @@ -1900,6 +2197,13 @@ add_func(cmd_t *cmd) if (initialize(TRUE) != Z_OK) return; if (global_scope) { + if (gz_invalid_resource(cmd->cmd_res_type)) { + zerr(gettext("Cannot add a %s resource to the " + "global zone."), rt_to_str(cmd->cmd_res_type)); + saw_error = TRUE; + return; + } + global_scope = FALSE; resource_scope = cmd->cmd_res_type; end_op = CMD_ADD; @@ -2273,26 +2577,85 @@ fill_in_dstab(cmd_t *cmd, struct zone_dstab *dstab, bool fill_in_only) } static void -remove_resource(cmd_t *cmd) +remove_aliased_rctl(int type, char *name) { - int err, type; - struct zone_fstab fstab; - struct zone_nwiftab nwiftab; - struct zone_devtab devtab; - struct zone_attrtab attrtab; - struct zone_rctltab rctltab; - struct zone_dstab dstab; + int err; + uint64_t tmp; - if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { - long_usage(CMD_REMOVE, TRUE); + if ((err = zonecfg_get_aliased_rctl(handle, name, &tmp)) != Z_OK) { + zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type), + zonecfg_strerror(err)); + saw_error = TRUE; return; } + if ((err = zonecfg_rm_aliased_rctl(handle, name)) != Z_OK) { + zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type), + zonecfg_strerror(err)); + saw_error = TRUE; + } else { + need_to_commit = TRUE; + } +} - if (initialize(TRUE) != Z_OK) - return; +static boolean_t +prompt_remove_resource(cmd_t *cmd, char *rsrc) +{ + int num; + int answer; + int arg; + boolean_t force = B_FALSE; + char prompt[128]; + + optind = 0; + while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) { + switch (arg) { + case 'F': + force = B_TRUE; + break; + default: + return (B_FALSE); + } + } + + num = zonecfg_num_resources(handle, rsrc); + + if (num == 0) { + z_cmd_rt_perror(CMD_REMOVE, cmd->cmd_res_type, Z_NO_ENTRY, + TRUE); + return (B_FALSE); + } + if (num > 1 && !force) { + if (!interactive_mode) { + zerr(gettext("There are multiple instances of this " + "resource. Either qualify the resource to\n" + "remove a single instance or use the -F option to " + "remove all instances.")); + saw_error = TRUE; + return (B_FALSE); + } + (void) snprintf(prompt, sizeof (prompt), gettext( + "Are you sure you want to remove ALL '%s' resources"), + rsrc); + answer = ask_yesno(FALSE, prompt); + if (answer == -1) { + zerr(gettext("Resource incomplete.")); + return (B_FALSE); + } + if (answer != 1) + return (B_FALSE); + } + return (B_TRUE); +} + +static void +remove_fs(cmd_t *cmd) +{ + int err; + + /* traditional, qualified fs removal */ + if (cmd->cmd_prop_nv_pairs > 0) { + struct zone_fstab fstab; - switch (type) { - case RT_FS: if ((err = fill_in_fstab(cmd, &fstab, FALSE)) != Z_OK) { z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, TRUE); return; @@ -2303,13 +2666,36 @@ remove_resource(cmd_t *cmd) need_to_commit = TRUE; zonecfg_free_fs_option_list(fstab.zone_fs_options); return; - case RT_IPD: - if (state_atleast(ZONE_STATE_INSTALLED)) { - zerr(gettext("Zone %s already installed; %s %s not " - "allowed."), zone, cmd_to_str(CMD_REMOVE), - rt_to_str(RT_IPD)); - return; - } + } + + /* + * unqualified fs removal. remove all fs's but prompt if more + * than one. + */ + if (!prompt_remove_resource(cmd, "fs")) + return; + + if ((err = zonecfg_del_all_resources(handle, "fs")) != Z_OK) + z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, TRUE); + else + need_to_commit = TRUE; +} + +static void +remove_ipd(cmd_t *cmd) +{ + int err; + + if (state_atleast(ZONE_STATE_INSTALLED)) { + zerr(gettext("Zone %s already installed; %s %s not allowed."), + zone, cmd_to_str(CMD_REMOVE), rt_to_str(RT_IPD)); + return; + } + + /* traditional, qualified ipd removal */ + if (cmd->cmd_prop_nv_pairs > 0) { + struct zone_fstab fstab; + if ((err = fill_in_ipdtab(cmd, &fstab, FALSE)) != Z_OK) { z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, TRUE); return; @@ -2319,7 +2705,31 @@ remove_resource(cmd_t *cmd) else need_to_commit = TRUE; return; - case RT_NET: + } + + /* + * unqualified ipd removal. remove all ipds but prompt if more + * than one. + */ + if (!prompt_remove_resource(cmd, "inherit-pkg-dir")) + return; + + if ((err = zonecfg_del_all_resources(handle, "inherit-pkg-dir")) + != Z_OK) + z_cmd_rt_perror(CMD_REMOVE, RT_IPD, err, TRUE); + else + need_to_commit = TRUE; +} + +static void +remove_net(cmd_t *cmd) +{ + int err; + + /* traditional, qualified net removal */ + if (cmd->cmd_prop_nv_pairs > 0) { + struct zone_nwiftab nwiftab; + if ((err = fill_in_nwiftab(cmd, &nwiftab, FALSE)) != Z_OK) { z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, TRUE); return; @@ -2329,7 +2739,30 @@ remove_resource(cmd_t *cmd) else need_to_commit = TRUE; return; - case RT_DEVICE: + } + + /* + * unqualified net removal. remove all nets but prompt if more + * than one. + */ + if (!prompt_remove_resource(cmd, "net")) + return; + + if ((err = zonecfg_del_all_resources(handle, "net")) != Z_OK) + z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, TRUE); + else + need_to_commit = TRUE; +} + +static void +remove_device(cmd_t *cmd) +{ + int err; + + /* traditional, qualified device removal */ + if (cmd->cmd_prop_nv_pairs > 0) { + struct zone_devtab devtab; + if ((err = fill_in_devtab(cmd, &devtab, FALSE)) != Z_OK) { z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, TRUE); return; @@ -2339,18 +2772,30 @@ remove_resource(cmd_t *cmd) else need_to_commit = TRUE; return; - case RT_RCTL: - if ((err = fill_in_rctltab(cmd, &rctltab, FALSE)) != Z_OK) { - z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, TRUE); - return; - } - if ((err = zonecfg_delete_rctl(handle, &rctltab)) != Z_OK) - z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, TRUE); - else - need_to_commit = TRUE; - zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); + } + + /* + * unqualified device removal. remove all devices but prompt if more + * than one. + */ + if (!prompt_remove_resource(cmd, "device")) return; - case RT_ATTR: + + if ((err = zonecfg_del_all_resources(handle, "device")) != Z_OK) + z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, TRUE); + else + need_to_commit = TRUE; +} + +static void +remove_attr(cmd_t *cmd) +{ + int err; + + /* traditional, qualified attr removal */ + if (cmd->cmd_prop_nv_pairs > 0) { + struct zone_attrtab attrtab; + if ((err = fill_in_attrtab(cmd, &attrtab, FALSE)) != Z_OK) { z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, TRUE); return; @@ -2360,7 +2805,30 @@ remove_resource(cmd_t *cmd) else need_to_commit = TRUE; return; - case RT_DATASET: + } + + /* + * unqualified attr removal. remove all attrs but prompt if more + * than one. + */ + if (!prompt_remove_resource(cmd, "attr")) + return; + + if ((err = zonecfg_del_all_resources(handle, "attr")) != Z_OK) + z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, TRUE); + else + need_to_commit = TRUE; +} + +static void +remove_dataset(cmd_t *cmd) +{ + int err; + + /* traditional, qualified dataset removal */ + if (cmd->cmd_prop_nv_pairs > 0) { + struct zone_dstab dstab; + if ((err = fill_in_dstab(cmd, &dstab, FALSE)) != Z_OK) { z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, TRUE); return; @@ -2370,6 +2838,177 @@ remove_resource(cmd_t *cmd) else need_to_commit = TRUE; return; + } + + /* + * unqualified dataset removal. remove all datasets but prompt if more + * than one. + */ + if (!prompt_remove_resource(cmd, "dataset")) + return; + + if ((err = zonecfg_del_all_resources(handle, "dataset")) != Z_OK) + z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, TRUE); + else + need_to_commit = TRUE; +} + +static void +remove_rctl(cmd_t *cmd) +{ + int err; + + /* traditional, qualified rctl removal */ + if (cmd->cmd_prop_nv_pairs > 0) { + struct zone_rctltab rctltab; + + if ((err = fill_in_rctltab(cmd, &rctltab, FALSE)) != Z_OK) { + z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, TRUE); + return; + } + if ((err = zonecfg_delete_rctl(handle, &rctltab)) != Z_OK) + z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, TRUE); + else + need_to_commit = TRUE; + zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); + return; + } + + /* + * unqualified rctl removal. remove all rctls but prompt if more + * than one. + */ + if (!prompt_remove_resource(cmd, "rctl")) + return; + + if ((err = zonecfg_del_all_resources(handle, "rctl")) != Z_OK) + z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, TRUE); + else + need_to_commit = TRUE; +} + +static void +remove_pset() +{ + int err; + struct zone_psettab psettab; + + if ((err = zonecfg_lookup_pset(handle, &psettab)) != Z_OK) { + z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, TRUE); + return; + } + if ((err = zonecfg_delete_pset(handle)) != Z_OK) + z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, TRUE); + else + need_to_commit = TRUE; +} + +static void +remove_mcap() +{ + int err, res1, res2, res3; + uint64_t tmp; + struct zone_mcaptab mcaptab; + boolean_t revert = B_FALSE; + + res1 = zonecfg_lookup_mcap(handle, &mcaptab); + res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp); + res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &tmp); + + /* if none of these exist, there is no resource to remove */ + if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) { + zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_MCAP), + zonecfg_strerror(Z_NO_RESOURCE_TYPE)); + saw_error = TRUE; + return; + } + if (res1 == Z_OK) { + if ((err = zonecfg_delete_mcap(handle)) != Z_OK) { + z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, TRUE); + revert = B_TRUE; + } else { + need_to_commit = TRUE; + } + } + if (res2 == Z_OK) { + if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXSWAP)) + != Z_OK) { + z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, TRUE); + revert = B_TRUE; + } else { + need_to_commit = TRUE; + } + } + if (res3 == Z_OK) { + if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM)) + != Z_OK) { + z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, TRUE); + revert = B_TRUE; + } else { + need_to_commit = TRUE; + } + } + + if (revert) + need_to_commit = FALSE; +} + +static void +remove_resource(cmd_t *cmd) +{ + int type; + int arg; + + if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { + long_usage(CMD_REMOVE, TRUE); + return; + } + + optind = 0; + while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) { + switch (arg) { + case '?': + longer_usage(CMD_REMOVE); + return; + case 'F': + break; + default: + short_usage(CMD_REMOVE); + return; + } + } + + if (initialize(TRUE) != Z_OK) + return; + + switch (type) { + case RT_FS: + remove_fs(cmd); + return; + case RT_IPD: + remove_ipd(cmd); + return; + case RT_NET: + remove_net(cmd); + return; + case RT_DEVICE: + remove_device(cmd); + return; + case RT_RCTL: + remove_rctl(cmd); + return; + case RT_ATTR: + remove_attr(cmd); + return; + case RT_DATASET: + remove_dataset(cmd); + return; + case RT_DCPU: + remove_pset(); + return; + case RT_MCAP: + remove_mcap(); + return; default: zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, TRUE); long_usage(CMD_REMOVE, TRUE); @@ -2513,16 +3152,175 @@ remove_func(cmd_t *cmd) assert(cmd != NULL); - if (global_scope) + if (global_scope) { + if (gz_invalid_resource(cmd->cmd_res_type)) { + zerr(gettext("%s is not a valid resource for the " + "global zone."), rt_to_str(cmd->cmd_res_type)); + saw_error = TRUE; + return; + } remove_resource(cmd); - else + } else { remove_property(cmd); + } +} + +static void +clear_property(cmd_t *cmd) +{ + int res_type, prop_type; + + res_type = resource_scope; + prop_type = cmd->cmd_res_type; + if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) { + long_usage(CMD_CLEAR, TRUE); + return; + } + + if (initialize(TRUE) != Z_OK) + return; + + switch (res_type) { + case RT_FS: + if (prop_type == PT_RAW) { + in_progress_fstab.zone_fs_raw[0] = '\0'; + need_to_commit = TRUE; + return; + } + break; + case RT_DCPU: + if (prop_type == PT_IMPORTANCE) { + in_progress_psettab.zone_importance[0] = '\0'; + need_to_commit = TRUE; + return; + } + break; + case RT_MCAP: + switch (prop_type) { + case PT_PHYSICAL: + in_progress_mcaptab.zone_physmem_cap[0] = '\0'; + need_to_commit = TRUE; + return; + case PT_SWAP: + remove_aliased_rctl(PT_SWAP, ALIAS_MAXSWAP); + return; + case PT_LOCKED: + remove_aliased_rctl(PT_LOCKED, ALIAS_MAXLOCKEDMEM); + return; + } + break; + default: + break; + } + + zone_perror(pt_to_str(prop_type), Z_CLEAR_DISALLOW, TRUE); +} + +static void +clear_global(cmd_t *cmd) +{ + int err, type; + + if ((type = cmd->cmd_res_type) == RT_UNKNOWN) { + long_usage(CMD_CLEAR, TRUE); + return; + } + + if (initialize(TRUE) != Z_OK) + return; + + switch (type) { + case PT_ZONENAME: + /* FALLTHRU */ + case PT_ZONEPATH: + /* FALLTHRU */ + case PT_BRAND: + zone_perror(pt_to_str(type), Z_CLEAR_DISALLOW, TRUE); + return; + case PT_AUTOBOOT: + /* false is default; we'll treat as equivalent to clearing */ + if ((err = zonecfg_set_autoboot(handle, B_FALSE)) != Z_OK) + z_cmd_rt_perror(CMD_CLEAR, RT_AUTOBOOT, err, TRUE); + else + need_to_commit = TRUE; + return; + case PT_POOL: + if ((err = zonecfg_set_pool(handle, NULL)) != Z_OK) + z_cmd_rt_perror(CMD_CLEAR, RT_POOL, err, TRUE); + else + need_to_commit = TRUE; + return; + case PT_LIMITPRIV: + if ((err = zonecfg_set_limitpriv(handle, NULL)) != Z_OK) + z_cmd_rt_perror(CMD_CLEAR, RT_LIMITPRIV, err, TRUE); + else + need_to_commit = TRUE; + return; + case PT_BOOTARGS: + if ((err = zonecfg_set_bootargs(handle, NULL)) != Z_OK) + z_cmd_rt_perror(CMD_CLEAR, RT_BOOTARGS, err, TRUE); + else + need_to_commit = TRUE; + return; + case PT_SCHED: + if ((err = zonecfg_set_sched(handle, NULL)) != Z_OK) + z_cmd_rt_perror(CMD_CLEAR, RT_SCHED, err, TRUE); + else + need_to_commit = TRUE; + return; + case PT_MAXLWPS: + remove_aliased_rctl(PT_MAXLWPS, ALIAS_MAXLWPS); + return; + case PT_MAXSHMMEM: + remove_aliased_rctl(PT_MAXSHMMEM, ALIAS_MAXSHMMEM); + return; + case PT_MAXSHMIDS: + remove_aliased_rctl(PT_MAXSHMIDS, ALIAS_MAXSHMIDS); + return; + case PT_MAXMSGIDS: + remove_aliased_rctl(PT_MAXMSGIDS, ALIAS_MAXMSGIDS); + return; + case PT_MAXSEMIDS: + remove_aliased_rctl(PT_MAXSEMIDS, ALIAS_MAXSEMIDS); + return; + case PT_SHARES: + remove_aliased_rctl(PT_SHARES, ALIAS_SHARES); + return; + default: + zone_perror(pt_to_str(type), Z_NO_PROPERTY_TYPE, TRUE); + long_usage(CMD_CLEAR, TRUE); + usage(FALSE, HELP_PROPS); + return; + } +} + +void +clear_func(cmd_t *cmd) +{ + if (zone_is_read_only(CMD_CLEAR)) + return; + + assert(cmd != NULL); + + if (global_scope) { + if (gz_invalid_property(cmd->cmd_res_type)) { + zerr(gettext("%s is not a valid property for the " + "global zone."), pt_to_str(cmd->cmd_res_type)); + saw_error = TRUE; + return; + } + + clear_global(cmd); + } else { + clear_property(cmd); + } } void select_func(cmd_t *cmd) { - int type, err; + int type, err, res; + uint64_t limit; if (zone_is_read_only(CMD_SELECT)) return; @@ -2612,6 +3410,32 @@ select_func(cmd_t *cmd) bcopy(&old_dstab, &in_progress_dstab, sizeof (struct zone_dstab)); return; + case RT_DCPU: + if ((err = zonecfg_lookup_pset(handle, &old_psettab)) != Z_OK) { + z_cmd_rt_perror(CMD_SELECT, RT_DCPU, err, TRUE); + global_scope = TRUE; + } + bcopy(&old_psettab, &in_progress_psettab, + sizeof (struct zone_psettab)); + return; + case RT_MCAP: + /* if none of these exist, there is no resource to select */ + if ((res = zonecfg_lookup_mcap(handle, &old_mcaptab)) != Z_OK && + zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &limit) + != Z_OK && + zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &limit) + != Z_OK) { + z_cmd_rt_perror(CMD_SELECT, RT_MCAP, Z_NO_RESOURCE_TYPE, + TRUE); + global_scope = TRUE; + } + if (res == Z_OK) + bcopy(&old_mcaptab, &in_progress_mcaptab, + sizeof (struct zone_mcaptab)); + else + bzero(&in_progress_mcaptab, + sizeof (in_progress_mcaptab)); + return; default: zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, TRUE); long_usage(CMD_SELECT, TRUE); @@ -2731,6 +3555,49 @@ valid_fs_type(const char *type) return (B_TRUE); } +static void +set_aliased_rctl(char *alias, int prop_type, char *s) +{ + uint64_t limit; + int err; + char tmp[128]; + + if (global_zone && strcmp(alias, ALIAS_SHARES) != 0) + zerr(gettext("WARNING: Setting a global zone resource " + "control too low could deny\nservice " + "to even the root user; " + "this could render the system impossible\n" + "to administer. Please use caution.")); + + /* convert memory based properties */ + if (prop_type == PT_MAXSHMMEM) { + if (!zonecfg_valid_memlimit(s, &limit)) { + zerr(gettext("A non-negative number with a required " + "scale suffix (K, M, G or T) was expected\nhere.")); + saw_error = TRUE; + return; + } + + (void) snprintf(tmp, sizeof (tmp), "%llu", limit); + s = tmp; + } + + if (!zonecfg_aliased_rctl_ok(handle, alias)) { + zone_perror(pt_to_str(prop_type), Z_ALIAS_DISALLOW, FALSE); + saw_error = TRUE; + } else if (!zonecfg_valid_alias_limit(alias, s, &limit)) { + zerr(gettext("%s property is out of range."), + pt_to_str(prop_type)); + saw_error = TRUE; + } else if ((err = zonecfg_set_aliased_rctl(handle, alias, limit)) + != Z_OK) { + zone_perror(zone, err, TRUE); + saw_error = TRUE; + } else { + need_to_commit = TRUE; + } +} + void set_func(cmd_t *cmd) { @@ -2739,6 +3606,9 @@ set_func(cmd_t *cmd) property_value_ptr_t pp; boolean_t autoboot; boolean_t force_set = FALSE; + size_t physmem_size = sizeof (in_progress_mcaptab.zone_physmem_cap); + uint64_t mem_cap, mem_limit; + struct zone_psettab tmp_psettab; if (zone_is_read_only(CMD_SET)) return; @@ -2762,6 +3632,13 @@ set_func(cmd_t *cmd) prop_type = cmd->cmd_prop_name[0]; if (global_scope) { + if (gz_invalid_property(prop_type)) { + zerr(gettext("%s is not a valid property for the " + "global zone."), pt_to_str(prop_type)); + saw_error = TRUE; + return; + } + if (prop_type == PT_ZONENAME) { res_type = RT_ZONENAME; } else if (prop_type == PT_ZONEPATH) { @@ -2776,6 +3653,20 @@ set_func(cmd_t *cmd) res_type = RT_LIMITPRIV; } else if (prop_type == PT_BOOTARGS) { res_type = RT_BOOTARGS; + } else if (prop_type == PT_SCHED) { + res_type = RT_SCHED; + } else if (prop_type == PT_MAXLWPS) { + res_type = RT_MAXLWPS; + } else if (prop_type == PT_MAXSHMMEM) { + res_type = RT_MAXSHMMEM; + } else if (prop_type == PT_MAXSHMIDS) { + res_type = RT_MAXSHMIDS; + } else if (prop_type == PT_MAXMSGIDS) { + res_type = RT_MAXMSGIDS; + } else if (prop_type == PT_MAXSEMIDS) { + res_type = RT_MAXSEMIDS; + } else if (prop_type == PT_SHARES) { + res_type = RT_SHARES; } else { zerr(gettext("Cannot set a resource-specific property " "from the global scope.")); @@ -2899,6 +3790,24 @@ set_func(cmd_t *cmd) need_to_commit = TRUE; return; case RT_POOL: + /* don't allow use of the reserved temporary pool names */ + if (strncmp("SUNW", prop_id, 4) == 0) { + zerr(gettext("pool names starting with SUNW are " + "reserved.")); + saw_error = TRUE; + return; + } + + /* can't set pool if dedicated-cpu exists */ + if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) { + zerr(gettext("The %s resource already exists. " + "A persistent pool is incompatible\nwith the %s " + "resource."), rt_to_str(RT_DCPU), + rt_to_str(RT_DCPU)); + saw_error = TRUE; + return; + } + if ((err = zonecfg_set_pool(handle, prop_id)) != Z_OK) zone_perror(zone, err, TRUE); else @@ -2916,6 +3825,30 @@ set_func(cmd_t *cmd) else need_to_commit = TRUE; return; + case RT_SCHED: + if ((err = zonecfg_set_sched(handle, prop_id)) != Z_OK) + zone_perror(zone, err, TRUE); + else + need_to_commit = TRUE; + return; + case RT_MAXLWPS: + set_aliased_rctl(ALIAS_MAXLWPS, prop_type, prop_id); + return; + case RT_MAXSHMMEM: + set_aliased_rctl(ALIAS_MAXSHMMEM, prop_type, prop_id); + return; + case RT_MAXSHMIDS: + set_aliased_rctl(ALIAS_MAXSHMIDS, prop_type, prop_id); + return; + case RT_MAXMSGIDS: + set_aliased_rctl(ALIAS_MAXMSGIDS, prop_type, prop_id); + return; + case RT_MAXSEMIDS: + set_aliased_rctl(ALIAS_MAXSEMIDS, prop_type, prop_id); + return; + case RT_SHARES: + set_aliased_rctl(ALIAS_SHARES, prop_type, prop_id); + return; case RT_FS: switch (prop_type) { case PT_DIR: @@ -3095,6 +4028,146 @@ set_func(cmd_t *cmd) long_usage(CMD_SET, TRUE); usage(FALSE, HELP_PROPS); return; + case RT_DCPU: + switch (prop_type) { + char *lowp, *highp; + + case PT_NCPUS: + lowp = prop_id; + if ((highp = strchr(prop_id, '-')) != NULL) + *highp++ = '\0'; + else + highp = lowp; + + /* Make sure the input makes sense. */ + if (!zonecfg_valid_ncpus(lowp, highp)) { + zerr(gettext("%s property is out of range."), + pt_to_str(PT_NCPUS)); + saw_error = TRUE; + return; + } + + (void) strlcpy( + in_progress_psettab.zone_ncpu_min, lowp, + sizeof (in_progress_psettab.zone_ncpu_min)); + (void) strlcpy( + in_progress_psettab.zone_ncpu_max, highp, + sizeof (in_progress_psettab.zone_ncpu_max)); + return; + case PT_IMPORTANCE: + /* Make sure the value makes sense. */ + if (!zonecfg_valid_importance(prop_id)) { + zerr(gettext("%s property is out of range."), + pt_to_str(PT_IMPORTANCE)); + saw_error = TRUE; + return; + } + + (void) strlcpy(in_progress_psettab.zone_importance, + prop_id, + sizeof (in_progress_psettab.zone_importance)); + return; + default: + break; + } + zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, TRUE); + long_usage(CMD_SET, TRUE); + usage(FALSE, HELP_PROPS); + return; + case RT_MCAP: + switch (prop_type) { + case PT_PHYSICAL: + if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) { + zerr(gettext("A positive number with a " + "required scale suffix (K, M, G or T) was " + "expected here.")); + saw_error = TRUE; + } else if (mem_cap < ONE_MB) { + zerr(gettext("%s value is too small. It must " + "be at least 1M."), pt_to_str(PT_PHYSICAL)); + saw_error = TRUE; + } else { + snprintf(in_progress_mcaptab.zone_physmem_cap, + physmem_size, "%llu", mem_cap); + } + break; + case PT_SWAP: + /* + * We have to check if an rctl is allowed here since + * there might already be a rctl defined that blocks + * the alias. + */ + if (!zonecfg_aliased_rctl_ok(handle, ALIAS_MAXSWAP)) { + zone_perror(pt_to_str(PT_MAXSWAP), + Z_ALIAS_DISALLOW, FALSE); + saw_error = TRUE; + return; + } + + if (global_zone) + mem_limit = ONE_MB * 100; + else + mem_limit = ONE_MB * 50; + + if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) { + zerr(gettext("A positive number with a " + "required scale suffix (K, M, G or T) was " + "expected here.")); + saw_error = TRUE; + } else if (mem_cap < mem_limit) { + char buf[128]; + + (void) snprintf(buf, sizeof (buf), "%llu", + mem_limit); + bytes_to_units(buf, buf, sizeof (buf)); + zerr(gettext("%s value is too small. It must " + "be at least %s."), pt_to_str(PT_SWAP), + buf); + saw_error = TRUE; + } else { + if ((err = zonecfg_set_aliased_rctl(handle, + ALIAS_MAXSWAP, mem_cap)) != Z_OK) + zone_perror(zone, err, TRUE); + else + need_to_commit = TRUE; + } + break; + case PT_LOCKED: + /* + * We have to check if an rctl is allowed here since + * there might already be a rctl defined that blocks + * the alias. + */ + if (!zonecfg_aliased_rctl_ok(handle, + ALIAS_MAXLOCKEDMEM)) { + zone_perror(pt_to_str(PT_LOCKED), + Z_ALIAS_DISALLOW, FALSE); + saw_error = TRUE; + return; + } + + if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) { + zerr(gettext("A non-negative number with a " + "required scale suffix (K, M, G or T) was " + "expected\nhere.")); + saw_error = TRUE; + } else { + if ((err = zonecfg_set_aliased_rctl(handle, + ALIAS_MAXLOCKEDMEM, mem_cap)) != Z_OK) + zone_perror(zone, err, TRUE); + else + need_to_commit = TRUE; + } + break; + default: + zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, + TRUE); + long_usage(CMD_SET, TRUE); + usage(FALSE, HELP_PROPS); + return; + } + + return; default: zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, TRUE); long_usage(CMD_SET, TRUE); @@ -3110,7 +4183,11 @@ output_prop(FILE *fp, int pnum, char *pval, bool print_notspec) if (*pval != '\0') { qstr = quoteit(pval); - (void) fprintf(fp, "\t%s: %s\n", pt_to_str(pnum), qstr); + if (pnum == PT_SWAP || pnum == PT_LOCKED) + (void) fprintf(fp, "\t[%s: %s]\n", pt_to_str(pnum), + qstr); + else + (void) fprintf(fp, "\t%s: %s\n", pt_to_str(pnum), qstr); free(qstr); } else if (print_notspec) (void) fprintf(fp, gettext("\t%s not specified\n"), @@ -3213,6 +4290,20 @@ info_bootargs(zone_dochandle_t handle, FILE *fp) } static void +info_sched(zone_dochandle_t handle, FILE *fp) +{ + char sched[MAXNAMELEN]; + int err; + + if ((err = zonecfg_get_sched_class(handle, sched, sizeof (sched))) + == Z_OK) { + (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_SCHED), sched); + } else { + zone_perror(zone, err, TRUE); + } +} + +static void output_fs(FILE *fp, struct zone_fstab *fstab) { zone_fsopt_t *this; @@ -3499,7 +4590,7 @@ info_ds(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) struct zone_dstab lookup, user; bool output = FALSE; - if (zonecfg_setdevent(handle) != Z_OK) + if (zonecfg_setdsent(handle) != Z_OK) return; while (zonecfg_getdsent(handle, &lookup) == Z_OK) { if (cmd->cmd_prop_nv_pairs == 0) { @@ -3525,12 +4616,132 @@ info_ds(zone_dochandle_t handle, FILE *fp, cmd_t *cmd) rt_to_str(RT_DATASET)); } +static void +output_pset(FILE *fp, struct zone_psettab *psettab) +{ + (void) fprintf(fp, "%s:\n", rt_to_str(RT_DCPU)); + if (strcmp(psettab->zone_ncpu_min, psettab->zone_ncpu_max) == 0) + (void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_NCPUS), + psettab->zone_ncpu_max); + else + (void) fprintf(fp, "\t%s: %s-%s\n", pt_to_str(PT_NCPUS), + psettab->zone_ncpu_min, psettab->zone_ncpu_max); + if (psettab->zone_importance[0] != '\0') + (void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_IMPORTANCE), + psettab->zone_importance); +} + +static void +info_pset(zone_dochandle_t handle, FILE *fp) +{ + struct zone_psettab lookup; + + if (zonecfg_getpsetent(handle, &lookup) == Z_OK) + output_pset(fp, &lookup); +} + +static void +info_aliased_rctl(zone_dochandle_t handle, FILE *fp, char *alias) +{ + uint64_t limit; + + if (zonecfg_get_aliased_rctl(handle, alias, &limit) == Z_OK) { + /* convert memory based properties */ + if (strcmp(alias, ALIAS_MAXSHMMEM) == 0) { + char buf[128]; + + (void) snprintf(buf, sizeof (buf), "%llu", limit); + bytes_to_units(buf, buf, sizeof (buf)); + (void) fprintf(fp, "[%s: %s]\n", alias, buf); + return; + } + + (void) fprintf(fp, "[%s: %llu]\n", alias, limit); + } +} + +static void +bytes_to_units(char *str, char *buf, int bufsize) +{ + unsigned long long num; + unsigned long long save = 0; + char *units = "BKMGT"; + char *up = units; + + num = strtoll(str, NULL, 10); + + if (num < 1024) { + (void) snprintf(buf, bufsize, "%llu", num); + return; + } + + while ((num >= 1024) && (*up != 'T')) { + up++; /* next unit of measurement */ + save = num; + num = (num + 512) >> 10; + } + + /* check if we should output a fraction. snprintf will round for us */ + if (save % 1024 != 0 && ((save >> 10) < 10)) + (void) snprintf(buf, bufsize, "%2.1f%c", ((float)save / 1024), + *up); + else + (void) snprintf(buf, bufsize, "%llu%c", num, *up); +} + +static void +output_mcap(FILE *fp, struct zone_mcaptab *mcaptab, int showswap, + uint64_t maxswap, int showlocked, uint64_t maxlocked) +{ + char buf[128]; + + (void) fprintf(fp, "%s:\n", rt_to_str(RT_MCAP)); + if (mcaptab->zone_physmem_cap[0] != '\0') { + bytes_to_units(mcaptab->zone_physmem_cap, buf, sizeof (buf)); + output_prop(fp, PT_PHYSICAL, buf, B_TRUE); + } + + if (showswap == Z_OK) { + (void) snprintf(buf, sizeof (buf), "%llu", maxswap); + bytes_to_units(buf, buf, sizeof (buf)); + output_prop(fp, PT_SWAP, buf, B_TRUE); + } + + if (showlocked == Z_OK) { + (void) snprintf(buf, sizeof (buf), "%llu", maxlocked); + bytes_to_units(buf, buf, sizeof (buf)); + output_prop(fp, PT_LOCKED, buf, B_TRUE); + } +} + +static void +info_mcap(zone_dochandle_t handle, FILE *fp) +{ + int res1, res2, res3; + uint64_t swap_limit; + uint64_t locked_limit; + struct zone_mcaptab lookup; + + bzero(&lookup, sizeof (lookup)); + res1 = zonecfg_getmcapent(handle, &lookup); + res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &swap_limit); + res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, + &locked_limit); + + if (res1 == Z_OK || res2 == Z_OK || res3 == Z_OK) + output_mcap(fp, &lookup, res2, swap_limit, res3, locked_limit); +} + void info_func(cmd_t *cmd) { FILE *fp = stdout; bool need_to_close = FALSE; char *pager; + int type; + int res1, res2; + uint64_t swap_limit; + uint64_t locked_limit; assert(cmd != NULL); @@ -3569,26 +4780,68 @@ info_func(cmd_t *cmd) case RT_DATASET: output_ds(fp, &in_progress_dstab); break; + case RT_DCPU: + output_pset(fp, &in_progress_psettab); + break; + case RT_MCAP: + res1 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, + &swap_limit); + res2 = zonecfg_get_aliased_rctl(handle, + ALIAS_MAXLOCKEDMEM, &locked_limit); + output_mcap(fp, &in_progress_mcaptab, res1, swap_limit, + res2, locked_limit); + break; } goto cleanup; } + type = cmd->cmd_res_type; + + if (gz_invalid_rt_property(type)) { + zerr(gettext("%s is not a valid property for the global zone."), + rt_to_str(type)); + goto cleanup; + } + + if (gz_invalid_resource(type)) { + zerr(gettext("%s is not a valid resource for the global zone."), + rt_to_str(type)); + goto cleanup; + } + switch (cmd->cmd_res_type) { case RT_UNKNOWN: info_zonename(handle, fp); - info_zonepath(handle, fp); - info_brand(handle, fp); - info_autoboot(handle, fp); - info_bootargs(handle, fp); + if (!global_zone) { + info_zonepath(handle, fp); + info_brand(handle, fp); + info_autoboot(handle, fp); + info_bootargs(handle, fp); + } info_pool(handle, fp); - info_limitpriv(handle, fp); - info_ipd(handle, fp, cmd); - info_fs(handle, fp, cmd); - info_net(handle, fp, cmd); - info_dev(handle, fp, cmd); + if (!global_zone) { + info_limitpriv(handle, fp); + info_sched(handle, fp); + } + info_aliased_rctl(handle, fp, ALIAS_MAXLWPS); + info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM); + info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS); + info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS); + info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS); + info_aliased_rctl(handle, fp, ALIAS_SHARES); + if (!global_zone) { + info_ipd(handle, fp, cmd); + info_fs(handle, fp, cmd); + info_net(handle, fp, cmd); + info_dev(handle, fp, cmd); + } + info_pset(handle, fp); + info_mcap(handle, fp); + if (!global_zone) { + info_attr(handle, fp, cmd); + info_ds(handle, fp, cmd); + } info_rctl(handle, fp, cmd); - info_attr(handle, fp, cmd); - info_ds(handle, fp, cmd); break; case RT_ZONENAME: info_zonename(handle, fp); @@ -3611,6 +4864,27 @@ info_func(cmd_t *cmd) case RT_BOOTARGS: info_bootargs(handle, fp); break; + case RT_SCHED: + info_sched(handle, fp); + break; + case RT_MAXLWPS: + info_aliased_rctl(handle, fp, ALIAS_MAXLWPS); + break; + case RT_MAXSHMMEM: + info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM); + break; + case RT_MAXSHMIDS: + info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS); + break; + case RT_MAXMSGIDS: + info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS); + break; + case RT_MAXSEMIDS: + info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS); + break; + case RT_SHARES: + info_aliased_rctl(handle, fp, ALIAS_SHARES); + break; case RT_FS: info_fs(handle, fp, cmd); break; @@ -3632,6 +4906,12 @@ info_func(cmd_t *cmd) case RT_DATASET: info_ds(handle, fp, cmd); break; + case RT_DCPU: + info_pset(handle, fp); + break; + case RT_MCAP: + info_mcap(handle, fp); + break; default: zone_perror(rt_to_str(cmd->cmd_res_type), Z_NO_RESOURCE_TYPE, TRUE); @@ -3765,10 +5045,13 @@ verify_func(cmd_t *cmd) struct zone_attrtab attrtab; struct zone_rctltab rctltab; struct zone_dstab dstab; + struct zone_psettab psettab; char zonepath[MAXPATHLEN]; + char sched[MAXNAMELEN]; char brand[MAXNAMELEN]; int err, ret_val = Z_OK, arg; bool save = FALSE; + boolean_t has_cpu_shares = B_FALSE; optind = 0; if ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) { @@ -3796,12 +5079,13 @@ verify_func(cmd_t *cmd) if (initialize(TRUE) != Z_OK) return; - if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) != Z_OK) { + if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) != Z_OK && + !global_zone) { zerr(gettext("%s not specified"), pt_to_str(PT_ZONEPATH)); ret_val = Z_REQD_RESOURCE_MISSING; saw_error = TRUE; } - if (strlen(zonepath) == 0) { + if (strlen(zonepath) == 0 && !global_zone) { zerr(gettext("%s cannot be empty."), pt_to_str(PT_ZONEPATH)); ret_val = Z_REQD_RESOURCE_MISSING; saw_error = TRUE; @@ -3861,6 +5145,9 @@ verify_func(cmd_t *cmd) check_reqd_prop(rctltab.zone_rctl_name, RT_RCTL, PT_NAME, &ret_val); + if (strcmp(rctltab.zone_rctl_name, "zone.cpu-shares") == 0) + has_cpu_shares = B_TRUE; + if (rctltab.zone_rctl_valptr == NULL) { zerr(gettext("%s: no %s specified"), rt_to_str(RT_RCTL), pt_to_str(PT_VALUE)); @@ -3873,6 +5160,25 @@ verify_func(cmd_t *cmd) } (void) zonecfg_endrctlent(handle); + if (zonecfg_lookup_pset(handle, &psettab) == Z_OK && has_cpu_shares) { + zerr(gettext("%s zone.cpu-shares and %s are incompatible."), + rt_to_str(RT_RCTL), rt_to_str(RT_DCPU)); + saw_error = TRUE; + if (ret_val == Z_OK) + ret_val = Z_INCOMPATIBLE; + } + + if (has_cpu_shares && zonecfg_get_sched_class(handle, sched, + sizeof (sched)) == Z_OK && strlen(sched) > 0 && + strcmp(sched, "FSS") != 0) { + zerr(gettext("WARNING: %s zone.cpu-shares and %s=%s are " + "incompatible"), + rt_to_str(RT_RCTL), rt_to_str(RT_SCHED), sched); + saw_error = TRUE; + if (ret_val == Z_OK) + ret_val = Z_INCOMPATIBLE; + } + if ((err = zonecfg_setattrent(handle)) != Z_OK) { zone_perror(zone, err, TRUE); return; @@ -4061,7 +5367,9 @@ end_func(cmd_t *cmd) struct zone_rctltab tmp_rctltab; struct zone_attrtab tmp_attrtab; struct zone_dstab tmp_dstab; - int err, arg; + int err, arg, res1, res2, res3; + uint64_t swap_limit; + uint64_t locked_limit; assert(cmd != NULL); @@ -4361,6 +5669,73 @@ end_func(cmd_t *cmd) &in_progress_dstab); } break; + case RT_DCPU: + /* Make sure everything was filled in. */ + if (end_check_reqd(in_progress_psettab.zone_ncpu_min, + PT_NCPUS, &validation_failed) != Z_OK) { + saw_error = TRUE; + return; + } + + if (end_op == CMD_ADD) { + err = zonecfg_add_pset(handle, &in_progress_psettab); + } else { + err = zonecfg_modify_pset(handle, &in_progress_psettab); + } + break; + case RT_MCAP: + /* Make sure everything was filled in. */ + res1 = strlen(in_progress_mcaptab.zone_physmem_cap) == 0 ? + Z_ERR : Z_OK; + res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, + &swap_limit); + res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, + &locked_limit); + + if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) { + zerr(gettext("No property was specified. One of %s, " + "%s or %s is required."), pt_to_str(PT_PHYSICAL), + pt_to_str(PT_SWAP), pt_to_str(PT_LOCKED)); + saw_error = TRUE; + return; + } + + /* if phys & locked are both set, verify locked <= phys */ + if (res1 == Z_OK && res3 == Z_OK) { + uint64_t phys_limit; + char *endp; + + phys_limit = strtoull( + in_progress_mcaptab.zone_physmem_cap, &endp, 10); + if (phys_limit < locked_limit) { + zerr(gettext("The %s cap must be less than or " + "equal to the %s cap."), + pt_to_str(PT_LOCKED), + pt_to_str(PT_PHYSICAL)); + saw_error = TRUE; + return; + } + } + + err = Z_OK; + if (res1 == Z_OK) { + /* + * We could be ending from either an add operation + * or a select operation. Since all of the properties + * within this resource are optional, we always use + * modify on the mcap entry. zonecfg_modify_mcap() + * will handle both adding and modifying a memory cap. + */ + err = zonecfg_modify_mcap(handle, &in_progress_mcaptab); + } else if (end_op == CMD_SELECT) { + /* + * If we're ending from a select and the physical + * memory cap is empty then the user could have cleared + * the physical cap value, so try to delete the entry. + */ + (void) zonecfg_delete_mcap(handle); + } + break; default: zone_perror(rt_to_str(resource_scope), Z_NO_RESOURCE_TYPE, TRUE); @@ -4885,7 +6260,9 @@ main(int argc, char *argv[]) zonecfg_set_root(optarg); break; case 'z': - if (zonecfg_validate_zonename(optarg) != Z_OK) { + if (strcmp(optarg, GLOBAL_ZONENAME) == 0) { + global_zone = TRUE; + } else if (zonecfg_validate_zonename(optarg) != Z_OK) { zone_perror(optarg, Z_BOGUS_ZONE_NAME, TRUE); usage(FALSE, HELP_SYNTAX); exit(Z_USAGE); |
