1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5ea8dc4b6Seschrock * Common Development and Distribution License (the "License"). 6ea8dc4b6Seschrock * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 21fa9e4066Sahrens /* 2206e0070dSMark Shellenbaum * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23*be6fd75aSMatthew Ahrens * Copyright (c) 2013 by Delphix. All rights reserved. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 2655da60b9SMark J Musante /* Portions Copyright 2010 Robert Milkowski */ 2755da60b9SMark J Musante 28ecd6cf80Smarks #include <sys/cred.h> 29fa9e4066Sahrens #include <sys/zfs_context.h> 30fa9e4066Sahrens #include <sys/dmu_objset.h> 31fa9e4066Sahrens #include <sys/dsl_dir.h> 32fa9e4066Sahrens #include <sys/dsl_dataset.h> 33fa9e4066Sahrens #include <sys/dsl_prop.h> 34fa9e4066Sahrens #include <sys/dsl_pool.h> 351d452cf5Sahrens #include <sys/dsl_synctask.h> 36ecd6cf80Smarks #include <sys/dsl_deleg.h> 37fa9e4066Sahrens #include <sys/dnode.h> 38fa9e4066Sahrens #include <sys/dbuf.h> 39a2eea2e1Sahrens #include <sys/zvol.h> 40fa9e4066Sahrens #include <sys/dmu_tx.h> 41fa9e4066Sahrens #include <sys/zap.h> 42fa9e4066Sahrens #include <sys/zil.h> 43fa9e4066Sahrens #include <sys/dmu_impl.h> 44ecd6cf80Smarks #include <sys/zfs_ioctl.h> 450a586ceaSMark Shellenbaum #include <sys/sa.h> 4699d5e173STim Haley #include <sys/zfs_onexit.h> 473b2aab18SMatthew Ahrens #include <sys/dsl_destroy.h> 48fa9e4066Sahrens 49744947dcSTom Erickson /* 50744947dcSTom Erickson * Needed to close a window in dnode_move() that allows the objset to be freed 51744947dcSTom Erickson * before it can be safely accessed. 52744947dcSTom Erickson */ 53744947dcSTom Erickson krwlock_t os_lock; 54744947dcSTom Erickson 55744947dcSTom Erickson void 56744947dcSTom Erickson dmu_objset_init(void) 57744947dcSTom Erickson { 58744947dcSTom Erickson rw_init(&os_lock, NULL, RW_DEFAULT, NULL); 59744947dcSTom Erickson } 60744947dcSTom Erickson 61744947dcSTom Erickson void 62744947dcSTom Erickson dmu_objset_fini(void) 63744947dcSTom Erickson { 64744947dcSTom Erickson rw_destroy(&os_lock); 65744947dcSTom Erickson } 66744947dcSTom Erickson 67fa9e4066Sahrens spa_t * 68fa9e4066Sahrens dmu_objset_spa(objset_t *os) 69fa9e4066Sahrens { 70503ad85cSMatthew Ahrens return (os->os_spa); 71fa9e4066Sahrens } 72fa9e4066Sahrens 73fa9e4066Sahrens zilog_t * 74fa9e4066Sahrens dmu_objset_zil(objset_t *os) 75fa9e4066Sahrens { 76503ad85cSMatthew Ahrens return (os->os_zil); 77fa9e4066Sahrens } 78fa9e4066Sahrens 79fa9e4066Sahrens dsl_pool_t * 80fa9e4066Sahrens dmu_objset_pool(objset_t *os) 81fa9e4066Sahrens { 82fa9e4066Sahrens dsl_dataset_t *ds; 83fa9e4066Sahrens 84503ad85cSMatthew Ahrens if ((ds = os->os_dsl_dataset) != NULL && ds->ds_dir) 85fa9e4066Sahrens return (ds->ds_dir->dd_pool); 86fa9e4066Sahrens else 87503ad85cSMatthew Ahrens return (spa_get_dsl(os->os_spa)); 88fa9e4066Sahrens } 89fa9e4066Sahrens 90fa9e4066Sahrens dsl_dataset_t * 91fa9e4066Sahrens dmu_objset_ds(objset_t *os) 92fa9e4066Sahrens { 93503ad85cSMatthew Ahrens return (os->os_dsl_dataset); 94fa9e4066Sahrens } 95fa9e4066Sahrens 96fa9e4066Sahrens dmu_objset_type_t 97fa9e4066Sahrens dmu_objset_type(objset_t *os) 98fa9e4066Sahrens { 99503ad85cSMatthew Ahrens return (os->os_phys->os_type); 100fa9e4066Sahrens } 101fa9e4066Sahrens 102fa9e4066Sahrens void 103fa9e4066Sahrens dmu_objset_name(objset_t *os, char *buf) 104fa9e4066Sahrens { 105503ad85cSMatthew Ahrens dsl_dataset_name(os->os_dsl_dataset, buf); 106fa9e4066Sahrens } 107fa9e4066Sahrens 108fa9e4066Sahrens uint64_t 109fa9e4066Sahrens dmu_objset_id(objset_t *os) 110fa9e4066Sahrens { 111503ad85cSMatthew Ahrens dsl_dataset_t *ds = os->os_dsl_dataset; 112fa9e4066Sahrens 113fa9e4066Sahrens return (ds ? ds->ds_object : 0); 114fa9e4066Sahrens } 115fa9e4066Sahrens 11655da60b9SMark J Musante uint64_t 11755da60b9SMark J Musante dmu_objset_syncprop(objset_t *os) 11855da60b9SMark J Musante { 11955da60b9SMark J Musante return (os->os_sync); 12055da60b9SMark J Musante } 12155da60b9SMark J Musante 122e09fa4daSNeil Perrin uint64_t 123e09fa4daSNeil Perrin dmu_objset_logbias(objset_t *os) 124e09fa4daSNeil Perrin { 125e09fa4daSNeil Perrin return (os->os_logbias); 126e09fa4daSNeil Perrin } 127e09fa4daSNeil Perrin 128fa9e4066Sahrens static void 129fa9e4066Sahrens checksum_changed_cb(void *arg, uint64_t newval) 130fa9e4066Sahrens { 131503ad85cSMatthew Ahrens objset_t *os = arg; 132fa9e4066Sahrens 133fa9e4066Sahrens /* 134fa9e4066Sahrens * Inheritance should have been done by now. 135fa9e4066Sahrens */ 136fa9e4066Sahrens ASSERT(newval != ZIO_CHECKSUM_INHERIT); 137fa9e4066Sahrens 138503ad85cSMatthew Ahrens os->os_checksum = zio_checksum_select(newval, ZIO_CHECKSUM_ON_VALUE); 139fa9e4066Sahrens } 140fa9e4066Sahrens 141fa9e4066Sahrens static void 142fa9e4066Sahrens compression_changed_cb(void *arg, uint64_t newval) 143fa9e4066Sahrens { 144503ad85cSMatthew Ahrens objset_t *os = arg; 145fa9e4066Sahrens 146fa9e4066Sahrens /* 147fa9e4066Sahrens * Inheritance and range checking should have been done by now. 148fa9e4066Sahrens */ 149fa9e4066Sahrens ASSERT(newval != ZIO_COMPRESS_INHERIT); 150fa9e4066Sahrens 151503ad85cSMatthew Ahrens os->os_compress = zio_compress_select(newval, ZIO_COMPRESS_ON_VALUE); 152fa9e4066Sahrens } 153fa9e4066Sahrens 154d0ad202dSahrens static void 155d0ad202dSahrens copies_changed_cb(void *arg, uint64_t newval) 156d0ad202dSahrens { 157503ad85cSMatthew Ahrens objset_t *os = arg; 158d0ad202dSahrens 159d0ad202dSahrens /* 160d0ad202dSahrens * Inheritance and range checking should have been done by now. 161d0ad202dSahrens */ 162d0ad202dSahrens ASSERT(newval > 0); 163503ad85cSMatthew Ahrens ASSERT(newval <= spa_max_replication(os->os_spa)); 164d0ad202dSahrens 165503ad85cSMatthew Ahrens os->os_copies = newval; 166d0ad202dSahrens } 167d0ad202dSahrens 168b24ab676SJeff Bonwick static void 169b24ab676SJeff Bonwick dedup_changed_cb(void *arg, uint64_t newval) 170b24ab676SJeff Bonwick { 171b24ab676SJeff Bonwick objset_t *os = arg; 172b24ab676SJeff Bonwick spa_t *spa = os->os_spa; 173b24ab676SJeff Bonwick enum zio_checksum checksum; 174b24ab676SJeff Bonwick 175b24ab676SJeff Bonwick /* 176b24ab676SJeff Bonwick * Inheritance should have been done by now. 177b24ab676SJeff Bonwick */ 178b24ab676SJeff Bonwick ASSERT(newval != ZIO_CHECKSUM_INHERIT); 179b24ab676SJeff Bonwick 180b24ab676SJeff Bonwick checksum = zio_checksum_dedup_select(spa, newval, ZIO_CHECKSUM_OFF); 181b24ab676SJeff Bonwick 182b24ab676SJeff Bonwick os->os_dedup_checksum = checksum & ZIO_CHECKSUM_MASK; 183b24ab676SJeff Bonwick os->os_dedup_verify = !!(checksum & ZIO_CHECKSUM_VERIFY); 184b24ab676SJeff Bonwick } 185b24ab676SJeff Bonwick 1863baa08fcSek static void 1873baa08fcSek primary_cache_changed_cb(void *arg, uint64_t newval) 1883baa08fcSek { 189503ad85cSMatthew Ahrens objset_t *os = arg; 1903baa08fcSek 1913baa08fcSek /* 1923baa08fcSek * Inheritance and range checking should have been done by now. 1933baa08fcSek */ 1943baa08fcSek ASSERT(newval == ZFS_CACHE_ALL || newval == ZFS_CACHE_NONE || 1953baa08fcSek newval == ZFS_CACHE_METADATA); 1963baa08fcSek 197503ad85cSMatthew Ahrens os->os_primary_cache = newval; 1983baa08fcSek } 1993baa08fcSek 2003baa08fcSek static void 2013baa08fcSek secondary_cache_changed_cb(void *arg, uint64_t newval) 2023baa08fcSek { 203503ad85cSMatthew Ahrens objset_t *os = arg; 2043baa08fcSek 2053baa08fcSek /* 2063baa08fcSek * Inheritance and range checking should have been done by now. 2073baa08fcSek */ 2083baa08fcSek ASSERT(newval == ZFS_CACHE_ALL || newval == ZFS_CACHE_NONE || 2093baa08fcSek newval == ZFS_CACHE_METADATA); 2103baa08fcSek 211503ad85cSMatthew Ahrens os->os_secondary_cache = newval; 2123baa08fcSek } 2133baa08fcSek 21455da60b9SMark J Musante static void 21555da60b9SMark J Musante sync_changed_cb(void *arg, uint64_t newval) 21655da60b9SMark J Musante { 21755da60b9SMark J Musante objset_t *os = arg; 21855da60b9SMark J Musante 21955da60b9SMark J Musante /* 22055da60b9SMark J Musante * Inheritance and range checking should have been done by now. 22155da60b9SMark J Musante */ 22255da60b9SMark J Musante ASSERT(newval == ZFS_SYNC_STANDARD || newval == ZFS_SYNC_ALWAYS || 22355da60b9SMark J Musante newval == ZFS_SYNC_DISABLED); 22455da60b9SMark J Musante 22555da60b9SMark J Musante os->os_sync = newval; 22655da60b9SMark J Musante if (os->os_zil) 22755da60b9SMark J Musante zil_set_sync(os->os_zil, newval); 22855da60b9SMark J Musante } 22955da60b9SMark J Musante 230e09fa4daSNeil Perrin static void 231e09fa4daSNeil Perrin logbias_changed_cb(void *arg, uint64_t newval) 232e09fa4daSNeil Perrin { 233e09fa4daSNeil Perrin objset_t *os = arg; 234e09fa4daSNeil Perrin 235e09fa4daSNeil Perrin ASSERT(newval == ZFS_LOGBIAS_LATENCY || 236e09fa4daSNeil Perrin newval == ZFS_LOGBIAS_THROUGHPUT); 237e09fa4daSNeil Perrin os->os_logbias = newval; 238e09fa4daSNeil Perrin if (os->os_zil) 239e09fa4daSNeil Perrin zil_set_logbias(os->os_zil, newval); 240e09fa4daSNeil Perrin } 241e09fa4daSNeil Perrin 242fa9e4066Sahrens void 243fa9e4066Sahrens dmu_objset_byteswap(void *buf, size_t size) 244fa9e4066Sahrens { 245fa9e4066Sahrens objset_phys_t *osp = buf; 246fa9e4066Sahrens 24714843421SMatthew Ahrens ASSERT(size == OBJSET_OLD_PHYS_SIZE || size == sizeof (objset_phys_t)); 248fa9e4066Sahrens dnode_byteswap(&osp->os_meta_dnode); 249fa9e4066Sahrens byteswap_uint64_array(&osp->os_zil_header, sizeof (zil_header_t)); 250fa9e4066Sahrens osp->os_type = BSWAP_64(osp->os_type); 25114843421SMatthew Ahrens osp->os_flags = BSWAP_64(osp->os_flags); 25214843421SMatthew Ahrens if (size == sizeof (objset_phys_t)) { 25314843421SMatthew Ahrens dnode_byteswap(&osp->os_userused_dnode); 25414843421SMatthew Ahrens dnode_byteswap(&osp->os_groupused_dnode); 25514843421SMatthew Ahrens } 256fa9e4066Sahrens } 257fa9e4066Sahrens 258ea8dc4b6Seschrock int 259ea8dc4b6Seschrock dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp, 260503ad85cSMatthew Ahrens objset_t **osp) 261fa9e4066Sahrens { 262503ad85cSMatthew Ahrens objset_t *os; 263088f3894Sahrens int i, err; 264fa9e4066Sahrens 26591ebeef5Sahrens ASSERT(ds == NULL || MUTEX_HELD(&ds->ds_opening_lock)); 26691ebeef5Sahrens 267503ad85cSMatthew Ahrens os = kmem_zalloc(sizeof (objset_t), KM_SLEEP); 268503ad85cSMatthew Ahrens os->os_dsl_dataset = ds; 269503ad85cSMatthew Ahrens os->os_spa = spa; 270503ad85cSMatthew Ahrens os->os_rootbp = bp; 271503ad85cSMatthew Ahrens if (!BP_IS_HOLE(os->os_rootbp)) { 27213506d1eSmaybee uint32_t aflags = ARC_WAIT; 273ea8dc4b6Seschrock zbookmark_t zb; 274b24ab676SJeff Bonwick SET_BOOKMARK(&zb, ds ? ds->ds_object : DMU_META_OBJSET, 275b24ab676SJeff Bonwick ZB_ROOT_OBJECT, ZB_ROOT_LEVEL, ZB_ROOT_BLKID); 276b24ab676SJeff Bonwick 277503ad85cSMatthew Ahrens if (DMU_OS_IS_L2CACHEABLE(os)) 2783baa08fcSek aflags |= ARC_L2CACHE; 279ea8dc4b6Seschrock 280503ad85cSMatthew Ahrens dprintf_bp(os->os_rootbp, "reading %s", ""); 2811b912ec7SGeorge Wilson err = arc_read(NULL, spa, os->os_rootbp, 282503ad85cSMatthew Ahrens arc_getbuf_func, &os->os_phys_buf, 28313506d1eSmaybee ZIO_PRIORITY_SYNC_READ, ZIO_FLAG_CANFAIL, &aflags, &zb); 2843b2aab18SMatthew Ahrens if (err != 0) { 285503ad85cSMatthew Ahrens kmem_free(os, sizeof (objset_t)); 286b87f3af3Sperrin /* convert checksum errors into IO errors */ 287b87f3af3Sperrin if (err == ECKSUM) 288*be6fd75aSMatthew Ahrens err = SET_ERROR(EIO); 289ea8dc4b6Seschrock return (err); 290ea8dc4b6Seschrock } 29114843421SMatthew Ahrens 29214843421SMatthew Ahrens /* Increase the blocksize if we are permitted. */ 29314843421SMatthew Ahrens if (spa_version(spa) >= SPA_VERSION_USERSPACE && 294503ad85cSMatthew Ahrens arc_buf_size(os->os_phys_buf) < sizeof (objset_phys_t)) { 29514843421SMatthew Ahrens arc_buf_t *buf = arc_buf_alloc(spa, 296503ad85cSMatthew Ahrens sizeof (objset_phys_t), &os->os_phys_buf, 29714843421SMatthew Ahrens ARC_BUFC_METADATA); 29814843421SMatthew Ahrens bzero(buf->b_data, sizeof (objset_phys_t)); 299503ad85cSMatthew Ahrens bcopy(os->os_phys_buf->b_data, buf->b_data, 300503ad85cSMatthew Ahrens arc_buf_size(os->os_phys_buf)); 301503ad85cSMatthew Ahrens (void) arc_buf_remove_ref(os->os_phys_buf, 302503ad85cSMatthew Ahrens &os->os_phys_buf); 303503ad85cSMatthew Ahrens os->os_phys_buf = buf; 30414843421SMatthew Ahrens } 30514843421SMatthew Ahrens 306503ad85cSMatthew Ahrens os->os_phys = os->os_phys_buf->b_data; 307503ad85cSMatthew Ahrens os->os_flags = os->os_phys->os_flags; 308fa9e4066Sahrens } else { 30914843421SMatthew Ahrens int size = spa_version(spa) >= SPA_VERSION_USERSPACE ? 31014843421SMatthew Ahrens sizeof (objset_phys_t) : OBJSET_OLD_PHYS_SIZE; 311503ad85cSMatthew Ahrens os->os_phys_buf = arc_buf_alloc(spa, size, 312503ad85cSMatthew Ahrens &os->os_phys_buf, ARC_BUFC_METADATA); 313503ad85cSMatthew Ahrens os->os_phys = os->os_phys_buf->b_data; 314503ad85cSMatthew Ahrens bzero(os->os_phys, size); 315fa9e4066Sahrens } 316fa9e4066Sahrens 317fa9e4066Sahrens /* 318fa9e4066Sahrens * Note: the changed_cb will be called once before the register 319fa9e4066Sahrens * func returns, thus changing the checksum/compression from the 3203baa08fcSek * default (fletcher2/off). Snapshots don't need to know about 3213baa08fcSek * checksum/compression/copies. 322fa9e4066Sahrens */ 3233baa08fcSek if (ds) { 3243b2aab18SMatthew Ahrens err = dsl_prop_register(ds, 3253b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_PRIMARYCACHE), 326503ad85cSMatthew Ahrens primary_cache_changed_cb, os); 3273b2aab18SMatthew Ahrens if (err == 0) { 3283b2aab18SMatthew Ahrens err = dsl_prop_register(ds, 3293b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_SECONDARYCACHE), 330503ad85cSMatthew Ahrens secondary_cache_changed_cb, os); 3313b2aab18SMatthew Ahrens } 3323baa08fcSek if (!dsl_dataset_is_snapshot(ds)) { 3333b2aab18SMatthew Ahrens if (err == 0) { 3343b2aab18SMatthew Ahrens err = dsl_prop_register(ds, 3353b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_CHECKSUM), 336503ad85cSMatthew Ahrens checksum_changed_cb, os); 3373b2aab18SMatthew Ahrens } 3383b2aab18SMatthew Ahrens if (err == 0) { 3393b2aab18SMatthew Ahrens err = dsl_prop_register(ds, 3403b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_COMPRESSION), 341503ad85cSMatthew Ahrens compression_changed_cb, os); 3423b2aab18SMatthew Ahrens } 3433b2aab18SMatthew Ahrens if (err == 0) { 3443b2aab18SMatthew Ahrens err = dsl_prop_register(ds, 3453b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_COPIES), 346503ad85cSMatthew Ahrens copies_changed_cb, os); 3473b2aab18SMatthew Ahrens } 3483b2aab18SMatthew Ahrens if (err == 0) { 3493b2aab18SMatthew Ahrens err = dsl_prop_register(ds, 3503b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_DEDUP), 351b24ab676SJeff Bonwick dedup_changed_cb, os); 3523b2aab18SMatthew Ahrens } 3533b2aab18SMatthew Ahrens if (err == 0) { 3543b2aab18SMatthew Ahrens err = dsl_prop_register(ds, 3553b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_LOGBIAS), 356e09fa4daSNeil Perrin logbias_changed_cb, os); 3573b2aab18SMatthew Ahrens } 3583b2aab18SMatthew Ahrens if (err == 0) { 3593b2aab18SMatthew Ahrens err = dsl_prop_register(ds, 3603b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_SYNC), 36155da60b9SMark J Musante sync_changed_cb, os); 3623b2aab18SMatthew Ahrens } 3633baa08fcSek } 3643b2aab18SMatthew Ahrens if (err != 0) { 365503ad85cSMatthew Ahrens VERIFY(arc_buf_remove_ref(os->os_phys_buf, 3663b2aab18SMatthew Ahrens &os->os_phys_buf)); 367503ad85cSMatthew Ahrens kmem_free(os, sizeof (objset_t)); 368ea8dc4b6Seschrock return (err); 369ea8dc4b6Seschrock } 37099653d4eSeschrock } else if (ds == NULL) { 371fa9e4066Sahrens /* It's the meta-objset. */ 372503ad85cSMatthew Ahrens os->os_checksum = ZIO_CHECKSUM_FLETCHER_4; 373503ad85cSMatthew Ahrens os->os_compress = ZIO_COMPRESS_LZJB; 374503ad85cSMatthew Ahrens os->os_copies = spa_max_replication(spa); 375b24ab676SJeff Bonwick os->os_dedup_checksum = ZIO_CHECKSUM_OFF; 376b24ab676SJeff Bonwick os->os_dedup_verify = 0; 377b24ab676SJeff Bonwick os->os_logbias = 0; 37855da60b9SMark J Musante os->os_sync = 0; 379503ad85cSMatthew Ahrens os->os_primary_cache = ZFS_CACHE_ALL; 380503ad85cSMatthew Ahrens os->os_secondary_cache = ZFS_CACHE_ALL; 381fa9e4066Sahrens } 382fa9e4066Sahrens 3836e0cbcaaSMatthew Ahrens if (ds == NULL || !dsl_dataset_is_snapshot(ds)) 3846e0cbcaaSMatthew Ahrens os->os_zil_header = os->os_phys->os_zil_header; 385503ad85cSMatthew Ahrens os->os_zil = zil_alloc(os, &os->os_zil_header); 386fa9e4066Sahrens 387fa9e4066Sahrens for (i = 0; i < TXG_SIZE; i++) { 388503ad85cSMatthew Ahrens list_create(&os->os_dirty_dnodes[i], sizeof (dnode_t), 389fa9e4066Sahrens offsetof(dnode_t, dn_dirty_link[i])); 390503ad85cSMatthew Ahrens list_create(&os->os_free_dnodes[i], sizeof (dnode_t), 391fa9e4066Sahrens offsetof(dnode_t, dn_dirty_link[i])); 392fa9e4066Sahrens } 393503ad85cSMatthew Ahrens list_create(&os->os_dnodes, sizeof (dnode_t), 394fa9e4066Sahrens offsetof(dnode_t, dn_link)); 395503ad85cSMatthew Ahrens list_create(&os->os_downgraded_dbufs, sizeof (dmu_buf_impl_t), 396fa9e4066Sahrens offsetof(dmu_buf_impl_t, db_link)); 397fa9e4066Sahrens 398503ad85cSMatthew Ahrens mutex_init(&os->os_lock, NULL, MUTEX_DEFAULT, NULL); 399503ad85cSMatthew Ahrens mutex_init(&os->os_obj_lock, NULL, MUTEX_DEFAULT, NULL); 400503ad85cSMatthew Ahrens mutex_init(&os->os_user_ptr_lock, NULL, MUTEX_DEFAULT, NULL); 401503ad85cSMatthew Ahrens 402744947dcSTom Erickson DMU_META_DNODE(os) = dnode_special_open(os, 403744947dcSTom Erickson &os->os_phys->os_meta_dnode, DMU_META_DNODE_OBJECT, 404744947dcSTom Erickson &os->os_meta_dnode); 405503ad85cSMatthew Ahrens if (arc_buf_size(os->os_phys_buf) >= sizeof (objset_phys_t)) { 406744947dcSTom Erickson DMU_USERUSED_DNODE(os) = dnode_special_open(os, 407744947dcSTom Erickson &os->os_phys->os_userused_dnode, DMU_USERUSED_OBJECT, 408744947dcSTom Erickson &os->os_userused_dnode); 409744947dcSTom Erickson DMU_GROUPUSED_DNODE(os) = dnode_special_open(os, 410744947dcSTom Erickson &os->os_phys->os_groupused_dnode, DMU_GROUPUSED_OBJECT, 411744947dcSTom Erickson &os->os_groupused_dnode); 41214843421SMatthew Ahrens } 413fa9e4066Sahrens 41491ebeef5Sahrens /* 41591ebeef5Sahrens * We should be the only thread trying to do this because we 41691ebeef5Sahrens * have ds_opening_lock 41791ebeef5Sahrens */ 41891ebeef5Sahrens if (ds) { 419503ad85cSMatthew Ahrens mutex_enter(&ds->ds_lock); 420503ad85cSMatthew Ahrens ASSERT(ds->ds_objset == NULL); 421503ad85cSMatthew Ahrens ds->ds_objset = os; 422503ad85cSMatthew Ahrens mutex_exit(&ds->ds_lock); 423fa9e4066Sahrens } 424fa9e4066Sahrens 425503ad85cSMatthew Ahrens *osp = os; 426ea8dc4b6Seschrock return (0); 427fa9e4066Sahrens } 428fa9e4066Sahrens 429503ad85cSMatthew Ahrens int 430503ad85cSMatthew Ahrens dmu_objset_from_ds(dsl_dataset_t *ds, objset_t **osp) 4313cb34c60Sahrens { 432503ad85cSMatthew Ahrens int err = 0; 4333cb34c60Sahrens 4343cb34c60Sahrens mutex_enter(&ds->ds_opening_lock); 435503ad85cSMatthew Ahrens *osp = ds->ds_objset; 436503ad85cSMatthew Ahrens if (*osp == NULL) { 4373cb34c60Sahrens err = dmu_objset_open_impl(dsl_dataset_get_spa(ds), 438feaa74e4SMark Maybee ds, dsl_dataset_get_blkptr(ds), osp); 4393cb34c60Sahrens } 4403cb34c60Sahrens mutex_exit(&ds->ds_opening_lock); 441503ad85cSMatthew Ahrens return (err); 4423cb34c60Sahrens } 4433cb34c60Sahrens 4443b2aab18SMatthew Ahrens /* 4453b2aab18SMatthew Ahrens * Holds the pool while the objset is held. Therefore only one objset 4463b2aab18SMatthew Ahrens * can be held at a time. 4473b2aab18SMatthew Ahrens */ 4483cb34c60Sahrens int 449503ad85cSMatthew Ahrens dmu_objset_hold(const char *name, void *tag, objset_t **osp) 4503cb34c60Sahrens { 4513b2aab18SMatthew Ahrens dsl_pool_t *dp; 452503ad85cSMatthew Ahrens dsl_dataset_t *ds; 4533cb34c60Sahrens int err; 4543cb34c60Sahrens 4553b2aab18SMatthew Ahrens err = dsl_pool_hold(name, tag, &dp); 4563b2aab18SMatthew Ahrens if (err != 0) 4573b2aab18SMatthew Ahrens return (err); 4583b2aab18SMatthew Ahrens err = dsl_dataset_hold(dp, name, tag, &ds); 4593b2aab18SMatthew Ahrens if (err != 0) { 4603b2aab18SMatthew Ahrens dsl_pool_rele(dp, tag); 461503ad85cSMatthew Ahrens return (err); 4623b2aab18SMatthew Ahrens } 463503ad85cSMatthew Ahrens 464503ad85cSMatthew Ahrens err = dmu_objset_from_ds(ds, osp); 4653b2aab18SMatthew Ahrens if (err != 0) { 466503ad85cSMatthew Ahrens dsl_dataset_rele(ds, tag); 4673b2aab18SMatthew Ahrens dsl_pool_rele(dp, tag); 4683b2aab18SMatthew Ahrens } 469503ad85cSMatthew Ahrens 4703cb34c60Sahrens return (err); 4713cb34c60Sahrens } 4723cb34c60Sahrens 4733b2aab18SMatthew Ahrens /* 4743b2aab18SMatthew Ahrens * dsl_pool must not be held when this is called. 4753b2aab18SMatthew Ahrens * Upon successful return, there will be a longhold on the dataset, 4763b2aab18SMatthew Ahrens * and the dsl_pool will not be held. 4773b2aab18SMatthew Ahrens */ 478fa9e4066Sahrens int 479503ad85cSMatthew Ahrens dmu_objset_own(const char *name, dmu_objset_type_t type, 480503ad85cSMatthew Ahrens boolean_t readonly, void *tag, objset_t **osp) 481fa9e4066Sahrens { 4823b2aab18SMatthew Ahrens dsl_pool_t *dp; 483f18faf3fSek dsl_dataset_t *ds; 484f18faf3fSek int err; 485fa9e4066Sahrens 4863b2aab18SMatthew Ahrens err = dsl_pool_hold(name, FTAG, &dp); 4873b2aab18SMatthew Ahrens if (err != 0) 4883b2aab18SMatthew Ahrens return (err); 4893b2aab18SMatthew Ahrens err = dsl_dataset_own(dp, name, tag, &ds); 4903b2aab18SMatthew Ahrens if (err != 0) { 4913b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 492fa9e4066Sahrens return (err); 4933b2aab18SMatthew Ahrens } 494fa9e4066Sahrens 495503ad85cSMatthew Ahrens err = dmu_objset_from_ds(ds, osp); 4963b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 4973b2aab18SMatthew Ahrens if (err != 0) { 498503ad85cSMatthew Ahrens dsl_dataset_disown(ds, tag); 499681d9761SEric Taylor } else if (type != DMU_OST_ANY && type != (*osp)->os_phys->os_type) { 5003b2aab18SMatthew Ahrens dsl_dataset_disown(ds, tag); 501*be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 502681d9761SEric Taylor } else if (!readonly && dsl_dataset_is_snapshot(ds)) { 5033b2aab18SMatthew Ahrens dsl_dataset_disown(ds, tag); 504*be6fd75aSMatthew Ahrens return (SET_ERROR(EROFS)); 505fa9e4066Sahrens } 5063cb34c60Sahrens return (err); 507fa9e4066Sahrens } 508fa9e4066Sahrens 509fa9e4066Sahrens void 510503ad85cSMatthew Ahrens dmu_objset_rele(objset_t *os, void *tag) 511fa9e4066Sahrens { 5123b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_objset_pool(os); 513503ad85cSMatthew Ahrens dsl_dataset_rele(os->os_dsl_dataset, tag); 5143b2aab18SMatthew Ahrens dsl_pool_rele(dp, tag); 515503ad85cSMatthew Ahrens } 516503ad85cSMatthew Ahrens 517503ad85cSMatthew Ahrens void 518503ad85cSMatthew Ahrens dmu_objset_disown(objset_t *os, void *tag) 519503ad85cSMatthew Ahrens { 520503ad85cSMatthew Ahrens dsl_dataset_disown(os->os_dsl_dataset, tag); 521fa9e4066Sahrens } 522fa9e4066Sahrens 5233b2aab18SMatthew Ahrens void 5241934e92fSmaybee dmu_objset_evict_dbufs(objset_t *os) 525ea8dc4b6Seschrock { 526ea8dc4b6Seschrock dnode_t *dn; 527c543ec06Sahrens 528503ad85cSMatthew Ahrens mutex_enter(&os->os_lock); 529c543ec06Sahrens 530c543ec06Sahrens /* process the mdn last, since the other dnodes have holds on it */ 531744947dcSTom Erickson list_remove(&os->os_dnodes, DMU_META_DNODE(os)); 532744947dcSTom Erickson list_insert_tail(&os->os_dnodes, DMU_META_DNODE(os)); 533ea8dc4b6Seschrock 534ea8dc4b6Seschrock /* 535c543ec06Sahrens * Find the first dnode with holds. We have to do this dance 536c543ec06Sahrens * because dnode_add_ref() only works if you already have a 537c543ec06Sahrens * hold. If there are no holds then it has no dbufs so OK to 538c543ec06Sahrens * skip. 539ea8dc4b6Seschrock */ 540503ad85cSMatthew Ahrens for (dn = list_head(&os->os_dnodes); 5411934e92fSmaybee dn && !dnode_add_ref(dn, FTAG); 542503ad85cSMatthew Ahrens dn = list_next(&os->os_dnodes, dn)) 543c543ec06Sahrens continue; 544c543ec06Sahrens 545c543ec06Sahrens while (dn) { 546c543ec06Sahrens dnode_t *next_dn = dn; 547c543ec06Sahrens 548c543ec06Sahrens do { 549503ad85cSMatthew Ahrens next_dn = list_next(&os->os_dnodes, next_dn); 5501934e92fSmaybee } while (next_dn && !dnode_add_ref(next_dn, FTAG)); 551c543ec06Sahrens 552503ad85cSMatthew Ahrens mutex_exit(&os->os_lock); 5531934e92fSmaybee dnode_evict_dbufs(dn); 554c543ec06Sahrens dnode_rele(dn, FTAG); 555503ad85cSMatthew Ahrens mutex_enter(&os->os_lock); 556c543ec06Sahrens dn = next_dn; 557ea8dc4b6Seschrock } 558503ad85cSMatthew Ahrens mutex_exit(&os->os_lock); 559ea8dc4b6Seschrock } 560ea8dc4b6Seschrock 561fa9e4066Sahrens void 562503ad85cSMatthew Ahrens dmu_objset_evict(objset_t *os) 563fa9e4066Sahrens { 564503ad85cSMatthew Ahrens dsl_dataset_t *ds = os->os_dsl_dataset; 565fa9e4066Sahrens 566b24ab676SJeff Bonwick for (int t = 0; t < TXG_SIZE; t++) 567b24ab676SJeff Bonwick ASSERT(!dmu_objset_is_dirty(os, t)); 568fa9e4066Sahrens 5693baa08fcSek if (ds) { 5703baa08fcSek if (!dsl_dataset_is_snapshot(ds)) { 5713b2aab18SMatthew Ahrens VERIFY0(dsl_prop_unregister(ds, 5723b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_CHECKSUM), 573503ad85cSMatthew Ahrens checksum_changed_cb, os)); 5743b2aab18SMatthew Ahrens VERIFY0(dsl_prop_unregister(ds, 5753b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_COMPRESSION), 576503ad85cSMatthew Ahrens compression_changed_cb, os)); 5773b2aab18SMatthew Ahrens VERIFY0(dsl_prop_unregister(ds, 5783b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_COPIES), 579503ad85cSMatthew Ahrens copies_changed_cb, os)); 5803b2aab18SMatthew Ahrens VERIFY0(dsl_prop_unregister(ds, 5813b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_DEDUP), 582b24ab676SJeff Bonwick dedup_changed_cb, os)); 5833b2aab18SMatthew Ahrens VERIFY0(dsl_prop_unregister(ds, 5843b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_LOGBIAS), 585e09fa4daSNeil Perrin logbias_changed_cb, os)); 5863b2aab18SMatthew Ahrens VERIFY0(dsl_prop_unregister(ds, 5873b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_SYNC), 58855da60b9SMark J Musante sync_changed_cb, os)); 5893baa08fcSek } 5903b2aab18SMatthew Ahrens VERIFY0(dsl_prop_unregister(ds, 5913b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_PRIMARYCACHE), 592503ad85cSMatthew Ahrens primary_cache_changed_cb, os)); 5933b2aab18SMatthew Ahrens VERIFY0(dsl_prop_unregister(ds, 5943b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_SECONDARYCACHE), 595503ad85cSMatthew Ahrens secondary_cache_changed_cb, os)); 596fa9e4066Sahrens } 597fa9e4066Sahrens 5980a586ceaSMark Shellenbaum if (os->os_sa) 5990a586ceaSMark Shellenbaum sa_tear_down(os); 6000a586ceaSMark Shellenbaum 6013b2aab18SMatthew Ahrens dmu_objset_evict_dbufs(os); 602ea8dc4b6Seschrock 603744947dcSTom Erickson dnode_special_close(&os->os_meta_dnode); 604744947dcSTom Erickson if (DMU_USERUSED_DNODE(os)) { 605744947dcSTom Erickson dnode_special_close(&os->os_userused_dnode); 606744947dcSTom Erickson dnode_special_close(&os->os_groupused_dnode); 60714843421SMatthew Ahrens } 608503ad85cSMatthew Ahrens zil_free(os->os_zil); 609fa9e4066Sahrens 610503ad85cSMatthew Ahrens ASSERT3P(list_head(&os->os_dnodes), ==, NULL); 61114843421SMatthew Ahrens 6123b2aab18SMatthew Ahrens VERIFY(arc_buf_remove_ref(os->os_phys_buf, &os->os_phys_buf)); 613744947dcSTom Erickson 614744947dcSTom Erickson /* 615744947dcSTom Erickson * This is a barrier to prevent the objset from going away in 616744947dcSTom Erickson * dnode_move() until we can safely ensure that the objset is still in 617744947dcSTom Erickson * use. We consider the objset valid before the barrier and invalid 618744947dcSTom Erickson * after the barrier. 619744947dcSTom Erickson */ 620744947dcSTom Erickson rw_enter(&os_lock, RW_READER); 621744947dcSTom Erickson rw_exit(&os_lock); 622744947dcSTom Erickson 623503ad85cSMatthew Ahrens mutex_destroy(&os->os_lock); 624503ad85cSMatthew Ahrens mutex_destroy(&os->os_obj_lock); 625503ad85cSMatthew Ahrens mutex_destroy(&os->os_user_ptr_lock); 626503ad85cSMatthew Ahrens kmem_free(os, sizeof (objset_t)); 627fa9e4066Sahrens } 628fa9e4066Sahrens 62971eb0538SChris Kirby timestruc_t 63071eb0538SChris Kirby dmu_objset_snap_cmtime(objset_t *os) 63171eb0538SChris Kirby { 63271eb0538SChris Kirby return (dsl_dir_snap_cmtime(os->os_dsl_dataset->ds_dir)); 63371eb0538SChris Kirby } 63471eb0538SChris Kirby 635fa9e4066Sahrens /* called from dsl for meta-objset */ 636503ad85cSMatthew Ahrens objset_t * 637c717a561Smaybee dmu_objset_create_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp, 638c717a561Smaybee dmu_objset_type_t type, dmu_tx_t *tx) 639fa9e4066Sahrens { 640503ad85cSMatthew Ahrens objset_t *os; 641fa9e4066Sahrens dnode_t *mdn; 642fa9e4066Sahrens 643fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 6443b2aab18SMatthew Ahrens 645feaa74e4SMark Maybee if (ds != NULL) 6463b2aab18SMatthew Ahrens VERIFY0(dmu_objset_from_ds(ds, &os)); 647feaa74e4SMark Maybee else 6483b2aab18SMatthew Ahrens VERIFY0(dmu_objset_open_impl(spa, NULL, bp, &os)); 649feaa74e4SMark Maybee 650744947dcSTom Erickson mdn = DMU_META_DNODE(os); 651fa9e4066Sahrens 652fa9e4066Sahrens dnode_allocate(mdn, DMU_OT_DNODE, 1 << DNODE_BLOCK_SHIFT, 653fa9e4066Sahrens DN_MAX_INDBLKSHIFT, DMU_OT_NONE, 0, tx); 654fa9e4066Sahrens 655fa9e4066Sahrens /* 656fa9e4066Sahrens * We don't want to have to increase the meta-dnode's nlevels 657fa9e4066Sahrens * later, because then we could do it in quescing context while 658fa9e4066Sahrens * we are also accessing it in open context. 659fa9e4066Sahrens * 660fa9e4066Sahrens * This precaution is not necessary for the MOS (ds == NULL), 661fa9e4066Sahrens * because the MOS is only updated in syncing context. 662fa9e4066Sahrens * This is most fortunate: the MOS is the only objset that 663fa9e4066Sahrens * needs to be synced multiple times as spa_sync() iterates 664fa9e4066Sahrens * to convergence, so minimizing its dn_nlevels matters. 665fa9e4066Sahrens */ 666ea8dc4b6Seschrock if (ds != NULL) { 667ea8dc4b6Seschrock int levels = 1; 668ea8dc4b6Seschrock 669ea8dc4b6Seschrock /* 670ea8dc4b6Seschrock * Determine the number of levels necessary for the meta-dnode 671ea8dc4b6Seschrock * to contain DN_MAX_OBJECT dnodes. 672ea8dc4b6Seschrock */ 673ea8dc4b6Seschrock while ((uint64_t)mdn->dn_nblkptr << (mdn->dn_datablkshift + 674ea8dc4b6Seschrock (levels - 1) * (mdn->dn_indblkshift - SPA_BLKPTRSHIFT)) < 675ea8dc4b6Seschrock DN_MAX_OBJECT * sizeof (dnode_phys_t)) 676ea8dc4b6Seschrock levels++; 677ea8dc4b6Seschrock 678fa9e4066Sahrens mdn->dn_next_nlevels[tx->tx_txg & TXG_MASK] = 679ea8dc4b6Seschrock mdn->dn_nlevels = levels; 680ea8dc4b6Seschrock } 681fa9e4066Sahrens 682fa9e4066Sahrens ASSERT(type != DMU_OST_NONE); 683fa9e4066Sahrens ASSERT(type != DMU_OST_ANY); 684fa9e4066Sahrens ASSERT(type < DMU_OST_NUMTYPES); 685503ad85cSMatthew Ahrens os->os_phys->os_type = type; 686503ad85cSMatthew Ahrens if (dmu_objset_userused_enabled(os)) { 687503ad85cSMatthew Ahrens os->os_phys->os_flags |= OBJSET_FLAG_USERACCOUNTING_COMPLETE; 688503ad85cSMatthew Ahrens os->os_flags = os->os_phys->os_flags; 68914843421SMatthew Ahrens } 690fa9e4066Sahrens 691fa9e4066Sahrens dsl_dataset_dirty(ds, tx); 692fa9e4066Sahrens 693503ad85cSMatthew Ahrens return (os); 694fa9e4066Sahrens } 695fa9e4066Sahrens 6963b2aab18SMatthew Ahrens typedef struct dmu_objset_create_arg { 6973b2aab18SMatthew Ahrens const char *doca_name; 6983b2aab18SMatthew Ahrens cred_t *doca_cred; 6993b2aab18SMatthew Ahrens void (*doca_userfunc)(objset_t *os, void *arg, 7003b2aab18SMatthew Ahrens cred_t *cr, dmu_tx_t *tx); 7013b2aab18SMatthew Ahrens void *doca_userarg; 7023b2aab18SMatthew Ahrens dmu_objset_type_t doca_type; 7033b2aab18SMatthew Ahrens uint64_t doca_flags; 7043b2aab18SMatthew Ahrens } dmu_objset_create_arg_t; 705fa9e4066Sahrens 706ecd6cf80Smarks /*ARGSUSED*/ 707fa9e4066Sahrens static int 7083b2aab18SMatthew Ahrens dmu_objset_create_check(void *arg, dmu_tx_t *tx) 709fa9e4066Sahrens { 7103b2aab18SMatthew Ahrens dmu_objset_create_arg_t *doca = arg; 7113b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 7123b2aab18SMatthew Ahrens dsl_dir_t *pdd; 7133b2aab18SMatthew Ahrens const char *tail; 7143b2aab18SMatthew Ahrens int error; 7151d452cf5Sahrens 7163b2aab18SMatthew Ahrens if (strchr(doca->doca_name, '@') != NULL) 717*be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 7181d452cf5Sahrens 7193b2aab18SMatthew Ahrens error = dsl_dir_hold(dp, doca->doca_name, FTAG, &pdd, &tail); 7203b2aab18SMatthew Ahrens if (error != 0) 7213b2aab18SMatthew Ahrens return (error); 7223b2aab18SMatthew Ahrens if (tail == NULL) { 7233b2aab18SMatthew Ahrens dsl_dir_rele(pdd, FTAG); 724*be6fd75aSMatthew Ahrens return (SET_ERROR(EEXIST)); 7251d452cf5Sahrens } 7263b2aab18SMatthew Ahrens dsl_dir_rele(pdd, FTAG); 727ecd6cf80Smarks 7281d452cf5Sahrens return (0); 7291d452cf5Sahrens } 7301d452cf5Sahrens 7311d452cf5Sahrens static void 7323b2aab18SMatthew Ahrens dmu_objset_create_sync(void *arg, dmu_tx_t *tx) 7331d452cf5Sahrens { 7343b2aab18SMatthew Ahrens dmu_objset_create_arg_t *doca = arg; 7353b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 7363b2aab18SMatthew Ahrens dsl_dir_t *pdd; 7373b2aab18SMatthew Ahrens const char *tail; 7384445fffbSMatthew Ahrens dsl_dataset_t *ds; 7393b2aab18SMatthew Ahrens uint64_t obj; 7404445fffbSMatthew Ahrens blkptr_t *bp; 7413b2aab18SMatthew Ahrens objset_t *os; 742fa9e4066Sahrens 7433b2aab18SMatthew Ahrens VERIFY0(dsl_dir_hold(dp, doca->doca_name, FTAG, &pdd, &tail)); 744fa9e4066Sahrens 7453b2aab18SMatthew Ahrens obj = dsl_dataset_create_sync(pdd, tail, NULL, doca->doca_flags, 7463b2aab18SMatthew Ahrens doca->doca_cred, tx); 747fa9e4066Sahrens 7483b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(pdd->dd_pool, obj, FTAG, &ds)); 7494445fffbSMatthew Ahrens bp = dsl_dataset_get_blkptr(ds); 7503b2aab18SMatthew Ahrens os = dmu_objset_create_impl(pdd->dd_pool->dp_spa, 7513b2aab18SMatthew Ahrens ds, bp, doca->doca_type, tx); 752fa9e4066Sahrens 7533b2aab18SMatthew Ahrens if (doca->doca_userfunc != NULL) { 7543b2aab18SMatthew Ahrens doca->doca_userfunc(os, doca->doca_userarg, 7553b2aab18SMatthew Ahrens doca->doca_cred, tx); 756fa9e4066Sahrens } 757ecd6cf80Smarks 7583b2aab18SMatthew Ahrens spa_history_log_internal_ds(ds, "create", tx, ""); 7594445fffbSMatthew Ahrens dsl_dataset_rele(ds, FTAG); 7603b2aab18SMatthew Ahrens dsl_dir_rele(pdd, FTAG); 761fa9e4066Sahrens } 762fa9e4066Sahrens 763fa9e4066Sahrens int 764ae46e4c7SMatthew Ahrens dmu_objset_create(const char *name, dmu_objset_type_t type, uint64_t flags, 765ecd6cf80Smarks void (*func)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx), void *arg) 766fa9e4066Sahrens { 7673b2aab18SMatthew Ahrens dmu_objset_create_arg_t doca; 768fa9e4066Sahrens 7693b2aab18SMatthew Ahrens doca.doca_name = name; 7703b2aab18SMatthew Ahrens doca.doca_cred = CRED(); 7713b2aab18SMatthew Ahrens doca.doca_flags = flags; 7723b2aab18SMatthew Ahrens doca.doca_userfunc = func; 7733b2aab18SMatthew Ahrens doca.doca_userarg = arg; 7743b2aab18SMatthew Ahrens doca.doca_type = type; 775ecd6cf80Smarks 7763b2aab18SMatthew Ahrens return (dsl_sync_task(name, 7773b2aab18SMatthew Ahrens dmu_objset_create_check, dmu_objset_create_sync, &doca, 5)); 778ae46e4c7SMatthew Ahrens } 779ae46e4c7SMatthew Ahrens 7803b2aab18SMatthew Ahrens typedef struct dmu_objset_clone_arg { 7813b2aab18SMatthew Ahrens const char *doca_clone; 7823b2aab18SMatthew Ahrens const char *doca_origin; 7833b2aab18SMatthew Ahrens cred_t *doca_cred; 7843b2aab18SMatthew Ahrens } dmu_objset_clone_arg_t; 7853b2aab18SMatthew Ahrens 7863b2aab18SMatthew Ahrens /*ARGSUSED*/ 7873b2aab18SMatthew Ahrens static int 7883b2aab18SMatthew Ahrens dmu_objset_clone_check(void *arg, dmu_tx_t *tx) 789ae46e4c7SMatthew Ahrens { 7903b2aab18SMatthew Ahrens dmu_objset_clone_arg_t *doca = arg; 791ae46e4c7SMatthew Ahrens dsl_dir_t *pdd; 792ae46e4c7SMatthew Ahrens const char *tail; 7933b2aab18SMatthew Ahrens int error; 7943b2aab18SMatthew Ahrens dsl_dataset_t *origin; 7953b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 796ae46e4c7SMatthew Ahrens 7973b2aab18SMatthew Ahrens if (strchr(doca->doca_clone, '@') != NULL) 798*be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 7993b2aab18SMatthew Ahrens 8003b2aab18SMatthew Ahrens error = dsl_dir_hold(dp, doca->doca_clone, FTAG, &pdd, &tail); 8013b2aab18SMatthew Ahrens if (error != 0) 8023b2aab18SMatthew Ahrens return (error); 803ae46e4c7SMatthew Ahrens if (tail == NULL) { 8043b2aab18SMatthew Ahrens dsl_dir_rele(pdd, FTAG); 805*be6fd75aSMatthew Ahrens return (SET_ERROR(EEXIST)); 806fa9e4066Sahrens } 8073b2aab18SMatthew Ahrens /* You can't clone across pools. */ 8083b2aab18SMatthew Ahrens if (pdd->dd_pool != dp) { 8093b2aab18SMatthew Ahrens dsl_dir_rele(pdd, FTAG); 810*be6fd75aSMatthew Ahrens return (SET_ERROR(EXDEV)); 811fa9e4066Sahrens } 8123b2aab18SMatthew Ahrens dsl_dir_rele(pdd, FTAG); 813fa9e4066Sahrens 8143b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, doca->doca_origin, FTAG, &origin); 8153b2aab18SMatthew Ahrens if (error != 0) 81699d5e173STim Haley return (error); 81799d5e173STim Haley 8183b2aab18SMatthew Ahrens /* You can't clone across pools. */ 8193b2aab18SMatthew Ahrens if (origin->ds_dir->dd_pool != dp) { 8203b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 821*be6fd75aSMatthew Ahrens return (SET_ERROR(EXDEV)); 82299d5e173STim Haley } 823ea2f5b9eSMatthew Ahrens 8243b2aab18SMatthew Ahrens /* You can only clone snapshots, not the head datasets. */ 8253b2aab18SMatthew Ahrens if (!dsl_dataset_is_snapshot(origin)) { 8263b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 827*be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 82892241e0bSTom Erickson } 8293b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 83099d5e173STim Haley 8313b2aab18SMatthew Ahrens return (0); 832ea2f5b9eSMatthew Ahrens } 8331d452cf5Sahrens 8343b2aab18SMatthew Ahrens static void 8353b2aab18SMatthew Ahrens dmu_objset_clone_sync(void *arg, dmu_tx_t *tx) 8361d452cf5Sahrens { 8373b2aab18SMatthew Ahrens dmu_objset_clone_arg_t *doca = arg; 8383b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 8393b2aab18SMatthew Ahrens dsl_dir_t *pdd; 8403b2aab18SMatthew Ahrens const char *tail; 8413b2aab18SMatthew Ahrens dsl_dataset_t *origin, *ds; 8423b2aab18SMatthew Ahrens uint64_t obj; 8433b2aab18SMatthew Ahrens char namebuf[MAXNAMELEN]; 8444445fffbSMatthew Ahrens 8453b2aab18SMatthew Ahrens VERIFY0(dsl_dir_hold(dp, doca->doca_clone, FTAG, &pdd, &tail)); 8463b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold(dp, doca->doca_origin, FTAG, &origin)); 8474445fffbSMatthew Ahrens 8483b2aab18SMatthew Ahrens obj = dsl_dataset_create_sync(pdd, tail, origin, 0, 8493b2aab18SMatthew Ahrens doca->doca_cred, tx); 850f2e10be3Srm 8513b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(pdd->dd_pool, obj, FTAG, &ds)); 8523b2aab18SMatthew Ahrens dsl_dataset_name(origin, namebuf); 8533b2aab18SMatthew Ahrens spa_history_log_internal_ds(ds, "clone", tx, 8543b2aab18SMatthew Ahrens "origin=%s (%llu)", namebuf, origin->ds_object); 8553b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 8563b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 8573b2aab18SMatthew Ahrens dsl_dir_rele(pdd, FTAG); 8581d452cf5Sahrens } 8591d452cf5Sahrens 8601d452cf5Sahrens int 8613b2aab18SMatthew Ahrens dmu_objset_clone(const char *clone, const char *origin) 8621d452cf5Sahrens { 8633b2aab18SMatthew Ahrens dmu_objset_clone_arg_t doca; 8644445fffbSMatthew Ahrens 8653b2aab18SMatthew Ahrens doca.doca_clone = clone; 8663b2aab18SMatthew Ahrens doca.doca_origin = origin; 8673b2aab18SMatthew Ahrens doca.doca_cred = CRED(); 86899d5e173STim Haley 8693b2aab18SMatthew Ahrens return (dsl_sync_task(clone, 8703b2aab18SMatthew Ahrens dmu_objset_clone_check, dmu_objset_clone_sync, &doca, 5)); 8714445fffbSMatthew Ahrens } 8724445fffbSMatthew Ahrens 8734445fffbSMatthew Ahrens int 8744445fffbSMatthew Ahrens dmu_objset_snapshot_one(const char *fsname, const char *snapname) 8754445fffbSMatthew Ahrens { 8764445fffbSMatthew Ahrens int err; 8774445fffbSMatthew Ahrens char *longsnap = kmem_asprintf("%s@%s", fsname, snapname); 8784445fffbSMatthew Ahrens nvlist_t *snaps = fnvlist_alloc(); 8794445fffbSMatthew Ahrens 8804445fffbSMatthew Ahrens fnvlist_add_boolean(snaps, longsnap); 8814445fffbSMatthew Ahrens strfree(longsnap); 8823b2aab18SMatthew Ahrens err = dsl_dataset_snapshot(snaps, NULL, NULL); 8833b2aab18SMatthew Ahrens fnvlist_free(snaps); 8844445fffbSMatthew Ahrens return (err); 8854445fffbSMatthew Ahrens } 8864445fffbSMatthew Ahrens 887fa9e4066Sahrens static void 88814843421SMatthew Ahrens dmu_objset_sync_dnodes(list_t *list, list_t *newlist, dmu_tx_t *tx) 889fa9e4066Sahrens { 890c717a561Smaybee dnode_t *dn; 891faafa6e3Sahrens 892c717a561Smaybee while (dn = list_head(list)) { 893c717a561Smaybee ASSERT(dn->dn_object != DMU_META_DNODE_OBJECT); 894c717a561Smaybee ASSERT(dn->dn_dbuf->db_data_pending); 895c717a561Smaybee /* 89614843421SMatthew Ahrens * Initialize dn_zio outside dnode_sync() because the 89714843421SMatthew Ahrens * meta-dnode needs to set it ouside dnode_sync(). 898c717a561Smaybee */ 899c717a561Smaybee dn->dn_zio = dn->dn_dbuf->db_data_pending->dr_zio; 900c717a561Smaybee ASSERT(dn->dn_zio); 901faafa6e3Sahrens 902c717a561Smaybee ASSERT3U(dn->dn_nlevels, <=, DN_MAX_LEVELS); 903c717a561Smaybee list_remove(list, dn); 90414843421SMatthew Ahrens 90514843421SMatthew Ahrens if (newlist) { 90614843421SMatthew Ahrens (void) dnode_add_ref(dn, newlist); 90714843421SMatthew Ahrens list_insert_tail(newlist, dn); 90814843421SMatthew Ahrens } 90914843421SMatthew Ahrens 910c717a561Smaybee dnode_sync(dn, tx); 911fa9e4066Sahrens } 912fa9e4066Sahrens } 913fa9e4066Sahrens 914fa9e4066Sahrens /* ARGSUSED */ 915fa9e4066Sahrens static void 916b24ab676SJeff Bonwick dmu_objset_write_ready(zio_t *zio, arc_buf_t *abuf, void *arg) 917fa9e4066Sahrens { 918e14bb325SJeff Bonwick blkptr_t *bp = zio->io_bp; 919503ad85cSMatthew Ahrens objset_t *os = arg; 920c717a561Smaybee dnode_phys_t *dnp = &os->os_phys->os_meta_dnode; 921fa9e4066Sahrens 9223b2aab18SMatthew Ahrens ASSERT3P(bp, ==, os->os_rootbp); 9233b2aab18SMatthew Ahrens ASSERT3U(BP_GET_TYPE(bp), ==, DMU_OT_OBJSET); 9243b2aab18SMatthew Ahrens ASSERT0(BP_GET_LEVEL(bp)); 9250a4e9518Sgw 926fa9e4066Sahrens /* 92714843421SMatthew Ahrens * Update rootbp fill count: it should be the number of objects 92814843421SMatthew Ahrens * allocated in the object set (not counting the "special" 92914843421SMatthew Ahrens * objects that are stored in the objset_phys_t -- the meta 93014843421SMatthew Ahrens * dnode and user/group accounting objects). 931fa9e4066Sahrens */ 93214843421SMatthew Ahrens bp->blk_fill = 0; 933e14bb325SJeff Bonwick for (int i = 0; i < dnp->dn_nblkptr; i++) 934c717a561Smaybee bp->blk_fill += dnp->dn_blkptr[i].blk_fill; 935b24ab676SJeff Bonwick } 936b24ab676SJeff Bonwick 937b24ab676SJeff Bonwick /* ARGSUSED */ 938b24ab676SJeff Bonwick static void 939b24ab676SJeff Bonwick dmu_objset_write_done(zio_t *zio, arc_buf_t *abuf, void *arg) 940b24ab676SJeff Bonwick { 941b24ab676SJeff Bonwick blkptr_t *bp = zio->io_bp; 942b24ab676SJeff Bonwick blkptr_t *bp_orig = &zio->io_bp_orig; 943b24ab676SJeff Bonwick objset_t *os = arg; 9440a4e9518Sgw 945e14bb325SJeff Bonwick if (zio->io_flags & ZIO_FLAG_IO_REWRITE) { 946b24ab676SJeff Bonwick ASSERT(BP_EQUAL(bp, bp_orig)); 947e14bb325SJeff Bonwick } else { 948b24ab676SJeff Bonwick dsl_dataset_t *ds = os->os_dsl_dataset; 949b24ab676SJeff Bonwick dmu_tx_t *tx = os->os_synctx; 950b24ab676SJeff Bonwick 951b24ab676SJeff Bonwick (void) dsl_dataset_block_kill(ds, bp_orig, tx, B_TRUE); 952b24ab676SJeff Bonwick dsl_dataset_block_born(ds, bp, tx); 9530a4e9518Sgw } 954c717a561Smaybee } 955c717a561Smaybee 956fa9e4066Sahrens /* called from dsl */ 957fa9e4066Sahrens void 958503ad85cSMatthew Ahrens dmu_objset_sync(objset_t *os, zio_t *pio, dmu_tx_t *tx) 959fa9e4066Sahrens { 960fa9e4066Sahrens int txgoff; 961ea8dc4b6Seschrock zbookmark_t zb; 962b24ab676SJeff Bonwick zio_prop_t zp; 963c717a561Smaybee zio_t *zio; 964c717a561Smaybee list_t *list; 96514843421SMatthew Ahrens list_t *newlist = NULL; 966c717a561Smaybee dbuf_dirty_record_t *dr; 967c717a561Smaybee 968c717a561Smaybee dprintf_ds(os->os_dsl_dataset, "txg=%llu\n", tx->tx_txg); 969fa9e4066Sahrens 970fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 971fa9e4066Sahrens /* XXX the write_done callback should really give us the tx... */ 972fa9e4066Sahrens os->os_synctx = tx; 973fa9e4066Sahrens 97487bd5c1eSahrens if (os->os_dsl_dataset == NULL) { 97587bd5c1eSahrens /* 97687bd5c1eSahrens * This is the MOS. If we have upgraded, 97787bd5c1eSahrens * spa_max_replication() could change, so reset 97887bd5c1eSahrens * os_copies here. 97987bd5c1eSahrens */ 98087bd5c1eSahrens os->os_copies = spa_max_replication(os->os_spa); 98187bd5c1eSahrens } 98287bd5c1eSahrens 983fa9e4066Sahrens /* 984c717a561Smaybee * Create the root block IO 985fa9e4066Sahrens */ 986b24ab676SJeff Bonwick SET_BOOKMARK(&zb, os->os_dsl_dataset ? 987b24ab676SJeff Bonwick os->os_dsl_dataset->ds_object : DMU_META_OBJSET, 988b24ab676SJeff Bonwick ZB_ROOT_OBJECT, ZB_ROOT_LEVEL, ZB_ROOT_BLKID); 9891b912ec7SGeorge Wilson arc_release(os->os_phys_buf, &os->os_phys_buf); 990b24ab676SJeff Bonwick 991b24ab676SJeff Bonwick dmu_write_policy(os, NULL, 0, 0, &zp); 992b24ab676SJeff Bonwick 993b24ab676SJeff Bonwick zio = arc_write(pio, os->os_spa, tx->tx_txg, 994b24ab676SJeff Bonwick os->os_rootbp, os->os_phys_buf, DMU_OS_IS_L2CACHEABLE(os), &zp, 995b24ab676SJeff Bonwick dmu_objset_write_ready, dmu_objset_write_done, os, 996e14bb325SJeff Bonwick ZIO_PRIORITY_ASYNC_WRITE, ZIO_FLAG_MUSTSUCCEED, &zb); 997c717a561Smaybee 998c717a561Smaybee /* 99914843421SMatthew Ahrens * Sync special dnodes - the parent IO for the sync is the root block 1000c717a561Smaybee */ 1001744947dcSTom Erickson DMU_META_DNODE(os)->dn_zio = zio; 1002744947dcSTom Erickson dnode_sync(DMU_META_DNODE(os), tx); 1003c717a561Smaybee 100414843421SMatthew Ahrens os->os_phys->os_flags = os->os_flags; 100514843421SMatthew Ahrens 1006744947dcSTom Erickson if (DMU_USERUSED_DNODE(os) && 1007744947dcSTom Erickson DMU_USERUSED_DNODE(os)->dn_type != DMU_OT_NONE) { 1008744947dcSTom Erickson DMU_USERUSED_DNODE(os)->dn_zio = zio; 1009744947dcSTom Erickson dnode_sync(DMU_USERUSED_DNODE(os), tx); 1010744947dcSTom Erickson DMU_GROUPUSED_DNODE(os)->dn_zio = zio; 1011744947dcSTom Erickson dnode_sync(DMU_GROUPUSED_DNODE(os), tx); 101214843421SMatthew Ahrens } 101314843421SMatthew Ahrens 1014c717a561Smaybee txgoff = tx->tx_txg & TXG_MASK; 1015fa9e4066Sahrens 101614843421SMatthew Ahrens if (dmu_objset_userused_enabled(os)) { 101714843421SMatthew Ahrens newlist = &os->os_synced_dnodes; 101814843421SMatthew Ahrens /* 101914843421SMatthew Ahrens * We must create the list here because it uses the 102014843421SMatthew Ahrens * dn_dirty_link[] of this txg. 102114843421SMatthew Ahrens */ 102214843421SMatthew Ahrens list_create(newlist, sizeof (dnode_t), 102314843421SMatthew Ahrens offsetof(dnode_t, dn_dirty_link[txgoff])); 102414843421SMatthew Ahrens } 102514843421SMatthew Ahrens 102614843421SMatthew Ahrens dmu_objset_sync_dnodes(&os->os_free_dnodes[txgoff], newlist, tx); 102714843421SMatthew Ahrens dmu_objset_sync_dnodes(&os->os_dirty_dnodes[txgoff], newlist, tx); 1028fa9e4066Sahrens 1029744947dcSTom Erickson list = &DMU_META_DNODE(os)->dn_dirty_records[txgoff]; 1030c717a561Smaybee while (dr = list_head(list)) { 10313b2aab18SMatthew Ahrens ASSERT0(dr->dr_dbuf->db_level); 1032c717a561Smaybee list_remove(list, dr); 1033c717a561Smaybee if (dr->dr_zio) 1034c717a561Smaybee zio_nowait(dr->dr_zio); 1035c717a561Smaybee } 1036c717a561Smaybee /* 1037c717a561Smaybee * Free intent log blocks up to this tx. 1038c717a561Smaybee */ 1039c717a561Smaybee zil_sync(os->os_zil, tx); 1040088f3894Sahrens os->os_phys->os_zil_header = os->os_zil_header; 1041c717a561Smaybee zio_nowait(zio); 1042fa9e4066Sahrens } 1043fa9e4066Sahrens 1044b24ab676SJeff Bonwick boolean_t 1045b24ab676SJeff Bonwick dmu_objset_is_dirty(objset_t *os, uint64_t txg) 1046b24ab676SJeff Bonwick { 1047b24ab676SJeff Bonwick return (!list_is_empty(&os->os_dirty_dnodes[txg & TXG_MASK]) || 1048b24ab676SJeff Bonwick !list_is_empty(&os->os_free_dnodes[txg & TXG_MASK])); 1049b24ab676SJeff Bonwick } 1050b24ab676SJeff Bonwick 1051744947dcSTom Erickson static objset_used_cb_t *used_cbs[DMU_OST_NUMTYPES]; 105214843421SMatthew Ahrens 105314843421SMatthew Ahrens void 105414843421SMatthew Ahrens dmu_objset_register_type(dmu_objset_type_t ost, objset_used_cb_t *cb) 105514843421SMatthew Ahrens { 105614843421SMatthew Ahrens used_cbs[ost] = cb; 105714843421SMatthew Ahrens } 105814843421SMatthew Ahrens 105914843421SMatthew Ahrens boolean_t 1060503ad85cSMatthew Ahrens dmu_objset_userused_enabled(objset_t *os) 106114843421SMatthew Ahrens { 106214843421SMatthew Ahrens return (spa_version(os->os_spa) >= SPA_VERSION_USERSPACE && 1063744947dcSTom Erickson used_cbs[os->os_phys->os_type] != NULL && 1064744947dcSTom Erickson DMU_USERUSED_DNODE(os) != NULL); 106514843421SMatthew Ahrens } 106614843421SMatthew Ahrens 10679966ca11SMatthew Ahrens static void 10680a586ceaSMark Shellenbaum do_userquota_update(objset_t *os, uint64_t used, uint64_t flags, 10690a586ceaSMark Shellenbaum uint64_t user, uint64_t group, boolean_t subtract, dmu_tx_t *tx) 10709966ca11SMatthew Ahrens { 10710a586ceaSMark Shellenbaum if ((flags & DNODE_FLAG_USERUSED_ACCOUNTED)) { 10720a586ceaSMark Shellenbaum int64_t delta = DNODE_SIZE + used; 10739966ca11SMatthew Ahrens if (subtract) 10749966ca11SMatthew Ahrens delta = -delta; 1075b420f3adSRichard Lowe VERIFY3U(0, ==, zap_increment_int(os, DMU_USERUSED_OBJECT, 10769966ca11SMatthew Ahrens user, delta, tx)); 1077b420f3adSRichard Lowe VERIFY3U(0, ==, zap_increment_int(os, DMU_GROUPUSED_OBJECT, 10789966ca11SMatthew Ahrens group, delta, tx)); 10799966ca11SMatthew Ahrens } 10809966ca11SMatthew Ahrens } 10819966ca11SMatthew Ahrens 108214843421SMatthew Ahrens void 10830a586ceaSMark Shellenbaum dmu_objset_do_userquota_updates(objset_t *os, dmu_tx_t *tx) 108414843421SMatthew Ahrens { 108514843421SMatthew Ahrens dnode_t *dn; 108614843421SMatthew Ahrens list_t *list = &os->os_synced_dnodes; 108714843421SMatthew Ahrens 108814843421SMatthew Ahrens ASSERT(list_head(list) == NULL || dmu_objset_userused_enabled(os)); 108914843421SMatthew Ahrens 109014843421SMatthew Ahrens while (dn = list_head(list)) { 10911d8ccc7bSMark Shellenbaum int flags; 109214843421SMatthew Ahrens ASSERT(!DMU_OBJECT_IS_SPECIAL(dn->dn_object)); 109314843421SMatthew Ahrens ASSERT(dn->dn_phys->dn_type == DMU_OT_NONE || 109414843421SMatthew Ahrens dn->dn_phys->dn_flags & 109514843421SMatthew Ahrens DNODE_FLAG_USERUSED_ACCOUNTED); 109614843421SMatthew Ahrens 109714843421SMatthew Ahrens /* Allocate the user/groupused objects if necessary. */ 1098744947dcSTom Erickson if (DMU_USERUSED_DNODE(os)->dn_type == DMU_OT_NONE) { 1099503ad85cSMatthew Ahrens VERIFY(0 == zap_create_claim(os, 110014843421SMatthew Ahrens DMU_USERUSED_OBJECT, 110114843421SMatthew Ahrens DMU_OT_USERGROUP_USED, DMU_OT_NONE, 0, tx)); 1102503ad85cSMatthew Ahrens VERIFY(0 == zap_create_claim(os, 110314843421SMatthew Ahrens DMU_GROUPUSED_OBJECT, 110414843421SMatthew Ahrens DMU_OT_USERGROUP_USED, DMU_OT_NONE, 0, tx)); 110514843421SMatthew Ahrens } 110614843421SMatthew Ahrens 110714843421SMatthew Ahrens /* 11089966ca11SMatthew Ahrens * We intentionally modify the zap object even if the 11090a586ceaSMark Shellenbaum * net delta is zero. Otherwise 11109966ca11SMatthew Ahrens * the block of the zap obj could be shared between 11119966ca11SMatthew Ahrens * datasets but need to be different between them after 11129966ca11SMatthew Ahrens * a bprewrite. 111314843421SMatthew Ahrens */ 111414843421SMatthew Ahrens 11151d8ccc7bSMark Shellenbaum flags = dn->dn_id_flags; 11161d8ccc7bSMark Shellenbaum ASSERT(flags); 11171d8ccc7bSMark Shellenbaum if (flags & DN_ID_OLD_EXIST) { 11180a586ceaSMark Shellenbaum do_userquota_update(os, dn->dn_oldused, dn->dn_oldflags, 11190a586ceaSMark Shellenbaum dn->dn_olduid, dn->dn_oldgid, B_TRUE, tx); 11200a586ceaSMark Shellenbaum } 11211d8ccc7bSMark Shellenbaum if (flags & DN_ID_NEW_EXIST) { 11220a586ceaSMark Shellenbaum do_userquota_update(os, DN_USED_BYTES(dn->dn_phys), 11230a586ceaSMark Shellenbaum dn->dn_phys->dn_flags, dn->dn_newuid, 11240a586ceaSMark Shellenbaum dn->dn_newgid, B_FALSE, tx); 11250a586ceaSMark Shellenbaum } 11260a586ceaSMark Shellenbaum 11271d8ccc7bSMark Shellenbaum mutex_enter(&dn->dn_mtx); 11280a586ceaSMark Shellenbaum dn->dn_oldused = 0; 11290a586ceaSMark Shellenbaum dn->dn_oldflags = 0; 11300a586ceaSMark Shellenbaum if (dn->dn_id_flags & DN_ID_NEW_EXIST) { 11310a586ceaSMark Shellenbaum dn->dn_olduid = dn->dn_newuid; 11320a586ceaSMark Shellenbaum dn->dn_oldgid = dn->dn_newgid; 11330a586ceaSMark Shellenbaum dn->dn_id_flags |= DN_ID_OLD_EXIST; 11340a586ceaSMark Shellenbaum if (dn->dn_bonuslen == 0) 11350a586ceaSMark Shellenbaum dn->dn_id_flags |= DN_ID_CHKED_SPILL; 11360a586ceaSMark Shellenbaum else 11370a586ceaSMark Shellenbaum dn->dn_id_flags |= DN_ID_CHKED_BONUS; 11380a586ceaSMark Shellenbaum } 113928d97a71SMark Shellenbaum dn->dn_id_flags &= ~(DN_ID_NEW_EXIST); 114014843421SMatthew Ahrens mutex_exit(&dn->dn_mtx); 114114843421SMatthew Ahrens 114214843421SMatthew Ahrens list_remove(list, dn); 114314843421SMatthew Ahrens dnode_rele(dn, list); 114414843421SMatthew Ahrens } 114514843421SMatthew Ahrens } 114614843421SMatthew Ahrens 114706e0070dSMark Shellenbaum /* 114806e0070dSMark Shellenbaum * Returns a pointer to data to find uid/gid from 114906e0070dSMark Shellenbaum * 115006e0070dSMark Shellenbaum * If a dirty record for transaction group that is syncing can't 115106e0070dSMark Shellenbaum * be found then NULL is returned. In the NULL case it is assumed 115206e0070dSMark Shellenbaum * the uid/gid aren't changing. 115306e0070dSMark Shellenbaum */ 115406e0070dSMark Shellenbaum static void * 115506e0070dSMark Shellenbaum dmu_objset_userquota_find_data(dmu_buf_impl_t *db, dmu_tx_t *tx) 115606e0070dSMark Shellenbaum { 115706e0070dSMark Shellenbaum dbuf_dirty_record_t *dr, **drp; 115806e0070dSMark Shellenbaum void *data; 115906e0070dSMark Shellenbaum 116006e0070dSMark Shellenbaum if (db->db_dirtycnt == 0) 116106e0070dSMark Shellenbaum return (db->db.db_data); /* Nothing is changing */ 116206e0070dSMark Shellenbaum 116306e0070dSMark Shellenbaum for (drp = &db->db_last_dirty; (dr = *drp) != NULL; drp = &dr->dr_next) 116406e0070dSMark Shellenbaum if (dr->dr_txg == tx->tx_txg) 116506e0070dSMark Shellenbaum break; 116606e0070dSMark Shellenbaum 1167744947dcSTom Erickson if (dr == NULL) { 116806e0070dSMark Shellenbaum data = NULL; 1169744947dcSTom Erickson } else { 1170744947dcSTom Erickson dnode_t *dn; 1171744947dcSTom Erickson 1172744947dcSTom Erickson DB_DNODE_ENTER(dr->dr_dbuf); 1173744947dcSTom Erickson dn = DB_DNODE(dr->dr_dbuf); 1174744947dcSTom Erickson 1175744947dcSTom Erickson if (dn->dn_bonuslen == 0 && 1176744947dcSTom Erickson dr->dr_dbuf->db_blkid == DMU_SPILL_BLKID) 1177744947dcSTom Erickson data = dr->dt.dl.dr_data->b_data; 1178744947dcSTom Erickson else 1179744947dcSTom Erickson data = dr->dt.dl.dr_data; 1180744947dcSTom Erickson 1181744947dcSTom Erickson DB_DNODE_EXIT(dr->dr_dbuf); 1182744947dcSTom Erickson } 1183744947dcSTom Erickson 118406e0070dSMark Shellenbaum return (data); 118506e0070dSMark Shellenbaum } 118606e0070dSMark Shellenbaum 11870a586ceaSMark Shellenbaum void 118806e0070dSMark Shellenbaum dmu_objset_userquota_get_ids(dnode_t *dn, boolean_t before, dmu_tx_t *tx) 11890a586ceaSMark Shellenbaum { 11900a586ceaSMark Shellenbaum objset_t *os = dn->dn_objset; 11910a586ceaSMark Shellenbaum void *data = NULL; 119206e0070dSMark Shellenbaum dmu_buf_impl_t *db = NULL; 1193d5285caeSGeorge Wilson uint64_t *user = NULL; 1194d5285caeSGeorge Wilson uint64_t *group = NULL; 11950a586ceaSMark Shellenbaum int flags = dn->dn_id_flags; 11960a586ceaSMark Shellenbaum int error; 119706e0070dSMark Shellenbaum boolean_t have_spill = B_FALSE; 11980a586ceaSMark Shellenbaum 11990a586ceaSMark Shellenbaum if (!dmu_objset_userused_enabled(dn->dn_objset)) 12000a586ceaSMark Shellenbaum return; 12010a586ceaSMark Shellenbaum 12020a586ceaSMark Shellenbaum if (before && (flags & (DN_ID_CHKED_BONUS|DN_ID_OLD_EXIST| 12030a586ceaSMark Shellenbaum DN_ID_CHKED_SPILL))) 12040a586ceaSMark Shellenbaum return; 12050a586ceaSMark Shellenbaum 12060a586ceaSMark Shellenbaum if (before && dn->dn_bonuslen != 0) 12070a586ceaSMark Shellenbaum data = DN_BONUS(dn->dn_phys); 120806e0070dSMark Shellenbaum else if (!before && dn->dn_bonuslen != 0) { 120906e0070dSMark Shellenbaum if (dn->dn_bonus) { 121006e0070dSMark Shellenbaum db = dn->dn_bonus; 121106e0070dSMark Shellenbaum mutex_enter(&db->db_mtx); 121206e0070dSMark Shellenbaum data = dmu_objset_userquota_find_data(db, tx); 121306e0070dSMark Shellenbaum } else { 121406e0070dSMark Shellenbaum data = DN_BONUS(dn->dn_phys); 121506e0070dSMark Shellenbaum } 121606e0070dSMark Shellenbaum } else if (dn->dn_bonuslen == 0 && dn->dn_bonustype == DMU_OT_SA) { 12170a586ceaSMark Shellenbaum int rf = 0; 12180a586ceaSMark Shellenbaum 12190a586ceaSMark Shellenbaum if (RW_WRITE_HELD(&dn->dn_struct_rwlock)) 12200a586ceaSMark Shellenbaum rf |= DB_RF_HAVESTRUCT; 12211d8ccc7bSMark Shellenbaum error = dmu_spill_hold_by_dnode(dn, 12221d8ccc7bSMark Shellenbaum rf | DB_RF_MUST_SUCCEED, 122306e0070dSMark Shellenbaum FTAG, (dmu_buf_t **)&db); 12240a586ceaSMark Shellenbaum ASSERT(error == 0); 122506e0070dSMark Shellenbaum mutex_enter(&db->db_mtx); 122606e0070dSMark Shellenbaum data = (before) ? db->db.db_data : 122706e0070dSMark Shellenbaum dmu_objset_userquota_find_data(db, tx); 122806e0070dSMark Shellenbaum have_spill = B_TRUE; 12290a586ceaSMark Shellenbaum } else { 12300a586ceaSMark Shellenbaum mutex_enter(&dn->dn_mtx); 12310a586ceaSMark Shellenbaum dn->dn_id_flags |= DN_ID_CHKED_BONUS; 12320a586ceaSMark Shellenbaum mutex_exit(&dn->dn_mtx); 12330a586ceaSMark Shellenbaum return; 12340a586ceaSMark Shellenbaum } 12350a586ceaSMark Shellenbaum 12360a586ceaSMark Shellenbaum if (before) { 123706e0070dSMark Shellenbaum ASSERT(data); 12380a586ceaSMark Shellenbaum user = &dn->dn_olduid; 12390a586ceaSMark Shellenbaum group = &dn->dn_oldgid; 124006e0070dSMark Shellenbaum } else if (data) { 12410a586ceaSMark Shellenbaum user = &dn->dn_newuid; 12420a586ceaSMark Shellenbaum group = &dn->dn_newgid; 12430a586ceaSMark Shellenbaum } 12440a586ceaSMark Shellenbaum 124506e0070dSMark Shellenbaum /* 124606e0070dSMark Shellenbaum * Must always call the callback in case the object 124706e0070dSMark Shellenbaum * type has changed and that type isn't an object type to track 124806e0070dSMark Shellenbaum */ 12490a586ceaSMark Shellenbaum error = used_cbs[os->os_phys->os_type](dn->dn_bonustype, data, 12500a586ceaSMark Shellenbaum user, group); 12510a586ceaSMark Shellenbaum 125206e0070dSMark Shellenbaum /* 125306e0070dSMark Shellenbaum * Preserve existing uid/gid when the callback can't determine 125406e0070dSMark Shellenbaum * what the new uid/gid are and the callback returned EEXIST. 125506e0070dSMark Shellenbaum * The EEXIST error tells us to just use the existing uid/gid. 125606e0070dSMark Shellenbaum * If we don't know what the old values are then just assign 125706e0070dSMark Shellenbaum * them to 0, since that is a new file being created. 125806e0070dSMark Shellenbaum */ 125906e0070dSMark Shellenbaum if (!before && data == NULL && error == EEXIST) { 126006e0070dSMark Shellenbaum if (flags & DN_ID_OLD_EXIST) { 126106e0070dSMark Shellenbaum dn->dn_newuid = dn->dn_olduid; 126206e0070dSMark Shellenbaum dn->dn_newgid = dn->dn_oldgid; 126306e0070dSMark Shellenbaum } else { 126406e0070dSMark Shellenbaum dn->dn_newuid = 0; 126506e0070dSMark Shellenbaum dn->dn_newgid = 0; 126606e0070dSMark Shellenbaum } 126706e0070dSMark Shellenbaum error = 0; 126806e0070dSMark Shellenbaum } 126906e0070dSMark Shellenbaum 127006e0070dSMark Shellenbaum if (db) 127106e0070dSMark Shellenbaum mutex_exit(&db->db_mtx); 127206e0070dSMark Shellenbaum 12730a586ceaSMark Shellenbaum mutex_enter(&dn->dn_mtx); 12740a586ceaSMark Shellenbaum if (error == 0 && before) 12750a586ceaSMark Shellenbaum dn->dn_id_flags |= DN_ID_OLD_EXIST; 12760a586ceaSMark Shellenbaum if (error == 0 && !before) 12770a586ceaSMark Shellenbaum dn->dn_id_flags |= DN_ID_NEW_EXIST; 12780a586ceaSMark Shellenbaum 127906e0070dSMark Shellenbaum if (have_spill) { 12800a586ceaSMark Shellenbaum dn->dn_id_flags |= DN_ID_CHKED_SPILL; 12810a586ceaSMark Shellenbaum } else { 12820a586ceaSMark Shellenbaum dn->dn_id_flags |= DN_ID_CHKED_BONUS; 12830a586ceaSMark Shellenbaum } 12840a586ceaSMark Shellenbaum mutex_exit(&dn->dn_mtx); 128506e0070dSMark Shellenbaum if (have_spill) 128606e0070dSMark Shellenbaum dmu_buf_rele((dmu_buf_t *)db, FTAG); 12870a586ceaSMark Shellenbaum } 12880a586ceaSMark Shellenbaum 128914843421SMatthew Ahrens boolean_t 129014843421SMatthew Ahrens dmu_objset_userspace_present(objset_t *os) 129114843421SMatthew Ahrens { 1292503ad85cSMatthew Ahrens return (os->os_phys->os_flags & 129314843421SMatthew Ahrens OBJSET_FLAG_USERACCOUNTING_COMPLETE); 129414843421SMatthew Ahrens } 129514843421SMatthew Ahrens 129614843421SMatthew Ahrens int 129714843421SMatthew Ahrens dmu_objset_userspace_upgrade(objset_t *os) 129814843421SMatthew Ahrens { 129914843421SMatthew Ahrens uint64_t obj; 130014843421SMatthew Ahrens int err = 0; 130114843421SMatthew Ahrens 130214843421SMatthew Ahrens if (dmu_objset_userspace_present(os)) 130314843421SMatthew Ahrens return (0); 1304503ad85cSMatthew Ahrens if (!dmu_objset_userused_enabled(os)) 1305*be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 130614843421SMatthew Ahrens if (dmu_objset_is_snapshot(os)) 1307*be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 130814843421SMatthew Ahrens 130914843421SMatthew Ahrens /* 131014843421SMatthew Ahrens * We simply need to mark every object dirty, so that it will be 131114843421SMatthew Ahrens * synced out and now accounted. If this is called 131214843421SMatthew Ahrens * concurrently, or if we already did some work before crashing, 131314843421SMatthew Ahrens * that's fine, since we track each object's accounted state 131414843421SMatthew Ahrens * independently. 131514843421SMatthew Ahrens */ 131614843421SMatthew Ahrens 131714843421SMatthew Ahrens for (obj = 0; err == 0; err = dmu_object_next(os, &obj, FALSE, 0)) { 131868857716SLin Ling dmu_tx_t *tx; 131914843421SMatthew Ahrens dmu_buf_t *db; 132014843421SMatthew Ahrens int objerr; 132114843421SMatthew Ahrens 132214843421SMatthew Ahrens if (issig(JUSTLOOKING) && issig(FORREAL)) 1323*be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 132414843421SMatthew Ahrens 132514843421SMatthew Ahrens objerr = dmu_bonus_hold(os, obj, FTAG, &db); 13263b2aab18SMatthew Ahrens if (objerr != 0) 132714843421SMatthew Ahrens continue; 132868857716SLin Ling tx = dmu_tx_create(os); 132914843421SMatthew Ahrens dmu_tx_hold_bonus(tx, obj); 133014843421SMatthew Ahrens objerr = dmu_tx_assign(tx, TXG_WAIT); 13313b2aab18SMatthew Ahrens if (objerr != 0) { 133214843421SMatthew Ahrens dmu_tx_abort(tx); 133314843421SMatthew Ahrens continue; 133414843421SMatthew Ahrens } 133514843421SMatthew Ahrens dmu_buf_will_dirty(db, tx); 133614843421SMatthew Ahrens dmu_buf_rele(db, FTAG); 133714843421SMatthew Ahrens dmu_tx_commit(tx); 133814843421SMatthew Ahrens } 133914843421SMatthew Ahrens 1340503ad85cSMatthew Ahrens os->os_flags |= OBJSET_FLAG_USERACCOUNTING_COMPLETE; 134114843421SMatthew Ahrens txg_wait_synced(dmu_objset_pool(os), 0); 134214843421SMatthew Ahrens return (0); 134314843421SMatthew Ahrens } 134414843421SMatthew Ahrens 1345fa9e4066Sahrens void 1346a2eea2e1Sahrens dmu_objset_space(objset_t *os, uint64_t *refdbytesp, uint64_t *availbytesp, 1347a2eea2e1Sahrens uint64_t *usedobjsp, uint64_t *availobjsp) 1348fa9e4066Sahrens { 1349503ad85cSMatthew Ahrens dsl_dataset_space(os->os_dsl_dataset, refdbytesp, availbytesp, 1350a2eea2e1Sahrens usedobjsp, availobjsp); 1351a2eea2e1Sahrens } 1352a2eea2e1Sahrens 1353a2eea2e1Sahrens uint64_t 1354a2eea2e1Sahrens dmu_objset_fsid_guid(objset_t *os) 1355a2eea2e1Sahrens { 1356503ad85cSMatthew Ahrens return (dsl_dataset_fsid_guid(os->os_dsl_dataset)); 1357a2eea2e1Sahrens } 1358a2eea2e1Sahrens 1359a2eea2e1Sahrens void 1360a2eea2e1Sahrens dmu_objset_fast_stat(objset_t *os, dmu_objset_stats_t *stat) 1361a2eea2e1Sahrens { 1362503ad85cSMatthew Ahrens stat->dds_type = os->os_phys->os_type; 1363503ad85cSMatthew Ahrens if (os->os_dsl_dataset) 1364503ad85cSMatthew Ahrens dsl_dataset_fast_stat(os->os_dsl_dataset, stat); 1365a2eea2e1Sahrens } 1366a2eea2e1Sahrens 1367a2eea2e1Sahrens void 1368a2eea2e1Sahrens dmu_objset_stats(objset_t *os, nvlist_t *nv) 1369a2eea2e1Sahrens { 1370503ad85cSMatthew Ahrens ASSERT(os->os_dsl_dataset || 1371503ad85cSMatthew Ahrens os->os_phys->os_type == DMU_OST_META); 1372a2eea2e1Sahrens 1373503ad85cSMatthew Ahrens if (os->os_dsl_dataset != NULL) 1374503ad85cSMatthew Ahrens dsl_dataset_stats(os->os_dsl_dataset, nv); 1375a2eea2e1Sahrens 1376a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_TYPE, 1377503ad85cSMatthew Ahrens os->os_phys->os_type); 137814843421SMatthew Ahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USERACCOUNTING, 137914843421SMatthew Ahrens dmu_objset_userspace_present(os)); 1380fa9e4066Sahrens } 1381fa9e4066Sahrens 1382fa9e4066Sahrens int 1383fa9e4066Sahrens dmu_objset_is_snapshot(objset_t *os) 1384fa9e4066Sahrens { 1385503ad85cSMatthew Ahrens if (os->os_dsl_dataset != NULL) 1386503ad85cSMatthew Ahrens return (dsl_dataset_is_snapshot(os->os_dsl_dataset)); 1387fa9e4066Sahrens else 1388fa9e4066Sahrens return (B_FALSE); 1389fa9e4066Sahrens } 1390fa9e4066Sahrens 1391ab04eb8eStimh int 1392ab04eb8eStimh dmu_snapshot_realname(objset_t *os, char *name, char *real, int maxlen, 1393ab04eb8eStimh boolean_t *conflict) 1394ab04eb8eStimh { 1395503ad85cSMatthew Ahrens dsl_dataset_t *ds = os->os_dsl_dataset; 1396ab04eb8eStimh uint64_t ignored; 1397ab04eb8eStimh 1398ab04eb8eStimh if (ds->ds_phys->ds_snapnames_zapobj == 0) 1399*be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 1400ab04eb8eStimh 1401ab04eb8eStimh return (zap_lookup_norm(ds->ds_dir->dd_pool->dp_meta_objset, 1402ab04eb8eStimh ds->ds_phys->ds_snapnames_zapobj, name, 8, 1, &ignored, MT_FIRST, 1403ab04eb8eStimh real, maxlen, conflict)); 1404ab04eb8eStimh } 1405ab04eb8eStimh 1406fa9e4066Sahrens int 1407fa9e4066Sahrens dmu_snapshot_list_next(objset_t *os, int namelen, char *name, 1408b38f0970Sck uint64_t *idp, uint64_t *offp, boolean_t *case_conflict) 1409fa9e4066Sahrens { 1410503ad85cSMatthew Ahrens dsl_dataset_t *ds = os->os_dsl_dataset; 1411fa9e4066Sahrens zap_cursor_t cursor; 1412fa9e4066Sahrens zap_attribute_t attr; 1413fa9e4066Sahrens 14143b2aab18SMatthew Ahrens ASSERT(dsl_pool_config_held(dmu_objset_pool(os))); 14153b2aab18SMatthew Ahrens 1416fa9e4066Sahrens if (ds->ds_phys->ds_snapnames_zapobj == 0) 1417*be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 1418fa9e4066Sahrens 1419fa9e4066Sahrens zap_cursor_init_serialized(&cursor, 1420fa9e4066Sahrens ds->ds_dir->dd_pool->dp_meta_objset, 1421fa9e4066Sahrens ds->ds_phys->ds_snapnames_zapobj, *offp); 1422fa9e4066Sahrens 142387e5029aSahrens if (zap_cursor_retrieve(&cursor, &attr) != 0) { 142487e5029aSahrens zap_cursor_fini(&cursor); 1425*be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 142687e5029aSahrens } 142787e5029aSahrens 142887e5029aSahrens if (strlen(attr.za_name) + 1 > namelen) { 142987e5029aSahrens zap_cursor_fini(&cursor); 1430*be6fd75aSMatthew Ahrens return (SET_ERROR(ENAMETOOLONG)); 143187e5029aSahrens } 143287e5029aSahrens 143387e5029aSahrens (void) strcpy(name, attr.za_name); 143487e5029aSahrens if (idp) 143587e5029aSahrens *idp = attr.za_first_integer; 1436b38f0970Sck if (case_conflict) 1437b38f0970Sck *case_conflict = attr.za_normalization_conflict; 143887e5029aSahrens zap_cursor_advance(&cursor); 143987e5029aSahrens *offp = zap_cursor_serialize(&cursor); 144087e5029aSahrens zap_cursor_fini(&cursor); 144187e5029aSahrens 144287e5029aSahrens return (0); 144387e5029aSahrens } 144487e5029aSahrens 144587e5029aSahrens int 144687e5029aSahrens dmu_dir_list_next(objset_t *os, int namelen, char *name, 144787e5029aSahrens uint64_t *idp, uint64_t *offp) 144887e5029aSahrens { 1449503ad85cSMatthew Ahrens dsl_dir_t *dd = os->os_dsl_dataset->ds_dir; 145087e5029aSahrens zap_cursor_t cursor; 145187e5029aSahrens zap_attribute_t attr; 145287e5029aSahrens 145387e5029aSahrens /* there is no next dir on a snapshot! */ 1454503ad85cSMatthew Ahrens if (os->os_dsl_dataset->ds_object != 145587e5029aSahrens dd->dd_phys->dd_head_dataset_obj) 1456*be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 1457fa9e4066Sahrens 145887e5029aSahrens zap_cursor_init_serialized(&cursor, 145987e5029aSahrens dd->dd_pool->dp_meta_objset, 146087e5029aSahrens dd->dd_phys->dd_child_dir_zapobj, *offp); 146187e5029aSahrens 146287e5029aSahrens if (zap_cursor_retrieve(&cursor, &attr) != 0) { 146387e5029aSahrens zap_cursor_fini(&cursor); 1464*be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 146587e5029aSahrens } 146687e5029aSahrens 146787e5029aSahrens if (strlen(attr.za_name) + 1 > namelen) { 146887e5029aSahrens zap_cursor_fini(&cursor); 1469*be6fd75aSMatthew Ahrens return (SET_ERROR(ENAMETOOLONG)); 147087e5029aSahrens } 1471fa9e4066Sahrens 1472fa9e4066Sahrens (void) strcpy(name, attr.za_name); 147387e5029aSahrens if (idp) 147487e5029aSahrens *idp = attr.za_first_integer; 1475fa9e4066Sahrens zap_cursor_advance(&cursor); 1476fa9e4066Sahrens *offp = zap_cursor_serialize(&cursor); 147787e5029aSahrens zap_cursor_fini(&cursor); 1478fa9e4066Sahrens 1479fa9e4066Sahrens return (0); 1480fa9e4066Sahrens } 1481fa9e4066Sahrens 1482fa9e4066Sahrens /* 14833b2aab18SMatthew Ahrens * Find objsets under and including ddobj, call func(ds) on each. 1484fa9e4066Sahrens */ 14851d452cf5Sahrens int 14863b2aab18SMatthew Ahrens dmu_objset_find_dp(dsl_pool_t *dp, uint64_t ddobj, 14873b2aab18SMatthew Ahrens int func(dsl_pool_t *, dsl_dataset_t *, void *), void *arg, int flags) 1488088f3894Sahrens { 14893b2aab18SMatthew Ahrens dsl_dir_t *dd; 14903b2aab18SMatthew Ahrens dsl_dataset_t *ds; 14913b2aab18SMatthew Ahrens zap_cursor_t zc; 14923b2aab18SMatthew Ahrens zap_attribute_t *attr; 14933b2aab18SMatthew Ahrens uint64_t thisobj; 14943b2aab18SMatthew Ahrens int err; 14953b2aab18SMatthew Ahrens 14963b2aab18SMatthew Ahrens ASSERT(dsl_pool_config_held(dp)); 14973b2aab18SMatthew Ahrens 14983b2aab18SMatthew Ahrens err = dsl_dir_hold_obj(dp, ddobj, NULL, FTAG, &dd); 14993b2aab18SMatthew Ahrens if (err != 0) 15003b2aab18SMatthew Ahrens return (err); 15013b2aab18SMatthew Ahrens 15023b2aab18SMatthew Ahrens /* Don't visit hidden ($MOS & $ORIGIN) objsets. */ 15033b2aab18SMatthew Ahrens if (dd->dd_myname[0] == '$') { 15043b2aab18SMatthew Ahrens dsl_dir_rele(dd, FTAG); 15053b2aab18SMatthew Ahrens return (0); 15063b2aab18SMatthew Ahrens } 15073b2aab18SMatthew Ahrens 15083b2aab18SMatthew Ahrens thisobj = dd->dd_phys->dd_head_dataset_obj; 15093b2aab18SMatthew Ahrens attr = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); 15103b2aab18SMatthew Ahrens 15113b2aab18SMatthew Ahrens /* 15123b2aab18SMatthew Ahrens * Iterate over all children. 15133b2aab18SMatthew Ahrens */ 15143b2aab18SMatthew Ahrens if (flags & DS_FIND_CHILDREN) { 15153b2aab18SMatthew Ahrens for (zap_cursor_init(&zc, dp->dp_meta_objset, 15163b2aab18SMatthew Ahrens dd->dd_phys->dd_child_dir_zapobj); 15173b2aab18SMatthew Ahrens zap_cursor_retrieve(&zc, attr) == 0; 15183b2aab18SMatthew Ahrens (void) zap_cursor_advance(&zc)) { 15193b2aab18SMatthew Ahrens ASSERT3U(attr->za_integer_length, ==, 15203b2aab18SMatthew Ahrens sizeof (uint64_t)); 15213b2aab18SMatthew Ahrens ASSERT3U(attr->za_num_integers, ==, 1); 15223b2aab18SMatthew Ahrens 15233b2aab18SMatthew Ahrens err = dmu_objset_find_dp(dp, attr->za_first_integer, 15243b2aab18SMatthew Ahrens func, arg, flags); 15253b2aab18SMatthew Ahrens if (err != 0) 15263b2aab18SMatthew Ahrens break; 15273b2aab18SMatthew Ahrens } 15283b2aab18SMatthew Ahrens zap_cursor_fini(&zc); 15293b2aab18SMatthew Ahrens 15303b2aab18SMatthew Ahrens if (err != 0) { 15313b2aab18SMatthew Ahrens dsl_dir_rele(dd, FTAG); 15323b2aab18SMatthew Ahrens kmem_free(attr, sizeof (zap_attribute_t)); 15333b2aab18SMatthew Ahrens return (err); 15343b2aab18SMatthew Ahrens } 15353b2aab18SMatthew Ahrens } 15363b2aab18SMatthew Ahrens 15373b2aab18SMatthew Ahrens /* 15383b2aab18SMatthew Ahrens * Iterate over all snapshots. 15393b2aab18SMatthew Ahrens */ 15403b2aab18SMatthew Ahrens if (flags & DS_FIND_SNAPSHOTS) { 15413b2aab18SMatthew Ahrens dsl_dataset_t *ds; 15423b2aab18SMatthew Ahrens err = dsl_dataset_hold_obj(dp, thisobj, FTAG, &ds); 15433b2aab18SMatthew Ahrens 15443b2aab18SMatthew Ahrens if (err == 0) { 15453b2aab18SMatthew Ahrens uint64_t snapobj = ds->ds_phys->ds_snapnames_zapobj; 15463b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 15473b2aab18SMatthew Ahrens 15483b2aab18SMatthew Ahrens for (zap_cursor_init(&zc, dp->dp_meta_objset, snapobj); 15493b2aab18SMatthew Ahrens zap_cursor_retrieve(&zc, attr) == 0; 15503b2aab18SMatthew Ahrens (void) zap_cursor_advance(&zc)) { 15513b2aab18SMatthew Ahrens ASSERT3U(attr->za_integer_length, ==, 15523b2aab18SMatthew Ahrens sizeof (uint64_t)); 15533b2aab18SMatthew Ahrens ASSERT3U(attr->za_num_integers, ==, 1); 15543b2aab18SMatthew Ahrens 15553b2aab18SMatthew Ahrens err = dsl_dataset_hold_obj(dp, 15563b2aab18SMatthew Ahrens attr->za_first_integer, FTAG, &ds); 15573b2aab18SMatthew Ahrens if (err != 0) 15583b2aab18SMatthew Ahrens break; 15593b2aab18SMatthew Ahrens err = func(dp, ds, arg); 15603b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 15613b2aab18SMatthew Ahrens if (err != 0) 15623b2aab18SMatthew Ahrens break; 15633b2aab18SMatthew Ahrens } 15643b2aab18SMatthew Ahrens zap_cursor_fini(&zc); 15653b2aab18SMatthew Ahrens } 15663b2aab18SMatthew Ahrens } 15673b2aab18SMatthew Ahrens 15683b2aab18SMatthew Ahrens dsl_dir_rele(dd, FTAG); 15693b2aab18SMatthew Ahrens kmem_free(attr, sizeof (zap_attribute_t)); 15703b2aab18SMatthew Ahrens 15713b2aab18SMatthew Ahrens if (err != 0) 15723b2aab18SMatthew Ahrens return (err); 15733b2aab18SMatthew Ahrens 15743b2aab18SMatthew Ahrens /* 15753b2aab18SMatthew Ahrens * Apply to self. 15763b2aab18SMatthew Ahrens */ 15773b2aab18SMatthew Ahrens err = dsl_dataset_hold_obj(dp, thisobj, FTAG, &ds); 15783b2aab18SMatthew Ahrens if (err != 0) 15793b2aab18SMatthew Ahrens return (err); 15803b2aab18SMatthew Ahrens err = func(dp, ds, arg); 15813b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 15823b2aab18SMatthew Ahrens return (err); 1583088f3894Sahrens } 1584088f3894Sahrens 1585088f3894Sahrens /* 15863b2aab18SMatthew Ahrens * Find all objsets under name, and for each, call 'func(child_name, arg)'. 15873b2aab18SMatthew Ahrens * The dp_config_rwlock must not be held when this is called, and it 15883b2aab18SMatthew Ahrens * will not be held when the callback is called. 15893b2aab18SMatthew Ahrens * Therefore this function should only be used when the pool is not changing 15903b2aab18SMatthew Ahrens * (e.g. in syncing context), or the callback can deal with the possible races. 1591088f3894Sahrens */ 15923b2aab18SMatthew Ahrens static int 15933b2aab18SMatthew Ahrens dmu_objset_find_impl(spa_t *spa, const char *name, 15943b2aab18SMatthew Ahrens int func(const char *, void *), void *arg, int flags) 1595fa9e4066Sahrens { 1596fa9e4066Sahrens dsl_dir_t *dd; 15973b2aab18SMatthew Ahrens dsl_pool_t *dp = spa_get_dsl(spa); 1598088f3894Sahrens dsl_dataset_t *ds; 1599fa9e4066Sahrens zap_cursor_t zc; 1600b7661cccSmmusante zap_attribute_t *attr; 1601fa9e4066Sahrens char *child; 1602088f3894Sahrens uint64_t thisobj; 1603088f3894Sahrens int err; 1604fa9e4066Sahrens 16053b2aab18SMatthew Ahrens dsl_pool_config_enter(dp, FTAG); 16063b2aab18SMatthew Ahrens 16073b2aab18SMatthew Ahrens err = dsl_dir_hold(dp, name, FTAG, &dd, NULL); 16083b2aab18SMatthew Ahrens if (err != 0) { 16093b2aab18SMatthew Ahrens dsl_pool_config_exit(dp, FTAG); 16101d452cf5Sahrens return (err); 16113b2aab18SMatthew Ahrens } 1612fa9e4066Sahrens 1613088f3894Sahrens /* Don't visit hidden ($MOS & $ORIGIN) objsets. */ 1614088f3894Sahrens if (dd->dd_myname[0] == '$') { 16153b2aab18SMatthew Ahrens dsl_dir_rele(dd, FTAG); 16163b2aab18SMatthew Ahrens dsl_pool_config_exit(dp, FTAG); 1617088f3894Sahrens return (0); 1618088f3894Sahrens } 1619088f3894Sahrens 1620088f3894Sahrens thisobj = dd->dd_phys->dd_head_dataset_obj; 1621b7661cccSmmusante attr = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); 1622fa9e4066Sahrens 1623fa9e4066Sahrens /* 1624fa9e4066Sahrens * Iterate over all children. 1625fa9e4066Sahrens */ 16260b69c2f0Sahrens if (flags & DS_FIND_CHILDREN) { 1627088f3894Sahrens for (zap_cursor_init(&zc, dp->dp_meta_objset, 16280b69c2f0Sahrens dd->dd_phys->dd_child_dir_zapobj); 1629b7661cccSmmusante zap_cursor_retrieve(&zc, attr) == 0; 16300b69c2f0Sahrens (void) zap_cursor_advance(&zc)) { 16313b2aab18SMatthew Ahrens ASSERT3U(attr->za_integer_length, ==, 16323b2aab18SMatthew Ahrens sizeof (uint64_t)); 16333b2aab18SMatthew Ahrens ASSERT3U(attr->za_num_integers, ==, 1); 1634fa9e4066Sahrens 1635486ae710SMatthew Ahrens child = kmem_asprintf("%s/%s", name, attr->za_name); 16363b2aab18SMatthew Ahrens dsl_pool_config_exit(dp, FTAG); 16373b2aab18SMatthew Ahrens err = dmu_objset_find_impl(spa, child, 16383b2aab18SMatthew Ahrens func, arg, flags); 16393b2aab18SMatthew Ahrens dsl_pool_config_enter(dp, FTAG); 1640486ae710SMatthew Ahrens strfree(child); 16413b2aab18SMatthew Ahrens if (err != 0) 16420b69c2f0Sahrens break; 16430b69c2f0Sahrens } 16440b69c2f0Sahrens zap_cursor_fini(&zc); 16451d452cf5Sahrens 16463b2aab18SMatthew Ahrens if (err != 0) { 16473b2aab18SMatthew Ahrens dsl_dir_rele(dd, FTAG); 16483b2aab18SMatthew Ahrens dsl_pool_config_exit(dp, FTAG); 1649b7661cccSmmusante kmem_free(attr, sizeof (zap_attribute_t)); 16500b69c2f0Sahrens return (err); 16510b69c2f0Sahrens } 1652fa9e4066Sahrens } 1653fa9e4066Sahrens 1654fa9e4066Sahrens /* 1655fa9e4066Sahrens * Iterate over all snapshots. 1656fa9e4066Sahrens */ 1657088f3894Sahrens if (flags & DS_FIND_SNAPSHOTS) { 1658088f3894Sahrens err = dsl_dataset_hold_obj(dp, thisobj, FTAG, &ds); 1659088f3894Sahrens 1660088f3894Sahrens if (err == 0) { 1661088f3894Sahrens uint64_t snapobj = ds->ds_phys->ds_snapnames_zapobj; 1662088f3894Sahrens dsl_dataset_rele(ds, FTAG); 1663088f3894Sahrens 1664088f3894Sahrens for (zap_cursor_init(&zc, dp->dp_meta_objset, snapobj); 1665088f3894Sahrens zap_cursor_retrieve(&zc, attr) == 0; 1666088f3894Sahrens (void) zap_cursor_advance(&zc)) { 16673b2aab18SMatthew Ahrens ASSERT3U(attr->za_integer_length, ==, 1668088f3894Sahrens sizeof (uint64_t)); 16693b2aab18SMatthew Ahrens ASSERT3U(attr->za_num_integers, ==, 1); 1670088f3894Sahrens 1671486ae710SMatthew Ahrens child = kmem_asprintf("%s@%s", 1672486ae710SMatthew Ahrens name, attr->za_name); 16733b2aab18SMatthew Ahrens dsl_pool_config_exit(dp, FTAG); 16743b2aab18SMatthew Ahrens err = func(child, arg); 16753b2aab18SMatthew Ahrens dsl_pool_config_enter(dp, FTAG); 1676486ae710SMatthew Ahrens strfree(child); 16773b2aab18SMatthew Ahrens if (err != 0) 1678088f3894Sahrens break; 1679088f3894Sahrens } 1680088f3894Sahrens zap_cursor_fini(&zc); 1681fa9e4066Sahrens } 1682fa9e4066Sahrens } 1683fa9e4066Sahrens 16843b2aab18SMatthew Ahrens dsl_dir_rele(dd, FTAG); 1685b7661cccSmmusante kmem_free(attr, sizeof (zap_attribute_t)); 16863b2aab18SMatthew Ahrens dsl_pool_config_exit(dp, FTAG); 1687fa9e4066Sahrens 16883b2aab18SMatthew Ahrens if (err != 0) 16891d452cf5Sahrens return (err); 16901d452cf5Sahrens 16913b2aab18SMatthew Ahrens /* Apply to self. */ 16923b2aab18SMatthew Ahrens return (func(name, arg)); 1693fa9e4066Sahrens } 1694f18faf3fSek 16953b2aab18SMatthew Ahrens /* 16963b2aab18SMatthew Ahrens * See comment above dmu_objset_find_impl(). 16973b2aab18SMatthew Ahrens */ 16987f73c863SRich Morris int 16993b2aab18SMatthew Ahrens dmu_objset_find(char *name, int func(const char *, void *), void *arg, 17003b2aab18SMatthew Ahrens int flags) 17017f73c863SRich Morris { 17023b2aab18SMatthew Ahrens spa_t *spa; 17033b2aab18SMatthew Ahrens int error; 17047f73c863SRich Morris 17053b2aab18SMatthew Ahrens error = spa_open(name, &spa, FTAG); 17063b2aab18SMatthew Ahrens if (error != 0) 17073b2aab18SMatthew Ahrens return (error); 17083b2aab18SMatthew Ahrens error = dmu_objset_find_impl(spa, name, func, arg, flags); 17093b2aab18SMatthew Ahrens spa_close(spa, FTAG); 17103b2aab18SMatthew Ahrens return (error); 17117f73c863SRich Morris } 17127f73c863SRich Morris 1713f18faf3fSek void 1714f18faf3fSek dmu_objset_set_user(objset_t *os, void *user_ptr) 1715f18faf3fSek { 1716503ad85cSMatthew Ahrens ASSERT(MUTEX_HELD(&os->os_user_ptr_lock)); 1717503ad85cSMatthew Ahrens os->os_user_ptr = user_ptr; 1718f18faf3fSek } 1719f18faf3fSek 1720f18faf3fSek void * 1721f18faf3fSek dmu_objset_get_user(objset_t *os) 1722f18faf3fSek { 1723503ad85cSMatthew Ahrens ASSERT(MUTEX_HELD(&os->os_user_ptr_lock)); 1724503ad85cSMatthew Ahrens return (os->os_user_ptr); 1725f18faf3fSek } 17263b2aab18SMatthew Ahrens 17273b2aab18SMatthew Ahrens /* 17283b2aab18SMatthew Ahrens * Determine name of filesystem, given name of snapshot. 17293b2aab18SMatthew Ahrens * buf must be at least MAXNAMELEN bytes 17303b2aab18SMatthew Ahrens */ 17313b2aab18SMatthew Ahrens int 17323b2aab18SMatthew Ahrens dmu_fsname(const char *snapname, char *buf) 17333b2aab18SMatthew Ahrens { 17343b2aab18SMatthew Ahrens char *atp = strchr(snapname, '@'); 17353b2aab18SMatthew Ahrens if (atp == NULL) 1736*be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 17373b2aab18SMatthew Ahrens if (atp - snapname >= MAXNAMELEN) 1738*be6fd75aSMatthew Ahrens return (SET_ERROR(ENAMETOOLONG)); 17393b2aab18SMatthew Ahrens (void) strlcpy(buf, snapname, atp - snapname + 1); 17403b2aab18SMatthew Ahrens return (0); 17413b2aab18SMatthew Ahrens } 1742