1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51512Sek110237 * Common Development and Distribution License (the "License"). 61512Sek110237 * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 21789Sahrens /* 228547SMark.Shellenbaum@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens /* 27789Sahrens * ZFS control directory (a.k.a. ".zfs") 28789Sahrens * 29789Sahrens * This directory provides a common location for all ZFS meta-objects. 30789Sahrens * Currently, this is only the 'snapshot' directory, but this may expand in the 31789Sahrens * future. The elements are built using the GFS primitives, as the hierarchy 32789Sahrens * does not actually exist on disk. 33789Sahrens * 34789Sahrens * For 'snapshot', we don't want to have all snapshots always mounted, because 35789Sahrens * this would take up a huge amount of space in /etc/mnttab. We have three 36789Sahrens * types of objects: 37789Sahrens * 38789Sahrens * ctldir ------> snapshotdir -------> snapshot 39789Sahrens * | 40789Sahrens * | 41789Sahrens * V 42789Sahrens * mounted fs 43789Sahrens * 44789Sahrens * The 'snapshot' node contains just enough information to lookup '..' and act 45789Sahrens * as a mountpoint for the snapshot. Whenever we lookup a specific snapshot, we 46789Sahrens * perform an automount of the underlying filesystem and return the 47789Sahrens * corresponding vnode. 48789Sahrens * 49789Sahrens * All mounts are handled automatically by the kernel, but unmounts are 50789Sahrens * (currently) handled from user land. The main reason is that there is no 51789Sahrens * reliable way to auto-unmount the filesystem when it's "no longer in use". 52789Sahrens * When the user unmounts a filesystem, we call zfsctl_unmount(), which 53789Sahrens * unmounts any snapshots within the snapshot directory. 545326Sek110237 * 555326Sek110237 * The '.zfs', '.zfs/snapshot', and all directories created under 565326Sek110237 * '.zfs/snapshot' (ie: '.zfs/snapshot/<snapname>') are all GFS nodes and 575326Sek110237 * share the same vfs_t as the head filesystem (what '.zfs' lives under). 585326Sek110237 * 595326Sek110237 * File systems mounted ontop of the GFS nodes '.zfs/snapshot/<snapname>' 605326Sek110237 * (ie: snapshots) are ZFS nodes and have their own unique vfs_t. 615326Sek110237 * However, vnodes within these mounted on file systems have their v_vfsp 625326Sek110237 * fields set to the head filesystem to make NFS happy (see 636068Sck153898 * zfsctl_snapdir_lookup()). We VFS_HOLD the head filesystem's vfs_t 646068Sck153898 * so that it cannot be freed until all snapshots have been unmounted. 65789Sahrens */ 66789Sahrens 67789Sahrens #include <fs/fs_subr.h> 68789Sahrens #include <sys/zfs_ctldir.h> 69789Sahrens #include <sys/zfs_ioctl.h> 70789Sahrens #include <sys/zfs_vfsops.h> 713898Srsb #include <sys/vfs_opreg.h> 72789Sahrens #include <sys/gfs.h> 73789Sahrens #include <sys/stat.h> 74789Sahrens #include <sys/dmu.h> 754543Smarks #include <sys/dsl_deleg.h> 76789Sahrens #include <sys/mount.h> 776492Stimh #include <sys/sunddi.h> 78789Sahrens 796658Smarks #include "zfs_namecheck.h" 806658Smarks 816068Sck153898 typedef struct zfsctl_node { 826068Sck153898 gfs_dir_t zc_gfs_private; 836068Sck153898 uint64_t zc_id; 846068Sck153898 timestruc_t zc_cmtime; /* ctime and mtime, always the same */ 856068Sck153898 } zfsctl_node_t; 866068Sck153898 876068Sck153898 typedef struct zfsctl_snapdir { 886068Sck153898 zfsctl_node_t sd_node; 896068Sck153898 kmutex_t sd_lock; 906068Sck153898 avl_tree_t sd_snaps; 916068Sck153898 } zfsctl_snapdir_t; 926068Sck153898 93789Sahrens typedef struct { 94789Sahrens char *se_name; 95789Sahrens vnode_t *se_root; 96789Sahrens avl_node_t se_node; 97789Sahrens } zfs_snapentry_t; 98789Sahrens 99789Sahrens static int 100789Sahrens snapentry_compare(const void *a, const void *b) 101789Sahrens { 102789Sahrens const zfs_snapentry_t *sa = a; 103789Sahrens const zfs_snapentry_t *sb = b; 104789Sahrens int ret = strcmp(sa->se_name, sb->se_name); 105789Sahrens 106789Sahrens if (ret < 0) 107789Sahrens return (-1); 108789Sahrens else if (ret > 0) 109789Sahrens return (1); 110789Sahrens else 111789Sahrens return (0); 112789Sahrens } 113789Sahrens 114789Sahrens vnodeops_t *zfsctl_ops_root; 115789Sahrens vnodeops_t *zfsctl_ops_snapdir; 116789Sahrens vnodeops_t *zfsctl_ops_snapshot; 1178845Samw@Sun.COM vnodeops_t *zfsctl_ops_shares; 1188845Samw@Sun.COM vnodeops_t *zfsctl_ops_shares_dir; 119789Sahrens 120789Sahrens static const fs_operation_def_t zfsctl_tops_root[]; 121789Sahrens static const fs_operation_def_t zfsctl_tops_snapdir[]; 122789Sahrens static const fs_operation_def_t zfsctl_tops_snapshot[]; 1238845Samw@Sun.COM static const fs_operation_def_t zfsctl_tops_shares[]; 124789Sahrens 125789Sahrens static vnode_t *zfsctl_mknode_snapdir(vnode_t *); 1268845Samw@Sun.COM static vnode_t *zfsctl_mknode_shares(vnode_t *); 127789Sahrens static vnode_t *zfsctl_snapshot_mknode(vnode_t *, uint64_t objset); 1286068Sck153898 static int zfsctl_unmount_snap(zfs_snapentry_t *, int, cred_t *); 129789Sahrens 130789Sahrens static gfs_opsvec_t zfsctl_opsvec[] = { 131789Sahrens { ".zfs", zfsctl_tops_root, &zfsctl_ops_root }, 132789Sahrens { ".zfs/snapshot", zfsctl_tops_snapdir, &zfsctl_ops_snapdir }, 133789Sahrens { ".zfs/snapshot/vnode", zfsctl_tops_snapshot, &zfsctl_ops_snapshot }, 1348845Samw@Sun.COM { ".zfs/shares", zfsctl_tops_shares, &zfsctl_ops_shares_dir }, 1358845Samw@Sun.COM { ".zfs/shares/vnode", zfsctl_tops_shares, &zfsctl_ops_shares }, 136789Sahrens { NULL } 137789Sahrens }; 138789Sahrens 139789Sahrens /* 1408845Samw@Sun.COM * Root directory elements. We only have two entries 1418845Samw@Sun.COM * snapshot and shares. 142789Sahrens */ 143789Sahrens static gfs_dirent_t zfsctl_root_entries[] = { 144789Sahrens { "snapshot", zfsctl_mknode_snapdir, GFS_CACHE_VNODE }, 1458845Samw@Sun.COM { "shares", zfsctl_mknode_shares, GFS_CACHE_VNODE }, 146789Sahrens { NULL } 147789Sahrens }; 148789Sahrens 149789Sahrens /* include . and .. in the calculation */ 150789Sahrens #define NROOT_ENTRIES ((sizeof (zfsctl_root_entries) / \ 151789Sahrens sizeof (gfs_dirent_t)) + 1) 152789Sahrens 153789Sahrens 154789Sahrens /* 155789Sahrens * Initialize the various GFS pieces we'll need to create and manipulate .zfs 156789Sahrens * directories. This is called from the ZFS init routine, and initializes the 157789Sahrens * vnode ops vectors that we'll be using. 158789Sahrens */ 159789Sahrens void 160789Sahrens zfsctl_init(void) 161789Sahrens { 162789Sahrens VERIFY(gfs_make_opsvec(zfsctl_opsvec) == 0); 163789Sahrens } 164789Sahrens 165789Sahrens void 166789Sahrens zfsctl_fini(void) 167789Sahrens { 168789Sahrens /* 169789Sahrens * Remove vfsctl vnode ops 170789Sahrens */ 171789Sahrens if (zfsctl_ops_root) 172789Sahrens vn_freevnodeops(zfsctl_ops_root); 173789Sahrens if (zfsctl_ops_snapdir) 174789Sahrens vn_freevnodeops(zfsctl_ops_snapdir); 175789Sahrens if (zfsctl_ops_snapshot) 176789Sahrens vn_freevnodeops(zfsctl_ops_snapshot); 1778845Samw@Sun.COM if (zfsctl_ops_shares) 1788845Samw@Sun.COM vn_freevnodeops(zfsctl_ops_shares); 1798845Samw@Sun.COM if (zfsctl_ops_shares_dir) 1808845Samw@Sun.COM vn_freevnodeops(zfsctl_ops_shares_dir); 181789Sahrens 182789Sahrens zfsctl_ops_root = NULL; 183789Sahrens zfsctl_ops_snapdir = NULL; 184789Sahrens zfsctl_ops_snapshot = NULL; 1858845Samw@Sun.COM zfsctl_ops_shares = NULL; 1868845Samw@Sun.COM zfsctl_ops_shares_dir = NULL; 187789Sahrens } 188789Sahrens 189789Sahrens /* 1908845Samw@Sun.COM * Return the inode number associated with the 'snapshot' or 1918845Samw@Sun.COM * 'shares' directory. 192789Sahrens */ 193789Sahrens /* ARGSUSED */ 194789Sahrens static ino64_t 195789Sahrens zfsctl_root_inode_cb(vnode_t *vp, int index) 196789Sahrens { 1978845Samw@Sun.COM zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 1988845Samw@Sun.COM 1998845Samw@Sun.COM ASSERT(index <= 2); 2008845Samw@Sun.COM 2018845Samw@Sun.COM if (index == 0) 2028845Samw@Sun.COM return (ZFSCTL_INO_SNAPDIR); 2038845Samw@Sun.COM 2048845Samw@Sun.COM return (zfsvfs->z_shares_dir); 205789Sahrens } 206789Sahrens 207789Sahrens /* 208789Sahrens * Create the '.zfs' directory. This directory is cached as part of the VFS 209789Sahrens * structure. This results in a hold on the vfs_t. The code in zfs_umount() 210789Sahrens * therefore checks against a vfs_count of 2 instead of 1. This reference 211789Sahrens * is removed when the ctldir is destroyed in the unmount. 212789Sahrens */ 213789Sahrens void 214789Sahrens zfsctl_create(zfsvfs_t *zfsvfs) 215789Sahrens { 2161571Sek110237 vnode_t *vp, *rvp; 217789Sahrens zfsctl_node_t *zcp; 218789Sahrens 219789Sahrens ASSERT(zfsvfs->z_ctldir == NULL); 220789Sahrens 221789Sahrens vp = gfs_root_create(sizeof (zfsctl_node_t), zfsvfs->z_vfs, 222789Sahrens zfsctl_ops_root, ZFSCTL_INO_ROOT, zfsctl_root_entries, 223789Sahrens zfsctl_root_inode_cb, MAXNAMELEN, NULL, NULL); 224789Sahrens zcp = vp->v_data; 225789Sahrens zcp->zc_id = ZFSCTL_INO_ROOT; 226789Sahrens 2271571Sek110237 VERIFY(VFS_ROOT(zfsvfs->z_vfs, &rvp) == 0); 2281571Sek110237 ZFS_TIME_DECODE(&zcp->zc_cmtime, VTOZ(rvp)->z_phys->zp_crtime); 2291571Sek110237 VN_RELE(rvp); 2301571Sek110237 231789Sahrens /* 232789Sahrens * We're only faking the fact that we have a root of a filesystem for 233789Sahrens * the sake of the GFS interfaces. Undo the flag manipulation it did 234789Sahrens * for us. 235789Sahrens */ 236789Sahrens vp->v_flag &= ~(VROOT | VNOCACHE | VNOMAP | VNOSWAP | VNOMOUNT); 237789Sahrens 238789Sahrens zfsvfs->z_ctldir = vp; 239789Sahrens } 240789Sahrens 241789Sahrens /* 2421298Sperrin * Destroy the '.zfs' directory. Only called when the filesystem is unmounted. 2431298Sperrin * There might still be more references if we were force unmounted, but only 2441298Sperrin * new zfs_inactive() calls can occur and they don't reference .zfs 245789Sahrens */ 246789Sahrens void 247789Sahrens zfsctl_destroy(zfsvfs_t *zfsvfs) 248789Sahrens { 249789Sahrens VN_RELE(zfsvfs->z_ctldir); 250789Sahrens zfsvfs->z_ctldir = NULL; 251789Sahrens } 252789Sahrens 253789Sahrens /* 254789Sahrens * Given a root znode, retrieve the associated .zfs directory. 255789Sahrens * Add a hold to the vnode and return it. 256789Sahrens */ 257789Sahrens vnode_t * 258789Sahrens zfsctl_root(znode_t *zp) 259789Sahrens { 260789Sahrens ASSERT(zfs_has_ctldir(zp)); 261789Sahrens VN_HOLD(zp->z_zfsvfs->z_ctldir); 262789Sahrens return (zp->z_zfsvfs->z_ctldir); 263789Sahrens } 264789Sahrens 265789Sahrens /* 266789Sahrens * Common open routine. Disallow any write access. 267789Sahrens */ 268789Sahrens /* ARGSUSED */ 269789Sahrens static int 2705331Samw zfsctl_common_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct) 271789Sahrens { 272789Sahrens if (flags & FWRITE) 273789Sahrens return (EACCES); 274789Sahrens 275789Sahrens return (0); 276789Sahrens } 277789Sahrens 278789Sahrens /* 279789Sahrens * Common close routine. Nothing to do here. 280789Sahrens */ 281789Sahrens /* ARGSUSED */ 282789Sahrens static int 283789Sahrens zfsctl_common_close(vnode_t *vpp, int flags, int count, offset_t off, 2845331Samw cred_t *cr, caller_context_t *ct) 285789Sahrens { 286789Sahrens return (0); 287789Sahrens } 288789Sahrens 289789Sahrens /* 290789Sahrens * Common access routine. Disallow writes. 291789Sahrens */ 292789Sahrens /* ARGSUSED */ 293789Sahrens static int 2945331Samw zfsctl_common_access(vnode_t *vp, int mode, int flags, cred_t *cr, 2955331Samw caller_context_t *ct) 296789Sahrens { 2978547SMark.Shellenbaum@Sun.COM if (flags & V_ACE_MASK) { 2988547SMark.Shellenbaum@Sun.COM if (mode & ACE_ALL_WRITE_PERMS) 2998547SMark.Shellenbaum@Sun.COM return (EACCES); 3008547SMark.Shellenbaum@Sun.COM } else { 3018547SMark.Shellenbaum@Sun.COM if (mode & VWRITE) 3028547SMark.Shellenbaum@Sun.COM return (EACCES); 3038547SMark.Shellenbaum@Sun.COM } 304789Sahrens 305789Sahrens return (0); 306789Sahrens } 307789Sahrens 308789Sahrens /* 309789Sahrens * Common getattr function. Fill in basic information. 310789Sahrens */ 311789Sahrens static void 312789Sahrens zfsctl_common_getattr(vnode_t *vp, vattr_t *vap) 313789Sahrens { 3141571Sek110237 zfsctl_node_t *zcp = vp->v_data; 3151571Sek110237 timestruc_t now; 316789Sahrens 317789Sahrens vap->va_uid = 0; 318789Sahrens vap->va_gid = 0; 319789Sahrens vap->va_rdev = 0; 320789Sahrens /* 321789Sahrens * We are a purly virtual object, so we have no 322789Sahrens * blocksize or allocated blocks. 323789Sahrens */ 324789Sahrens vap->va_blksize = 0; 325789Sahrens vap->va_nblocks = 0; 326789Sahrens vap->va_seq = 0; 327789Sahrens vap->va_fsid = vp->v_vfsp->vfs_dev; 328789Sahrens vap->va_mode = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | 329789Sahrens S_IROTH | S_IXOTH; 330789Sahrens vap->va_type = VDIR; 331789Sahrens /* 3321571Sek110237 * We live in the now (for atime). 333789Sahrens */ 334789Sahrens gethrestime(&now); 3351571Sek110237 vap->va_atime = now; 3361571Sek110237 vap->va_mtime = vap->va_ctime = zcp->zc_cmtime; 337789Sahrens } 338789Sahrens 3395331Samw /*ARGSUSED*/ 340789Sahrens static int 3415331Samw zfsctl_common_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct) 342789Sahrens { 343789Sahrens zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 344789Sahrens zfsctl_node_t *zcp = vp->v_data; 345789Sahrens uint64_t object = zcp->zc_id; 346789Sahrens zfid_short_t *zfid; 347789Sahrens int i; 348789Sahrens 349789Sahrens ZFS_ENTER(zfsvfs); 350789Sahrens 351789Sahrens if (fidp->fid_len < SHORT_FID_LEN) { 352789Sahrens fidp->fid_len = SHORT_FID_LEN; 3531512Sek110237 ZFS_EXIT(zfsvfs); 354789Sahrens return (ENOSPC); 355789Sahrens } 356789Sahrens 357789Sahrens zfid = (zfid_short_t *)fidp; 358789Sahrens 359789Sahrens zfid->zf_len = SHORT_FID_LEN; 360789Sahrens 361789Sahrens for (i = 0; i < sizeof (zfid->zf_object); i++) 362789Sahrens zfid->zf_object[i] = (uint8_t)(object >> (8 * i)); 363789Sahrens 364789Sahrens /* .zfs znodes always have a generation number of 0 */ 365789Sahrens for (i = 0; i < sizeof (zfid->zf_gen); i++) 366789Sahrens zfid->zf_gen[i] = 0; 367789Sahrens 368789Sahrens ZFS_EXIT(zfsvfs); 369789Sahrens return (0); 370789Sahrens } 371789Sahrens 3728845Samw@Sun.COM 3738845Samw@Sun.COM /*ARGSUSED*/ 3748845Samw@Sun.COM static int 3758845Samw@Sun.COM zfsctl_shares_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct) 3768845Samw@Sun.COM { 3778845Samw@Sun.COM zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 3788845Samw@Sun.COM znode_t *dzp; 3798845Samw@Sun.COM int error; 3808845Samw@Sun.COM 3818845Samw@Sun.COM ZFS_ENTER(zfsvfs); 3829030SMark.Shellenbaum@Sun.COM 3839030SMark.Shellenbaum@Sun.COM if (zfsvfs->z_shares_dir == 0) { 3849030SMark.Shellenbaum@Sun.COM ZFS_EXIT(zfsvfs); 3859030SMark.Shellenbaum@Sun.COM return (ENOTSUP); 3869030SMark.Shellenbaum@Sun.COM } 3879030SMark.Shellenbaum@Sun.COM 3888845Samw@Sun.COM if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) { 3898845Samw@Sun.COM error = VOP_FID(ZTOV(dzp), fidp, ct); 3908845Samw@Sun.COM VN_RELE(ZTOV(dzp)); 3918845Samw@Sun.COM } 3928845Samw@Sun.COM 3938845Samw@Sun.COM ZFS_EXIT(zfsvfs); 3948845Samw@Sun.COM return (error); 3958845Samw@Sun.COM } 396789Sahrens /* 397789Sahrens * .zfs inode namespace 398789Sahrens * 399789Sahrens * We need to generate unique inode numbers for all files and directories 400789Sahrens * within the .zfs pseudo-filesystem. We use the following scheme: 401789Sahrens * 402789Sahrens * ENTRY ZFSCTL_INODE 403789Sahrens * .zfs 1 404789Sahrens * .zfs/snapshot 2 405789Sahrens * .zfs/snapshot/<snap> objectid(snap) 406789Sahrens */ 407789Sahrens 408789Sahrens #define ZFSCTL_INO_SNAP(id) (id) 409789Sahrens 410789Sahrens /* 411789Sahrens * Get root directory attributes. 412789Sahrens */ 413789Sahrens /* ARGSUSED */ 414789Sahrens static int 4155331Samw zfsctl_root_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 4165331Samw caller_context_t *ct) 417789Sahrens { 418789Sahrens zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 419789Sahrens 420789Sahrens ZFS_ENTER(zfsvfs); 421789Sahrens vap->va_nodeid = ZFSCTL_INO_ROOT; 422789Sahrens vap->va_nlink = vap->va_size = NROOT_ENTRIES; 423789Sahrens 424789Sahrens zfsctl_common_getattr(vp, vap); 425789Sahrens ZFS_EXIT(zfsvfs); 426789Sahrens 427789Sahrens return (0); 428789Sahrens } 429789Sahrens 430789Sahrens /* 431789Sahrens * Special case the handling of "..". 432789Sahrens */ 433789Sahrens /* ARGSUSED */ 434789Sahrens int 435789Sahrens zfsctl_root_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp, 4365331Samw int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct, 4375331Samw int *direntflags, pathname_t *realpnp) 438789Sahrens { 439789Sahrens zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 440789Sahrens int err; 441789Sahrens 4425331Samw /* 4435331Samw * No extended attributes allowed under .zfs 4445331Samw */ 4455331Samw if (flags & LOOKUP_XATTR) 4465331Samw return (EINVAL); 4475331Samw 448789Sahrens ZFS_ENTER(zfsvfs); 449789Sahrens 450789Sahrens if (strcmp(nm, "..") == 0) { 451789Sahrens err = VFS_ROOT(dvp->v_vfsp, vpp); 452789Sahrens } else { 4536492Stimh err = gfs_vop_lookup(dvp, nm, vpp, pnp, flags, rdir, 4546492Stimh cr, ct, direntflags, realpnp); 455789Sahrens } 456789Sahrens 457789Sahrens ZFS_EXIT(zfsvfs); 458789Sahrens 459789Sahrens return (err); 460789Sahrens } 461789Sahrens 4628547SMark.Shellenbaum@Sun.COM static int 4638547SMark.Shellenbaum@Sun.COM zfsctl_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, 4648547SMark.Shellenbaum@Sun.COM caller_context_t *ct) 4658547SMark.Shellenbaum@Sun.COM { 4668547SMark.Shellenbaum@Sun.COM /* 4678547SMark.Shellenbaum@Sun.COM * We only care about ACL_ENABLED so that libsec can 4688547SMark.Shellenbaum@Sun.COM * display ACL correctly and not default to POSIX draft. 4698547SMark.Shellenbaum@Sun.COM */ 4708547SMark.Shellenbaum@Sun.COM if (cmd == _PC_ACL_ENABLED) { 4718547SMark.Shellenbaum@Sun.COM *valp = _ACL_ACE_ENABLED; 4728547SMark.Shellenbaum@Sun.COM return (0); 4738547SMark.Shellenbaum@Sun.COM } 4748547SMark.Shellenbaum@Sun.COM 4758547SMark.Shellenbaum@Sun.COM return (fs_pathconf(vp, cmd, valp, cr, ct)); 4768547SMark.Shellenbaum@Sun.COM } 4778547SMark.Shellenbaum@Sun.COM 478789Sahrens static const fs_operation_def_t zfsctl_tops_root[] = { 4793898Srsb { VOPNAME_OPEN, { .vop_open = zfsctl_common_open } }, 4803898Srsb { VOPNAME_CLOSE, { .vop_close = zfsctl_common_close } }, 4813898Srsb { VOPNAME_IOCTL, { .error = fs_inval } }, 4823898Srsb { VOPNAME_GETATTR, { .vop_getattr = zfsctl_root_getattr } }, 4833898Srsb { VOPNAME_ACCESS, { .vop_access = zfsctl_common_access } }, 4843898Srsb { VOPNAME_READDIR, { .vop_readdir = gfs_vop_readdir } }, 4853898Srsb { VOPNAME_LOOKUP, { .vop_lookup = zfsctl_root_lookup } }, 4863898Srsb { VOPNAME_SEEK, { .vop_seek = fs_seek } }, 4873898Srsb { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } }, 4888547SMark.Shellenbaum@Sun.COM { VOPNAME_PATHCONF, { .vop_pathconf = zfsctl_pathconf } }, 4893898Srsb { VOPNAME_FID, { .vop_fid = zfsctl_common_fid } }, 490789Sahrens { NULL } 491789Sahrens }; 492789Sahrens 493789Sahrens static int 494789Sahrens zfsctl_snapshot_zname(vnode_t *vp, const char *name, int len, char *zname) 495789Sahrens { 496789Sahrens objset_t *os = ((zfsvfs_t *)((vp)->v_vfsp->vfs_data))->z_os; 497789Sahrens 4986658Smarks if (snapshot_namecheck(name, NULL, NULL) != 0) 4996658Smarks return (EILSEQ); 500789Sahrens dmu_objset_name(os, zname); 5011154Smaybee if (strlen(zname) + 1 + strlen(name) >= len) 5021154Smaybee return (ENAMETOOLONG); 503789Sahrens (void) strcat(zname, "@"); 504789Sahrens (void) strcat(zname, name); 505789Sahrens return (0); 506789Sahrens } 507789Sahrens 5086068Sck153898 static int 5096068Sck153898 zfsctl_unmount_snap(zfs_snapentry_t *sep, int fflags, cred_t *cr) 510789Sahrens { 5116068Sck153898 vnode_t *svp = sep->se_root; 5126068Sck153898 int error; 513789Sahrens 5146068Sck153898 ASSERT(vn_ismntpt(svp)); 515789Sahrens 516789Sahrens /* this will be dropped by dounmount() */ 5176068Sck153898 if ((error = vn_vfswlock(svp)) != 0) 5186068Sck153898 return (error); 519789Sahrens 5206068Sck153898 VN_HOLD(svp); 5216068Sck153898 error = dounmount(vn_mountedvfs(svp), fflags, cr); 5226068Sck153898 if (error) { 5236068Sck153898 VN_RELE(svp); 5246068Sck153898 return (error); 5251589Smaybee } 5269214Schris.kirby@sun.com 5276068Sck153898 /* 5286068Sck153898 * We can't use VN_RELE(), as that will try to invoke 5296068Sck153898 * zfsctl_snapdir_inactive(), which would cause us to destroy 5306068Sck153898 * the sd_lock mutex held by our caller. 5316068Sck153898 */ 5326068Sck153898 ASSERT(svp->v_count == 1); 5336068Sck153898 gfs_vop_inactive(svp, cr, NULL); 534789Sahrens 535789Sahrens kmem_free(sep->se_name, strlen(sep->se_name) + 1); 536789Sahrens kmem_free(sep, sizeof (zfs_snapentry_t)); 537789Sahrens 538789Sahrens return (0); 539789Sahrens } 540789Sahrens 5411154Smaybee static void 542789Sahrens zfsctl_rename_snap(zfsctl_snapdir_t *sdp, zfs_snapentry_t *sep, const char *nm) 543789Sahrens { 544789Sahrens avl_index_t where; 545789Sahrens vfs_t *vfsp; 546789Sahrens refstr_t *pathref; 547789Sahrens char newpath[MAXNAMELEN]; 548789Sahrens char *tail; 549789Sahrens 550789Sahrens ASSERT(MUTEX_HELD(&sdp->sd_lock)); 551789Sahrens ASSERT(sep != NULL); 552789Sahrens 553789Sahrens vfsp = vn_mountedvfs(sep->se_root); 554789Sahrens ASSERT(vfsp != NULL); 555789Sahrens 5561154Smaybee vfs_lock_wait(vfsp); 557789Sahrens 558789Sahrens /* 559789Sahrens * Change the name in the AVL tree. 560789Sahrens */ 561789Sahrens avl_remove(&sdp->sd_snaps, sep); 562789Sahrens kmem_free(sep->se_name, strlen(sep->se_name) + 1); 563789Sahrens sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP); 564789Sahrens (void) strcpy(sep->se_name, nm); 565789Sahrens VERIFY(avl_find(&sdp->sd_snaps, sep, &where) == NULL); 566789Sahrens avl_insert(&sdp->sd_snaps, sep, where); 567789Sahrens 568789Sahrens /* 569789Sahrens * Change the current mountpoint info: 570789Sahrens * - update the tail of the mntpoint path 571789Sahrens * - update the tail of the resource path 572789Sahrens */ 573789Sahrens pathref = vfs_getmntpoint(vfsp); 5742417Sahrens (void) strncpy(newpath, refstr_value(pathref), sizeof (newpath)); 5752417Sahrens VERIFY((tail = strrchr(newpath, '/')) != NULL); 5762417Sahrens *(tail+1) = '\0'; 5772417Sahrens ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath)); 578789Sahrens (void) strcat(newpath, nm); 579789Sahrens refstr_rele(pathref); 580789Sahrens vfs_setmntpoint(vfsp, newpath); 581789Sahrens 582789Sahrens pathref = vfs_getresource(vfsp); 5832417Sahrens (void) strncpy(newpath, refstr_value(pathref), sizeof (newpath)); 5842417Sahrens VERIFY((tail = strrchr(newpath, '@')) != NULL); 5852417Sahrens *(tail+1) = '\0'; 5862417Sahrens ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath)); 587789Sahrens (void) strcat(newpath, nm); 588789Sahrens refstr_rele(pathref); 589789Sahrens vfs_setresource(vfsp, newpath); 590789Sahrens 591789Sahrens vfs_unlock(vfsp); 592789Sahrens } 593789Sahrens 5945331Samw /*ARGSUSED*/ 595789Sahrens static int 596789Sahrens zfsctl_snapdir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, 5975331Samw cred_t *cr, caller_context_t *ct, int flags) 598789Sahrens { 599789Sahrens zfsctl_snapdir_t *sdp = sdvp->v_data; 600789Sahrens zfs_snapentry_t search, *sep; 6016492Stimh zfsvfs_t *zfsvfs; 602789Sahrens avl_index_t where; 603789Sahrens char from[MAXNAMELEN], to[MAXNAMELEN]; 6046492Stimh char real[MAXNAMELEN]; 605789Sahrens int err; 606789Sahrens 6076492Stimh zfsvfs = sdvp->v_vfsp->vfs_data; 6086492Stimh ZFS_ENTER(zfsvfs); 6096492Stimh 6106492Stimh if ((flags & FIGNORECASE) || zfsvfs->z_case == ZFS_CASE_INSENSITIVE) { 6116492Stimh err = dmu_snapshot_realname(zfsvfs->z_os, snm, real, 6126492Stimh MAXNAMELEN, NULL); 6136492Stimh if (err == 0) { 6146492Stimh snm = real; 6156492Stimh } else if (err != ENOTSUP) { 6166492Stimh ZFS_EXIT(zfsvfs); 6176492Stimh return (err); 6186492Stimh } 6196492Stimh } 6206492Stimh 6216492Stimh ZFS_EXIT(zfsvfs); 6226492Stimh 6231154Smaybee err = zfsctl_snapshot_zname(sdvp, snm, MAXNAMELEN, from); 6246492Stimh if (!err) 6256492Stimh err = zfsctl_snapshot_zname(tdvp, tnm, MAXNAMELEN, to); 6266492Stimh if (!err) 6276492Stimh err = zfs_secpolicy_rename_perms(from, to, cr); 6281154Smaybee if (err) 6291154Smaybee return (err); 6304543Smarks 631789Sahrens /* 632789Sahrens * Cannot move snapshots out of the snapdir. 633789Sahrens */ 634789Sahrens if (sdvp != tdvp) 635789Sahrens return (EINVAL); 636789Sahrens 637789Sahrens if (strcmp(snm, tnm) == 0) 638789Sahrens return (0); 639789Sahrens 640789Sahrens mutex_enter(&sdp->sd_lock); 641789Sahrens 642789Sahrens search.se_name = (char *)snm; 6431154Smaybee if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) == NULL) { 6441154Smaybee mutex_exit(&sdp->sd_lock); 6451154Smaybee return (ENOENT); 646789Sahrens } 647789Sahrens 6484007Smmusante err = dmu_objset_rename(from, to, B_FALSE); 6491154Smaybee if (err == 0) 6501154Smaybee zfsctl_rename_snap(sdp, sep, tnm); 651789Sahrens 652789Sahrens mutex_exit(&sdp->sd_lock); 653789Sahrens 654789Sahrens return (err); 655789Sahrens } 656789Sahrens 657789Sahrens /* ARGSUSED */ 658789Sahrens static int 6595331Samw zfsctl_snapdir_remove(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr, 6605331Samw caller_context_t *ct, int flags) 661789Sahrens { 662789Sahrens zfsctl_snapdir_t *sdp = dvp->v_data; 6636068Sck153898 zfs_snapentry_t *sep; 6646068Sck153898 zfs_snapentry_t search; 6656492Stimh zfsvfs_t *zfsvfs; 666789Sahrens char snapname[MAXNAMELEN]; 6676492Stimh char real[MAXNAMELEN]; 668789Sahrens int err; 669789Sahrens 6706492Stimh zfsvfs = dvp->v_vfsp->vfs_data; 6716492Stimh ZFS_ENTER(zfsvfs); 6726492Stimh 6736492Stimh if ((flags & FIGNORECASE) || zfsvfs->z_case == ZFS_CASE_INSENSITIVE) { 6746492Stimh 6756492Stimh err = dmu_snapshot_realname(zfsvfs->z_os, name, real, 6766492Stimh MAXNAMELEN, NULL); 6776492Stimh if (err == 0) { 6786492Stimh name = real; 6796492Stimh } else if (err != ENOTSUP) { 6806492Stimh ZFS_EXIT(zfsvfs); 6816492Stimh return (err); 6826492Stimh } 6836492Stimh } 6846492Stimh 6856492Stimh ZFS_EXIT(zfsvfs); 6866492Stimh 6871154Smaybee err = zfsctl_snapshot_zname(dvp, name, MAXNAMELEN, snapname); 6886492Stimh if (!err) 6896492Stimh err = zfs_secpolicy_destroy_perms(snapname, cr); 6901154Smaybee if (err) 6911154Smaybee return (err); 6924543Smarks 693789Sahrens mutex_enter(&sdp->sd_lock); 694789Sahrens 6956068Sck153898 search.se_name = name; 6966068Sck153898 sep = avl_find(&sdp->sd_snaps, &search, NULL); 6976068Sck153898 if (sep) { 6986068Sck153898 avl_remove(&sdp->sd_snaps, sep); 6996068Sck153898 err = zfsctl_unmount_snap(sep, MS_FORCE, cr); 7006068Sck153898 if (err) 7016068Sck153898 avl_add(&sdp->sd_snaps, sep); 7026068Sck153898 else 70310242Schris.kirby@sun.com err = dmu_objset_destroy(snapname, B_FALSE); 7046068Sck153898 } else { 7056068Sck153898 err = ENOENT; 706789Sahrens } 707789Sahrens 708789Sahrens mutex_exit(&sdp->sd_lock); 709789Sahrens 710789Sahrens return (err); 711789Sahrens } 712789Sahrens 7135326Sek110237 /* 7145326Sek110237 * This creates a snapshot under '.zfs/snapshot'. 7155326Sek110237 */ 7164543Smarks /* ARGSUSED */ 7174543Smarks static int 7184543Smarks zfsctl_snapdir_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, 7195331Samw cred_t *cr, caller_context_t *cc, int flags, vsecattr_t *vsecp) 7204543Smarks { 7214543Smarks zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 7224543Smarks char name[MAXNAMELEN]; 7234543Smarks int err; 7244543Smarks static enum symfollow follow = NO_FOLLOW; 7254543Smarks static enum uio_seg seg = UIO_SYSSPACE; 7264543Smarks 7276658Smarks if (snapshot_namecheck(dirname, NULL, NULL) != 0) 7286658Smarks return (EILSEQ); 7296658Smarks 7304543Smarks dmu_objset_name(zfsvfs->z_os, name); 7314543Smarks 7324543Smarks *vpp = NULL; 7334543Smarks 7344543Smarks err = zfs_secpolicy_snapshot_perms(name, cr); 7354543Smarks if (err) 7364543Smarks return (err); 7374543Smarks 7384543Smarks if (err == 0) { 7399355SMatthew.Ahrens@Sun.COM err = dmu_objset_snapshot(name, dirname, NULL, B_FALSE); 7404543Smarks if (err) 7414543Smarks return (err); 7424543Smarks err = lookupnameat(dirname, seg, follow, NULL, vpp, dvp); 7434543Smarks } 7444543Smarks 7454543Smarks return (err); 7464543Smarks } 7474543Smarks 748789Sahrens /* 749789Sahrens * Lookup entry point for the 'snapshot' directory. Try to open the 750789Sahrens * snapshot if it exist, creating the pseudo filesystem vnode as necessary. 751789Sahrens * Perform a mount of the associated dataset on top of the vnode. 752789Sahrens */ 753789Sahrens /* ARGSUSED */ 754789Sahrens static int 755789Sahrens zfsctl_snapdir_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp, 7565331Samw int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct, 7575331Samw int *direntflags, pathname_t *realpnp) 758789Sahrens { 759789Sahrens zfsctl_snapdir_t *sdp = dvp->v_data; 760789Sahrens objset_t *snap; 761789Sahrens char snapname[MAXNAMELEN]; 7626492Stimh char real[MAXNAMELEN]; 763789Sahrens char *mountpoint; 764789Sahrens zfs_snapentry_t *sep, search; 765789Sahrens struct mounta margs; 766789Sahrens vfs_t *vfsp; 767789Sahrens size_t mountpoint_len; 768789Sahrens avl_index_t where; 769789Sahrens zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 770789Sahrens int err; 771789Sahrens 7725331Samw /* 7735331Samw * No extended attributes allowed under .zfs 7745331Samw */ 7755331Samw if (flags & LOOKUP_XATTR) 7765331Samw return (EINVAL); 7775331Samw 778789Sahrens ASSERT(dvp->v_type == VDIR); 779789Sahrens 780789Sahrens /* 781789Sahrens * If we get a recursive call, that means we got called 782789Sahrens * from the domount() code while it was trying to look up the 783789Sahrens * spec (which looks like a local path for zfs). We need to 784789Sahrens * add some flag to domount() to tell it not to do this lookup. 785789Sahrens */ 786789Sahrens if (MUTEX_HELD(&sdp->sd_lock)) 787789Sahrens return (ENOENT); 788789Sahrens 789789Sahrens ZFS_ENTER(zfsvfs); 790789Sahrens 7919214Schris.kirby@sun.com if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0) { 7929214Schris.kirby@sun.com ZFS_EXIT(zfsvfs); 7939214Schris.kirby@sun.com return (0); 7949214Schris.kirby@sun.com } 7959214Schris.kirby@sun.com 7966492Stimh if (flags & FIGNORECASE) { 7976492Stimh boolean_t conflict = B_FALSE; 7986492Stimh 7996492Stimh err = dmu_snapshot_realname(zfsvfs->z_os, nm, real, 8006492Stimh MAXNAMELEN, &conflict); 8016492Stimh if (err == 0) { 8026492Stimh nm = real; 8036492Stimh } else if (err != ENOTSUP) { 8046492Stimh ZFS_EXIT(zfsvfs); 8056492Stimh return (err); 8066492Stimh } 8076492Stimh if (realpnp) 8086492Stimh (void) strlcpy(realpnp->pn_buf, nm, 8096492Stimh realpnp->pn_bufsize); 8106492Stimh if (conflict && direntflags) 8116492Stimh *direntflags = ED_CASE_CONFLICT; 8126492Stimh } 8136492Stimh 814789Sahrens mutex_enter(&sdp->sd_lock); 815789Sahrens search.se_name = (char *)nm; 816789Sahrens if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) != NULL) { 817789Sahrens *vpp = sep->se_root; 818789Sahrens VN_HOLD(*vpp); 8191589Smaybee err = traverse(vpp); 8201589Smaybee if (err) { 8211589Smaybee VN_RELE(*vpp); 8221589Smaybee *vpp = NULL; 8231589Smaybee } else if (*vpp == sep->se_root) { 8241589Smaybee /* 8251589Smaybee * The snapshot was unmounted behind our backs, 8261589Smaybee * try to remount it. 8271589Smaybee */ 828789Sahrens goto domount; 8296068Sck153898 } else { 8306068Sck153898 /* 8316068Sck153898 * VROOT was set during the traverse call. We need 8326068Sck153898 * to clear it since we're pretending to be part 8336068Sck153898 * of our parent's vfs. 8346068Sck153898 */ 8356068Sck153898 (*vpp)->v_flag &= ~VROOT; 8361566Smaybee } 837789Sahrens mutex_exit(&sdp->sd_lock); 838789Sahrens ZFS_EXIT(zfsvfs); 8391589Smaybee return (err); 840789Sahrens } 841789Sahrens 842789Sahrens /* 843789Sahrens * The requested snapshot is not currently mounted, look it up. 844789Sahrens */ 8451154Smaybee err = zfsctl_snapshot_zname(dvp, nm, MAXNAMELEN, snapname); 8461154Smaybee if (err) { 8471154Smaybee mutex_exit(&sdp->sd_lock); 8481154Smaybee ZFS_EXIT(zfsvfs); 8497229Smarks /* 8507229Smarks * handle "ls *" or "?" in a graceful manner, 8517229Smarks * forcing EILSEQ to ENOENT. 8527229Smarks * Since shell ultimately passes "*" or "?" as name to lookup 8537229Smarks */ 8547229Smarks return (err == EILSEQ ? ENOENT : err); 8551154Smaybee } 856*10298SMatthew.Ahrens@Sun.COM if (dmu_objset_hold(snapname, FTAG, &snap) != 0) { 857789Sahrens mutex_exit(&sdp->sd_lock); 858789Sahrens ZFS_EXIT(zfsvfs); 859789Sahrens return (ENOENT); 860789Sahrens } 861789Sahrens 862789Sahrens sep = kmem_alloc(sizeof (zfs_snapentry_t), KM_SLEEP); 863789Sahrens sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP); 864789Sahrens (void) strcpy(sep->se_name, nm); 865789Sahrens *vpp = sep->se_root = zfsctl_snapshot_mknode(dvp, dmu_objset_id(snap)); 866789Sahrens avl_insert(&sdp->sd_snaps, sep, where); 867789Sahrens 868*10298SMatthew.Ahrens@Sun.COM dmu_objset_rele(snap, FTAG); 869789Sahrens domount: 870789Sahrens mountpoint_len = strlen(refstr_value(dvp->v_vfsp->vfs_mntpt)) + 871789Sahrens strlen("/.zfs/snapshot/") + strlen(nm) + 1; 872789Sahrens mountpoint = kmem_alloc(mountpoint_len, KM_SLEEP); 873789Sahrens (void) snprintf(mountpoint, mountpoint_len, "%s/.zfs/snapshot/%s", 874789Sahrens refstr_value(dvp->v_vfsp->vfs_mntpt), nm); 875789Sahrens 876789Sahrens margs.spec = snapname; 877789Sahrens margs.dir = mountpoint; 878789Sahrens margs.flags = MS_SYSSPACE | MS_NOMNTTAB; 879789Sahrens margs.fstype = "zfs"; 880789Sahrens margs.dataptr = NULL; 881789Sahrens margs.datalen = 0; 882789Sahrens margs.optptr = NULL; 883789Sahrens margs.optlen = 0; 884789Sahrens 885789Sahrens err = domount("zfs", &margs, *vpp, kcred, &vfsp); 886789Sahrens kmem_free(mountpoint, mountpoint_len); 887789Sahrens 888816Smaybee if (err == 0) { 889816Smaybee /* 890816Smaybee * Return the mounted root rather than the covered mount point. 8915326Sek110237 * Takes the GFS vnode at .zfs/snapshot/<snapname> and returns 8925326Sek110237 * the ZFS vnode mounted on top of the GFS node. This ZFS 8939214Schris.kirby@sun.com * vnode is the root of the newly created vfsp. 894816Smaybee */ 895816Smaybee VFS_RELE(vfsp); 896816Smaybee err = traverse(vpp); 897816Smaybee } 898789Sahrens 899816Smaybee if (err == 0) { 900816Smaybee /* 9015326Sek110237 * Fix up the root vnode mounted on .zfs/snapshot/<snapname>. 9024736Sek110237 * 9034736Sek110237 * This is where we lie about our v_vfsp in order to 9045326Sek110237 * make .zfs/snapshot/<snapname> accessible over NFS 9055326Sek110237 * without requiring manual mounts of <snapname>. 906816Smaybee */ 907816Smaybee ASSERT(VTOZ(*vpp)->z_zfsvfs != zfsvfs); 908816Smaybee VTOZ(*vpp)->z_zfsvfs->z_parent = zfsvfs; 909816Smaybee (*vpp)->v_vfsp = zfsvfs->z_vfs; 910816Smaybee (*vpp)->v_flag &= ~VROOT; 911816Smaybee } 912789Sahrens mutex_exit(&sdp->sd_lock); 913789Sahrens ZFS_EXIT(zfsvfs); 914789Sahrens 9151566Smaybee /* 9161566Smaybee * If we had an error, drop our hold on the vnode and 9171566Smaybee * zfsctl_snapshot_inactive() will clean up. 9181566Smaybee */ 9191566Smaybee if (err) { 920816Smaybee VN_RELE(*vpp); 9211566Smaybee *vpp = NULL; 9221566Smaybee } 923816Smaybee return (err); 924789Sahrens } 925789Sahrens 926789Sahrens /* ARGSUSED */ 927789Sahrens static int 9288845Samw@Sun.COM zfsctl_shares_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp, 9298845Samw@Sun.COM int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct, 9308845Samw@Sun.COM int *direntflags, pathname_t *realpnp) 9318845Samw@Sun.COM { 9328845Samw@Sun.COM zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 9338845Samw@Sun.COM znode_t *dzp; 9348845Samw@Sun.COM int error; 9358845Samw@Sun.COM 9368845Samw@Sun.COM ZFS_ENTER(zfsvfs); 9378845Samw@Sun.COM 9388845Samw@Sun.COM if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0) { 9398845Samw@Sun.COM ZFS_EXIT(zfsvfs); 9408845Samw@Sun.COM return (0); 9418845Samw@Sun.COM } 9428845Samw@Sun.COM 9439030SMark.Shellenbaum@Sun.COM if (zfsvfs->z_shares_dir == 0) { 9449030SMark.Shellenbaum@Sun.COM ZFS_EXIT(zfsvfs); 9459030SMark.Shellenbaum@Sun.COM return (ENOTSUP); 9469030SMark.Shellenbaum@Sun.COM } 9478845Samw@Sun.COM if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) 9488845Samw@Sun.COM error = VOP_LOOKUP(ZTOV(dzp), nm, vpp, pnp, 9498845Samw@Sun.COM flags, rdir, cr, ct, direntflags, realpnp); 9508845Samw@Sun.COM 9518845Samw@Sun.COM VN_RELE(ZTOV(dzp)); 9528845Samw@Sun.COM ZFS_EXIT(zfsvfs); 9538845Samw@Sun.COM 9548845Samw@Sun.COM return (error); 9558845Samw@Sun.COM } 9568845Samw@Sun.COM 9578845Samw@Sun.COM /* ARGSUSED */ 9588845Samw@Sun.COM static int 9595663Sck153898 zfsctl_snapdir_readdir_cb(vnode_t *vp, void *dp, int *eofp, 9605663Sck153898 offset_t *offp, offset_t *nextp, void *data, int flags) 961789Sahrens { 962789Sahrens zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 963789Sahrens char snapname[MAXNAMELEN]; 964789Sahrens uint64_t id, cookie; 9655663Sck153898 boolean_t case_conflict; 9665663Sck153898 int error; 967789Sahrens 968789Sahrens ZFS_ENTER(zfsvfs); 969789Sahrens 970789Sahrens cookie = *offp; 9715663Sck153898 error = dmu_snapshot_list_next(zfsvfs->z_os, MAXNAMELEN, snapname, &id, 9725663Sck153898 &cookie, &case_conflict); 9735663Sck153898 if (error) { 974789Sahrens ZFS_EXIT(zfsvfs); 9755663Sck153898 if (error == ENOENT) { 9765663Sck153898 *eofp = 1; 9775663Sck153898 return (0); 9785663Sck153898 } 9795663Sck153898 return (error); 980789Sahrens } 981789Sahrens 9825663Sck153898 if (flags & V_RDDIR_ENTFLAGS) { 9835663Sck153898 edirent_t *eodp = dp; 9845663Sck153898 9855663Sck153898 (void) strcpy(eodp->ed_name, snapname); 9865663Sck153898 eodp->ed_ino = ZFSCTL_INO_SNAP(id); 9875663Sck153898 eodp->ed_eflags = case_conflict ? ED_CASE_CONFLICT : 0; 9885663Sck153898 } else { 9895663Sck153898 struct dirent64 *odp = dp; 9905663Sck153898 9915663Sck153898 (void) strcpy(odp->d_name, snapname); 9925663Sck153898 odp->d_ino = ZFSCTL_INO_SNAP(id); 9935663Sck153898 } 994789Sahrens *nextp = cookie; 995789Sahrens 996789Sahrens ZFS_EXIT(zfsvfs); 997789Sahrens 998789Sahrens return (0); 999789Sahrens } 1000789Sahrens 10018845Samw@Sun.COM /* ARGSUSED */ 10028845Samw@Sun.COM static int 10038845Samw@Sun.COM zfsctl_shares_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp, 10048845Samw@Sun.COM caller_context_t *ct, int flags) 10058845Samw@Sun.COM { 10068845Samw@Sun.COM zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 10078845Samw@Sun.COM znode_t *dzp; 10088845Samw@Sun.COM int error; 10098845Samw@Sun.COM 10108845Samw@Sun.COM ZFS_ENTER(zfsvfs); 10118845Samw@Sun.COM 10129030SMark.Shellenbaum@Sun.COM if (zfsvfs->z_shares_dir == 0) { 10139030SMark.Shellenbaum@Sun.COM ZFS_EXIT(zfsvfs); 10149030SMark.Shellenbaum@Sun.COM return (ENOTSUP); 10159030SMark.Shellenbaum@Sun.COM } 10168845Samw@Sun.COM if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) { 10178845Samw@Sun.COM error = VOP_READDIR(ZTOV(dzp), uiop, cr, eofp, ct, flags); 10188845Samw@Sun.COM VN_RELE(ZTOV(dzp)); 10198845Samw@Sun.COM } else { 10208845Samw@Sun.COM *eofp = 1; 10218845Samw@Sun.COM error = ENOENT; 10228845Samw@Sun.COM } 10238845Samw@Sun.COM 10248845Samw@Sun.COM ZFS_EXIT(zfsvfs); 10258845Samw@Sun.COM return (error); 10268845Samw@Sun.COM } 10278845Samw@Sun.COM 10285326Sek110237 /* 10295326Sek110237 * pvp is the '.zfs' directory (zfsctl_node_t). 10305326Sek110237 * Creates vp, which is '.zfs/snapshot' (zfsctl_snapdir_t). 10315326Sek110237 * 10325326Sek110237 * This function is the callback to create a GFS vnode for '.zfs/snapshot' 10335326Sek110237 * when a lookup is performed on .zfs for "snapshot". 10345326Sek110237 */ 1035789Sahrens vnode_t * 1036789Sahrens zfsctl_mknode_snapdir(vnode_t *pvp) 1037789Sahrens { 1038789Sahrens vnode_t *vp; 1039789Sahrens zfsctl_snapdir_t *sdp; 1040789Sahrens 1041789Sahrens vp = gfs_dir_create(sizeof (zfsctl_snapdir_t), pvp, 1042789Sahrens zfsctl_ops_snapdir, NULL, NULL, MAXNAMELEN, 1043789Sahrens zfsctl_snapdir_readdir_cb, NULL); 1044789Sahrens sdp = vp->v_data; 1045789Sahrens sdp->sd_node.zc_id = ZFSCTL_INO_SNAPDIR; 10461571Sek110237 sdp->sd_node.zc_cmtime = ((zfsctl_node_t *)pvp->v_data)->zc_cmtime; 1047789Sahrens mutex_init(&sdp->sd_lock, NULL, MUTEX_DEFAULT, NULL); 1048789Sahrens avl_create(&sdp->sd_snaps, snapentry_compare, 1049789Sahrens sizeof (zfs_snapentry_t), offsetof(zfs_snapentry_t, se_node)); 1050789Sahrens return (vp); 1051789Sahrens } 1052789Sahrens 10538845Samw@Sun.COM vnode_t * 10548845Samw@Sun.COM zfsctl_mknode_shares(vnode_t *pvp) 10558845Samw@Sun.COM { 10568845Samw@Sun.COM vnode_t *vp; 10578845Samw@Sun.COM zfsctl_node_t *sdp; 10588845Samw@Sun.COM 10598845Samw@Sun.COM vp = gfs_dir_create(sizeof (zfsctl_node_t), pvp, 10608845Samw@Sun.COM zfsctl_ops_shares, NULL, NULL, MAXNAMELEN, 10618845Samw@Sun.COM NULL, NULL); 10628845Samw@Sun.COM sdp = vp->v_data; 10638845Samw@Sun.COM sdp->zc_cmtime = ((zfsctl_node_t *)pvp->v_data)->zc_cmtime; 10648845Samw@Sun.COM return (vp); 10658845Samw@Sun.COM 10668845Samw@Sun.COM } 10678845Samw@Sun.COM 10688845Samw@Sun.COM /* ARGSUSED */ 10698845Samw@Sun.COM static int 10708845Samw@Sun.COM zfsctl_shares_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 10718845Samw@Sun.COM caller_context_t *ct) 10728845Samw@Sun.COM { 10738845Samw@Sun.COM zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 10748845Samw@Sun.COM znode_t *dzp; 10758845Samw@Sun.COM int error; 10768845Samw@Sun.COM 10778845Samw@Sun.COM ZFS_ENTER(zfsvfs); 10789030SMark.Shellenbaum@Sun.COM if (zfsvfs->z_shares_dir == 0) { 10799030SMark.Shellenbaum@Sun.COM ZFS_EXIT(zfsvfs); 10809030SMark.Shellenbaum@Sun.COM return (ENOTSUP); 10819030SMark.Shellenbaum@Sun.COM } 10828845Samw@Sun.COM if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) { 10838845Samw@Sun.COM error = VOP_GETATTR(ZTOV(dzp), vap, flags, cr, ct); 10848845Samw@Sun.COM VN_RELE(ZTOV(dzp)); 10858845Samw@Sun.COM } 10868845Samw@Sun.COM ZFS_EXIT(zfsvfs); 10878845Samw@Sun.COM return (error); 10888845Samw@Sun.COM 10898845Samw@Sun.COM 10908845Samw@Sun.COM } 10918845Samw@Sun.COM 1092789Sahrens /* ARGSUSED */ 1093789Sahrens static int 10945331Samw zfsctl_snapdir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 10955331Samw caller_context_t *ct) 1096789Sahrens { 1097789Sahrens zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 1098789Sahrens zfsctl_snapdir_t *sdp = vp->v_data; 1099789Sahrens 1100789Sahrens ZFS_ENTER(zfsvfs); 1101789Sahrens zfsctl_common_getattr(vp, vap); 1102789Sahrens vap->va_nodeid = gfs_file_inode(vp); 1103789Sahrens vap->va_nlink = vap->va_size = avl_numnodes(&sdp->sd_snaps) + 2; 1104789Sahrens ZFS_EXIT(zfsvfs); 1105789Sahrens 1106789Sahrens return (0); 1107789Sahrens } 1108789Sahrens 11091566Smaybee /* ARGSUSED */ 1110789Sahrens static void 11115331Samw zfsctl_snapdir_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) 1112789Sahrens { 1113789Sahrens zfsctl_snapdir_t *sdp = vp->v_data; 11141566Smaybee void *private; 1115789Sahrens 11161566Smaybee private = gfs_dir_inactive(vp); 11171566Smaybee if (private != NULL) { 11181566Smaybee ASSERT(avl_numnodes(&sdp->sd_snaps) == 0); 11191566Smaybee mutex_destroy(&sdp->sd_lock); 11201566Smaybee avl_destroy(&sdp->sd_snaps); 11211566Smaybee kmem_free(private, sizeof (zfsctl_snapdir_t)); 11221566Smaybee } 1123789Sahrens } 1124789Sahrens 1125789Sahrens static const fs_operation_def_t zfsctl_tops_snapdir[] = { 11263898Srsb { VOPNAME_OPEN, { .vop_open = zfsctl_common_open } }, 11273898Srsb { VOPNAME_CLOSE, { .vop_close = zfsctl_common_close } }, 11283898Srsb { VOPNAME_IOCTL, { .error = fs_inval } }, 11293898Srsb { VOPNAME_GETATTR, { .vop_getattr = zfsctl_snapdir_getattr } }, 11303898Srsb { VOPNAME_ACCESS, { .vop_access = zfsctl_common_access } }, 11313898Srsb { VOPNAME_RENAME, { .vop_rename = zfsctl_snapdir_rename } }, 11323898Srsb { VOPNAME_RMDIR, { .vop_rmdir = zfsctl_snapdir_remove } }, 11334543Smarks { VOPNAME_MKDIR, { .vop_mkdir = zfsctl_snapdir_mkdir } }, 11343898Srsb { VOPNAME_READDIR, { .vop_readdir = gfs_vop_readdir } }, 11353898Srsb { VOPNAME_LOOKUP, { .vop_lookup = zfsctl_snapdir_lookup } }, 11363898Srsb { VOPNAME_SEEK, { .vop_seek = fs_seek } }, 11373898Srsb { VOPNAME_INACTIVE, { .vop_inactive = zfsctl_snapdir_inactive } }, 11383898Srsb { VOPNAME_FID, { .vop_fid = zfsctl_common_fid } }, 1139789Sahrens { NULL } 1140789Sahrens }; 1141789Sahrens 11428845Samw@Sun.COM static const fs_operation_def_t zfsctl_tops_shares[] = { 11438845Samw@Sun.COM { VOPNAME_OPEN, { .vop_open = zfsctl_common_open } }, 11448845Samw@Sun.COM { VOPNAME_CLOSE, { .vop_close = zfsctl_common_close } }, 11458845Samw@Sun.COM { VOPNAME_IOCTL, { .error = fs_inval } }, 11468845Samw@Sun.COM { VOPNAME_GETATTR, { .vop_getattr = zfsctl_shares_getattr } }, 11478845Samw@Sun.COM { VOPNAME_ACCESS, { .vop_access = zfsctl_common_access } }, 11488845Samw@Sun.COM { VOPNAME_READDIR, { .vop_readdir = zfsctl_shares_readdir } }, 11498845Samw@Sun.COM { VOPNAME_LOOKUP, { .vop_lookup = zfsctl_shares_lookup } }, 11508845Samw@Sun.COM { VOPNAME_SEEK, { .vop_seek = fs_seek } }, 11518845Samw@Sun.COM { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } }, 11528845Samw@Sun.COM { VOPNAME_FID, { .vop_fid = zfsctl_shares_fid } }, 11538845Samw@Sun.COM { NULL } 11548845Samw@Sun.COM }; 11558845Samw@Sun.COM 11565326Sek110237 /* 11575326Sek110237 * pvp is the GFS vnode '.zfs/snapshot'. 11585326Sek110237 * 11595326Sek110237 * This creates a GFS node under '.zfs/snapshot' representing each 11605326Sek110237 * snapshot. This newly created GFS node is what we mount snapshot 11615326Sek110237 * vfs_t's ontop of. 11625326Sek110237 */ 1163789Sahrens static vnode_t * 1164789Sahrens zfsctl_snapshot_mknode(vnode_t *pvp, uint64_t objset) 1165789Sahrens { 1166789Sahrens vnode_t *vp; 1167789Sahrens zfsctl_node_t *zcp; 1168789Sahrens 1169789Sahrens vp = gfs_dir_create(sizeof (zfsctl_node_t), pvp, 1170789Sahrens zfsctl_ops_snapshot, NULL, NULL, MAXNAMELEN, NULL, NULL); 1171789Sahrens zcp = vp->v_data; 1172789Sahrens zcp->zc_id = objset; 1173789Sahrens 1174789Sahrens return (vp); 1175789Sahrens } 1176789Sahrens 1177789Sahrens static void 11785331Samw zfsctl_snapshot_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) 1179789Sahrens { 1180789Sahrens zfsctl_snapdir_t *sdp; 1181789Sahrens zfs_snapentry_t *sep, *next; 1182789Sahrens vnode_t *dvp; 1183789Sahrens 11846492Stimh VERIFY(gfs_dir_lookup(vp, "..", &dvp, cr, 0, NULL, NULL) == 0); 1185789Sahrens sdp = dvp->v_data; 1186789Sahrens 1187789Sahrens mutex_enter(&sdp->sd_lock); 1188789Sahrens 1189789Sahrens if (vp->v_count > 1) { 1190789Sahrens mutex_exit(&sdp->sd_lock); 1191789Sahrens return; 1192789Sahrens } 1193789Sahrens ASSERT(!vn_ismntpt(vp)); 1194789Sahrens 1195789Sahrens sep = avl_first(&sdp->sd_snaps); 1196789Sahrens while (sep != NULL) { 1197789Sahrens next = AVL_NEXT(&sdp->sd_snaps, sep); 1198789Sahrens 1199789Sahrens if (sep->se_root == vp) { 1200789Sahrens avl_remove(&sdp->sd_snaps, sep); 1201789Sahrens kmem_free(sep->se_name, strlen(sep->se_name) + 1); 1202789Sahrens kmem_free(sep, sizeof (zfs_snapentry_t)); 1203789Sahrens break; 1204789Sahrens } 1205789Sahrens sep = next; 1206789Sahrens } 1207789Sahrens ASSERT(sep != NULL); 1208789Sahrens 1209789Sahrens mutex_exit(&sdp->sd_lock); 1210789Sahrens VN_RELE(dvp); 1211789Sahrens 12121566Smaybee /* 12131566Smaybee * Dispose of the vnode for the snapshot mount point. 12141566Smaybee * This is safe to do because once this entry has been removed 12151566Smaybee * from the AVL tree, it can't be found again, so cannot become 12161566Smaybee * "active". If we lookup the same name again we will end up 12171566Smaybee * creating a new vnode. 12181566Smaybee */ 12195331Samw gfs_vop_inactive(vp, cr, ct); 1220789Sahrens } 1221789Sahrens 1222789Sahrens 1223789Sahrens /* 1224789Sahrens * These VP's should never see the light of day. They should always 1225789Sahrens * be covered. 1226789Sahrens */ 1227789Sahrens static const fs_operation_def_t zfsctl_tops_snapshot[] = { 12283898Srsb VOPNAME_INACTIVE, { .vop_inactive = zfsctl_snapshot_inactive }, 1229789Sahrens NULL, NULL 1230789Sahrens }; 1231789Sahrens 1232789Sahrens int 1233789Sahrens zfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t **zfsvfsp) 1234789Sahrens { 1235789Sahrens zfsvfs_t *zfsvfs = vfsp->vfs_data; 1236789Sahrens vnode_t *dvp, *vp; 1237789Sahrens zfsctl_snapdir_t *sdp; 1238789Sahrens zfsctl_node_t *zcp; 1239789Sahrens zfs_snapentry_t *sep; 1240789Sahrens int error; 1241789Sahrens 1242789Sahrens ASSERT(zfsvfs->z_ctldir != NULL); 1243789Sahrens error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp, 12445331Samw NULL, 0, NULL, kcred, NULL, NULL, NULL); 1245789Sahrens if (error != 0) 1246789Sahrens return (error); 1247789Sahrens sdp = dvp->v_data; 1248789Sahrens 1249789Sahrens mutex_enter(&sdp->sd_lock); 1250789Sahrens sep = avl_first(&sdp->sd_snaps); 1251789Sahrens while (sep != NULL) { 1252789Sahrens vp = sep->se_root; 1253789Sahrens zcp = vp->v_data; 1254789Sahrens if (zcp->zc_id == objsetid) 1255789Sahrens break; 1256789Sahrens 1257789Sahrens sep = AVL_NEXT(&sdp->sd_snaps, sep); 1258789Sahrens } 1259789Sahrens 1260789Sahrens if (sep != NULL) { 1261789Sahrens VN_HOLD(vp); 12625326Sek110237 /* 12635326Sek110237 * Return the mounted root rather than the covered mount point. 12645326Sek110237 * Takes the GFS vnode at .zfs/snapshot/<snapshot objsetid> 12655326Sek110237 * and returns the ZFS vnode mounted on top of the GFS node. 12665326Sek110237 * This ZFS vnode is the root of the vfs for objset 'objsetid'. 12675326Sek110237 */ 1268789Sahrens error = traverse(&vp); 12691589Smaybee if (error == 0) { 12701589Smaybee if (vp == sep->se_root) 12711589Smaybee error = EINVAL; 12721589Smaybee else 12731589Smaybee *zfsvfsp = VTOZ(vp)->z_zfsvfs; 12741589Smaybee } 12751572Snd150628 mutex_exit(&sdp->sd_lock); 1276789Sahrens VN_RELE(vp); 1277789Sahrens } else { 1278789Sahrens error = EINVAL; 12791572Snd150628 mutex_exit(&sdp->sd_lock); 1280789Sahrens } 1281789Sahrens 1282789Sahrens VN_RELE(dvp); 1283789Sahrens 1284789Sahrens return (error); 1285789Sahrens } 1286789Sahrens 1287789Sahrens /* 1288789Sahrens * Unmount any snapshots for the given filesystem. This is called from 1289789Sahrens * zfs_umount() - if we have a ctldir, then go through and unmount all the 1290789Sahrens * snapshots. 1291789Sahrens */ 1292789Sahrens int 1293789Sahrens zfsctl_umount_snapshots(vfs_t *vfsp, int fflags, cred_t *cr) 1294789Sahrens { 1295789Sahrens zfsvfs_t *zfsvfs = vfsp->vfs_data; 12966068Sck153898 vnode_t *dvp; 1297789Sahrens zfsctl_snapdir_t *sdp; 1298789Sahrens zfs_snapentry_t *sep, *next; 1299789Sahrens int error; 1300789Sahrens 1301789Sahrens ASSERT(zfsvfs->z_ctldir != NULL); 1302789Sahrens error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp, 13035331Samw NULL, 0, NULL, cr, NULL, NULL, NULL); 1304789Sahrens if (error != 0) 1305789Sahrens return (error); 1306789Sahrens sdp = dvp->v_data; 1307789Sahrens 1308789Sahrens mutex_enter(&sdp->sd_lock); 1309789Sahrens 1310789Sahrens sep = avl_first(&sdp->sd_snaps); 1311789Sahrens while (sep != NULL) { 1312789Sahrens next = AVL_NEXT(&sdp->sd_snaps, sep); 1313789Sahrens 1314789Sahrens /* 1315789Sahrens * If this snapshot is not mounted, then it must 1316789Sahrens * have just been unmounted by somebody else, and 1317789Sahrens * will be cleaned up by zfsctl_snapdir_inactive(). 1318789Sahrens */ 13196068Sck153898 if (vn_ismntpt(sep->se_root)) { 13206068Sck153898 avl_remove(&sdp->sd_snaps, sep); 13216068Sck153898 error = zfsctl_unmount_snap(sep, fflags, cr); 1322789Sahrens if (error) { 13236068Sck153898 avl_add(&sdp->sd_snaps, sep); 13246068Sck153898 break; 1325789Sahrens } 1326789Sahrens } 1327789Sahrens sep = next; 1328789Sahrens } 13296068Sck153898 1330789Sahrens mutex_exit(&sdp->sd_lock); 1331789Sahrens VN_RELE(dvp); 1332789Sahrens 1333789Sahrens return (error); 1334789Sahrens } 1335