PSARC/2007/121 zfs set copies
authorahrens
Fri, 16 Mar 2007 00:42:33 -0700
changeset 3835 063f0749804a
parent 3834 c868e50ecaba
child 3836 716c62490510
PSARC/2007/121 zfs set copies 6459491 want 'zfs set copies=' to use ditto blocks for user data
usr/src/common/zfs/zfs_prop.c
usr/src/lib/libzfs/common/libzfs_dataset.c
usr/src/uts/common/fs/zfs/dbuf.c
usr/src/uts/common/fs/zfs/dmu.c
usr/src/uts/common/fs/zfs/dmu_objset.c
usr/src/uts/common/fs/zfs/sys/dmu.h
usr/src/uts/common/fs/zfs/sys/dmu_objset.h
usr/src/uts/common/sys/fs/zfs.h
--- a/usr/src/common/zfs/zfs_prop.c	Fri Mar 16 00:25:23 2007 -0700
+++ b/usr/src/common/zfs/zfs_prop.c	Fri Mar 16 00:42:33 2007 -0700
@@ -176,6 +176,9 @@
 	    "on | off", "XATTR", B_TRUE, B_TRUE },
 	{ "numclones", prop_type_number,	0,	NULL,	prop_readonly,
 	    ZFS_TYPE_SNAPSHOT, NULL, NULL, B_FALSE, B_FALSE },
+	{ "copies",	prop_type_index,	1,	"1",	prop_inherit,
+	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
+	    "1 | 2 | 3", "COPIES", B_TRUE, B_TRUE },
 };
 
 #define	ZFS_PROP_COUNT	((sizeof (zfs_prop_table))/(sizeof (prop_desc_t)))
@@ -361,6 +364,13 @@
 	{ NULL }
 };
 
+static zfs_index_t copies_table[] = {
+	{ "1",	1 },
+	{ "2",	2 },
+	{ "3",	3 },
+	{ NULL }
+};
+
 static zfs_index_t *
 zfs_prop_index_table(zfs_prop_t prop)
 {
@@ -375,6 +385,8 @@
 		return (acl_mode_table);
 	case ZFS_PROP_ACLINHERIT:
 		return (acl_inherit_table);
+	case ZFS_PROP_COPIES:
+		return (copies_table);
 	default:
 		return (NULL);
 	}
--- a/usr/src/lib/libzfs/common/libzfs_dataset.c	Fri Mar 16 00:25:23 2007 -0700
+++ b/usr/src/lib/libzfs/common/libzfs_dataset.c	Fri Mar 16 00:42:33 2007 -0700
@@ -1537,6 +1537,7 @@
 	case ZFS_PROP_SNAPDIR:
 	case ZFS_PROP_ACLMODE:
 	case ZFS_PROP_ACLINHERIT:
+	case ZFS_PROP_COPIES:
 		val = getprop_uint64(zhp, prop, &source);
 		verify(zfs_prop_index_to_string(prop, val, &strval) == 0);
 		(void) strlcpy(propbuf, strval, proplen);
--- a/usr/src/uts/common/fs/zfs/dbuf.c	Fri Mar 16 00:25:23 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/dbuf.c	Fri Mar 16 00:42:33 2007 -0700
@@ -2094,7 +2094,7 @@
 		    os->os_dsl_dataset, db->db_blkptr, zio, tx);
 
 	dr->dr_zio = arc_write(zio, os->os_spa, checksum, compress,
-	    dmu_get_replication_level(os->os_spa, &zb, dn->dn_type), txg,
+	    dmu_get_replication_level(os, &zb, dn->dn_type), txg,
 	    db->db_blkptr, data, dbuf_write_ready, dbuf_write_done, db,
 	    ZIO_PRIORITY_ASYNC_WRITE, zio_flags, &zb);
 }
--- a/usr/src/uts/common/fs/zfs/dmu.c	Fri Mar 16 00:25:23 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/dmu.c	Fri Mar 16 00:42:33 2007 -0700
@@ -797,7 +797,7 @@
 	zio = arc_write(pio, os->os_spa,
 	    zio_checksum_select(db->db_dnode->dn_checksum, os->os_checksum),
 	    zio_compress_select(db->db_dnode->dn_compress, os->os_compress),
-	    dmu_get_replication_level(os->os_spa, &zb, db->db_dnode->dn_type),
+	    dmu_get_replication_level(os, &zb, db->db_dnode->dn_type),
 	    txg, bp, dr->dt.dl.dr_data, NULL, dmu_sync_done, in,
 	    ZIO_PRIORITY_SYNC_WRITE, zio_flags, &zb);
 
@@ -854,22 +854,19 @@
 	dnode_rele(dn, FTAG);
 }
 
-/*
- * XXX - eventually, this should take into account per-dataset (or
- *       even per-object?) user requests for higher levels of replication.
- */
 int
-dmu_get_replication_level(spa_t *spa, zbookmark_t *zb, dmu_object_type_t ot)
+dmu_get_replication_level(objset_impl_t *os,
+    zbookmark_t *zb, dmu_object_type_t ot)
 {
-	int ncopies = 1;
+	int ncopies = os->os_copies;
 
-	if (dmu_ot[ot].ot_metadata)
+	/* If it's the mos, it should have max copies set. */
+	ASSERT(zb->zb_objset != 0 ||
+	    ncopies == spa_max_replication(os->os_spa));
+
+	if (dmu_ot[ot].ot_metadata || zb->zb_level != 0)
 		ncopies++;
-	if (zb->zb_level != 0)
-		ncopies++;
-	if (zb->zb_objset == 0 && zb->zb_object == 0)
-		ncopies++;
-	return (MIN(ncopies, spa_max_replication(spa)));
+	return (MIN(ncopies, spa_max_replication(os->os_spa)));
 }
 
 int
--- a/usr/src/uts/common/fs/zfs/dmu_objset.c	Fri Mar 16 00:25:23 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/dmu_objset.c	Fri Mar 16 00:42:33 2007 -0700
@@ -117,6 +117,20 @@
 	osi->os_compress = zio_compress_select(newval, ZIO_COMPRESS_ON_VALUE);
 }
 
+static void
+copies_changed_cb(void *arg, uint64_t newval)
+{
+	objset_impl_t *osi = arg;
+
+	/*
+	 * Inheritance and range checking should have been done by now.
+	 */
+	ASSERT(newval > 0);
+	ASSERT(newval <= spa_max_replication(osi->os_spa));
+
+	osi->os_copies = newval;
+}
+
 void
 dmu_objset_byteswap(void *buf, size_t size)
 {
@@ -178,6 +192,9 @@
 		if (err == 0)
 			err = dsl_prop_register(ds, "compression",
 			    compression_changed_cb, osi);
+		if (err == 0)
+			err = dsl_prop_register(ds, "copies",
+			    copies_changed_cb, osi);
 		if (err) {
 			VERIFY(arc_buf_remove_ref(osi->os_phys_buf,
 			    &osi->os_phys_buf) == 1);
@@ -188,6 +205,7 @@
 		/* It's the meta-objset. */
 		osi->os_checksum = ZIO_CHECKSUM_FLETCHER_4;
 		osi->os_compress = ZIO_COMPRESS_LZJB;
+		osi->os_copies = spa_max_replication(spa);
 	}
 
 	osi->os_zil = zil_alloc(&osi->os, &osi->os_phys->os_zil_header);
@@ -348,6 +366,8 @@
 		    checksum_changed_cb, osi));
 		VERIFY(0 == dsl_prop_unregister(ds, "compression",
 		    compression_changed_cb, osi));
+		VERIFY(0 == dsl_prop_unregister(ds, "copies",
+		    copies_changed_cb, osi));
 	}
 
 	/*
@@ -767,7 +787,7 @@
 		    os->os_rootbp, pio, tx);
 	zio = arc_write(pio, os->os_spa, os->os_md_checksum,
 	    os->os_md_compress,
-	    dmu_get_replication_level(os->os_spa, &zb, DMU_OT_OBJSET),
+	    dmu_get_replication_level(os, &zb, DMU_OT_OBJSET),
 	    tx->tx_txg, os->os_rootbp, os->os_phys_buf, ready, killer, os,
 	    ZIO_PRIORITY_ASYNC_WRITE, zio_flags, &zb);
 
--- a/usr/src/uts/common/fs/zfs/sys/dmu.h	Fri Mar 16 00:25:23 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/dmu.h	Fri Mar 16 00:42:33 2007 -0700
@@ -60,6 +60,7 @@
 struct zbookmark;
 struct spa;
 struct nvlist;
+struct objset_impl;
 
 typedef struct objset objset_t;
 typedef struct dmu_tx dmu_tx_t;
@@ -280,7 +281,7 @@
  * Decide how many copies of a given block we should make.  Can be from
  * 1 to SPA_DVAS_PER_BP.
  */
-int dmu_get_replication_level(struct spa *spa, struct zbookmark *zb,
+int dmu_get_replication_level(struct objset_impl *, struct zbookmark *zb,
     dmu_object_type_t ot);
 /*
  * The bonus data is accessed more or less like a regular buffer.
--- a/usr/src/uts/common/fs/zfs/sys/dmu_objset.h	Fri Mar 16 00:25:23 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/dmu_objset.h	Fri Mar 16 00:42:33 2007 -0700
@@ -68,6 +68,7 @@
 	objset_t os;
 	uint8_t os_checksum;	/* can change, under dsl_dir's locks */
 	uint8_t os_compress;	/* can change, under dsl_dir's locks */
+	uint8_t os_copies;	/* can change, under dsl_dir's locks */
 	uint8_t os_md_checksum;
 	uint8_t os_md_compress;
 
--- a/usr/src/uts/common/sys/fs/zfs.h	Fri Mar 16 00:25:23 2007 -0700
+++ b/usr/src/uts/common/sys/fs/zfs.h	Fri Mar 16 00:42:33 2007 -0700
@@ -93,7 +93,8 @@
 	ZFS_PROP_SHAREISCSI,
 	ZFS_PROP_ISCSIOPTIONS,		/* not exposed to the user */
 	ZFS_PROP_XATTR,
-	ZFS_PROP_NUMCLONES		/* not exposed to the user */
+	ZFS_PROP_NUMCLONES,		/* not exposed to the user */
+	ZFS_PROP_COPIES
 } zfs_prop_t;
 
 #define	ZFS_PROP_VALUE		"value"