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 } 526*9214Schris.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 7036068Sck153898 err = dmu_objset_destroy(snapname); 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) { 7394543Smarks err = dmu_objset_snapshot(name, dirname, 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 791*9214Schris.kirby@sun.com if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0) { 792*9214Schris.kirby@sun.com ZFS_EXIT(zfsvfs); 793*9214Schris.kirby@sun.com return (0); 794*9214Schris.kirby@sun.com } 795*9214Schris.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 } 856789Sahrens if (dmu_objset_open(snapname, DMU_OST_ZFS, 8576689Smaybee DS_MODE_USER | DS_MODE_READONLY, &snap) != 0) { 858789Sahrens mutex_exit(&sdp->sd_lock); 859789Sahrens ZFS_EXIT(zfsvfs); 860789Sahrens return (ENOENT); 861789Sahrens } 862789Sahrens 863789Sahrens sep = kmem_alloc(sizeof (zfs_snapentry_t), KM_SLEEP); 864789Sahrens sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP); 865789Sahrens (void) strcpy(sep->se_name, nm); 866789Sahrens *vpp = sep->se_root = zfsctl_snapshot_mknode(dvp, dmu_objset_id(snap)); 867789Sahrens avl_insert(&sdp->sd_snaps, sep, where); 868789Sahrens 869789Sahrens dmu_objset_close(snap); 870789Sahrens domount: 871789Sahrens mountpoint_len = strlen(refstr_value(dvp->v_vfsp->vfs_mntpt)) + 872789Sahrens strlen("/.zfs/snapshot/") + strlen(nm) + 1; 873789Sahrens mountpoint = kmem_alloc(mountpoint_len, KM_SLEEP); 874789Sahrens (void) snprintf(mountpoint, mountpoint_len, "%s/.zfs/snapshot/%s", 875789Sahrens refstr_value(dvp->v_vfsp->vfs_mntpt), nm); 876789Sahrens 877789Sahrens margs.spec = snapname; 878789Sahrens margs.dir = mountpoint; 879789Sahrens margs.flags = MS_SYSSPACE | MS_NOMNTTAB; 880789Sahrens margs.fstype = "zfs"; 881789Sahrens margs.dataptr = NULL; 882789Sahrens margs.datalen = 0; 883789Sahrens margs.optptr = NULL; 884789Sahrens margs.optlen = 0; 885789Sahrens 886789Sahrens err = domount("zfs", &margs, *vpp, kcred, &vfsp); 887789Sahrens kmem_free(mountpoint, mountpoint_len); 888789Sahrens 889816Smaybee if (err == 0) { 890816Smaybee /* 891816Smaybee * Return the mounted root rather than the covered mount point. 8925326Sek110237 * Takes the GFS vnode at .zfs/snapshot/<snapname> and returns 8935326Sek110237 * the ZFS vnode mounted on top of the GFS node. This ZFS 894*9214Schris.kirby@sun.com * vnode is the root of the newly created vfsp. 895816Smaybee */ 896816Smaybee VFS_RELE(vfsp); 897816Smaybee err = traverse(vpp); 898816Smaybee } 899789Sahrens 900816Smaybee if (err == 0) { 901816Smaybee /* 9025326Sek110237 * Fix up the root vnode mounted on .zfs/snapshot/<snapname>. 9034736Sek110237 * 9044736Sek110237 * This is where we lie about our v_vfsp in order to 9055326Sek110237 * make .zfs/snapshot/<snapname> accessible over NFS 9065326Sek110237 * without requiring manual mounts of <snapname>. 907816Smaybee */ 908816Smaybee ASSERT(VTOZ(*vpp)->z_zfsvfs != zfsvfs); 909816Smaybee VTOZ(*vpp)->z_zfsvfs->z_parent = zfsvfs; 910816Smaybee (*vpp)->v_vfsp = zfsvfs->z_vfs; 911816Smaybee (*vpp)->v_flag &= ~VROOT; 912816Smaybee } 913789Sahrens mutex_exit(&sdp->sd_lock); 914789Sahrens ZFS_EXIT(zfsvfs); 915789Sahrens 9161566Smaybee /* 9171566Smaybee * If we had an error, drop our hold on the vnode and 9181566Smaybee * zfsctl_snapshot_inactive() will clean up. 9191566Smaybee */ 9201566Smaybee if (err) { 921816Smaybee VN_RELE(*vpp); 9221566Smaybee *vpp = NULL; 9231566Smaybee } 924816Smaybee return (err); 925789Sahrens } 926789Sahrens 927789Sahrens /* ARGSUSED */ 928789Sahrens static int 9298845Samw@Sun.COM zfsctl_shares_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp, 9308845Samw@Sun.COM int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct, 9318845Samw@Sun.COM int *direntflags, pathname_t *realpnp) 9328845Samw@Sun.COM { 9338845Samw@Sun.COM zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 9348845Samw@Sun.COM znode_t *dzp; 9358845Samw@Sun.COM int error; 9368845Samw@Sun.COM 9378845Samw@Sun.COM ZFS_ENTER(zfsvfs); 9388845Samw@Sun.COM 9398845Samw@Sun.COM if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0) { 9408845Samw@Sun.COM ZFS_EXIT(zfsvfs); 9418845Samw@Sun.COM return (0); 9428845Samw@Sun.COM } 9438845Samw@Sun.COM 9449030SMark.Shellenbaum@Sun.COM if (zfsvfs->z_shares_dir == 0) { 9459030SMark.Shellenbaum@Sun.COM ZFS_EXIT(zfsvfs); 9469030SMark.Shellenbaum@Sun.COM return (ENOTSUP); 9479030SMark.Shellenbaum@Sun.COM } 9488845Samw@Sun.COM if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) 9498845Samw@Sun.COM error = VOP_LOOKUP(ZTOV(dzp), nm, vpp, pnp, 9508845Samw@Sun.COM flags, rdir, cr, ct, direntflags, realpnp); 9518845Samw@Sun.COM 9528845Samw@Sun.COM VN_RELE(ZTOV(dzp)); 9538845Samw@Sun.COM ZFS_EXIT(zfsvfs); 9548845Samw@Sun.COM 9558845Samw@Sun.COM return (error); 9568845Samw@Sun.COM } 9578845Samw@Sun.COM 9588845Samw@Sun.COM /* ARGSUSED */ 9598845Samw@Sun.COM static int 9605663Sck153898 zfsctl_snapdir_readdir_cb(vnode_t *vp, void *dp, int *eofp, 9615663Sck153898 offset_t *offp, offset_t *nextp, void *data, int flags) 962789Sahrens { 963789Sahrens zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 964789Sahrens char snapname[MAXNAMELEN]; 965789Sahrens uint64_t id, cookie; 9665663Sck153898 boolean_t case_conflict; 9675663Sck153898 int error; 968789Sahrens 969789Sahrens ZFS_ENTER(zfsvfs); 970789Sahrens 971789Sahrens cookie = *offp; 9725663Sck153898 error = dmu_snapshot_list_next(zfsvfs->z_os, MAXNAMELEN, snapname, &id, 9735663Sck153898 &cookie, &case_conflict); 9745663Sck153898 if (error) { 975789Sahrens ZFS_EXIT(zfsvfs); 9765663Sck153898 if (error == ENOENT) { 9775663Sck153898 *eofp = 1; 9785663Sck153898 return (0); 9795663Sck153898 } 9805663Sck153898 return (error); 981789Sahrens } 982789Sahrens 9835663Sck153898 if (flags & V_RDDIR_ENTFLAGS) { 9845663Sck153898 edirent_t *eodp = dp; 9855663Sck153898 9865663Sck153898 (void) strcpy(eodp->ed_name, snapname); 9875663Sck153898 eodp->ed_ino = ZFSCTL_INO_SNAP(id); 9885663Sck153898 eodp->ed_eflags = case_conflict ? ED_CASE_CONFLICT : 0; 9895663Sck153898 } else { 9905663Sck153898 struct dirent64 *odp = dp; 9915663Sck153898 9925663Sck153898 (void) strcpy(odp->d_name, snapname); 9935663Sck153898 odp->d_ino = ZFSCTL_INO_SNAP(id); 9945663Sck153898 } 995789Sahrens *nextp = cookie; 996789Sahrens 997789Sahrens ZFS_EXIT(zfsvfs); 998789Sahrens 999789Sahrens return (0); 1000789Sahrens } 1001789Sahrens 10028845Samw@Sun.COM /* ARGSUSED */ 10038845Samw@Sun.COM static int 10048845Samw@Sun.COM zfsctl_shares_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp, 10058845Samw@Sun.COM caller_context_t *ct, int flags) 10068845Samw@Sun.COM { 10078845Samw@Sun.COM zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 10088845Samw@Sun.COM znode_t *dzp; 10098845Samw@Sun.COM int error; 10108845Samw@Sun.COM 10118845Samw@Sun.COM ZFS_ENTER(zfsvfs); 10128845Samw@Sun.COM 10139030SMark.Shellenbaum@Sun.COM if (zfsvfs->z_shares_dir == 0) { 10149030SMark.Shellenbaum@Sun.COM ZFS_EXIT(zfsvfs); 10159030SMark.Shellenbaum@Sun.COM return (ENOTSUP); 10169030SMark.Shellenbaum@Sun.COM } 10178845Samw@Sun.COM if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) { 10188845Samw@Sun.COM error = VOP_READDIR(ZTOV(dzp), uiop, cr, eofp, ct, flags); 10198845Samw@Sun.COM VN_RELE(ZTOV(dzp)); 10208845Samw@Sun.COM } else { 10218845Samw@Sun.COM *eofp = 1; 10228845Samw@Sun.COM error = ENOENT; 10238845Samw@Sun.COM } 10248845Samw@Sun.COM 10258845Samw@Sun.COM ZFS_EXIT(zfsvfs); 10268845Samw@Sun.COM return (error); 10278845Samw@Sun.COM } 10288845Samw@Sun.COM 10295326Sek110237 /* 10305326Sek110237 * pvp is the '.zfs' directory (zfsctl_node_t). 10315326Sek110237 * Creates vp, which is '.zfs/snapshot' (zfsctl_snapdir_t). 10325326Sek110237 * 10335326Sek110237 * This function is the callback to create a GFS vnode for '.zfs/snapshot' 10345326Sek110237 * when a lookup is performed on .zfs for "snapshot". 10355326Sek110237 */ 1036789Sahrens vnode_t * 1037789Sahrens zfsctl_mknode_snapdir(vnode_t *pvp) 1038789Sahrens { 1039789Sahrens vnode_t *vp; 1040789Sahrens zfsctl_snapdir_t *sdp; 1041789Sahrens 1042789Sahrens vp = gfs_dir_create(sizeof (zfsctl_snapdir_t), pvp, 1043789Sahrens zfsctl_ops_snapdir, NULL, NULL, MAXNAMELEN, 1044789Sahrens zfsctl_snapdir_readdir_cb, NULL); 1045789Sahrens sdp = vp->v_data; 1046789Sahrens sdp->sd_node.zc_id = ZFSCTL_INO_SNAPDIR; 10471571Sek110237 sdp->sd_node.zc_cmtime = ((zfsctl_node_t *)pvp->v_data)->zc_cmtime; 1048789Sahrens mutex_init(&sdp->sd_lock, NULL, MUTEX_DEFAULT, NULL); 1049789Sahrens avl_create(&sdp->sd_snaps, snapentry_compare, 1050789Sahrens sizeof (zfs_snapentry_t), offsetof(zfs_snapentry_t, se_node)); 1051789Sahrens return (vp); 1052789Sahrens } 1053789Sahrens 10548845Samw@Sun.COM vnode_t * 10558845Samw@Sun.COM zfsctl_mknode_shares(vnode_t *pvp) 10568845Samw@Sun.COM { 10578845Samw@Sun.COM vnode_t *vp; 10588845Samw@Sun.COM zfsctl_node_t *sdp; 10598845Samw@Sun.COM 10608845Samw@Sun.COM vp = gfs_dir_create(sizeof (zfsctl_node_t), pvp, 10618845Samw@Sun.COM zfsctl_ops_shares, NULL, NULL, MAXNAMELEN, 10628845Samw@Sun.COM NULL, NULL); 10638845Samw@Sun.COM sdp = vp->v_data; 10648845Samw@Sun.COM sdp->zc_cmtime = ((zfsctl_node_t *)pvp->v_data)->zc_cmtime; 10658845Samw@Sun.COM return (vp); 10668845Samw@Sun.COM 10678845Samw@Sun.COM } 10688845Samw@Sun.COM 10698845Samw@Sun.COM /* ARGSUSED */ 10708845Samw@Sun.COM static int 10718845Samw@Sun.COM zfsctl_shares_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 10728845Samw@Sun.COM caller_context_t *ct) 10738845Samw@Sun.COM { 10748845Samw@Sun.COM zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 10758845Samw@Sun.COM znode_t *dzp; 10768845Samw@Sun.COM int error; 10778845Samw@Sun.COM 10788845Samw@Sun.COM ZFS_ENTER(zfsvfs); 10799030SMark.Shellenbaum@Sun.COM if (zfsvfs->z_shares_dir == 0) { 10809030SMark.Shellenbaum@Sun.COM ZFS_EXIT(zfsvfs); 10819030SMark.Shellenbaum@Sun.COM return (ENOTSUP); 10829030SMark.Shellenbaum@Sun.COM } 10838845Samw@Sun.COM if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) { 10848845Samw@Sun.COM error = VOP_GETATTR(ZTOV(dzp), vap, flags, cr, ct); 10858845Samw@Sun.COM VN_RELE(ZTOV(dzp)); 10868845Samw@Sun.COM } 10878845Samw@Sun.COM ZFS_EXIT(zfsvfs); 10888845Samw@Sun.COM return (error); 10898845Samw@Sun.COM 10908845Samw@Sun.COM 10918845Samw@Sun.COM } 10928845Samw@Sun.COM 1093789Sahrens /* ARGSUSED */ 1094789Sahrens static int 10955331Samw zfsctl_snapdir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 10965331Samw caller_context_t *ct) 1097789Sahrens { 1098789Sahrens zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 1099789Sahrens zfsctl_snapdir_t *sdp = vp->v_data; 1100789Sahrens 1101789Sahrens ZFS_ENTER(zfsvfs); 1102789Sahrens zfsctl_common_getattr(vp, vap); 1103789Sahrens vap->va_nodeid = gfs_file_inode(vp); 1104789Sahrens vap->va_nlink = vap->va_size = avl_numnodes(&sdp->sd_snaps) + 2; 1105789Sahrens ZFS_EXIT(zfsvfs); 1106789Sahrens 1107789Sahrens return (0); 1108789Sahrens } 1109789Sahrens 11101566Smaybee /* ARGSUSED */ 1111789Sahrens static void 11125331Samw zfsctl_snapdir_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) 1113789Sahrens { 1114789Sahrens zfsctl_snapdir_t *sdp = vp->v_data; 11151566Smaybee void *private; 1116789Sahrens 11171566Smaybee private = gfs_dir_inactive(vp); 11181566Smaybee if (private != NULL) { 11191566Smaybee ASSERT(avl_numnodes(&sdp->sd_snaps) == 0); 11201566Smaybee mutex_destroy(&sdp->sd_lock); 11211566Smaybee avl_destroy(&sdp->sd_snaps); 11221566Smaybee kmem_free(private, sizeof (zfsctl_snapdir_t)); 11231566Smaybee } 1124789Sahrens } 1125789Sahrens 1126789Sahrens static const fs_operation_def_t zfsctl_tops_snapdir[] = { 11273898Srsb { VOPNAME_OPEN, { .vop_open = zfsctl_common_open } }, 11283898Srsb { VOPNAME_CLOSE, { .vop_close = zfsctl_common_close } }, 11293898Srsb { VOPNAME_IOCTL, { .error = fs_inval } }, 11303898Srsb { VOPNAME_GETATTR, { .vop_getattr = zfsctl_snapdir_getattr } }, 11313898Srsb { VOPNAME_ACCESS, { .vop_access = zfsctl_common_access } }, 11323898Srsb { VOPNAME_RENAME, { .vop_rename = zfsctl_snapdir_rename } }, 11333898Srsb { VOPNAME_RMDIR, { .vop_rmdir = zfsctl_snapdir_remove } }, 11344543Smarks { VOPNAME_MKDIR, { .vop_mkdir = zfsctl_snapdir_mkdir } }, 11353898Srsb { VOPNAME_READDIR, { .vop_readdir = gfs_vop_readdir } }, 11363898Srsb { VOPNAME_LOOKUP, { .vop_lookup = zfsctl_snapdir_lookup } }, 11373898Srsb { VOPNAME_SEEK, { .vop_seek = fs_seek } }, 11383898Srsb { VOPNAME_INACTIVE, { .vop_inactive = zfsctl_snapdir_inactive } }, 11393898Srsb { VOPNAME_FID, { .vop_fid = zfsctl_common_fid } }, 1140789Sahrens { NULL } 1141789Sahrens }; 1142789Sahrens 11438845Samw@Sun.COM static const fs_operation_def_t zfsctl_tops_shares[] = { 11448845Samw@Sun.COM { VOPNAME_OPEN, { .vop_open = zfsctl_common_open } }, 11458845Samw@Sun.COM { VOPNAME_CLOSE, { .vop_close = zfsctl_common_close } }, 11468845Samw@Sun.COM { VOPNAME_IOCTL, { .error = fs_inval } }, 11478845Samw@Sun.COM { VOPNAME_GETATTR, { .vop_getattr = zfsctl_shares_getattr } }, 11488845Samw@Sun.COM { VOPNAME_ACCESS, { .vop_access = zfsctl_common_access } }, 11498845Samw@Sun.COM { VOPNAME_READDIR, { .vop_readdir = zfsctl_shares_readdir } }, 11508845Samw@Sun.COM { VOPNAME_LOOKUP, { .vop_lookup = zfsctl_shares_lookup } }, 11518845Samw@Sun.COM { VOPNAME_SEEK, { .vop_seek = fs_seek } }, 11528845Samw@Sun.COM { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } }, 11538845Samw@Sun.COM { VOPNAME_FID, { .vop_fid = zfsctl_shares_fid } }, 11548845Samw@Sun.COM { NULL } 11558845Samw@Sun.COM }; 11568845Samw@Sun.COM 11575326Sek110237 /* 11585326Sek110237 * pvp is the GFS vnode '.zfs/snapshot'. 11595326Sek110237 * 11605326Sek110237 * This creates a GFS node under '.zfs/snapshot' representing each 11615326Sek110237 * snapshot. This newly created GFS node is what we mount snapshot 11625326Sek110237 * vfs_t's ontop of. 11635326Sek110237 */ 1164789Sahrens static vnode_t * 1165789Sahrens zfsctl_snapshot_mknode(vnode_t *pvp, uint64_t objset) 1166789Sahrens { 1167789Sahrens vnode_t *vp; 1168789Sahrens zfsctl_node_t *zcp; 1169789Sahrens 1170789Sahrens vp = gfs_dir_create(sizeof (zfsctl_node_t), pvp, 1171789Sahrens zfsctl_ops_snapshot, NULL, NULL, MAXNAMELEN, NULL, NULL); 1172789Sahrens zcp = vp->v_data; 1173789Sahrens zcp->zc_id = objset; 1174789Sahrens 1175789Sahrens return (vp); 1176789Sahrens } 1177789Sahrens 1178789Sahrens static void 11795331Samw zfsctl_snapshot_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) 1180789Sahrens { 1181789Sahrens zfsctl_snapdir_t *sdp; 1182789Sahrens zfs_snapentry_t *sep, *next; 1183789Sahrens vnode_t *dvp; 1184789Sahrens 11856492Stimh VERIFY(gfs_dir_lookup(vp, "..", &dvp, cr, 0, NULL, NULL) == 0); 1186789Sahrens sdp = dvp->v_data; 1187789Sahrens 1188789Sahrens mutex_enter(&sdp->sd_lock); 1189789Sahrens 1190789Sahrens if (vp->v_count > 1) { 1191789Sahrens mutex_exit(&sdp->sd_lock); 1192789Sahrens return; 1193789Sahrens } 1194789Sahrens ASSERT(!vn_ismntpt(vp)); 1195789Sahrens 1196789Sahrens sep = avl_first(&sdp->sd_snaps); 1197789Sahrens while (sep != NULL) { 1198789Sahrens next = AVL_NEXT(&sdp->sd_snaps, sep); 1199789Sahrens 1200789Sahrens if (sep->se_root == vp) { 1201789Sahrens avl_remove(&sdp->sd_snaps, sep); 1202789Sahrens kmem_free(sep->se_name, strlen(sep->se_name) + 1); 1203789Sahrens kmem_free(sep, sizeof (zfs_snapentry_t)); 1204789Sahrens break; 1205789Sahrens } 1206789Sahrens sep = next; 1207789Sahrens } 1208789Sahrens ASSERT(sep != NULL); 1209789Sahrens 1210789Sahrens mutex_exit(&sdp->sd_lock); 1211789Sahrens VN_RELE(dvp); 1212789Sahrens 12131566Smaybee /* 12141566Smaybee * Dispose of the vnode for the snapshot mount point. 12151566Smaybee * This is safe to do because once this entry has been removed 12161566Smaybee * from the AVL tree, it can't be found again, so cannot become 12171566Smaybee * "active". If we lookup the same name again we will end up 12181566Smaybee * creating a new vnode. 12191566Smaybee */ 12205331Samw gfs_vop_inactive(vp, cr, ct); 1221789Sahrens } 1222789Sahrens 1223789Sahrens 1224789Sahrens /* 1225789Sahrens * These VP's should never see the light of day. They should always 1226789Sahrens * be covered. 1227789Sahrens */ 1228789Sahrens static const fs_operation_def_t zfsctl_tops_snapshot[] = { 12293898Srsb VOPNAME_INACTIVE, { .vop_inactive = zfsctl_snapshot_inactive }, 1230789Sahrens NULL, NULL 1231789Sahrens }; 1232789Sahrens 1233789Sahrens int 1234789Sahrens zfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t **zfsvfsp) 1235789Sahrens { 1236789Sahrens zfsvfs_t *zfsvfs = vfsp->vfs_data; 1237789Sahrens vnode_t *dvp, *vp; 1238789Sahrens zfsctl_snapdir_t *sdp; 1239789Sahrens zfsctl_node_t *zcp; 1240789Sahrens zfs_snapentry_t *sep; 1241789Sahrens int error; 1242789Sahrens 1243789Sahrens ASSERT(zfsvfs->z_ctldir != NULL); 1244789Sahrens error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp, 12455331Samw NULL, 0, NULL, kcred, NULL, NULL, NULL); 1246789Sahrens if (error != 0) 1247789Sahrens return (error); 1248789Sahrens sdp = dvp->v_data; 1249789Sahrens 1250789Sahrens mutex_enter(&sdp->sd_lock); 1251789Sahrens sep = avl_first(&sdp->sd_snaps); 1252789Sahrens while (sep != NULL) { 1253789Sahrens vp = sep->se_root; 1254789Sahrens zcp = vp->v_data; 1255789Sahrens if (zcp->zc_id == objsetid) 1256789Sahrens break; 1257789Sahrens 1258789Sahrens sep = AVL_NEXT(&sdp->sd_snaps, sep); 1259789Sahrens } 1260789Sahrens 1261789Sahrens if (sep != NULL) { 1262789Sahrens VN_HOLD(vp); 12635326Sek110237 /* 12645326Sek110237 * Return the mounted root rather than the covered mount point. 12655326Sek110237 * Takes the GFS vnode at .zfs/snapshot/<snapshot objsetid> 12665326Sek110237 * and returns the ZFS vnode mounted on top of the GFS node. 12675326Sek110237 * This ZFS vnode is the root of the vfs for objset 'objsetid'. 12685326Sek110237 */ 1269789Sahrens error = traverse(&vp); 12701589Smaybee if (error == 0) { 12711589Smaybee if (vp == sep->se_root) 12721589Smaybee error = EINVAL; 12731589Smaybee else 12741589Smaybee *zfsvfsp = VTOZ(vp)->z_zfsvfs; 12751589Smaybee } 12761572Snd150628 mutex_exit(&sdp->sd_lock); 1277789Sahrens VN_RELE(vp); 1278789Sahrens } else { 1279789Sahrens error = EINVAL; 12801572Snd150628 mutex_exit(&sdp->sd_lock); 1281789Sahrens } 1282789Sahrens 1283789Sahrens VN_RELE(dvp); 1284789Sahrens 1285789Sahrens return (error); 1286789Sahrens } 1287789Sahrens 1288789Sahrens /* 1289789Sahrens * Unmount any snapshots for the given filesystem. This is called from 1290789Sahrens * zfs_umount() - if we have a ctldir, then go through and unmount all the 1291789Sahrens * snapshots. 1292789Sahrens */ 1293789Sahrens int 1294789Sahrens zfsctl_umount_snapshots(vfs_t *vfsp, int fflags, cred_t *cr) 1295789Sahrens { 1296789Sahrens zfsvfs_t *zfsvfs = vfsp->vfs_data; 12976068Sck153898 vnode_t *dvp; 1298789Sahrens zfsctl_snapdir_t *sdp; 1299789Sahrens zfs_snapentry_t *sep, *next; 1300789Sahrens int error; 1301789Sahrens 1302789Sahrens ASSERT(zfsvfs->z_ctldir != NULL); 1303789Sahrens error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp, 13045331Samw NULL, 0, NULL, cr, NULL, NULL, NULL); 1305789Sahrens if (error != 0) 1306789Sahrens return (error); 1307789Sahrens sdp = dvp->v_data; 1308789Sahrens 1309789Sahrens mutex_enter(&sdp->sd_lock); 1310789Sahrens 1311789Sahrens sep = avl_first(&sdp->sd_snaps); 1312789Sahrens while (sep != NULL) { 1313789Sahrens next = AVL_NEXT(&sdp->sd_snaps, sep); 1314789Sahrens 1315789Sahrens /* 1316789Sahrens * If this snapshot is not mounted, then it must 1317789Sahrens * have just been unmounted by somebody else, and 1318789Sahrens * will be cleaned up by zfsctl_snapdir_inactive(). 1319789Sahrens */ 13206068Sck153898 if (vn_ismntpt(sep->se_root)) { 13216068Sck153898 avl_remove(&sdp->sd_snaps, sep); 13226068Sck153898 error = zfsctl_unmount_snap(sep, fflags, cr); 1323789Sahrens if (error) { 13246068Sck153898 avl_add(&sdp->sd_snaps, sep); 13256068Sck153898 break; 1326789Sahrens } 1327789Sahrens } 1328789Sahrens sep = next; 1329789Sahrens } 13306068Sck153898 1331789Sahrens mutex_exit(&sdp->sd_lock); 1332789Sahrens VN_RELE(dvp); 1333789Sahrens 1334789Sahrens return (error); 1335789Sahrens } 1336