changeset 13326:70ccb19abd77

719 beadm should allow BEs outside of <rpool>/ROOT Reviewed by: Dan McDonald <danmcd@nexenta.com> Reviewed by: Rich Lowe <richlowe@richlowe.net> Approved by: Garrett D'Amore <garrett@nexenta.com>
author Alexander Eremin <a.eremin@nexenta.com>
date Wed, 06 Apr 2011 07:45:22 -0700
parents ab46f88a2660
children b9e92167922a
files usr/src/lib/libbe/common/be_create.c usr/src/lib/libbe/common/be_list.c usr/src/lib/libbe/common/be_snapshot.c usr/src/lib/libbe/common/be_utils.c usr/src/lib/libbe/common/libbe_priv.h usr/src/man/man1m/beadm.1m
diffstat 6 files changed, 262 insertions(+), 87 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/lib/libbe/common/be_create.c	Tue Apr 05 09:31:14 2011 -0700
+++ b/usr/src/lib/libbe/common/be_create.c	Wed Apr 06 07:45:22 2011 -0700
@@ -24,6 +24,10 @@
  */
 
 /*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
  * System includes
  */
 
@@ -576,17 +580,20 @@
 	be_transaction_data_t	bt = { 0 };
 	be_fs_list_data_t	fld = { 0 };
 	zfs_handle_t	*zhp = NULL;
+	zpool_handle_t	*zphp = NULL;
 	nvlist_t	*zfs_props = NULL;
 	uuid_t		uu = { 0 };
 	char		obe_root_ds[MAXPATHLEN];
 	char		nbe_root_ds[MAXPATHLEN];
 	char		ss[MAXPATHLEN];
 	char		*new_mp = NULL;
+	char		*obe_name = NULL;
 	boolean_t	autoname = B_FALSE;
 	boolean_t	be_created = B_FALSE;
 	int		i;
 	int		zret;
 	int		ret = BE_SUCCESS;
+	struct be_defaults be_defaults;
 
 	/* Initialize libzfs handle */
 	if (!be_zfs_init())
@@ -594,18 +601,21 @@
 
 	/* Get original BE name */
 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
-	    BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &bt.obe_name, NULL) != 0) {
+	    BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &obe_name, NULL) != 0) {
 		be_print_err(gettext("be_copy: failed to lookup "
 		    "BE_ATTR_ORIG_BE_NAME attribute\n"));
 		return (BE_ERR_INVAL);
 	}
 
+	if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
+		return (ret);
+	}
+
+	be_get_defaults(&be_defaults);
+
 	/* If original BE name not provided, use current BE */
-	if (bt.obe_name == NULL) {
-		if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
-			return (ret);
-		}
-	} else {
+	if (obe_name != NULL) {
+		bt.obe_name = obe_name;
 		/* Validate original BE name */
 		if (!be_valid_be_name(bt.obe_name)) {
 			be_print_err(gettext("be_copy: "
@@ -614,16 +624,29 @@
 		}
 	}
 
-	/* Find which zpool obe_name lives in */
-	if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
-		be_print_err(gettext("be_copy: failed to "
-		    "find zpool for BE (%s)\n"), bt.obe_name);
-		return (BE_ERR_BE_NOENT);
-	} else if (zret < 0) {
-		be_print_err(gettext("be_copy: "
-		    "zpool_iter failed: %s\n"),
-		    libzfs_error_description(g_zfs));
-		return (zfs_err_to_be_err(g_zfs));
+	if (be_defaults.be_deflt_rpool_container) {
+		if ((zphp = zpool_open(g_zfs, bt.obe_zpool)) == NULL) {
+			be_print_err(gettext("be_get_node_data: failed to "
+			    "open rpool (%s): %s\n"), bt.obe_zpool,
+			    libzfs_error_description(g_zfs));
+			return (zfs_err_to_be_err(g_zfs));
+		}
+		if (be_find_zpool_callback(zphp, &bt) == 0) {
+			return (BE_ERR_BE_NOENT);
+		}
+	} else {
+		/* Find which zpool obe_name lives in */
+		if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) ==
+		    0) {
+			be_print_err(gettext("be_copy: failed to "
+			    "find zpool for BE (%s)\n"), bt.obe_name);
+			return (BE_ERR_BE_NOENT);
+		} else if (zret < 0) {
+			be_print_err(gettext("be_copy: "
+			    "zpool_iter failed: %s\n"),
+			    libzfs_error_description(g_zfs));
+			return (zfs_err_to_be_err(g_zfs));
+		}
 	}
 
 	/* Get snapshot name of original BE if one was provided */
@@ -1414,7 +1437,8 @@
 	if (be_destroy_callback(zhp, dd) != 0) {
 		be_print_err(gettext("be_destroy: failed to "
 		    "destroy BE %s\n"), root_ds);
-		return (BE_ERR_DESTROY);
+		ret = zfs_err_to_be_err(g_zfs);
+		return (ret);
 	}
 
 	/* If BE has an origin */
--- a/usr/src/lib/libbe/common/be_list.c	Tue Apr 05 09:31:14 2011 -0700
+++ b/usr/src/lib/libbe/common/be_list.c	Wed Apr 06 07:45:22 2011 -0700
@@ -23,6 +23,10 @@
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
+/*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ */
+
 #include <assert.h>
 #include <libintl.h>
 #include <libnvpair.h>
@@ -153,10 +157,15 @@
 	list_callback_data_t cb = { 0 };
 	be_transaction_data_t bt = { 0 };
 	int ret = BE_SUCCESS;
+	zpool_handle_t *zphp;
+	char *rpool = NULL;
+	struct be_defaults be_defaults;
 
 	if (be_nodes == NULL)
 		return (BE_ERR_INVAL);
 
+	be_get_defaults(&be_defaults);
+
 	if (be_find_current_be(&bt) != BE_SUCCESS) {
 		/*
 		 * We were unable to find a currently booted BE which
@@ -167,6 +176,7 @@
 	} else {
 		(void) strncpy(cb.current_be, bt.obe_name,
 		    sizeof (cb.current_be));
+		rpool = bt.obe_zpool;
 	}
 
 	/*
@@ -176,13 +186,25 @@
 	if (be_name != NULL)
 		cb.be_name = strdup(be_name);
 
-	if ((zpool_iter(g_zfs, be_get_list_callback, &cb)) != 0) {
-		if (cb.be_nodes_head != NULL) {
-			be_free_list(cb.be_nodes_head);
-			cb.be_nodes_head = NULL;
-			cb.be_nodes = NULL;
+	if (be_defaults.be_deflt_rpool_container && rpool != NULL) {
+		if ((zphp = zpool_open(g_zfs, rpool)) == NULL) {
+			be_print_err(gettext("be_get_node_data: failed to "
+			    "open rpool (%s): %s\n"), rpool,
+			    libzfs_error_description(g_zfs));
+			free(cb.be_name);
+			return (zfs_err_to_be_err(g_zfs));
 		}
-		ret = BE_ERR_BE_NOENT;
+
+		ret = be_get_list_callback(zphp, &cb);
+	} else {
+		if ((zpool_iter(g_zfs, be_get_list_callback, &cb)) != 0) {
+			if (cb.be_nodes_head != NULL) {
+				be_free_list(cb.be_nodes_head);
+				cb.be_nodes_head = NULL;
+				cb.be_nodes = NULL;
+			}
+			ret = BE_ERR_BE_NOENT;
+		}
 	}
 
 	if (cb.be_nodes_head == NULL) {
@@ -367,6 +389,8 @@
 	 * the information for the specified BE.
 	 */
 	if (cb->be_name != NULL) {
+		if (!be_valid_be_name(cb->be_name))
+			return (BE_ERR_INVAL);
 		/*
 		 * Generate string for the BE root dataset
 		 */
@@ -398,16 +422,6 @@
 		return (ret);
 	}
 
-	if (cb->be_nodes_head == NULL) {
-		if ((cb->be_nodes_head = be_list_alloc(&ret,
-		    sizeof (be_node_list_t))) == NULL) {
-			ZFS_CLOSE(zhp);
-			zpool_close(zlp);
-			return (ret);
-		}
-		cb->be_nodes = cb->be_nodes_head;
-	}
-
 	/*
 	 * If a BE name was specified we iterate through the datasets
 	 * and snapshots for this BE only. Otherwise we will iterate
@@ -415,6 +429,16 @@
 	 * within the pool
 	 */
 	if (cb->be_name != NULL) {
+		if (cb->be_nodes_head == NULL) {
+			if ((cb->be_nodes_head = be_list_alloc(&ret,
+			    sizeof (be_node_list_t))) == NULL) {
+				ZFS_CLOSE(zhp);
+				zpool_close(zlp);
+				return (ret);
+			}
+			cb->be_nodes = cb->be_nodes_head;
+		}
+
 		if ((ret = be_get_node_data(zhp, cb->be_nodes, cb->be_name,
 		    rpool, cb->current_be, be_ds)) != BE_SUCCESS) {
 			ZFS_CLOSE(zhp);
@@ -454,6 +478,9 @@
 	list_callback_data_t	*cb = (list_callback_data_t *)data;
 	char			*str = NULL, *ds_path = NULL;
 	int			ret = 0;
+	struct be_defaults be_defaults;
+
+	be_get_defaults(&be_defaults);
 
 	ds_path = str = strdup(zfs_get_name(zhp));
 
@@ -461,6 +488,21 @@
 	 * get past the end of the container dataset plus the trailing "/"
 	 */
 	str = str + (strlen(be_container_ds) + 1);
+	if (be_defaults.be_deflt_bename_starts_with != '\0') {
+		/* just skip if invalid */
+		if (!be_valid_be_name(str))
+			return (BE_SUCCESS);
+	}
+
+	if (cb->be_nodes_head == NULL) {
+		if ((cb->be_nodes_head = be_list_alloc(&ret,
+		    sizeof (be_node_list_t))) == NULL) {
+			ZFS_CLOSE(zhp);
+			return (ret);
+		}
+		cb->be_nodes = cb->be_nodes_head;
+	}
+
 	if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && !zone_be) {
 		be_snapshot_list_t *snapshots = NULL;
 		if (cb->be_nodes->be_node_snapshots == NULL) {
--- a/usr/src/lib/libbe/common/be_snapshot.c	Tue Apr 05 09:31:14 2011 -0700
+++ b/usr/src/lib/libbe/common/be_snapshot.c	Wed Apr 06 07:45:22 2011 -0700
@@ -24,6 +24,10 @@
  */
 
 /*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
  * System includes
  */
 #include <assert.h>
@@ -248,27 +252,33 @@
 {
 	be_transaction_data_t	bt = { 0 };
 	zfs_handle_t		*zhp = NULL;
+	zpool_handle_t		*zphp;
 	char			obe_root_ds[MAXPATHLEN];
+	char			*obe_name = NULL;
 	int			zret = 0, ret = BE_SUCCESS;
+	struct be_defaults be_defaults;
 
 	/* Initialize libzfs handle */
 	if (!be_zfs_init())
 		return (BE_ERR_INIT);
 
+	if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
+		return (ret);
+	}
+
 	/* Get original BE name if one was provided */
 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
-	    BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &bt.obe_name, NULL) != 0) {
+	    BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &obe_name, NULL) != 0) {
 		be_print_err(gettext("be_rollback: "
 		    "failed to lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
 		return (BE_ERR_INVAL);
 	}
 
+	be_get_defaults(&be_defaults);
+
 	/* If original BE name not provided, use current BE */
-	if (bt.obe_name == NULL) {
-		if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
-			return (ret);
-		}
-	} else {
+	if (obe_name != NULL) {
+		bt.obe_name = obe_name;
 		/* Validate original BE name  */
 		if (!be_valid_be_name(bt.obe_name)) {
 			be_print_err(gettext("be_rollback: "
@@ -285,16 +295,27 @@
 		return (BE_ERR_INVAL);
 	}
 
-	/* Find which zpool obe_name lives in */
-	if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
-		be_print_err(gettext("be_rollback: "
-		    "failed to find zpool for BE (%s)\n"), bt.obe_name);
-		return (BE_ERR_BE_NOENT);
-	} else if (zret < 0) {
-		be_print_err(gettext("be_rollback: "
-		    "zpool_iter failed: %s\n"),
-		    libzfs_error_description(g_zfs));
-		return (zfs_err_to_be_err(g_zfs));
+	if (be_defaults.be_deflt_rpool_container) {
+		if ((zphp = zpool_open(g_zfs, bt.obe_zpool)) == NULL) {
+			be_print_err(gettext("be_rollback: failed to "
+			    "open rpool (%s): %s\n"), bt.obe_zpool,
+			    libzfs_error_description(g_zfs));
+			return (zfs_err_to_be_err(g_zfs));
+		}
+		zret = be_find_zpool_callback(zphp, &bt);
+	} else {
+		/* Find which zpool obe_name lives in */
+		if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) ==
+		    0) {
+			be_print_err(gettext("be_rollback: "
+			    "failed to find zpool for BE (%s)\n"), bt.obe_name);
+			return (BE_ERR_BE_NOENT);
+		} else if (zret < 0) {
+			be_print_err(gettext("be_rollback: "
+			    "zpool_iter failed: %s\n"),
+			    libzfs_error_description(g_zfs));
+			return (zfs_err_to_be_err(g_zfs));
+		}
 	}
 
 	/* Generate string for BE's root dataset */
--- a/usr/src/lib/libbe/common/be_utils.c	Tue Apr 05 09:31:14 2011 -0700
+++ b/usr/src/lib/libbe/common/be_utils.c	Wed Apr 06 07:45:22 2011 -0700
@@ -50,6 +50,7 @@
 #include <time.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <deflt.h>
 #include <wait.h>
 #include <libdevinfo.h>
 
@@ -59,8 +60,8 @@
 /* Private function prototypes */
 static int update_dataset(char *, int, char *, char *, char *);
 static int _update_vfstab(char *, char *, char *, char *, be_fs_list_data_t *);
-static int be_open_menu(char *, char *, char *, FILE **, char *, boolean_t);
-static int be_create_menu(char *, char *, char *, FILE **, char *);
+static int be_open_menu(char *, char *, FILE **, char *, boolean_t);
+static int be_create_menu(char *, char *, FILE **, char *);
 static char *be_get_auto_name(char *, char *, boolean_t);
 
 /*
@@ -181,6 +182,35 @@
 }
 
 /*
+ * Function:	be_get_defaults
+ * Description:	Open defaults and gets be default paramets
+ * Parameters:
+ *		defaults - be defaults struct
+ * Returns:
+ *		None
+ * Scope:
+ *		Semi-private (library wide use only)
+ */
+void
+be_get_defaults(struct be_defaults *defaults)
+{
+	void	*defp;
+
+	defaults->be_deflt_rpool_container = B_FALSE;
+	defaults->be_deflt_bename_starts_with[0] = '\0';
+
+	if ((defp = defopen_r(BE_DEFAULTS)) != NULL) {
+		const char *res = defread_r(BE_DFLT_BENAME_STARTS, defp);
+		if (res != NULL && res[0] != NULL) {
+			(void) strlcpy(defaults->be_deflt_bename_starts_with,
+			    res, ZFS_MAXNAMELEN);
+			defaults->be_deflt_rpool_container = B_TRUE;
+		}
+		defclose_r(defp);
+	}
+}
+
+/*
  * Function:	be_make_root_ds
  * Description:	Generate string for BE's root dataset given the pool
  *		it lives in and the BE name.
@@ -198,8 +228,15 @@
 be_make_root_ds(const char *zpool, const char *be_name, char *be_root_ds,
     int be_root_ds_size)
 {
-	(void) snprintf(be_root_ds, be_root_ds_size, "%s/%s/%s", zpool,
-	    BE_CONTAINER_DS_NAME, be_name);
+	struct be_defaults be_defaults;
+	be_get_defaults(&be_defaults);
+
+	if (be_defaults.be_deflt_rpool_container)
+		(void) snprintf(be_root_ds, be_root_ds_size, "%s/%s", zpool,
+		    be_name);
+	else
+		(void) snprintf(be_root_ds, be_root_ds_size, "%s/%s/%s", zpool,
+		    BE_CONTAINER_DS_NAME, be_name);
 }
 
 /*
@@ -219,8 +256,14 @@
 be_make_container_ds(const char *zpool,  char *container_ds,
     int container_ds_size)
 {
-	(void) snprintf(container_ds, container_ds_size, "%s/%s", zpool,
-	    BE_CONTAINER_DS_NAME);
+	struct be_defaults be_defaults;
+	be_get_defaults(&be_defaults);
+
+	if (be_defaults.be_deflt_rpool_container)
+		(void) snprintf(container_ds, container_ds_size, "%s", zpool);
+	else
+		(void) snprintf(container_ds, container_ds_size, "%s/%s", zpool,
+		    BE_CONTAINER_DS_NAME);
 }
 
 /*
@@ -244,31 +287,41 @@
 	char	ds[ZFS_MAXNAMELEN];
 	char	*tok = NULL;
 	char	*name = NULL;
+	struct be_defaults be_defaults;
+	int	rlen = strlen(rc_loc);
+
+	be_get_defaults(&be_defaults);
 
 	/*
 	 * First token is the location of where the root container dataset
 	 * lives; it must match rc_loc.
 	 */
-	if (strncmp(dataset, rc_loc, strlen(rc_loc)) == 0 &&
-	    dataset[strlen(rc_loc)] == '/') {
-		(void) strlcpy(ds, dataset + strlen(rc_loc) + 1, sizeof (ds));
-	} else {
+	if (strncmp(dataset, rc_loc, rlen) == 0 && dataset[rlen] == '/')
+		(void) strlcpy(ds, dataset + rlen + 1, sizeof (ds));
+	else
 		return (NULL);
-	}
-
-	/* Second token must be BE container dataset name */
-	if ((tok = strtok(ds, "/")) == NULL ||
-	    strcmp(tok, BE_CONTAINER_DS_NAME) != 0)
-		return (NULL);
-
-	/* Return the remaining token if one exists */
-	if ((tok = strtok(NULL, "")) == NULL)
-		return (NULL);
-
-	if ((name = strdup(tok)) == NULL) {
-		be_print_err(gettext("be_make_name_from_ds: "
-		    "memory allocation failed\n"));
-		return (NULL);
+
+	if (be_defaults.be_deflt_rpool_container) {
+		if ((name = strdup(ds)) == NULL) {
+			be_print_err(gettext("be_make_name_from_ds: "
+			    "memory allocation failed\n"));
+			return (NULL);
+		}
+	} else {
+		/* Second token must be BE container dataset name */
+		if ((tok = strtok(ds, "/")) == NULL ||
+		    strcmp(tok, BE_CONTAINER_DS_NAME) != 0)
+			return (NULL);
+
+		/* Return the remaining token if one exists */
+		if ((tok = strtok(NULL, "")) == NULL)
+			return (NULL);
+
+		if ((name = strdup(tok)) == NULL) {
+			be_print_err(gettext("be_make_name_from_ds: "
+			    "memory allocation failed\n"));
+			return (NULL);
+		}
 	}
 
 	return (name);
@@ -393,7 +446,7 @@
 	 * track of that BE's menu entry. We will then use the lines from
 	 * that entry to create the entry for the new BE.
 	 */
-	if ((ret = be_open_menu(be_root_pool, pool_mntpnt, menu_file,
+	if ((ret = be_open_menu(be_root_pool, menu_file,
 	    &menu_fp, "r", B_TRUE)) != BE_SUCCESS) {
 		goto cleanup;
 	} else if (menu_fp == NULL) {
@@ -682,7 +735,7 @@
 		(void) strlcat(menu, BE_SPARC_MENU, sizeof (menu));
 
 	/* Get handle to boot menu file */
-	if ((ret = be_open_menu(be_root_pool, pool_mntpnt, menu, &menu_fp, "r",
+	if ((ret = be_open_menu(be_root_pool, menu, &menu_fp, "r",
 	    B_TRUE)) != BE_SUCCESS) {
 		goto cleanup;
 	} else if (menu_fp == NULL) {
@@ -1122,7 +1175,7 @@
 	(void) snprintf(grub_file, MAXPATHLEN, "%s%s",
 	    pool_mntpnt, BE_GRUB_MENU);
 
-	if ((ret = be_open_menu((char *)be_root_pool, pool_mntpnt, grub_file,
+	if ((ret = be_open_menu((char *)be_root_pool, grub_file,
 	    &menu_fp, "r", B_FALSE)) != BE_SUCCESS) {
 		goto cleanup;
 	} else if (menu_fp == NULL) {
@@ -1283,7 +1336,7 @@
 	(void) snprintf(grub_file, MAXPATHLEN, "%s%s",
 	    pool_mntpnt, BE_GRUB_MENU);
 
-	if ((ret = be_open_menu(be_root_pool, pool_mntpnt, grub_file,
+	if ((ret = be_open_menu(be_root_pool, grub_file,
 	    &grub_fp, "r+", B_TRUE)) != BE_SUCCESS) {
 		goto cleanup;
 	} else if (grub_fp == NULL) {
@@ -1521,7 +1574,7 @@
 	be_make_root_ds(be_root_pool, be_new_name, be_new_root_ds,
 	    sizeof (be_new_root_ds));
 
-	if ((ret = be_open_menu(be_root_pool, pool_mntpnt, menu_file,
+	if ((ret = be_open_menu(be_root_pool, menu_file,
 	    &menu_fp, "r", B_TRUE)) != BE_SUCCESS) {
 		goto cleanup;
 	} else if (menu_fp == NULL) {
@@ -1787,7 +1840,7 @@
 		    rpool_mntpnt, BE_SPARC_MENU);
 	}
 
-	if (be_open_menu(be_root_pool, rpool_mntpnt, menu_file, &menu_fp, "r",
+	if (be_open_menu(be_root_pool, menu_file, &menu_fp, "r",
 	    B_FALSE) != 0) {
 		ret = B_FALSE;
 		goto cleanup;
@@ -2098,10 +2151,13 @@
 be_valid_be_name(const char *be_name)
 {
 	const char	*c = NULL;
+	struct be_defaults be_defaults;
 
 	if (be_name == NULL)
 		return (B_FALSE);
 
+	be_get_defaults(&be_defaults);
+
 	/*
 	 * A BE name must not be a multi-level dataset name.  We also check
 	 * that it does not contain the ' ' and '%' characters.  The ' ' is
@@ -2124,6 +2180,11 @@
 	    strlen(be_name) > BE_NAME_MAX_LEN)
 		return (B_FALSE);
 
+	if (be_defaults.be_deflt_bename_starts_with[0] != '\0' &&
+	    strstr(be_name, be_defaults.be_deflt_bename_starts_with) == NULL) {
+		return (B_FALSE);
+	}
+
 	return (B_TRUE);
 }
 
@@ -2469,6 +2530,7 @@
 				ZFS_CLOSE(zhp);
 				return (0);
 			}
+
 			if ((bt->obe_name = strdup(basename(bt->obe_root_ds)))
 			    == NULL) {
 				be_print_err(gettext(
@@ -3506,7 +3568,6 @@
  *		lines are added to the file.
  * Parameters:
  *		pool - The name of the pool the menu.lst file is on
- *		pool_mntpt - The mountpoint for the pool we're using.
  *		menu_file - The name of the file we're creating.
  *		menu_fp - A pointer to the file pointer of the file we
  *			  created. This is also used to pass back the file
@@ -3522,7 +3583,6 @@
 static int
 be_create_menu(
 	char *pool,
-	char *pool_mntpt,
 	char *menu_file,
 	FILE **menu_fp,
 	char *mode)
@@ -3653,9 +3713,6 @@
  *              exist it is simply opened using the mode passed in.
  * Parameters:
  *		pool - The name of the pool the menu.lst file is on
- *		pool_mntpt - The mountpoint for the pool we're using.
- *			     The mountpoint is used since the mountpoint
- *			     name can differ from the pool name.
  *		menu_file - The name of the file we're opening.
  *		menu_fp - A pointer to the file pointer of the file we're
  *			  opening. This is also used to pass back the file
@@ -3675,7 +3732,6 @@
 static int
 be_open_menu(
 	char *pool,
-	char *pool_mntpt,
 	char *menu_file,
 	FILE **menu_fp,
 	char *mode,
@@ -3700,7 +3756,7 @@
 			if (set_print)
 				do_print = B_FALSE;
 			err = 0;
-			if ((err = be_create_menu(pool, pool_mntpt, menu_file,
+			if ((err = be_create_menu(pool, menu_file,
 			    menu_fp, mode)) == ENOENT)
 				return (BE_ERR_NO_MENU);
 			else if (err != BE_SUCCESS)
--- a/usr/src/lib/libbe/common/libbe_priv.h	Tue Apr 05 09:31:14 2011 -0700
+++ b/usr/src/lib/libbe/common/libbe_priv.h	Wed Apr 06 07:45:22 2011 -0700
@@ -41,6 +41,8 @@
 #define	ARCH_LENGTH		MAXNAMELEN
 #define	BE_AUTO_NAME_MAX_TRY	3
 #define	BE_AUTO_NAME_DELIM	'-'
+#define	BE_DEFAULTS		"/etc/default/be"
+#define	BE_DFLT_BENAME_STARTS	"BENAME_STARTS_WITH="
 #define	BE_CONTAINER_DS_NAME	"ROOT"
 #define	BE_DEFAULT_CONSOLE	"text"
 #define	BE_POLICY_PROPERTY	"org.opensolaris.libbe:policy"
@@ -129,6 +131,11 @@
 	struct be_plcy_list	*be_next_plcy;
 }be_plcy_list_t;
 
+struct be_defaults {
+	boolean_t	be_deflt_rpool_container;
+	char		be_deflt_bename_starts_with[ZFS_MAXNAMELEN];
+};
+
 /* Library globals */
 extern libzfs_handle_t *g_zfs;
 extern boolean_t do_print;
@@ -211,6 +218,9 @@
 int be_zfs_find_current_be_callback(zfs_handle_t *, void *);
 int be_check_be_roots_callback(zpool_handle_t *, void *);
 
+/* defaults */
+void be_get_defaults(struct be_defaults *defaults);
+
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/man/man1m/beadm.1m	Tue Apr 05 09:31:14 2011 -0700
+++ b/usr/src/man/man1m/beadm.1m	Wed Apr 06 07:45:22 2011 -0700
@@ -1,4 +1,5 @@
 '\" te
+.\" Copyright 2011 Nexenta Systems, Inc. All rights reserved.
 .TH beadm 1M "26 Feb 2011" "SunOS 5.11" "System Administration Commands"
 .SH NAME
 beadm \- utility for managing zfs boot environments
@@ -406,6 +407,13 @@
 Makes beName the active BE on next reboot.
 .RE
 
+.SH ALTERNATE BE LOCATION
+.LP
+The alternate BE location outside rpool/ROOT can be configured
+by modifying the BENAME_STARTS_WITH parameter in /etc/default/be.
+For example: BENAME_STARTS_WITH=rootfs
+.RE
+
 .SH EXAMPLES
 .LP     
 \fBExample 1\fR: Create a new BE named BE1, by cloning the current live BE.
@@ -685,6 +693,20 @@
 .sp
 .RE
 .RE
+.sp
+.LP     
+.sp
+.ne 2
+.mk
+.na
+\fB/etc/default/be\fR
+.ad
+.sp .6
+.RS 4n    
+Contains default value for BENAME_STARTS_WITH parameter
+.sp
+.RE
+.RE
 
 .SH ATTRIBUTES
 .sp