usr/src/uts/common/fs/zfs/zfs_ioctl.c
changeset 5367 c40abbe796be
parent 5331 3047ad28a67b
child 5375 c682f8c5f5e3
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c	Mon Oct 29 16:16:37 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c	Mon Oct 29 17:12:17 2007 -0700
@@ -345,7 +345,7 @@
 	if (!INGLOBALZONE(curproc))
 		return (EPERM);
 
-	if (secpolicy_nfs(CRED()) == 0) {
+	if (secpolicy_nfs(cr) == 0) {
 		return (0);
 	} else {
 		vnode_t *vp;
@@ -477,7 +477,7 @@
 
 		rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER);
 		error = dsl_dataset_open_obj(dd->dd_pool,
-		    dd->dd_phys->dd_clone_parent_obj, NULL,
+		    dd->dd_phys->dd_origin_obj, NULL,
 		    DS_MODE_NONE, FTAG, &pclone);
 		rw_exit(&dd->dd_pool->dp_config_rwlock);
 		if (error) {
@@ -1083,6 +1083,17 @@
 	return (error);
 }
 
+/*
+ * inputs:
+ * zc_name		name of filesystem
+ * zc_nvlist_dst_size	size of buffer for property nvlist
+ *
+ * outputs:
+ * zc_objset_stats	stats
+ * zc_nvlist_dst	property nvlist
+ * zc_nvlist_dst_size	size of property nvlist
+ * zc_value		alternate root
+ */
 static int
 zfs_ioc_objset_stats(zfs_cmd_t *zc)
 {
@@ -1133,6 +1144,19 @@
 	return (error);
 }
 
+/*
+ * inputs:
+ * zc_name		name of filesystem
+ * zc_cookie		zap cursor
+ * zc_nvlist_dst_size	size of buffer for property nvlist
+ *
+ * outputs:
+ * zc_name		name of next filesystem
+ * zc_objset_stats	stats
+ * zc_nvlist_dst	property nvlist
+ * zc_nvlist_dst_size	size of property nvlist
+ * zc_value		alternate root
+ */
 static int
 zfs_ioc_objset_version(zfs_cmd_t *zc)
 {
@@ -1226,6 +1250,19 @@
 	return (error);
 }
 
+/*
+ * inputs:
+ * zc_name		name of filesystem
+ * zc_cookie		zap cursor
+ * zc_nvlist_dst_size	size of buffer for property nvlist
+ *
+ * outputs:
+ * zc_name		name of next snapshot
+ * zc_objset_stats	stats
+ * zc_nvlist_dst	property nvlist
+ * zc_nvlist_dst_size	size of property nvlist
+ * zc_value		alternate root
+ */
 static int
 zfs_ioc_snapshot_list_next(zfs_cmd_t *zc)
 {
@@ -1270,6 +1307,10 @@
 	if (error == 0)
 		error = zfs_ioc_objset_stats(zc); /* fill in the stats */
 
+	/* if we failed, undo the @ that we tacked on to zc_name */
+	if (error != 0)
+		*strchr(zc->zc_name, '@') = '\0';
+
 	dmu_objset_close(os);
 	return (error);
 }
@@ -1435,6 +1476,14 @@
 	return (0);
 }
 
+/*
+ * inputs:
+ * zc_name		name of filesystem
+ * zc_value		name of property to inherit
+ * zc_nvlist_src{_size}	nvlist of properties to apply
+ *
+ * outputs:		none
+ */
 static int
 zfs_ioc_set_prop(zfs_cmd_t *zc)
 {
@@ -1451,6 +1500,13 @@
 	return (error);
 }
 
+/*
+ * inputs:
+ * zc_name		name of filesystem
+ * zc_value		name of property to inherit
+ *
+ * outputs:		none
+ */
 static int
 zfs_ioc_inherit_prop(zfs_cmd_t *zc)
 {
@@ -1553,6 +1609,14 @@
 	return (error);
 }
 
+/*
+ * inputs:
+ * zc_name		name of filesystem
+ * zc_nvlist_src{_size}	nvlist of delegated permissions
+ * zc_perm_action	allow/unallow flag
+ *
+ * outputs:		none
+ */
 static int
 zfs_ioc_set_fsacl(zfs_cmd_t *zc)
 {
@@ -1595,6 +1659,13 @@
 	return (error);
 }
 
+/*
+ * inputs:
+ * zc_name		name of filesystem
+ *
+ * outputs:
+ * zc_nvlist_src{_size}	nvlist of delegated permissions
+ */
 static int
 zfs_ioc_get_fsacl(zfs_cmd_t *zc)
 {
@@ -1609,12 +1680,24 @@
 	return (error);
 }
 
+/*
+ * inputs:
+ * zc_name		name of volume
+ *
+ * outputs:		none
+ */
 static int
 zfs_ioc_create_minor(zfs_cmd_t *zc)
 {
 	return (zvol_create_minor(zc->zc_name, ddi_driver_major(zfs_dip)));
 }
 
+/*
+ * inputs:
+ * zc_name		name of volume
+ *
+ * outputs:		none
+ */
 static int
 zfs_ioc_remove_minor(zfs_cmd_t *zc)
 {
@@ -1809,6 +1892,15 @@
 	return (0);
 }
 
+/*
+ * inputs:
+ * zc_objset_type	type of objset to create (fs vs zvol)
+ * zc_name		name of new objset
+ * zc_value		name of snapshot to clone from (may be empty)
+ * zc_nvlist_src{_size}	nvlist of properties to apply
+ *
+ * outputs:		none
+ */
 static int
 zfs_ioc_create(zfs_cmd_t *zc)
 {
@@ -1973,6 +2065,14 @@
 	return (error);
 }
 
+/*
+ * inputs:
+ * zc_name	name of filesystem
+ * zc_value	short name of snapshot
+ * zc_cookie	recursive flag
+ *
+ * outputs:	none
+ */
 static int
 zfs_ioc_snapshot(zfs_cmd_t *zc)
 {
@@ -2022,6 +2122,13 @@
 	return (0);
 }
 
+/*
+ * inputs:
+ * zc_name	name of filesystem
+ * zc_value	short name of snapshot
+ *
+ * outputs:	none
+ */
 static int
 zfs_ioc_destroy_snaps(zfs_cmd_t *zc)
 {
@@ -2036,6 +2143,13 @@
 	return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value));
 }
 
+/*
+ * inputs:
+ * zc_name		name of dataset to destroy
+ * zc_objset_type	type of objset
+ *
+ * outputs:		none
+ */
 static int
 zfs_ioc_destroy(zfs_cmd_t *zc)
 {
@@ -2048,12 +2162,26 @@
 	return (dmu_objset_destroy(zc->zc_name));
 }
 
+/*
+ * inputs:
+ * zc_name	name of snapshot to roll back to
+ *
+ * outputs:	none
+ */
 static int
 zfs_ioc_rollback(zfs_cmd_t *zc)
 {
 	return (dmu_objset_rollback(zc->zc_name));
 }
 
+/*
+ * inputs:
+ * zc_name	old name of dataset
+ * zc_value	new name of dataset
+ * zc_cookie	recursive flag (only valid for snapshots)
+ *
+ * outputs:	none
+ */
 static int
 zfs_ioc_rename(zfs_cmd_t *zc)
 {
@@ -2079,38 +2207,64 @@
 	return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive));
 }
 
+/*
+ * inputs:
+ * zc_name		name of containing filesystem
+ * zc_nvlist_src{_size}	nvlist of properties to apply
+ * zc_value		name of snapshot to create
+ * zc_string		name of clone origin (if DRR_FLAG_CLONE)
+ * zc_cookie		file descriptor to recv from
+ * zc_begin_record	the BEGIN record of the stream (not byteswapped)
+ * zc_guid		force flag
+ *
+ * outputs:
+ * zc_cookie		number of bytes read
+ */
 static int
-zfs_ioc_recvbackup(zfs_cmd_t *zc)
+zfs_ioc_recv(zfs_cmd_t *zc)
 {
 	file_t *fp;
-	offset_t new_off;
 	objset_t *os;
+	dmu_recv_cookie_t drc;
 	zfsvfs_t *zfsvfs = NULL;
-	char *cp;
-	char cosname[MAXNAMELEN];
 	boolean_t force = (boolean_t)zc->zc_guid;
 	int error, fd;
+	offset_t off;
+	nvlist_t *props = NULL;
+	objset_t *origin = NULL;
+	char *tosnap;
+	char tofs[ZFS_MAXNAMELEN];
 
 	if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
 	    strchr(zc->zc_value, '@') == NULL ||
 	    strchr(zc->zc_value, '%'))
 		return (EINVAL);
 
+	(void) strcpy(tofs, zc->zc_value);
+	tosnap = strchr(tofs, '@');
+	*tosnap = '\0';
+	tosnap++;
+
+	if (zc->zc_nvlist_src != NULL &&
+	    (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
+	    &props)) != 0)
+		return (error);
+
 	fd = zc->zc_cookie;
 	fp = getf(fd);
-	if (fp == NULL)
+	if (fp == NULL) {
+		nvlist_free(props);
 		return (EBADF);
+	}
 
 	/*
 	 * Get the zfsvfs for the receiving objset. There
 	 * won't be one if we're operating on a zvol, if the
 	 * objset doesn't exist yet, or is not mounted.
 	 */
-	cp = strchr(zc->zc_value, '@');
-	*cp = '\0';
-	error = dmu_objset_open(zc->zc_value, DMU_OST_ANY,
+
+	error = dmu_objset_open(tofs, DMU_OST_ANY,
 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
-	*cp = '@';
 	if (!error) {
 		if (dmu_objset_type(os) == DMU_OST_ZFS) {
 			mutex_enter(&os->os->os_user_ptr_lock);
@@ -2122,60 +2276,111 @@
 		dmu_objset_close(os);
 	}
 
-	error = dmu_recvbackup(zc->zc_value, &zc->zc_begin_record,
-	    &zc->zc_cookie, force, zfsvfs != NULL, fp->f_vnode,
-	    fp->f_offset, cosname);
+	if (zc->zc_string[0]) {
+		error = dmu_objset_open(zc->zc_string, DMU_OST_ANY,
+		    DS_MODE_STANDARD | DS_MODE_READONLY, &origin);
+		if (error) {
+			if (zfsvfs != NULL)
+				VFS_RELE(zfsvfs->z_vfs);
+			nvlist_free(props);
+			releasef(fd);
+			return (error);
+		}
+	}
+
+	error = dmu_recv_begin(tofs, tosnap, &zc->zc_begin_record,
+	    force, origin, zfsvfs != NULL, &drc);
+	if (origin)
+		dmu_objset_close(origin);
+	if (error) {
+		if (zfsvfs != NULL)
+			VFS_RELE(zfsvfs->z_vfs);
+		nvlist_free(props);
+		releasef(fd);
+		return (error);
+	}
 
 	/*
-	 * For incremental snapshots where we created a
-	 * temporary clone, we now swap zfsvfs::z_os with
-	 * the newly created and received "cosname".
+	 * If properties are supplied, they are to completely replace
+	 * the existing ones; "inherit" any existing properties.
 	 */
-	if (!error && zfsvfs != NULL) {
-		char osname[MAXNAMELEN];
-		int mode;
-
-		error = zfs_suspend_fs(zfsvfs, osname, &mode);
-		if (!error) {
-			int swap_err;
-			int snap_err = 0;
-
-			swap_err = dsl_dataset_clone_swap(cosname, force);
-			if (!swap_err) {
-				char *cp = strrchr(zc->zc_value, '@');
-
-				*cp = '\0';
-				snap_err = dmu_replay_end_snapshot(zc->zc_value,
-				    &zc->zc_begin_record);
-				*cp = '@';
+	if (props) {
+		objset_t *os;
+		nvlist_t *nv = NULL;
+
+		error = dmu_objset_open(tofs, DMU_OST_ANY,
+		    DS_MODE_STANDARD | DS_MODE_READONLY | DS_MODE_INCONSISTENT,
+		    &os);
+		if (error == 0) {
+			error = dsl_prop_get_all(os, &nv);
+			dmu_objset_close(os);
+		}
+		if (error == 0) {
+			nvpair_t *elem;
+			zfs_cmd_t zc2 = { 0 };
+
+			(void) strcpy(zc2.zc_name, tofs);
+			for (elem = nvlist_next_nvpair(nv, NULL); elem;
+			    elem = nvlist_next_nvpair(nv, elem)) {
+				(void) strcpy(zc2.zc_value, nvpair_name(elem));
+				if (zfs_secpolicy_inherit(&zc2, CRED()) == 0)
+					(void) zfs_ioc_inherit_prop(&zc2);
 			}
-			error = zfs_resume_fs(zfsvfs, osname, mode);
-			if (!error)
-				error = swap_err;
-			if (!error)
-				error = snap_err;
 		}
-
-		/* destroy the clone we created */
-		(void) dmu_objset_destroy(cosname);
+		if (nv)
+			nvlist_free(nv);
+	}
+
+	/*
+	 * Set properties.  Note, we ignore errors.  Would be better to
+	 * do best-effort in zfs_set_prop_nvlist, too.
+	 */
+	(void) zfs_set_prop_nvlist(tofs, props);
+	nvlist_free(props);
+
+	off = fp->f_offset;
+	error = dmu_recv_stream(&drc, fp->f_vnode, &off);
+
+	if (error == 0) {
+		if (zfsvfs != NULL) {
+			char osname[MAXNAMELEN];
+			int mode;
+
+			(void) zfs_suspend_fs(zfsvfs, osname, &mode);
+			error = dmu_recv_end(&drc);
+			error |= zfs_resume_fs(zfsvfs, osname, mode);
+		} else {
+			error = dmu_recv_end(&drc);
+		}
 	}
 	if (zfsvfs != NULL)
 		VFS_RELE(zfsvfs->z_vfs);
-	new_off = fp->f_offset + zc->zc_cookie;
-	if (VOP_SEEK(fp->f_vnode, fp->f_offset, &new_off, NULL) == 0)
-		fp->f_offset = new_off;
+
+	zc->zc_cookie = off - fp->f_offset;
+	if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
+		fp->f_offset = off;
 
 	releasef(fd);
 	return (error);
 }
 
+/*
+ * inputs:
+ * zc_name	name of snapshot to send
+ * zc_value	short name of incremental fromsnap (may be empty)
+ * zc_cookie	file descriptor to send stream to
+ * zc_obj	fromorigin flag (mutually exclusive with zc_value)
+ *
+ * outputs: none
+ */
 static int
-zfs_ioc_sendbackup(zfs_cmd_t *zc)
+zfs_ioc_send(zfs_cmd_t *zc)
 {
 	objset_t *fromsnap = NULL;
 	objset_t *tosnap;
 	file_t *fp;
 	int error;
+	offset_t off;
 
 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
 	    DS_MODE_STANDARD | DS_MODE_READONLY, &tosnap);
@@ -2207,8 +2412,11 @@
 		return (EBADF);
 	}
 
-	error = dmu_sendbackup(tosnap, fromsnap, fp->f_vnode);
-
+	off = fp->f_offset;
+	error = dmu_sendbackup(tosnap, fromsnap, zc->zc_obj, fp->f_vnode, &off);
+
+	if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
+		fp->f_offset = off;
 	releasef(zc->zc_cookie);
 	if (fromsnap)
 		dmu_objset_close(fromsnap);
@@ -2313,6 +2521,13 @@
 	return (0);
 }
 
+/*
+ * inputs:
+ * zc_name	name of filesystem
+ * zc_value	name of origin snapshot
+ *
+ * outputs:	none
+ */
 static int
 zfs_ioc_promote(zfs_cmd_t *zc)
 {
@@ -2500,8 +2715,8 @@
 	{ zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE },
 	{ zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE },
 	{ zfs_ioc_rename, zfs_secpolicy_rename,	DATASET_NAME, B_TRUE },
-	{ zfs_ioc_recvbackup, zfs_secpolicy_receive, DATASET_NAME, B_TRUE },
-	{ zfs_ioc_sendbackup, zfs_secpolicy_send, DATASET_NAME, B_TRUE },
+	{ zfs_ioc_recv, zfs_secpolicy_receive, DATASET_NAME, B_TRUE },
+	{ zfs_ioc_send, zfs_secpolicy_send, DATASET_NAME, B_TRUE },
 	{ zfs_ioc_inject_fault,	zfs_secpolicy_inject, NO_NAME, B_FALSE },
 	{ zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE },
 	{ zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE },