]> git.proxmox.com Git - mirror_zfs.git/commitdiff
OpenZFS 7386 - zfs get does not work properly with bookmarks
authorGeorge Melikov <mail@gmelikov.ru>
Thu, 26 Jan 2017 22:42:15 +0000 (01:42 +0300)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 26 Jan 2017 22:42:15 +0000 (14:42 -0800)
Authored by: Marcel Telka <marcel@telka.sk>
Reviewed by: Simon Klinkert <simon.klinkert@gmail.com>
Reviewed by: Paul Dagnelie <pcd@delphix.com>
Approved by: Matthew Ahrens <mahrens@delphix.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Ported-by: George Melikov <mail@gmelikov.ru>
OpenZFS-issue: https://www.illumos.org/issues/7386
OpenZFS-commit: https://github.com/openzfs/openzfs/commit/edb901a
Closes #5666

13 files changed:
cmd/zfs/zfs_main.c
include/zfs_namecheck.h
lib/libzfs/libzfs_dataset.c
lib/libzfs/libzfs_pool.c
lib/libzfs/libzfs_util.c
man/man8/zfs.8
module/zcommon/zfs_namecheck.c
tests/zfs-tests/include/default.cfg.in
tests/zfs-tests/include/libtest.shlib
tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_001_pos.ksh
tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_005_neg.ksh
tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_008_pos.ksh
tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_common.kshlib

index 3b72d60f2284cb66c6425f6d9c287d5990ab7584..2a7525758b27ac1f06d70f02568ee53d7cebfe17 100644 (file)
@@ -232,7 +232,7 @@ get_usage(zfs_help_t idx)
                    "[-o \"all\" | field[,...]]\n"
                    "\t    [-t type[,...]] [-s source[,...]]\n"
                    "\t    <\"all\" | property[,...]> "
-                   "[filesystem|volume|snapshot] ...\n"));
+                   "[filesystem|volume|snapshot|bookmark] ...\n"));
        case HELP_INHERIT:
                return (gettext("\tinherit [-rS] <property> "
                    "<filesystem|volume|snapshot> ...\n"));
@@ -1608,7 +1608,7 @@ zfs_do_get(int argc, char **argv)
 {
        zprop_get_cbdata_t cb = { 0 };
        int i, c, flags = ZFS_ITER_ARGS_CAN_BE_PATHS;
-       int types = ZFS_TYPE_DATASET;
+       int types = ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK;
        char *value, *fields;
        int ret = 0;
        int limit = 0;
index cbefbaa0d5ab6fc11a543b1d5b32402e5ffcef12..db70641dbab22d41c2a3684fe3213b3ff918b306 100644 (file)
@@ -38,7 +38,7 @@ typedef enum {
        NAME_ERR_EMPTY_COMPONENT,       /* name contains an empty component */
        NAME_ERR_TRAILING_SLASH,        /* name ends with a slash */
        NAME_ERR_INVALCHAR,             /* invalid character found */
-       NAME_ERR_MULTIPLE_AT,           /* multiple '@' characters found */
+       NAME_ERR_MULTIPLE_DELIMITERS,   /* multiple '@'/'#' delimiters found */
        NAME_ERR_NOLETTER,              /* pool doesn't begin with a letter */
        NAME_ERR_RESERVED,              /* entire name is reserved */
        NAME_ERR_DISKLIKE,              /* reserved disk name (c[0-9].*) */
@@ -49,6 +49,7 @@ typedef enum {
 #define        ZFS_PERMSET_MAXLEN      64
 
 int pool_namecheck(const char *, namecheck_err_t *, char *);
+int entity_namecheck(const char *, namecheck_err_t *, char *);
 int dataset_namecheck(const char *, namecheck_err_t *, char *);
 int mountpoint_namecheck(const char *, namecheck_err_t *);
 int zfs_component_namecheck(const char *, namecheck_err_t *, char *);
index 469bdee20f8508fbf442673862eee201d357f61e..7c3ef744d3712b6eeb15ddc0e1bbba074b4ec837 100644 (file)
@@ -100,7 +100,7 @@ zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
        char what;
 
        (void) zfs_prop_get_table();
-       if (dataset_namecheck(path, &why, &what) != 0) {
+       if (entity_namecheck(path, &why, &what) != 0) {
                if (hdl != NULL) {
                        switch (why) {
                        case NAME_ERR_TOOLONG:
@@ -129,9 +129,10 @@ zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
                                    "'%c' in name"), what);
                                break;
 
-                       case NAME_ERR_MULTIPLE_AT:
+                       case NAME_ERR_MULTIPLE_DELIMITERS:
                                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
-                                   "multiple '@' delimiters in name"));
+                                   "multiple '@' and/or '#' delimiters in "
+                                   "name"));
                                break;
 
                        case NAME_ERR_NOLETTER:
@@ -159,7 +160,7 @@ zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
        if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) {
                if (hdl != NULL)
                        zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
-                           "snapshot delimiter '@' in filesystem name"));
+                           "snapshot delimiter '@' is not expected here"));
                return (0);
        }
 
@@ -170,6 +171,20 @@ zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
                return (0);
        }
 
+       if (!(type & ZFS_TYPE_BOOKMARK) && strchr(path, '#') != NULL) {
+               if (hdl != NULL)
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "bookmark delimiter '#' is not expected here"));
+               return (0);
+       }
+
+       if (type == ZFS_TYPE_BOOKMARK && strchr(path, '#') == NULL) {
+               if (hdl != NULL)
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "missing '#' delimiter in bookmark name"));
+               return (0);
+       }
+
        if (modifying && strchr(path, '%') != NULL) {
                if (hdl != NULL)
                        zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
@@ -610,8 +625,36 @@ make_bookmark_handle(zfs_handle_t *parent, const char *path,
        return (zhp);
 }
 
+struct zfs_open_bookmarks_cb_data {
+       const char *path;
+       zfs_handle_t *zhp;
+};
+
+static int
+zfs_open_bookmarks_cb(zfs_handle_t *zhp, void *data)
+{
+       struct zfs_open_bookmarks_cb_data *dp = data;
+
+       /*
+        * Is it the one we are looking for?
+        */
+       if (strcmp(dp->path, zfs_get_name(zhp)) == 0) {
+               /*
+                * We found it.  Save it and let the caller know we are done.
+                */
+               dp->zhp = zhp;
+               return (EEXIST);
+       }
+
+       /*
+        * Not found.  Close the handle and ask for another one.
+        */
+       zfs_close(zhp);
+       return (0);
+}
+
 /*
- * Opens the given snapshot, filesystem, or volume.   The 'types'
+ * Opens the given snapshot, bookmark, filesystem, or volume.   The 'types'
  * argument is a mask of acceptable types.  The function will print an
  * appropriate error message and return NULL if it can't be opened.
  */
@@ -620,6 +663,7 @@ zfs_open(libzfs_handle_t *hdl, const char *path, int types)
 {
        zfs_handle_t *zhp;
        char errbuf[1024];
+       char *bookp;
 
        (void) snprintf(errbuf, sizeof (errbuf),
            dgettext(TEXT_DOMAIN, "cannot open '%s'"), path);
@@ -627,20 +671,68 @@ zfs_open(libzfs_handle_t *hdl, const char *path, int types)
        /*
         * Validate the name before we even try to open it.
         */
-       if (!zfs_validate_name(hdl, path, ZFS_TYPE_DATASET, B_FALSE)) {
-               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
-                   "invalid dataset name"));
+       if (!zfs_validate_name(hdl, path, types, B_FALSE)) {
                (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
                return (NULL);
        }
 
        /*
-        * Try to get stats for the dataset, which will tell us if it exists.
+        * Bookmarks needs to be handled separately.
         */
-       errno = 0;
-       if ((zhp = make_dataset_handle(hdl, path)) == NULL) {
-               (void) zfs_standard_error(hdl, errno, errbuf);
-               return (NULL);
+       bookp = strchr(path, '#');
+       if (bookp == NULL) {
+               /*
+                * Try to get stats for the dataset, which will tell us if it
+                * exists.
+                */
+               errno = 0;
+               if ((zhp = make_dataset_handle(hdl, path)) == NULL) {
+                       (void) zfs_standard_error(hdl, errno, errbuf);
+                       return (NULL);
+               }
+       } else {
+               char dsname[ZFS_MAX_DATASET_NAME_LEN];
+               zfs_handle_t *pzhp;
+               struct zfs_open_bookmarks_cb_data cb_data = {path, NULL};
+
+               /*
+                * We need to cut out '#' and everything after '#'
+                * to get the parent dataset name only.
+                */
+               assert(bookp - path < sizeof (dsname));
+               (void) strncpy(dsname, path, bookp - path);
+               dsname[bookp - path] = '\0';
+
+               /*
+                * Create handle for the parent dataset.
+                */
+               errno = 0;
+               if ((pzhp = make_dataset_handle(hdl, dsname)) == NULL) {
+                       (void) zfs_standard_error(hdl, errno, errbuf);
+                       return (NULL);
+               }
+
+               /*
+                * Iterate bookmarks to find the right one.
+                */
+               errno = 0;
+               if ((zfs_iter_bookmarks(pzhp, zfs_open_bookmarks_cb,
+                   &cb_data) == 0) && (cb_data.zhp == NULL)) {
+                       (void) zfs_error(hdl, EZFS_NOENT, errbuf);
+                       zfs_close(pzhp);
+                       return (NULL);
+               }
+               if (cb_data.zhp == NULL) {
+                       (void) zfs_standard_error(hdl, errno, errbuf);
+                       zfs_close(pzhp);
+                       return (NULL);
+               }
+               zhp = cb_data.zhp;
+
+               /*
+                * Cleanup.
+                */
+               zfs_close(pzhp);
        }
 
        if (!(types & zhp->zfs_type)) {
index 76ada47d67c07d5163784f042e78f4aa201ddba2..2e1d927511dfe836ebf33182120f4c3a06c93850 100644 (file)
@@ -1031,9 +1031,10 @@ zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool)
                                    "trailing slash in name"));
                                break;
 
-                       case NAME_ERR_MULTIPLE_AT:
+                       case NAME_ERR_MULTIPLE_DELIMITERS:
                                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
-                                   "multiple '@' delimiters in name"));
+                                   "multiple '@' and/or '#' delimiters in "
+                                   "name"));
                                break;
                        case NAME_ERR_NO_AT:
                                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
index a9c8374f19e44c1f2c6ffa3cc1807eb44fd17650..71facc88eb8fa2f2c4b85ced7c04b6f688ce36d1 100644 (file)
@@ -927,7 +927,7 @@ zfs_get_pool_handle(const zfs_handle_t *zhp)
  * Given a name, determine whether or not it's a valid path
  * (starts with '/' or "./").  If so, walk the mnttab trying
  * to match the device number.  If not, treat the path as an
- * fs/vol/snap name.
+ * fs/vol/snap/bkmark name.
  */
 zfs_handle_t *
 zfs_path_to_zhandle(libzfs_handle_t *hdl, char *path, zfs_type_t argtype)
index 6417ee7711947f30406cd3d00df1302e2d043c0b..0f9a631d975691e25bbf4dc21baaa4997674ed8c 100644 (file)
@@ -2202,7 +2202,7 @@ A comma-separated list of types to display, where \fItype\fR is one of \fBfilesy
 .ne 2
 .na
 \fB\fBzfs set\fR \fIproperty\fR=\fIvalue\fR[ \fIproperty\fR=\fIvalue\fR]...
-\fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR ...\fR
+\fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR|\fIbookmark\fR ...\fR
 .ad
 .sp .6
 .RS 4n
@@ -2214,7 +2214,7 @@ can be set on snapshots. For more information, see the "User Properties" section
 
 .sp
 .ne 2
-\fB\fBzfs get\fR [\fB-r\fR|\fB-d\fR \fIdepth\fR] [\fB-Hp\fR] [\fB-o\fR \fIfield\fR[,...] [\fB-t\fR \fItype\fR[,...]] [\fB-s\fR \fIsource\fR[,...] "\fIall\fR" | \fIproperty\fR[,...] \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR ...\fR
+\fB\fBzfs get\fR [\fB-r\fR|\fB-d\fR \fIdepth\fR] [\fB-Hp\fR] [\fB-o\fR \fIfield\fR[,...] [\fB-t\fR \fItype\fR[,...]] [\fB-s\fR \fIsource\fR[,...] "\fIall\fR" | \fIproperty\fR[,...] \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR ...\fR|\fIbookmark\fR ...\fR
 .ad
 .sp .6
 .RS 4n
index b58071bed0557bdde450cf45f34cfa92c943e6a8..f9c20896d46016f66e1fa5d8618a8265a9849b3a 100644 (file)
@@ -120,9 +120,9 @@ permset_namecheck(const char *path, namecheck_err_t *why, char *what)
 }
 
 /*
- * Dataset names must be of the following form:
+ * Entity names must be of the following form:
  *
- *     [component][/]*[component][@component]
+ *     [component/]*[component][(@|#)component]?
  *
  * Where each component is made up of alphanumeric characters plus the following
  * characters:
@@ -133,10 +133,10 @@ permset_namecheck(const char *path, namecheck_err_t *why, char *what)
  * names for temporary clones (for online recv).
  */
 int
-dataset_namecheck(const char *path, namecheck_err_t *why, char *what)
+entity_namecheck(const char *path, namecheck_err_t *why, char *what)
 {
-       const char *loc, *end;
-       int found_snapshot;
+       const char *start, *end, *loc;
+       int found_delim;
 
        /*
         * Make sure the name is not too long.
@@ -160,12 +160,13 @@ dataset_namecheck(const char *path, namecheck_err_t *why, char *what)
                return (-1);
        }
 
-       loc = path;
-       found_snapshot = 0;
+       start = path;
+       found_delim = 0;
        for (;;) {
                /* Find the end of this component */
-               end = loc;
-               while (*end != '/' && *end != '@' && *end != '\0')
+               end = start;
+               while (*end != '/' && *end != '@' && *end != '#' &&
+                   *end != '\0')
                        end++;
 
                if (*end == '\0' && end[-1] == '/') {
@@ -175,25 +176,8 @@ dataset_namecheck(const char *path, namecheck_err_t *why, char *what)
                        return (-1);
                }
 
-               /* Zero-length components are not allowed */
-               if (loc == end) {
-                       if (why) {
-                               /*
-                                * Make sure this is really a zero-length
-                                * component and not a '@@'.
-                                */
-                               if (*end == '@' && found_snapshot) {
-                                       *why = NAME_ERR_MULTIPLE_AT;
-                               } else {
-                                       *why = NAME_ERR_EMPTY_COMPONENT;
-                               }
-                       }
-
-                       return (-1);
-               }
-
                /* Validate the contents of this component */
-               while (loc != end) {
+               for (loc = start; loc != end; loc++) {
                        if (!valid_char(*loc) && *loc != '%') {
                                if (why) {
                                        *why = NAME_ERR_INVALCHAR;
@@ -201,43 +185,64 @@ dataset_namecheck(const char *path, namecheck_err_t *why, char *what)
                                }
                                return (-1);
                        }
-                       loc++;
                }
 
-               /* If we've reached the end of the string, we're OK */
-               if (*end == '\0')
-                       return (0);
-
-               if (*end == '@') {
-                       /*
-                        * If we've found an @ symbol, indicate that we're in
-                        * the snapshot component, and report a second '@'
-                        * character as an error.
-                        */
-                       if (found_snapshot) {
+               /* Snapshot or bookmark delimiter found */
+               if (*end == '@' || *end == '#') {
+                       /* Multiple delimiters are not allowed */
+                       if (found_delim != 0) {
                                if (why)
-                                       *why = NAME_ERR_MULTIPLE_AT;
+                                       *why = NAME_ERR_MULTIPLE_DELIMITERS;
                                return (-1);
                        }
 
-                       found_snapshot = 1;
+                       found_delim = 1;
                }
 
+               /* Zero-length components are not allowed */
+               if (start == end) {
+                       if (why)
+                               *why = NAME_ERR_EMPTY_COMPONENT;
+                       return (-1);
+               }
+
+               /* If we've reached the end of the string, we're OK */
+               if (*end == '\0')
+                       return (0);
+
                /*
-                * If there is a '/' in a snapshot name
+                * If there is a '/' in a snapshot or bookmark name
                 * then report an error
                 */
-               if (*end == '/' && found_snapshot) {
+               if (*end == '/' && found_delim != 0) {
                        if (why)
                                *why = NAME_ERR_TRAILING_SLASH;
                        return (-1);
                }
 
                /* Update to the next component */
-               loc = end + 1;
+               start = end + 1;
        }
 }
 
+/*
+ * Dataset is any entity, except bookmark
+ */
+int
+dataset_namecheck(const char *path, namecheck_err_t *why, char *what)
+{
+       int ret = entity_namecheck(path, why, what);
+
+       if (ret == 0 && strchr(path, '#') != NULL) {
+               if (why != NULL) {
+                       *why = NAME_ERR_INVALCHAR;
+                       *what = '#';
+               }
+               return (-1);
+       }
+
+       return (ret);
+}
 
 /*
  * mountpoint names must be of the following form:
index f93bfa98c91740078e503ae3351d534750805f59..d6913f1f3a3eea2a592875fad3bb8c70123236c2 100644 (file)
@@ -147,6 +147,7 @@ export TESTVOL2=testvol2$$
 export TESTFILE0=testfile0.$$
 export TESTFILE1=testfile1.$$
 export TESTFILE2=testfile2.$$
+export TESTBKMARK=testbkmark$$
 
 export LONGPNAME="poolname50charslong_012345678901234567890123456789"
 export LONGFSNAME="fsysname50charslong_012345678901234567890123456789"
index 4e68ffc3e5985bb93474d9ce57efc3c5c5989907..199a93503f9e4a85de649ee6a3d5731f5393f63b 100644 (file)
@@ -291,6 +291,35 @@ function create_clone   # snapshot clone
        log_must $ZFS clone $snap $clone
 }
 
+#
+# Create a bookmark of the given snapshot.  Defaultly create a bookmark on
+# filesystem.
+#
+# $1 Existing filesystem or volume name. Default, $TESTFS
+# $2 Existing snapshot name. Default, $TESTSNAP
+# $3 bookmark name. Default, $TESTBKMARK
+#
+function create_bookmark
+{
+       typeset fs_vol=${1:-$TESTFS}
+       typeset snap=${2:-$TESTSNAP}
+       typeset bkmark=${3:-$TESTBKMARK}
+
+       [[ -z $fs_vol ]] && log_fail "Filesystem or volume's name is undefined."
+       [[ -z $snap ]] && log_fail "Snapshot's name is undefined."
+       [[ -z $bkmark ]] && log_fail "Bookmark's name is undefined."
+
+       if bkmarkexists $fs_vol#$bkmark; then
+               log_fail "$fs_vol#$bkmark already exists."
+       fi
+       datasetexists $fs_vol || \
+               log_fail "$fs_vol must exist."
+       snapexists $fs_vol@$snap || \
+               log_fail "$fs_vol@$snap must exist."
+
+       log_must $ZFS bookmark $fs_vol@$snap $fs_vol#$bkmark
+}
+
 function default_mirror_setup
 {
        default_mirror_setup_noexit $1 $2 $3
@@ -575,6 +604,23 @@ function destroy_clone
                log_must $RM -rf $mtpt
 }
 
+#
+# Common function used to cleanup bookmark of file system or volume.  Default
+# to delete the file system's bookmark.
+#
+# $1 bookmark name
+#
+function destroy_bookmark
+{
+       typeset bkmark=${1:-$TESTPOOL/$TESTFS#$TESTBKMARK}
+
+       if ! bkmarkexists $bkmark; then
+               log_fail "'$bkmarkp' does not existed."
+       fi
+
+       log_must $ZFS destroy $bkmark
+}
+
 # Return 0 if a snapshot exists; $? otherwise
 #
 # $1 - snapshot name
@@ -585,6 +631,17 @@ function snapexists
        return $?
 }
 
+#
+# Return 0 if a bookmark exists; $? otherwise
+#
+# $1 - bookmark name
+#
+function bkmarkexists
+{
+       $ZFS list -H -t bookmark "$1" > /dev/null 2>&1
+       return $?
+}
+
 #
 # Set a property to a certain value on a dataset.
 # Sets a property of the dataset to the value as passed in.
index dbac85402c2d508ffd0dba54c72a74243febaaf0..e62482d3fb08b3bd004f7ece14cad46f6f80465d 100755 (executable)
@@ -34,7 +34,7 @@
 # correct property value.
 #
 # STRATEGY:
-# 1. Create pool, filesystem, volume and snapshot.
+# 1. Create pool, filesystem, volume, snapshot, and bookmark.
 # 2. Setting valid parameter, 'zfs get' should succeed.
 # 3. Compare the output property name with the original input property.
 #
@@ -65,6 +65,9 @@ typeset all_props=("${zfs_props[@]}" "${userquota_props[@]}")
 typeset dataset=($TESTPOOL/$TESTCTR $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL \
        $TESTPOOL/$TESTFS@$TESTSNAP $TESTPOOL/$TESTVOL@$TESTSNAP)
 
+typeset bookmark_props=(creation)
+typeset bookmark=($TESTPOOL/$TESTFS#$TESTBKMARK $TESTPOOL/$TESTVOL#$TESTBKMARK)
+
 #
 # According to dataset and option, checking if 'zfs get' return correct
 # property information.
@@ -111,6 +114,10 @@ log_onexit cleanup
 create_snapshot $TESTPOOL/$TESTFS $TESTSNAP
 create_snapshot $TESTPOOL/$TESTVOL $TESTSNAP
 
+# Create filesystem and volume's bookmark
+create_bookmark $TESTPOOL/$TESTFS $TESTSNAP $TESTBKMARK
+create_bookmark $TESTPOOL/$TESTVOL $TESTSNAP $TESTBKMARK
+
 typeset -i i=0
 while ((i < ${#dataset[@]})); do
        for opt in "${options[@]}"; do
@@ -127,5 +134,21 @@ while ((i < ${#dataset[@]})); do
        ((i += 1))
 done
 
+i=0
+while ((i < ${#bookmark[@]})); do
+       for opt in "${options[@]}"; do
+               for prop in ${bookmark_props[@]}; do
+                       eval "$ZFS get $opt $prop ${bookmark[i]} > \
+                           $TESTDIR/$TESTFILE0"
+                       ret=$?
+                       if [[ $ret != 0 ]]; then
+                               log_fail "$ZFS get returned: $ret"
+                       fi
+                       check_return_value ${bookmark[i]} "$prop" "$opt"
+               done
+       done
+       ((i += 1))
+done
+
 log_pass "Setting the valid options to dataset, it should succeed and return " \
     "valid value. 'zfs get' pass."
index c77f769de118a5cecfd20316cbda436814e8b0cf..bc4ca2a434f771dd090f14946f68a16063aa3ca2 100755 (executable)
@@ -67,6 +67,9 @@ val_props_str="$val_props_str -a -d"
 inval_opts_str=$(gen_option_str "${inval_opts[*]}" "-" "" $opt_numb)
 inval_props_str=$(gen_option_str "${inval_props[*]}" "" "," $prop_numb)
 
+typeset val_bookmark_props=(creation)
+typeset bookmark=($TESTPOOL/$TESTFS#$TESTBKMARK $TESTPOOL/$TESTVOL#$TESTBKMARK)
+
 #
 # Test different options and properties combination.
 #
@@ -92,6 +95,31 @@ function test_options
        done
 }
 
+#
+# Test different options and properties combination for bookmarks.
+#
+# $1 options
+# $2 properties
+#
+function test_options_bookmarks
+{
+       typeset opts=$1
+       typeset props=$2
+
+       for dst in ${bookmark[@]}; do
+               for opt in $opts; do
+                       for prop in $props; do
+                               $ZFS get $opt -- $prop $dst > /dev/null 2>&1
+                               ret=$?
+                               if [[ $ret == 0 ]]; then
+                                       log_fail "$ZFS get $opt -- $prop " \
+                                           "$dst unexpectedly succeeded."
+                               fi
+                       done
+               done
+       done
+}
+
 log_assert "Setting the invalid option and properties, 'zfs get' should be \
     failed."
 log_onexit cleanup
@@ -100,13 +128,20 @@ log_onexit cleanup
 create_snapshot $TESTPOOL/$TESTFS $TESTSNAP
 create_snapshot $TESTPOOL/$TESTVOL $TESTSNAP
 
+# Create filesystem and volume's bookmark
+create_bookmark $TESTPOOL/$TESTFS $TESTSNAP $TESTBKMARK
+create_bookmark $TESTPOOL/$TESTVOL $TESTSNAP $TESTBKMARK
+
 log_note "Valid options + invalid properties, 'zfs get' should fail."
 test_options "$val_opts_str" "$inval_props_str"
+test_options_bookmark "$val_opts_str" "$inval_props_str"
 
 log_note "Invalid options + valid properties, 'zfs get' should fail."
 test_options "$inval_opts_str" "$val_props_str"
+test_options_bookmark "$inval_opts_str" "$val_bookmark_props"
 
 log_note "Invalid options + invalid properties, 'zfs get' should fail."
 test_options "$inval_opts_str" "$inval_props_str"
+test_options_bookmarks "$inval_opts_str" "$inval_props_str"
 
 log_pass "Setting the invalid options to dataset, 'zfs get' pass."
index af1b5681af617583b4a21cfa5a232417dce6b3be..9d54625623157582998fee427b811c6cbaef5916 100755 (executable)
@@ -33,7 +33,7 @@
 # Verify "-d <n>" can work with other options
 #
 # STRATEGY:
-# 1. Create pool, filesystem, dataset, volume and snapshot.
+# 1. Create pool, filesystem, dataset, volume, snapshot, and bookmark.
 # 2. Getting an -d option, other options and properties random combination.
 # 3. Using the combination as the parameters of 'zfs get' to check the
 # command line return value.
@@ -61,6 +61,9 @@ fi
 set -A dataset $TESTPOOL/$TESTCTR $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL \
        $TESTPOOL/$TESTFS@$TESTSNAP $TESTPOOL/$TESTVOL@$TESTSNAP
 
+set -A bookmark_props creation
+set -A bookmark $TESTPOOL/$TESTFS#$TESTBKMARK $TESTPOOL/$TESTVOL#$TESTBKMARK
+
 log_assert "Verify '-d <n>' can work with other options"
 log_onexit cleanup
 
@@ -68,6 +71,10 @@ log_onexit cleanup
 create_snapshot $TESTPOOL/$TESTFS $TESTSNAP
 create_snapshot $TESTPOOL/$TESTVOL $TESTSNAP
 
+# Create filesystem and volume's bookmark
+create_bookmark $TESTPOOL/$TESTFS $TESTSNAP $TESTBKMARK
+create_bookmark $TESTPOOL/$TESTVOL $TESTSNAP $TESTBKMARK
+
 typeset -i opt_numb=16
 typeset -i prop_numb=16
 typeset -i i=0
@@ -87,5 +94,15 @@ for dst in ${dataset[@]}; do
        done
 done
 
+for dst in ${bookmark[@]}; do
+       (( i=0 ))
+       while (( i < opt_numb )); do
+               (( item = $RANDOM % ${#options[@]} ))
+               (( depth_item = $RANDOM % ${#depth_options[@]} ))
+               log_must eval "$ZFS get -${depth_options[depth_item]} ${options[item]} $bookmark_props $dst > /dev/null 2>&1"
+               (( i += 1 ))
+       done
+done
+
 log_pass "Verify '-d <n>' can work with other options"
 
index b1978cb6c00a40b53f01589de98d7bdc3056381a..965686b935dd93bb550d8077f59da958532ad3b1 100644 (file)
@@ -83,8 +83,8 @@ function gen_option_str # $elements $prefix $separator $counter
 }
 
 #
-# Cleanup the volume snapshot and filesystem snapshot were created for
-# this test case.
+# Cleanup the volume snapshot, filesystem snapshot, volume bookmark, and
+# filesystem bookmark that were created for this test case.
 #
 function cleanup
 {
@@ -93,5 +93,10 @@ function cleanup
        datasetexists $TESTPOOL/$TESTFS@$TESTSNAP && \
                destroy_snapshot $TESTPOOL/$TESTFS@$TESTSNAP
 
+       bkmarkexists $TESTPOOL/$TESTVOL#$TESTBKMARK && \
+               destroy_bookmark $TESTPOOL/$TESTVOL#$TESTBKMARK
+       bkmarkexists $TESTPOOL/$TESTFS#$TESTBKMARK && \
+               destroy_bookmark $TESTPOOL/$TESTFS#$TESTBKMARK
+
        [[ -e $TESTFILE0 ]] && log_must $RM $TESTFILE0
 }