1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5033f9833Sek * Common Development and Distribution License (the "License"). 6033f9833Sek * 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 /* 22dc7cd546SMark Shellenbaum * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 231fdcbd00SMatthew Ahrens * Copyright (c) 2012, 2015 by Delphix. All rights reserved. 24c3d26abcSMatthew Ahrens * Copyright (c) 2014 Integros [integros.com] 25eb721827SAlek Pinchuk * Copyright 2016 Nexenta Systems, Inc. All rights reserved. 26*f67950b2SNasf-Fan * Copyright 2019 Joyent, Inc. 27fa9e4066Sahrens */ 28fa9e4066Sahrens 2955da60b9SMark J Musante /* Portions Copyright 2010 Robert Milkowski */ 3055da60b9SMark J Musante 31fa9e4066Sahrens #include <sys/types.h> 32fa9e4066Sahrens #include <sys/param.h> 33fa9e4066Sahrens #include <sys/systm.h> 34fa9e4066Sahrens #include <sys/sysmacros.h> 35fa9e4066Sahrens #include <sys/kmem.h> 36fa9e4066Sahrens #include <sys/pathname.h> 37fa9e4066Sahrens #include <sys/vnode.h> 38fa9e4066Sahrens #include <sys/vfs.h> 39aa59c4cbSrsb #include <sys/vfs_opreg.h> 40fa9e4066Sahrens #include <sys/mntent.h> 41fa9e4066Sahrens #include <sys/mount.h> 42fa9e4066Sahrens #include <sys/cmn_err.h> 43fa9e4066Sahrens #include "fs/fs_subr.h" 44fa9e4066Sahrens #include <sys/zfs_znode.h> 45893a6d32Sahrens #include <sys/zfs_dir.h> 46fa9e4066Sahrens #include <sys/zil.h> 47fa9e4066Sahrens #include <sys/fs/zfs.h> 48fa9e4066Sahrens #include <sys/dmu.h> 49fa9e4066Sahrens #include <sys/dsl_prop.h> 50b1b8ab34Slling #include <sys/dsl_dataset.h> 51ecd6cf80Smarks #include <sys/dsl_deleg.h> 52fa9e4066Sahrens #include <sys/spa.h> 53fa9e4066Sahrens #include <sys/zap.h> 540a586ceaSMark Shellenbaum #include <sys/sa.h> 55e828a46dSMatthew Ahrens #include <sys/sa_impl.h> 56fa9e4066Sahrens #include <sys/varargs.h> 57fa9e4066Sahrens #include <sys/policy.h> 58fa9e4066Sahrens #include <sys/atomic.h> 59fa9e4066Sahrens #include <sys/mkdev.h> 60fa9e4066Sahrens #include <sys/modctl.h> 61ecd6cf80Smarks #include <sys/refstr.h> 62fa9e4066Sahrens #include <sys/zfs_ioctl.h> 63fa9e4066Sahrens #include <sys/zfs_ctldir.h> 64da6c28aaSamw #include <sys/zfs_fuid.h> 65ea8dc4b6Seschrock #include <sys/bootconf.h> 66a0965f35Sbonwick #include <sys/sunddi.h> 67033f9833Sek #include <sys/dnlc.h> 68f18faf3fSek #include <sys/dmu_objset.h> 69e7cbe64fSgw #include <sys/spa_boot.h> 700a586ceaSMark Shellenbaum #include "zfs_comutil.h" 71fa9e4066Sahrens 72fa9e4066Sahrens int zfsfstype; 73fa9e4066Sahrens vfsops_t *zfs_vfsops = NULL; 74a0965f35Sbonwick static major_t zfs_major; 75fa9e4066Sahrens static minor_t zfs_minor; 76fa9e4066Sahrens static kmutex_t zfs_dev_mtx; 77fa9e4066Sahrens 7854d692b7SGeorge Wilson extern int sys_shutdown; 7954d692b7SGeorge Wilson 80fa9e4066Sahrens static int zfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr); 81fa9e4066Sahrens static int zfs_umount(vfs_t *vfsp, int fflag, cred_t *cr); 82ea8dc4b6Seschrock static int zfs_mountroot(vfs_t *vfsp, enum whymountroot); 83fa9e4066Sahrens static int zfs_root(vfs_t *vfsp, vnode_t **vpp); 84fa9e4066Sahrens static int zfs_statvfs(vfs_t *vfsp, struct statvfs64 *statp); 85fa9e4066Sahrens static int zfs_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp); 86fa9e4066Sahrens static void zfs_freevfs(vfs_t *vfsp); 87fa9e4066Sahrens 88fa9e4066Sahrens static const fs_operation_def_t zfs_vfsops_template[] = { 89aa59c4cbSrsb VFSNAME_MOUNT, { .vfs_mount = zfs_mount }, 90aa59c4cbSrsb VFSNAME_MOUNTROOT, { .vfs_mountroot = zfs_mountroot }, 91aa59c4cbSrsb VFSNAME_UNMOUNT, { .vfs_unmount = zfs_umount }, 92aa59c4cbSrsb VFSNAME_ROOT, { .vfs_root = zfs_root }, 93aa59c4cbSrsb VFSNAME_STATVFS, { .vfs_statvfs = zfs_statvfs }, 94aa59c4cbSrsb VFSNAME_SYNC, { .vfs_sync = zfs_sync }, 95aa59c4cbSrsb VFSNAME_VGET, { .vfs_vget = zfs_vget }, 96aa59c4cbSrsb VFSNAME_FREEVFS, { .vfs_freevfs = zfs_freevfs }, 97aa59c4cbSrsb NULL, NULL 98fa9e4066Sahrens }; 99fa9e4066Sahrens 100fa9e4066Sahrens /* 101fa9e4066Sahrens * We need to keep a count of active fs's. 102fa9e4066Sahrens * This is necessary to prevent our module 103fa9e4066Sahrens * from being unloaded after a umount -f 104fa9e4066Sahrens */ 105fa9e4066Sahrens static uint32_t zfs_active_fs_count = 0; 106fa9e4066Sahrens 107fa9e4066Sahrens static char *noatime_cancel[] = { MNTOPT_ATIME, NULL }; 108fa9e4066Sahrens static char *atime_cancel[] = { MNTOPT_NOATIME, NULL }; 1097b55fa8eSck static char *noxattr_cancel[] = { MNTOPT_XATTR, NULL }; 1107b55fa8eSck static char *xattr_cancel[] = { MNTOPT_NOXATTR, NULL }; 111fa9e4066Sahrens 1127b55fa8eSck /* 113b510d378Slling * MO_DEFAULT is not used since the default value is determined 114b510d378Slling * by the equivalent property. 1157b55fa8eSck */ 116fa9e4066Sahrens static mntopt_t mntopts[] = { 1177b55fa8eSck { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, NULL }, 1187b55fa8eSck { MNTOPT_XATTR, xattr_cancel, NULL, 0, NULL }, 119b510d378Slling { MNTOPT_NOATIME, noatime_cancel, NULL, 0, NULL }, 120fa9e4066Sahrens { MNTOPT_ATIME, atime_cancel, NULL, 0, NULL } 121fa9e4066Sahrens }; 122fa9e4066Sahrens 123fa9e4066Sahrens static mntopts_t zfs_mntopts = { 124fa9e4066Sahrens sizeof (mntopts) / sizeof (mntopt_t), 125fa9e4066Sahrens mntopts 126fa9e4066Sahrens }; 127fa9e4066Sahrens 128fa9e4066Sahrens /*ARGSUSED*/ 129fa9e4066Sahrens int 130fa9e4066Sahrens zfs_sync(vfs_t *vfsp, short flag, cred_t *cr) 131fa9e4066Sahrens { 132fa9e4066Sahrens /* 133fa9e4066Sahrens * Data integrity is job one. We don't want a compromised kernel 134fa9e4066Sahrens * writing to the storage pool, so we never sync during panic. 135fa9e4066Sahrens */ 136fa9e4066Sahrens if (panicstr) 137fa9e4066Sahrens return (0); 138fa9e4066Sahrens 139fa9e4066Sahrens /* 140fa9e4066Sahrens * SYNC_ATTR is used by fsflush() to force old filesystems like UFS 141fa9e4066Sahrens * to sync metadata, which they would otherwise cache indefinitely. 142fa9e4066Sahrens * Semantically, the only requirement is that the sync be initiated. 143fa9e4066Sahrens * The DMU syncs out txgs frequently, so there's nothing to do. 144fa9e4066Sahrens */ 145fa9e4066Sahrens if (flag & SYNC_ATTR) 146fa9e4066Sahrens return (0); 147fa9e4066Sahrens 148fa9e4066Sahrens if (vfsp != NULL) { 149fa9e4066Sahrens /* 150fa9e4066Sahrens * Sync a specific filesystem. 151fa9e4066Sahrens */ 152fa9e4066Sahrens zfsvfs_t *zfsvfs = vfsp->vfs_data; 15354d692b7SGeorge Wilson dsl_pool_t *dp; 154fa9e4066Sahrens 155fa9e4066Sahrens ZFS_ENTER(zfsvfs); 15654d692b7SGeorge Wilson dp = dmu_objset_pool(zfsvfs->z_os); 15754d692b7SGeorge Wilson 15854d692b7SGeorge Wilson /* 15954d692b7SGeorge Wilson * If the system is shutting down, then skip any 16054d692b7SGeorge Wilson * filesystems which may exist on a suspended pool. 16154d692b7SGeorge Wilson */ 16254d692b7SGeorge Wilson if (sys_shutdown && spa_suspended(dp->dp_spa)) { 16354d692b7SGeorge Wilson ZFS_EXIT(zfsvfs); 16454d692b7SGeorge Wilson return (0); 16554d692b7SGeorge Wilson } 16654d692b7SGeorge Wilson 167fa9e4066Sahrens if (zfsvfs->z_log != NULL) 1685002558fSNeil Perrin zil_commit(zfsvfs->z_log, 0); 16955da60b9SMark J Musante 170fa9e4066Sahrens ZFS_EXIT(zfsvfs); 171fa9e4066Sahrens } else { 172fa9e4066Sahrens /* 173fa9e4066Sahrens * Sync all ZFS filesystems. This is what happens when you 174fa9e4066Sahrens * run sync(1M). Unlike other filesystems, ZFS honors the 175fa9e4066Sahrens * request by waiting for all pools to commit all dirty data. 176fa9e4066Sahrens */ 177fa9e4066Sahrens spa_sync_allpools(); 178fa9e4066Sahrens } 179fa9e4066Sahrens 180fa9e4066Sahrens return (0); 181fa9e4066Sahrens } 182fa9e4066Sahrens 183ea8dc4b6Seschrock static int 184ea8dc4b6Seschrock zfs_create_unique_device(dev_t *dev) 185ea8dc4b6Seschrock { 186ea8dc4b6Seschrock major_t new_major; 187ea8dc4b6Seschrock 188ea8dc4b6Seschrock do { 189ea8dc4b6Seschrock ASSERT3U(zfs_minor, <=, MAXMIN32); 190ea8dc4b6Seschrock minor_t start = zfs_minor; 191ea8dc4b6Seschrock do { 192ea8dc4b6Seschrock mutex_enter(&zfs_dev_mtx); 193ea8dc4b6Seschrock if (zfs_minor >= MAXMIN32) { 194ea8dc4b6Seschrock /* 195ea8dc4b6Seschrock * If we're still using the real major 196ea8dc4b6Seschrock * keep out of /dev/zfs and /dev/zvol minor 197ea8dc4b6Seschrock * number space. If we're using a getudev()'ed 198ea8dc4b6Seschrock * major number, we can use all of its minors. 199ea8dc4b6Seschrock */ 200ea8dc4b6Seschrock if (zfs_major == ddi_name_to_major(ZFS_DRIVER)) 201ea8dc4b6Seschrock zfs_minor = ZFS_MIN_MINOR; 202ea8dc4b6Seschrock else 203ea8dc4b6Seschrock zfs_minor = 0; 204ea8dc4b6Seschrock } else { 205ea8dc4b6Seschrock zfs_minor++; 206ea8dc4b6Seschrock } 207ea8dc4b6Seschrock *dev = makedevice(zfs_major, zfs_minor); 208ea8dc4b6Seschrock mutex_exit(&zfs_dev_mtx); 209ea8dc4b6Seschrock } while (vfs_devismounted(*dev) && zfs_minor != start); 210ea8dc4b6Seschrock if (zfs_minor == start) { 211ea8dc4b6Seschrock /* 212ea8dc4b6Seschrock * We are using all ~262,000 minor numbers for the 213ea8dc4b6Seschrock * current major number. Create a new major number. 214ea8dc4b6Seschrock */ 215ea8dc4b6Seschrock if ((new_major = getudev()) == (major_t)-1) { 216ea8dc4b6Seschrock cmn_err(CE_WARN, 217ea8dc4b6Seschrock "zfs_mount: Can't get unique major " 218ea8dc4b6Seschrock "device number."); 219ea8dc4b6Seschrock return (-1); 220ea8dc4b6Seschrock } 221ea8dc4b6Seschrock mutex_enter(&zfs_dev_mtx); 222ea8dc4b6Seschrock zfs_major = new_major; 223ea8dc4b6Seschrock zfs_minor = 0; 224ea8dc4b6Seschrock 225ea8dc4b6Seschrock mutex_exit(&zfs_dev_mtx); 226ea8dc4b6Seschrock } else { 227ea8dc4b6Seschrock break; 228ea8dc4b6Seschrock } 229ea8dc4b6Seschrock /* CONSTANTCONDITION */ 230ea8dc4b6Seschrock } while (1); 231ea8dc4b6Seschrock 232ea8dc4b6Seschrock return (0); 233ea8dc4b6Seschrock } 234ea8dc4b6Seschrock 235fa9e4066Sahrens static void 236fa9e4066Sahrens atime_changed_cb(void *arg, uint64_t newval) 237fa9e4066Sahrens { 238fa9e4066Sahrens zfsvfs_t *zfsvfs = arg; 239fa9e4066Sahrens 240fa9e4066Sahrens if (newval == TRUE) { 241fa9e4066Sahrens zfsvfs->z_atime = TRUE; 242fa9e4066Sahrens vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_NOATIME); 243fa9e4066Sahrens vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_ATIME, NULL, 0); 244fa9e4066Sahrens } else { 245fa9e4066Sahrens zfsvfs->z_atime = FALSE; 246fa9e4066Sahrens vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_ATIME); 247fa9e4066Sahrens vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_NOATIME, NULL, 0); 248fa9e4066Sahrens } 249fa9e4066Sahrens } 250fa9e4066Sahrens 2517b55fa8eSck static void 2527b55fa8eSck xattr_changed_cb(void *arg, uint64_t newval) 2537b55fa8eSck { 2547b55fa8eSck zfsvfs_t *zfsvfs = arg; 2557b55fa8eSck 2567b55fa8eSck if (newval == TRUE) { 2577b55fa8eSck /* XXX locking on vfs_flag? */ 2587b55fa8eSck zfsvfs->z_vfs->vfs_flag |= VFS_XATTR; 2597b55fa8eSck vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_NOXATTR); 2607b55fa8eSck vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_XATTR, NULL, 0); 2617b55fa8eSck } else { 2627b55fa8eSck /* XXX locking on vfs_flag? */ 2637b55fa8eSck zfsvfs->z_vfs->vfs_flag &= ~VFS_XATTR; 2647b55fa8eSck vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_XATTR); 2657b55fa8eSck vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_NOXATTR, NULL, 0); 2667b55fa8eSck } 2677b55fa8eSck } 2687b55fa8eSck 269fa9e4066Sahrens static void 270fa9e4066Sahrens blksz_changed_cb(void *arg, uint64_t newval) 271fa9e4066Sahrens { 272fa9e4066Sahrens zfsvfs_t *zfsvfs = arg; 273b5152584SMatthew Ahrens ASSERT3U(newval, <=, spa_maxblocksize(dmu_objset_spa(zfsvfs->z_os))); 274b5152584SMatthew Ahrens ASSERT3U(newval, >=, SPA_MINBLOCKSIZE); 275b5152584SMatthew Ahrens ASSERT(ISP2(newval)); 276fa9e4066Sahrens 277fa9e4066Sahrens zfsvfs->z_max_blksz = newval; 278fa9e4066Sahrens zfsvfs->z_vfs->vfs_bsize = newval; 279fa9e4066Sahrens } 280fa9e4066Sahrens 281fa9e4066Sahrens static void 282fa9e4066Sahrens readonly_changed_cb(void *arg, uint64_t newval) 283fa9e4066Sahrens { 284fa9e4066Sahrens zfsvfs_t *zfsvfs = arg; 285fa9e4066Sahrens 286fa9e4066Sahrens if (newval) { 287fa9e4066Sahrens /* XXX locking on vfs_flag? */ 288fa9e4066Sahrens zfsvfs->z_vfs->vfs_flag |= VFS_RDONLY; 289fa9e4066Sahrens vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_RW); 290fa9e4066Sahrens vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_RO, NULL, 0); 291fa9e4066Sahrens } else { 292fa9e4066Sahrens /* XXX locking on vfs_flag? */ 293fa9e4066Sahrens zfsvfs->z_vfs->vfs_flag &= ~VFS_RDONLY; 294fa9e4066Sahrens vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_RO); 295fa9e4066Sahrens vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_RW, NULL, 0); 296fa9e4066Sahrens } 297fa9e4066Sahrens } 298fa9e4066Sahrens 299fa9e4066Sahrens static void 300fa9e4066Sahrens devices_changed_cb(void *arg, uint64_t newval) 301fa9e4066Sahrens { 302fa9e4066Sahrens zfsvfs_t *zfsvfs = arg; 303fa9e4066Sahrens 304fa9e4066Sahrens if (newval == FALSE) { 305fa9e4066Sahrens zfsvfs->z_vfs->vfs_flag |= VFS_NODEVICES; 306fa9e4066Sahrens vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_DEVICES); 307fa9e4066Sahrens vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_NODEVICES, NULL, 0); 308fa9e4066Sahrens } else { 309fa9e4066Sahrens zfsvfs->z_vfs->vfs_flag &= ~VFS_NODEVICES; 310fa9e4066Sahrens vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_NODEVICES); 311fa9e4066Sahrens vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_DEVICES, NULL, 0); 312fa9e4066Sahrens } 313fa9e4066Sahrens } 314fa9e4066Sahrens 315fa9e4066Sahrens static void 316fa9e4066Sahrens setuid_changed_cb(void *arg, uint64_t newval) 317fa9e4066Sahrens { 318fa9e4066Sahrens zfsvfs_t *zfsvfs = arg; 319fa9e4066Sahrens 320fa9e4066Sahrens if (newval == FALSE) { 321fa9e4066Sahrens zfsvfs->z_vfs->vfs_flag |= VFS_NOSETUID; 322fa9e4066Sahrens vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_SETUID); 323fa9e4066Sahrens vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_NOSETUID, NULL, 0); 324fa9e4066Sahrens } else { 325fa9e4066Sahrens zfsvfs->z_vfs->vfs_flag &= ~VFS_NOSETUID; 326fa9e4066Sahrens vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_NOSETUID); 327fa9e4066Sahrens vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_SETUID, NULL, 0); 328fa9e4066Sahrens } 329fa9e4066Sahrens } 330fa9e4066Sahrens 331fa9e4066Sahrens static void 332fa9e4066Sahrens exec_changed_cb(void *arg, uint64_t newval) 333fa9e4066Sahrens { 334fa9e4066Sahrens zfsvfs_t *zfsvfs = arg; 335fa9e4066Sahrens 336fa9e4066Sahrens if (newval == FALSE) { 337fa9e4066Sahrens zfsvfs->z_vfs->vfs_flag |= VFS_NOEXEC; 338fa9e4066Sahrens vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_EXEC); 339fa9e4066Sahrens vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_NOEXEC, NULL, 0); 340fa9e4066Sahrens } else { 341fa9e4066Sahrens zfsvfs->z_vfs->vfs_flag &= ~VFS_NOEXEC; 342fa9e4066Sahrens vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_NOEXEC); 343fa9e4066Sahrens vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_EXEC, NULL, 0); 344fa9e4066Sahrens } 345fa9e4066Sahrens } 346fa9e4066Sahrens 347da6c28aaSamw /* 348da6c28aaSamw * The nbmand mount option can be changed at mount time. 349da6c28aaSamw * We can't allow it to be toggled on live file systems or incorrect 350da6c28aaSamw * behavior may be seen from cifs clients 351da6c28aaSamw * 352da6c28aaSamw * This property isn't registered via dsl_prop_register(), but this callback 353da6c28aaSamw * will be called when a file system is first mounted 354da6c28aaSamw */ 355da6c28aaSamw static void 356da6c28aaSamw nbmand_changed_cb(void *arg, uint64_t newval) 357da6c28aaSamw { 358da6c28aaSamw zfsvfs_t *zfsvfs = arg; 359da6c28aaSamw if (newval == FALSE) { 360da6c28aaSamw vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_NBMAND); 361da6c28aaSamw vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_NONBMAND, NULL, 0); 362da6c28aaSamw } else { 363da6c28aaSamw vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_NONBMAND); 364da6c28aaSamw vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_NBMAND, NULL, 0); 365da6c28aaSamw } 366da6c28aaSamw } 367da6c28aaSamw 368fa9e4066Sahrens static void 369fa9e4066Sahrens snapdir_changed_cb(void *arg, uint64_t newval) 370fa9e4066Sahrens { 371fa9e4066Sahrens zfsvfs_t *zfsvfs = arg; 372fa9e4066Sahrens 373fa9e4066Sahrens zfsvfs->z_show_ctldir = newval; 374fa9e4066Sahrens } 375fa9e4066Sahrens 376da6c28aaSamw static void 377da6c28aaSamw vscan_changed_cb(void *arg, uint64_t newval) 378da6c28aaSamw { 379da6c28aaSamw zfsvfs_t *zfsvfs = arg; 380da6c28aaSamw 381da6c28aaSamw zfsvfs->z_vscan = newval; 382da6c28aaSamw } 383da6c28aaSamw 384a3c49ce1SAlbert Lee static void 385a3c49ce1SAlbert Lee acl_mode_changed_cb(void *arg, uint64_t newval) 386a3c49ce1SAlbert Lee { 387a3c49ce1SAlbert Lee zfsvfs_t *zfsvfs = arg; 388a3c49ce1SAlbert Lee 389a3c49ce1SAlbert Lee zfsvfs->z_acl_mode = newval; 390a3c49ce1SAlbert Lee } 391a3c49ce1SAlbert Lee 392fa9e4066Sahrens static void 393fa9e4066Sahrens acl_inherit_changed_cb(void *arg, uint64_t newval) 394fa9e4066Sahrens { 395fa9e4066Sahrens zfsvfs_t *zfsvfs = arg; 396fa9e4066Sahrens 397fa9e4066Sahrens zfsvfs->z_acl_inherit = newval; 398fa9e4066Sahrens } 399fa9e4066Sahrens 400ea8dc4b6Seschrock static int 401ea8dc4b6Seschrock zfs_register_callbacks(vfs_t *vfsp) 402ea8dc4b6Seschrock { 403ea8dc4b6Seschrock struct dsl_dataset *ds = NULL; 404ea8dc4b6Seschrock objset_t *os = NULL; 405ea8dc4b6Seschrock zfsvfs_t *zfsvfs = NULL; 406da6c28aaSamw uint64_t nbmand; 407d5285caeSGeorge Wilson boolean_t readonly = B_FALSE; 408d5285caeSGeorge Wilson boolean_t do_readonly = B_FALSE; 409d5285caeSGeorge Wilson boolean_t setuid = B_FALSE; 410d5285caeSGeorge Wilson boolean_t do_setuid = B_FALSE; 411d5285caeSGeorge Wilson boolean_t exec = B_FALSE; 412d5285caeSGeorge Wilson boolean_t do_exec = B_FALSE; 413d5285caeSGeorge Wilson boolean_t devices = B_FALSE; 414d5285caeSGeorge Wilson boolean_t do_devices = B_FALSE; 415d5285caeSGeorge Wilson boolean_t xattr = B_FALSE; 416d5285caeSGeorge Wilson boolean_t do_xattr = B_FALSE; 417d5285caeSGeorge Wilson boolean_t atime = B_FALSE; 418d5285caeSGeorge Wilson boolean_t do_atime = B_FALSE; 419ea8dc4b6Seschrock int error = 0; 420ea8dc4b6Seschrock 421ea8dc4b6Seschrock ASSERT(vfsp); 422ea8dc4b6Seschrock zfsvfs = vfsp->vfs_data; 423ea8dc4b6Seschrock ASSERT(zfsvfs); 424ea8dc4b6Seschrock os = zfsvfs->z_os; 425fa9e4066Sahrens 426fa9e4066Sahrens /* 427ea8dc4b6Seschrock * The act of registering our callbacks will destroy any mount 428ea8dc4b6Seschrock * options we may have. In order to enable temporary overrides 4297b55fa8eSck * of mount options, we stash away the current values and 430ea8dc4b6Seschrock * restore them after we register the callbacks. 431fa9e4066Sahrens */ 432f9af39baSGeorge Wilson if (vfs_optionisset(vfsp, MNTOPT_RO, NULL) || 433f9af39baSGeorge Wilson !spa_writeable(dmu_objset_spa(os))) { 434ea8dc4b6Seschrock readonly = B_TRUE; 435ea8dc4b6Seschrock do_readonly = B_TRUE; 436ea8dc4b6Seschrock } else if (vfs_optionisset(vfsp, MNTOPT_RW, NULL)) { 437ea8dc4b6Seschrock readonly = B_FALSE; 438ea8dc4b6Seschrock do_readonly = B_TRUE; 439ea8dc4b6Seschrock } 440ea8dc4b6Seschrock if (vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL)) { 441ea8dc4b6Seschrock devices = B_FALSE; 442ea8dc4b6Seschrock setuid = B_FALSE; 443ea8dc4b6Seschrock do_devices = B_TRUE; 444ea8dc4b6Seschrock do_setuid = B_TRUE; 445ea8dc4b6Seschrock } else { 446ea8dc4b6Seschrock if (vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL)) { 447ea8dc4b6Seschrock devices = B_FALSE; 448ea8dc4b6Seschrock do_devices = B_TRUE; 449b1b8ab34Slling } else if (vfs_optionisset(vfsp, MNTOPT_DEVICES, NULL)) { 450ea8dc4b6Seschrock devices = B_TRUE; 451ea8dc4b6Seschrock do_devices = B_TRUE; 452fa9e4066Sahrens } 453fa9e4066Sahrens 454ea8dc4b6Seschrock if (vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL)) { 455ea8dc4b6Seschrock setuid = B_FALSE; 456ea8dc4b6Seschrock do_setuid = B_TRUE; 457ea8dc4b6Seschrock } else if (vfs_optionisset(vfsp, MNTOPT_SETUID, NULL)) { 458ea8dc4b6Seschrock setuid = B_TRUE; 459ea8dc4b6Seschrock do_setuid = B_TRUE; 460fa9e4066Sahrens } 461ea8dc4b6Seschrock } 462ea8dc4b6Seschrock if (vfs_optionisset(vfsp, MNTOPT_NOEXEC, NULL)) { 463ea8dc4b6Seschrock exec = B_FALSE; 464ea8dc4b6Seschrock do_exec = B_TRUE; 465ea8dc4b6Seschrock } else if (vfs_optionisset(vfsp, MNTOPT_EXEC, NULL)) { 466ea8dc4b6Seschrock exec = B_TRUE; 467ea8dc4b6Seschrock do_exec = B_TRUE; 468fa9e4066Sahrens } 4697b55fa8eSck if (vfs_optionisset(vfsp, MNTOPT_NOXATTR, NULL)) { 4707b55fa8eSck xattr = B_FALSE; 4717b55fa8eSck do_xattr = B_TRUE; 4727b55fa8eSck } else if (vfs_optionisset(vfsp, MNTOPT_XATTR, NULL)) { 4737b55fa8eSck xattr = B_TRUE; 4747b55fa8eSck do_xattr = B_TRUE; 4757b55fa8eSck } 476b510d378Slling if (vfs_optionisset(vfsp, MNTOPT_NOATIME, NULL)) { 477b510d378Slling atime = B_FALSE; 478b510d378Slling do_atime = B_TRUE; 479b510d378Slling } else if (vfs_optionisset(vfsp, MNTOPT_ATIME, NULL)) { 480b510d378Slling atime = B_TRUE; 481b510d378Slling do_atime = B_TRUE; 482b510d378Slling } 483fa9e4066Sahrens 484da6c28aaSamw /* 485da6c28aaSamw * nbmand is a special property. It can only be changed at 486da6c28aaSamw * mount time. 487da6c28aaSamw * 488da6c28aaSamw * This is weird, but it is documented to only be changeable 489da6c28aaSamw * at mount time. 490da6c28aaSamw */ 491da6c28aaSamw if (vfs_optionisset(vfsp, MNTOPT_NONBMAND, NULL)) { 492da6c28aaSamw nbmand = B_FALSE; 493da6c28aaSamw } else if (vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL)) { 494da6c28aaSamw nbmand = B_TRUE; 495da6c28aaSamw } else { 4969adfa60dSMatthew Ahrens char osname[ZFS_MAX_DATASET_NAME_LEN]; 497da6c28aaSamw 498da6c28aaSamw dmu_objset_name(os, osname); 499da6c28aaSamw if (error = dsl_prop_get_integer(osname, "nbmand", &nbmand, 500bb0ade09Sahrens NULL)) { 501bb0ade09Sahrens return (error); 502bb0ade09Sahrens } 503da6c28aaSamw } 504da6c28aaSamw 505fa9e4066Sahrens /* 506ea8dc4b6Seschrock * Register property callbacks. 507ea8dc4b6Seschrock * 508ea8dc4b6Seschrock * It would probably be fine to just check for i/o error from 509ea8dc4b6Seschrock * the first prop_register(), but I guess I like to go 510ea8dc4b6Seschrock * overboard... 511fa9e4066Sahrens */ 512ea8dc4b6Seschrock ds = dmu_objset_ds(os); 5133b2aab18SMatthew Ahrens dsl_pool_config_enter(dmu_objset_pool(os), FTAG); 5143b2aab18SMatthew Ahrens error = dsl_prop_register(ds, 5153b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_ATIME), atime_changed_cb, zfsvfs); 5167b55fa8eSck error = error ? error : dsl_prop_register(ds, 5173b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_XATTR), xattr_changed_cb, zfsvfs); 518ea8dc4b6Seschrock error = error ? error : dsl_prop_register(ds, 5193b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_RECORDSIZE), blksz_changed_cb, zfsvfs); 520ea8dc4b6Seschrock error = error ? error : dsl_prop_register(ds, 5213b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_READONLY), readonly_changed_cb, zfsvfs); 522ea8dc4b6Seschrock error = error ? error : dsl_prop_register(ds, 5233b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_DEVICES), devices_changed_cb, zfsvfs); 524ea8dc4b6Seschrock error = error ? error : dsl_prop_register(ds, 5253b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_SETUID), setuid_changed_cb, zfsvfs); 526ea8dc4b6Seschrock error = error ? error : dsl_prop_register(ds, 5273b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_EXEC), exec_changed_cb, zfsvfs); 528ea8dc4b6Seschrock error = error ? error : dsl_prop_register(ds, 5293b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_SNAPDIR), snapdir_changed_cb, zfsvfs); 530a3c49ce1SAlbert Lee error = error ? error : dsl_prop_register(ds, 5313b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_ACLMODE), acl_mode_changed_cb, zfsvfs); 532ea8dc4b6Seschrock error = error ? error : dsl_prop_register(ds, 5333b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_ACLINHERIT), acl_inherit_changed_cb, 5343b2aab18SMatthew Ahrens zfsvfs); 535da6c28aaSamw error = error ? error : dsl_prop_register(ds, 5363b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_VSCAN), vscan_changed_cb, zfsvfs); 5373b2aab18SMatthew Ahrens dsl_pool_config_exit(dmu_objset_pool(os), FTAG); 538ea8dc4b6Seschrock if (error) 539ea8dc4b6Seschrock goto unregister; 540fa9e4066Sahrens 541ea8dc4b6Seschrock /* 542ea8dc4b6Seschrock * Invoke our callbacks to restore temporary mount options. 543ea8dc4b6Seschrock */ 544ea8dc4b6Seschrock if (do_readonly) 545ea8dc4b6Seschrock readonly_changed_cb(zfsvfs, readonly); 546ea8dc4b6Seschrock if (do_setuid) 547ea8dc4b6Seschrock setuid_changed_cb(zfsvfs, setuid); 548ea8dc4b6Seschrock if (do_exec) 549ea8dc4b6Seschrock exec_changed_cb(zfsvfs, exec); 550ea8dc4b6Seschrock if (do_devices) 551ea8dc4b6Seschrock devices_changed_cb(zfsvfs, devices); 5527b55fa8eSck if (do_xattr) 5537b55fa8eSck xattr_changed_cb(zfsvfs, xattr); 554b510d378Slling if (do_atime) 555b510d378Slling atime_changed_cb(zfsvfs, atime); 556fa9e4066Sahrens 557da6c28aaSamw nbmand_changed_cb(zfsvfs, nbmand); 558da6c28aaSamw 559ea8dc4b6Seschrock return (0); 560fa9e4066Sahrens 561ea8dc4b6Seschrock unregister: 56203bad06fSJustin Gibbs dsl_prop_unregister_all(ds, zfsvfs); 563ea8dc4b6Seschrock return (error); 564ea8dc4b6Seschrock } 565ea8dc4b6Seschrock 5669966ca11SMatthew Ahrens static int 5670a586ceaSMark Shellenbaum zfs_space_delta_cb(dmu_object_type_t bonustype, void *data, 568*f67950b2SNasf-Fan uint64_t *userp, uint64_t *groupp, uint64_t *projectp) 56914843421SMatthew Ahrens { 570*f67950b2SNasf-Fan sa_hdr_phys_t sa; 571*f67950b2SNasf-Fan sa_hdr_phys_t *sap = data; 572*f67950b2SNasf-Fan uint64_t flags; 573*f67950b2SNasf-Fan int hdrsize; 574*f67950b2SNasf-Fan boolean_t swap = B_FALSE; 575*f67950b2SNasf-Fan 57606e0070dSMark Shellenbaum /* 57706e0070dSMark Shellenbaum * Is it a valid type of object to track? 57806e0070dSMark Shellenbaum */ 5790a586ceaSMark Shellenbaum if (bonustype != DMU_OT_ZNODE && bonustype != DMU_OT_SA) 580be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 58114843421SMatthew Ahrens 58206e0070dSMark Shellenbaum /* 58306e0070dSMark Shellenbaum * If we have a NULL data pointer 58406e0070dSMark Shellenbaum * then assume the id's aren't changing and 58506e0070dSMark Shellenbaum * return EEXIST to the dmu to let it know to 58606e0070dSMark Shellenbaum * use the same ids 58706e0070dSMark Shellenbaum */ 58806e0070dSMark Shellenbaum if (data == NULL) 589be6fd75aSMatthew Ahrens return (SET_ERROR(EEXIST)); 59006e0070dSMark Shellenbaum 5910a586ceaSMark Shellenbaum if (bonustype == DMU_OT_ZNODE) { 592e828a46dSMatthew Ahrens znode_phys_t *znp = data; 5930a586ceaSMark Shellenbaum *userp = znp->zp_uid; 5940a586ceaSMark Shellenbaum *groupp = znp->zp_gid; 595*f67950b2SNasf-Fan *projectp = ZFS_DEFAULT_PROJID; 596*f67950b2SNasf-Fan return (0); 597*f67950b2SNasf-Fan } 598*f67950b2SNasf-Fan 599*f67950b2SNasf-Fan if (sap->sa_magic == 0) { 600*f67950b2SNasf-Fan /* 601*f67950b2SNasf-Fan * This should only happen for newly created files 602*f67950b2SNasf-Fan * that haven't had the znode data filled in yet. 603*f67950b2SNasf-Fan */ 604*f67950b2SNasf-Fan *userp = 0; 605*f67950b2SNasf-Fan *groupp = 0; 606*f67950b2SNasf-Fan *projectp = ZFS_DEFAULT_PROJID; 607*f67950b2SNasf-Fan return (0); 608*f67950b2SNasf-Fan } 609*f67950b2SNasf-Fan 610*f67950b2SNasf-Fan sa = *sap; 611*f67950b2SNasf-Fan if (sa.sa_magic == BSWAP_32(SA_MAGIC)) { 612*f67950b2SNasf-Fan sa.sa_magic = SA_MAGIC; 613*f67950b2SNasf-Fan sa.sa_layout_info = BSWAP_16(sa.sa_layout_info); 614*f67950b2SNasf-Fan swap = B_TRUE; 6150a586ceaSMark Shellenbaum } else { 616*f67950b2SNasf-Fan VERIFY3U(sa.sa_magic, ==, SA_MAGIC); 617*f67950b2SNasf-Fan } 6180a586ceaSMark Shellenbaum 619*f67950b2SNasf-Fan hdrsize = sa_hdrsize(&sa); 620*f67950b2SNasf-Fan VERIFY3U(hdrsize, >=, sizeof (sa_hdr_phys_t)); 6210a586ceaSMark Shellenbaum 622*f67950b2SNasf-Fan *userp = *((uint64_t *)((uintptr_t)data + hdrsize + SA_UID_OFFSET)); 623*f67950b2SNasf-Fan *groupp = *((uint64_t *)((uintptr_t)data + hdrsize + SA_GID_OFFSET)); 624*f67950b2SNasf-Fan flags = *((uint64_t *)((uintptr_t)data + hdrsize + SA_FLAGS_OFFSET)); 625*f67950b2SNasf-Fan if (swap) 626*f67950b2SNasf-Fan flags = BSWAP_64(flags); 627e828a46dSMatthew Ahrens 628*f67950b2SNasf-Fan if (flags & ZFS_PROJID) 629*f67950b2SNasf-Fan *projectp = *((uint64_t *)((uintptr_t)data + hdrsize + 630*f67950b2SNasf-Fan SA_PROJID_OFFSET)); 631*f67950b2SNasf-Fan else 632*f67950b2SNasf-Fan *projectp = ZFS_DEFAULT_PROJID; 633*f67950b2SNasf-Fan 634*f67950b2SNasf-Fan if (swap) { 635*f67950b2SNasf-Fan *userp = BSWAP_64(*userp); 636*f67950b2SNasf-Fan *groupp = BSWAP_64(*groupp); 637*f67950b2SNasf-Fan *projectp = BSWAP_64(*projectp); 6380a586ceaSMark Shellenbaum } 6393b2aab18SMatthew Ahrens return (0); 64014843421SMatthew Ahrens } 64114843421SMatthew Ahrens 64214843421SMatthew Ahrens static void 64314843421SMatthew Ahrens fuidstr_to_sid(zfsvfs_t *zfsvfs, const char *fuidstr, 64414843421SMatthew Ahrens char *domainbuf, int buflen, uid_t *ridp) 64514843421SMatthew Ahrens { 64614843421SMatthew Ahrens uint64_t fuid; 64714843421SMatthew Ahrens const char *domain; 64814843421SMatthew Ahrens 6494585130bSYuri Pankov fuid = zfs_strtonum(fuidstr, NULL); 65014843421SMatthew Ahrens 65114843421SMatthew Ahrens domain = zfs_fuid_find_by_idx(zfsvfs, FUID_INDEX(fuid)); 65214843421SMatthew Ahrens if (domain) 65314843421SMatthew Ahrens (void) strlcpy(domainbuf, domain, buflen); 65414843421SMatthew Ahrens else 65514843421SMatthew Ahrens domainbuf[0] = '\0'; 65614843421SMatthew Ahrens *ridp = FUID_RID(fuid); 65714843421SMatthew Ahrens } 65814843421SMatthew Ahrens 65914843421SMatthew Ahrens static uint64_t 66014843421SMatthew Ahrens zfs_userquota_prop_to_obj(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type) 66114843421SMatthew Ahrens { 66214843421SMatthew Ahrens switch (type) { 66314843421SMatthew Ahrens case ZFS_PROP_USERUSED: 664*f67950b2SNasf-Fan case ZFS_PROP_USEROBJUSED: 66514843421SMatthew Ahrens return (DMU_USERUSED_OBJECT); 66614843421SMatthew Ahrens case ZFS_PROP_GROUPUSED: 667*f67950b2SNasf-Fan case ZFS_PROP_GROUPOBJUSED: 66814843421SMatthew Ahrens return (DMU_GROUPUSED_OBJECT); 669*f67950b2SNasf-Fan case ZFS_PROP_PROJECTUSED: 670*f67950b2SNasf-Fan case ZFS_PROP_PROJECTOBJUSED: 671*f67950b2SNasf-Fan return (DMU_PROJECTUSED_OBJECT); 67214843421SMatthew Ahrens case ZFS_PROP_USERQUOTA: 67314843421SMatthew Ahrens return (zfsvfs->z_userquota_obj); 67414843421SMatthew Ahrens case ZFS_PROP_GROUPQUOTA: 67514843421SMatthew Ahrens return (zfsvfs->z_groupquota_obj); 676*f67950b2SNasf-Fan case ZFS_PROP_USEROBJQUOTA: 677*f67950b2SNasf-Fan return (zfsvfs->z_userobjquota_obj); 678*f67950b2SNasf-Fan case ZFS_PROP_GROUPOBJQUOTA: 679*f67950b2SNasf-Fan return (zfsvfs->z_groupobjquota_obj); 680*f67950b2SNasf-Fan case ZFS_PROP_PROJECTQUOTA: 681*f67950b2SNasf-Fan return (zfsvfs->z_projectquota_obj); 682*f67950b2SNasf-Fan case ZFS_PROP_PROJECTOBJQUOTA: 683*f67950b2SNasf-Fan return (zfsvfs->z_projectobjquota_obj); 684*f67950b2SNasf-Fan default: 685*f67950b2SNasf-Fan return (ZFS_NO_OBJECT); 68614843421SMatthew Ahrens } 68714843421SMatthew Ahrens } 68814843421SMatthew Ahrens 68914843421SMatthew Ahrens int 69014843421SMatthew Ahrens zfs_userspace_many(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type, 69114843421SMatthew Ahrens uint64_t *cookiep, void *vbuf, uint64_t *bufsizep) 69214843421SMatthew Ahrens { 69314843421SMatthew Ahrens int error; 69414843421SMatthew Ahrens zap_cursor_t zc; 69514843421SMatthew Ahrens zap_attribute_t za; 69614843421SMatthew Ahrens zfs_useracct_t *buf = vbuf; 69714843421SMatthew Ahrens uint64_t obj; 698*f67950b2SNasf-Fan int offset = 0; 69914843421SMatthew Ahrens 70014843421SMatthew Ahrens if (!dmu_objset_userspace_present(zfsvfs->z_os)) 701be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 70214843421SMatthew Ahrens 703*f67950b2SNasf-Fan if ((type == ZFS_PROP_PROJECTQUOTA || type == ZFS_PROP_PROJECTUSED || 704*f67950b2SNasf-Fan type == ZFS_PROP_PROJECTOBJQUOTA || 705*f67950b2SNasf-Fan type == ZFS_PROP_PROJECTOBJUSED) && 706*f67950b2SNasf-Fan !dmu_objset_projectquota_present(zfsvfs->z_os)) 707*f67950b2SNasf-Fan return (SET_ERROR(ENOTSUP)); 708*f67950b2SNasf-Fan 709*f67950b2SNasf-Fan if ((type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED || 710*f67950b2SNasf-Fan type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA || 711*f67950b2SNasf-Fan type == ZFS_PROP_PROJECTOBJUSED || 712*f67950b2SNasf-Fan type == ZFS_PROP_PROJECTOBJQUOTA) && 713*f67950b2SNasf-Fan !dmu_objset_userobjspace_present(zfsvfs->z_os)) 714*f67950b2SNasf-Fan return (SET_ERROR(ENOTSUP)); 715*f67950b2SNasf-Fan 71614843421SMatthew Ahrens obj = zfs_userquota_prop_to_obj(zfsvfs, type); 717*f67950b2SNasf-Fan if (obj == ZFS_NO_OBJECT) { 71814843421SMatthew Ahrens *bufsizep = 0; 71914843421SMatthew Ahrens return (0); 72014843421SMatthew Ahrens } 72114843421SMatthew Ahrens 722*f67950b2SNasf-Fan if (type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED || 723*f67950b2SNasf-Fan type == ZFS_PROP_PROJECTOBJUSED) 724*f67950b2SNasf-Fan offset = DMU_OBJACCT_PREFIX_LEN; 725*f67950b2SNasf-Fan 72614843421SMatthew Ahrens for (zap_cursor_init_serialized(&zc, zfsvfs->z_os, obj, *cookiep); 72714843421SMatthew Ahrens (error = zap_cursor_retrieve(&zc, &za)) == 0; 72814843421SMatthew Ahrens zap_cursor_advance(&zc)) { 72914843421SMatthew Ahrens if ((uintptr_t)buf - (uintptr_t)vbuf + sizeof (zfs_useracct_t) > 73014843421SMatthew Ahrens *bufsizep) 73114843421SMatthew Ahrens break; 73214843421SMatthew Ahrens 733*f67950b2SNasf-Fan /* 734*f67950b2SNasf-Fan * skip object quota (with zap name prefix DMU_OBJACCT_PREFIX) 735*f67950b2SNasf-Fan * when dealing with block quota and vice versa. 736*f67950b2SNasf-Fan */ 737*f67950b2SNasf-Fan if ((offset > 0) != (strncmp(za.za_name, DMU_OBJACCT_PREFIX, 738*f67950b2SNasf-Fan DMU_OBJACCT_PREFIX_LEN) == 0)) 739*f67950b2SNasf-Fan continue; 740*f67950b2SNasf-Fan 741*f67950b2SNasf-Fan fuidstr_to_sid(zfsvfs, za.za_name + offset, 74214843421SMatthew Ahrens buf->zu_domain, sizeof (buf->zu_domain), &buf->zu_rid); 74314843421SMatthew Ahrens 74414843421SMatthew Ahrens buf->zu_space = za.za_first_integer; 74514843421SMatthew Ahrens buf++; 74614843421SMatthew Ahrens } 74714843421SMatthew Ahrens if (error == ENOENT) 74814843421SMatthew Ahrens error = 0; 74914843421SMatthew Ahrens 75014843421SMatthew Ahrens ASSERT3U((uintptr_t)buf - (uintptr_t)vbuf, <=, *bufsizep); 75114843421SMatthew Ahrens *bufsizep = (uintptr_t)buf - (uintptr_t)vbuf; 75214843421SMatthew Ahrens *cookiep = zap_cursor_serialize(&zc); 75314843421SMatthew Ahrens zap_cursor_fini(&zc); 75414843421SMatthew Ahrens return (error); 75514843421SMatthew Ahrens } 75614843421SMatthew Ahrens 75714843421SMatthew Ahrens /* 75814843421SMatthew Ahrens * buf must be big enough (eg, 32 bytes) 75914843421SMatthew Ahrens */ 76014843421SMatthew Ahrens static int 76114843421SMatthew Ahrens id_to_fuidstr(zfsvfs_t *zfsvfs, const char *domain, uid_t rid, 76214843421SMatthew Ahrens char *buf, boolean_t addok) 76314843421SMatthew Ahrens { 76414843421SMatthew Ahrens uint64_t fuid; 76514843421SMatthew Ahrens int domainid = 0; 76614843421SMatthew Ahrens 76714843421SMatthew Ahrens if (domain && domain[0]) { 76814843421SMatthew Ahrens domainid = zfs_fuid_find_by_domain(zfsvfs, domain, NULL, addok); 76914843421SMatthew Ahrens if (domainid == -1) 770be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 77114843421SMatthew Ahrens } 77214843421SMatthew Ahrens fuid = FUID_ENCODE(domainid, rid); 77314843421SMatthew Ahrens (void) sprintf(buf, "%llx", (longlong_t)fuid); 77414843421SMatthew Ahrens return (0); 77514843421SMatthew Ahrens } 77614843421SMatthew Ahrens 77714843421SMatthew Ahrens int 77814843421SMatthew Ahrens zfs_userspace_one(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type, 77914843421SMatthew Ahrens const char *domain, uint64_t rid, uint64_t *valp) 78014843421SMatthew Ahrens { 781*f67950b2SNasf-Fan char buf[20 + DMU_OBJACCT_PREFIX_LEN]; 782*f67950b2SNasf-Fan int offset = 0; 78314843421SMatthew Ahrens int err; 78414843421SMatthew Ahrens uint64_t obj; 78514843421SMatthew Ahrens 78614843421SMatthew Ahrens *valp = 0; 78714843421SMatthew Ahrens 78814843421SMatthew Ahrens if (!dmu_objset_userspace_present(zfsvfs->z_os)) 789be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 79014843421SMatthew Ahrens 791*f67950b2SNasf-Fan if ((type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED || 792*f67950b2SNasf-Fan type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA || 793*f67950b2SNasf-Fan type == ZFS_PROP_PROJECTOBJUSED || 794*f67950b2SNasf-Fan type == ZFS_PROP_PROJECTOBJQUOTA) && 795*f67950b2SNasf-Fan !dmu_objset_userobjspace_present(zfsvfs->z_os)) 796*f67950b2SNasf-Fan return (SET_ERROR(ENOTSUP)); 797*f67950b2SNasf-Fan 798*f67950b2SNasf-Fan if (type == ZFS_PROP_PROJECTQUOTA || type == ZFS_PROP_PROJECTUSED || 799*f67950b2SNasf-Fan type == ZFS_PROP_PROJECTOBJQUOTA || 800*f67950b2SNasf-Fan type == ZFS_PROP_PROJECTOBJUSED) { 801*f67950b2SNasf-Fan if (!dmu_objset_projectquota_present(zfsvfs->z_os)) 802*f67950b2SNasf-Fan return (SET_ERROR(ENOTSUP)); 803*f67950b2SNasf-Fan if (!zpl_is_valid_projid(rid)) 804*f67950b2SNasf-Fan return (SET_ERROR(EINVAL)); 805*f67950b2SNasf-Fan } 806*f67950b2SNasf-Fan 80714843421SMatthew Ahrens obj = zfs_userquota_prop_to_obj(zfsvfs, type); 808*f67950b2SNasf-Fan if (obj == ZFS_NO_OBJECT) 80914843421SMatthew Ahrens return (0); 81014843421SMatthew Ahrens 811*f67950b2SNasf-Fan if (type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED || 812*f67950b2SNasf-Fan type == ZFS_PROP_PROJECTOBJUSED) { 813*f67950b2SNasf-Fan strncpy(buf, DMU_OBJACCT_PREFIX, DMU_OBJACCT_PREFIX_LEN); 814*f67950b2SNasf-Fan offset = DMU_OBJACCT_PREFIX_LEN; 815*f67950b2SNasf-Fan } 816*f67950b2SNasf-Fan 817*f67950b2SNasf-Fan err = id_to_fuidstr(zfsvfs, domain, rid, buf + offset, B_FALSE); 81814843421SMatthew Ahrens if (err) 81914843421SMatthew Ahrens return (err); 82014843421SMatthew Ahrens 82114843421SMatthew Ahrens err = zap_lookup(zfsvfs->z_os, obj, buf, 8, 1, valp); 82214843421SMatthew Ahrens if (err == ENOENT) 82314843421SMatthew Ahrens err = 0; 82414843421SMatthew Ahrens return (err); 82514843421SMatthew Ahrens } 82614843421SMatthew Ahrens 82714843421SMatthew Ahrens int 82814843421SMatthew Ahrens zfs_set_userquota(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type, 82914843421SMatthew Ahrens const char *domain, uint64_t rid, uint64_t quota) 83014843421SMatthew Ahrens { 83114843421SMatthew Ahrens char buf[32]; 83214843421SMatthew Ahrens int err; 83314843421SMatthew Ahrens dmu_tx_t *tx; 83414843421SMatthew Ahrens uint64_t *objp; 83514843421SMatthew Ahrens boolean_t fuid_dirtied; 83614843421SMatthew Ahrens 83714843421SMatthew Ahrens if (zfsvfs->z_version < ZPL_VERSION_USERSPACE) 838be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 83914843421SMatthew Ahrens 840*f67950b2SNasf-Fan switch (type) { 841*f67950b2SNasf-Fan case ZFS_PROP_USERQUOTA: 842*f67950b2SNasf-Fan objp = &zfsvfs->z_userquota_obj; 843*f67950b2SNasf-Fan break; 844*f67950b2SNasf-Fan case ZFS_PROP_GROUPQUOTA: 845*f67950b2SNasf-Fan objp = &zfsvfs->z_groupquota_obj; 846*f67950b2SNasf-Fan break; 847*f67950b2SNasf-Fan case ZFS_PROP_USEROBJQUOTA: 848*f67950b2SNasf-Fan objp = &zfsvfs->z_userobjquota_obj; 849*f67950b2SNasf-Fan break; 850*f67950b2SNasf-Fan case ZFS_PROP_GROUPOBJQUOTA: 851*f67950b2SNasf-Fan objp = &zfsvfs->z_groupobjquota_obj; 852*f67950b2SNasf-Fan break; 853*f67950b2SNasf-Fan case ZFS_PROP_PROJECTQUOTA: 854*f67950b2SNasf-Fan if (!dmu_objset_projectquota_enabled(zfsvfs->z_os)) 855*f67950b2SNasf-Fan return (SET_ERROR(ENOTSUP)); 856*f67950b2SNasf-Fan if (!zpl_is_valid_projid(rid)) 857*f67950b2SNasf-Fan return (SET_ERROR(EINVAL)); 858*f67950b2SNasf-Fan 859*f67950b2SNasf-Fan objp = &zfsvfs->z_projectquota_obj; 860*f67950b2SNasf-Fan break; 861*f67950b2SNasf-Fan case ZFS_PROP_PROJECTOBJQUOTA: 862*f67950b2SNasf-Fan if (!dmu_objset_projectquota_enabled(zfsvfs->z_os)) 863*f67950b2SNasf-Fan return (SET_ERROR(ENOTSUP)); 864*f67950b2SNasf-Fan if (!zpl_is_valid_projid(rid)) 865*f67950b2SNasf-Fan return (SET_ERROR(EINVAL)); 866*f67950b2SNasf-Fan 867*f67950b2SNasf-Fan objp = &zfsvfs->z_projectobjquota_obj; 868*f67950b2SNasf-Fan break; 869*f67950b2SNasf-Fan default: 870*f67950b2SNasf-Fan return (SET_ERROR(EINVAL)); 871*f67950b2SNasf-Fan } 87214843421SMatthew Ahrens 87314843421SMatthew Ahrens err = id_to_fuidstr(zfsvfs, domain, rid, buf, B_TRUE); 87414843421SMatthew Ahrens if (err) 87514843421SMatthew Ahrens return (err); 87614843421SMatthew Ahrens fuid_dirtied = zfsvfs->z_fuid_dirty; 87714843421SMatthew Ahrens 87814843421SMatthew Ahrens tx = dmu_tx_create(zfsvfs->z_os); 87914843421SMatthew Ahrens dmu_tx_hold_zap(tx, *objp ? *objp : DMU_NEW_OBJECT, B_TRUE, NULL); 88014843421SMatthew Ahrens if (*objp == 0) { 88114843421SMatthew Ahrens dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, B_TRUE, 88214843421SMatthew Ahrens zfs_userquota_prop_prefixes[type]); 88314843421SMatthew Ahrens } 88414843421SMatthew Ahrens if (fuid_dirtied) 88514843421SMatthew Ahrens zfs_fuid_txhold(zfsvfs, tx); 88614843421SMatthew Ahrens err = dmu_tx_assign(tx, TXG_WAIT); 88714843421SMatthew Ahrens if (err) { 88814843421SMatthew Ahrens dmu_tx_abort(tx); 88914843421SMatthew Ahrens return (err); 89014843421SMatthew Ahrens } 89114843421SMatthew Ahrens 89214843421SMatthew Ahrens mutex_enter(&zfsvfs->z_lock); 89314843421SMatthew Ahrens if (*objp == 0) { 89414843421SMatthew Ahrens *objp = zap_create(zfsvfs->z_os, DMU_OT_USERGROUP_QUOTA, 89514843421SMatthew Ahrens DMU_OT_NONE, 0, tx); 89614843421SMatthew Ahrens VERIFY(0 == zap_add(zfsvfs->z_os, MASTER_NODE_OBJ, 89714843421SMatthew Ahrens zfs_userquota_prop_prefixes[type], 8, 1, objp, tx)); 89814843421SMatthew Ahrens } 89914843421SMatthew Ahrens mutex_exit(&zfsvfs->z_lock); 90014843421SMatthew Ahrens 90114843421SMatthew Ahrens if (quota == 0) { 90214843421SMatthew Ahrens err = zap_remove(zfsvfs->z_os, *objp, buf, tx); 90314843421SMatthew Ahrens if (err == ENOENT) 90414843421SMatthew Ahrens err = 0; 90514843421SMatthew Ahrens } else { 90614843421SMatthew Ahrens err = zap_update(zfsvfs->z_os, *objp, buf, 8, 1, "a, tx); 90714843421SMatthew Ahrens } 90814843421SMatthew Ahrens ASSERT(err == 0); 90914843421SMatthew Ahrens if (fuid_dirtied) 91014843421SMatthew Ahrens zfs_fuid_sync(zfsvfs, tx); 91114843421SMatthew Ahrens dmu_tx_commit(tx); 91214843421SMatthew Ahrens return (err); 91314843421SMatthew Ahrens } 91414843421SMatthew Ahrens 91514843421SMatthew Ahrens boolean_t 916*f67950b2SNasf-Fan zfs_id_overobjquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id) 91714843421SMatthew Ahrens { 918*f67950b2SNasf-Fan char buf[20 + DMU_OBJACCT_PREFIX_LEN]; 919*f67950b2SNasf-Fan uint64_t used, quota, quotaobj; 92014843421SMatthew Ahrens int err; 92114843421SMatthew Ahrens 922*f67950b2SNasf-Fan if (!dmu_objset_userobjspace_present(zfsvfs->z_os)) { 923*f67950b2SNasf-Fan if (dmu_objset_userobjspace_upgradable(zfsvfs->z_os)) 924*f67950b2SNasf-Fan dmu_objset_id_quota_upgrade(zfsvfs->z_os); 925*f67950b2SNasf-Fan return (B_FALSE); 926*f67950b2SNasf-Fan } 92714843421SMatthew Ahrens 928*f67950b2SNasf-Fan if (usedobj == DMU_PROJECTUSED_OBJECT) { 929*f67950b2SNasf-Fan if (!dmu_objset_projectquota_present(zfsvfs->z_os)) { 930*f67950b2SNasf-Fan if (dmu_objset_projectquota_upgradable(zfsvfs->z_os)) { 931*f67950b2SNasf-Fan dsl_pool_config_enter( 932*f67950b2SNasf-Fan dmu_objset_pool(zfsvfs->z_os), FTAG); 933*f67950b2SNasf-Fan dmu_objset_id_quota_upgrade(zfsvfs->z_os); 934*f67950b2SNasf-Fan dsl_pool_config_exit( 935*f67950b2SNasf-Fan dmu_objset_pool(zfsvfs->z_os), FTAG); 936*f67950b2SNasf-Fan } 937*f67950b2SNasf-Fan return (B_FALSE); 938*f67950b2SNasf-Fan } 939*f67950b2SNasf-Fan quotaobj = zfsvfs->z_projectobjquota_obj; 940*f67950b2SNasf-Fan } else if (usedobj == DMU_USERUSED_OBJECT) { 941*f67950b2SNasf-Fan quotaobj = zfsvfs->z_userobjquota_obj; 942*f67950b2SNasf-Fan } else if (usedobj == DMU_GROUPUSED_OBJECT) { 943*f67950b2SNasf-Fan quotaobj = zfsvfs->z_groupobjquota_obj; 944*f67950b2SNasf-Fan } else { 945*f67950b2SNasf-Fan return (B_FALSE); 946*f67950b2SNasf-Fan } 94714843421SMatthew Ahrens if (quotaobj == 0 || zfsvfs->z_replay) 94814843421SMatthew Ahrens return (B_FALSE); 94914843421SMatthew Ahrens 950*f67950b2SNasf-Fan (void) sprintf(buf, "%llx", (longlong_t)id); 95114843421SMatthew Ahrens err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, "a); 95214843421SMatthew Ahrens if (err != 0) 95314843421SMatthew Ahrens return (B_FALSE); 95414843421SMatthew Ahrens 955*f67950b2SNasf-Fan (void) sprintf(buf, DMU_OBJACCT_PREFIX "%llx", (longlong_t)id); 95614843421SMatthew Ahrens err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used); 95714843421SMatthew Ahrens if (err != 0) 95814843421SMatthew Ahrens return (B_FALSE); 95914843421SMatthew Ahrens return (used >= quota); 96014843421SMatthew Ahrens } 96114843421SMatthew Ahrens 9620a586ceaSMark Shellenbaum boolean_t 963*f67950b2SNasf-Fan zfs_id_overblockquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id) 9640a586ceaSMark Shellenbaum { 965*f67950b2SNasf-Fan char buf[20]; 966*f67950b2SNasf-Fan uint64_t used, quota, quotaobj; 967*f67950b2SNasf-Fan int err; 9680a586ceaSMark Shellenbaum 969*f67950b2SNasf-Fan if (usedobj == DMU_PROJECTUSED_OBJECT) { 970*f67950b2SNasf-Fan if (!dmu_objset_projectquota_present(zfsvfs->z_os)) { 971*f67950b2SNasf-Fan if (dmu_objset_projectquota_upgradable(zfsvfs->z_os)) { 972*f67950b2SNasf-Fan dsl_pool_config_enter( 973*f67950b2SNasf-Fan dmu_objset_pool(zfsvfs->z_os), FTAG); 974*f67950b2SNasf-Fan dmu_objset_id_quota_upgrade(zfsvfs->z_os); 975*f67950b2SNasf-Fan dsl_pool_config_exit( 976*f67950b2SNasf-Fan dmu_objset_pool(zfsvfs->z_os), FTAG); 977*f67950b2SNasf-Fan } 978*f67950b2SNasf-Fan return (B_FALSE); 979*f67950b2SNasf-Fan } 980*f67950b2SNasf-Fan quotaobj = zfsvfs->z_projectquota_obj; 981*f67950b2SNasf-Fan } else if (usedobj == DMU_USERUSED_OBJECT) { 982*f67950b2SNasf-Fan quotaobj = zfsvfs->z_userquota_obj; 983*f67950b2SNasf-Fan } else if (usedobj == DMU_GROUPUSED_OBJECT) { 984*f67950b2SNasf-Fan quotaobj = zfsvfs->z_groupquota_obj; 985*f67950b2SNasf-Fan } else { 986*f67950b2SNasf-Fan return (B_FALSE); 987*f67950b2SNasf-Fan } 988*f67950b2SNasf-Fan if (quotaobj == 0 || zfsvfs->z_replay) 989*f67950b2SNasf-Fan return (B_FALSE); 9900a586ceaSMark Shellenbaum 991*f67950b2SNasf-Fan (void) sprintf(buf, "%llx", (longlong_t)id); 992*f67950b2SNasf-Fan err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, "a); 993*f67950b2SNasf-Fan if (err != 0) 994*f67950b2SNasf-Fan return (B_FALSE); 9950a586ceaSMark Shellenbaum 996*f67950b2SNasf-Fan err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used); 997*f67950b2SNasf-Fan if (err != 0) 9980a586ceaSMark Shellenbaum return (B_FALSE); 999*f67950b2SNasf-Fan return (used >= quota); 1000*f67950b2SNasf-Fan } 10010a586ceaSMark Shellenbaum 1002*f67950b2SNasf-Fan boolean_t 1003*f67950b2SNasf-Fan zfs_id_overquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id) 1004*f67950b2SNasf-Fan { 1005*f67950b2SNasf-Fan return (zfs_id_overblockquota(zfsvfs, usedobj, id) || 1006*f67950b2SNasf-Fan zfs_id_overobjquota(zfsvfs, usedobj, id)); 10070a586ceaSMark Shellenbaum } 10080a586ceaSMark Shellenbaum 10091fdcbd00SMatthew Ahrens /* 10101fdcbd00SMatthew Ahrens * Associate this zfsvfs with the given objset, which must be owned. 10111fdcbd00SMatthew Ahrens * This will cache a bunch of on-disk state from the objset in the 10121fdcbd00SMatthew Ahrens * zfsvfs. 10131fdcbd00SMatthew Ahrens */ 10141fdcbd00SMatthew Ahrens static int 10151fdcbd00SMatthew Ahrens zfsvfs_init(zfsvfs_t *zfsvfs, objset_t *os) 101614843421SMatthew Ahrens { 10171fdcbd00SMatthew Ahrens int error; 10181fdcbd00SMatthew Ahrens uint64_t val; 101914843421SMatthew Ahrens 1020b5152584SMatthew Ahrens zfsvfs->z_max_blksz = SPA_OLD_MAXBLOCKSIZE; 102114843421SMatthew Ahrens zfsvfs->z_show_ctldir = ZFS_SNAPDIR_VISIBLE; 102214843421SMatthew Ahrens zfsvfs->z_os = os; 102314843421SMatthew Ahrens 102414843421SMatthew Ahrens error = zfs_get_zplprop(os, ZFS_PROP_VERSION, &zfsvfs->z_version); 10251fdcbd00SMatthew Ahrens if (error != 0) 10261fdcbd00SMatthew Ahrens return (error); 10271fdcbd00SMatthew Ahrens if (zfsvfs->z_version > 1028dc7cd546SMark Shellenbaum zfs_zpl_version_map(spa_version(dmu_objset_spa(os)))) { 1029dc7cd546SMark Shellenbaum (void) printf("Can't mount a version %lld file system " 1030dc7cd546SMark Shellenbaum "on a version %lld pool\n. Pool must be upgraded to mount " 1031dc7cd546SMark Shellenbaum "this file system.", (u_longlong_t)zfsvfs->z_version, 1032dc7cd546SMark Shellenbaum (u_longlong_t)spa_version(dmu_objset_spa(os))); 10331fdcbd00SMatthew Ahrens return (SET_ERROR(ENOTSUP)); 103414843421SMatthew Ahrens } 10351fdcbd00SMatthew Ahrens error = zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &val); 10361fdcbd00SMatthew Ahrens if (error != 0) 10371fdcbd00SMatthew Ahrens return (error); 10381fdcbd00SMatthew Ahrens zfsvfs->z_norm = (int)val; 103914843421SMatthew Ahrens 10401fdcbd00SMatthew Ahrens error = zfs_get_zplprop(os, ZFS_PROP_UTF8ONLY, &val); 10411fdcbd00SMatthew Ahrens if (error != 0) 10421fdcbd00SMatthew Ahrens return (error); 10431fdcbd00SMatthew Ahrens zfsvfs->z_utf8 = (val != 0); 104414843421SMatthew Ahrens 10451fdcbd00SMatthew Ahrens error = zfs_get_zplprop(os, ZFS_PROP_CASE, &val); 10461fdcbd00SMatthew Ahrens if (error != 0) 10471fdcbd00SMatthew Ahrens return (error); 10481fdcbd00SMatthew Ahrens zfsvfs->z_case = (uint_t)val; 104914843421SMatthew Ahrens 105014843421SMatthew Ahrens /* 105114843421SMatthew Ahrens * Fold case on file systems that are always or sometimes case 105214843421SMatthew Ahrens * insensitive. 105314843421SMatthew Ahrens */ 105414843421SMatthew Ahrens if (zfsvfs->z_case == ZFS_CASE_INSENSITIVE || 105514843421SMatthew Ahrens zfsvfs->z_case == ZFS_CASE_MIXED) 105614843421SMatthew Ahrens zfsvfs->z_norm |= U8_TEXTPREP_TOUPPER; 105714843421SMatthew Ahrens 105814843421SMatthew Ahrens zfsvfs->z_use_fuids = USE_FUIDS(zfsvfs->z_version, zfsvfs->z_os); 10590a586ceaSMark Shellenbaum zfsvfs->z_use_sa = USE_SA(zfsvfs->z_version, zfsvfs->z_os); 10600a586ceaSMark Shellenbaum 10611fdcbd00SMatthew Ahrens uint64_t sa_obj = 0; 10620a586ceaSMark Shellenbaum if (zfsvfs->z_use_sa) { 10630a586ceaSMark Shellenbaum /* should either have both of these objects or none */ 10640a586ceaSMark Shellenbaum error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_SA_ATTRS, 8, 1, 10650a586ceaSMark Shellenbaum &sa_obj); 10661fdcbd00SMatthew Ahrens if (error != 0) 10671fdcbd00SMatthew Ahrens return (error); 10680a586ceaSMark Shellenbaum } 10690a586ceaSMark Shellenbaum 10701d8ccc7bSMark Shellenbaum error = sa_setup(os, sa_obj, zfs_attr_table, ZPL_END, 10711d8ccc7bSMark Shellenbaum &zfsvfs->z_attr_table); 10721fdcbd00SMatthew Ahrens if (error != 0) 10731fdcbd00SMatthew Ahrens return (error); 10740a586ceaSMark Shellenbaum 10750a586ceaSMark Shellenbaum if (zfsvfs->z_version >= ZPL_VERSION_SA) 10760a586ceaSMark Shellenbaum sa_register_update_callback(os, zfs_sa_upgrade); 107714843421SMatthew Ahrens 107814843421SMatthew Ahrens error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_ROOT_OBJ, 8, 1, 107914843421SMatthew Ahrens &zfsvfs->z_root); 10801fdcbd00SMatthew Ahrens if (error != 0) 10811fdcbd00SMatthew Ahrens return (error); 108214843421SMatthew Ahrens ASSERT(zfsvfs->z_root != 0); 108314843421SMatthew Ahrens 108414843421SMatthew Ahrens error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_UNLINKED_SET, 8, 1, 108514843421SMatthew Ahrens &zfsvfs->z_unlinkedobj); 10861fdcbd00SMatthew Ahrens if (error != 0) 10871fdcbd00SMatthew Ahrens return (error); 108814843421SMatthew Ahrens 108914843421SMatthew Ahrens error = zap_lookup(os, MASTER_NODE_OBJ, 109014843421SMatthew Ahrens zfs_userquota_prop_prefixes[ZFS_PROP_USERQUOTA], 109114843421SMatthew Ahrens 8, 1, &zfsvfs->z_userquota_obj); 10921fdcbd00SMatthew Ahrens if (error == ENOENT) 10931fdcbd00SMatthew Ahrens zfsvfs->z_userquota_obj = 0; 10941fdcbd00SMatthew Ahrens else if (error != 0) 10951fdcbd00SMatthew Ahrens return (error); 109614843421SMatthew Ahrens 109714843421SMatthew Ahrens error = zap_lookup(os, MASTER_NODE_OBJ, 109814843421SMatthew Ahrens zfs_userquota_prop_prefixes[ZFS_PROP_GROUPQUOTA], 109914843421SMatthew Ahrens 8, 1, &zfsvfs->z_groupquota_obj); 11001fdcbd00SMatthew Ahrens if (error == ENOENT) 11011fdcbd00SMatthew Ahrens zfsvfs->z_groupquota_obj = 0; 11021fdcbd00SMatthew Ahrens else if (error != 0) 11031fdcbd00SMatthew Ahrens return (error); 110414843421SMatthew Ahrens 1105*f67950b2SNasf-Fan error = zap_lookup(os, MASTER_NODE_OBJ, 1106*f67950b2SNasf-Fan zfs_userquota_prop_prefixes[ZFS_PROP_PROJECTQUOTA], 1107*f67950b2SNasf-Fan 8, 1, &zfsvfs->z_projectquota_obj); 1108*f67950b2SNasf-Fan if (error == ENOENT) 1109*f67950b2SNasf-Fan zfsvfs->z_projectquota_obj = 0; 1110*f67950b2SNasf-Fan else if (error != 0) 1111*f67950b2SNasf-Fan return (error); 1112*f67950b2SNasf-Fan 1113*f67950b2SNasf-Fan error = zap_lookup(os, MASTER_NODE_OBJ, 1114*f67950b2SNasf-Fan zfs_userquota_prop_prefixes[ZFS_PROP_USEROBJQUOTA], 1115*f67950b2SNasf-Fan 8, 1, &zfsvfs->z_userobjquota_obj); 1116*f67950b2SNasf-Fan if (error == ENOENT) 1117*f67950b2SNasf-Fan zfsvfs->z_userobjquota_obj = 0; 1118*f67950b2SNasf-Fan else if (error != 0) 1119*f67950b2SNasf-Fan return (error); 1120*f67950b2SNasf-Fan 1121*f67950b2SNasf-Fan error = zap_lookup(os, MASTER_NODE_OBJ, 1122*f67950b2SNasf-Fan zfs_userquota_prop_prefixes[ZFS_PROP_GROUPOBJQUOTA], 1123*f67950b2SNasf-Fan 8, 1, &zfsvfs->z_groupobjquota_obj); 1124*f67950b2SNasf-Fan if (error == ENOENT) 1125*f67950b2SNasf-Fan zfsvfs->z_groupobjquota_obj = 0; 1126*f67950b2SNasf-Fan else if (error != 0) 1127*f67950b2SNasf-Fan return (error); 1128*f67950b2SNasf-Fan 1129*f67950b2SNasf-Fan error = zap_lookup(os, MASTER_NODE_OBJ, 1130*f67950b2SNasf-Fan zfs_userquota_prop_prefixes[ZFS_PROP_PROJECTOBJQUOTA], 1131*f67950b2SNasf-Fan 8, 1, &zfsvfs->z_projectobjquota_obj); 1132*f67950b2SNasf-Fan if (error == ENOENT) 1133*f67950b2SNasf-Fan zfsvfs->z_projectobjquota_obj = 0; 1134*f67950b2SNasf-Fan else if (error != 0) 1135*f67950b2SNasf-Fan return (error); 1136*f67950b2SNasf-Fan 113714843421SMatthew Ahrens error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_FUID_TABLES, 8, 1, 113814843421SMatthew Ahrens &zfsvfs->z_fuid_obj); 11391fdcbd00SMatthew Ahrens if (error == ENOENT) 11401fdcbd00SMatthew Ahrens zfsvfs->z_fuid_obj = 0; 11411fdcbd00SMatthew Ahrens else if (error != 0) 11421fdcbd00SMatthew Ahrens return (error); 114314843421SMatthew Ahrens 114414843421SMatthew Ahrens error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_SHARES_DIR, 8, 1, 114514843421SMatthew Ahrens &zfsvfs->z_shares_dir); 11461fdcbd00SMatthew Ahrens if (error == ENOENT) 11471fdcbd00SMatthew Ahrens zfsvfs->z_shares_dir = 0; 11481fdcbd00SMatthew Ahrens else if (error != 0) 11491fdcbd00SMatthew Ahrens return (error); 11501fdcbd00SMatthew Ahrens 11511fdcbd00SMatthew Ahrens return (0); 11521fdcbd00SMatthew Ahrens } 11531fdcbd00SMatthew Ahrens 11541fdcbd00SMatthew Ahrens int 11551fdcbd00SMatthew Ahrens zfsvfs_create(const char *osname, zfsvfs_t **zfvp) 11561fdcbd00SMatthew Ahrens { 11571fdcbd00SMatthew Ahrens objset_t *os; 11581fdcbd00SMatthew Ahrens zfsvfs_t *zfsvfs; 11591fdcbd00SMatthew Ahrens int error; 1160*f67950b2SNasf-Fan boolean_t ro = (strchr(osname, '@') != NULL); 11611fdcbd00SMatthew Ahrens 11621fdcbd00SMatthew Ahrens zfsvfs = kmem_zalloc(sizeof (zfsvfs_t), KM_SLEEP); 11631fdcbd00SMatthew Ahrens 1164*f67950b2SNasf-Fan error = dmu_objset_own(osname, DMU_OST_ZFS, ro, B_TRUE, zfsvfs, &os); 1165dfc11533SChris Williamson if (error != 0) { 11661fdcbd00SMatthew Ahrens kmem_free(zfsvfs, sizeof (zfsvfs_t)); 11671fdcbd00SMatthew Ahrens return (error); 11681fdcbd00SMatthew Ahrens } 11691fdcbd00SMatthew Ahrens 1170dfc11533SChris Williamson error = zfsvfs_create_impl(zfvp, zfsvfs, os); 1171dfc11533SChris Williamson if (error != 0) { 1172eb633035STom Caputi dmu_objset_disown(os, B_TRUE, zfsvfs); 1173dfc11533SChris Williamson } 1174dfc11533SChris Williamson return (error); 1175dfc11533SChris Williamson } 1176dfc11533SChris Williamson 1177dfc11533SChris Williamson 1178dfc11533SChris Williamson int 1179dfc11533SChris Williamson zfsvfs_create_impl(zfsvfs_t **zfvp, zfsvfs_t *zfsvfs, objset_t *os) 1180dfc11533SChris Williamson { 1181dfc11533SChris Williamson int error; 1182dfc11533SChris Williamson 11831fdcbd00SMatthew Ahrens zfsvfs->z_vfs = NULL; 11841fdcbd00SMatthew Ahrens zfsvfs->z_parent = zfsvfs; 118514843421SMatthew Ahrens 118614843421SMatthew Ahrens mutex_init(&zfsvfs->z_znodes_lock, NULL, MUTEX_DEFAULT, NULL); 118714843421SMatthew Ahrens mutex_init(&zfsvfs->z_lock, NULL, MUTEX_DEFAULT, NULL); 118814843421SMatthew Ahrens list_create(&zfsvfs->z_all_znodes, sizeof (znode_t), 118914843421SMatthew Ahrens offsetof(znode_t, z_link_node)); 1190c9030f6cSAlexander Motin rrm_init(&zfsvfs->z_teardown_lock, B_FALSE); 119114843421SMatthew Ahrens rw_init(&zfsvfs->z_teardown_inactive_lock, NULL, RW_DEFAULT, NULL); 119214843421SMatthew Ahrens rw_init(&zfsvfs->z_fuid_lock, NULL, RW_DEFAULT, NULL); 11931fdcbd00SMatthew Ahrens for (int i = 0; i != ZFS_OBJ_MTX_SZ; i++) 119414843421SMatthew Ahrens mutex_init(&zfsvfs->z_hold_mtx[i], NULL, MUTEX_DEFAULT, NULL); 119514843421SMatthew Ahrens 11961fdcbd00SMatthew Ahrens error = zfsvfs_init(zfsvfs, os); 11971fdcbd00SMatthew Ahrens if (error != 0) { 11981fdcbd00SMatthew Ahrens *zfvp = NULL; 11991fdcbd00SMatthew Ahrens kmem_free(zfsvfs, sizeof (zfsvfs_t)); 12001fdcbd00SMatthew Ahrens return (error); 12011fdcbd00SMatthew Ahrens } 12021fdcbd00SMatthew Ahrens 1203af4c679fSSean McEnroe *zfvp = zfsvfs; 120414843421SMatthew Ahrens return (0); 120514843421SMatthew Ahrens } 120614843421SMatthew Ahrens 1207f18faf3fSek static int 1208f18faf3fSek zfsvfs_setup(zfsvfs_t *zfsvfs, boolean_t mounting) 1209f18faf3fSek { 1210f18faf3fSek int error; 1211f18faf3fSek 1212f18faf3fSek error = zfs_register_callbacks(zfsvfs->z_vfs); 1213f18faf3fSek if (error) 1214f18faf3fSek return (error); 1215f18faf3fSek 1216377c02aaSNeil Perrin zfsvfs->z_log = zil_open(zfsvfs->z_os, zfs_get_data); 1217377c02aaSNeil Perrin 1218f18faf3fSek /* 1219f18faf3fSek * If we are not mounting (ie: online recv), then we don't 1220f18faf3fSek * have to worry about replaying the log as we blocked all 1221f18faf3fSek * operations out since we closed the ZIL. 1222f18faf3fSek */ 1223f18faf3fSek if (mounting) { 1224a6e57bd4SNeil Perrin boolean_t readonly; 1225a6e57bd4SNeil Perrin 1226f18faf3fSek /* 1227f18faf3fSek * During replay we remove the read only flag to 1228f18faf3fSek * allow replays to succeed. 1229f18faf3fSek */ 1230f18faf3fSek readonly = zfsvfs->z_vfs->vfs_flag & VFS_RDONLY; 12311209a471SNeil Perrin if (readonly != 0) 12321209a471SNeil Perrin zfsvfs->z_vfs->vfs_flag &= ~VFS_RDONLY; 12331209a471SNeil Perrin else 12341209a471SNeil Perrin zfs_unlinked_drain(zfsvfs); 1235f18faf3fSek 123655da60b9SMark J Musante /* 123755da60b9SMark J Musante * Parse and replay the intent log. 123855da60b9SMark J Musante * 123955da60b9SMark J Musante * Because of ziltest, this must be done after 124055da60b9SMark J Musante * zfs_unlinked_drain(). (Further note: ziltest 124155da60b9SMark J Musante * doesn't use readonly mounts, where 124255da60b9SMark J Musante * zfs_unlinked_drain() isn't called.) This is because 124355da60b9SMark J Musante * ziltest causes spa_sync() to think it's committed, 124455da60b9SMark J Musante * but actually it is not, so the intent log contains 124555da60b9SMark J Musante * many txg's worth of changes. 124655da60b9SMark J Musante * 124755da60b9SMark J Musante * In particular, if object N is in the unlinked set in 124855da60b9SMark J Musante * the last txg to actually sync, then it could be 124955da60b9SMark J Musante * actually freed in a later txg and then reallocated 125055da60b9SMark J Musante * in a yet later txg. This would write a "create 125155da60b9SMark J Musante * object N" record to the intent log. Normally, this 125255da60b9SMark J Musante * would be fine because the spa_sync() would have 125355da60b9SMark J Musante * written out the fact that object N is free, before 125455da60b9SMark J Musante * we could write the "create object N" intent log 125555da60b9SMark J Musante * record. 125655da60b9SMark J Musante * 125755da60b9SMark J Musante * But when we are in ziltest mode, we advance the "open 125855da60b9SMark J Musante * txg" without actually spa_sync()-ing the changes to 125955da60b9SMark J Musante * disk. So we would see that object N is still 126055da60b9SMark J Musante * allocated and in the unlinked set, and there is an 126155da60b9SMark J Musante * intent log record saying to allocate it. 126255da60b9SMark J Musante */ 1263f9af39baSGeorge Wilson if (spa_writeable(dmu_objset_spa(zfsvfs->z_os))) { 1264f9af39baSGeorge Wilson if (zil_replay_disable) { 1265f9af39baSGeorge Wilson zil_destroy(zfsvfs->z_log, B_FALSE); 1266f9af39baSGeorge Wilson } else { 1267f9af39baSGeorge Wilson zfsvfs->z_replay = B_TRUE; 1268f9af39baSGeorge Wilson zil_replay(zfsvfs->z_os, zfsvfs, 1269f9af39baSGeorge Wilson zfs_replay_vector); 1270f9af39baSGeorge Wilson zfsvfs->z_replay = B_FALSE; 1271f9af39baSGeorge Wilson } 12721209a471SNeil Perrin } 1273eb633035STom Caputi 1274eb633035STom Caputi /* restore readonly bit */ 1275eb633035STom Caputi if (readonly != 0) 1276eb633035STom Caputi zfsvfs->z_vfs->vfs_flag |= VFS_RDONLY; 1277f18faf3fSek } 1278f18faf3fSek 127990f2c094SAndriy Gapon /* 128090f2c094SAndriy Gapon * Set the objset user_ptr to track its zfsvfs. 128190f2c094SAndriy Gapon */ 128290f2c094SAndriy Gapon mutex_enter(&zfsvfs->z_os->os_user_ptr_lock); 128390f2c094SAndriy Gapon dmu_objset_set_user(zfsvfs->z_os, zfsvfs); 128490f2c094SAndriy Gapon mutex_exit(&zfsvfs->z_os->os_user_ptr_lock); 128590f2c094SAndriy Gapon 1286f18faf3fSek return (0); 1287f18faf3fSek } 1288f18faf3fSek 128914843421SMatthew Ahrens void 129014843421SMatthew Ahrens zfsvfs_free(zfsvfs_t *zfsvfs) 129147f263f4Sek { 129214843421SMatthew Ahrens int i; 12934e9583b2STom Erickson extern krwlock_t zfsvfs_lock; /* in zfs_znode.c */ 12944e9583b2STom Erickson 12954e9583b2STom Erickson /* 12964e9583b2STom Erickson * This is a barrier to prevent the filesystem from going away in 12974e9583b2STom Erickson * zfs_znode_move() until we can safely ensure that the filesystem is 12984e9583b2STom Erickson * not unmounted. We consider the filesystem valid before the barrier 12994e9583b2STom Erickson * and invalid after the barrier. 13004e9583b2STom Erickson */ 13014e9583b2STom Erickson rw_enter(&zfsvfs_lock, RW_READER); 13024e9583b2STom Erickson rw_exit(&zfsvfs_lock); 130314843421SMatthew Ahrens 130414843421SMatthew Ahrens zfs_fuid_destroy(zfsvfs); 130514843421SMatthew Ahrens 130647f263f4Sek mutex_destroy(&zfsvfs->z_znodes_lock); 13079e1320c0SMark Shellenbaum mutex_destroy(&zfsvfs->z_lock); 130847f263f4Sek list_destroy(&zfsvfs->z_all_znodes); 1309c9030f6cSAlexander Motin rrm_destroy(&zfsvfs->z_teardown_lock); 131047f263f4Sek rw_destroy(&zfsvfs->z_teardown_inactive_lock); 131147f263f4Sek rw_destroy(&zfsvfs->z_fuid_lock); 131214843421SMatthew Ahrens for (i = 0; i != ZFS_OBJ_MTX_SZ; i++) 131314843421SMatthew Ahrens mutex_destroy(&zfsvfs->z_hold_mtx[i]); 131447f263f4Sek kmem_free(zfsvfs, sizeof (zfsvfs_t)); 131547f263f4Sek } 131647f263f4Sek 131714843421SMatthew Ahrens static void 131814843421SMatthew Ahrens zfs_set_fuid_feature(zfsvfs_t *zfsvfs) 131914843421SMatthew Ahrens { 132014843421SMatthew Ahrens zfsvfs->z_use_fuids = USE_FUIDS(zfsvfs->z_version, zfsvfs->z_os); 132144bffe01SMark Shellenbaum if (zfsvfs->z_vfs) { 132244bffe01SMark Shellenbaum if (zfsvfs->z_use_fuids) { 132344bffe01SMark Shellenbaum vfs_set_feature(zfsvfs->z_vfs, VFSFT_XVATTR); 132444bffe01SMark Shellenbaum vfs_set_feature(zfsvfs->z_vfs, VFSFT_SYSATTR_VIEWS); 132544bffe01SMark Shellenbaum vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACEMASKONACCESS); 132644bffe01SMark Shellenbaum vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACLONCREATE); 132744bffe01SMark Shellenbaum vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACCESS_FILTER); 132844bffe01SMark Shellenbaum vfs_set_feature(zfsvfs->z_vfs, VFSFT_REPARSE); 132944bffe01SMark Shellenbaum } else { 133044bffe01SMark Shellenbaum vfs_clear_feature(zfsvfs->z_vfs, VFSFT_XVATTR); 133144bffe01SMark Shellenbaum vfs_clear_feature(zfsvfs->z_vfs, VFSFT_SYSATTR_VIEWS); 133244bffe01SMark Shellenbaum vfs_clear_feature(zfsvfs->z_vfs, VFSFT_ACEMASKONACCESS); 133344bffe01SMark Shellenbaum vfs_clear_feature(zfsvfs->z_vfs, VFSFT_ACLONCREATE); 133444bffe01SMark Shellenbaum vfs_clear_feature(zfsvfs->z_vfs, VFSFT_ACCESS_FILTER); 133544bffe01SMark Shellenbaum vfs_clear_feature(zfsvfs->z_vfs, VFSFT_REPARSE); 133644bffe01SMark Shellenbaum } 133714843421SMatthew Ahrens } 13380a586ceaSMark Shellenbaum zfsvfs->z_use_sa = USE_SA(zfsvfs->z_version, zfsvfs->z_os); 133914843421SMatthew Ahrens } 134014843421SMatthew Ahrens 1341ea8dc4b6Seschrock static int 1342088f3894Sahrens zfs_domount(vfs_t *vfsp, char *osname) 1343ea8dc4b6Seschrock { 1344ea8dc4b6Seschrock dev_t mount_dev; 134514843421SMatthew Ahrens uint64_t recordsize, fsid_guid; 1346ea8dc4b6Seschrock int error = 0; 1347ea8dc4b6Seschrock zfsvfs_t *zfsvfs; 1348ea8dc4b6Seschrock 1349ea8dc4b6Seschrock ASSERT(vfsp); 1350ea8dc4b6Seschrock ASSERT(osname); 1351fa9e4066Sahrens 1352503ad85cSMatthew Ahrens error = zfsvfs_create(osname, &zfsvfs); 135314843421SMatthew Ahrens if (error) 135414843421SMatthew Ahrens return (error); 1355fa9e4066Sahrens zfsvfs->z_vfs = vfsp; 1356fa9e4066Sahrens 1357ea8dc4b6Seschrock /* Initialize the generic filesystem structure. */ 1358fa9e4066Sahrens vfsp->vfs_bcount = 0; 1359fa9e4066Sahrens vfsp->vfs_data = NULL; 1360fa9e4066Sahrens 1361ea8dc4b6Seschrock if (zfs_create_unique_device(&mount_dev) == -1) { 1362be6fd75aSMatthew Ahrens error = SET_ERROR(ENODEV); 1363ea8dc4b6Seschrock goto out; 1364ea8dc4b6Seschrock } 1365fa9e4066Sahrens ASSERT(vfs_devismounted(mount_dev) == 0); 1366fa9e4066Sahrens 1367ea8dc4b6Seschrock if (error = dsl_prop_get_integer(osname, "recordsize", &recordsize, 1368ea8dc4b6Seschrock NULL)) 1369ea8dc4b6Seschrock goto out; 1370fa9e4066Sahrens 1371fa9e4066Sahrens vfsp->vfs_dev = mount_dev; 1372fa9e4066Sahrens vfsp->vfs_fstype = zfsfstype; 1373fa9e4066Sahrens vfsp->vfs_bsize = recordsize; 1374fa9e4066Sahrens vfsp->vfs_flag |= VFS_NOTRUNC; 1375fa9e4066Sahrens vfsp->vfs_data = zfsvfs; 1376fa9e4066Sahrens 137714843421SMatthew Ahrens /* 137814843421SMatthew Ahrens * The fsid is 64 bits, composed of an 8-bit fs type, which 137914843421SMatthew Ahrens * separates our fsid from any other filesystem types, and a 138014843421SMatthew Ahrens * 56-bit objset unique ID. The objset unique ID is unique to 138114843421SMatthew Ahrens * all objsets open on this system, provided by unique_create(). 138214843421SMatthew Ahrens * The 8-bit fs type must be put in the low bits of fsid[1] 138314843421SMatthew Ahrens * because that's where other Solaris filesystems put it. 138414843421SMatthew Ahrens */ 138514843421SMatthew Ahrens fsid_guid = dmu_objset_fsid_guid(zfsvfs->z_os); 138614843421SMatthew Ahrens ASSERT((fsid_guid & ~((1ULL<<56)-1)) == 0); 138714843421SMatthew Ahrens vfsp->vfs_fsid.val[0] = fsid_guid; 138814843421SMatthew Ahrens vfsp->vfs_fsid.val[1] = ((fsid_guid>>32) << 8) | 138914843421SMatthew Ahrens zfsfstype & 0xFF; 1390ea8dc4b6Seschrock 1391da6c28aaSamw /* 1392da6c28aaSamw * Set features for file system. 1393da6c28aaSamw */ 139414843421SMatthew Ahrens zfs_set_fuid_feature(zfsvfs); 1395de8267e0Stimh if (zfsvfs->z_case == ZFS_CASE_INSENSITIVE) { 1396de8267e0Stimh vfs_set_feature(vfsp, VFSFT_DIRENTFLAGS); 1397de8267e0Stimh vfs_set_feature(vfsp, VFSFT_CASEINSENSITIVE); 1398de8267e0Stimh vfs_set_feature(vfsp, VFSFT_NOCASESENSITIVE); 1399de8267e0Stimh } else if (zfsvfs->z_case == ZFS_CASE_MIXED) { 1400de8267e0Stimh vfs_set_feature(vfsp, VFSFT_DIRENTFLAGS); 1401de8267e0Stimh vfs_set_feature(vfsp, VFSFT_CASEINSENSITIVE); 1402de8267e0Stimh } 1403c242f9a0Schunli zhang - Sun Microsystems - Irvine United States vfs_set_feature(vfsp, VFSFT_ZEROCOPY_SUPPORTED); 1404da6c28aaSamw 1405ea8dc4b6Seschrock if (dmu_objset_is_snapshot(zfsvfs->z_os)) { 1406da6c28aaSamw uint64_t pval; 14077b55fa8eSck 1408fa9e4066Sahrens atime_changed_cb(zfsvfs, B_FALSE); 1409fa9e4066Sahrens readonly_changed_cb(zfsvfs, B_TRUE); 1410da6c28aaSamw if (error = dsl_prop_get_integer(osname, "xattr", &pval, NULL)) 14117b55fa8eSck goto out; 1412da6c28aaSamw xattr_changed_cb(zfsvfs, pval); 1413fa9e4066Sahrens zfsvfs->z_issnap = B_TRUE; 1414b9deb9cbSMark J Musante zfsvfs->z_os->os_sync = ZFS_SYNC_DISABLED; 1415777badbaSMatthew Ahrens 1416503ad85cSMatthew Ahrens mutex_enter(&zfsvfs->z_os->os_user_ptr_lock); 1417777badbaSMatthew Ahrens dmu_objset_set_user(zfsvfs->z_os, zfsvfs); 1418503ad85cSMatthew Ahrens mutex_exit(&zfsvfs->z_os->os_user_ptr_lock); 1419fa9e4066Sahrens } else { 1420f18faf3fSek error = zfsvfs_setup(zfsvfs, B_TRUE); 1421ea8dc4b6Seschrock } 1422fa9e4066Sahrens 1423ea8dc4b6Seschrock if (!zfsvfs->z_issnap) 1424ea8dc4b6Seschrock zfsctl_create(zfsvfs); 1425ea8dc4b6Seschrock out: 1426ea8dc4b6Seschrock if (error) { 1427eb633035STom Caputi dmu_objset_disown(zfsvfs->z_os, B_TRUE, zfsvfs); 142814843421SMatthew Ahrens zfsvfs_free(zfsvfs); 1429ea8dc4b6Seschrock } else { 14301a5e258fSJosef 'Jeff' Sipek atomic_inc_32(&zfs_active_fs_count); 1431ea8dc4b6Seschrock } 1432fa9e4066Sahrens 1433ea8dc4b6Seschrock return (error); 1434ea8dc4b6Seschrock } 1435ea8dc4b6Seschrock 1436ea8dc4b6Seschrock void 1437ea8dc4b6Seschrock zfs_unregister_callbacks(zfsvfs_t *zfsvfs) 1438ea8dc4b6Seschrock { 1439ea8dc4b6Seschrock objset_t *os = zfsvfs->z_os; 1440fa9e4066Sahrens 144103bad06fSJustin Gibbs if (!dmu_objset_is_snapshot(os)) 144203bad06fSJustin Gibbs dsl_prop_unregister_all(dmu_objset_ds(os), zfsvfs); 1443ea8dc4b6Seschrock } 1444fa9e4066Sahrens 1445b1b8ab34Slling /* 1446b1b8ab34Slling * Convert a decimal digit string to a uint64_t integer. 1447b1b8ab34Slling */ 1448b1b8ab34Slling static int 1449b1b8ab34Slling str_to_uint64(char *str, uint64_t *objnum) 1450b1b8ab34Slling { 1451b1b8ab34Slling uint64_t num = 0; 1452b1b8ab34Slling 1453b1b8ab34Slling while (*str) { 1454b1b8ab34Slling if (*str < '0' || *str > '9') 1455be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1456b1b8ab34Slling 1457b1b8ab34Slling num = num*10 + *str++ - '0'; 1458b1b8ab34Slling } 1459b1b8ab34Slling 1460b1b8ab34Slling *objnum = num; 1461b1b8ab34Slling return (0); 1462b1b8ab34Slling } 1463b1b8ab34Slling 1464b1b8ab34Slling /* 1465b1b8ab34Slling * The boot path passed from the boot loader is in the form of 1466b1b8ab34Slling * "rootpool-name/root-filesystem-object-number'. Convert this 1467b1b8ab34Slling * string to a dataset name: "rootpool-name/root-filesystem-name". 1468b1b8ab34Slling */ 1469b1b8ab34Slling static int 1470e7cbe64fSgw zfs_parse_bootfs(char *bpath, char *outpath) 1471b1b8ab34Slling { 1472b1b8ab34Slling char *slashp; 1473b1b8ab34Slling uint64_t objnum; 1474b1b8ab34Slling int error; 1475b1b8ab34Slling 1476b1b8ab34Slling if (*bpath == 0 || *bpath == '/') 1477be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1478b1b8ab34Slling 147919397407SSherry Moore (void) strcpy(outpath, bpath); 148019397407SSherry Moore 1481b1b8ab34Slling slashp = strchr(bpath, '/'); 1482b1b8ab34Slling 1483b1b8ab34Slling /* if no '/', just return the pool name */ 1484b1b8ab34Slling if (slashp == NULL) { 1485b1b8ab34Slling return (0); 1486b1b8ab34Slling } 1487b1b8ab34Slling 148819397407SSherry Moore /* if not a number, just return the root dataset name */ 148919397407SSherry Moore if (str_to_uint64(slashp+1, &objnum)) { 149019397407SSherry Moore return (0); 149119397407SSherry Moore } 1492b1b8ab34Slling 1493b1b8ab34Slling *slashp = '\0'; 1494b1b8ab34Slling error = dsl_dsobj_to_dsname(bpath, objnum, outpath); 1495b1b8ab34Slling *slashp = '/'; 1496b1b8ab34Slling 1497b1b8ab34Slling return (error); 1498b1b8ab34Slling } 1499b1b8ab34Slling 15004201a95eSRic Aleshire /* 1501f7170741SWill Andrews * Check that the hex label string is appropriate for the dataset being 1502f7170741SWill Andrews * mounted into the global_zone proper. 15034201a95eSRic Aleshire * 1504f7170741SWill Andrews * Return an error if the hex label string is not default or 1505f7170741SWill Andrews * admin_low/admin_high. For admin_low labels, the corresponding 1506f7170741SWill Andrews * dataset must be readonly. 15074201a95eSRic Aleshire */ 15084201a95eSRic Aleshire int 15094201a95eSRic Aleshire zfs_check_global_label(const char *dsname, const char *hexsl) 15104201a95eSRic Aleshire { 15114201a95eSRic Aleshire if (strcasecmp(hexsl, ZFS_MLSLABEL_DEFAULT) == 0) 15124201a95eSRic Aleshire return (0); 15134201a95eSRic Aleshire if (strcasecmp(hexsl, ADMIN_HIGH) == 0) 15144201a95eSRic Aleshire return (0); 15154201a95eSRic Aleshire if (strcasecmp(hexsl, ADMIN_LOW) == 0) { 15164201a95eSRic Aleshire /* must be readonly */ 15174201a95eSRic Aleshire uint64_t rdonly; 15184201a95eSRic Aleshire 15194201a95eSRic Aleshire if (dsl_prop_get_integer(dsname, 15204201a95eSRic Aleshire zfs_prop_to_name(ZFS_PROP_READONLY), &rdonly, NULL)) 1521be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES)); 15224201a95eSRic Aleshire return (rdonly ? 0 : EACCES); 15234201a95eSRic Aleshire } 1524be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES)); 15254201a95eSRic Aleshire } 15264201a95eSRic Aleshire 1527*f67950b2SNasf-Fan static int 1528*f67950b2SNasf-Fan zfs_statfs_project(zfsvfs_t *zfsvfs, znode_t *zp, struct statvfs64 *statp, 1529*f67950b2SNasf-Fan uint32_t bshift) 1530*f67950b2SNasf-Fan { 1531*f67950b2SNasf-Fan char buf[20 + DMU_OBJACCT_PREFIX_LEN]; 1532*f67950b2SNasf-Fan uint64_t offset = DMU_OBJACCT_PREFIX_LEN; 1533*f67950b2SNasf-Fan uint64_t quota; 1534*f67950b2SNasf-Fan uint64_t used; 1535*f67950b2SNasf-Fan int err; 1536*f67950b2SNasf-Fan 1537*f67950b2SNasf-Fan strlcpy(buf, DMU_OBJACCT_PREFIX, DMU_OBJACCT_PREFIX_LEN + 1); 1538*f67950b2SNasf-Fan err = id_to_fuidstr(zfsvfs, NULL, zp->z_projid, buf + offset, B_FALSE); 1539*f67950b2SNasf-Fan if (err) 1540*f67950b2SNasf-Fan return (err); 1541*f67950b2SNasf-Fan 1542*f67950b2SNasf-Fan if (zfsvfs->z_projectquota_obj == 0) 1543*f67950b2SNasf-Fan goto objs; 1544*f67950b2SNasf-Fan 1545*f67950b2SNasf-Fan err = zap_lookup(zfsvfs->z_os, zfsvfs->z_projectquota_obj, 1546*f67950b2SNasf-Fan buf + offset, 8, 1, "a); 1547*f67950b2SNasf-Fan if (err == ENOENT) 1548*f67950b2SNasf-Fan goto objs; 1549*f67950b2SNasf-Fan else if (err) 1550*f67950b2SNasf-Fan return (err); 1551*f67950b2SNasf-Fan 1552*f67950b2SNasf-Fan err = zap_lookup(zfsvfs->z_os, DMU_PROJECTUSED_OBJECT, 1553*f67950b2SNasf-Fan buf + offset, 8, 1, &used); 1554*f67950b2SNasf-Fan if (unlikely(err == ENOENT)) { 1555*f67950b2SNasf-Fan uint32_t blksize; 1556*f67950b2SNasf-Fan u_longlong_t nblocks; 1557*f67950b2SNasf-Fan 1558*f67950b2SNasf-Fan /* 1559*f67950b2SNasf-Fan * Quota accounting is async, so it is possible race case. 1560*f67950b2SNasf-Fan * There is at least one object with the given project ID. 1561*f67950b2SNasf-Fan */ 1562*f67950b2SNasf-Fan sa_object_size(zp->z_sa_hdl, &blksize, &nblocks); 1563*f67950b2SNasf-Fan if (unlikely(zp->z_blksz == 0)) 1564*f67950b2SNasf-Fan blksize = zfsvfs->z_max_blksz; 1565*f67950b2SNasf-Fan 1566*f67950b2SNasf-Fan used = blksize * nblocks; 1567*f67950b2SNasf-Fan } else if (err) { 1568*f67950b2SNasf-Fan return (err); 1569*f67950b2SNasf-Fan } 1570*f67950b2SNasf-Fan 1571*f67950b2SNasf-Fan statp->f_blocks = quota >> bshift; 1572*f67950b2SNasf-Fan statp->f_bfree = (quota > used) ? ((quota - used) >> bshift) : 0; 1573*f67950b2SNasf-Fan statp->f_bavail = statp->f_bfree; 1574*f67950b2SNasf-Fan 1575*f67950b2SNasf-Fan objs: 1576*f67950b2SNasf-Fan if (zfsvfs->z_projectobjquota_obj == 0) 1577*f67950b2SNasf-Fan return (0); 1578*f67950b2SNasf-Fan 1579*f67950b2SNasf-Fan err = zap_lookup(zfsvfs->z_os, zfsvfs->z_projectobjquota_obj, 1580*f67950b2SNasf-Fan buf + offset, 8, 1, "a); 1581*f67950b2SNasf-Fan if (err == ENOENT) 1582*f67950b2SNasf-Fan return (0); 1583*f67950b2SNasf-Fan else if (err) 1584*f67950b2SNasf-Fan return (err); 1585*f67950b2SNasf-Fan 1586*f67950b2SNasf-Fan err = zap_lookup(zfsvfs->z_os, DMU_PROJECTUSED_OBJECT, 1587*f67950b2SNasf-Fan buf, 8, 1, &used); 1588*f67950b2SNasf-Fan if (unlikely(err == ENOENT)) { 1589*f67950b2SNasf-Fan /* 1590*f67950b2SNasf-Fan * Quota accounting is async, so it is possible race case. 1591*f67950b2SNasf-Fan * There is at least one object with the given project ID. 1592*f67950b2SNasf-Fan */ 1593*f67950b2SNasf-Fan used = 1; 1594*f67950b2SNasf-Fan } else if (err) { 1595*f67950b2SNasf-Fan return (err); 1596*f67950b2SNasf-Fan } 1597*f67950b2SNasf-Fan 1598*f67950b2SNasf-Fan statp->f_files = quota; 1599*f67950b2SNasf-Fan statp->f_ffree = (quota > used) ? (quota - used) : 0; 1600*f67950b2SNasf-Fan 1601*f67950b2SNasf-Fan return (0); 1602*f67950b2SNasf-Fan } 1603*f67950b2SNasf-Fan 16044201a95eSRic Aleshire /* 1605f7170741SWill Andrews * Determine whether the mount is allowed according to MAC check. 1606f7170741SWill Andrews * by comparing (where appropriate) label of the dataset against 1607f7170741SWill Andrews * the label of the zone being mounted into. If the dataset has 1608f7170741SWill Andrews * no label, create one. 16094201a95eSRic Aleshire * 1610f7170741SWill Andrews * Returns 0 if access allowed, error otherwise (e.g. EACCES) 16114201a95eSRic Aleshire */ 16124201a95eSRic Aleshire static int 16134201a95eSRic Aleshire zfs_mount_label_policy(vfs_t *vfsp, char *osname) 16144201a95eSRic Aleshire { 16154201a95eSRic Aleshire int error, retv; 16164201a95eSRic Aleshire zone_t *mntzone = NULL; 16174201a95eSRic Aleshire ts_label_t *mnt_tsl; 16184201a95eSRic Aleshire bslabel_t *mnt_sl; 16194201a95eSRic Aleshire bslabel_t ds_sl; 16204201a95eSRic Aleshire char ds_hexsl[MAXNAMELEN]; 16214201a95eSRic Aleshire 16224201a95eSRic Aleshire retv = EACCES; /* assume the worst */ 16234201a95eSRic Aleshire 16244201a95eSRic Aleshire /* 16254201a95eSRic Aleshire * Start by getting the dataset label if it exists. 16264201a95eSRic Aleshire */ 16274201a95eSRic Aleshire error = dsl_prop_get(osname, zfs_prop_to_name(ZFS_PROP_MLSLABEL), 16284201a95eSRic Aleshire 1, sizeof (ds_hexsl), &ds_hexsl, NULL); 16294201a95eSRic Aleshire if (error) 1630be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES)); 16314201a95eSRic Aleshire 16324201a95eSRic Aleshire /* 16334201a95eSRic Aleshire * If labeling is NOT enabled, then disallow the mount of datasets 16344201a95eSRic Aleshire * which have a non-default label already. No other label checks 16354201a95eSRic Aleshire * are needed. 16364201a95eSRic Aleshire */ 16374201a95eSRic Aleshire if (!is_system_labeled()) { 16384201a95eSRic Aleshire if (strcasecmp(ds_hexsl, ZFS_MLSLABEL_DEFAULT) == 0) 16394201a95eSRic Aleshire return (0); 1640be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES)); 16414201a95eSRic Aleshire } 16424201a95eSRic Aleshire 16434201a95eSRic Aleshire /* 16444201a95eSRic Aleshire * Get the label of the mountpoint. If mounting into the global 16454201a95eSRic Aleshire * zone (i.e. mountpoint is not within an active zone and the 16464201a95eSRic Aleshire * zoned property is off), the label must be default or 16474201a95eSRic Aleshire * admin_low/admin_high only; no other checks are needed. 16484201a95eSRic Aleshire */ 16494201a95eSRic Aleshire mntzone = zone_find_by_any_path(refstr_value(vfsp->vfs_mntpt), B_FALSE); 16504201a95eSRic Aleshire if (mntzone->zone_id == GLOBAL_ZONEID) { 16514201a95eSRic Aleshire uint64_t zoned; 16524201a95eSRic Aleshire 16534201a95eSRic Aleshire zone_rele(mntzone); 16544201a95eSRic Aleshire 16554201a95eSRic Aleshire if (dsl_prop_get_integer(osname, 16564201a95eSRic Aleshire zfs_prop_to_name(ZFS_PROP_ZONED), &zoned, NULL)) 1657be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES)); 16584201a95eSRic Aleshire if (!zoned) 16594201a95eSRic Aleshire return (zfs_check_global_label(osname, ds_hexsl)); 16604201a95eSRic Aleshire else 16614201a95eSRic Aleshire /* 16624201a95eSRic Aleshire * This is the case of a zone dataset being mounted 16634201a95eSRic Aleshire * initially, before the zone has been fully created; 16644201a95eSRic Aleshire * allow this mount into global zone. 16654201a95eSRic Aleshire */ 16664201a95eSRic Aleshire return (0); 16674201a95eSRic Aleshire } 16684201a95eSRic Aleshire 16694201a95eSRic Aleshire mnt_tsl = mntzone->zone_slabel; 16704201a95eSRic Aleshire ASSERT(mnt_tsl != NULL); 16714201a95eSRic Aleshire label_hold(mnt_tsl); 16724201a95eSRic Aleshire mnt_sl = label2bslabel(mnt_tsl); 16734201a95eSRic Aleshire 16744201a95eSRic Aleshire if (strcasecmp(ds_hexsl, ZFS_MLSLABEL_DEFAULT) == 0) { 16754201a95eSRic Aleshire /* 16764201a95eSRic Aleshire * The dataset doesn't have a real label, so fabricate one. 16774201a95eSRic Aleshire */ 16784201a95eSRic Aleshire char *str = NULL; 16794201a95eSRic Aleshire 16804201a95eSRic Aleshire if (l_to_str_internal(mnt_sl, &str) == 0 && 16813b2aab18SMatthew Ahrens dsl_prop_set_string(osname, 16823b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_MLSLABEL), 16833b2aab18SMatthew Ahrens ZPROP_SRC_LOCAL, str) == 0) 16844201a95eSRic Aleshire retv = 0; 16854201a95eSRic Aleshire if (str != NULL) 16864201a95eSRic Aleshire kmem_free(str, strlen(str) + 1); 16874201a95eSRic Aleshire } else if (hexstr_to_label(ds_hexsl, &ds_sl) == 0) { 16884201a95eSRic Aleshire /* 16894201a95eSRic Aleshire * Now compare labels to complete the MAC check. If the 16904201a95eSRic Aleshire * labels are equal then allow access. If the mountpoint 16914201a95eSRic Aleshire * label dominates the dataset label, allow readonly access. 16924201a95eSRic Aleshire * Otherwise, access is denied. 16934201a95eSRic Aleshire */ 16944201a95eSRic Aleshire if (blequal(mnt_sl, &ds_sl)) 16954201a95eSRic Aleshire retv = 0; 16964201a95eSRic Aleshire else if (bldominates(mnt_sl, &ds_sl)) { 16974201a95eSRic Aleshire vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); 16984201a95eSRic Aleshire retv = 0; 16994201a95eSRic Aleshire } 17004201a95eSRic Aleshire } 17014201a95eSRic Aleshire 17024201a95eSRic Aleshire label_rele(mnt_tsl); 17034201a95eSRic Aleshire zone_rele(mntzone); 17044201a95eSRic Aleshire return (retv); 17054201a95eSRic Aleshire } 17064201a95eSRic Aleshire 1707ea8dc4b6Seschrock static int 1708ea8dc4b6Seschrock zfs_mountroot(vfs_t *vfsp, enum whymountroot why) 1709ea8dc4b6Seschrock { 1710ea8dc4b6Seschrock int error = 0; 1711ea8dc4b6Seschrock static int zfsrootdone = 0; 1712ea8dc4b6Seschrock zfsvfs_t *zfsvfs = NULL; 1713ea8dc4b6Seschrock znode_t *zp = NULL; 1714ea8dc4b6Seschrock vnode_t *vp = NULL; 1715e7cbe64fSgw char *zfs_bootfs; 1716051aabe6Staylor char *zfs_devid; 1717ea8dc4b6Seschrock 1718ea8dc4b6Seschrock ASSERT(vfsp); 1719ea8dc4b6Seschrock 1720ea8dc4b6Seschrock /* 1721b1b8ab34Slling * The filesystem that we mount as root is defined in the 1722e7cbe64fSgw * boot property "zfs-bootfs" with a format of 1723e7cbe64fSgw * "poolname/root-dataset-objnum". 1724ea8dc4b6Seschrock */ 1725ea8dc4b6Seschrock if (why == ROOT_INIT) { 1726ea8dc4b6Seschrock if (zfsrootdone++) 1727be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 1728e7cbe64fSgw /* 1729e7cbe64fSgw * the process of doing a spa_load will require the 1730e7cbe64fSgw * clock to be set before we could (for example) do 1731e7cbe64fSgw * something better by looking at the timestamp on 1732e7cbe64fSgw * an uberblock, so just set it to -1. 1733e7cbe64fSgw */ 1734e7cbe64fSgw clkset(-1); 1735fa9e4066Sahrens 1736051aabe6Staylor if ((zfs_bootfs = spa_get_bootprop("zfs-bootfs")) == NULL) { 1737051aabe6Staylor cmn_err(CE_NOTE, "spa_get_bootfs: can not get " 1738051aabe6Staylor "bootfs name"); 1739be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1740986fd29aSsetje } 1741051aabe6Staylor zfs_devid = spa_get_bootprop("diskdevid"); 1742051aabe6Staylor error = spa_import_rootpool(rootfs.bo_name, zfs_devid); 1743051aabe6Staylor if (zfs_devid) 1744051aabe6Staylor spa_free_bootprop(zfs_devid); 1745051aabe6Staylor if (error) { 1746051aabe6Staylor spa_free_bootprop(zfs_bootfs); 1747051aabe6Staylor cmn_err(CE_NOTE, "spa_import_rootpool: error %d", 1748e7cbe64fSgw error); 1749e7cbe64fSgw return (error); 1750e7cbe64fSgw } 1751e7cbe64fSgw if (error = zfs_parse_bootfs(zfs_bootfs, rootfs.bo_name)) { 1752051aabe6Staylor spa_free_bootprop(zfs_bootfs); 1753051aabe6Staylor cmn_err(CE_NOTE, "zfs_parse_bootfs: error %d", 1754e7cbe64fSgw error); 1755b1b8ab34Slling return (error); 1756e7cbe64fSgw } 1757e7cbe64fSgw 1758051aabe6Staylor spa_free_bootprop(zfs_bootfs); 1759fa9e4066Sahrens 1760ea8dc4b6Seschrock if (error = vfs_lock(vfsp)) 1761ea8dc4b6Seschrock return (error); 1762fa9e4066Sahrens 1763088f3894Sahrens if (error = zfs_domount(vfsp, rootfs.bo_name)) { 1764051aabe6Staylor cmn_err(CE_NOTE, "zfs_domount: error %d", error); 1765ea8dc4b6Seschrock goto out; 1766e7cbe64fSgw } 1767ea8dc4b6Seschrock 1768ea8dc4b6Seschrock zfsvfs = (zfsvfs_t *)vfsp->vfs_data; 1769ea8dc4b6Seschrock ASSERT(zfsvfs); 1770e7cbe64fSgw if (error = zfs_zget(zfsvfs, zfsvfs->z_root, &zp)) { 1771051aabe6Staylor cmn_err(CE_NOTE, "zfs_zget: error %d", error); 1772ea8dc4b6Seschrock goto out; 1773e7cbe64fSgw } 1774ea8dc4b6Seschrock 1775ea8dc4b6Seschrock vp = ZTOV(zp); 1776ea8dc4b6Seschrock mutex_enter(&vp->v_lock); 1777ea8dc4b6Seschrock vp->v_flag |= VROOT; 1778ea8dc4b6Seschrock mutex_exit(&vp->v_lock); 1779ea8dc4b6Seschrock rootvp = vp; 1780ea8dc4b6Seschrock 1781ea8dc4b6Seschrock /* 178240d3dfe1Smarks * Leave rootvp held. The root file system is never unmounted. 1783ea8dc4b6Seschrock */ 1784ea8dc4b6Seschrock 1785ea8dc4b6Seschrock vfs_add((struct vnode *)0, vfsp, 1786ea8dc4b6Seschrock (vfsp->vfs_flag & VFS_RDONLY) ? MS_RDONLY : 0); 1787ea8dc4b6Seschrock out: 1788ea8dc4b6Seschrock vfs_unlock(vfsp); 1789e7cbe64fSgw return (error); 1790ea8dc4b6Seschrock } else if (why == ROOT_REMOUNT) { 1791ea8dc4b6Seschrock readonly_changed_cb(vfsp->vfs_data, B_FALSE); 1792ea8dc4b6Seschrock vfsp->vfs_flag |= VFS_REMOUNT; 1793b510d378Slling 1794b510d378Slling /* refresh mount options */ 1795b510d378Slling zfs_unregister_callbacks(vfsp->vfs_data); 1796b510d378Slling return (zfs_register_callbacks(vfsp)); 1797b510d378Slling 1798ea8dc4b6Seschrock } else if (why == ROOT_UNMOUNT) { 1799ea8dc4b6Seschrock zfs_unregister_callbacks((zfsvfs_t *)vfsp->vfs_data); 1800ea8dc4b6Seschrock (void) zfs_sync(vfsp, 0, 0); 1801ea8dc4b6Seschrock return (0); 1802ea8dc4b6Seschrock } 1803ea8dc4b6Seschrock 1804ea8dc4b6Seschrock /* 1805ea8dc4b6Seschrock * if "why" is equal to anything else other than ROOT_INIT, 1806ea8dc4b6Seschrock * ROOT_REMOUNT, or ROOT_UNMOUNT, we do not support it. 1807ea8dc4b6Seschrock */ 1808be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 1809ea8dc4b6Seschrock } 1810ea8dc4b6Seschrock 1811ea8dc4b6Seschrock /*ARGSUSED*/ 1812ea8dc4b6Seschrock static int 1813ea8dc4b6Seschrock zfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) 1814ea8dc4b6Seschrock { 1815ea8dc4b6Seschrock char *osname; 1816ea8dc4b6Seschrock pathname_t spn; 1817ea8dc4b6Seschrock int error = 0; 1818ea8dc4b6Seschrock uio_seg_t fromspace = (uap->flags & MS_SYSSPACE) ? 1819b1b8ab34Slling UIO_SYSSPACE : UIO_USERSPACE; 1820ea8dc4b6Seschrock int canwrite; 1821ea8dc4b6Seschrock 1822ea8dc4b6Seschrock if (mvp->v_type != VDIR) 1823be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTDIR)); 1824ea8dc4b6Seschrock 1825ea8dc4b6Seschrock mutex_enter(&mvp->v_lock); 1826ea8dc4b6Seschrock if ((uap->flags & MS_REMOUNT) == 0 && 1827ea8dc4b6Seschrock (uap->flags & MS_OVERLAY) == 0 && 1828ea8dc4b6Seschrock (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { 1829ea8dc4b6Seschrock mutex_exit(&mvp->v_lock); 1830be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 1831ea8dc4b6Seschrock } 1832ea8dc4b6Seschrock mutex_exit(&mvp->v_lock); 1833ea8dc4b6Seschrock 1834ea8dc4b6Seschrock /* 1835ea8dc4b6Seschrock * ZFS does not support passing unparsed data in via MS_DATA. 1836ea8dc4b6Seschrock * Users should use the MS_OPTIONSTR interface; this means 1837ea8dc4b6Seschrock * that all option parsing is already done and the options struct 1838ea8dc4b6Seschrock * can be interrogated. 1839ea8dc4b6Seschrock */ 1840ea8dc4b6Seschrock if ((uap->flags & MS_DATA) && uap->datalen > 0) 1841be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1842ea8dc4b6Seschrock 1843ea8dc4b6Seschrock /* 1844ea8dc4b6Seschrock * Get the objset name (the "special" mount argument). 1845ea8dc4b6Seschrock */ 1846ea8dc4b6Seschrock if (error = pn_get(uap->spec, fromspace, &spn)) 1847ea8dc4b6Seschrock return (error); 1848ea8dc4b6Seschrock 1849ea8dc4b6Seschrock osname = spn.pn_path; 1850ea8dc4b6Seschrock 1851ecd6cf80Smarks /* 1852ecd6cf80Smarks * Check for mount privilege? 1853ecd6cf80Smarks * 1854ecd6cf80Smarks * If we don't have privilege then see if 1855ecd6cf80Smarks * we have local permission to allow it 1856ecd6cf80Smarks */ 1857ecd6cf80Smarks error = secpolicy_fs_mount(cr, mvp, vfsp); 1858ecd6cf80Smarks if (error) { 185998679b56SMark Shellenbaum if (dsl_deleg_access(osname, ZFS_DELEG_PERM_MOUNT, cr) == 0) { 1860ecd6cf80Smarks vattr_t vattr; 1861ecd6cf80Smarks 1862ecd6cf80Smarks /* 1863ecd6cf80Smarks * Make sure user is the owner of the mount point 1864ecd6cf80Smarks * or has sufficient privileges. 1865ecd6cf80Smarks */ 1866ecd6cf80Smarks 1867ecd6cf80Smarks vattr.va_mask = AT_UID; 1868ecd6cf80Smarks 186998679b56SMark Shellenbaum if (VOP_GETATTR(mvp, &vattr, 0, cr, NULL)) { 1870ecd6cf80Smarks goto out; 1871ecd6cf80Smarks } 1872ecd6cf80Smarks 18732459a9eaSmarks if (secpolicy_vnode_owner(cr, vattr.va_uid) != 0 && 18742459a9eaSmarks VOP_ACCESS(mvp, VWRITE, 0, cr, NULL) != 0) { 1875ecd6cf80Smarks goto out; 1876ecd6cf80Smarks } 1877ecd6cf80Smarks secpolicy_fs_mount_clearopts(cr, vfsp); 1878ecd6cf80Smarks } else { 1879ecd6cf80Smarks goto out; 1880ecd6cf80Smarks } 1881ecd6cf80Smarks } 1882ea8dc4b6Seschrock 1883ea8dc4b6Seschrock /* 1884ea8dc4b6Seschrock * Refuse to mount a filesystem if we are in a local zone and the 1885ea8dc4b6Seschrock * dataset is not visible. 1886ea8dc4b6Seschrock */ 1887ea8dc4b6Seschrock if (!INGLOBALZONE(curproc) && 1888ea8dc4b6Seschrock (!zone_dataset_visible(osname, &canwrite) || !canwrite)) { 1889be6fd75aSMatthew Ahrens error = SET_ERROR(EPERM); 1890ea8dc4b6Seschrock goto out; 1891ea8dc4b6Seschrock } 1892ea8dc4b6Seschrock 18934201a95eSRic Aleshire error = zfs_mount_label_policy(vfsp, osname); 18944201a95eSRic Aleshire if (error) 18954201a95eSRic Aleshire goto out; 18964201a95eSRic Aleshire 1897b510d378Slling /* 1898b510d378Slling * When doing a remount, we simply refresh our temporary properties 1899b510d378Slling * according to those options set in the current VFS options. 1900b510d378Slling */ 1901b510d378Slling if (uap->flags & MS_REMOUNT) { 1902b510d378Slling /* refresh mount options */ 1903b510d378Slling zfs_unregister_callbacks(vfsp->vfs_data); 1904b510d378Slling error = zfs_register_callbacks(vfsp); 1905b510d378Slling goto out; 1906b510d378Slling } 1907b510d378Slling 1908088f3894Sahrens error = zfs_domount(vfsp, osname); 1909ea8dc4b6Seschrock 1910142ae85dSChris Kirby /* 1911142ae85dSChris Kirby * Add an extra VFS_HOLD on our parent vfs so that it can't 1912142ae85dSChris Kirby * disappear due to a forced unmount. 1913142ae85dSChris Kirby */ 1914984a131bSChris Kirby if (error == 0 && ((zfsvfs_t *)vfsp->vfs_data)->z_issnap) 1915142ae85dSChris Kirby VFS_HOLD(mvp->v_vfsp); 1916142ae85dSChris Kirby 1917ea8dc4b6Seschrock out: 1918fa9e4066Sahrens pn_free(&spn); 1919fa9e4066Sahrens return (error); 1920fa9e4066Sahrens } 1921fa9e4066Sahrens 1922fa9e4066Sahrens static int 1923fa9e4066Sahrens zfs_statvfs(vfs_t *vfsp, struct statvfs64 *statp) 1924fa9e4066Sahrens { 1925fa9e4066Sahrens zfsvfs_t *zfsvfs = vfsp->vfs_data; 1926fa9e4066Sahrens dev32_t d32; 1927a2eea2e1Sahrens uint64_t refdbytes, availbytes, usedobjs, availobjs; 1928*f67950b2SNasf-Fan int err = 0; 1929fa9e4066Sahrens 1930fa9e4066Sahrens ZFS_ENTER(zfsvfs); 1931fa9e4066Sahrens 1932a2eea2e1Sahrens dmu_objset_space(zfsvfs->z_os, 1933a2eea2e1Sahrens &refdbytes, &availbytes, &usedobjs, &availobjs); 1934fa9e4066Sahrens 1935fa9e4066Sahrens /* 1936fa9e4066Sahrens * The underlying storage pool actually uses multiple block sizes. 1937fa9e4066Sahrens * We report the fragsize as the smallest block size we support, 1938fa9e4066Sahrens * and we report our blocksize as the filesystem's maximum blocksize. 1939fa9e4066Sahrens */ 1940fa9e4066Sahrens statp->f_frsize = 1UL << SPA_MINBLOCKSHIFT; 1941fa9e4066Sahrens statp->f_bsize = zfsvfs->z_max_blksz; 1942fa9e4066Sahrens 1943fa9e4066Sahrens /* 1944fa9e4066Sahrens * The following report "total" blocks of various kinds in the 1945fa9e4066Sahrens * file system, but reported in terms of f_frsize - the 1946fa9e4066Sahrens * "fragment" size. 1947fa9e4066Sahrens */ 1948fa9e4066Sahrens 1949a2eea2e1Sahrens statp->f_blocks = (refdbytes + availbytes) >> SPA_MINBLOCKSHIFT; 1950a2eea2e1Sahrens statp->f_bfree = availbytes >> SPA_MINBLOCKSHIFT; 1951fa9e4066Sahrens statp->f_bavail = statp->f_bfree; /* no root reservation */ 1952fa9e4066Sahrens 1953fa9e4066Sahrens /* 1954fa9e4066Sahrens * statvfs() should really be called statufs(), because it assumes 1955fa9e4066Sahrens * static metadata. ZFS doesn't preallocate files, so the best 1956fa9e4066Sahrens * we can do is report the max that could possibly fit in f_files, 1957fa9e4066Sahrens * and that minus the number actually used in f_ffree. 1958fa9e4066Sahrens * For f_ffree, report the smaller of the number of object available 1959fa9e4066Sahrens * and the number of blocks (each object will take at least a block). 1960fa9e4066Sahrens */ 1961a2eea2e1Sahrens statp->f_ffree = MIN(availobjs, statp->f_bfree); 1962fa9e4066Sahrens statp->f_favail = statp->f_ffree; /* no "root reservation" */ 1963a2eea2e1Sahrens statp->f_files = statp->f_ffree + usedobjs; 1964fa9e4066Sahrens 1965fa9e4066Sahrens (void) cmpldev(&d32, vfsp->vfs_dev); 1966fa9e4066Sahrens statp->f_fsid = d32; 1967fa9e4066Sahrens 1968fa9e4066Sahrens /* 1969fa9e4066Sahrens * We're a zfs filesystem. 1970fa9e4066Sahrens */ 1971fa9e4066Sahrens (void) strcpy(statp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name); 1972fa9e4066Sahrens 1973a5be7ebbSmarks statp->f_flag = vf_to_stf(vfsp->vfs_flag); 1974fa9e4066Sahrens 19759adfa60dSMatthew Ahrens statp->f_namemax = MAXNAMELEN - 1; 1976fa9e4066Sahrens 1977fa9e4066Sahrens /* 1978fa9e4066Sahrens * We have all of 32 characters to stuff a string here. 1979fa9e4066Sahrens * Is there anything useful we could/should provide? 1980fa9e4066Sahrens */ 1981fa9e4066Sahrens bzero(statp->f_fstr, sizeof (statp->f_fstr)); 1982fa9e4066Sahrens 1983*f67950b2SNasf-Fan if (dmu_objset_projectquota_enabled(zfsvfs->z_os) && 1984*f67950b2SNasf-Fan dmu_objset_projectquota_present(zfsvfs->z_os)) { 1985*f67950b2SNasf-Fan znode_t *zp; 1986*f67950b2SNasf-Fan 1987*f67950b2SNasf-Fan /* 1988*f67950b2SNasf-Fan * In ZoL, zfs_statvfs is passed a Linux dentry (directory 1989*f67950b2SNasf-Fan * entry), instead of a vfsp. The ZoL code uses the dentry 1990*f67950b2SNasf-Fan * to get the znode from the dentry's inode. This represents 1991*f67950b2SNasf-Fan * whatever filename was passed to the user-level statvfs 1992*f67950b2SNasf-Fan * syscall. 1993*f67950b2SNasf-Fan * 1994*f67950b2SNasf-Fan * We're using the VFS root znode here, so this represents a 1995*f67950b2SNasf-Fan * potential difference from ZoL. 1996*f67950b2SNasf-Fan */ 1997*f67950b2SNasf-Fan if (zfs_zget(zfsvfs, zfsvfs->z_root, &zp) == 0) { 1998*f67950b2SNasf-Fan uint32_t bshift = ddi_fls(statp->f_bsize) - 1; 1999*f67950b2SNasf-Fan 2000*f67950b2SNasf-Fan if (zp->z_pflags & ZFS_PROJINHERIT && zp->z_projid && 2001*f67950b2SNasf-Fan zpl_is_valid_projid(zp->z_projid)) 2002*f67950b2SNasf-Fan err = zfs_statfs_project(zfsvfs, zp, statp, 2003*f67950b2SNasf-Fan bshift); 2004*f67950b2SNasf-Fan VN_RELE(ZTOV(zp)); 2005*f67950b2SNasf-Fan } 2006*f67950b2SNasf-Fan } 2007*f67950b2SNasf-Fan 2008fa9e4066Sahrens ZFS_EXIT(zfsvfs); 2009*f67950b2SNasf-Fan return (err); 2010fa9e4066Sahrens } 2011fa9e4066Sahrens 2012fa9e4066Sahrens static int 2013fa9e4066Sahrens zfs_root(vfs_t *vfsp, vnode_t **vpp) 2014fa9e4066Sahrens { 2015fa9e4066Sahrens zfsvfs_t *zfsvfs = vfsp->vfs_data; 2016fa9e4066Sahrens znode_t *rootzp; 2017fa9e4066Sahrens int error; 2018fa9e4066Sahrens 2019fa9e4066Sahrens ZFS_ENTER(zfsvfs); 2020fa9e4066Sahrens 2021fa9e4066Sahrens error = zfs_zget(zfsvfs, zfsvfs->z_root, &rootzp); 2022fa9e4066Sahrens if (error == 0) 2023fa9e4066Sahrens *vpp = ZTOV(rootzp); 2024fa9e4066Sahrens 2025fa9e4066Sahrens ZFS_EXIT(zfsvfs); 2026fa9e4066Sahrens return (error); 2027fa9e4066Sahrens } 2028fa9e4066Sahrens 2029f18faf3fSek /* 2030f18faf3fSek * Teardown the zfsvfs::z_os. 2031f18faf3fSek * 2032eb721827SAlek Pinchuk * Note, if 'unmounting' is FALSE, we return with the 'z_teardown_lock' 2033f18faf3fSek * and 'z_teardown_inactive_lock' held. 2034f18faf3fSek */ 2035f18faf3fSek static int 2036f18faf3fSek zfsvfs_teardown(zfsvfs_t *zfsvfs, boolean_t unmounting) 2037f18faf3fSek { 2038874395d5Smaybee znode_t *zp; 2039f18faf3fSek 2040c9030f6cSAlexander Motin rrm_enter(&zfsvfs->z_teardown_lock, RW_WRITER, FTAG); 2041f18faf3fSek 2042f18faf3fSek if (!unmounting) { 2043f18faf3fSek /* 2044f18faf3fSek * We purge the parent filesystem's vfsp as the parent 2045f18faf3fSek * filesystem and all of its snapshots have their vnode's 2046f18faf3fSek * v_vfsp set to the parent's filesystem's vfsp. Note, 2047f18faf3fSek * 'z_parent' is self referential for non-snapshots. 2048f18faf3fSek */ 2049f18faf3fSek (void) dnlc_purge_vfsp(zfsvfs->z_parent->z_vfs, 0); 2050f18faf3fSek } 2051f18faf3fSek 2052f18faf3fSek /* 2053f18faf3fSek * Close the zil. NB: Can't close the zil while zfs_inactive 2054f18faf3fSek * threads are blocked as zil_close can call zfs_inactive. 2055f18faf3fSek */ 2056f18faf3fSek if (zfsvfs->z_log) { 2057f18faf3fSek zil_close(zfsvfs->z_log); 2058f18faf3fSek zfsvfs->z_log = NULL; 2059f18faf3fSek } 2060f18faf3fSek 2061f18faf3fSek rw_enter(&zfsvfs->z_teardown_inactive_lock, RW_WRITER); 2062f18faf3fSek 2063f18faf3fSek /* 2064f18faf3fSek * If we are not unmounting (ie: online recv) and someone already 2065f18faf3fSek * unmounted this file system while we were doing the switcheroo, 2066f18faf3fSek * or a reopen of z_os failed then just bail out now. 2067f18faf3fSek */ 2068f18faf3fSek if (!unmounting && (zfsvfs->z_unmounted || zfsvfs->z_os == NULL)) { 2069f18faf3fSek rw_exit(&zfsvfs->z_teardown_inactive_lock); 2070c9030f6cSAlexander Motin rrm_exit(&zfsvfs->z_teardown_lock, FTAG); 2071be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 2072f18faf3fSek } 2073f18faf3fSek 2074f18faf3fSek /* 2075f18faf3fSek * At this point there are no vops active, and any new vops will 2076f18faf3fSek * fail with EIO since we have z_teardown_lock for writer (only 2077f18faf3fSek * relavent for forced unmount). 2078f18faf3fSek * 2079f18faf3fSek * Release all holds on dbufs. 2080f18faf3fSek */ 2081f18faf3fSek mutex_enter(&zfsvfs->z_znodes_lock); 2082874395d5Smaybee for (zp = list_head(&zfsvfs->z_all_znodes); zp != NULL; 2083874395d5Smaybee zp = list_next(&zfsvfs->z_all_znodes, zp)) 20840a586ceaSMark Shellenbaum if (zp->z_sa_hdl) { 2085874395d5Smaybee ASSERT(ZTOV(zp)->v_count > 0); 2086874395d5Smaybee zfs_znode_dmu_fini(zp); 2087f18faf3fSek } 2088f18faf3fSek mutex_exit(&zfsvfs->z_znodes_lock); 2089f18faf3fSek 2090f18faf3fSek /* 2091f18faf3fSek * If we are unmounting, set the unmounted flag and let new vops 2092f18faf3fSek * unblock. zfs_inactive will have the unmounted behavior, and all 2093f18faf3fSek * other vops will fail with EIO. 2094f18faf3fSek */ 2095f18faf3fSek if (unmounting) { 2096f18faf3fSek zfsvfs->z_unmounted = B_TRUE; 2097f18faf3fSek rw_exit(&zfsvfs->z_teardown_inactive_lock); 2098eb721827SAlek Pinchuk rrm_exit(&zfsvfs->z_teardown_lock, FTAG); 2099f18faf3fSek } 2100f18faf3fSek 2101f18faf3fSek /* 2102f18faf3fSek * z_os will be NULL if there was an error in attempting to reopen 2103f18faf3fSek * zfsvfs, so just return as the properties had already been 2104f18faf3fSek * unregistered and cached data had been evicted before. 2105f18faf3fSek */ 2106f18faf3fSek if (zfsvfs->z_os == NULL) 2107f18faf3fSek return (0); 2108f18faf3fSek 2109f18faf3fSek /* 2110f18faf3fSek * Unregister properties. 2111f18faf3fSek */ 2112f18faf3fSek zfs_unregister_callbacks(zfsvfs); 2113f18faf3fSek 2114f18faf3fSek /* 2115f18faf3fSek * Evict cached data 2116f18faf3fSek */ 21172e2c1355SMatthew Ahrens if (dsl_dataset_is_dirty(dmu_objset_ds(zfsvfs->z_os)) && 21182e2c1355SMatthew Ahrens !(zfsvfs->z_vfs->vfs_flag & VFS_RDONLY)) 21192e2c1355SMatthew Ahrens txg_wait_synced(dmu_objset_pool(zfsvfs->z_os), 0); 21203b2aab18SMatthew Ahrens dmu_objset_evict_dbufs(zfsvfs->z_os); 2121f18faf3fSek 2122f18faf3fSek return (0); 2123f18faf3fSek } 2124f18faf3fSek 2125fa9e4066Sahrens /*ARGSUSED*/ 2126fa9e4066Sahrens static int 2127fa9e4066Sahrens zfs_umount(vfs_t *vfsp, int fflag, cred_t *cr) 2128fa9e4066Sahrens { 2129fa9e4066Sahrens zfsvfs_t *zfsvfs = vfsp->vfs_data; 2130f18faf3fSek objset_t *os; 2131fa9e4066Sahrens int ret; 2132fa9e4066Sahrens 2133ecd6cf80Smarks ret = secpolicy_fs_unmount(cr, vfsp); 2134ecd6cf80Smarks if (ret) { 213598679b56SMark Shellenbaum if (dsl_deleg_access((char *)refstr_value(vfsp->vfs_resource), 213698679b56SMark Shellenbaum ZFS_DELEG_PERM_MOUNT, cr)) 2137ecd6cf80Smarks return (ret); 2138ecd6cf80Smarks } 2139033f9833Sek 2140ed097989Sek /* 2141ed097989Sek * We purge the parent filesystem's vfsp as the parent filesystem 2142ed097989Sek * and all of its snapshots have their vnode's v_vfsp set to the 2143ed097989Sek * parent's filesystem's vfsp. Note, 'z_parent' is self 2144ed097989Sek * referential for non-snapshots. 2145ed097989Sek */ 2146ed097989Sek (void) dnlc_purge_vfsp(zfsvfs->z_parent->z_vfs, 0); 2147033f9833Sek 2148fa9e4066Sahrens /* 2149fa9e4066Sahrens * Unmount any snapshots mounted under .zfs before unmounting the 2150fa9e4066Sahrens * dataset itself. 2151fa9e4066Sahrens */ 2152fa9e4066Sahrens if (zfsvfs->z_ctldir != NULL && 2153ecd6cf80Smarks (ret = zfsctl_umount_snapshots(vfsp, fflag, cr)) != 0) { 2154fa9e4066Sahrens return (ret); 2155ecd6cf80Smarks } 2156fa9e4066Sahrens 215791ebeef5Sahrens if (!(fflag & MS_FORCE)) { 2158fa9e4066Sahrens /* 215991ebeef5Sahrens * Check the number of active vnodes in the file system. 216091ebeef5Sahrens * Our count is maintained in the vfs structure, but the 216191ebeef5Sahrens * number is off by 1 to indicate a hold on the vfs 216291ebeef5Sahrens * structure itself. 216391ebeef5Sahrens * 216491ebeef5Sahrens * The '.zfs' directory maintains a reference of its 216591ebeef5Sahrens * own, and any active references underneath are 216691ebeef5Sahrens * reflected in the vnode count. 2167fa9e4066Sahrens */ 216891ebeef5Sahrens if (zfsvfs->z_ctldir == NULL) { 216991ebeef5Sahrens if (vfsp->vfs_count > 1) 2170be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 217191ebeef5Sahrens } else { 217291ebeef5Sahrens if (vfsp->vfs_count > 2 || 2173f18faf3fSek zfsvfs->z_ctldir->v_count > 1) 2174be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 2175fa9e4066Sahrens } 217691ebeef5Sahrens } 2177fa9e4066Sahrens 217891ebeef5Sahrens vfsp->vfs_flag |= VFS_UNMOUNTED; 217991ebeef5Sahrens 2180f18faf3fSek VERIFY(zfsvfs_teardown(zfsvfs, B_TRUE) == 0); 2181f18faf3fSek os = zfsvfs->z_os; 218291ebeef5Sahrens 218391ebeef5Sahrens /* 2184f18faf3fSek * z_os will be NULL if there was an error in 2185f18faf3fSek * attempting to reopen zfsvfs. 218691ebeef5Sahrens */ 2187f18faf3fSek if (os != NULL) { 2188f18faf3fSek /* 2189f18faf3fSek * Unset the objset user_ptr. 2190f18faf3fSek */ 2191503ad85cSMatthew Ahrens mutex_enter(&os->os_user_ptr_lock); 2192f18faf3fSek dmu_objset_set_user(os, NULL); 2193503ad85cSMatthew Ahrens mutex_exit(&os->os_user_ptr_lock); 219491ebeef5Sahrens 2195f18faf3fSek /* 2196745cd3c5Smaybee * Finally release the objset 2197f18faf3fSek */ 2198eb633035STom Caputi dmu_objset_disown(os, B_TRUE, zfsvfs); 219991ebeef5Sahrens } 220091ebeef5Sahrens 220191ebeef5Sahrens /* 220291ebeef5Sahrens * We can now safely destroy the '.zfs' directory node. 220391ebeef5Sahrens */ 220491ebeef5Sahrens if (zfsvfs->z_ctldir != NULL) 220591ebeef5Sahrens zfsctl_destroy(zfsvfs); 2206fa9e4066Sahrens 2207fa9e4066Sahrens return (0); 2208fa9e4066Sahrens } 2209fa9e4066Sahrens 2210fa9e4066Sahrens static int 2211fa9e4066Sahrens zfs_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp) 2212fa9e4066Sahrens { 2213fa9e4066Sahrens zfsvfs_t *zfsvfs = vfsp->vfs_data; 2214fa9e4066Sahrens znode_t *zp; 2215fa9e4066Sahrens uint64_t object = 0; 2216fa9e4066Sahrens uint64_t fid_gen = 0; 2217fa9e4066Sahrens uint64_t gen_mask; 2218fa9e4066Sahrens uint64_t zp_gen; 2219fa9e4066Sahrens int i, err; 2220fa9e4066Sahrens 2221fa9e4066Sahrens *vpp = NULL; 2222fa9e4066Sahrens 2223fa9e4066Sahrens ZFS_ENTER(zfsvfs); 2224fa9e4066Sahrens 2225fa9e4066Sahrens if (fidp->fid_len == LONG_FID_LEN) { 2226fa9e4066Sahrens zfid_long_t *zlfid = (zfid_long_t *)fidp; 2227fa9e4066Sahrens uint64_t objsetid = 0; 2228fa9e4066Sahrens uint64_t setgen = 0; 2229fa9e4066Sahrens 2230fa9e4066Sahrens for (i = 0; i < sizeof (zlfid->zf_setid); i++) 2231fa9e4066Sahrens objsetid |= ((uint64_t)zlfid->zf_setid[i]) << (8 * i); 2232fa9e4066Sahrens 2233fa9e4066Sahrens for (i = 0; i < sizeof (zlfid->zf_setgen); i++) 2234fa9e4066Sahrens setgen |= ((uint64_t)zlfid->zf_setgen[i]) << (8 * i); 2235fa9e4066Sahrens 2236fa9e4066Sahrens ZFS_EXIT(zfsvfs); 2237fa9e4066Sahrens 2238fa9e4066Sahrens err = zfsctl_lookup_objset(vfsp, objsetid, &zfsvfs); 2239fa9e4066Sahrens if (err) 2240be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 2241fa9e4066Sahrens ZFS_ENTER(zfsvfs); 2242fa9e4066Sahrens } 2243fa9e4066Sahrens 2244fa9e4066Sahrens if (fidp->fid_len == SHORT_FID_LEN || fidp->fid_len == LONG_FID_LEN) { 2245fa9e4066Sahrens zfid_short_t *zfid = (zfid_short_t *)fidp; 2246fa9e4066Sahrens 2247fa9e4066Sahrens for (i = 0; i < sizeof (zfid->zf_object); i++) 2248fa9e4066Sahrens object |= ((uint64_t)zfid->zf_object[i]) << (8 * i); 2249fa9e4066Sahrens 2250fa9e4066Sahrens for (i = 0; i < sizeof (zfid->zf_gen); i++) 2251fa9e4066Sahrens fid_gen |= ((uint64_t)zfid->zf_gen[i]) << (8 * i); 2252fa9e4066Sahrens } else { 2253fa9e4066Sahrens ZFS_EXIT(zfsvfs); 2254be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 2255fa9e4066Sahrens } 2256fa9e4066Sahrens 2257fa9e4066Sahrens /* A zero fid_gen means we are in the .zfs control directories */ 2258fa9e4066Sahrens if (fid_gen == 0 && 2259fa9e4066Sahrens (object == ZFSCTL_INO_ROOT || object == ZFSCTL_INO_SNAPDIR)) { 2260fa9e4066Sahrens *vpp = zfsvfs->z_ctldir; 2261fa9e4066Sahrens ASSERT(*vpp != NULL); 2262fa9e4066Sahrens if (object == ZFSCTL_INO_SNAPDIR) { 2263fa9e4066Sahrens VERIFY(zfsctl_root_lookup(*vpp, "snapshot", vpp, NULL, 2264da6c28aaSamw 0, NULL, NULL, NULL, NULL, NULL) == 0); 2265fa9e4066Sahrens } else { 2266fa9e4066Sahrens VN_HOLD(*vpp); 2267fa9e4066Sahrens } 2268fa9e4066Sahrens ZFS_EXIT(zfsvfs); 2269fa9e4066Sahrens return (0); 2270fa9e4066Sahrens } 2271fa9e4066Sahrens 2272fa9e4066Sahrens gen_mask = -1ULL >> (64 - 8 * i); 2273fa9e4066Sahrens 2274fa9e4066Sahrens dprintf("getting %llu [%u mask %llx]\n", object, fid_gen, gen_mask); 2275fa9e4066Sahrens if (err = zfs_zget(zfsvfs, object, &zp)) { 2276fa9e4066Sahrens ZFS_EXIT(zfsvfs); 2277fa9e4066Sahrens return (err); 2278fa9e4066Sahrens } 22790a586ceaSMark Shellenbaum (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_GEN(zfsvfs), &zp_gen, 22800a586ceaSMark Shellenbaum sizeof (uint64_t)); 22810a586ceaSMark Shellenbaum zp_gen = zp_gen & gen_mask; 2282fa9e4066Sahrens if (zp_gen == 0) 2283fa9e4066Sahrens zp_gen = 1; 2284893a6d32Sahrens if (zp->z_unlinked || zp_gen != fid_gen) { 2285fa9e4066Sahrens dprintf("znode gen (%u) != fid gen (%u)\n", zp_gen, fid_gen); 2286fa9e4066Sahrens VN_RELE(ZTOV(zp)); 2287fa9e4066Sahrens ZFS_EXIT(zfsvfs); 2288be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 2289fa9e4066Sahrens } 2290fa9e4066Sahrens 2291fa9e4066Sahrens *vpp = ZTOV(zp); 2292fa9e4066Sahrens ZFS_EXIT(zfsvfs); 2293fa9e4066Sahrens return (0); 2294fa9e4066Sahrens } 2295fa9e4066Sahrens 2296f18faf3fSek /* 2297f18faf3fSek * Block out VOPs and close zfsvfs_t::z_os 2298f18faf3fSek * 2299f18faf3fSek * Note, if successful, then we return with the 'z_teardown_lock' and 230091948b51SKeith M Wesolowski * 'z_teardown_inactive_lock' write held. We leave ownership of the underlying 230191948b51SKeith M Wesolowski * dataset and objset intact so that they can be atomically handed off during 230291948b51SKeith M Wesolowski * a subsequent rollback or recv operation and the resume thereafter. 2303f18faf3fSek */ 2304f18faf3fSek int 2305503ad85cSMatthew Ahrens zfs_suspend_fs(zfsvfs_t *zfsvfs) 2306f18faf3fSek { 2307f18faf3fSek int error; 2308f18faf3fSek 2309f18faf3fSek if ((error = zfsvfs_teardown(zfsvfs, B_FALSE)) != 0) 2310f18faf3fSek return (error); 2311f18faf3fSek 2312f18faf3fSek return (0); 2313f18faf3fSek } 2314f18faf3fSek 2315f18faf3fSek /* 231691948b51SKeith M Wesolowski * Rebuild SA and release VOPs. Note that ownership of the underlying dataset 231791948b51SKeith M Wesolowski * is an invariant across any of the operations that can be performed while the 231891948b51SKeith M Wesolowski * filesystem was suspended. Whether it succeeded or failed, the preconditions 231991948b51SKeith M Wesolowski * are the same: the relevant objset and associated dataset are owned by 232091948b51SKeith M Wesolowski * zfsvfs, held, and long held on entry. 2321f18faf3fSek */ 2322f18faf3fSek int 2323690041b9SAndriy Gapon zfs_resume_fs(zfsvfs_t *zfsvfs, dsl_dataset_t *ds) 2324f18faf3fSek { 232544bffe01SMark Shellenbaum int err; 232691948b51SKeith M Wesolowski znode_t *zp; 2327f18faf3fSek 2328c9030f6cSAlexander Motin ASSERT(RRM_WRITE_HELD(&zfsvfs->z_teardown_lock)); 2329f18faf3fSek ASSERT(RW_WRITE_HELD(&zfsvfs->z_teardown_inactive_lock)); 2330f18faf3fSek 233191948b51SKeith M Wesolowski /* 2332690041b9SAndriy Gapon * We already own this, so just update the objset_t, as the one we 2333690041b9SAndriy Gapon * had before may have been evicted. 233491948b51SKeith M Wesolowski */ 23351fdcbd00SMatthew Ahrens objset_t *os; 2336690041b9SAndriy Gapon VERIFY3P(ds->ds_owner, ==, zfsvfs); 2337690041b9SAndriy Gapon VERIFY(dsl_dataset_long_held(ds)); 2338690041b9SAndriy Gapon VERIFY0(dmu_objset_from_ds(ds, &os)); 23390a586ceaSMark Shellenbaum 23401fdcbd00SMatthew Ahrens err = zfsvfs_init(zfsvfs, os); 23411fdcbd00SMatthew Ahrens if (err != 0) 234291948b51SKeith M Wesolowski goto bail; 2343f18faf3fSek 234491948b51SKeith M Wesolowski VERIFY(zfsvfs_setup(zfsvfs, B_FALSE) == 0); 2345f18faf3fSek 234691948b51SKeith M Wesolowski zfs_set_fuid_feature(zfsvfs); 234744bffe01SMark Shellenbaum 234891948b51SKeith M Wesolowski /* 234991948b51SKeith M Wesolowski * Attempt to re-establish all the active znodes with 235091948b51SKeith M Wesolowski * their dbufs. If a zfs_rezget() fails, then we'll let 235191948b51SKeith M Wesolowski * any potential callers discover that via ZFS_ENTER_VERIFY_VP 235291948b51SKeith M Wesolowski * when they try to use their znode. 235391948b51SKeith M Wesolowski */ 235491948b51SKeith M Wesolowski mutex_enter(&zfsvfs->z_znodes_lock); 235591948b51SKeith M Wesolowski for (zp = list_head(&zfsvfs->z_all_znodes); zp; 235691948b51SKeith M Wesolowski zp = list_next(&zfsvfs->z_all_znodes, zp)) { 235791948b51SKeith M Wesolowski (void) zfs_rezget(zp); 2358f18faf3fSek } 235991948b51SKeith M Wesolowski mutex_exit(&zfsvfs->z_znodes_lock); 2360f18faf3fSek 23610a586ceaSMark Shellenbaum bail: 2362f18faf3fSek /* release the VOPs */ 2363f18faf3fSek rw_exit(&zfsvfs->z_teardown_inactive_lock); 2364c9030f6cSAlexander Motin rrm_exit(&zfsvfs->z_teardown_lock, FTAG); 2365f18faf3fSek 2366f18faf3fSek if (err) { 2367f18faf3fSek /* 236891948b51SKeith M Wesolowski * Since we couldn't setup the sa framework, try to force 236991948b51SKeith M Wesolowski * unmount this file system. 2370f18faf3fSek */ 2371f18faf3fSek if (vn_vfswlock(zfsvfs->z_vfs->vfs_vnodecovered) == 0) 2372f18faf3fSek (void) dounmount(zfsvfs->z_vfs, MS_FORCE, CRED()); 2373f18faf3fSek } 2374f18faf3fSek return (err); 2375f18faf3fSek } 2376f18faf3fSek 2377fa9e4066Sahrens static void 2378fa9e4066Sahrens zfs_freevfs(vfs_t *vfsp) 2379fa9e4066Sahrens { 2380fa9e4066Sahrens zfsvfs_t *zfsvfs = vfsp->vfs_data; 2381142ae85dSChris Kirby 2382142ae85dSChris Kirby /* 2383142ae85dSChris Kirby * If this is a snapshot, we have an extra VFS_HOLD on our parent 2384f80ce222SChris Kirby * from zfs_mount(). Release it here. If we came through 2385f80ce222SChris Kirby * zfs_mountroot() instead, we didn't grab an extra hold, so 2386f80ce222SChris Kirby * skip the VFS_RELE for rootvfs. 2387142ae85dSChris Kirby */ 2388f80ce222SChris Kirby if (zfsvfs->z_issnap && (vfsp != rootvfs)) 2389142ae85dSChris Kirby VFS_RELE(zfsvfs->z_parent->z_vfs); 2390142ae85dSChris Kirby 239114843421SMatthew Ahrens zfsvfs_free(zfsvfs); 2392fa9e4066Sahrens 23931a5e258fSJosef 'Jeff' Sipek atomic_dec_32(&zfs_active_fs_count); 2394fa9e4066Sahrens } 2395fa9e4066Sahrens 2396fa9e4066Sahrens /* 2397fa9e4066Sahrens * VFS_INIT() initialization. Note that there is no VFS_FINI(), 2398fa9e4066Sahrens * so we can't safely do any non-idempotent initialization here. 2399fa9e4066Sahrens * Leave that to zfs_init() and zfs_fini(), which are called 2400fa9e4066Sahrens * from the module's _init() and _fini() entry points. 2401fa9e4066Sahrens */ 2402fa9e4066Sahrens /*ARGSUSED*/ 2403fa9e4066Sahrens static int 2404fa9e4066Sahrens zfs_vfsinit(int fstype, char *name) 2405fa9e4066Sahrens { 2406fa9e4066Sahrens int error; 2407fa9e4066Sahrens 2408fa9e4066Sahrens zfsfstype = fstype; 2409fa9e4066Sahrens 2410fa9e4066Sahrens /* 2411fa9e4066Sahrens * Setup vfsops and vnodeops tables. 2412fa9e4066Sahrens */ 2413fa9e4066Sahrens error = vfs_setfsops(fstype, zfs_vfsops_template, &zfs_vfsops); 2414fa9e4066Sahrens if (error != 0) { 2415fa9e4066Sahrens cmn_err(CE_WARN, "zfs: bad vfs ops template"); 2416fa9e4066Sahrens } 2417fa9e4066Sahrens 2418fa9e4066Sahrens error = zfs_create_op_tables(); 2419fa9e4066Sahrens if (error) { 2420fa9e4066Sahrens zfs_remove_op_tables(); 2421fa9e4066Sahrens cmn_err(CE_WARN, "zfs: bad vnode ops template"); 2422fa9e4066Sahrens (void) vfs_freevfsops_by_type(zfsfstype); 2423fa9e4066Sahrens return (error); 2424fa9e4066Sahrens } 2425fa9e4066Sahrens 2426fa9e4066Sahrens mutex_init(&zfs_dev_mtx, NULL, MUTEX_DEFAULT, NULL); 2427fa9e4066Sahrens 2428fa9e4066Sahrens /* 2429a0965f35Sbonwick * Unique major number for all zfs mounts. 2430a0965f35Sbonwick * If we run out of 32-bit minors, we'll getudev() another major. 2431fa9e4066Sahrens */ 2432a0965f35Sbonwick zfs_major = ddi_name_to_major(ZFS_DRIVER); 2433a0965f35Sbonwick zfs_minor = ZFS_MIN_MINOR; 2434fa9e4066Sahrens 2435fa9e4066Sahrens return (0); 2436fa9e4066Sahrens } 2437fa9e4066Sahrens 2438fa9e4066Sahrens void 2439fa9e4066Sahrens zfs_init(void) 2440fa9e4066Sahrens { 2441fa9e4066Sahrens /* 2442fa9e4066Sahrens * Initialize .zfs directory structures 2443fa9e4066Sahrens */ 2444fa9e4066Sahrens zfsctl_init(); 2445fa9e4066Sahrens 2446fa9e4066Sahrens /* 2447fa9e4066Sahrens * Initialize znode cache, vnode ops, etc... 2448fa9e4066Sahrens */ 2449fa9e4066Sahrens zfs_znode_init(); 245014843421SMatthew Ahrens 245114843421SMatthew Ahrens dmu_objset_register_type(DMU_OST_ZFS, zfs_space_delta_cb); 2452fa9e4066Sahrens } 2453fa9e4066Sahrens 2454fa9e4066Sahrens void 2455fa9e4066Sahrens zfs_fini(void) 2456fa9e4066Sahrens { 2457fa9e4066Sahrens zfsctl_fini(); 2458fa9e4066Sahrens zfs_znode_fini(); 2459fa9e4066Sahrens } 2460fa9e4066Sahrens 2461fa9e4066Sahrens int 2462fa9e4066Sahrens zfs_busy(void) 2463fa9e4066Sahrens { 2464fa9e4066Sahrens return (zfs_active_fs_count != 0); 2465fa9e4066Sahrens } 2466fa9e4066Sahrens 2467e7437265Sahrens int 246814843421SMatthew Ahrens zfs_set_version(zfsvfs_t *zfsvfs, uint64_t newvers) 2469e7437265Sahrens { 2470e7437265Sahrens int error; 247114843421SMatthew Ahrens objset_t *os = zfsvfs->z_os; 2472e7437265Sahrens dmu_tx_t *tx; 2473e7437265Sahrens 2474e7437265Sahrens if (newvers < ZPL_VERSION_INITIAL || newvers > ZPL_VERSION) 2475be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 2476e7437265Sahrens 247714843421SMatthew Ahrens if (newvers < zfsvfs->z_version) 2478be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 2479e7437265Sahrens 24800a586ceaSMark Shellenbaum if (zfs_spa_version_map(newvers) > 24810a586ceaSMark Shellenbaum spa_version(dmu_objset_spa(zfsvfs->z_os))) 2482be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 24830a586ceaSMark Shellenbaum 2484e7437265Sahrens tx = dmu_tx_create(os); 248514843421SMatthew Ahrens dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, B_FALSE, ZPL_VERSION_STR); 24860a586ceaSMark Shellenbaum if (newvers >= ZPL_VERSION_SA && !zfsvfs->z_use_sa) { 24870a586ceaSMark Shellenbaum dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, B_TRUE, 24880a586ceaSMark Shellenbaum ZFS_SA_ATTRS); 24890a586ceaSMark Shellenbaum dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL); 24900a586ceaSMark Shellenbaum } 2491e7437265Sahrens error = dmu_tx_assign(tx, TXG_WAIT); 2492e7437265Sahrens if (error) { 2493e7437265Sahrens dmu_tx_abort(tx); 249414843421SMatthew Ahrens return (error); 249514843421SMatthew Ahrens } 24960a586ceaSMark Shellenbaum 249714843421SMatthew Ahrens error = zap_update(os, MASTER_NODE_OBJ, ZPL_VERSION_STR, 249814843421SMatthew Ahrens 8, 1, &newvers, tx); 249914843421SMatthew Ahrens 250014843421SMatthew Ahrens if (error) { 250114843421SMatthew Ahrens dmu_tx_commit(tx); 250214843421SMatthew Ahrens return (error); 2503e7437265Sahrens } 2504e7437265Sahrens 25050a586ceaSMark Shellenbaum if (newvers >= ZPL_VERSION_SA && !zfsvfs->z_use_sa) { 25060a586ceaSMark Shellenbaum uint64_t sa_obj; 25070a586ceaSMark Shellenbaum 25080a586ceaSMark Shellenbaum ASSERT3U(spa_version(dmu_objset_spa(zfsvfs->z_os)), >=, 25090a586ceaSMark Shellenbaum SPA_VERSION_SA); 25100a586ceaSMark Shellenbaum sa_obj = zap_create(os, DMU_OT_SA_MASTER_NODE, 25110a586ceaSMark Shellenbaum DMU_OT_NONE, 0, tx); 25120a586ceaSMark Shellenbaum 25130a586ceaSMark Shellenbaum error = zap_add(os, MASTER_NODE_OBJ, 25140a586ceaSMark Shellenbaum ZFS_SA_ATTRS, 8, 1, &sa_obj, tx); 2515fb09f5aaSMadhav Suresh ASSERT0(error); 25160a586ceaSMark Shellenbaum 25170a586ceaSMark Shellenbaum VERIFY(0 == sa_set_sa_object(os, sa_obj)); 25180a586ceaSMark Shellenbaum sa_register_update_callback(os, zfs_sa_upgrade); 25190a586ceaSMark Shellenbaum } 25200a586ceaSMark Shellenbaum 25214445fffbSMatthew Ahrens spa_history_log_internal_ds(dmu_objset_ds(os), "upgrade", tx, 25224445fffbSMatthew Ahrens "from %llu to %llu", zfsvfs->z_version, newvers); 252314843421SMatthew Ahrens 2524e7437265Sahrens dmu_tx_commit(tx); 2525e7437265Sahrens 252614843421SMatthew Ahrens zfsvfs->z_version = newvers; 2527adb52d92SMatthew Ahrens os->os_version = newvers; 252814843421SMatthew Ahrens 252944bffe01SMark Shellenbaum zfs_set_fuid_feature(zfsvfs); 253014843421SMatthew Ahrens 253114843421SMatthew Ahrens return (0); 2532e7437265Sahrens } 2533e7437265Sahrens 2534de8267e0Stimh /* 2535de8267e0Stimh * Read a property stored within the master node. 2536de8267e0Stimh */ 2537de8267e0Stimh int 2538de8267e0Stimh zfs_get_zplprop(objset_t *os, zfs_prop_t prop, uint64_t *value) 2539de8267e0Stimh { 2540adb52d92SMatthew Ahrens uint64_t *cached_copy = NULL; 2541de8267e0Stimh 2542de8267e0Stimh /* 2543adb52d92SMatthew Ahrens * Figure out where in the objset_t the cached copy would live, if it 2544adb52d92SMatthew Ahrens * is available for the requested property. 2545de8267e0Stimh */ 2546adb52d92SMatthew Ahrens if (os != NULL) { 2547adb52d92SMatthew Ahrens switch (prop) { 2548adb52d92SMatthew Ahrens case ZFS_PROP_VERSION: 2549adb52d92SMatthew Ahrens cached_copy = &os->os_version; 2550adb52d92SMatthew Ahrens break; 2551adb52d92SMatthew Ahrens case ZFS_PROP_NORMALIZE: 2552adb52d92SMatthew Ahrens cached_copy = &os->os_normalization; 2553adb52d92SMatthew Ahrens break; 2554adb52d92SMatthew Ahrens case ZFS_PROP_UTF8ONLY: 2555adb52d92SMatthew Ahrens cached_copy = &os->os_utf8only; 2556adb52d92SMatthew Ahrens break; 2557adb52d92SMatthew Ahrens case ZFS_PROP_CASE: 2558adb52d92SMatthew Ahrens cached_copy = &os->os_casesensitivity; 2559adb52d92SMatthew Ahrens break; 2560adb52d92SMatthew Ahrens default: 2561adb52d92SMatthew Ahrens break; 2562adb52d92SMatthew Ahrens } 2563adb52d92SMatthew Ahrens } 2564adb52d92SMatthew Ahrens if (cached_copy != NULL && *cached_copy != OBJSET_PROP_UNINITIALIZED) { 2565adb52d92SMatthew Ahrens *value = *cached_copy; 2566adb52d92SMatthew Ahrens return (0); 2567adb52d92SMatthew Ahrens } 2568adb52d92SMatthew Ahrens 2569adb52d92SMatthew Ahrens /* 2570adb52d92SMatthew Ahrens * If the property wasn't cached, look up the file system's value for 2571adb52d92SMatthew Ahrens * the property. For the version property, we look up a slightly 2572adb52d92SMatthew Ahrens * different string. 2573adb52d92SMatthew Ahrens */ 2574adb52d92SMatthew Ahrens const char *pname; 2575adb52d92SMatthew Ahrens int error = ENOENT; 2576adb52d92SMatthew Ahrens if (prop == ZFS_PROP_VERSION) { 2577de8267e0Stimh pname = ZPL_VERSION_STR; 2578adb52d92SMatthew Ahrens } else { 2579de8267e0Stimh pname = zfs_prop_to_name(prop); 2580adb52d92SMatthew Ahrens } 2581de8267e0Stimh 2582b127fe3cSAndriy Gapon if (os != NULL) { 2583b127fe3cSAndriy Gapon ASSERT3U(os->os_phys->os_type, ==, DMU_OST_ZFS); 25840a48a24eStimh error = zap_lookup(os, MASTER_NODE_OBJ, pname, 8, 1, value); 2585b127fe3cSAndriy Gapon } 2586de8267e0Stimh 2587aa60ed0eSmaybee if (error == ENOENT) { 2588de8267e0Stimh /* No value set, use the default value */ 2589de8267e0Stimh switch (prop) { 2590aa60ed0eSmaybee case ZFS_PROP_VERSION: 2591aa60ed0eSmaybee *value = ZPL_VERSION; 2592aa60ed0eSmaybee break; 2593de8267e0Stimh case ZFS_PROP_NORMALIZE: 2594de8267e0Stimh case ZFS_PROP_UTF8ONLY: 2595de8267e0Stimh *value = 0; 2596de8267e0Stimh break; 2597de8267e0Stimh case ZFS_PROP_CASE: 2598de8267e0Stimh *value = ZFS_CASE_SENSITIVE; 2599de8267e0Stimh break; 2600de8267e0Stimh default: 2601aa60ed0eSmaybee return (error); 2602de8267e0Stimh } 2603aa60ed0eSmaybee error = 0; 2604de8267e0Stimh } 2605adb52d92SMatthew Ahrens 2606adb52d92SMatthew Ahrens /* 2607adb52d92SMatthew Ahrens * If one of the methods for getting the property value above worked, 2608adb52d92SMatthew Ahrens * copy it into the objset_t's cache. 2609adb52d92SMatthew Ahrens */ 2610adb52d92SMatthew Ahrens if (error == 0 && cached_copy != NULL) { 2611adb52d92SMatthew Ahrens *cached_copy = *value; 2612adb52d92SMatthew Ahrens } 2613adb52d92SMatthew Ahrens 2614aa60ed0eSmaybee return (error); 2615de8267e0Stimh } 2616de8267e0Stimh 2617eb721827SAlek Pinchuk /* 2618eb721827SAlek Pinchuk * Return true if the coresponding vfs's unmounted flag is set. 2619eb721827SAlek Pinchuk * Otherwise return false. 2620eb721827SAlek Pinchuk * If this function returns true we know VFS unmount has been initiated. 2621eb721827SAlek Pinchuk */ 2622eb721827SAlek Pinchuk boolean_t 2623eb721827SAlek Pinchuk zfs_get_vfs_flag_unmounted(objset_t *os) 2624eb721827SAlek Pinchuk { 2625eb721827SAlek Pinchuk zfsvfs_t *zfvp; 2626eb721827SAlek Pinchuk boolean_t unmounted = B_FALSE; 2627eb721827SAlek Pinchuk 2628eb721827SAlek Pinchuk ASSERT(dmu_objset_type(os) == DMU_OST_ZFS); 2629eb721827SAlek Pinchuk 2630eb721827SAlek Pinchuk mutex_enter(&os->os_user_ptr_lock); 2631eb721827SAlek Pinchuk zfvp = dmu_objset_get_user(os); 2632eb721827SAlek Pinchuk if (zfvp != NULL && zfvp->z_vfs != NULL && 2633eb721827SAlek Pinchuk (zfvp->z_vfs->vfs_flag & VFS_UNMOUNTED)) 2634eb721827SAlek Pinchuk unmounted = B_TRUE; 2635eb721827SAlek Pinchuk mutex_exit(&os->os_user_ptr_lock); 2636eb721827SAlek Pinchuk 2637eb721827SAlek Pinchuk return (unmounted); 2638eb721827SAlek Pinchuk } 2639eb721827SAlek Pinchuk 2640fa9e4066Sahrens static vfsdef_t vfw = { 2641fa9e4066Sahrens VFSDEF_VERSION, 2642fa9e4066Sahrens MNTTYPE_ZFS, 2643fa9e4066Sahrens zfs_vfsinit, 2644da6c28aaSamw VSW_HASPROTO|VSW_CANRWRO|VSW_CANREMOUNT|VSW_VOLATILEDEV|VSW_STATS| 26450fbb751dSJohn Levon VSW_XID|VSW_ZMOUNT, 2646fa9e4066Sahrens &zfs_mntopts 2647fa9e4066Sahrens }; 2648fa9e4066Sahrens 2649fa9e4066Sahrens struct modlfs zfs_modlfs = { 2650e7437265Sahrens &mod_fsops, "ZFS filesystem version " SPA_VERSION_STRING, &vfw 2651fa9e4066Sahrens }; 2652