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. 26f67950b2SNasf-Fan * Copyright 2019 Joyent, Inc. 2730c304d9SJoshua M. Clulow * Copyright 2020 Joshua M. Clulow <josh@sysmgr.org> 28*b39b008fSAndy Fiddaman * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. 29fa9e4066Sahrens */ 30fa9e4066Sahrens 3155da60b9SMark J Musante /* Portions Copyright 2010 Robert Milkowski */ 3255da60b9SMark J Musante 33fa9e4066Sahrens #include <sys/types.h> 34fa9e4066Sahrens #include <sys/param.h> 35fa9e4066Sahrens #include <sys/systm.h> 36fa9e4066Sahrens #include <sys/sysmacros.h> 37fa9e4066Sahrens #include <sys/kmem.h> 38fa9e4066Sahrens #include <sys/pathname.h> 39fa9e4066Sahrens #include <sys/vnode.h> 40fa9e4066Sahrens #include <sys/vfs.h> 41aa59c4cbSrsb #include <sys/vfs_opreg.h> 42fa9e4066Sahrens #include <sys/mntent.h> 43fa9e4066Sahrens #include <sys/mount.h> 44fa9e4066Sahrens #include <sys/cmn_err.h> 45fa9e4066Sahrens #include "fs/fs_subr.h" 46fa9e4066Sahrens #include <sys/zfs_znode.h> 47893a6d32Sahrens #include <sys/zfs_dir.h> 48fa9e4066Sahrens #include <sys/zil.h> 49fa9e4066Sahrens #include <sys/fs/zfs.h> 50fa9e4066Sahrens #include <sys/dmu.h> 51fa9e4066Sahrens #include <sys/dsl_prop.h> 52b1b8ab34Slling #include <sys/dsl_dataset.h> 53ecd6cf80Smarks #include <sys/dsl_deleg.h> 54fa9e4066Sahrens #include <sys/spa.h> 55fa9e4066Sahrens #include <sys/zap.h> 560a586ceaSMark Shellenbaum #include <sys/sa.h> 57e828a46dSMatthew Ahrens #include <sys/sa_impl.h> 58fa9e4066Sahrens #include <sys/varargs.h> 59fa9e4066Sahrens #include <sys/policy.h> 60fa9e4066Sahrens #include <sys/atomic.h> 61fa9e4066Sahrens #include <sys/mkdev.h> 62fa9e4066Sahrens #include <sys/modctl.h> 63ecd6cf80Smarks #include <sys/refstr.h> 64fa9e4066Sahrens #include <sys/zfs_ioctl.h> 65fa9e4066Sahrens #include <sys/zfs_ctldir.h> 66da6c28aaSamw #include <sys/zfs_fuid.h> 67ea8dc4b6Seschrock #include <sys/bootconf.h> 6830c304d9SJoshua M. Clulow #include <sys/ddi.h> 69a0965f35Sbonwick #include <sys/sunddi.h> 70033f9833Sek #include <sys/dnlc.h> 71f18faf3fSek #include <sys/dmu_objset.h> 72e7cbe64fSgw #include <sys/spa_boot.h> 7330c304d9SJoshua M. Clulow #include <sys/vdev_impl.h> 740a586ceaSMark Shellenbaum #include "zfs_comutil.h" 75fa9e4066Sahrens 76fa9e4066Sahrens int zfsfstype; 77fa9e4066Sahrens vfsops_t *zfs_vfsops = NULL; 78a0965f35Sbonwick static major_t zfs_major; 79fa9e4066Sahrens static minor_t zfs_minor; 80fa9e4066Sahrens static kmutex_t zfs_dev_mtx; 81fa9e4066Sahrens 8254d692b7SGeorge Wilson extern int sys_shutdown; 8354d692b7SGeorge Wilson 84fa9e4066Sahrens static int zfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr); 85fa9e4066Sahrens static int zfs_umount(vfs_t *vfsp, int fflag, cred_t *cr); 86ea8dc4b6Seschrock static int zfs_mountroot(vfs_t *vfsp, enum whymountroot); 87fa9e4066Sahrens static int zfs_root(vfs_t *vfsp, vnode_t **vpp); 88fa9e4066Sahrens static int zfs_statvfs(vfs_t *vfsp, struct statvfs64 *statp); 89fa9e4066Sahrens static int zfs_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp); 90fa9e4066Sahrens static void zfs_freevfs(vfs_t *vfsp); 91fa9e4066Sahrens 92fa9e4066Sahrens static const fs_operation_def_t zfs_vfsops_template[] = { 93aa59c4cbSrsb VFSNAME_MOUNT, { .vfs_mount = zfs_mount }, 94aa59c4cbSrsb VFSNAME_MOUNTROOT, { .vfs_mountroot = zfs_mountroot }, 95aa59c4cbSrsb VFSNAME_UNMOUNT, { .vfs_unmount = zfs_umount }, 96aa59c4cbSrsb VFSNAME_ROOT, { .vfs_root = zfs_root }, 97aa59c4cbSrsb VFSNAME_STATVFS, { .vfs_statvfs = zfs_statvfs }, 98aa59c4cbSrsb VFSNAME_SYNC, { .vfs_sync = zfs_sync }, 99aa59c4cbSrsb VFSNAME_VGET, { .vfs_vget = zfs_vget }, 100aa59c4cbSrsb VFSNAME_FREEVFS, { .vfs_freevfs = zfs_freevfs }, 101aa59c4cbSrsb NULL, NULL 102fa9e4066Sahrens }; 103fa9e4066Sahrens 104fa9e4066Sahrens /* 105fa9e4066Sahrens * We need to keep a count of active fs's. 106fa9e4066Sahrens * This is necessary to prevent our module 107fa9e4066Sahrens * from being unloaded after a umount -f 108fa9e4066Sahrens */ 109fa9e4066Sahrens static uint32_t zfs_active_fs_count = 0; 110fa9e4066Sahrens 111fa9e4066Sahrens static char *noatime_cancel[] = { MNTOPT_ATIME, NULL }; 112fa9e4066Sahrens static char *atime_cancel[] = { MNTOPT_NOATIME, NULL }; 1137b55fa8eSck static char *noxattr_cancel[] = { MNTOPT_XATTR, NULL }; 1147b55fa8eSck static char *xattr_cancel[] = { MNTOPT_NOXATTR, NULL }; 115fa9e4066Sahrens 1167b55fa8eSck /* 117b510d378Slling * MO_DEFAULT is not used since the default value is determined 118b510d378Slling * by the equivalent property. 1197b55fa8eSck */ 120fa9e4066Sahrens static mntopt_t mntopts[] = { 1217b55fa8eSck { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, NULL }, 1227b55fa8eSck { MNTOPT_XATTR, xattr_cancel, NULL, 0, NULL }, 123b510d378Slling { MNTOPT_NOATIME, noatime_cancel, NULL, 0, NULL }, 124fa9e4066Sahrens { MNTOPT_ATIME, atime_cancel, NULL, 0, NULL } 125fa9e4066Sahrens }; 126fa9e4066Sahrens 127fa9e4066Sahrens static mntopts_t zfs_mntopts = { 128fa9e4066Sahrens sizeof (mntopts) / sizeof (mntopt_t), 129fa9e4066Sahrens mntopts 130fa9e4066Sahrens }; 131fa9e4066Sahrens 132fa9e4066Sahrens /*ARGSUSED*/ 133fa9e4066Sahrens int 134fa9e4066Sahrens zfs_sync(vfs_t *vfsp, short flag, cred_t *cr) 135fa9e4066Sahrens { 136fa9e4066Sahrens /* 137fa9e4066Sahrens * Data integrity is job one. We don't want a compromised kernel 138fa9e4066Sahrens * writing to the storage pool, so we never sync during panic. 139fa9e4066Sahrens */ 140fa9e4066Sahrens if (panicstr) 141fa9e4066Sahrens return (0); 142fa9e4066Sahrens 143fa9e4066Sahrens /* 144fa9e4066Sahrens * SYNC_ATTR is used by fsflush() to force old filesystems like UFS 145fa9e4066Sahrens * to sync metadata, which they would otherwise cache indefinitely. 146fa9e4066Sahrens * Semantically, the only requirement is that the sync be initiated. 147fa9e4066Sahrens * The DMU syncs out txgs frequently, so there's nothing to do. 148fa9e4066Sahrens */ 149fa9e4066Sahrens if (flag & SYNC_ATTR) 150fa9e4066Sahrens return (0); 151fa9e4066Sahrens 152fa9e4066Sahrens if (vfsp != NULL) { 153fa9e4066Sahrens /* 154fa9e4066Sahrens * Sync a specific filesystem. 155fa9e4066Sahrens */ 156fa9e4066Sahrens zfsvfs_t *zfsvfs = vfsp->vfs_data; 15754d692b7SGeorge Wilson dsl_pool_t *dp; 158fa9e4066Sahrens 159fa9e4066Sahrens ZFS_ENTER(zfsvfs); 16054d692b7SGeorge Wilson dp = dmu_objset_pool(zfsvfs->z_os); 16154d692b7SGeorge Wilson 16254d692b7SGeorge Wilson /* 16354d692b7SGeorge Wilson * If the system is shutting down, then skip any 16454d692b7SGeorge Wilson * filesystems which may exist on a suspended pool. 16554d692b7SGeorge Wilson */ 16654d692b7SGeorge Wilson if (sys_shutdown && spa_suspended(dp->dp_spa)) { 16754d692b7SGeorge Wilson ZFS_EXIT(zfsvfs); 16854d692b7SGeorge Wilson return (0); 16954d692b7SGeorge Wilson } 17054d692b7SGeorge Wilson 171fa9e4066Sahrens if (zfsvfs->z_log != NULL) 1725002558fSNeil Perrin zil_commit(zfsvfs->z_log, 0); 17355da60b9SMark J Musante 174fa9e4066Sahrens ZFS_EXIT(zfsvfs); 175fa9e4066Sahrens } else { 176fa9e4066Sahrens /* 177fa9e4066Sahrens * Sync all ZFS filesystems. This is what happens when you 178fa9e4066Sahrens * run sync(1M). Unlike other filesystems, ZFS honors the 179fa9e4066Sahrens * request by waiting for all pools to commit all dirty data. 180fa9e4066Sahrens */ 181fa9e4066Sahrens spa_sync_allpools(); 182fa9e4066Sahrens } 183fa9e4066Sahrens 184fa9e4066Sahrens return (0); 185fa9e4066Sahrens } 186fa9e4066Sahrens 187ea8dc4b6Seschrock static int 188ea8dc4b6Seschrock zfs_create_unique_device(dev_t *dev) 189ea8dc4b6Seschrock { 190ea8dc4b6Seschrock major_t new_major; 191ea8dc4b6Seschrock 192ea8dc4b6Seschrock do { 193ea8dc4b6Seschrock ASSERT3U(zfs_minor, <=, MAXMIN32); 194ea8dc4b6Seschrock minor_t start = zfs_minor; 195ea8dc4b6Seschrock do { 196ea8dc4b6Seschrock mutex_enter(&zfs_dev_mtx); 197ea8dc4b6Seschrock if (zfs_minor >= MAXMIN32) { 198ea8dc4b6Seschrock /* 199ea8dc4b6Seschrock * If we're still using the real major 200ea8dc4b6Seschrock * keep out of /dev/zfs and /dev/zvol minor 201ea8dc4b6Seschrock * number space. If we're using a getudev()'ed 202ea8dc4b6Seschrock * major number, we can use all of its minors. 203ea8dc4b6Seschrock */ 204ea8dc4b6Seschrock if (zfs_major == ddi_name_to_major(ZFS_DRIVER)) 205ea8dc4b6Seschrock zfs_minor = ZFS_MIN_MINOR; 206ea8dc4b6Seschrock else 207ea8dc4b6Seschrock zfs_minor = 0; 208ea8dc4b6Seschrock } else { 209ea8dc4b6Seschrock zfs_minor++; 210ea8dc4b6Seschrock } 211ea8dc4b6Seschrock *dev = makedevice(zfs_major, zfs_minor); 212ea8dc4b6Seschrock mutex_exit(&zfs_dev_mtx); 213ea8dc4b6Seschrock } while (vfs_devismounted(*dev) && zfs_minor != start); 214ea8dc4b6Seschrock if (zfs_minor == start) { 215ea8dc4b6Seschrock /* 216ea8dc4b6Seschrock * We are using all ~262,000 minor numbers for the 217ea8dc4b6Seschrock * current major number. Create a new major number. 218ea8dc4b6Seschrock */ 219ea8dc4b6Seschrock if ((new_major = getudev()) == (major_t)-1) { 220ea8dc4b6Seschrock cmn_err(CE_WARN, 221ea8dc4b6Seschrock "zfs_mount: Can't get unique major " 222ea8dc4b6Seschrock "device number."); 223ea8dc4b6Seschrock return (-1); 224ea8dc4b6Seschrock } 225ea8dc4b6Seschrock mutex_enter(&zfs_dev_mtx); 226ea8dc4b6Seschrock zfs_major = new_major; 227ea8dc4b6Seschrock zfs_minor = 0; 228ea8dc4b6Seschrock 229ea8dc4b6Seschrock mutex_exit(&zfs_dev_mtx); 230ea8dc4b6Seschrock } else { 231ea8dc4b6Seschrock break; 232ea8dc4b6Seschrock } 233ea8dc4b6Seschrock /* CONSTANTCONDITION */ 234ea8dc4b6Seschrock } while (1); 235ea8dc4b6Seschrock 236ea8dc4b6Seschrock return (0); 237ea8dc4b6Seschrock } 238ea8dc4b6Seschrock 239fa9e4066Sahrens static void 240fa9e4066Sahrens atime_changed_cb(void *arg, uint64_t newval) 241fa9e4066Sahrens { 242fa9e4066Sahrens zfsvfs_t *zfsvfs = arg; 243fa9e4066Sahrens 244fa9e4066Sahrens if (newval == TRUE) { 245fa9e4066Sahrens zfsvfs->z_atime = TRUE; 246fa9e4066Sahrens vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_NOATIME); 247fa9e4066Sahrens vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_ATIME, NULL, 0); 248fa9e4066Sahrens } else { 249fa9e4066Sahrens zfsvfs->z_atime = FALSE; 250fa9e4066Sahrens vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_ATIME); 251fa9e4066Sahrens vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_NOATIME, NULL, 0); 252fa9e4066Sahrens } 253fa9e4066Sahrens } 254fa9e4066Sahrens 2557b55fa8eSck static void 2567b55fa8eSck xattr_changed_cb(void *arg, uint64_t newval) 2577b55fa8eSck { 2587b55fa8eSck zfsvfs_t *zfsvfs = arg; 2597b55fa8eSck 2607b55fa8eSck if (newval == TRUE) { 2617b55fa8eSck /* XXX locking on vfs_flag? */ 2627b55fa8eSck zfsvfs->z_vfs->vfs_flag |= VFS_XATTR; 2637b55fa8eSck vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_NOXATTR); 2647b55fa8eSck vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_XATTR, NULL, 0); 2657b55fa8eSck } else { 2667b55fa8eSck /* XXX locking on vfs_flag? */ 2677b55fa8eSck zfsvfs->z_vfs->vfs_flag &= ~VFS_XATTR; 2687b55fa8eSck vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_XATTR); 2697b55fa8eSck vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_NOXATTR, NULL, 0); 2707b55fa8eSck } 2717b55fa8eSck } 2727b55fa8eSck 273fa9e4066Sahrens static void 274fa9e4066Sahrens blksz_changed_cb(void *arg, uint64_t newval) 275fa9e4066Sahrens { 276fa9e4066Sahrens zfsvfs_t *zfsvfs = arg; 277b5152584SMatthew Ahrens ASSERT3U(newval, <=, spa_maxblocksize(dmu_objset_spa(zfsvfs->z_os))); 278b5152584SMatthew Ahrens ASSERT3U(newval, >=, SPA_MINBLOCKSIZE); 279b5152584SMatthew Ahrens ASSERT(ISP2(newval)); 280fa9e4066Sahrens 281fa9e4066Sahrens zfsvfs->z_max_blksz = newval; 282fa9e4066Sahrens zfsvfs->z_vfs->vfs_bsize = newval; 283fa9e4066Sahrens } 284fa9e4066Sahrens 285fa9e4066Sahrens static void 286fa9e4066Sahrens readonly_changed_cb(void *arg, uint64_t newval) 287fa9e4066Sahrens { 288fa9e4066Sahrens zfsvfs_t *zfsvfs = arg; 289fa9e4066Sahrens 290fa9e4066Sahrens if (newval) { 291fa9e4066Sahrens /* XXX locking on vfs_flag? */ 292fa9e4066Sahrens zfsvfs->z_vfs->vfs_flag |= VFS_RDONLY; 293fa9e4066Sahrens vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_RW); 294fa9e4066Sahrens vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_RO, NULL, 0); 295fa9e4066Sahrens } else { 296fa9e4066Sahrens /* XXX locking on vfs_flag? */ 297fa9e4066Sahrens zfsvfs->z_vfs->vfs_flag &= ~VFS_RDONLY; 298fa9e4066Sahrens vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_RO); 299fa9e4066Sahrens vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_RW, NULL, 0); 300fa9e4066Sahrens } 301fa9e4066Sahrens } 302fa9e4066Sahrens 303fa9e4066Sahrens static void 304fa9e4066Sahrens devices_changed_cb(void *arg, uint64_t newval) 305fa9e4066Sahrens { 306fa9e4066Sahrens zfsvfs_t *zfsvfs = arg; 307fa9e4066Sahrens 308fa9e4066Sahrens if (newval == FALSE) { 309fa9e4066Sahrens zfsvfs->z_vfs->vfs_flag |= VFS_NODEVICES; 310fa9e4066Sahrens vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_DEVICES); 311fa9e4066Sahrens vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_NODEVICES, NULL, 0); 312fa9e4066Sahrens } else { 313fa9e4066Sahrens zfsvfs->z_vfs->vfs_flag &= ~VFS_NODEVICES; 314fa9e4066Sahrens vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_NODEVICES); 315fa9e4066Sahrens vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_DEVICES, NULL, 0); 316fa9e4066Sahrens } 317fa9e4066Sahrens } 318fa9e4066Sahrens 319fa9e4066Sahrens static void 320fa9e4066Sahrens setuid_changed_cb(void *arg, uint64_t newval) 321fa9e4066Sahrens { 322fa9e4066Sahrens zfsvfs_t *zfsvfs = arg; 323fa9e4066Sahrens 324fa9e4066Sahrens if (newval == FALSE) { 325fa9e4066Sahrens zfsvfs->z_vfs->vfs_flag |= VFS_NOSETUID; 326fa9e4066Sahrens vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_SETUID); 327fa9e4066Sahrens vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_NOSETUID, NULL, 0); 328fa9e4066Sahrens } else { 329fa9e4066Sahrens zfsvfs->z_vfs->vfs_flag &= ~VFS_NOSETUID; 330fa9e4066Sahrens vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_NOSETUID); 331fa9e4066Sahrens vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_SETUID, NULL, 0); 332fa9e4066Sahrens } 333fa9e4066Sahrens } 334fa9e4066Sahrens 335fa9e4066Sahrens static void 336fa9e4066Sahrens exec_changed_cb(void *arg, uint64_t newval) 337fa9e4066Sahrens { 338fa9e4066Sahrens zfsvfs_t *zfsvfs = arg; 339fa9e4066Sahrens 340fa9e4066Sahrens if (newval == FALSE) { 341fa9e4066Sahrens zfsvfs->z_vfs->vfs_flag |= VFS_NOEXEC; 342fa9e4066Sahrens vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_EXEC); 343fa9e4066Sahrens vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_NOEXEC, NULL, 0); 344fa9e4066Sahrens } else { 345fa9e4066Sahrens zfsvfs->z_vfs->vfs_flag &= ~VFS_NOEXEC; 346fa9e4066Sahrens vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_NOEXEC); 347fa9e4066Sahrens vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_EXEC, NULL, 0); 348fa9e4066Sahrens } 349fa9e4066Sahrens } 350fa9e4066Sahrens 351da6c28aaSamw /* 352da6c28aaSamw * The nbmand mount option can be changed at mount time. 353da6c28aaSamw * We can't allow it to be toggled on live file systems or incorrect 354da6c28aaSamw * behavior may be seen from cifs clients 355da6c28aaSamw * 356da6c28aaSamw * This property isn't registered via dsl_prop_register(), but this callback 357da6c28aaSamw * will be called when a file system is first mounted 358da6c28aaSamw */ 359da6c28aaSamw static void 360da6c28aaSamw nbmand_changed_cb(void *arg, uint64_t newval) 361da6c28aaSamw { 362da6c28aaSamw zfsvfs_t *zfsvfs = arg; 363da6c28aaSamw if (newval == FALSE) { 364da6c28aaSamw vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_NBMAND); 365da6c28aaSamw vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_NONBMAND, NULL, 0); 366da6c28aaSamw } else { 367da6c28aaSamw vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_NONBMAND); 368da6c28aaSamw vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_NBMAND, NULL, 0); 369da6c28aaSamw } 370da6c28aaSamw } 371da6c28aaSamw 372fa9e4066Sahrens static void 373fa9e4066Sahrens snapdir_changed_cb(void *arg, uint64_t newval) 374fa9e4066Sahrens { 375fa9e4066Sahrens zfsvfs_t *zfsvfs = arg; 376fa9e4066Sahrens 377fa9e4066Sahrens zfsvfs->z_show_ctldir = newval; 378fa9e4066Sahrens } 379fa9e4066Sahrens 380da6c28aaSamw static void 381da6c28aaSamw vscan_changed_cb(void *arg, uint64_t newval) 382da6c28aaSamw { 383da6c28aaSamw zfsvfs_t *zfsvfs = arg; 384da6c28aaSamw 385da6c28aaSamw zfsvfs->z_vscan = newval; 386da6c28aaSamw } 387da6c28aaSamw 388a3c49ce1SAlbert Lee static void 389a3c49ce1SAlbert Lee acl_mode_changed_cb(void *arg, uint64_t newval) 390a3c49ce1SAlbert Lee { 391a3c49ce1SAlbert Lee zfsvfs_t *zfsvfs = arg; 392a3c49ce1SAlbert Lee 393a3c49ce1SAlbert Lee zfsvfs->z_acl_mode = newval; 394a3c49ce1SAlbert Lee } 395a3c49ce1SAlbert Lee 396fa9e4066Sahrens static void 397fa9e4066Sahrens acl_inherit_changed_cb(void *arg, uint64_t newval) 398fa9e4066Sahrens { 399fa9e4066Sahrens zfsvfs_t *zfsvfs = arg; 400fa9e4066Sahrens 401fa9e4066Sahrens zfsvfs->z_acl_inherit = newval; 402fa9e4066Sahrens } 403fa9e4066Sahrens 404ea8dc4b6Seschrock static int 405ea8dc4b6Seschrock zfs_register_callbacks(vfs_t *vfsp) 406ea8dc4b6Seschrock { 407ea8dc4b6Seschrock struct dsl_dataset *ds = NULL; 408ea8dc4b6Seschrock objset_t *os = NULL; 409ea8dc4b6Seschrock zfsvfs_t *zfsvfs = NULL; 410da6c28aaSamw uint64_t nbmand; 411d5285caeSGeorge Wilson boolean_t readonly = B_FALSE; 412d5285caeSGeorge Wilson boolean_t do_readonly = B_FALSE; 413d5285caeSGeorge Wilson boolean_t setuid = B_FALSE; 414d5285caeSGeorge Wilson boolean_t do_setuid = B_FALSE; 415d5285caeSGeorge Wilson boolean_t exec = B_FALSE; 416d5285caeSGeorge Wilson boolean_t do_exec = B_FALSE; 417d5285caeSGeorge Wilson boolean_t devices = B_FALSE; 418d5285caeSGeorge Wilson boolean_t do_devices = B_FALSE; 419d5285caeSGeorge Wilson boolean_t xattr = B_FALSE; 420d5285caeSGeorge Wilson boolean_t do_xattr = B_FALSE; 421d5285caeSGeorge Wilson boolean_t atime = B_FALSE; 422d5285caeSGeorge Wilson boolean_t do_atime = B_FALSE; 423ea8dc4b6Seschrock int error = 0; 424ea8dc4b6Seschrock 425ea8dc4b6Seschrock ASSERT(vfsp); 426ea8dc4b6Seschrock zfsvfs = vfsp->vfs_data; 427ea8dc4b6Seschrock ASSERT(zfsvfs); 428ea8dc4b6Seschrock os = zfsvfs->z_os; 429fa9e4066Sahrens 430fa9e4066Sahrens /* 431ea8dc4b6Seschrock * The act of registering our callbacks will destroy any mount 432ea8dc4b6Seschrock * options we may have. In order to enable temporary overrides 4337b55fa8eSck * of mount options, we stash away the current values and 434ea8dc4b6Seschrock * restore them after we register the callbacks. 435fa9e4066Sahrens */ 436f9af39baSGeorge Wilson if (vfs_optionisset(vfsp, MNTOPT_RO, NULL) || 437f9af39baSGeorge Wilson !spa_writeable(dmu_objset_spa(os))) { 438ea8dc4b6Seschrock readonly = B_TRUE; 439ea8dc4b6Seschrock do_readonly = B_TRUE; 440ea8dc4b6Seschrock } else if (vfs_optionisset(vfsp, MNTOPT_RW, NULL)) { 441ea8dc4b6Seschrock readonly = B_FALSE; 442ea8dc4b6Seschrock do_readonly = B_TRUE; 443ea8dc4b6Seschrock } 444ea8dc4b6Seschrock if (vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL)) { 445ea8dc4b6Seschrock devices = B_FALSE; 446ea8dc4b6Seschrock setuid = B_FALSE; 447ea8dc4b6Seschrock do_devices = B_TRUE; 448ea8dc4b6Seschrock do_setuid = B_TRUE; 449ea8dc4b6Seschrock } else { 450ea8dc4b6Seschrock if (vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL)) { 451ea8dc4b6Seschrock devices = B_FALSE; 452ea8dc4b6Seschrock do_devices = B_TRUE; 453b1b8ab34Slling } else if (vfs_optionisset(vfsp, MNTOPT_DEVICES, NULL)) { 454ea8dc4b6Seschrock devices = B_TRUE; 455ea8dc4b6Seschrock do_devices = B_TRUE; 456fa9e4066Sahrens } 457fa9e4066Sahrens 458ea8dc4b6Seschrock if (vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL)) { 459ea8dc4b6Seschrock setuid = B_FALSE; 460ea8dc4b6Seschrock do_setuid = B_TRUE; 461ea8dc4b6Seschrock } else if (vfs_optionisset(vfsp, MNTOPT_SETUID, NULL)) { 462ea8dc4b6Seschrock setuid = B_TRUE; 463ea8dc4b6Seschrock do_setuid = B_TRUE; 464fa9e4066Sahrens } 465ea8dc4b6Seschrock } 466ea8dc4b6Seschrock if (vfs_optionisset(vfsp, MNTOPT_NOEXEC, NULL)) { 467ea8dc4b6Seschrock exec = B_FALSE; 468ea8dc4b6Seschrock do_exec = B_TRUE; 469ea8dc4b6Seschrock } else if (vfs_optionisset(vfsp, MNTOPT_EXEC, NULL)) { 470ea8dc4b6Seschrock exec = B_TRUE; 471ea8dc4b6Seschrock do_exec = B_TRUE; 472fa9e4066Sahrens } 4737b55fa8eSck if (vfs_optionisset(vfsp, MNTOPT_NOXATTR, NULL)) { 4747b55fa8eSck xattr = B_FALSE; 4757b55fa8eSck do_xattr = B_TRUE; 4767b55fa8eSck } else if (vfs_optionisset(vfsp, MNTOPT_XATTR, NULL)) { 4777b55fa8eSck xattr = B_TRUE; 4787b55fa8eSck do_xattr = B_TRUE; 4797b55fa8eSck } 480b510d378Slling if (vfs_optionisset(vfsp, MNTOPT_NOATIME, NULL)) { 481b510d378Slling atime = B_FALSE; 482b510d378Slling do_atime = B_TRUE; 483b510d378Slling } else if (vfs_optionisset(vfsp, MNTOPT_ATIME, NULL)) { 484b510d378Slling atime = B_TRUE; 485b510d378Slling do_atime = B_TRUE; 486b510d378Slling } 487fa9e4066Sahrens 488da6c28aaSamw /* 489da6c28aaSamw * nbmand is a special property. It can only be changed at 490da6c28aaSamw * mount time. 491da6c28aaSamw * 492da6c28aaSamw * This is weird, but it is documented to only be changeable 493da6c28aaSamw * at mount time. 494da6c28aaSamw */ 495da6c28aaSamw if (vfs_optionisset(vfsp, MNTOPT_NONBMAND, NULL)) { 496da6c28aaSamw nbmand = B_FALSE; 497da6c28aaSamw } else if (vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL)) { 498da6c28aaSamw nbmand = B_TRUE; 499da6c28aaSamw } else { 5009adfa60dSMatthew Ahrens char osname[ZFS_MAX_DATASET_NAME_LEN]; 501da6c28aaSamw 502da6c28aaSamw dmu_objset_name(os, osname); 503da6c28aaSamw if (error = dsl_prop_get_integer(osname, "nbmand", &nbmand, 504bb0ade09Sahrens NULL)) { 505bb0ade09Sahrens return (error); 506bb0ade09Sahrens } 507da6c28aaSamw } 508da6c28aaSamw 509fa9e4066Sahrens /* 510ea8dc4b6Seschrock * Register property callbacks. 511ea8dc4b6Seschrock * 512ea8dc4b6Seschrock * It would probably be fine to just check for i/o error from 513ea8dc4b6Seschrock * the first prop_register(), but I guess I like to go 514ea8dc4b6Seschrock * overboard... 515fa9e4066Sahrens */ 516ea8dc4b6Seschrock ds = dmu_objset_ds(os); 5173b2aab18SMatthew Ahrens dsl_pool_config_enter(dmu_objset_pool(os), FTAG); 5183b2aab18SMatthew Ahrens error = dsl_prop_register(ds, 5193b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_ATIME), atime_changed_cb, zfsvfs); 5207b55fa8eSck error = error ? error : dsl_prop_register(ds, 5213b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_XATTR), xattr_changed_cb, zfsvfs); 522ea8dc4b6Seschrock error = error ? error : dsl_prop_register(ds, 5233b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_RECORDSIZE), blksz_changed_cb, zfsvfs); 524ea8dc4b6Seschrock error = error ? error : dsl_prop_register(ds, 5253b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_READONLY), readonly_changed_cb, zfsvfs); 526ea8dc4b6Seschrock error = error ? error : dsl_prop_register(ds, 5273b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_DEVICES), devices_changed_cb, zfsvfs); 528ea8dc4b6Seschrock error = error ? error : dsl_prop_register(ds, 5293b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_SETUID), setuid_changed_cb, zfsvfs); 530ea8dc4b6Seschrock error = error ? error : dsl_prop_register(ds, 5313b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_EXEC), exec_changed_cb, zfsvfs); 532ea8dc4b6Seschrock error = error ? error : dsl_prop_register(ds, 5333b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_SNAPDIR), snapdir_changed_cb, zfsvfs); 534a3c49ce1SAlbert Lee error = error ? error : dsl_prop_register(ds, 5353b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_ACLMODE), acl_mode_changed_cb, zfsvfs); 536ea8dc4b6Seschrock error = error ? error : dsl_prop_register(ds, 5373b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_ACLINHERIT), acl_inherit_changed_cb, 5383b2aab18SMatthew Ahrens zfsvfs); 539da6c28aaSamw error = error ? error : dsl_prop_register(ds, 5403b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_VSCAN), vscan_changed_cb, zfsvfs); 5413b2aab18SMatthew Ahrens dsl_pool_config_exit(dmu_objset_pool(os), FTAG); 542ea8dc4b6Seschrock if (error) 543ea8dc4b6Seschrock goto unregister; 544fa9e4066Sahrens 545ea8dc4b6Seschrock /* 546ea8dc4b6Seschrock * Invoke our callbacks to restore temporary mount options. 547ea8dc4b6Seschrock */ 548ea8dc4b6Seschrock if (do_readonly) 549ea8dc4b6Seschrock readonly_changed_cb(zfsvfs, readonly); 550ea8dc4b6Seschrock if (do_setuid) 551ea8dc4b6Seschrock setuid_changed_cb(zfsvfs, setuid); 552ea8dc4b6Seschrock if (do_exec) 553ea8dc4b6Seschrock exec_changed_cb(zfsvfs, exec); 554ea8dc4b6Seschrock if (do_devices) 555ea8dc4b6Seschrock devices_changed_cb(zfsvfs, devices); 5567b55fa8eSck if (do_xattr) 5577b55fa8eSck xattr_changed_cb(zfsvfs, xattr); 558b510d378Slling if (do_atime) 559b510d378Slling atime_changed_cb(zfsvfs, atime); 560fa9e4066Sahrens 561da6c28aaSamw nbmand_changed_cb(zfsvfs, nbmand); 562da6c28aaSamw 563ea8dc4b6Seschrock return (0); 564fa9e4066Sahrens 565ea8dc4b6Seschrock unregister: 56603bad06fSJustin Gibbs dsl_prop_unregister_all(ds, zfsvfs); 567ea8dc4b6Seschrock return (error); 568ea8dc4b6Seschrock } 569ea8dc4b6Seschrock 5709966ca11SMatthew Ahrens static int 5710a586ceaSMark Shellenbaum zfs_space_delta_cb(dmu_object_type_t bonustype, void *data, 572f67950b2SNasf-Fan uint64_t *userp, uint64_t *groupp, uint64_t *projectp) 57314843421SMatthew Ahrens { 574f67950b2SNasf-Fan sa_hdr_phys_t sa; 575f67950b2SNasf-Fan sa_hdr_phys_t *sap = data; 576f67950b2SNasf-Fan uint64_t flags; 577f67950b2SNasf-Fan int hdrsize; 578f67950b2SNasf-Fan boolean_t swap = B_FALSE; 579f67950b2SNasf-Fan 58006e0070dSMark Shellenbaum /* 58106e0070dSMark Shellenbaum * Is it a valid type of object to track? 58206e0070dSMark Shellenbaum */ 5830a586ceaSMark Shellenbaum if (bonustype != DMU_OT_ZNODE && bonustype != DMU_OT_SA) 584be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 58514843421SMatthew Ahrens 58606e0070dSMark Shellenbaum /* 58706e0070dSMark Shellenbaum * If we have a NULL data pointer 58806e0070dSMark Shellenbaum * then assume the id's aren't changing and 58906e0070dSMark Shellenbaum * return EEXIST to the dmu to let it know to 59006e0070dSMark Shellenbaum * use the same ids 59106e0070dSMark Shellenbaum */ 59206e0070dSMark Shellenbaum if (data == NULL) 593be6fd75aSMatthew Ahrens return (SET_ERROR(EEXIST)); 59406e0070dSMark Shellenbaum 5950a586ceaSMark Shellenbaum if (bonustype == DMU_OT_ZNODE) { 596e828a46dSMatthew Ahrens znode_phys_t *znp = data; 5970a586ceaSMark Shellenbaum *userp = znp->zp_uid; 5980a586ceaSMark Shellenbaum *groupp = znp->zp_gid; 599f67950b2SNasf-Fan *projectp = ZFS_DEFAULT_PROJID; 600f67950b2SNasf-Fan return (0); 601f67950b2SNasf-Fan } 602f67950b2SNasf-Fan 603f67950b2SNasf-Fan if (sap->sa_magic == 0) { 604f67950b2SNasf-Fan /* 605f67950b2SNasf-Fan * This should only happen for newly created files 606f67950b2SNasf-Fan * that haven't had the znode data filled in yet. 607f67950b2SNasf-Fan */ 608f67950b2SNasf-Fan *userp = 0; 609f67950b2SNasf-Fan *groupp = 0; 610f67950b2SNasf-Fan *projectp = ZFS_DEFAULT_PROJID; 611f67950b2SNasf-Fan return (0); 612f67950b2SNasf-Fan } 613f67950b2SNasf-Fan 614f67950b2SNasf-Fan sa = *sap; 615f67950b2SNasf-Fan if (sa.sa_magic == BSWAP_32(SA_MAGIC)) { 616f67950b2SNasf-Fan sa.sa_magic = SA_MAGIC; 617f67950b2SNasf-Fan sa.sa_layout_info = BSWAP_16(sa.sa_layout_info); 618f67950b2SNasf-Fan swap = B_TRUE; 6190a586ceaSMark Shellenbaum } else { 620f67950b2SNasf-Fan VERIFY3U(sa.sa_magic, ==, SA_MAGIC); 621f67950b2SNasf-Fan } 6220a586ceaSMark Shellenbaum 623f67950b2SNasf-Fan hdrsize = sa_hdrsize(&sa); 624f67950b2SNasf-Fan VERIFY3U(hdrsize, >=, sizeof (sa_hdr_phys_t)); 6250a586ceaSMark Shellenbaum 626f67950b2SNasf-Fan *userp = *((uint64_t *)((uintptr_t)data + hdrsize + SA_UID_OFFSET)); 627f67950b2SNasf-Fan *groupp = *((uint64_t *)((uintptr_t)data + hdrsize + SA_GID_OFFSET)); 628f67950b2SNasf-Fan flags = *((uint64_t *)((uintptr_t)data + hdrsize + SA_FLAGS_OFFSET)); 629f67950b2SNasf-Fan if (swap) 630f67950b2SNasf-Fan flags = BSWAP_64(flags); 631e828a46dSMatthew Ahrens 632f67950b2SNasf-Fan if (flags & ZFS_PROJID) 633f67950b2SNasf-Fan *projectp = *((uint64_t *)((uintptr_t)data + hdrsize + 634f67950b2SNasf-Fan SA_PROJID_OFFSET)); 635f67950b2SNasf-Fan else 636f67950b2SNasf-Fan *projectp = ZFS_DEFAULT_PROJID; 637f67950b2SNasf-Fan 638f67950b2SNasf-Fan if (swap) { 639f67950b2SNasf-Fan *userp = BSWAP_64(*userp); 640f67950b2SNasf-Fan *groupp = BSWAP_64(*groupp); 641f67950b2SNasf-Fan *projectp = BSWAP_64(*projectp); 6420a586ceaSMark Shellenbaum } 6433b2aab18SMatthew Ahrens return (0); 64414843421SMatthew Ahrens } 64514843421SMatthew Ahrens 64614843421SMatthew Ahrens static void 64714843421SMatthew Ahrens fuidstr_to_sid(zfsvfs_t *zfsvfs, const char *fuidstr, 64814843421SMatthew Ahrens char *domainbuf, int buflen, uid_t *ridp) 64914843421SMatthew Ahrens { 65014843421SMatthew Ahrens uint64_t fuid; 65114843421SMatthew Ahrens const char *domain; 65214843421SMatthew Ahrens 6534585130bSYuri Pankov fuid = zfs_strtonum(fuidstr, NULL); 65414843421SMatthew Ahrens 65514843421SMatthew Ahrens domain = zfs_fuid_find_by_idx(zfsvfs, FUID_INDEX(fuid)); 65614843421SMatthew Ahrens if (domain) 65714843421SMatthew Ahrens (void) strlcpy(domainbuf, domain, buflen); 65814843421SMatthew Ahrens else 65914843421SMatthew Ahrens domainbuf[0] = '\0'; 66014843421SMatthew Ahrens *ridp = FUID_RID(fuid); 66114843421SMatthew Ahrens } 66214843421SMatthew Ahrens 66314843421SMatthew Ahrens static uint64_t 66414843421SMatthew Ahrens zfs_userquota_prop_to_obj(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type) 66514843421SMatthew Ahrens { 66614843421SMatthew Ahrens switch (type) { 66714843421SMatthew Ahrens case ZFS_PROP_USERUSED: 668f67950b2SNasf-Fan case ZFS_PROP_USEROBJUSED: 66914843421SMatthew Ahrens return (DMU_USERUSED_OBJECT); 67014843421SMatthew Ahrens case ZFS_PROP_GROUPUSED: 671f67950b2SNasf-Fan case ZFS_PROP_GROUPOBJUSED: 67214843421SMatthew Ahrens return (DMU_GROUPUSED_OBJECT); 673f67950b2SNasf-Fan case ZFS_PROP_PROJECTUSED: 674f67950b2SNasf-Fan case ZFS_PROP_PROJECTOBJUSED: 675f67950b2SNasf-Fan return (DMU_PROJECTUSED_OBJECT); 67614843421SMatthew Ahrens case ZFS_PROP_USERQUOTA: 67714843421SMatthew Ahrens return (zfsvfs->z_userquota_obj); 67814843421SMatthew Ahrens case ZFS_PROP_GROUPQUOTA: 67914843421SMatthew Ahrens return (zfsvfs->z_groupquota_obj); 680f67950b2SNasf-Fan case ZFS_PROP_USEROBJQUOTA: 681f67950b2SNasf-Fan return (zfsvfs->z_userobjquota_obj); 682f67950b2SNasf-Fan case ZFS_PROP_GROUPOBJQUOTA: 683f67950b2SNasf-Fan return (zfsvfs->z_groupobjquota_obj); 684f67950b2SNasf-Fan case ZFS_PROP_PROJECTQUOTA: 685f67950b2SNasf-Fan return (zfsvfs->z_projectquota_obj); 686f67950b2SNasf-Fan case ZFS_PROP_PROJECTOBJQUOTA: 687f67950b2SNasf-Fan return (zfsvfs->z_projectobjquota_obj); 688f67950b2SNasf-Fan default: 689f67950b2SNasf-Fan return (ZFS_NO_OBJECT); 69014843421SMatthew Ahrens } 69114843421SMatthew Ahrens } 69214843421SMatthew Ahrens 69314843421SMatthew Ahrens int 69414843421SMatthew Ahrens zfs_userspace_many(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type, 69514843421SMatthew Ahrens uint64_t *cookiep, void *vbuf, uint64_t *bufsizep) 69614843421SMatthew Ahrens { 69714843421SMatthew Ahrens int error; 69814843421SMatthew Ahrens zap_cursor_t zc; 69914843421SMatthew Ahrens zap_attribute_t za; 70014843421SMatthew Ahrens zfs_useracct_t *buf = vbuf; 70114843421SMatthew Ahrens uint64_t obj; 702f67950b2SNasf-Fan int offset = 0; 70314843421SMatthew Ahrens 70414843421SMatthew Ahrens if (!dmu_objset_userspace_present(zfsvfs->z_os)) 705be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 70614843421SMatthew Ahrens 707f67950b2SNasf-Fan if ((type == ZFS_PROP_PROJECTQUOTA || type == ZFS_PROP_PROJECTUSED || 708f67950b2SNasf-Fan type == ZFS_PROP_PROJECTOBJQUOTA || 709f67950b2SNasf-Fan type == ZFS_PROP_PROJECTOBJUSED) && 710f67950b2SNasf-Fan !dmu_objset_projectquota_present(zfsvfs->z_os)) 711f67950b2SNasf-Fan return (SET_ERROR(ENOTSUP)); 712f67950b2SNasf-Fan 713f67950b2SNasf-Fan if ((type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED || 714f67950b2SNasf-Fan type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA || 715f67950b2SNasf-Fan type == ZFS_PROP_PROJECTOBJUSED || 716f67950b2SNasf-Fan type == ZFS_PROP_PROJECTOBJQUOTA) && 717f67950b2SNasf-Fan !dmu_objset_userobjspace_present(zfsvfs->z_os)) 718f67950b2SNasf-Fan return (SET_ERROR(ENOTSUP)); 719f67950b2SNasf-Fan 72014843421SMatthew Ahrens obj = zfs_userquota_prop_to_obj(zfsvfs, type); 721f67950b2SNasf-Fan if (obj == ZFS_NO_OBJECT) { 72214843421SMatthew Ahrens *bufsizep = 0; 72314843421SMatthew Ahrens return (0); 72414843421SMatthew Ahrens } 72514843421SMatthew Ahrens 726f67950b2SNasf-Fan if (type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED || 727f67950b2SNasf-Fan type == ZFS_PROP_PROJECTOBJUSED) 728f67950b2SNasf-Fan offset = DMU_OBJACCT_PREFIX_LEN; 729f67950b2SNasf-Fan 73014843421SMatthew Ahrens for (zap_cursor_init_serialized(&zc, zfsvfs->z_os, obj, *cookiep); 73114843421SMatthew Ahrens (error = zap_cursor_retrieve(&zc, &za)) == 0; 73214843421SMatthew Ahrens zap_cursor_advance(&zc)) { 73314843421SMatthew Ahrens if ((uintptr_t)buf - (uintptr_t)vbuf + sizeof (zfs_useracct_t) > 73414843421SMatthew Ahrens *bufsizep) 73514843421SMatthew Ahrens break; 73614843421SMatthew Ahrens 737f67950b2SNasf-Fan /* 738f67950b2SNasf-Fan * skip object quota (with zap name prefix DMU_OBJACCT_PREFIX) 739f67950b2SNasf-Fan * when dealing with block quota and vice versa. 740f67950b2SNasf-Fan */ 741f67950b2SNasf-Fan if ((offset > 0) != (strncmp(za.za_name, DMU_OBJACCT_PREFIX, 742f67950b2SNasf-Fan DMU_OBJACCT_PREFIX_LEN) == 0)) 743f67950b2SNasf-Fan continue; 744f67950b2SNasf-Fan 745f67950b2SNasf-Fan fuidstr_to_sid(zfsvfs, za.za_name + offset, 74614843421SMatthew Ahrens buf->zu_domain, sizeof (buf->zu_domain), &buf->zu_rid); 74714843421SMatthew Ahrens 74814843421SMatthew Ahrens buf->zu_space = za.za_first_integer; 74914843421SMatthew Ahrens buf++; 75014843421SMatthew Ahrens } 75114843421SMatthew Ahrens if (error == ENOENT) 75214843421SMatthew Ahrens error = 0; 75314843421SMatthew Ahrens 75414843421SMatthew Ahrens ASSERT3U((uintptr_t)buf - (uintptr_t)vbuf, <=, *bufsizep); 75514843421SMatthew Ahrens *bufsizep = (uintptr_t)buf - (uintptr_t)vbuf; 75614843421SMatthew Ahrens *cookiep = zap_cursor_serialize(&zc); 75714843421SMatthew Ahrens zap_cursor_fini(&zc); 75814843421SMatthew Ahrens return (error); 75914843421SMatthew Ahrens } 76014843421SMatthew Ahrens 76114843421SMatthew Ahrens /* 76214843421SMatthew Ahrens * buf must be big enough (eg, 32 bytes) 76314843421SMatthew Ahrens */ 76414843421SMatthew Ahrens static int 76514843421SMatthew Ahrens id_to_fuidstr(zfsvfs_t *zfsvfs, const char *domain, uid_t rid, 76614843421SMatthew Ahrens char *buf, boolean_t addok) 76714843421SMatthew Ahrens { 76814843421SMatthew Ahrens uint64_t fuid; 76914843421SMatthew Ahrens int domainid = 0; 77014843421SMatthew Ahrens 77114843421SMatthew Ahrens if (domain && domain[0]) { 77214843421SMatthew Ahrens domainid = zfs_fuid_find_by_domain(zfsvfs, domain, NULL, addok); 77314843421SMatthew Ahrens if (domainid == -1) 774be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 77514843421SMatthew Ahrens } 77614843421SMatthew Ahrens fuid = FUID_ENCODE(domainid, rid); 77714843421SMatthew Ahrens (void) sprintf(buf, "%llx", (longlong_t)fuid); 77814843421SMatthew Ahrens return (0); 77914843421SMatthew Ahrens } 78014843421SMatthew Ahrens 78114843421SMatthew Ahrens int 78214843421SMatthew Ahrens zfs_userspace_one(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type, 78314843421SMatthew Ahrens const char *domain, uint64_t rid, uint64_t *valp) 78414843421SMatthew Ahrens { 785f67950b2SNasf-Fan char buf[20 + DMU_OBJACCT_PREFIX_LEN]; 786f67950b2SNasf-Fan int offset = 0; 78714843421SMatthew Ahrens int err; 78814843421SMatthew Ahrens uint64_t obj; 78914843421SMatthew Ahrens 79014843421SMatthew Ahrens *valp = 0; 79114843421SMatthew Ahrens 79214843421SMatthew Ahrens if (!dmu_objset_userspace_present(zfsvfs->z_os)) 793be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 79414843421SMatthew Ahrens 795f67950b2SNasf-Fan if ((type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED || 796f67950b2SNasf-Fan type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA || 797f67950b2SNasf-Fan type == ZFS_PROP_PROJECTOBJUSED || 798f67950b2SNasf-Fan type == ZFS_PROP_PROJECTOBJQUOTA) && 799f67950b2SNasf-Fan !dmu_objset_userobjspace_present(zfsvfs->z_os)) 800f67950b2SNasf-Fan return (SET_ERROR(ENOTSUP)); 801f67950b2SNasf-Fan 802f67950b2SNasf-Fan if (type == ZFS_PROP_PROJECTQUOTA || type == ZFS_PROP_PROJECTUSED || 803f67950b2SNasf-Fan type == ZFS_PROP_PROJECTOBJQUOTA || 804f67950b2SNasf-Fan type == ZFS_PROP_PROJECTOBJUSED) { 805f67950b2SNasf-Fan if (!dmu_objset_projectquota_present(zfsvfs->z_os)) 806f67950b2SNasf-Fan return (SET_ERROR(ENOTSUP)); 807f67950b2SNasf-Fan if (!zpl_is_valid_projid(rid)) 808f67950b2SNasf-Fan return (SET_ERROR(EINVAL)); 809f67950b2SNasf-Fan } 810f67950b2SNasf-Fan 81114843421SMatthew Ahrens obj = zfs_userquota_prop_to_obj(zfsvfs, type); 812f67950b2SNasf-Fan if (obj == ZFS_NO_OBJECT) 81314843421SMatthew Ahrens return (0); 81414843421SMatthew Ahrens 815f67950b2SNasf-Fan if (type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED || 816f67950b2SNasf-Fan type == ZFS_PROP_PROJECTOBJUSED) { 817f67950b2SNasf-Fan strncpy(buf, DMU_OBJACCT_PREFIX, DMU_OBJACCT_PREFIX_LEN); 818f67950b2SNasf-Fan offset = DMU_OBJACCT_PREFIX_LEN; 819f67950b2SNasf-Fan } 820f67950b2SNasf-Fan 821f67950b2SNasf-Fan err = id_to_fuidstr(zfsvfs, domain, rid, buf + offset, B_FALSE); 82214843421SMatthew Ahrens if (err) 82314843421SMatthew Ahrens return (err); 82414843421SMatthew Ahrens 82514843421SMatthew Ahrens err = zap_lookup(zfsvfs->z_os, obj, buf, 8, 1, valp); 82614843421SMatthew Ahrens if (err == ENOENT) 82714843421SMatthew Ahrens err = 0; 82814843421SMatthew Ahrens return (err); 82914843421SMatthew Ahrens } 83014843421SMatthew Ahrens 83114843421SMatthew Ahrens int 83214843421SMatthew Ahrens zfs_set_userquota(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type, 83314843421SMatthew Ahrens const char *domain, uint64_t rid, uint64_t quota) 83414843421SMatthew Ahrens { 83514843421SMatthew Ahrens char buf[32]; 83614843421SMatthew Ahrens int err; 83714843421SMatthew Ahrens dmu_tx_t *tx; 83814843421SMatthew Ahrens uint64_t *objp; 83914843421SMatthew Ahrens boolean_t fuid_dirtied; 84014843421SMatthew Ahrens 84114843421SMatthew Ahrens if (zfsvfs->z_version < ZPL_VERSION_USERSPACE) 842be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 84314843421SMatthew Ahrens 844f67950b2SNasf-Fan switch (type) { 845f67950b2SNasf-Fan case ZFS_PROP_USERQUOTA: 846f67950b2SNasf-Fan objp = &zfsvfs->z_userquota_obj; 847f67950b2SNasf-Fan break; 848f67950b2SNasf-Fan case ZFS_PROP_GROUPQUOTA: 849f67950b2SNasf-Fan objp = &zfsvfs->z_groupquota_obj; 850f67950b2SNasf-Fan break; 851f67950b2SNasf-Fan case ZFS_PROP_USEROBJQUOTA: 852f67950b2SNasf-Fan objp = &zfsvfs->z_userobjquota_obj; 853f67950b2SNasf-Fan break; 854f67950b2SNasf-Fan case ZFS_PROP_GROUPOBJQUOTA: 855f67950b2SNasf-Fan objp = &zfsvfs->z_groupobjquota_obj; 856f67950b2SNasf-Fan break; 857f67950b2SNasf-Fan case ZFS_PROP_PROJECTQUOTA: 858f67950b2SNasf-Fan if (!dmu_objset_projectquota_enabled(zfsvfs->z_os)) 859f67950b2SNasf-Fan return (SET_ERROR(ENOTSUP)); 860f67950b2SNasf-Fan if (!zpl_is_valid_projid(rid)) 861f67950b2SNasf-Fan return (SET_ERROR(EINVAL)); 862f67950b2SNasf-Fan 863f67950b2SNasf-Fan objp = &zfsvfs->z_projectquota_obj; 864f67950b2SNasf-Fan break; 865f67950b2SNasf-Fan case ZFS_PROP_PROJECTOBJQUOTA: 866f67950b2SNasf-Fan if (!dmu_objset_projectquota_enabled(zfsvfs->z_os)) 867f67950b2SNasf-Fan return (SET_ERROR(ENOTSUP)); 868f67950b2SNasf-Fan if (!zpl_is_valid_projid(rid)) 869f67950b2SNasf-Fan return (SET_ERROR(EINVAL)); 870f67950b2SNasf-Fan 871f67950b2SNasf-Fan objp = &zfsvfs->z_projectobjquota_obj; 872f67950b2SNasf-Fan break; 873f67950b2SNasf-Fan default: 874f67950b2SNasf-Fan return (SET_ERROR(EINVAL)); 875f67950b2SNasf-Fan } 87614843421SMatthew Ahrens 87714843421SMatthew Ahrens err = id_to_fuidstr(zfsvfs, domain, rid, buf, B_TRUE); 87814843421SMatthew Ahrens if (err) 87914843421SMatthew Ahrens return (err); 88014843421SMatthew Ahrens fuid_dirtied = zfsvfs->z_fuid_dirty; 88114843421SMatthew Ahrens 88214843421SMatthew Ahrens tx = dmu_tx_create(zfsvfs->z_os); 88314843421SMatthew Ahrens dmu_tx_hold_zap(tx, *objp ? *objp : DMU_NEW_OBJECT, B_TRUE, NULL); 88414843421SMatthew Ahrens if (*objp == 0) { 88514843421SMatthew Ahrens dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, B_TRUE, 88614843421SMatthew Ahrens zfs_userquota_prop_prefixes[type]); 88714843421SMatthew Ahrens } 88814843421SMatthew Ahrens if (fuid_dirtied) 88914843421SMatthew Ahrens zfs_fuid_txhold(zfsvfs, tx); 89014843421SMatthew Ahrens err = dmu_tx_assign(tx, TXG_WAIT); 89114843421SMatthew Ahrens if (err) { 89214843421SMatthew Ahrens dmu_tx_abort(tx); 89314843421SMatthew Ahrens return (err); 89414843421SMatthew Ahrens } 89514843421SMatthew Ahrens 89614843421SMatthew Ahrens mutex_enter(&zfsvfs->z_lock); 89714843421SMatthew Ahrens if (*objp == 0) { 89814843421SMatthew Ahrens *objp = zap_create(zfsvfs->z_os, DMU_OT_USERGROUP_QUOTA, 89914843421SMatthew Ahrens DMU_OT_NONE, 0, tx); 90014843421SMatthew Ahrens VERIFY(0 == zap_add(zfsvfs->z_os, MASTER_NODE_OBJ, 90114843421SMatthew Ahrens zfs_userquota_prop_prefixes[type], 8, 1, objp, tx)); 90214843421SMatthew Ahrens } 90314843421SMatthew Ahrens mutex_exit(&zfsvfs->z_lock); 90414843421SMatthew Ahrens 90514843421SMatthew Ahrens if (quota == 0) { 90614843421SMatthew Ahrens err = zap_remove(zfsvfs->z_os, *objp, buf, tx); 90714843421SMatthew Ahrens if (err == ENOENT) 90814843421SMatthew Ahrens err = 0; 90914843421SMatthew Ahrens } else { 91014843421SMatthew Ahrens err = zap_update(zfsvfs->z_os, *objp, buf, 8, 1, "a, tx); 91114843421SMatthew Ahrens } 91214843421SMatthew Ahrens ASSERT(err == 0); 91314843421SMatthew Ahrens if (fuid_dirtied) 91414843421SMatthew Ahrens zfs_fuid_sync(zfsvfs, tx); 91514843421SMatthew Ahrens dmu_tx_commit(tx); 91614843421SMatthew Ahrens return (err); 91714843421SMatthew Ahrens } 91814843421SMatthew Ahrens 91914843421SMatthew Ahrens boolean_t 920f67950b2SNasf-Fan zfs_id_overobjquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id) 92114843421SMatthew Ahrens { 922f67950b2SNasf-Fan char buf[20 + DMU_OBJACCT_PREFIX_LEN]; 923f67950b2SNasf-Fan uint64_t used, quota, quotaobj; 92414843421SMatthew Ahrens int err; 92514843421SMatthew Ahrens 926f67950b2SNasf-Fan if (!dmu_objset_userobjspace_present(zfsvfs->z_os)) { 927f67950b2SNasf-Fan if (dmu_objset_userobjspace_upgradable(zfsvfs->z_os)) 928f67950b2SNasf-Fan dmu_objset_id_quota_upgrade(zfsvfs->z_os); 929f67950b2SNasf-Fan return (B_FALSE); 930f67950b2SNasf-Fan } 93114843421SMatthew Ahrens 932f67950b2SNasf-Fan if (usedobj == DMU_PROJECTUSED_OBJECT) { 933f67950b2SNasf-Fan if (!dmu_objset_projectquota_present(zfsvfs->z_os)) { 934f67950b2SNasf-Fan if (dmu_objset_projectquota_upgradable(zfsvfs->z_os)) { 935f67950b2SNasf-Fan dsl_pool_config_enter( 936f67950b2SNasf-Fan dmu_objset_pool(zfsvfs->z_os), FTAG); 937f67950b2SNasf-Fan dmu_objset_id_quota_upgrade(zfsvfs->z_os); 938f67950b2SNasf-Fan dsl_pool_config_exit( 939f67950b2SNasf-Fan dmu_objset_pool(zfsvfs->z_os), FTAG); 940f67950b2SNasf-Fan } 941f67950b2SNasf-Fan return (B_FALSE); 942f67950b2SNasf-Fan } 943f67950b2SNasf-Fan quotaobj = zfsvfs->z_projectobjquota_obj; 944f67950b2SNasf-Fan } else if (usedobj == DMU_USERUSED_OBJECT) { 945f67950b2SNasf-Fan quotaobj = zfsvfs->z_userobjquota_obj; 946f67950b2SNasf-Fan } else if (usedobj == DMU_GROUPUSED_OBJECT) { 947f67950b2SNasf-Fan quotaobj = zfsvfs->z_groupobjquota_obj; 948f67950b2SNasf-Fan } else { 949f67950b2SNasf-Fan return (B_FALSE); 950f67950b2SNasf-Fan } 95114843421SMatthew Ahrens if (quotaobj == 0 || zfsvfs->z_replay) 95214843421SMatthew Ahrens return (B_FALSE); 95314843421SMatthew Ahrens 954f67950b2SNasf-Fan (void) sprintf(buf, "%llx", (longlong_t)id); 95514843421SMatthew Ahrens err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, "a); 95614843421SMatthew Ahrens if (err != 0) 95714843421SMatthew Ahrens return (B_FALSE); 95814843421SMatthew Ahrens 959f67950b2SNasf-Fan (void) sprintf(buf, DMU_OBJACCT_PREFIX "%llx", (longlong_t)id); 96014843421SMatthew Ahrens err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used); 96114843421SMatthew Ahrens if (err != 0) 96214843421SMatthew Ahrens return (B_FALSE); 96314843421SMatthew Ahrens return (used >= quota); 96414843421SMatthew Ahrens } 96514843421SMatthew Ahrens 9660a586ceaSMark Shellenbaum boolean_t 967f67950b2SNasf-Fan zfs_id_overblockquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id) 9680a586ceaSMark Shellenbaum { 969f67950b2SNasf-Fan char buf[20]; 970f67950b2SNasf-Fan uint64_t used, quota, quotaobj; 971f67950b2SNasf-Fan int err; 9720a586ceaSMark Shellenbaum 973f67950b2SNasf-Fan if (usedobj == DMU_PROJECTUSED_OBJECT) { 974f67950b2SNasf-Fan if (!dmu_objset_projectquota_present(zfsvfs->z_os)) { 975f67950b2SNasf-Fan if (dmu_objset_projectquota_upgradable(zfsvfs->z_os)) { 976f67950b2SNasf-Fan dsl_pool_config_enter( 977f67950b2SNasf-Fan dmu_objset_pool(zfsvfs->z_os), FTAG); 978f67950b2SNasf-Fan dmu_objset_id_quota_upgrade(zfsvfs->z_os); 979f67950b2SNasf-Fan dsl_pool_config_exit( 980f67950b2SNasf-Fan dmu_objset_pool(zfsvfs->z_os), FTAG); 981f67950b2SNasf-Fan } 982f67950b2SNasf-Fan return (B_FALSE); 983f67950b2SNasf-Fan } 984f67950b2SNasf-Fan quotaobj = zfsvfs->z_projectquota_obj; 985f67950b2SNasf-Fan } else if (usedobj == DMU_USERUSED_OBJECT) { 986f67950b2SNasf-Fan quotaobj = zfsvfs->z_userquota_obj; 987f67950b2SNasf-Fan } else if (usedobj == DMU_GROUPUSED_OBJECT) { 988f67950b2SNasf-Fan quotaobj = zfsvfs->z_groupquota_obj; 989f67950b2SNasf-Fan } else { 990f67950b2SNasf-Fan return (B_FALSE); 991f67950b2SNasf-Fan } 992f67950b2SNasf-Fan if (quotaobj == 0 || zfsvfs->z_replay) 993f67950b2SNasf-Fan return (B_FALSE); 9940a586ceaSMark Shellenbaum 995f67950b2SNasf-Fan (void) sprintf(buf, "%llx", (longlong_t)id); 996f67950b2SNasf-Fan err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, "a); 997f67950b2SNasf-Fan if (err != 0) 998f67950b2SNasf-Fan return (B_FALSE); 9990a586ceaSMark Shellenbaum 1000f67950b2SNasf-Fan err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used); 1001f67950b2SNasf-Fan if (err != 0) 10020a586ceaSMark Shellenbaum return (B_FALSE); 1003f67950b2SNasf-Fan return (used >= quota); 1004f67950b2SNasf-Fan } 10050a586ceaSMark Shellenbaum 1006f67950b2SNasf-Fan boolean_t 1007f67950b2SNasf-Fan zfs_id_overquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id) 1008f67950b2SNasf-Fan { 1009f67950b2SNasf-Fan return (zfs_id_overblockquota(zfsvfs, usedobj, id) || 1010f67950b2SNasf-Fan zfs_id_overobjquota(zfsvfs, usedobj, id)); 10110a586ceaSMark Shellenbaum } 10120a586ceaSMark Shellenbaum 10131fdcbd00SMatthew Ahrens /* 10141fdcbd00SMatthew Ahrens * Associate this zfsvfs with the given objset, which must be owned. 10151fdcbd00SMatthew Ahrens * This will cache a bunch of on-disk state from the objset in the 10161fdcbd00SMatthew Ahrens * zfsvfs. 10171fdcbd00SMatthew Ahrens */ 10181fdcbd00SMatthew Ahrens static int 10191fdcbd00SMatthew Ahrens zfsvfs_init(zfsvfs_t *zfsvfs, objset_t *os) 102014843421SMatthew Ahrens { 10211fdcbd00SMatthew Ahrens int error; 10221fdcbd00SMatthew Ahrens uint64_t val; 102314843421SMatthew Ahrens 1024b5152584SMatthew Ahrens zfsvfs->z_max_blksz = SPA_OLD_MAXBLOCKSIZE; 102514843421SMatthew Ahrens zfsvfs->z_show_ctldir = ZFS_SNAPDIR_VISIBLE; 102614843421SMatthew Ahrens zfsvfs->z_os = os; 102714843421SMatthew Ahrens 102814843421SMatthew Ahrens error = zfs_get_zplprop(os, ZFS_PROP_VERSION, &zfsvfs->z_version); 10291fdcbd00SMatthew Ahrens if (error != 0) 10301fdcbd00SMatthew Ahrens return (error); 10311fdcbd00SMatthew Ahrens if (zfsvfs->z_version > 1032dc7cd546SMark Shellenbaum zfs_zpl_version_map(spa_version(dmu_objset_spa(os)))) { 1033dc7cd546SMark Shellenbaum (void) printf("Can't mount a version %lld file system " 1034dc7cd546SMark Shellenbaum "on a version %lld pool\n. Pool must be upgraded to mount " 1035dc7cd546SMark Shellenbaum "this file system.", (u_longlong_t)zfsvfs->z_version, 1036dc7cd546SMark Shellenbaum (u_longlong_t)spa_version(dmu_objset_spa(os))); 10371fdcbd00SMatthew Ahrens return (SET_ERROR(ENOTSUP)); 103814843421SMatthew Ahrens } 10391fdcbd00SMatthew Ahrens error = zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &val); 10401fdcbd00SMatthew Ahrens if (error != 0) 10411fdcbd00SMatthew Ahrens return (error); 10421fdcbd00SMatthew Ahrens zfsvfs->z_norm = (int)val; 104314843421SMatthew Ahrens 10441fdcbd00SMatthew Ahrens error = zfs_get_zplprop(os, ZFS_PROP_UTF8ONLY, &val); 10451fdcbd00SMatthew Ahrens if (error != 0) 10461fdcbd00SMatthew Ahrens return (error); 10471fdcbd00SMatthew Ahrens zfsvfs->z_utf8 = (val != 0); 104814843421SMatthew Ahrens 10491fdcbd00SMatthew Ahrens error = zfs_get_zplprop(os, ZFS_PROP_CASE, &val); 10501fdcbd00SMatthew Ahrens if (error != 0) 10511fdcbd00SMatthew Ahrens return (error); 10521fdcbd00SMatthew Ahrens zfsvfs->z_case = (uint_t)val; 105314843421SMatthew Ahrens 105414843421SMatthew Ahrens /* 105514843421SMatthew Ahrens * Fold case on file systems that are always or sometimes case 105614843421SMatthew Ahrens * insensitive. 105714843421SMatthew Ahrens */ 105814843421SMatthew Ahrens if (zfsvfs->z_case == ZFS_CASE_INSENSITIVE || 105914843421SMatthew Ahrens zfsvfs->z_case == ZFS_CASE_MIXED) 106014843421SMatthew Ahrens zfsvfs->z_norm |= U8_TEXTPREP_TOUPPER; 106114843421SMatthew Ahrens 106214843421SMatthew Ahrens zfsvfs->z_use_fuids = USE_FUIDS(zfsvfs->z_version, zfsvfs->z_os); 10630a586ceaSMark Shellenbaum zfsvfs->z_use_sa = USE_SA(zfsvfs->z_version, zfsvfs->z_os); 10640a586ceaSMark Shellenbaum 10651fdcbd00SMatthew Ahrens uint64_t sa_obj = 0; 10660a586ceaSMark Shellenbaum if (zfsvfs->z_use_sa) { 10670a586ceaSMark Shellenbaum /* should either have both of these objects or none */ 10680a586ceaSMark Shellenbaum error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_SA_ATTRS, 8, 1, 10690a586ceaSMark Shellenbaum &sa_obj); 10701fdcbd00SMatthew Ahrens if (error != 0) 10711fdcbd00SMatthew Ahrens return (error); 10720a586ceaSMark Shellenbaum } 10730a586ceaSMark Shellenbaum 10741d8ccc7bSMark Shellenbaum error = sa_setup(os, sa_obj, zfs_attr_table, ZPL_END, 10751d8ccc7bSMark Shellenbaum &zfsvfs->z_attr_table); 10761fdcbd00SMatthew Ahrens if (error != 0) 10771fdcbd00SMatthew Ahrens return (error); 10780a586ceaSMark Shellenbaum 10790a586ceaSMark Shellenbaum if (zfsvfs->z_version >= ZPL_VERSION_SA) 10800a586ceaSMark Shellenbaum sa_register_update_callback(os, zfs_sa_upgrade); 108114843421SMatthew Ahrens 108214843421SMatthew Ahrens error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_ROOT_OBJ, 8, 1, 108314843421SMatthew Ahrens &zfsvfs->z_root); 10841fdcbd00SMatthew Ahrens if (error != 0) 10851fdcbd00SMatthew Ahrens return (error); 108614843421SMatthew Ahrens ASSERT(zfsvfs->z_root != 0); 108714843421SMatthew Ahrens 108814843421SMatthew Ahrens error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_UNLINKED_SET, 8, 1, 108914843421SMatthew Ahrens &zfsvfs->z_unlinkedobj); 10901fdcbd00SMatthew Ahrens if (error != 0) 10911fdcbd00SMatthew Ahrens return (error); 109214843421SMatthew Ahrens 109314843421SMatthew Ahrens error = zap_lookup(os, MASTER_NODE_OBJ, 109414843421SMatthew Ahrens zfs_userquota_prop_prefixes[ZFS_PROP_USERQUOTA], 109514843421SMatthew Ahrens 8, 1, &zfsvfs->z_userquota_obj); 10961fdcbd00SMatthew Ahrens if (error == ENOENT) 10971fdcbd00SMatthew Ahrens zfsvfs->z_userquota_obj = 0; 10981fdcbd00SMatthew Ahrens else if (error != 0) 10991fdcbd00SMatthew Ahrens return (error); 110014843421SMatthew Ahrens 110114843421SMatthew Ahrens error = zap_lookup(os, MASTER_NODE_OBJ, 110214843421SMatthew Ahrens zfs_userquota_prop_prefixes[ZFS_PROP_GROUPQUOTA], 110314843421SMatthew Ahrens 8, 1, &zfsvfs->z_groupquota_obj); 11041fdcbd00SMatthew Ahrens if (error == ENOENT) 11051fdcbd00SMatthew Ahrens zfsvfs->z_groupquota_obj = 0; 11061fdcbd00SMatthew Ahrens else if (error != 0) 11071fdcbd00SMatthew Ahrens return (error); 110814843421SMatthew Ahrens 1109f67950b2SNasf-Fan error = zap_lookup(os, MASTER_NODE_OBJ, 1110f67950b2SNasf-Fan zfs_userquota_prop_prefixes[ZFS_PROP_PROJECTQUOTA], 1111f67950b2SNasf-Fan 8, 1, &zfsvfs->z_projectquota_obj); 1112f67950b2SNasf-Fan if (error == ENOENT) 1113f67950b2SNasf-Fan zfsvfs->z_projectquota_obj = 0; 1114f67950b2SNasf-Fan else if (error != 0) 1115f67950b2SNasf-Fan return (error); 1116f67950b2SNasf-Fan 1117f67950b2SNasf-Fan error = zap_lookup(os, MASTER_NODE_OBJ, 1118f67950b2SNasf-Fan zfs_userquota_prop_prefixes[ZFS_PROP_USEROBJQUOTA], 1119f67950b2SNasf-Fan 8, 1, &zfsvfs->z_userobjquota_obj); 1120f67950b2SNasf-Fan if (error == ENOENT) 1121f67950b2SNasf-Fan zfsvfs->z_userobjquota_obj = 0; 1122f67950b2SNasf-Fan else if (error != 0) 1123f67950b2SNasf-Fan return (error); 1124f67950b2SNasf-Fan 1125f67950b2SNasf-Fan error = zap_lookup(os, MASTER_NODE_OBJ, 1126f67950b2SNasf-Fan zfs_userquota_prop_prefixes[ZFS_PROP_GROUPOBJQUOTA], 1127f67950b2SNasf-Fan 8, 1, &zfsvfs->z_groupobjquota_obj); 1128f67950b2SNasf-Fan if (error == ENOENT) 1129f67950b2SNasf-Fan zfsvfs->z_groupobjquota_obj = 0; 1130f67950b2SNasf-Fan else if (error != 0) 1131f67950b2SNasf-Fan return (error); 1132f67950b2SNasf-Fan 1133f67950b2SNasf-Fan error = zap_lookup(os, MASTER_NODE_OBJ, 1134f67950b2SNasf-Fan zfs_userquota_prop_prefixes[ZFS_PROP_PROJECTOBJQUOTA], 1135f67950b2SNasf-Fan 8, 1, &zfsvfs->z_projectobjquota_obj); 1136f67950b2SNasf-Fan if (error == ENOENT) 1137f67950b2SNasf-Fan zfsvfs->z_projectobjquota_obj = 0; 1138f67950b2SNasf-Fan else if (error != 0) 1139f67950b2SNasf-Fan return (error); 1140f67950b2SNasf-Fan 114114843421SMatthew Ahrens error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_FUID_TABLES, 8, 1, 114214843421SMatthew Ahrens &zfsvfs->z_fuid_obj); 11431fdcbd00SMatthew Ahrens if (error == ENOENT) 11441fdcbd00SMatthew Ahrens zfsvfs->z_fuid_obj = 0; 11451fdcbd00SMatthew Ahrens else if (error != 0) 11461fdcbd00SMatthew Ahrens return (error); 114714843421SMatthew Ahrens 114814843421SMatthew Ahrens error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_SHARES_DIR, 8, 1, 114914843421SMatthew Ahrens &zfsvfs->z_shares_dir); 11501fdcbd00SMatthew Ahrens if (error == ENOENT) 11511fdcbd00SMatthew Ahrens zfsvfs->z_shares_dir = 0; 11521fdcbd00SMatthew Ahrens else if (error != 0) 11531fdcbd00SMatthew Ahrens return (error); 11541fdcbd00SMatthew Ahrens 11551fdcbd00SMatthew Ahrens return (0); 11561fdcbd00SMatthew Ahrens } 11571fdcbd00SMatthew Ahrens 11581fdcbd00SMatthew Ahrens int 11598bf394f1STom Caputi zfsvfs_create(const char *osname, boolean_t readonly, zfsvfs_t **zfvp) 11601fdcbd00SMatthew Ahrens { 11611fdcbd00SMatthew Ahrens objset_t *os; 11621fdcbd00SMatthew Ahrens zfsvfs_t *zfsvfs; 11631fdcbd00SMatthew Ahrens int error; 11648bf394f1STom Caputi boolean_t ro = (readonly || (strchr(osname, '@') != NULL)); 11651fdcbd00SMatthew Ahrens 11661fdcbd00SMatthew Ahrens zfsvfs = kmem_zalloc(sizeof (zfsvfs_t), KM_SLEEP); 11671fdcbd00SMatthew Ahrens 1168f67950b2SNasf-Fan error = dmu_objset_own(osname, DMU_OST_ZFS, ro, B_TRUE, zfsvfs, &os); 1169dfc11533SChris Williamson if (error != 0) { 11701fdcbd00SMatthew Ahrens kmem_free(zfsvfs, sizeof (zfsvfs_t)); 11711fdcbd00SMatthew Ahrens return (error); 11721fdcbd00SMatthew Ahrens } 11731fdcbd00SMatthew Ahrens 1174dfc11533SChris Williamson error = zfsvfs_create_impl(zfvp, zfsvfs, os); 1175dfc11533SChris Williamson if (error != 0) { 1176eb633035STom Caputi dmu_objset_disown(os, B_TRUE, zfsvfs); 1177dfc11533SChris Williamson } 1178dfc11533SChris Williamson return (error); 1179dfc11533SChris Williamson } 1180dfc11533SChris Williamson 1181dfc11533SChris Williamson 1182dfc11533SChris Williamson int 1183dfc11533SChris Williamson zfsvfs_create_impl(zfsvfs_t **zfvp, zfsvfs_t *zfsvfs, objset_t *os) 1184dfc11533SChris Williamson { 1185dfc11533SChris Williamson int error; 1186dfc11533SChris Williamson 11871fdcbd00SMatthew Ahrens zfsvfs->z_vfs = NULL; 11881fdcbd00SMatthew Ahrens zfsvfs->z_parent = zfsvfs; 118914843421SMatthew Ahrens 119014843421SMatthew Ahrens mutex_init(&zfsvfs->z_znodes_lock, NULL, MUTEX_DEFAULT, NULL); 119114843421SMatthew Ahrens mutex_init(&zfsvfs->z_lock, NULL, MUTEX_DEFAULT, NULL); 119214843421SMatthew Ahrens list_create(&zfsvfs->z_all_znodes, sizeof (znode_t), 119314843421SMatthew Ahrens offsetof(znode_t, z_link_node)); 1194c9030f6cSAlexander Motin rrm_init(&zfsvfs->z_teardown_lock, B_FALSE); 119514843421SMatthew Ahrens rw_init(&zfsvfs->z_teardown_inactive_lock, NULL, RW_DEFAULT, NULL); 119614843421SMatthew Ahrens rw_init(&zfsvfs->z_fuid_lock, NULL, RW_DEFAULT, NULL); 11971fdcbd00SMatthew Ahrens for (int i = 0; i != ZFS_OBJ_MTX_SZ; i++) 119814843421SMatthew Ahrens mutex_init(&zfsvfs->z_hold_mtx[i], NULL, MUTEX_DEFAULT, NULL); 119914843421SMatthew Ahrens 12001fdcbd00SMatthew Ahrens error = zfsvfs_init(zfsvfs, os); 12011fdcbd00SMatthew Ahrens if (error != 0) { 12021fdcbd00SMatthew Ahrens *zfvp = NULL; 12031fdcbd00SMatthew Ahrens kmem_free(zfsvfs, sizeof (zfsvfs_t)); 12041fdcbd00SMatthew Ahrens return (error); 12051fdcbd00SMatthew Ahrens } 12061fdcbd00SMatthew Ahrens 1207c5832a53SAlek Pinchuk zfsvfs->z_drain_task = TASKQID_INVALID; 1208c5832a53SAlek Pinchuk zfsvfs->z_draining = B_FALSE; 1209c5832a53SAlek Pinchuk zfsvfs->z_drain_cancel = B_TRUE; 1210c5832a53SAlek Pinchuk 1211af4c679fSSean McEnroe *zfvp = zfsvfs; 121214843421SMatthew Ahrens return (0); 121314843421SMatthew Ahrens } 121414843421SMatthew Ahrens 1215f18faf3fSek static int 1216f18faf3fSek zfsvfs_setup(zfsvfs_t *zfsvfs, boolean_t mounting) 1217f18faf3fSek { 1218f18faf3fSek int error; 1219f18faf3fSek 1220f18faf3fSek error = zfs_register_callbacks(zfsvfs->z_vfs); 1221f18faf3fSek if (error) 1222f18faf3fSek return (error); 1223f18faf3fSek 1224377c02aaSNeil Perrin zfsvfs->z_log = zil_open(zfsvfs->z_os, zfs_get_data); 1225377c02aaSNeil Perrin 1226f18faf3fSek /* 1227f18faf3fSek * If we are not mounting (ie: online recv), then we don't 1228f18faf3fSek * have to worry about replaying the log as we blocked all 1229f18faf3fSek * operations out since we closed the ZIL. 1230f18faf3fSek */ 1231f18faf3fSek if (mounting) { 1232a6e57bd4SNeil Perrin boolean_t readonly; 1233a6e57bd4SNeil Perrin 1234f18faf3fSek /* 1235f18faf3fSek * During replay we remove the read only flag to 1236f18faf3fSek * allow replays to succeed. 1237f18faf3fSek */ 1238f18faf3fSek readonly = zfsvfs->z_vfs->vfs_flag & VFS_RDONLY; 1239c5832a53SAlek Pinchuk if (readonly != 0) { 12401209a471SNeil Perrin zfsvfs->z_vfs->vfs_flag &= ~VFS_RDONLY; 1241c5832a53SAlek Pinchuk } else { 12421209a471SNeil Perrin zfs_unlinked_drain(zfsvfs); 1243c5832a53SAlek Pinchuk } 1244f18faf3fSek 124555da60b9SMark J Musante /* 124655da60b9SMark J Musante * Parse and replay the intent log. 124755da60b9SMark J Musante * 124855da60b9SMark J Musante * Because of ziltest, this must be done after 124955da60b9SMark J Musante * zfs_unlinked_drain(). (Further note: ziltest 125055da60b9SMark J Musante * doesn't use readonly mounts, where 125155da60b9SMark J Musante * zfs_unlinked_drain() isn't called.) This is because 125255da60b9SMark J Musante * ziltest causes spa_sync() to think it's committed, 125355da60b9SMark J Musante * but actually it is not, so the intent log contains 125455da60b9SMark J Musante * many txg's worth of changes. 125555da60b9SMark J Musante * 125655da60b9SMark J Musante * In particular, if object N is in the unlinked set in 125755da60b9SMark J Musante * the last txg to actually sync, then it could be 125855da60b9SMark J Musante * actually freed in a later txg and then reallocated 125955da60b9SMark J Musante * in a yet later txg. This would write a "create 126055da60b9SMark J Musante * object N" record to the intent log. Normally, this 126155da60b9SMark J Musante * would be fine because the spa_sync() would have 126255da60b9SMark J Musante * written out the fact that object N is free, before 126355da60b9SMark J Musante * we could write the "create object N" intent log 126455da60b9SMark J Musante * record. 126555da60b9SMark J Musante * 126655da60b9SMark J Musante * But when we are in ziltest mode, we advance the "open 126755da60b9SMark J Musante * txg" without actually spa_sync()-ing the changes to 126855da60b9SMark J Musante * disk. So we would see that object N is still 126955da60b9SMark J Musante * allocated and in the unlinked set, and there is an 127055da60b9SMark J Musante * intent log record saying to allocate it. 127155da60b9SMark J Musante */ 1272f9af39baSGeorge Wilson if (spa_writeable(dmu_objset_spa(zfsvfs->z_os))) { 1273f9af39baSGeorge Wilson if (zil_replay_disable) { 1274f9af39baSGeorge Wilson zil_destroy(zfsvfs->z_log, B_FALSE); 1275f9af39baSGeorge Wilson } else { 1276f9af39baSGeorge Wilson zfsvfs->z_replay = B_TRUE; 1277f9af39baSGeorge Wilson zil_replay(zfsvfs->z_os, zfsvfs, 1278f9af39baSGeorge Wilson zfs_replay_vector); 1279f9af39baSGeorge Wilson zfsvfs->z_replay = B_FALSE; 1280f9af39baSGeorge Wilson } 12811209a471SNeil Perrin } 1282eb633035STom Caputi 1283eb633035STom Caputi /* restore readonly bit */ 1284eb633035STom Caputi if (readonly != 0) 1285eb633035STom Caputi zfsvfs->z_vfs->vfs_flag |= VFS_RDONLY; 1286f18faf3fSek } 1287f18faf3fSek 128890f2c094SAndriy Gapon /* 128990f2c094SAndriy Gapon * Set the objset user_ptr to track its zfsvfs. 129090f2c094SAndriy Gapon */ 129190f2c094SAndriy Gapon mutex_enter(&zfsvfs->z_os->os_user_ptr_lock); 129290f2c094SAndriy Gapon dmu_objset_set_user(zfsvfs->z_os, zfsvfs); 129390f2c094SAndriy Gapon mutex_exit(&zfsvfs->z_os->os_user_ptr_lock); 129490f2c094SAndriy Gapon 1295f18faf3fSek return (0); 1296f18faf3fSek } 1297f18faf3fSek 129814843421SMatthew Ahrens void 129914843421SMatthew Ahrens zfsvfs_free(zfsvfs_t *zfsvfs) 130047f263f4Sek { 130114843421SMatthew Ahrens int i; 13024e9583b2STom Erickson extern krwlock_t zfsvfs_lock; /* in zfs_znode.c */ 13034e9583b2STom Erickson 13044e9583b2STom Erickson /* 13054e9583b2STom Erickson * This is a barrier to prevent the filesystem from going away in 13064e9583b2STom Erickson * zfs_znode_move() until we can safely ensure that the filesystem is 13074e9583b2STom Erickson * not unmounted. We consider the filesystem valid before the barrier 13084e9583b2STom Erickson * and invalid after the barrier. 13094e9583b2STom Erickson */ 13104e9583b2STom Erickson rw_enter(&zfsvfs_lock, RW_READER); 13114e9583b2STom Erickson rw_exit(&zfsvfs_lock); 131214843421SMatthew Ahrens 131314843421SMatthew Ahrens zfs_fuid_destroy(zfsvfs); 131414843421SMatthew Ahrens 131547f263f4Sek mutex_destroy(&zfsvfs->z_znodes_lock); 13169e1320c0SMark Shellenbaum mutex_destroy(&zfsvfs->z_lock); 131747f263f4Sek list_destroy(&zfsvfs->z_all_znodes); 1318c9030f6cSAlexander Motin rrm_destroy(&zfsvfs->z_teardown_lock); 131947f263f4Sek rw_destroy(&zfsvfs->z_teardown_inactive_lock); 132047f263f4Sek rw_destroy(&zfsvfs->z_fuid_lock); 132114843421SMatthew Ahrens for (i = 0; i != ZFS_OBJ_MTX_SZ; i++) 132214843421SMatthew Ahrens mutex_destroy(&zfsvfs->z_hold_mtx[i]); 132347f263f4Sek kmem_free(zfsvfs, sizeof (zfsvfs_t)); 132447f263f4Sek } 132547f263f4Sek 132614843421SMatthew Ahrens static void 132714843421SMatthew Ahrens zfs_set_fuid_feature(zfsvfs_t *zfsvfs) 132814843421SMatthew Ahrens { 132914843421SMatthew Ahrens zfsvfs->z_use_fuids = USE_FUIDS(zfsvfs->z_version, zfsvfs->z_os); 133044bffe01SMark Shellenbaum if (zfsvfs->z_vfs) { 133144bffe01SMark Shellenbaum if (zfsvfs->z_use_fuids) { 133244bffe01SMark Shellenbaum vfs_set_feature(zfsvfs->z_vfs, VFSFT_XVATTR); 133344bffe01SMark Shellenbaum vfs_set_feature(zfsvfs->z_vfs, VFSFT_SYSATTR_VIEWS); 133444bffe01SMark Shellenbaum vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACEMASKONACCESS); 133544bffe01SMark Shellenbaum vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACLONCREATE); 133644bffe01SMark Shellenbaum vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACCESS_FILTER); 133744bffe01SMark Shellenbaum vfs_set_feature(zfsvfs->z_vfs, VFSFT_REPARSE); 133844bffe01SMark Shellenbaum } else { 133944bffe01SMark Shellenbaum vfs_clear_feature(zfsvfs->z_vfs, VFSFT_XVATTR); 134044bffe01SMark Shellenbaum vfs_clear_feature(zfsvfs->z_vfs, VFSFT_SYSATTR_VIEWS); 134144bffe01SMark Shellenbaum vfs_clear_feature(zfsvfs->z_vfs, VFSFT_ACEMASKONACCESS); 134244bffe01SMark Shellenbaum vfs_clear_feature(zfsvfs->z_vfs, VFSFT_ACLONCREATE); 134344bffe01SMark Shellenbaum vfs_clear_feature(zfsvfs->z_vfs, VFSFT_ACCESS_FILTER); 134444bffe01SMark Shellenbaum vfs_clear_feature(zfsvfs->z_vfs, VFSFT_REPARSE); 134544bffe01SMark Shellenbaum } 134614843421SMatthew Ahrens } 13470a586ceaSMark Shellenbaum zfsvfs->z_use_sa = USE_SA(zfsvfs->z_version, zfsvfs->z_os); 134814843421SMatthew Ahrens } 134914843421SMatthew Ahrens 1350ea8dc4b6Seschrock static int 1351088f3894Sahrens zfs_domount(vfs_t *vfsp, char *osname) 1352ea8dc4b6Seschrock { 1353ea8dc4b6Seschrock dev_t mount_dev; 135414843421SMatthew Ahrens uint64_t recordsize, fsid_guid; 1355ea8dc4b6Seschrock int error = 0; 1356ea8dc4b6Seschrock zfsvfs_t *zfsvfs; 13578bf394f1STom Caputi boolean_t readonly = vfsp->vfs_flag & VFS_RDONLY ? B_TRUE : B_FALSE; 1358ea8dc4b6Seschrock 1359ea8dc4b6Seschrock ASSERT(vfsp); 1360ea8dc4b6Seschrock ASSERT(osname); 1361fa9e4066Sahrens 13628bf394f1STom Caputi error = zfsvfs_create(osname, readonly, &zfsvfs); 136314843421SMatthew Ahrens if (error) 136414843421SMatthew Ahrens return (error); 1365fa9e4066Sahrens zfsvfs->z_vfs = vfsp; 1366fa9e4066Sahrens 1367ea8dc4b6Seschrock /* Initialize the generic filesystem structure. */ 1368fa9e4066Sahrens vfsp->vfs_bcount = 0; 1369fa9e4066Sahrens vfsp->vfs_data = NULL; 1370fa9e4066Sahrens 1371ea8dc4b6Seschrock if (zfs_create_unique_device(&mount_dev) == -1) { 1372be6fd75aSMatthew Ahrens error = SET_ERROR(ENODEV); 1373ea8dc4b6Seschrock goto out; 1374ea8dc4b6Seschrock } 1375fa9e4066Sahrens ASSERT(vfs_devismounted(mount_dev) == 0); 1376fa9e4066Sahrens 1377ea8dc4b6Seschrock if (error = dsl_prop_get_integer(osname, "recordsize", &recordsize, 1378ea8dc4b6Seschrock NULL)) 1379ea8dc4b6Seschrock goto out; 1380fa9e4066Sahrens 1381fa9e4066Sahrens vfsp->vfs_dev = mount_dev; 1382fa9e4066Sahrens vfsp->vfs_fstype = zfsfstype; 1383fa9e4066Sahrens vfsp->vfs_bsize = recordsize; 1384fa9e4066Sahrens vfsp->vfs_flag |= VFS_NOTRUNC; 1385fa9e4066Sahrens vfsp->vfs_data = zfsvfs; 1386fa9e4066Sahrens 138714843421SMatthew Ahrens /* 138814843421SMatthew Ahrens * The fsid is 64 bits, composed of an 8-bit fs type, which 138914843421SMatthew Ahrens * separates our fsid from any other filesystem types, and a 139014843421SMatthew Ahrens * 56-bit objset unique ID. The objset unique ID is unique to 139114843421SMatthew Ahrens * all objsets open on this system, provided by unique_create(). 139214843421SMatthew Ahrens * The 8-bit fs type must be put in the low bits of fsid[1] 139314843421SMatthew Ahrens * because that's where other Solaris filesystems put it. 139414843421SMatthew Ahrens */ 139514843421SMatthew Ahrens fsid_guid = dmu_objset_fsid_guid(zfsvfs->z_os); 139614843421SMatthew Ahrens ASSERT((fsid_guid & ~((1ULL<<56)-1)) == 0); 139714843421SMatthew Ahrens vfsp->vfs_fsid.val[0] = fsid_guid; 139814843421SMatthew Ahrens vfsp->vfs_fsid.val[1] = ((fsid_guid>>32) << 8) | 139914843421SMatthew Ahrens zfsfstype & 0xFF; 1400ea8dc4b6Seschrock 1401da6c28aaSamw /* 1402da6c28aaSamw * Set features for file system. 1403da6c28aaSamw */ 140414843421SMatthew Ahrens zfs_set_fuid_feature(zfsvfs); 1405de8267e0Stimh if (zfsvfs->z_case == ZFS_CASE_INSENSITIVE) { 1406de8267e0Stimh vfs_set_feature(vfsp, VFSFT_DIRENTFLAGS); 1407de8267e0Stimh vfs_set_feature(vfsp, VFSFT_CASEINSENSITIVE); 1408de8267e0Stimh vfs_set_feature(vfsp, VFSFT_NOCASESENSITIVE); 1409de8267e0Stimh } else if (zfsvfs->z_case == ZFS_CASE_MIXED) { 1410de8267e0Stimh vfs_set_feature(vfsp, VFSFT_DIRENTFLAGS); 1411de8267e0Stimh vfs_set_feature(vfsp, VFSFT_CASEINSENSITIVE); 1412de8267e0Stimh } 1413c242f9a0Schunli zhang - Sun Microsystems - Irvine United States vfs_set_feature(vfsp, VFSFT_ZEROCOPY_SUPPORTED); 1414da6c28aaSamw 1415ea8dc4b6Seschrock if (dmu_objset_is_snapshot(zfsvfs->z_os)) { 1416da6c28aaSamw uint64_t pval; 14177b55fa8eSck 1418fa9e4066Sahrens atime_changed_cb(zfsvfs, B_FALSE); 1419fa9e4066Sahrens readonly_changed_cb(zfsvfs, B_TRUE); 1420da6c28aaSamw if (error = dsl_prop_get_integer(osname, "xattr", &pval, NULL)) 14217b55fa8eSck goto out; 1422da6c28aaSamw xattr_changed_cb(zfsvfs, pval); 1423fa9e4066Sahrens zfsvfs->z_issnap = B_TRUE; 1424b9deb9cbSMark J Musante zfsvfs->z_os->os_sync = ZFS_SYNC_DISABLED; 1425777badbaSMatthew Ahrens 1426503ad85cSMatthew Ahrens mutex_enter(&zfsvfs->z_os->os_user_ptr_lock); 1427777badbaSMatthew Ahrens dmu_objset_set_user(zfsvfs->z_os, zfsvfs); 1428503ad85cSMatthew Ahrens mutex_exit(&zfsvfs->z_os->os_user_ptr_lock); 1429fa9e4066Sahrens } else { 1430f18faf3fSek error = zfsvfs_setup(zfsvfs, B_TRUE); 1431ea8dc4b6Seschrock } 1432fa9e4066Sahrens 1433ea8dc4b6Seschrock if (!zfsvfs->z_issnap) 1434ea8dc4b6Seschrock zfsctl_create(zfsvfs); 1435ea8dc4b6Seschrock out: 1436ea8dc4b6Seschrock if (error) { 1437eb633035STom Caputi dmu_objset_disown(zfsvfs->z_os, B_TRUE, zfsvfs); 143814843421SMatthew Ahrens zfsvfs_free(zfsvfs); 1439ea8dc4b6Seschrock } else { 14401a5e258fSJosef 'Jeff' Sipek atomic_inc_32(&zfs_active_fs_count); 1441ea8dc4b6Seschrock } 1442fa9e4066Sahrens 1443ea8dc4b6Seschrock return (error); 1444ea8dc4b6Seschrock } 1445ea8dc4b6Seschrock 1446ea8dc4b6Seschrock void 1447ea8dc4b6Seschrock zfs_unregister_callbacks(zfsvfs_t *zfsvfs) 1448ea8dc4b6Seschrock { 1449ea8dc4b6Seschrock objset_t *os = zfsvfs->z_os; 1450fa9e4066Sahrens 145103bad06fSJustin Gibbs if (!dmu_objset_is_snapshot(os)) 145203bad06fSJustin Gibbs dsl_prop_unregister_all(dmu_objset_ds(os), zfsvfs); 1453ea8dc4b6Seschrock } 1454fa9e4066Sahrens 1455b1b8ab34Slling /* 1456b1b8ab34Slling * Convert a decimal digit string to a uint64_t integer. 1457b1b8ab34Slling */ 1458b1b8ab34Slling static int 1459b1b8ab34Slling str_to_uint64(char *str, uint64_t *objnum) 1460b1b8ab34Slling { 1461b1b8ab34Slling uint64_t num = 0; 1462b1b8ab34Slling 1463b1b8ab34Slling while (*str) { 1464b1b8ab34Slling if (*str < '0' || *str > '9') 1465be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1466b1b8ab34Slling 1467b1b8ab34Slling num = num*10 + *str++ - '0'; 1468b1b8ab34Slling } 1469b1b8ab34Slling 1470b1b8ab34Slling *objnum = num; 1471b1b8ab34Slling return (0); 1472b1b8ab34Slling } 1473b1b8ab34Slling 1474b1b8ab34Slling /* 1475b1b8ab34Slling * The boot path passed from the boot loader is in the form of 1476b1b8ab34Slling * "rootpool-name/root-filesystem-object-number'. Convert this 1477b1b8ab34Slling * string to a dataset name: "rootpool-name/root-filesystem-name". 1478b1b8ab34Slling */ 1479b1b8ab34Slling static int 1480e7cbe64fSgw zfs_parse_bootfs(char *bpath, char *outpath) 1481b1b8ab34Slling { 1482b1b8ab34Slling char *slashp; 1483b1b8ab34Slling uint64_t objnum; 1484b1b8ab34Slling int error; 1485b1b8ab34Slling 1486b1b8ab34Slling if (*bpath == 0 || *bpath == '/') 1487be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1488b1b8ab34Slling 148919397407SSherry Moore (void) strcpy(outpath, bpath); 149019397407SSherry Moore 1491b1b8ab34Slling slashp = strchr(bpath, '/'); 1492b1b8ab34Slling 1493b1b8ab34Slling /* if no '/', just return the pool name */ 1494b1b8ab34Slling if (slashp == NULL) { 1495b1b8ab34Slling return (0); 1496b1b8ab34Slling } 1497b1b8ab34Slling 149819397407SSherry Moore /* if not a number, just return the root dataset name */ 149919397407SSherry Moore if (str_to_uint64(slashp+1, &objnum)) { 150019397407SSherry Moore return (0); 150119397407SSherry Moore } 1502b1b8ab34Slling 1503b1b8ab34Slling *slashp = '\0'; 1504b1b8ab34Slling error = dsl_dsobj_to_dsname(bpath, objnum, outpath); 1505b1b8ab34Slling *slashp = '/'; 1506b1b8ab34Slling 1507b1b8ab34Slling return (error); 1508b1b8ab34Slling } 1509b1b8ab34Slling 15104201a95eSRic Aleshire /* 1511f7170741SWill Andrews * Check that the hex label string is appropriate for the dataset being 1512f7170741SWill Andrews * mounted into the global_zone proper. 15134201a95eSRic Aleshire * 1514f7170741SWill Andrews * Return an error if the hex label string is not default or 1515f7170741SWill Andrews * admin_low/admin_high. For admin_low labels, the corresponding 1516f7170741SWill Andrews * dataset must be readonly. 15174201a95eSRic Aleshire */ 15184201a95eSRic Aleshire int 15194201a95eSRic Aleshire zfs_check_global_label(const char *dsname, const char *hexsl) 15204201a95eSRic Aleshire { 15214201a95eSRic Aleshire if (strcasecmp(hexsl, ZFS_MLSLABEL_DEFAULT) == 0) 15224201a95eSRic Aleshire return (0); 15234201a95eSRic Aleshire if (strcasecmp(hexsl, ADMIN_HIGH) == 0) 15244201a95eSRic Aleshire return (0); 15254201a95eSRic Aleshire if (strcasecmp(hexsl, ADMIN_LOW) == 0) { 15264201a95eSRic Aleshire /* must be readonly */ 15274201a95eSRic Aleshire uint64_t rdonly; 15284201a95eSRic Aleshire 15294201a95eSRic Aleshire if (dsl_prop_get_integer(dsname, 15304201a95eSRic Aleshire zfs_prop_to_name(ZFS_PROP_READONLY), &rdonly, NULL)) 1531be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES)); 15324201a95eSRic Aleshire return (rdonly ? 0 : EACCES); 15334201a95eSRic Aleshire } 1534be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES)); 15354201a95eSRic Aleshire } 15364201a95eSRic Aleshire 1537f67950b2SNasf-Fan static int 1538f67950b2SNasf-Fan zfs_statfs_project(zfsvfs_t *zfsvfs, znode_t *zp, struct statvfs64 *statp, 1539f67950b2SNasf-Fan uint32_t bshift) 1540f67950b2SNasf-Fan { 1541f67950b2SNasf-Fan char buf[20 + DMU_OBJACCT_PREFIX_LEN]; 1542f67950b2SNasf-Fan uint64_t offset = DMU_OBJACCT_PREFIX_LEN; 1543f67950b2SNasf-Fan uint64_t quota; 1544f67950b2SNasf-Fan uint64_t used; 1545f67950b2SNasf-Fan int err; 1546f67950b2SNasf-Fan 1547f67950b2SNasf-Fan strlcpy(buf, DMU_OBJACCT_PREFIX, DMU_OBJACCT_PREFIX_LEN + 1); 1548f67950b2SNasf-Fan err = id_to_fuidstr(zfsvfs, NULL, zp->z_projid, buf + offset, B_FALSE); 1549f67950b2SNasf-Fan if (err) 1550f67950b2SNasf-Fan return (err); 1551f67950b2SNasf-Fan 1552f67950b2SNasf-Fan if (zfsvfs->z_projectquota_obj == 0) 1553f67950b2SNasf-Fan goto objs; 1554f67950b2SNasf-Fan 1555f67950b2SNasf-Fan err = zap_lookup(zfsvfs->z_os, zfsvfs->z_projectquota_obj, 1556f67950b2SNasf-Fan buf + offset, 8, 1, "a); 1557f67950b2SNasf-Fan if (err == ENOENT) 1558f67950b2SNasf-Fan goto objs; 1559f67950b2SNasf-Fan else if (err) 1560f67950b2SNasf-Fan return (err); 1561f67950b2SNasf-Fan 1562f67950b2SNasf-Fan err = zap_lookup(zfsvfs->z_os, DMU_PROJECTUSED_OBJECT, 1563f67950b2SNasf-Fan buf + offset, 8, 1, &used); 1564f67950b2SNasf-Fan if (unlikely(err == ENOENT)) { 1565f67950b2SNasf-Fan uint32_t blksize; 1566f67950b2SNasf-Fan u_longlong_t nblocks; 1567f67950b2SNasf-Fan 1568f67950b2SNasf-Fan /* 1569f67950b2SNasf-Fan * Quota accounting is async, so it is possible race case. 1570f67950b2SNasf-Fan * There is at least one object with the given project ID. 1571f67950b2SNasf-Fan */ 1572f67950b2SNasf-Fan sa_object_size(zp->z_sa_hdl, &blksize, &nblocks); 1573f67950b2SNasf-Fan if (unlikely(zp->z_blksz == 0)) 1574f67950b2SNasf-Fan blksize = zfsvfs->z_max_blksz; 1575f67950b2SNasf-Fan 1576f67950b2SNasf-Fan used = blksize * nblocks; 1577f67950b2SNasf-Fan } else if (err) { 1578f67950b2SNasf-Fan return (err); 1579f67950b2SNasf-Fan } 1580f67950b2SNasf-Fan 1581f67950b2SNasf-Fan statp->f_blocks = quota >> bshift; 1582f67950b2SNasf-Fan statp->f_bfree = (quota > used) ? ((quota - used) >> bshift) : 0; 1583f67950b2SNasf-Fan statp->f_bavail = statp->f_bfree; 1584f67950b2SNasf-Fan 1585f67950b2SNasf-Fan objs: 1586f67950b2SNasf-Fan if (zfsvfs->z_projectobjquota_obj == 0) 1587f67950b2SNasf-Fan return (0); 1588f67950b2SNasf-Fan 1589f67950b2SNasf-Fan err = zap_lookup(zfsvfs->z_os, zfsvfs->z_projectobjquota_obj, 1590f67950b2SNasf-Fan buf + offset, 8, 1, "a); 1591f67950b2SNasf-Fan if (err == ENOENT) 1592f67950b2SNasf-Fan return (0); 1593f67950b2SNasf-Fan else if (err) 1594f67950b2SNasf-Fan return (err); 1595f67950b2SNasf-Fan 1596f67950b2SNasf-Fan err = zap_lookup(zfsvfs->z_os, DMU_PROJECTUSED_OBJECT, 1597f67950b2SNasf-Fan buf, 8, 1, &used); 1598f67950b2SNasf-Fan if (unlikely(err == ENOENT)) { 1599f67950b2SNasf-Fan /* 1600f67950b2SNasf-Fan * Quota accounting is async, so it is possible race case. 1601f67950b2SNasf-Fan * There is at least one object with the given project ID. 1602f67950b2SNasf-Fan */ 1603f67950b2SNasf-Fan used = 1; 1604f67950b2SNasf-Fan } else if (err) { 1605f67950b2SNasf-Fan return (err); 1606f67950b2SNasf-Fan } 1607f67950b2SNasf-Fan 1608f67950b2SNasf-Fan statp->f_files = quota; 1609f67950b2SNasf-Fan statp->f_ffree = (quota > used) ? (quota - used) : 0; 1610f67950b2SNasf-Fan 1611f67950b2SNasf-Fan return (0); 1612f67950b2SNasf-Fan } 1613f67950b2SNasf-Fan 16144201a95eSRic Aleshire /* 1615f7170741SWill Andrews * Determine whether the mount is allowed according to MAC check. 1616f7170741SWill Andrews * by comparing (where appropriate) label of the dataset against 1617f7170741SWill Andrews * the label of the zone being mounted into. If the dataset has 1618f7170741SWill Andrews * no label, create one. 16194201a95eSRic Aleshire * 1620f7170741SWill Andrews * Returns 0 if access allowed, error otherwise (e.g. EACCES) 16214201a95eSRic Aleshire */ 16224201a95eSRic Aleshire static int 16234201a95eSRic Aleshire zfs_mount_label_policy(vfs_t *vfsp, char *osname) 16244201a95eSRic Aleshire { 16254201a95eSRic Aleshire int error, retv; 16264201a95eSRic Aleshire zone_t *mntzone = NULL; 16274201a95eSRic Aleshire ts_label_t *mnt_tsl; 16284201a95eSRic Aleshire bslabel_t *mnt_sl; 16294201a95eSRic Aleshire bslabel_t ds_sl; 16304201a95eSRic Aleshire char ds_hexsl[MAXNAMELEN]; 16314201a95eSRic Aleshire 16324201a95eSRic Aleshire retv = EACCES; /* assume the worst */ 16334201a95eSRic Aleshire 16344201a95eSRic Aleshire /* 16354201a95eSRic Aleshire * Start by getting the dataset label if it exists. 16364201a95eSRic Aleshire */ 16374201a95eSRic Aleshire error = dsl_prop_get(osname, zfs_prop_to_name(ZFS_PROP_MLSLABEL), 16384201a95eSRic Aleshire 1, sizeof (ds_hexsl), &ds_hexsl, NULL); 16394201a95eSRic Aleshire if (error) 1640be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES)); 16414201a95eSRic Aleshire 16424201a95eSRic Aleshire /* 16434201a95eSRic Aleshire * If labeling is NOT enabled, then disallow the mount of datasets 16444201a95eSRic Aleshire * which have a non-default label already. No other label checks 16454201a95eSRic Aleshire * are needed. 16464201a95eSRic Aleshire */ 16474201a95eSRic Aleshire if (!is_system_labeled()) { 16484201a95eSRic Aleshire if (strcasecmp(ds_hexsl, ZFS_MLSLABEL_DEFAULT) == 0) 16494201a95eSRic Aleshire return (0); 1650be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES)); 16514201a95eSRic Aleshire } 16524201a95eSRic Aleshire 16534201a95eSRic Aleshire /* 16544201a95eSRic Aleshire * Get the label of the mountpoint. If mounting into the global 16554201a95eSRic Aleshire * zone (i.e. mountpoint is not within an active zone and the 16564201a95eSRic Aleshire * zoned property is off), the label must be default or 16574201a95eSRic Aleshire * admin_low/admin_high only; no other checks are needed. 16584201a95eSRic Aleshire */ 16594201a95eSRic Aleshire mntzone = zone_find_by_any_path(refstr_value(vfsp->vfs_mntpt), B_FALSE); 16604201a95eSRic Aleshire if (mntzone->zone_id == GLOBAL_ZONEID) { 16614201a95eSRic Aleshire uint64_t zoned; 16624201a95eSRic Aleshire 16634201a95eSRic Aleshire zone_rele(mntzone); 16644201a95eSRic Aleshire 16654201a95eSRic Aleshire if (dsl_prop_get_integer(osname, 16664201a95eSRic Aleshire zfs_prop_to_name(ZFS_PROP_ZONED), &zoned, NULL)) 1667be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES)); 16684201a95eSRic Aleshire if (!zoned) 16694201a95eSRic Aleshire return (zfs_check_global_label(osname, ds_hexsl)); 16704201a95eSRic Aleshire else 16714201a95eSRic Aleshire /* 16724201a95eSRic Aleshire * This is the case of a zone dataset being mounted 16734201a95eSRic Aleshire * initially, before the zone has been fully created; 16744201a95eSRic Aleshire * allow this mount into global zone. 16754201a95eSRic Aleshire */ 16764201a95eSRic Aleshire return (0); 16774201a95eSRic Aleshire } 16784201a95eSRic Aleshire 16794201a95eSRic Aleshire mnt_tsl = mntzone->zone_slabel; 16804201a95eSRic Aleshire ASSERT(mnt_tsl != NULL); 16814201a95eSRic Aleshire label_hold(mnt_tsl); 16824201a95eSRic Aleshire mnt_sl = label2bslabel(mnt_tsl); 16834201a95eSRic Aleshire 16844201a95eSRic Aleshire if (strcasecmp(ds_hexsl, ZFS_MLSLABEL_DEFAULT) == 0) { 16854201a95eSRic Aleshire /* 16864201a95eSRic Aleshire * The dataset doesn't have a real label, so fabricate one. 16874201a95eSRic Aleshire */ 16884201a95eSRic Aleshire char *str = NULL; 16894201a95eSRic Aleshire 16904201a95eSRic Aleshire if (l_to_str_internal(mnt_sl, &str) == 0 && 16913b2aab18SMatthew Ahrens dsl_prop_set_string(osname, 16923b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_MLSLABEL), 16933b2aab18SMatthew Ahrens ZPROP_SRC_LOCAL, str) == 0) 16944201a95eSRic Aleshire retv = 0; 16954201a95eSRic Aleshire if (str != NULL) 16964201a95eSRic Aleshire kmem_free(str, strlen(str) + 1); 16974201a95eSRic Aleshire } else if (hexstr_to_label(ds_hexsl, &ds_sl) == 0) { 16984201a95eSRic Aleshire /* 16994201a95eSRic Aleshire * Now compare labels to complete the MAC check. If the 17004201a95eSRic Aleshire * labels are equal then allow access. If the mountpoint 17014201a95eSRic Aleshire * label dominates the dataset label, allow readonly access. 17024201a95eSRic Aleshire * Otherwise, access is denied. 17034201a95eSRic Aleshire */ 17044201a95eSRic Aleshire if (blequal(mnt_sl, &ds_sl)) 17054201a95eSRic Aleshire retv = 0; 17064201a95eSRic Aleshire else if (bldominates(mnt_sl, &ds_sl)) { 17074201a95eSRic Aleshire vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); 17084201a95eSRic Aleshire retv = 0; 17094201a95eSRic Aleshire } 17104201a95eSRic Aleshire } 17114201a95eSRic Aleshire 17124201a95eSRic Aleshire label_rele(mnt_tsl); 17134201a95eSRic Aleshire zone_rele(mntzone); 17144201a95eSRic Aleshire return (retv); 17154201a95eSRic Aleshire } 17164201a95eSRic Aleshire 171730c304d9SJoshua M. Clulow /* 171830c304d9SJoshua M. Clulow * Load a string-valued boot property and attempt to convert it to a 64-bit 171930c304d9SJoshua M. Clulow * unsigned integer. If the value is not present, or the conversion fails, 172030c304d9SJoshua M. Clulow * return the provided default value. 172130c304d9SJoshua M. Clulow */ 172230c304d9SJoshua M. Clulow static uint64_t 172330c304d9SJoshua M. Clulow spa_get_bootprop_uint64(const char *name, uint64_t defval) 172430c304d9SJoshua M. Clulow { 172530c304d9SJoshua M. Clulow char *propval; 172630c304d9SJoshua M. Clulow u_longlong_t r; 172730c304d9SJoshua M. Clulow int e; 172830c304d9SJoshua M. Clulow 172930c304d9SJoshua M. Clulow if ((propval = spa_get_bootprop(name)) == NULL) { 173030c304d9SJoshua M. Clulow /* 173130c304d9SJoshua M. Clulow * The property does not exist. 173230c304d9SJoshua M. Clulow */ 173330c304d9SJoshua M. Clulow return (defval); 173430c304d9SJoshua M. Clulow } 173530c304d9SJoshua M. Clulow 173630c304d9SJoshua M. Clulow e = ddi_strtoull(propval, NULL, 10, &r); 173730c304d9SJoshua M. Clulow 173830c304d9SJoshua M. Clulow spa_free_bootprop(propval); 173930c304d9SJoshua M. Clulow 174030c304d9SJoshua M. Clulow /* 174130c304d9SJoshua M. Clulow * If the conversion succeeded, return the value. If there was any 174230c304d9SJoshua M. Clulow * kind of failure, just return the default value. 174330c304d9SJoshua M. Clulow */ 174430c304d9SJoshua M. Clulow return (e == 0 ? r : defval); 174530c304d9SJoshua M. Clulow } 174630c304d9SJoshua M. Clulow 1747ea8dc4b6Seschrock static int 1748ea8dc4b6Seschrock zfs_mountroot(vfs_t *vfsp, enum whymountroot why) 1749ea8dc4b6Seschrock { 1750ea8dc4b6Seschrock int error = 0; 1751ea8dc4b6Seschrock static int zfsrootdone = 0; 1752ea8dc4b6Seschrock zfsvfs_t *zfsvfs = NULL; 1753ea8dc4b6Seschrock znode_t *zp = NULL; 1754ea8dc4b6Seschrock vnode_t *vp = NULL; 1755e7cbe64fSgw char *zfs_bootfs; 1756051aabe6Staylor char *zfs_devid; 175730c304d9SJoshua M. Clulow uint64_t zfs_bootpool; 175830c304d9SJoshua M. Clulow uint64_t zfs_bootvdev; 1759ea8dc4b6Seschrock 1760ea8dc4b6Seschrock ASSERT(vfsp); 1761ea8dc4b6Seschrock 1762ea8dc4b6Seschrock /* 1763b1b8ab34Slling * The filesystem that we mount as root is defined in the 1764e7cbe64fSgw * boot property "zfs-bootfs" with a format of 1765e7cbe64fSgw * "poolname/root-dataset-objnum". 1766ea8dc4b6Seschrock */ 1767ea8dc4b6Seschrock if (why == ROOT_INIT) { 1768ea8dc4b6Seschrock if (zfsrootdone++) 1769be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 177030c304d9SJoshua M. Clulow 1771e7cbe64fSgw /* 1772e7cbe64fSgw * the process of doing a spa_load will require the 1773e7cbe64fSgw * clock to be set before we could (for example) do 1774e7cbe64fSgw * something better by looking at the timestamp on 1775e7cbe64fSgw * an uberblock, so just set it to -1. 1776e7cbe64fSgw */ 1777e7cbe64fSgw clkset(-1); 1778fa9e4066Sahrens 1779051aabe6Staylor if ((zfs_bootfs = spa_get_bootprop("zfs-bootfs")) == NULL) { 1780051aabe6Staylor cmn_err(CE_NOTE, "spa_get_bootfs: can not get " 1781051aabe6Staylor "bootfs name"); 1782be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1783986fd29aSsetje } 1784051aabe6Staylor zfs_devid = spa_get_bootprop("diskdevid"); 178530c304d9SJoshua M. Clulow 178630c304d9SJoshua M. Clulow /* 178730c304d9SJoshua M. Clulow * The boot loader may also provide us with the GUID for both 178830c304d9SJoshua M. Clulow * the pool and the nominated boot vdev. A GUID value of 0 is 178930c304d9SJoshua M. Clulow * explicitly invalid (see "spa_change_guid()"), so we use this 179030c304d9SJoshua M. Clulow * as a sentinel value when no GUID is present. 179130c304d9SJoshua M. Clulow */ 179230c304d9SJoshua M. Clulow zfs_bootpool = spa_get_bootprop_uint64("zfs-bootpool", 0); 179330c304d9SJoshua M. Clulow zfs_bootvdev = spa_get_bootprop_uint64("zfs-bootvdev", 0); 179430c304d9SJoshua M. Clulow 179530c304d9SJoshua M. Clulow /* 179630c304d9SJoshua M. Clulow * Initialise the early boot device rescan mechanism. A scan 179730c304d9SJoshua M. Clulow * will not actually be performed unless we need to do so in 179830c304d9SJoshua M. Clulow * order to find the correct /devices path for a relocated 179930c304d9SJoshua M. Clulow * device. 180030c304d9SJoshua M. Clulow */ 180130c304d9SJoshua M. Clulow vdev_disk_preroot_init(); 180230c304d9SJoshua M. Clulow 180330c304d9SJoshua M. Clulow error = spa_import_rootpool(rootfs.bo_name, zfs_devid, 180430c304d9SJoshua M. Clulow zfs_bootpool, zfs_bootvdev); 180530c304d9SJoshua M. Clulow 180630c304d9SJoshua M. Clulow spa_free_bootprop(zfs_devid); 180730c304d9SJoshua M. Clulow 180830c304d9SJoshua M. Clulow if (error != 0) { 1809051aabe6Staylor spa_free_bootprop(zfs_bootfs); 181030c304d9SJoshua M. Clulow vdev_disk_preroot_fini(); 1811051aabe6Staylor cmn_err(CE_NOTE, "spa_import_rootpool: error %d", 1812e7cbe64fSgw error); 1813e7cbe64fSgw return (error); 1814e7cbe64fSgw } 181530c304d9SJoshua M. Clulow 1816e7cbe64fSgw if (error = zfs_parse_bootfs(zfs_bootfs, rootfs.bo_name)) { 1817051aabe6Staylor spa_free_bootprop(zfs_bootfs); 181830c304d9SJoshua M. Clulow vdev_disk_preroot_fini(); 1819051aabe6Staylor cmn_err(CE_NOTE, "zfs_parse_bootfs: error %d", 1820e7cbe64fSgw error); 1821b1b8ab34Slling return (error); 1822e7cbe64fSgw } 1823e7cbe64fSgw 1824051aabe6Staylor spa_free_bootprop(zfs_bootfs); 182530c304d9SJoshua M. Clulow vdev_disk_preroot_fini(); 1826fa9e4066Sahrens 1827ea8dc4b6Seschrock if (error = vfs_lock(vfsp)) 1828ea8dc4b6Seschrock return (error); 1829fa9e4066Sahrens 1830088f3894Sahrens if (error = zfs_domount(vfsp, rootfs.bo_name)) { 1831051aabe6Staylor cmn_err(CE_NOTE, "zfs_domount: error %d", error); 1832ea8dc4b6Seschrock goto out; 1833e7cbe64fSgw } 1834ea8dc4b6Seschrock 1835ea8dc4b6Seschrock zfsvfs = (zfsvfs_t *)vfsp->vfs_data; 1836ea8dc4b6Seschrock ASSERT(zfsvfs); 1837e7cbe64fSgw if (error = zfs_zget(zfsvfs, zfsvfs->z_root, &zp)) { 1838051aabe6Staylor cmn_err(CE_NOTE, "zfs_zget: error %d", error); 1839ea8dc4b6Seschrock goto out; 1840e7cbe64fSgw } 1841ea8dc4b6Seschrock 1842ea8dc4b6Seschrock vp = ZTOV(zp); 1843ea8dc4b6Seschrock mutex_enter(&vp->v_lock); 1844ea8dc4b6Seschrock vp->v_flag |= VROOT; 1845ea8dc4b6Seschrock mutex_exit(&vp->v_lock); 1846ea8dc4b6Seschrock rootvp = vp; 1847ea8dc4b6Seschrock 1848ea8dc4b6Seschrock /* 184940d3dfe1Smarks * Leave rootvp held. The root file system is never unmounted. 1850ea8dc4b6Seschrock */ 1851ea8dc4b6Seschrock 1852ea8dc4b6Seschrock vfs_add((struct vnode *)0, vfsp, 1853ea8dc4b6Seschrock (vfsp->vfs_flag & VFS_RDONLY) ? MS_RDONLY : 0); 1854ea8dc4b6Seschrock out: 1855ea8dc4b6Seschrock vfs_unlock(vfsp); 1856e7cbe64fSgw return (error); 1857ea8dc4b6Seschrock } else if (why == ROOT_REMOUNT) { 1858ea8dc4b6Seschrock readonly_changed_cb(vfsp->vfs_data, B_FALSE); 1859ea8dc4b6Seschrock vfsp->vfs_flag |= VFS_REMOUNT; 1860b510d378Slling 1861b510d378Slling /* refresh mount options */ 1862b510d378Slling zfs_unregister_callbacks(vfsp->vfs_data); 1863b510d378Slling return (zfs_register_callbacks(vfsp)); 1864b510d378Slling 1865ea8dc4b6Seschrock } else if (why == ROOT_UNMOUNT) { 1866ea8dc4b6Seschrock zfs_unregister_callbacks((zfsvfs_t *)vfsp->vfs_data); 1867ea8dc4b6Seschrock (void) zfs_sync(vfsp, 0, 0); 1868ea8dc4b6Seschrock return (0); 1869ea8dc4b6Seschrock } 1870ea8dc4b6Seschrock 1871ea8dc4b6Seschrock /* 1872ea8dc4b6Seschrock * if "why" is equal to anything else other than ROOT_INIT, 1873ea8dc4b6Seschrock * ROOT_REMOUNT, or ROOT_UNMOUNT, we do not support it. 1874ea8dc4b6Seschrock */ 1875be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 1876ea8dc4b6Seschrock } 1877ea8dc4b6Seschrock 1878ea8dc4b6Seschrock /*ARGSUSED*/ 1879ea8dc4b6Seschrock static int 1880ea8dc4b6Seschrock zfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) 1881ea8dc4b6Seschrock { 1882ea8dc4b6Seschrock char *osname; 1883ea8dc4b6Seschrock pathname_t spn; 1884ea8dc4b6Seschrock int error = 0; 1885ea8dc4b6Seschrock uio_seg_t fromspace = (uap->flags & MS_SYSSPACE) ? 1886b1b8ab34Slling UIO_SYSSPACE : UIO_USERSPACE; 1887ea8dc4b6Seschrock int canwrite; 1888ea8dc4b6Seschrock 1889ea8dc4b6Seschrock if (mvp->v_type != VDIR) 1890be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTDIR)); 1891ea8dc4b6Seschrock 1892ea8dc4b6Seschrock mutex_enter(&mvp->v_lock); 1893ea8dc4b6Seschrock if ((uap->flags & MS_REMOUNT) == 0 && 1894ea8dc4b6Seschrock (uap->flags & MS_OVERLAY) == 0 && 1895ea8dc4b6Seschrock (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { 1896ea8dc4b6Seschrock mutex_exit(&mvp->v_lock); 1897be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 1898ea8dc4b6Seschrock } 1899ea8dc4b6Seschrock mutex_exit(&mvp->v_lock); 1900ea8dc4b6Seschrock 1901ea8dc4b6Seschrock /* 1902ea8dc4b6Seschrock * ZFS does not support passing unparsed data in via MS_DATA. 1903ea8dc4b6Seschrock * Users should use the MS_OPTIONSTR interface; this means 1904ea8dc4b6Seschrock * that all option parsing is already done and the options struct 1905ea8dc4b6Seschrock * can be interrogated. 1906ea8dc4b6Seschrock */ 1907ea8dc4b6Seschrock if ((uap->flags & MS_DATA) && uap->datalen > 0) 1908be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1909ea8dc4b6Seschrock 1910ea8dc4b6Seschrock /* 1911ea8dc4b6Seschrock * Get the objset name (the "special" mount argument). 1912ea8dc4b6Seschrock */ 1913ea8dc4b6Seschrock if (error = pn_get(uap->spec, fromspace, &spn)) 1914ea8dc4b6Seschrock return (error); 1915ea8dc4b6Seschrock 1916ea8dc4b6Seschrock osname = spn.pn_path; 1917ea8dc4b6Seschrock 1918ecd6cf80Smarks /* 1919ecd6cf80Smarks * Check for mount privilege? 1920ecd6cf80Smarks * 1921ecd6cf80Smarks * If we don't have privilege then see if 1922ecd6cf80Smarks * we have local permission to allow it 1923ecd6cf80Smarks */ 1924ecd6cf80Smarks error = secpolicy_fs_mount(cr, mvp, vfsp); 1925ecd6cf80Smarks if (error) { 192698679b56SMark Shellenbaum if (dsl_deleg_access(osname, ZFS_DELEG_PERM_MOUNT, cr) == 0) { 1927ecd6cf80Smarks vattr_t vattr; 1928ecd6cf80Smarks 1929ecd6cf80Smarks /* 1930ecd6cf80Smarks * Make sure user is the owner of the mount point 1931ecd6cf80Smarks * or has sufficient privileges. 1932ecd6cf80Smarks */ 1933ecd6cf80Smarks 1934ecd6cf80Smarks vattr.va_mask = AT_UID; 1935ecd6cf80Smarks 193698679b56SMark Shellenbaum if (VOP_GETATTR(mvp, &vattr, 0, cr, NULL)) { 1937ecd6cf80Smarks goto out; 1938ecd6cf80Smarks } 1939ecd6cf80Smarks 19402459a9eaSmarks if (secpolicy_vnode_owner(cr, vattr.va_uid) != 0 && 19412459a9eaSmarks VOP_ACCESS(mvp, VWRITE, 0, cr, NULL) != 0) { 1942ecd6cf80Smarks goto out; 1943ecd6cf80Smarks } 1944ecd6cf80Smarks secpolicy_fs_mount_clearopts(cr, vfsp); 1945ecd6cf80Smarks } else { 1946ecd6cf80Smarks goto out; 1947ecd6cf80Smarks } 1948ecd6cf80Smarks } 1949ea8dc4b6Seschrock 1950ea8dc4b6Seschrock /* 1951ea8dc4b6Seschrock * Refuse to mount a filesystem if we are in a local zone and the 1952ea8dc4b6Seschrock * dataset is not visible. 1953ea8dc4b6Seschrock */ 1954ea8dc4b6Seschrock if (!INGLOBALZONE(curproc) && 1955ea8dc4b6Seschrock (!zone_dataset_visible(osname, &canwrite) || !canwrite)) { 1956be6fd75aSMatthew Ahrens error = SET_ERROR(EPERM); 1957ea8dc4b6Seschrock goto out; 1958ea8dc4b6Seschrock } 1959ea8dc4b6Seschrock 19604201a95eSRic Aleshire error = zfs_mount_label_policy(vfsp, osname); 19614201a95eSRic Aleshire if (error) 19624201a95eSRic Aleshire goto out; 19634201a95eSRic Aleshire 1964b510d378Slling /* 1965b510d378Slling * When doing a remount, we simply refresh our temporary properties 1966b510d378Slling * according to those options set in the current VFS options. 1967b510d378Slling */ 1968b510d378Slling if (uap->flags & MS_REMOUNT) { 1969b510d378Slling /* refresh mount options */ 1970b510d378Slling zfs_unregister_callbacks(vfsp->vfs_data); 1971b510d378Slling error = zfs_register_callbacks(vfsp); 1972b510d378Slling goto out; 1973b510d378Slling } 1974b510d378Slling 1975088f3894Sahrens error = zfs_domount(vfsp, osname); 1976ea8dc4b6Seschrock 1977142ae85dSChris Kirby /* 1978142ae85dSChris Kirby * Add an extra VFS_HOLD on our parent vfs so that it can't 1979142ae85dSChris Kirby * disappear due to a forced unmount. 1980142ae85dSChris Kirby */ 1981984a131bSChris Kirby if (error == 0 && ((zfsvfs_t *)vfsp->vfs_data)->z_issnap) 1982142ae85dSChris Kirby VFS_HOLD(mvp->v_vfsp); 1983142ae85dSChris Kirby 1984ea8dc4b6Seschrock out: 1985fa9e4066Sahrens pn_free(&spn); 1986fa9e4066Sahrens return (error); 1987fa9e4066Sahrens } 1988fa9e4066Sahrens 1989fa9e4066Sahrens static int 1990fa9e4066Sahrens zfs_statvfs(vfs_t *vfsp, struct statvfs64 *statp) 1991fa9e4066Sahrens { 1992fa9e4066Sahrens zfsvfs_t *zfsvfs = vfsp->vfs_data; 1993fa9e4066Sahrens dev32_t d32; 1994a2eea2e1Sahrens uint64_t refdbytes, availbytes, usedobjs, availobjs; 1995f67950b2SNasf-Fan int err = 0; 1996fa9e4066Sahrens 1997fa9e4066Sahrens ZFS_ENTER(zfsvfs); 1998fa9e4066Sahrens 1999a2eea2e1Sahrens dmu_objset_space(zfsvfs->z_os, 2000a2eea2e1Sahrens &refdbytes, &availbytes, &usedobjs, &availobjs); 2001fa9e4066Sahrens 2002fa9e4066Sahrens /* 2003fa9e4066Sahrens * The underlying storage pool actually uses multiple block sizes. 2004fa9e4066Sahrens * We report the fragsize as the smallest block size we support, 2005fa9e4066Sahrens * and we report our blocksize as the filesystem's maximum blocksize. 2006fa9e4066Sahrens */ 2007fa9e4066Sahrens statp->f_frsize = 1UL << SPA_MINBLOCKSHIFT; 2008fa9e4066Sahrens statp->f_bsize = zfsvfs->z_max_blksz; 2009fa9e4066Sahrens 2010fa9e4066Sahrens /* 2011fa9e4066Sahrens * The following report "total" blocks of various kinds in the 2012fa9e4066Sahrens * file system, but reported in terms of f_frsize - the 2013fa9e4066Sahrens * "fragment" size. 2014fa9e4066Sahrens */ 2015fa9e4066Sahrens 2016a2eea2e1Sahrens statp->f_blocks = (refdbytes + availbytes) >> SPA_MINBLOCKSHIFT; 2017a2eea2e1Sahrens statp->f_bfree = availbytes >> SPA_MINBLOCKSHIFT; 2018fa9e4066Sahrens statp->f_bavail = statp->f_bfree; /* no root reservation */ 2019fa9e4066Sahrens 2020fa9e4066Sahrens /* 2021fa9e4066Sahrens * statvfs() should really be called statufs(), because it assumes 2022fa9e4066Sahrens * static metadata. ZFS doesn't preallocate files, so the best 2023fa9e4066Sahrens * we can do is report the max that could possibly fit in f_files, 2024fa9e4066Sahrens * and that minus the number actually used in f_ffree. 2025fa9e4066Sahrens * For f_ffree, report the smaller of the number of object available 2026fa9e4066Sahrens * and the number of blocks (each object will take at least a block). 2027fa9e4066Sahrens */ 2028a2eea2e1Sahrens statp->f_ffree = MIN(availobjs, statp->f_bfree); 2029fa9e4066Sahrens statp->f_favail = statp->f_ffree; /* no "root reservation" */ 2030a2eea2e1Sahrens statp->f_files = statp->f_ffree + usedobjs; 2031fa9e4066Sahrens 2032fa9e4066Sahrens (void) cmpldev(&d32, vfsp->vfs_dev); 2033fa9e4066Sahrens statp->f_fsid = d32; 2034fa9e4066Sahrens 2035fa9e4066Sahrens /* 2036fa9e4066Sahrens * We're a zfs filesystem. 2037fa9e4066Sahrens */ 2038fa9e4066Sahrens (void) strcpy(statp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name); 2039fa9e4066Sahrens 2040a5be7ebbSmarks statp->f_flag = vf_to_stf(vfsp->vfs_flag); 2041fa9e4066Sahrens 20429adfa60dSMatthew Ahrens statp->f_namemax = MAXNAMELEN - 1; 2043fa9e4066Sahrens 2044fa9e4066Sahrens /* 2045fa9e4066Sahrens * We have all of 32 characters to stuff a string here. 2046fa9e4066Sahrens * Is there anything useful we could/should provide? 2047fa9e4066Sahrens */ 2048fa9e4066Sahrens bzero(statp->f_fstr, sizeof (statp->f_fstr)); 2049fa9e4066Sahrens 2050f67950b2SNasf-Fan if (dmu_objset_projectquota_enabled(zfsvfs->z_os) && 2051f67950b2SNasf-Fan dmu_objset_projectquota_present(zfsvfs->z_os)) { 2052f67950b2SNasf-Fan znode_t *zp; 2053f67950b2SNasf-Fan 2054f67950b2SNasf-Fan /* 2055f67950b2SNasf-Fan * In ZoL, zfs_statvfs is passed a Linux dentry (directory 2056f67950b2SNasf-Fan * entry), instead of a vfsp. The ZoL code uses the dentry 2057f67950b2SNasf-Fan * to get the znode from the dentry's inode. This represents 2058f67950b2SNasf-Fan * whatever filename was passed to the user-level statvfs 2059f67950b2SNasf-Fan * syscall. 2060f67950b2SNasf-Fan * 2061f67950b2SNasf-Fan * We're using the VFS root znode here, so this represents a 2062f67950b2SNasf-Fan * potential difference from ZoL. 2063f67950b2SNasf-Fan */ 2064f67950b2SNasf-Fan if (zfs_zget(zfsvfs, zfsvfs->z_root, &zp) == 0) { 2065f67950b2SNasf-Fan uint32_t bshift = ddi_fls(statp->f_bsize) - 1; 2066f67950b2SNasf-Fan 2067f67950b2SNasf-Fan if (zp->z_pflags & ZFS_PROJINHERIT && zp->z_projid && 2068f67950b2SNasf-Fan zpl_is_valid_projid(zp->z_projid)) 2069f67950b2SNasf-Fan err = zfs_statfs_project(zfsvfs, zp, statp, 2070f67950b2SNasf-Fan bshift); 2071f67950b2SNasf-Fan VN_RELE(ZTOV(zp)); 2072f67950b2SNasf-Fan } 2073f67950b2SNasf-Fan } 2074f67950b2SNasf-Fan 2075fa9e4066Sahrens ZFS_EXIT(zfsvfs); 2076f67950b2SNasf-Fan return (err); 2077fa9e4066Sahrens } 2078fa9e4066Sahrens 2079fa9e4066Sahrens static int 2080fa9e4066Sahrens zfs_root(vfs_t *vfsp, vnode_t **vpp) 2081fa9e4066Sahrens { 2082fa9e4066Sahrens zfsvfs_t *zfsvfs = vfsp->vfs_data; 2083fa9e4066Sahrens znode_t *rootzp; 2084fa9e4066Sahrens int error; 2085fa9e4066Sahrens 2086fa9e4066Sahrens ZFS_ENTER(zfsvfs); 2087fa9e4066Sahrens 2088fa9e4066Sahrens error = zfs_zget(zfsvfs, zfsvfs->z_root, &rootzp); 2089fa9e4066Sahrens if (error == 0) 2090fa9e4066Sahrens *vpp = ZTOV(rootzp); 2091fa9e4066Sahrens 2092fa9e4066Sahrens ZFS_EXIT(zfsvfs); 2093fa9e4066Sahrens return (error); 2094fa9e4066Sahrens } 2095fa9e4066Sahrens 2096f18faf3fSek /* 2097f18faf3fSek * Teardown the zfsvfs::z_os. 2098f18faf3fSek * 2099eb721827SAlek Pinchuk * Note, if 'unmounting' is FALSE, we return with the 'z_teardown_lock' 2100f18faf3fSek * and 'z_teardown_inactive_lock' held. 2101f18faf3fSek */ 2102f18faf3fSek static int 2103f18faf3fSek zfsvfs_teardown(zfsvfs_t *zfsvfs, boolean_t unmounting) 2104f18faf3fSek { 2105874395d5Smaybee znode_t *zp; 2106f18faf3fSek 2107c5832a53SAlek Pinchuk zfs_unlinked_drain_stop_wait(zfsvfs); 2108c5832a53SAlek Pinchuk 2109c9030f6cSAlexander Motin rrm_enter(&zfsvfs->z_teardown_lock, RW_WRITER, FTAG); 2110f18faf3fSek 2111f18faf3fSek if (!unmounting) { 2112f18faf3fSek /* 2113f18faf3fSek * We purge the parent filesystem's vfsp as the parent 2114f18faf3fSek * filesystem and all of its snapshots have their vnode's 2115f18faf3fSek * v_vfsp set to the parent's filesystem's vfsp. Note, 2116f18faf3fSek * 'z_parent' is self referential for non-snapshots. 2117f18faf3fSek */ 2118f18faf3fSek (void) dnlc_purge_vfsp(zfsvfs->z_parent->z_vfs, 0); 2119f18faf3fSek } 2120f18faf3fSek 2121f18faf3fSek /* 2122f18faf3fSek * Close the zil. NB: Can't close the zil while zfs_inactive 2123f18faf3fSek * threads are blocked as zil_close can call zfs_inactive. 2124f18faf3fSek */ 2125f18faf3fSek if (zfsvfs->z_log) { 2126f18faf3fSek zil_close(zfsvfs->z_log); 2127f18faf3fSek zfsvfs->z_log = NULL; 2128f18faf3fSek } 2129f18faf3fSek 2130f18faf3fSek rw_enter(&zfsvfs->z_teardown_inactive_lock, RW_WRITER); 2131f18faf3fSek 2132f18faf3fSek /* 2133f18faf3fSek * If we are not unmounting (ie: online recv) and someone already 2134f18faf3fSek * unmounted this file system while we were doing the switcheroo, 2135f18faf3fSek * or a reopen of z_os failed then just bail out now. 2136f18faf3fSek */ 2137f18faf3fSek if (!unmounting && (zfsvfs->z_unmounted || zfsvfs->z_os == NULL)) { 2138f18faf3fSek rw_exit(&zfsvfs->z_teardown_inactive_lock); 2139c9030f6cSAlexander Motin rrm_exit(&zfsvfs->z_teardown_lock, FTAG); 2140be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 2141f18faf3fSek } 2142f18faf3fSek 2143f18faf3fSek /* 2144f18faf3fSek * At this point there are no vops active, and any new vops will 2145f18faf3fSek * fail with EIO since we have z_teardown_lock for writer (only 2146f18faf3fSek * relavent for forced unmount). 2147f18faf3fSek * 2148f18faf3fSek * Release all holds on dbufs. 2149f18faf3fSek */ 2150f18faf3fSek mutex_enter(&zfsvfs->z_znodes_lock); 2151874395d5Smaybee for (zp = list_head(&zfsvfs->z_all_znodes); zp != NULL; 2152874395d5Smaybee zp = list_next(&zfsvfs->z_all_znodes, zp)) 21530a586ceaSMark Shellenbaum if (zp->z_sa_hdl) { 2154874395d5Smaybee ASSERT(ZTOV(zp)->v_count > 0); 2155874395d5Smaybee zfs_znode_dmu_fini(zp); 2156f18faf3fSek } 2157f18faf3fSek mutex_exit(&zfsvfs->z_znodes_lock); 2158f18faf3fSek 2159f18faf3fSek /* 2160f18faf3fSek * If we are unmounting, set the unmounted flag and let new vops 2161f18faf3fSek * unblock. zfs_inactive will have the unmounted behavior, and all 2162f18faf3fSek * other vops will fail with EIO. 2163f18faf3fSek */ 2164f18faf3fSek if (unmounting) { 2165f18faf3fSek zfsvfs->z_unmounted = B_TRUE; 2166f18faf3fSek rw_exit(&zfsvfs->z_teardown_inactive_lock); 2167eb721827SAlek Pinchuk rrm_exit(&zfsvfs->z_teardown_lock, FTAG); 2168f18faf3fSek } 2169f18faf3fSek 2170f18faf3fSek /* 2171f18faf3fSek * z_os will be NULL if there was an error in attempting to reopen 2172f18faf3fSek * zfsvfs, so just return as the properties had already been 2173f18faf3fSek * unregistered and cached data had been evicted before. 2174f18faf3fSek */ 2175f18faf3fSek if (zfsvfs->z_os == NULL) 2176f18faf3fSek return (0); 2177f18faf3fSek 2178f18faf3fSek /* 2179f18faf3fSek * Unregister properties. 2180f18faf3fSek */ 2181f18faf3fSek zfs_unregister_callbacks(zfsvfs); 2182f18faf3fSek 2183f18faf3fSek /* 2184f18faf3fSek * Evict cached data 2185f18faf3fSek */ 21862e2c1355SMatthew Ahrens if (dsl_dataset_is_dirty(dmu_objset_ds(zfsvfs->z_os)) && 21872e2c1355SMatthew Ahrens !(zfsvfs->z_vfs->vfs_flag & VFS_RDONLY)) 21882e2c1355SMatthew Ahrens txg_wait_synced(dmu_objset_pool(zfsvfs->z_os), 0); 21893b2aab18SMatthew Ahrens dmu_objset_evict_dbufs(zfsvfs->z_os); 2190f18faf3fSek 2191f18faf3fSek return (0); 2192f18faf3fSek } 2193f18faf3fSek 2194fa9e4066Sahrens /*ARGSUSED*/ 2195fa9e4066Sahrens static int 2196fa9e4066Sahrens zfs_umount(vfs_t *vfsp, int fflag, cred_t *cr) 2197fa9e4066Sahrens { 2198fa9e4066Sahrens zfsvfs_t *zfsvfs = vfsp->vfs_data; 2199f18faf3fSek objset_t *os; 2200fa9e4066Sahrens int ret; 2201fa9e4066Sahrens 2202ecd6cf80Smarks ret = secpolicy_fs_unmount(cr, vfsp); 2203ecd6cf80Smarks if (ret) { 220498679b56SMark Shellenbaum if (dsl_deleg_access((char *)refstr_value(vfsp->vfs_resource), 220598679b56SMark Shellenbaum ZFS_DELEG_PERM_MOUNT, cr)) 2206ecd6cf80Smarks return (ret); 2207ecd6cf80Smarks } 2208033f9833Sek 2209ed097989Sek /* 2210ed097989Sek * We purge the parent filesystem's vfsp as the parent filesystem 2211ed097989Sek * and all of its snapshots have their vnode's v_vfsp set to the 2212ed097989Sek * parent's filesystem's vfsp. Note, 'z_parent' is self 2213ed097989Sek * referential for non-snapshots. 2214ed097989Sek */ 2215ed097989Sek (void) dnlc_purge_vfsp(zfsvfs->z_parent->z_vfs, 0); 2216033f9833Sek 2217fa9e4066Sahrens /* 2218fa9e4066Sahrens * Unmount any snapshots mounted under .zfs before unmounting the 2219fa9e4066Sahrens * dataset itself. 2220fa9e4066Sahrens */ 2221fa9e4066Sahrens if (zfsvfs->z_ctldir != NULL && 2222ecd6cf80Smarks (ret = zfsctl_umount_snapshots(vfsp, fflag, cr)) != 0) { 2223fa9e4066Sahrens return (ret); 2224ecd6cf80Smarks } 2225fa9e4066Sahrens 222691ebeef5Sahrens if (!(fflag & MS_FORCE)) { 2227fa9e4066Sahrens /* 222891ebeef5Sahrens * Check the number of active vnodes in the file system. 222991ebeef5Sahrens * Our count is maintained in the vfs structure, but the 223091ebeef5Sahrens * number is off by 1 to indicate a hold on the vfs 223191ebeef5Sahrens * structure itself. 2232fa9e4066Sahrens */ 2233*b39b008fSAndy Fiddaman boolean_t draining; 2234*b39b008fSAndy Fiddaman uint_t thresh = 1; 2235*b39b008fSAndy Fiddaman 2236*b39b008fSAndy Fiddaman /* 2237*b39b008fSAndy Fiddaman * The '.zfs' directory maintains a reference of its own, and 2238*b39b008fSAndy Fiddaman * any active references underneath are reflected in the vnode 2239*b39b008fSAndy Fiddaman * count. Allow one additional reference for it. 2240*b39b008fSAndy Fiddaman */ 2241*b39b008fSAndy Fiddaman if (zfsvfs->z_ctldir != NULL) 2242*b39b008fSAndy Fiddaman thresh++; 2243*b39b008fSAndy Fiddaman 2244*b39b008fSAndy Fiddaman /* 2245*b39b008fSAndy Fiddaman * If it's running, the asynchronous unlinked drain task needs 2246*b39b008fSAndy Fiddaman * to be stopped before the number of active vnodes can be 2247*b39b008fSAndy Fiddaman * reliably checked. 2248*b39b008fSAndy Fiddaman */ 2249*b39b008fSAndy Fiddaman draining = zfsvfs->z_draining; 2250*b39b008fSAndy Fiddaman if (draining) 2251*b39b008fSAndy Fiddaman zfs_unlinked_drain_stop_wait(zfsvfs); 2252*b39b008fSAndy Fiddaman 2253*b39b008fSAndy Fiddaman if (vfsp->vfs_count > thresh || (zfsvfs->z_ctldir != NULL && 2254*b39b008fSAndy Fiddaman zfsvfs->z_ctldir->v_count > 1)) { 2255*b39b008fSAndy Fiddaman if (draining) { 2256*b39b008fSAndy Fiddaman /* If it was draining, restart the task */ 2257*b39b008fSAndy Fiddaman zfs_unlinked_drain(zfsvfs); 2258*b39b008fSAndy Fiddaman } 2259*b39b008fSAndy Fiddaman return (SET_ERROR(EBUSY)); 2260fa9e4066Sahrens } 226191ebeef5Sahrens } 2262fa9e4066Sahrens 226391ebeef5Sahrens vfsp->vfs_flag |= VFS_UNMOUNTED; 226491ebeef5Sahrens 2265f18faf3fSek VERIFY(zfsvfs_teardown(zfsvfs, B_TRUE) == 0); 2266f18faf3fSek os = zfsvfs->z_os; 226791ebeef5Sahrens 226891ebeef5Sahrens /* 2269f18faf3fSek * z_os will be NULL if there was an error in 2270f18faf3fSek * attempting to reopen zfsvfs. 227191ebeef5Sahrens */ 2272f18faf3fSek if (os != NULL) { 2273f18faf3fSek /* 2274f18faf3fSek * Unset the objset user_ptr. 2275f18faf3fSek */ 2276503ad85cSMatthew Ahrens mutex_enter(&os->os_user_ptr_lock); 2277f18faf3fSek dmu_objset_set_user(os, NULL); 2278503ad85cSMatthew Ahrens mutex_exit(&os->os_user_ptr_lock); 227991ebeef5Sahrens 2280f18faf3fSek /* 2281745cd3c5Smaybee * Finally release the objset 2282f18faf3fSek */ 2283eb633035STom Caputi dmu_objset_disown(os, B_TRUE, zfsvfs); 228491ebeef5Sahrens } 228591ebeef5Sahrens 228691ebeef5Sahrens /* 228791ebeef5Sahrens * We can now safely destroy the '.zfs' directory node. 228891ebeef5Sahrens */ 228991ebeef5Sahrens if (zfsvfs->z_ctldir != NULL) 229091ebeef5Sahrens zfsctl_destroy(zfsvfs); 2291fa9e4066Sahrens 2292fa9e4066Sahrens return (0); 2293fa9e4066Sahrens } 2294fa9e4066Sahrens 2295fa9e4066Sahrens static int 2296fa9e4066Sahrens zfs_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp) 2297fa9e4066Sahrens { 2298fa9e4066Sahrens zfsvfs_t *zfsvfs = vfsp->vfs_data; 2299fa9e4066Sahrens znode_t *zp; 2300fa9e4066Sahrens uint64_t object = 0; 2301fa9e4066Sahrens uint64_t fid_gen = 0; 2302fa9e4066Sahrens uint64_t gen_mask; 2303fa9e4066Sahrens uint64_t zp_gen; 23048bf394f1STom Caputi int i, err; 2305fa9e4066Sahrens 2306fa9e4066Sahrens *vpp = NULL; 2307fa9e4066Sahrens 2308fa9e4066Sahrens ZFS_ENTER(zfsvfs); 2309fa9e4066Sahrens 2310fa9e4066Sahrens if (fidp->fid_len == LONG_FID_LEN) { 2311fa9e4066Sahrens zfid_long_t *zlfid = (zfid_long_t *)fidp; 2312fa9e4066Sahrens uint64_t objsetid = 0; 2313fa9e4066Sahrens uint64_t setgen = 0; 2314fa9e4066Sahrens 2315fa9e4066Sahrens for (i = 0; i < sizeof (zlfid->zf_setid); i++) 2316fa9e4066Sahrens objsetid |= ((uint64_t)zlfid->zf_setid[i]) << (8 * i); 2317fa9e4066Sahrens 2318fa9e4066Sahrens for (i = 0; i < sizeof (zlfid->zf_setgen); i++) 2319fa9e4066Sahrens setgen |= ((uint64_t)zlfid->zf_setgen[i]) << (8 * i); 2320fa9e4066Sahrens 2321fa9e4066Sahrens ZFS_EXIT(zfsvfs); 2322fa9e4066Sahrens 2323fa9e4066Sahrens err = zfsctl_lookup_objset(vfsp, objsetid, &zfsvfs); 2324fa9e4066Sahrens if (err) 2325be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 2326fa9e4066Sahrens ZFS_ENTER(zfsvfs); 2327fa9e4066Sahrens } 2328fa9e4066Sahrens 2329fa9e4066Sahrens if (fidp->fid_len == SHORT_FID_LEN || fidp->fid_len == LONG_FID_LEN) { 2330fa9e4066Sahrens zfid_short_t *zfid = (zfid_short_t *)fidp; 2331fa9e4066Sahrens 2332fa9e4066Sahrens for (i = 0; i < sizeof (zfid->zf_object); i++) 2333fa9e4066Sahrens object |= ((uint64_t)zfid->zf_object[i]) << (8 * i); 2334fa9e4066Sahrens 2335fa9e4066Sahrens for (i = 0; i < sizeof (zfid->zf_gen); i++) 2336fa9e4066Sahrens fid_gen |= ((uint64_t)zfid->zf_gen[i]) << (8 * i); 2337fa9e4066Sahrens } else { 2338fa9e4066Sahrens ZFS_EXIT(zfsvfs); 2339be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 2340fa9e4066Sahrens } 2341fa9e4066Sahrens 2342fa9e4066Sahrens /* A zero fid_gen means we are in the .zfs control directories */ 2343fa9e4066Sahrens if (fid_gen == 0 && 2344fa9e4066Sahrens (object == ZFSCTL_INO_ROOT || object == ZFSCTL_INO_SNAPDIR)) { 2345fa9e4066Sahrens *vpp = zfsvfs->z_ctldir; 2346fa9e4066Sahrens ASSERT(*vpp != NULL); 2347fa9e4066Sahrens if (object == ZFSCTL_INO_SNAPDIR) { 2348fa9e4066Sahrens VERIFY(zfsctl_root_lookup(*vpp, "snapshot", vpp, NULL, 2349da6c28aaSamw 0, NULL, NULL, NULL, NULL, NULL) == 0); 2350fa9e4066Sahrens } else { 2351fa9e4066Sahrens VN_HOLD(*vpp); 2352fa9e4066Sahrens } 2353fa9e4066Sahrens ZFS_EXIT(zfsvfs); 2354fa9e4066Sahrens return (0); 2355fa9e4066Sahrens } 2356fa9e4066Sahrens 2357fa9e4066Sahrens gen_mask = -1ULL >> (64 - 8 * i); 2358fa9e4066Sahrens 2359fa9e4066Sahrens dprintf("getting %llu [%u mask %llx]\n", object, fid_gen, gen_mask); 2360fa9e4066Sahrens if (err = zfs_zget(zfsvfs, object, &zp)) { 2361fa9e4066Sahrens ZFS_EXIT(zfsvfs); 2362fa9e4066Sahrens return (err); 2363fa9e4066Sahrens } 23640a586ceaSMark Shellenbaum (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_GEN(zfsvfs), &zp_gen, 23650a586ceaSMark Shellenbaum sizeof (uint64_t)); 23660a586ceaSMark Shellenbaum zp_gen = zp_gen & gen_mask; 2367fa9e4066Sahrens if (zp_gen == 0) 2368fa9e4066Sahrens zp_gen = 1; 2369893a6d32Sahrens if (zp->z_unlinked || zp_gen != fid_gen) { 2370fa9e4066Sahrens dprintf("znode gen (%u) != fid gen (%u)\n", zp_gen, fid_gen); 2371fa9e4066Sahrens VN_RELE(ZTOV(zp)); 2372fa9e4066Sahrens ZFS_EXIT(zfsvfs); 2373be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 2374fa9e4066Sahrens } 2375fa9e4066Sahrens 2376fa9e4066Sahrens *vpp = ZTOV(zp); 2377fa9e4066Sahrens ZFS_EXIT(zfsvfs); 2378fa9e4066Sahrens return (0); 2379fa9e4066Sahrens } 2380fa9e4066Sahrens 2381f18faf3fSek /* 2382f18faf3fSek * Block out VOPs and close zfsvfs_t::z_os 2383f18faf3fSek * 2384f18faf3fSek * Note, if successful, then we return with the 'z_teardown_lock' and 238591948b51SKeith M Wesolowski * 'z_teardown_inactive_lock' write held. We leave ownership of the underlying 238691948b51SKeith M Wesolowski * dataset and objset intact so that they can be atomically handed off during 238791948b51SKeith M Wesolowski * a subsequent rollback or recv operation and the resume thereafter. 2388f18faf3fSek */ 2389f18faf3fSek int 2390503ad85cSMatthew Ahrens zfs_suspend_fs(zfsvfs_t *zfsvfs) 2391f18faf3fSek { 2392f18faf3fSek int error; 2393f18faf3fSek 2394f18faf3fSek if ((error = zfsvfs_teardown(zfsvfs, B_FALSE)) != 0) 2395f18faf3fSek return (error); 2396f18faf3fSek 2397f18faf3fSek return (0); 2398f18faf3fSek } 2399f18faf3fSek 2400f18faf3fSek /* 240191948b51SKeith M Wesolowski * Rebuild SA and release VOPs. Note that ownership of the underlying dataset 240291948b51SKeith M Wesolowski * is an invariant across any of the operations that can be performed while the 240391948b51SKeith M Wesolowski * filesystem was suspended. Whether it succeeded or failed, the preconditions 240491948b51SKeith M Wesolowski * are the same: the relevant objset and associated dataset are owned by 240591948b51SKeith M Wesolowski * zfsvfs, held, and long held on entry. 2406f18faf3fSek */ 2407f18faf3fSek int 2408690041b9SAndriy Gapon zfs_resume_fs(zfsvfs_t *zfsvfs, dsl_dataset_t *ds) 2409f18faf3fSek { 241044bffe01SMark Shellenbaum int err; 241191948b51SKeith M Wesolowski znode_t *zp; 2412f18faf3fSek 2413c9030f6cSAlexander Motin ASSERT(RRM_WRITE_HELD(&zfsvfs->z_teardown_lock)); 2414f18faf3fSek ASSERT(RW_WRITE_HELD(&zfsvfs->z_teardown_inactive_lock)); 2415f18faf3fSek 241691948b51SKeith M Wesolowski /* 2417690041b9SAndriy Gapon * We already own this, so just update the objset_t, as the one we 2418690041b9SAndriy Gapon * had before may have been evicted. 241991948b51SKeith M Wesolowski */ 24201fdcbd00SMatthew Ahrens objset_t *os; 2421690041b9SAndriy Gapon VERIFY3P(ds->ds_owner, ==, zfsvfs); 2422690041b9SAndriy Gapon VERIFY(dsl_dataset_long_held(ds)); 2423690041b9SAndriy Gapon VERIFY0(dmu_objset_from_ds(ds, &os)); 24240a586ceaSMark Shellenbaum 24251fdcbd00SMatthew Ahrens err = zfsvfs_init(zfsvfs, os); 24261fdcbd00SMatthew Ahrens if (err != 0) 242791948b51SKeith M Wesolowski goto bail; 2428f18faf3fSek 242991948b51SKeith M Wesolowski VERIFY(zfsvfs_setup(zfsvfs, B_FALSE) == 0); 2430f18faf3fSek 243191948b51SKeith M Wesolowski zfs_set_fuid_feature(zfsvfs); 243244bffe01SMark Shellenbaum 243391948b51SKeith M Wesolowski /* 243491948b51SKeith M Wesolowski * Attempt to re-establish all the active znodes with 243591948b51SKeith M Wesolowski * their dbufs. If a zfs_rezget() fails, then we'll let 243691948b51SKeith M Wesolowski * any potential callers discover that via ZFS_ENTER_VERIFY_VP 243791948b51SKeith M Wesolowski * when they try to use their znode. 243891948b51SKeith M Wesolowski */ 243991948b51SKeith M Wesolowski mutex_enter(&zfsvfs->z_znodes_lock); 244091948b51SKeith M Wesolowski for (zp = list_head(&zfsvfs->z_all_znodes); zp; 244191948b51SKeith M Wesolowski zp = list_next(&zfsvfs->z_all_znodes, zp)) { 244291948b51SKeith M Wesolowski (void) zfs_rezget(zp); 2443f18faf3fSek } 244491948b51SKeith M Wesolowski mutex_exit(&zfsvfs->z_znodes_lock); 2445f18faf3fSek 2446c5832a53SAlek Pinchuk if (((zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) == 0) && 2447c5832a53SAlek Pinchuk !zfsvfs->z_unmounted) { 2448c5832a53SAlek Pinchuk /* 2449c5832a53SAlek Pinchuk * zfs_suspend_fs() could have interrupted freeing 2450c5832a53SAlek Pinchuk * of dnodes. We need to restart this freeing so 2451c5832a53SAlek Pinchuk * that we don't "leak" the space. 2452c5832a53SAlek Pinchuk */ 2453c5832a53SAlek Pinchuk zfs_unlinked_drain(zfsvfs); 2454c5832a53SAlek Pinchuk } 2455c5832a53SAlek Pinchuk 24560a586ceaSMark Shellenbaum bail: 2457f18faf3fSek /* release the VOPs */ 2458f18faf3fSek rw_exit(&zfsvfs->z_teardown_inactive_lock); 2459c9030f6cSAlexander Motin rrm_exit(&zfsvfs->z_teardown_lock, FTAG); 2460f18faf3fSek 2461f18faf3fSek if (err) { 2462f18faf3fSek /* 246391948b51SKeith M Wesolowski * Since we couldn't setup the sa framework, try to force 246491948b51SKeith M Wesolowski * unmount this file system. 2465f18faf3fSek */ 2466f18faf3fSek if (vn_vfswlock(zfsvfs->z_vfs->vfs_vnodecovered) == 0) 2467f18faf3fSek (void) dounmount(zfsvfs->z_vfs, MS_FORCE, CRED()); 2468f18faf3fSek } 2469f18faf3fSek return (err); 2470f18faf3fSek } 2471f18faf3fSek 2472fa9e4066Sahrens static void 2473fa9e4066Sahrens zfs_freevfs(vfs_t *vfsp) 2474fa9e4066Sahrens { 2475fa9e4066Sahrens zfsvfs_t *zfsvfs = vfsp->vfs_data; 2476142ae85dSChris Kirby 2477142ae85dSChris Kirby /* 2478142ae85dSChris Kirby * If this is a snapshot, we have an extra VFS_HOLD on our parent 2479f80ce222SChris Kirby * from zfs_mount(). Release it here. If we came through 2480f80ce222SChris Kirby * zfs_mountroot() instead, we didn't grab an extra hold, so 2481f80ce222SChris Kirby * skip the VFS_RELE for rootvfs. 2482142ae85dSChris Kirby */ 2483f80ce222SChris Kirby if (zfsvfs->z_issnap && (vfsp != rootvfs)) 2484142ae85dSChris Kirby VFS_RELE(zfsvfs->z_parent->z_vfs); 2485142ae85dSChris Kirby 248614843421SMatthew Ahrens zfsvfs_free(zfsvfs); 2487fa9e4066Sahrens 24881a5e258fSJosef 'Jeff' Sipek atomic_dec_32(&zfs_active_fs_count); 2489fa9e4066Sahrens } 2490fa9e4066Sahrens 2491fa9e4066Sahrens /* 2492fa9e4066Sahrens * VFS_INIT() initialization. Note that there is no VFS_FINI(), 2493fa9e4066Sahrens * so we can't safely do any non-idempotent initialization here. 2494fa9e4066Sahrens * Leave that to zfs_init() and zfs_fini(), which are called 2495fa9e4066Sahrens * from the module's _init() and _fini() entry points. 2496fa9e4066Sahrens */ 2497fa9e4066Sahrens /*ARGSUSED*/ 2498fa9e4066Sahrens static int 2499fa9e4066Sahrens zfs_vfsinit(int fstype, char *name) 2500fa9e4066Sahrens { 2501fa9e4066Sahrens int error; 2502fa9e4066Sahrens 2503fa9e4066Sahrens zfsfstype = fstype; 2504fa9e4066Sahrens 2505fa9e4066Sahrens /* 2506fa9e4066Sahrens * Setup vfsops and vnodeops tables. 2507fa9e4066Sahrens */ 2508fa9e4066Sahrens error = vfs_setfsops(fstype, zfs_vfsops_template, &zfs_vfsops); 2509fa9e4066Sahrens if (error != 0) { 2510fa9e4066Sahrens cmn_err(CE_WARN, "zfs: bad vfs ops template"); 2511fa9e4066Sahrens } 2512fa9e4066Sahrens 2513fa9e4066Sahrens error = zfs_create_op_tables(); 2514fa9e4066Sahrens if (error) { 2515fa9e4066Sahrens zfs_remove_op_tables(); 2516fa9e4066Sahrens cmn_err(CE_WARN, "zfs: bad vnode ops template"); 2517fa9e4066Sahrens (void) vfs_freevfsops_by_type(zfsfstype); 2518fa9e4066Sahrens return (error); 2519fa9e4066Sahrens } 2520fa9e4066Sahrens 2521fa9e4066Sahrens mutex_init(&zfs_dev_mtx, NULL, MUTEX_DEFAULT, NULL); 2522fa9e4066Sahrens 2523fa9e4066Sahrens /* 2524a0965f35Sbonwick * Unique major number for all zfs mounts. 2525a0965f35Sbonwick * If we run out of 32-bit minors, we'll getudev() another major. 2526fa9e4066Sahrens */ 2527a0965f35Sbonwick zfs_major = ddi_name_to_major(ZFS_DRIVER); 2528a0965f35Sbonwick zfs_minor = ZFS_MIN_MINOR; 2529fa9e4066Sahrens 2530fa9e4066Sahrens return (0); 2531fa9e4066Sahrens } 2532fa9e4066Sahrens 2533fa9e4066Sahrens void 2534fa9e4066Sahrens zfs_init(void) 2535fa9e4066Sahrens { 2536fa9e4066Sahrens /* 2537fa9e4066Sahrens * Initialize .zfs directory structures 2538fa9e4066Sahrens */ 2539fa9e4066Sahrens zfsctl_init(); 2540fa9e4066Sahrens 2541fa9e4066Sahrens /* 2542fa9e4066Sahrens * Initialize znode cache, vnode ops, etc... 2543fa9e4066Sahrens */ 2544fa9e4066Sahrens zfs_znode_init(); 254514843421SMatthew Ahrens 254614843421SMatthew Ahrens dmu_objset_register_type(DMU_OST_ZFS, zfs_space_delta_cb); 2547fa9e4066Sahrens } 2548fa9e4066Sahrens 2549fa9e4066Sahrens void 2550fa9e4066Sahrens zfs_fini(void) 2551fa9e4066Sahrens { 2552fa9e4066Sahrens zfsctl_fini(); 2553fa9e4066Sahrens zfs_znode_fini(); 2554fa9e4066Sahrens } 2555fa9e4066Sahrens 2556fa9e4066Sahrens int 2557fa9e4066Sahrens zfs_busy(void) 2558fa9e4066Sahrens { 2559fa9e4066Sahrens return (zfs_active_fs_count != 0); 2560fa9e4066Sahrens } 2561fa9e4066Sahrens 2562e7437265Sahrens int 256314843421SMatthew Ahrens zfs_set_version(zfsvfs_t *zfsvfs, uint64_t newvers) 2564e7437265Sahrens { 2565e7437265Sahrens int error; 256614843421SMatthew Ahrens objset_t *os = zfsvfs->z_os; 2567e7437265Sahrens dmu_tx_t *tx; 2568e7437265Sahrens 2569e7437265Sahrens if (newvers < ZPL_VERSION_INITIAL || newvers > ZPL_VERSION) 2570be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 2571e7437265Sahrens 257214843421SMatthew Ahrens if (newvers < zfsvfs->z_version) 2573be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 2574e7437265Sahrens 25750a586ceaSMark Shellenbaum if (zfs_spa_version_map(newvers) > 25760a586ceaSMark Shellenbaum spa_version(dmu_objset_spa(zfsvfs->z_os))) 2577be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 25780a586ceaSMark Shellenbaum 2579e7437265Sahrens tx = dmu_tx_create(os); 258014843421SMatthew Ahrens dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, B_FALSE, ZPL_VERSION_STR); 25810a586ceaSMark Shellenbaum if (newvers >= ZPL_VERSION_SA && !zfsvfs->z_use_sa) { 25820a586ceaSMark Shellenbaum dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, B_TRUE, 25830a586ceaSMark Shellenbaum ZFS_SA_ATTRS); 25840a586ceaSMark Shellenbaum dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL); 25850a586ceaSMark Shellenbaum } 2586e7437265Sahrens error = dmu_tx_assign(tx, TXG_WAIT); 2587e7437265Sahrens if (error) { 2588e7437265Sahrens dmu_tx_abort(tx); 258914843421SMatthew Ahrens return (error); 259014843421SMatthew Ahrens } 25910a586ceaSMark Shellenbaum 259214843421SMatthew Ahrens error = zap_update(os, MASTER_NODE_OBJ, ZPL_VERSION_STR, 259314843421SMatthew Ahrens 8, 1, &newvers, tx); 259414843421SMatthew Ahrens 259514843421SMatthew Ahrens if (error) { 259614843421SMatthew Ahrens dmu_tx_commit(tx); 259714843421SMatthew Ahrens return (error); 2598e7437265Sahrens } 2599e7437265Sahrens 26000a586ceaSMark Shellenbaum if (newvers >= ZPL_VERSION_SA && !zfsvfs->z_use_sa) { 26010a586ceaSMark Shellenbaum uint64_t sa_obj; 26020a586ceaSMark Shellenbaum 26030a586ceaSMark Shellenbaum ASSERT3U(spa_version(dmu_objset_spa(zfsvfs->z_os)), >=, 26040a586ceaSMark Shellenbaum SPA_VERSION_SA); 26050a586ceaSMark Shellenbaum sa_obj = zap_create(os, DMU_OT_SA_MASTER_NODE, 26060a586ceaSMark Shellenbaum DMU_OT_NONE, 0, tx); 26070a586ceaSMark Shellenbaum 26080a586ceaSMark Shellenbaum error = zap_add(os, MASTER_NODE_OBJ, 26090a586ceaSMark Shellenbaum ZFS_SA_ATTRS, 8, 1, &sa_obj, tx); 2610fb09f5aaSMadhav Suresh ASSERT0(error); 26110a586ceaSMark Shellenbaum 26120a586ceaSMark Shellenbaum VERIFY(0 == sa_set_sa_object(os, sa_obj)); 26130a586ceaSMark Shellenbaum sa_register_update_callback(os, zfs_sa_upgrade); 26140a586ceaSMark Shellenbaum } 26150a586ceaSMark Shellenbaum 26164445fffbSMatthew Ahrens spa_history_log_internal_ds(dmu_objset_ds(os), "upgrade", tx, 26174445fffbSMatthew Ahrens "from %llu to %llu", zfsvfs->z_version, newvers); 261814843421SMatthew Ahrens 2619e7437265Sahrens dmu_tx_commit(tx); 2620e7437265Sahrens 262114843421SMatthew Ahrens zfsvfs->z_version = newvers; 2622adb52d92SMatthew Ahrens os->os_version = newvers; 262314843421SMatthew Ahrens 262444bffe01SMark Shellenbaum zfs_set_fuid_feature(zfsvfs); 262514843421SMatthew Ahrens 262614843421SMatthew Ahrens return (0); 2627e7437265Sahrens } 2628e7437265Sahrens 2629de8267e0Stimh /* 2630de8267e0Stimh * Read a property stored within the master node. 2631de8267e0Stimh */ 2632de8267e0Stimh int 2633de8267e0Stimh zfs_get_zplprop(objset_t *os, zfs_prop_t prop, uint64_t *value) 2634de8267e0Stimh { 2635adb52d92SMatthew Ahrens uint64_t *cached_copy = NULL; 2636de8267e0Stimh 2637de8267e0Stimh /* 2638adb52d92SMatthew Ahrens * Figure out where in the objset_t the cached copy would live, if it 2639adb52d92SMatthew Ahrens * is available for the requested property. 2640de8267e0Stimh */ 2641adb52d92SMatthew Ahrens if (os != NULL) { 2642adb52d92SMatthew Ahrens switch (prop) { 2643adb52d92SMatthew Ahrens case ZFS_PROP_VERSION: 2644adb52d92SMatthew Ahrens cached_copy = &os->os_version; 2645adb52d92SMatthew Ahrens break; 2646adb52d92SMatthew Ahrens case ZFS_PROP_NORMALIZE: 2647adb52d92SMatthew Ahrens cached_copy = &os->os_normalization; 2648adb52d92SMatthew Ahrens break; 2649adb52d92SMatthew Ahrens case ZFS_PROP_UTF8ONLY: 2650adb52d92SMatthew Ahrens cached_copy = &os->os_utf8only; 2651adb52d92SMatthew Ahrens break; 2652adb52d92SMatthew Ahrens case ZFS_PROP_CASE: 2653adb52d92SMatthew Ahrens cached_copy = &os->os_casesensitivity; 2654adb52d92SMatthew Ahrens break; 2655adb52d92SMatthew Ahrens default: 2656adb52d92SMatthew Ahrens break; 2657adb52d92SMatthew Ahrens } 2658adb52d92SMatthew Ahrens } 2659adb52d92SMatthew Ahrens if (cached_copy != NULL && *cached_copy != OBJSET_PROP_UNINITIALIZED) { 2660adb52d92SMatthew Ahrens *value = *cached_copy; 2661adb52d92SMatthew Ahrens return (0); 2662adb52d92SMatthew Ahrens } 2663adb52d92SMatthew Ahrens 2664adb52d92SMatthew Ahrens /* 2665adb52d92SMatthew Ahrens * If the property wasn't cached, look up the file system's value for 2666adb52d92SMatthew Ahrens * the property. For the version property, we look up a slightly 2667adb52d92SMatthew Ahrens * different string. 2668adb52d92SMatthew Ahrens */ 2669adb52d92SMatthew Ahrens const char *pname; 2670adb52d92SMatthew Ahrens int error = ENOENT; 2671adb52d92SMatthew Ahrens if (prop == ZFS_PROP_VERSION) { 2672de8267e0Stimh pname = ZPL_VERSION_STR; 2673adb52d92SMatthew Ahrens } else { 2674de8267e0Stimh pname = zfs_prop_to_name(prop); 2675adb52d92SMatthew Ahrens } 2676de8267e0Stimh 2677b127fe3cSAndriy Gapon if (os != NULL) { 2678b127fe3cSAndriy Gapon ASSERT3U(os->os_phys->os_type, ==, DMU_OST_ZFS); 26790a48a24eStimh error = zap_lookup(os, MASTER_NODE_OBJ, pname, 8, 1, value); 2680b127fe3cSAndriy Gapon } 2681de8267e0Stimh 2682aa60ed0eSmaybee if (error == ENOENT) { 2683de8267e0Stimh /* No value set, use the default value */ 2684de8267e0Stimh switch (prop) { 2685aa60ed0eSmaybee case ZFS_PROP_VERSION: 2686aa60ed0eSmaybee *value = ZPL_VERSION; 2687aa60ed0eSmaybee break; 2688de8267e0Stimh case ZFS_PROP_NORMALIZE: 2689de8267e0Stimh case ZFS_PROP_UTF8ONLY: 2690de8267e0Stimh *value = 0; 2691de8267e0Stimh break; 2692de8267e0Stimh case ZFS_PROP_CASE: 2693de8267e0Stimh *value = ZFS_CASE_SENSITIVE; 2694de8267e0Stimh break; 2695de8267e0Stimh default: 2696aa60ed0eSmaybee return (error); 2697de8267e0Stimh } 2698aa60ed0eSmaybee error = 0; 2699de8267e0Stimh } 2700adb52d92SMatthew Ahrens 2701adb52d92SMatthew Ahrens /* 2702adb52d92SMatthew Ahrens * If one of the methods for getting the property value above worked, 2703adb52d92SMatthew Ahrens * copy it into the objset_t's cache. 2704adb52d92SMatthew Ahrens */ 2705adb52d92SMatthew Ahrens if (error == 0 && cached_copy != NULL) { 2706adb52d92SMatthew Ahrens *cached_copy = *value; 2707adb52d92SMatthew Ahrens } 2708adb52d92SMatthew Ahrens 2709aa60ed0eSmaybee return (error); 2710de8267e0Stimh } 2711de8267e0Stimh 2712eb721827SAlek Pinchuk /* 2713eb721827SAlek Pinchuk * Return true if the coresponding vfs's unmounted flag is set. 2714eb721827SAlek Pinchuk * Otherwise return false. 2715eb721827SAlek Pinchuk * If this function returns true we know VFS unmount has been initiated. 2716eb721827SAlek Pinchuk */ 2717eb721827SAlek Pinchuk boolean_t 2718eb721827SAlek Pinchuk zfs_get_vfs_flag_unmounted(objset_t *os) 2719eb721827SAlek Pinchuk { 2720eb721827SAlek Pinchuk zfsvfs_t *zfvp; 2721eb721827SAlek Pinchuk boolean_t unmounted = B_FALSE; 2722eb721827SAlek Pinchuk 2723eb721827SAlek Pinchuk ASSERT(dmu_objset_type(os) == DMU_OST_ZFS); 2724eb721827SAlek Pinchuk 2725eb721827SAlek Pinchuk mutex_enter(&os->os_user_ptr_lock); 2726eb721827SAlek Pinchuk zfvp = dmu_objset_get_user(os); 2727eb721827SAlek Pinchuk if (zfvp != NULL && zfvp->z_vfs != NULL && 2728eb721827SAlek Pinchuk (zfvp->z_vfs->vfs_flag & VFS_UNMOUNTED)) 2729eb721827SAlek Pinchuk unmounted = B_TRUE; 2730eb721827SAlek Pinchuk mutex_exit(&os->os_user_ptr_lock); 2731eb721827SAlek Pinchuk 2732eb721827SAlek Pinchuk return (unmounted); 2733eb721827SAlek Pinchuk } 2734eb721827SAlek Pinchuk 2735fa9e4066Sahrens static vfsdef_t vfw = { 2736fa9e4066Sahrens VFSDEF_VERSION, 2737fa9e4066Sahrens MNTTYPE_ZFS, 2738fa9e4066Sahrens zfs_vfsinit, 2739da6c28aaSamw VSW_HASPROTO|VSW_CANRWRO|VSW_CANREMOUNT|VSW_VOLATILEDEV|VSW_STATS| 27400fbb751dSJohn Levon VSW_XID|VSW_ZMOUNT, 2741fa9e4066Sahrens &zfs_mntopts 2742fa9e4066Sahrens }; 2743fa9e4066Sahrens 2744fa9e4066Sahrens struct modlfs zfs_modlfs = { 2745e7437265Sahrens &mod_fsops, "ZFS filesystem version " SPA_VERSION_STRING, &vfw 2746fa9e4066Sahrens }; 2747