--- a/usr/src/lib/libzfs/common/libzfs_dataset.c Fri Sep 28 11:01:47 2007 -0700
+++ b/usr/src/lib/libzfs/common/libzfs_dataset.c Fri Sep 28 15:53:20 2007 -0700
@@ -1788,6 +1788,7 @@
get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
char **source, uint64_t *val)
{
+ zfs_cmd_t zc = { 0 };
struct mnttab mnt;
char *mntopt_on = NULL;
char *mntopt_off = NULL;
@@ -1900,6 +1901,18 @@
*val = zhp->zfs_dmustats.dds_num_clones;
break;
+ case ZFS_PROP_VERSION:
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+ if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_VERSION, &zc) ||
+ (zc.zc_cookie == 0)) {
+ zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
+ "unable to get version property"));
+ return (zfs_error(zhp->zfs_hdl, EZFS_BADVERSION,
+ dgettext(TEXT_DOMAIN, "internal error")));
+ }
+ *val = zc.zc_cookie;
+ break;
+
default:
switch (zfs_prop_get_type(prop)) {
case PROP_TYPE_NUMBER:
--- a/usr/src/uts/common/fs/zfs/dmu_objset.c Fri Sep 28 11:01:47 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/dmu_objset.c Fri Sep 28 15:53:20 2007 -0700
@@ -177,7 +177,8 @@
return (err);
}
osi->os_phys = osi->os_phys_buf->b_data;
- arc_release(osi->os_phys_buf, &osi->os_phys_buf);
+ if (ds == NULL || dsl_dataset_is_snapshot(ds) == 0)
+ arc_release(osi->os_phys_buf, &osi->os_phys_buf);
} else {
osi->os_phys_buf = arc_buf_alloc(spa, sizeof (objset_phys_t),
&osi->os_phys_buf, ARC_BUFC_METADATA);
--- a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h Fri Sep 28 11:01:47 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h Fri Sep 28 15:53:20 2007 -0700
@@ -257,7 +257,7 @@
extern int zfs_create_op_tables();
extern int zfs_sync(vfs_t *vfsp, short flag, cred_t *cr);
extern dev_t zfs_cmpldev(uint64_t);
-extern int zfs_get_stats(objset_t *os, nvlist_t *nv);
+extern int zfs_get_version(objset_t *os, uint64_t *version);
extern int zfs_set_version(const char *name, uint64_t newvers);
extern void zfs_log_create(zilog_t *zilog, dmu_tx_t *tx, int txtype,
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c Fri Sep 28 11:01:47 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c Fri Sep 28 15:53:20 2007 -0700
@@ -1093,7 +1093,7 @@
(error = dsl_prop_get_all(os, &nv)) == 0) {
dmu_objset_stats(os, nv);
/*
- * NB: {zpl,zvol}_get_stats() will read the objset contents,
+ * NB: zvol_get_stats() will read the objset contents,
* which we aren't supposed to do with a
* DS_MODE_STANDARD open, because it could be
* inconsistent. So this is a bit of a workaround...
@@ -1101,8 +1101,6 @@
if (!zc->zc_objset_stats.dds_inconsistent) {
if (dmu_objset_type(os) == DMU_OST_ZVOL)
VERIFY(zvol_get_stats(os, nv) == 0);
- else if (dmu_objset_type(os) == DMU_OST_ZFS)
- (void) zfs_get_stats(os, nv);
}
error = put_nvlist(zc, nv);
nvlist_free(nv);
@@ -1115,6 +1113,47 @@
}
static int
+zfs_ioc_objset_version(zfs_cmd_t *zc)
+{
+ objset_t *os = NULL;
+ int error;
+
+retry:
+ error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
+ DS_MODE_STANDARD | DS_MODE_READONLY, &os);
+ if (error != 0) {
+ /*
+ * This is ugly: dmu_objset_open() can return EBUSY if
+ * the objset is held exclusively. Fortunately this hold is
+ * only for a short while, so we retry here.
+ * This avoids user code having to handle EBUSY,
+ * for example for a "zfs list".
+ */
+ if (error == EBUSY) {
+ delay(1);
+ goto retry;
+ }
+ return (error);
+ }
+
+ dmu_objset_fast_stat(os, &zc->zc_objset_stats);
+
+ /*
+ * NB: zfs_get_version() will read the objset contents,
+ * which we aren't supposed to do with a
+ * DS_MODE_STANDARD open, because it could be
+ * inconsistent. So this is a bit of a workaround...
+ */
+ zc->zc_cookie = 0;
+ if (!zc->zc_objset_stats.dds_inconsistent)
+ if (dmu_objset_type(os) == DMU_OST_ZFS)
+ (void) zfs_get_version(os, &zc->zc_cookie);
+
+ dmu_objset_close(os);
+ return (0);
+}
+
+static int
zfs_ioc_dataset_list_next(zfs_cmd_t *zc)
{
objset_t *os;
@@ -2087,6 +2126,7 @@
{ zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE },
{ zfs_ioc_vdev_setpath, zfs_secpolicy_config, POOL_NAME, B_FALSE },
{ zfs_ioc_objset_stats, zfs_secpolicy_read, DATASET_NAME, B_FALSE },
+ { zfs_ioc_objset_version, zfs_secpolicy_read, DATASET_NAME, B_FALSE },
{ zfs_ioc_dataset_list_next, zfs_secpolicy_read,
DATASET_NAME, B_FALSE },
{ zfs_ioc_snapshot_list_next, zfs_secpolicy_read,
--- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c Fri Sep 28 11:01:47 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c Fri Sep 28 15:53:20 2007 -0700
@@ -1322,15 +1322,11 @@
}
int
-zfs_get_stats(objset_t *os, nvlist_t *nv)
+zfs_get_version(objset_t *os, uint64_t *version)
{
int error;
- uint64_t val;
- error = zap_lookup(os, MASTER_NODE_OBJ, ZPL_VERSION_STR, 8, 1, &val);
- if (error == 0)
- dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_VERSION, val);
-
+ error = zap_lookup(os, MASTER_NODE_OBJ, ZPL_VERSION_STR, 8, 1, version);
return (error);
}
--- a/usr/src/uts/common/sys/fs/zfs.h Fri Sep 28 11:01:47 2007 -0700
+++ b/usr/src/uts/common/sys/fs/zfs.h Fri Sep 28 15:53:20 2007 -0700
@@ -462,6 +462,7 @@
ZFS_IOC_VDEV_DETACH,
ZFS_IOC_VDEV_SETPATH,
ZFS_IOC_OBJSET_STATS,
+ ZFS_IOC_OBJSET_VERSION,
ZFS_IOC_DATASET_LIST_NEXT,
ZFS_IOC_SNAPSHOT_LIST_NEXT,
ZFS_IOC_SET_PROP,