zfs_ctldir.c revision 211900
1168404Spjd/* 2168404Spjd * CDDL HEADER START 3168404Spjd * 4168404Spjd * The contents of this file are subject to the terms of the 5168404Spjd * Common Development and Distribution License (the "License"). 6168404Spjd * You may not use this file except in compliance with the License. 7168404Spjd * 8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9168404Spjd * or http://www.opensolaris.org/os/licensing. 10168404Spjd * See the License for the specific language governing permissions 11168404Spjd * and limitations under the License. 12168404Spjd * 13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each 14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15168404Spjd * If applicable, add the following below this CDDL HEADER, with the 16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18168404Spjd * 19168404Spjd * CDDL HEADER END 20168404Spjd */ 21168404Spjd/* 22209962Smm * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23168404Spjd * Use is subject to license terms. 24168404Spjd */ 25168404Spjd 26168404Spjd/* 27168404Spjd * ZFS control directory (a.k.a. ".zfs") 28168404Spjd * 29168404Spjd * This directory provides a common location for all ZFS meta-objects. 30168404Spjd * Currently, this is only the 'snapshot' directory, but this may expand in the 31168404Spjd * future. The elements are built using the GFS primitives, as the hierarchy 32168404Spjd * does not actually exist on disk. 33168404Spjd * 34168404Spjd * For 'snapshot', we don't want to have all snapshots always mounted, because 35168404Spjd * this would take up a huge amount of space in /etc/mnttab. We have three 36168404Spjd * types of objects: 37168404Spjd * 38168404Spjd * ctldir ------> snapshotdir -------> snapshot 39168404Spjd * | 40168404Spjd * | 41168404Spjd * V 42168404Spjd * mounted fs 43168404Spjd * 44168404Spjd * The 'snapshot' node contains just enough information to lookup '..' and act 45168404Spjd * as a mountpoint for the snapshot. Whenever we lookup a specific snapshot, we 46168404Spjd * perform an automount of the underlying filesystem and return the 47168404Spjd * corresponding vnode. 48168404Spjd * 49168404Spjd * All mounts are handled automatically by the kernel, but unmounts are 50168404Spjd * (currently) handled from user land. The main reason is that there is no 51168404Spjd * reliable way to auto-unmount the filesystem when it's "no longer in use". 52168404Spjd * When the user unmounts a filesystem, we call zfsctl_unmount(), which 53168404Spjd * unmounts any snapshots within the snapshot directory. 54185029Spjd * 55185029Spjd * The '.zfs', '.zfs/snapshot', and all directories created under 56185029Spjd * '.zfs/snapshot' (ie: '.zfs/snapshot/<snapname>') are all GFS nodes and 57185029Spjd * share the same vfs_t as the head filesystem (what '.zfs' lives under). 58185029Spjd * 59185029Spjd * File systems mounted ontop of the GFS nodes '.zfs/snapshot/<snapname>' 60185029Spjd * (ie: snapshots) are ZFS nodes and have their own unique vfs_t. 61185029Spjd * However, vnodes within these mounted on file systems have their v_vfsp 62185029Spjd * fields set to the head filesystem to make NFS happy (see 63185029Spjd * zfsctl_snapdir_lookup()). We VFS_HOLD the head filesystem's vfs_t 64185029Spjd * so that it cannot be freed until all snapshots have been unmounted. 65168404Spjd */ 66168404Spjd 67168404Spjd#include <sys/zfs_context.h> 68168404Spjd#include <sys/zfs_ctldir.h> 69168404Spjd#include <sys/zfs_ioctl.h> 70168404Spjd#include <sys/zfs_vfsops.h> 71168404Spjd#include <sys/namei.h> 72168404Spjd#include <sys/gfs.h> 73168404Spjd#include <sys/stat.h> 74168404Spjd#include <sys/dmu.h> 75185029Spjd#include <sys/dsl_deleg.h> 76168404Spjd#include <sys/mount.h> 77185029Spjd#include <sys/sunddi.h> 78168404Spjd 79185029Spjd#include "zfs_namecheck.h" 80185029Spjd 81185029Spjdtypedef struct zfsctl_node { 82185029Spjd gfs_dir_t zc_gfs_private; 83185029Spjd uint64_t zc_id; 84185029Spjd timestruc_t zc_cmtime; /* ctime and mtime, always the same */ 85185029Spjd} zfsctl_node_t; 86185029Spjd 87185029Spjdtypedef struct zfsctl_snapdir { 88185029Spjd zfsctl_node_t sd_node; 89185029Spjd kmutex_t sd_lock; 90185029Spjd avl_tree_t sd_snaps; 91185029Spjd} zfsctl_snapdir_t; 92185029Spjd 93168404Spjdtypedef struct { 94168404Spjd char *se_name; 95168404Spjd vnode_t *se_root; 96168404Spjd avl_node_t se_node; 97168404Spjd} zfs_snapentry_t; 98168404Spjd 99168404Spjdstatic int 100168404Spjdsnapentry_compare(const void *a, const void *b) 101168404Spjd{ 102168404Spjd const zfs_snapentry_t *sa = a; 103168404Spjd const zfs_snapentry_t *sb = b; 104168404Spjd int ret = strcmp(sa->se_name, sb->se_name); 105168404Spjd 106168404Spjd if (ret < 0) 107168404Spjd return (-1); 108168404Spjd else if (ret > 0) 109168404Spjd return (1); 110168404Spjd else 111168404Spjd return (0); 112168404Spjd} 113168404Spjd 114168404Spjdstatic struct vop_vector zfsctl_ops_root; 115168404Spjdstatic struct vop_vector zfsctl_ops_snapdir; 116168404Spjdstatic struct vop_vector zfsctl_ops_snapshot; 117209962Smmstatic struct vop_vector zfsctl_ops_shares; 118209962Smmstatic struct vop_vector zfsctl_ops_shares_dir; 119168404Spjd 120168404Spjdstatic vnode_t *zfsctl_mknode_snapdir(vnode_t *); 121209962Smmstatic vnode_t *zfsctl_mknode_shares(vnode_t *); 122168404Spjdstatic vnode_t *zfsctl_snapshot_mknode(vnode_t *, uint64_t objset); 123185029Spjdstatic int zfsctl_unmount_snap(zfs_snapentry_t *, int, cred_t *); 124168404Spjd 125168404Spjd/* 126209962Smm * Root directory elements. We only have two entries 127209962Smm * snapshot and shares. 128168404Spjd */ 129168404Spjdstatic gfs_dirent_t zfsctl_root_entries[] = { 130168404Spjd { "snapshot", zfsctl_mknode_snapdir, GFS_CACHE_VNODE }, 131209962Smm { "shares", zfsctl_mknode_shares, GFS_CACHE_VNODE }, 132168404Spjd { NULL } 133168404Spjd}; 134168404Spjd 135168404Spjd/* include . and .. in the calculation */ 136168404Spjd#define NROOT_ENTRIES ((sizeof (zfsctl_root_entries) / \ 137168404Spjd sizeof (gfs_dirent_t)) + 1) 138168404Spjd 139168404Spjd 140168404Spjd/* 141168404Spjd * Initialize the various GFS pieces we'll need to create and manipulate .zfs 142168404Spjd * directories. This is called from the ZFS init routine, and initializes the 143168404Spjd * vnode ops vectors that we'll be using. 144168404Spjd */ 145168404Spjdvoid 146168404Spjdzfsctl_init(void) 147168404Spjd{ 148168404Spjd} 149168404Spjd 150168404Spjdvoid 151168404Spjdzfsctl_fini(void) 152168404Spjd{ 153168404Spjd} 154168404Spjd 155168404Spjd/* 156209962Smm * Return the inode number associated with the 'snapshot' or 157209962Smm * 'shares' directory. 158168404Spjd */ 159168404Spjd/* ARGSUSED */ 160168404Spjdstatic ino64_t 161168404Spjdzfsctl_root_inode_cb(vnode_t *vp, int index) 162168404Spjd{ 163209962Smm zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 164209962Smm 165209962Smm ASSERT(index <= 2); 166209962Smm 167209962Smm if (index == 0) 168209962Smm return (ZFSCTL_INO_SNAPDIR); 169209962Smm 170209962Smm return (zfsvfs->z_shares_dir); 171168404Spjd} 172168404Spjd 173168404Spjd/* 174168404Spjd * Create the '.zfs' directory. This directory is cached as part of the VFS 175168404Spjd * structure. This results in a hold on the vfs_t. The code in zfs_umount() 176168404Spjd * therefore checks against a vfs_count of 2 instead of 1. This reference 177168404Spjd * is removed when the ctldir is destroyed in the unmount. 178168404Spjd */ 179168404Spjdvoid 180168404Spjdzfsctl_create(zfsvfs_t *zfsvfs) 181168404Spjd{ 182168404Spjd vnode_t *vp, *rvp; 183168404Spjd zfsctl_node_t *zcp; 184168404Spjd 185168404Spjd ASSERT(zfsvfs->z_ctldir == NULL); 186168404Spjd 187168404Spjd vp = gfs_root_create(sizeof (zfsctl_node_t), zfsvfs->z_vfs, 188168404Spjd &zfsctl_ops_root, ZFSCTL_INO_ROOT, zfsctl_root_entries, 189168404Spjd zfsctl_root_inode_cb, MAXNAMELEN, NULL, NULL); 190168404Spjd zcp = vp->v_data; 191168404Spjd zcp->zc_id = ZFSCTL_INO_ROOT; 192168404Spjd 193191990Sattilio VERIFY(VFS_ROOT(zfsvfs->z_vfs, LK_EXCLUSIVE, &rvp) == 0); 194168404Spjd ZFS_TIME_DECODE(&zcp->zc_cmtime, VTOZ(rvp)->z_phys->zp_crtime); 195168404Spjd VN_URELE(rvp); 196168404Spjd 197168404Spjd /* 198168404Spjd * We're only faking the fact that we have a root of a filesystem for 199168404Spjd * the sake of the GFS interfaces. Undo the flag manipulation it did 200168404Spjd * for us. 201168404Spjd */ 202168404Spjd vp->v_vflag &= ~VV_ROOT; 203168404Spjd 204168404Spjd zfsvfs->z_ctldir = vp; 205182781Spjd 206182781Spjd VOP_UNLOCK(vp, 0); 207168404Spjd} 208168404Spjd 209168404Spjd/* 210168404Spjd * Destroy the '.zfs' directory. Only called when the filesystem is unmounted. 211168404Spjd * There might still be more references if we were force unmounted, but only 212168404Spjd * new zfs_inactive() calls can occur and they don't reference .zfs 213168404Spjd */ 214168404Spjdvoid 215168404Spjdzfsctl_destroy(zfsvfs_t *zfsvfs) 216168404Spjd{ 217168404Spjd VN_RELE(zfsvfs->z_ctldir); 218168404Spjd zfsvfs->z_ctldir = NULL; 219168404Spjd} 220168404Spjd 221168404Spjd/* 222168404Spjd * Given a root znode, retrieve the associated .zfs directory. 223168404Spjd * Add a hold to the vnode and return it. 224168404Spjd */ 225168404Spjdvnode_t * 226168404Spjdzfsctl_root(znode_t *zp) 227168404Spjd{ 228168404Spjd ASSERT(zfs_has_ctldir(zp)); 229168404Spjd VN_HOLD(zp->z_zfsvfs->z_ctldir); 230168404Spjd return (zp->z_zfsvfs->z_ctldir); 231168404Spjd} 232168404Spjd 233168404Spjd/* 234168404Spjd * Common open routine. Disallow any write access. 235168404Spjd */ 236168404Spjd/* ARGSUSED */ 237168404Spjdstatic int 238168404Spjdzfsctl_common_open(struct vop_open_args *ap) 239168404Spjd{ 240168404Spjd int flags = ap->a_mode; 241168404Spjd 242168404Spjd if (flags & FWRITE) 243168404Spjd return (EACCES); 244168404Spjd 245168404Spjd return (0); 246168404Spjd} 247168404Spjd 248168404Spjd/* 249168404Spjd * Common close routine. Nothing to do here. 250168404Spjd */ 251168404Spjd/* ARGSUSED */ 252168404Spjdstatic int 253168404Spjdzfsctl_common_close(struct vop_close_args *ap) 254168404Spjd{ 255168404Spjd return (0); 256168404Spjd} 257168404Spjd 258168404Spjd/* 259168404Spjd * Common access routine. Disallow writes. 260168404Spjd */ 261168404Spjd/* ARGSUSED */ 262168404Spjdstatic int 263168404Spjdzfsctl_common_access(ap) 264168404Spjd struct vop_access_args /* { 265168404Spjd struct vnode *a_vp; 266185029Spjd int a_accmode; 267168404Spjd struct ucred *a_cred; 268168404Spjd struct thread *a_td; 269168404Spjd } */ *ap; 270168404Spjd{ 271185029Spjd int mode = ap->a_accmode; 272168404Spjd 273209962Smm#ifdef TODO 274209962Smm if (flags & V_ACE_MASK) { 275209962Smm if (accmode & ACE_ALL_WRITE_PERMS) 276209962Smm return (EACCES); 277209962Smm } else { 278209962Smm#endif 279185029Spjd if (mode & VWRITE) 280168404Spjd return (EACCES); 281209962Smm#ifdef TODO 282209962Smm } 283209962Smm#endif 284168404Spjd 285168404Spjd return (0); 286168404Spjd} 287168404Spjd 288168404Spjd/* 289168404Spjd * Common getattr function. Fill in basic information. 290168404Spjd */ 291168404Spjdstatic void 292168404Spjdzfsctl_common_getattr(vnode_t *vp, vattr_t *vap) 293168404Spjd{ 294168404Spjd zfsctl_node_t *zcp = vp->v_data; 295168404Spjd timestruc_t now; 296168404Spjd 297168404Spjd vap->va_uid = 0; 298168404Spjd vap->va_gid = 0; 299168404Spjd vap->va_rdev = 0; 300168404Spjd /* 301168404Spjd * We are a purly virtual object, so we have no 302168404Spjd * blocksize or allocated blocks. 303168404Spjd */ 304168404Spjd vap->va_blksize = 0; 305168404Spjd vap->va_nblocks = 0; 306168404Spjd vap->va_seq = 0; 307168404Spjd vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 308168404Spjd vap->va_mode = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | 309168404Spjd S_IROTH | S_IXOTH; 310168404Spjd vap->va_type = VDIR; 311168404Spjd /* 312168404Spjd * We live in the now (for atime). 313168404Spjd */ 314168404Spjd gethrestime(&now); 315168404Spjd vap->va_atime = now; 316168404Spjd vap->va_mtime = vap->va_ctime = vap->va_birthtime = zcp->zc_cmtime; 317168404Spjd /* FreeBSD: Reset chflags(2) flags. */ 318168404Spjd vap->va_flags = 0; 319168404Spjd} 320168404Spjd 321185029Spjd/*ARGSUSED*/ 322168404Spjdstatic int 323168404Spjdzfsctl_common_fid(ap) 324168404Spjd struct vop_fid_args /* { 325168404Spjd struct vnode *a_vp; 326168404Spjd struct fid *a_fid; 327168404Spjd } */ *ap; 328168404Spjd{ 329168404Spjd vnode_t *vp = ap->a_vp; 330168404Spjd fid_t *fidp = (void *)ap->a_fid; 331168404Spjd zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 332168404Spjd zfsctl_node_t *zcp = vp->v_data; 333168404Spjd uint64_t object = zcp->zc_id; 334168404Spjd zfid_short_t *zfid; 335168404Spjd int i; 336168404Spjd 337168404Spjd ZFS_ENTER(zfsvfs); 338168404Spjd 339168404Spjd fidp->fid_len = SHORT_FID_LEN; 340168404Spjd 341168404Spjd zfid = (zfid_short_t *)fidp; 342168404Spjd 343168404Spjd zfid->zf_len = SHORT_FID_LEN; 344168404Spjd 345168404Spjd for (i = 0; i < sizeof (zfid->zf_object); i++) 346168404Spjd zfid->zf_object[i] = (uint8_t)(object >> (8 * i)); 347168404Spjd 348168404Spjd /* .zfs znodes always have a generation number of 0 */ 349168404Spjd for (i = 0; i < sizeof (zfid->zf_gen); i++) 350168404Spjd zfid->zf_gen[i] = 0; 351168404Spjd 352168404Spjd ZFS_EXIT(zfsvfs); 353168404Spjd return (0); 354168404Spjd} 355168404Spjd 356209962Smm/*ARGSUSED*/ 357168404Spjdstatic int 358209962Smmzfsctl_shares_fid(ap) 359209962Smm struct vop_fid_args /* { 360209962Smm struct vnode *a_vp; 361209962Smm struct fid *a_fid; 362209962Smm } */ *ap; 363209962Smm{ 364209962Smm vnode_t *vp = ap->a_vp; 365209962Smm fid_t *fidp = (void *)ap->a_fid; 366209962Smm zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 367209962Smm znode_t *dzp; 368209962Smm int error; 369209962Smm 370209962Smm ZFS_ENTER(zfsvfs); 371209962Smm 372209962Smm if (zfsvfs->z_shares_dir == 0) { 373209962Smm ZFS_EXIT(zfsvfs); 374209962Smm return (ENOTSUP); 375209962Smm } 376209962Smm 377209962Smm if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) { 378209962Smm error = VOP_FID(ZTOV(dzp), fidp); 379209962Smm VN_RELE(ZTOV(dzp)); 380209962Smm } 381209962Smm 382209962Smm ZFS_EXIT(zfsvfs); 383209962Smm return (error); 384209962Smm} 385209962Smm 386209962Smmstatic int 387168404Spjdzfsctl_common_reclaim(ap) 388168404Spjd struct vop_reclaim_args /* { 389168404Spjd struct vnode *a_vp; 390168404Spjd struct thread *a_td; 391168404Spjd } */ *ap; 392168404Spjd{ 393168404Spjd vnode_t *vp = ap->a_vp; 394168404Spjd 395168404Spjd /* 396168404Spjd * Destroy the vm object and flush associated pages. 397168404Spjd */ 398168404Spjd vnode_destroy_vobject(vp); 399168404Spjd VI_LOCK(vp); 400168404Spjd vp->v_data = NULL; 401168404Spjd VI_UNLOCK(vp); 402168404Spjd return (0); 403168404Spjd} 404168404Spjd 405168404Spjd/* 406168404Spjd * .zfs inode namespace 407168404Spjd * 408168404Spjd * We need to generate unique inode numbers for all files and directories 409168404Spjd * within the .zfs pseudo-filesystem. We use the following scheme: 410168404Spjd * 411168404Spjd * ENTRY ZFSCTL_INODE 412168404Spjd * .zfs 1 413168404Spjd * .zfs/snapshot 2 414168404Spjd * .zfs/snapshot/<snap> objectid(snap) 415168404Spjd */ 416168404Spjd 417168404Spjd#define ZFSCTL_INO_SNAP(id) (id) 418168404Spjd 419168404Spjd/* 420168404Spjd * Get root directory attributes. 421168404Spjd */ 422168404Spjd/* ARGSUSED */ 423168404Spjdstatic int 424168404Spjdzfsctl_root_getattr(ap) 425168404Spjd struct vop_getattr_args /* { 426168404Spjd struct vnode *a_vp; 427168404Spjd struct vattr *a_vap; 428168404Spjd struct ucred *a_cred; 429185029Spjd struct thread *a_td; 430168404Spjd } */ *ap; 431168404Spjd{ 432168404Spjd struct vnode *vp = ap->a_vp; 433168404Spjd struct vattr *vap = ap->a_vap; 434168404Spjd zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 435168404Spjd 436168404Spjd ZFS_ENTER(zfsvfs); 437168404Spjd vap->va_nodeid = ZFSCTL_INO_ROOT; 438168404Spjd vap->va_nlink = vap->va_size = NROOT_ENTRIES; 439168404Spjd 440168404Spjd zfsctl_common_getattr(vp, vap); 441168404Spjd ZFS_EXIT(zfsvfs); 442168404Spjd 443168404Spjd return (0); 444168404Spjd} 445168404Spjd 446209962Smm#ifdef sun 447209962Smmstatic int 448209962Smmzfsctl_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, 449209962Smm caller_context_t *ct) 450209962Smm{ 451209962Smm /* 452209962Smm * We only care about ACL_ENABLED so that libsec can 453209962Smm * display ACL correctly and not default to POSIX draft. 454209962Smm */ 455209962Smm if (cmd == _PC_ACL_ENABLED) { 456209962Smm *valp = _ACL_ACE_ENABLED; 457209962Smm return (0); 458209962Smm } 459209962Smm 460209962Smm return (fs_pathconf(vp, cmd, valp, cr, ct)); 461209962Smm} 462209962Smm#endif /* sun */ 463209962Smm 464209962Smm#ifdef sun 465209962Smmstatic const fs_operation_def_t zfsctl_tops_root[] = { 466209962Smm { VOPNAME_OPEN, { .vop_open = zfsctl_common_open } }, 467209962Smm { VOPNAME_CLOSE, { .vop_close = zfsctl_common_close } }, 468209962Smm { VOPNAME_IOCTL, { .error = fs_inval } }, 469209962Smm { VOPNAME_GETATTR, { .vop_getattr = zfsctl_root_getattr } }, 470209962Smm { VOPNAME_ACCESS, { .vop_access = zfsctl_common_access } }, 471209962Smm { VOPNAME_READDIR, { .vop_readdir = gfs_vop_readdir } }, 472209962Smm { VOPNAME_LOOKUP, { .vop_lookup = zfsctl_root_lookup } }, 473209962Smm { VOPNAME_SEEK, { .vop_seek = fs_seek } }, 474209962Smm { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } }, 475209962Smm { VOPNAME_PATHCONF, { .vop_pathconf = zfsctl_pathconf } }, 476209962Smm { VOPNAME_FID, { .vop_fid = zfsctl_common_fid } }, 477209962Smm { NULL } 478209962Smm}; 479209962Smm#endif /* sun */ 480209962Smm 481168404Spjd/* 482168404Spjd * Special case the handling of "..". 483168404Spjd */ 484168404Spjd/* ARGSUSED */ 485168404Spjdint 486168404Spjdzfsctl_root_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp, 487185029Spjd int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct, 488185029Spjd int *direntflags, pathname_t *realpnp) 489168404Spjd{ 490168404Spjd zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 491168404Spjd int err; 492168404Spjd 493185029Spjd /* 494185029Spjd * No extended attributes allowed under .zfs 495185029Spjd */ 496185029Spjd if (flags & LOOKUP_XATTR) 497185029Spjd return (EINVAL); 498185029Spjd 499168404Spjd ZFS_ENTER(zfsvfs); 500168404Spjd 501168404Spjd if (strcmp(nm, "..") == 0) { 502191990Sattilio err = VFS_ROOT(dvp->v_vfsp, LK_EXCLUSIVE, vpp); 503168404Spjd if (err == 0) 504175294Sattilio VOP_UNLOCK(*vpp, 0); 505168404Spjd } else { 506185029Spjd err = gfs_vop_lookup(dvp, nm, vpp, pnp, flags, rdir, 507185029Spjd cr, ct, direntflags, realpnp); 508168404Spjd } 509168404Spjd 510168404Spjd ZFS_EXIT(zfsvfs); 511168404Spjd 512168404Spjd return (err); 513168404Spjd} 514168404Spjd 515168404Spjd/* 516168404Spjd * Special case the handling of "..". 517168404Spjd */ 518168404Spjd/* ARGSUSED */ 519168404Spjdint 520185029Spjdzfsctl_freebsd_root_lookup(ap) 521168404Spjd struct vop_lookup_args /* { 522168404Spjd struct vnode *a_dvp; 523168404Spjd struct vnode **a_vpp; 524168404Spjd struct componentname *a_cnp; 525168404Spjd } */ *ap; 526168404Spjd{ 527168404Spjd vnode_t *dvp = ap->a_dvp; 528168404Spjd vnode_t **vpp = ap->a_vpp; 529168404Spjd cred_t *cr = ap->a_cnp->cn_cred; 530168404Spjd int flags = ap->a_cnp->cn_flags; 531168404Spjd int nameiop = ap->a_cnp->cn_nameiop; 532168404Spjd char nm[NAME_MAX + 1]; 533168404Spjd int err; 534168404Spjd 535168404Spjd if ((flags & ISLASTCN) && (nameiop == RENAME || nameiop == CREATE)) 536168404Spjd return (EOPNOTSUPP); 537168404Spjd 538168404Spjd ASSERT(ap->a_cnp->cn_namelen < sizeof(nm)); 539168404Spjd strlcpy(nm, ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen + 1); 540168404Spjd 541185029Spjd err = zfsctl_root_lookup(dvp, nm, vpp, NULL, 0, NULL, cr, NULL, NULL, NULL); 542168404Spjd if (err == 0 && (nm[0] != '.' || nm[1] != '\0')) 543175202Sattilio vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); 544168404Spjd 545168404Spjd return (err); 546168404Spjd} 547168404Spjd 548168404Spjdstatic struct vop_vector zfsctl_ops_root = { 549168404Spjd .vop_default = &default_vnodeops, 550168404Spjd .vop_open = zfsctl_common_open, 551168404Spjd .vop_close = zfsctl_common_close, 552168404Spjd .vop_ioctl = VOP_EINVAL, 553168404Spjd .vop_getattr = zfsctl_root_getattr, 554168404Spjd .vop_access = zfsctl_common_access, 555168404Spjd .vop_readdir = gfs_vop_readdir, 556185029Spjd .vop_lookup = zfsctl_freebsd_root_lookup, 557168404Spjd .vop_inactive = gfs_vop_inactive, 558168404Spjd .vop_reclaim = zfsctl_common_reclaim, 559168404Spjd .vop_fid = zfsctl_common_fid, 560168404Spjd}; 561168404Spjd 562168404Spjdstatic int 563168404Spjdzfsctl_snapshot_zname(vnode_t *vp, const char *name, int len, char *zname) 564168404Spjd{ 565168404Spjd objset_t *os = ((zfsvfs_t *)((vp)->v_vfsp->vfs_data))->z_os; 566168404Spjd 567185029Spjd if (snapshot_namecheck(name, NULL, NULL) != 0) 568185029Spjd return (EILSEQ); 569168404Spjd dmu_objset_name(os, zname); 570168404Spjd if (strlen(zname) + 1 + strlen(name) >= len) 571168404Spjd return (ENAMETOOLONG); 572168404Spjd (void) strcat(zname, "@"); 573168404Spjd (void) strcat(zname, name); 574168404Spjd return (0); 575168404Spjd} 576168404Spjd 577168404Spjdstatic int 578185029Spjdzfsctl_unmount_snap(zfs_snapentry_t *sep, int fflags, cred_t *cr) 579168404Spjd{ 580185029Spjd vnode_t *svp = sep->se_root; 581185029Spjd int error; 582168404Spjd 583185029Spjd ASSERT(vn_ismntpt(svp)); 584168404Spjd 585168404Spjd /* this will be dropped by dounmount() */ 586185029Spjd if ((error = vn_vfswlock(svp)) != 0) 587185029Spjd return (error); 588168404Spjd 589185029Spjd return (dounmount(vn_mountedvfs(svp), fflags, curthread)); 590168404Spjd} 591168404Spjd 592168404Spjd#if 0 593168404Spjdstatic void 594168404Spjdzfsctl_rename_snap(zfsctl_snapdir_t *sdp, zfs_snapentry_t *sep, const char *nm) 595168404Spjd{ 596168404Spjd avl_index_t where; 597168404Spjd vfs_t *vfsp; 598168404Spjd refstr_t *pathref; 599168404Spjd char newpath[MAXNAMELEN]; 600168404Spjd char *tail; 601168404Spjd 602168404Spjd ASSERT(MUTEX_HELD(&sdp->sd_lock)); 603168404Spjd ASSERT(sep != NULL); 604168404Spjd 605168404Spjd vfsp = vn_mountedvfs(sep->se_root); 606168404Spjd ASSERT(vfsp != NULL); 607168404Spjd 608168404Spjd vfs_lock_wait(vfsp); 609168404Spjd 610168404Spjd /* 611168404Spjd * Change the name in the AVL tree. 612168404Spjd */ 613168404Spjd avl_remove(&sdp->sd_snaps, sep); 614168404Spjd kmem_free(sep->se_name, strlen(sep->se_name) + 1); 615168404Spjd sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP); 616168404Spjd (void) strcpy(sep->se_name, nm); 617168404Spjd VERIFY(avl_find(&sdp->sd_snaps, sep, &where) == NULL); 618168404Spjd avl_insert(&sdp->sd_snaps, sep, where); 619168404Spjd 620168404Spjd /* 621168404Spjd * Change the current mountpoint info: 622168404Spjd * - update the tail of the mntpoint path 623168404Spjd * - update the tail of the resource path 624168404Spjd */ 625168404Spjd pathref = vfs_getmntpoint(vfsp); 626168404Spjd (void) strncpy(newpath, refstr_value(pathref), sizeof (newpath)); 627168404Spjd VERIFY((tail = strrchr(newpath, '/')) != NULL); 628168404Spjd *(tail+1) = '\0'; 629168404Spjd ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath)); 630168404Spjd (void) strcat(newpath, nm); 631168404Spjd refstr_rele(pathref); 632168404Spjd vfs_setmntpoint(vfsp, newpath); 633168404Spjd 634168404Spjd pathref = vfs_getresource(vfsp); 635168404Spjd (void) strncpy(newpath, refstr_value(pathref), sizeof (newpath)); 636168404Spjd VERIFY((tail = strrchr(newpath, '@')) != NULL); 637168404Spjd *(tail+1) = '\0'; 638168404Spjd ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath)); 639168404Spjd (void) strcat(newpath, nm); 640168404Spjd refstr_rele(pathref); 641168404Spjd vfs_setresource(vfsp, newpath); 642168404Spjd 643168404Spjd vfs_unlock(vfsp); 644168404Spjd} 645168404Spjd#endif 646168404Spjd 647168404Spjd#if 0 648185029Spjd/*ARGSUSED*/ 649168404Spjdstatic int 650168404Spjdzfsctl_snapdir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, 651185029Spjd cred_t *cr, caller_context_t *ct, int flags) 652168404Spjd{ 653168404Spjd zfsctl_snapdir_t *sdp = sdvp->v_data; 654168404Spjd zfs_snapentry_t search, *sep; 655185029Spjd zfsvfs_t *zfsvfs; 656168404Spjd avl_index_t where; 657168404Spjd char from[MAXNAMELEN], to[MAXNAMELEN]; 658185029Spjd char real[MAXNAMELEN]; 659168404Spjd int err; 660168404Spjd 661185029Spjd zfsvfs = sdvp->v_vfsp->vfs_data; 662185029Spjd ZFS_ENTER(zfsvfs); 663185029Spjd 664185029Spjd if ((flags & FIGNORECASE) || zfsvfs->z_case == ZFS_CASE_INSENSITIVE) { 665185029Spjd err = dmu_snapshot_realname(zfsvfs->z_os, snm, real, 666185029Spjd MAXNAMELEN, NULL); 667185029Spjd if (err == 0) { 668185029Spjd snm = real; 669185029Spjd } else if (err != ENOTSUP) { 670185029Spjd ZFS_EXIT(zfsvfs); 671185029Spjd return (err); 672185029Spjd } 673185029Spjd } 674185029Spjd 675185029Spjd ZFS_EXIT(zfsvfs); 676185029Spjd 677168404Spjd err = zfsctl_snapshot_zname(sdvp, snm, MAXNAMELEN, from); 678185029Spjd if (!err) 679185029Spjd err = zfsctl_snapshot_zname(tdvp, tnm, MAXNAMELEN, to); 680185029Spjd if (!err) 681185029Spjd err = zfs_secpolicy_rename_perms(from, to, cr); 682168404Spjd if (err) 683168404Spjd return (err); 684168404Spjd 685168404Spjd /* 686168404Spjd * Cannot move snapshots out of the snapdir. 687168404Spjd */ 688168404Spjd if (sdvp != tdvp) 689168404Spjd return (EINVAL); 690168404Spjd 691168404Spjd if (strcmp(snm, tnm) == 0) 692168404Spjd return (0); 693168404Spjd 694168404Spjd mutex_enter(&sdp->sd_lock); 695168404Spjd 696168404Spjd search.se_name = (char *)snm; 697168404Spjd if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) == NULL) { 698168404Spjd mutex_exit(&sdp->sd_lock); 699168404Spjd return (ENOENT); 700168404Spjd } 701168404Spjd 702168676Spjd err = dmu_objset_rename(from, to, B_FALSE); 703168404Spjd if (err == 0) 704168404Spjd zfsctl_rename_snap(sdp, sep, tnm); 705168404Spjd 706168404Spjd mutex_exit(&sdp->sd_lock); 707168404Spjd 708168404Spjd return (err); 709168404Spjd} 710168404Spjd#endif 711168404Spjd 712168404Spjd#if 0 713168404Spjd/* ARGSUSED */ 714168404Spjdstatic int 715185029Spjdzfsctl_snapdir_remove(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr, 716185029Spjd caller_context_t *ct, int flags) 717168404Spjd{ 718169170Spjd zfsctl_snapdir_t *sdp = dvp->v_data; 719185029Spjd zfs_snapentry_t *sep; 720185029Spjd zfs_snapentry_t search; 721185029Spjd zfsvfs_t *zfsvfs; 722169170Spjd char snapname[MAXNAMELEN]; 723185029Spjd char real[MAXNAMELEN]; 724169170Spjd int err; 725168404Spjd 726185029Spjd zfsvfs = dvp->v_vfsp->vfs_data; 727185029Spjd ZFS_ENTER(zfsvfs); 728185029Spjd 729185029Spjd if ((flags & FIGNORECASE) || zfsvfs->z_case == ZFS_CASE_INSENSITIVE) { 730185029Spjd 731185029Spjd err = dmu_snapshot_realname(zfsvfs->z_os, name, real, 732185029Spjd MAXNAMELEN, NULL); 733185029Spjd if (err == 0) { 734185029Spjd name = real; 735185029Spjd } else if (err != ENOTSUP) { 736185029Spjd ZFS_EXIT(zfsvfs); 737185029Spjd return (err); 738185029Spjd } 739185029Spjd } 740185029Spjd 741185029Spjd ZFS_EXIT(zfsvfs); 742185029Spjd 743169170Spjd err = zfsctl_snapshot_zname(dvp, name, MAXNAMELEN, snapname); 744185029Spjd if (!err) 745185029Spjd err = zfs_secpolicy_destroy_perms(snapname, cr); 746169170Spjd if (err) 747169170Spjd return (err); 748168404Spjd 749169170Spjd mutex_enter(&sdp->sd_lock); 750168404Spjd 751185029Spjd search.se_name = name; 752185029Spjd sep = avl_find(&sdp->sd_snaps, &search, NULL); 753185029Spjd if (sep) { 754185029Spjd avl_remove(&sdp->sd_snaps, sep); 755185029Spjd err = zfsctl_unmount_snap(sep, MS_FORCE, cr); 756196954Spjd if (err) { 757196954Spjd avl_index_t where; 758196954Spjd 759196954Spjd if (avl_find(&sdp->sd_snaps, sep, &where) == NULL) 760196954Spjd avl_insert(&sdp->sd_snaps, sep, where); 761196954Spjd } else 762185029Spjd err = dmu_objset_destroy(snapname); 763185029Spjd } else { 764185029Spjd err = ENOENT; 765169170Spjd } 766168404Spjd 767169170Spjd mutex_exit(&sdp->sd_lock); 768168404Spjd 769169170Spjd return (err); 770168404Spjd} 771168404Spjd#endif 772168404Spjd 773168404Spjd/* 774185029Spjd * This creates a snapshot under '.zfs/snapshot'. 775185029Spjd */ 776185029Spjd/* ARGSUSED */ 777185029Spjdstatic int 778185029Spjdzfsctl_snapdir_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, 779185029Spjd cred_t *cr, caller_context_t *cc, int flags, vsecattr_t *vsecp) 780185029Spjd{ 781185029Spjd zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 782185029Spjd char name[MAXNAMELEN]; 783185029Spjd int err; 784185029Spjd static enum symfollow follow = NO_FOLLOW; 785185029Spjd static enum uio_seg seg = UIO_SYSSPACE; 786185029Spjd 787185029Spjd if (snapshot_namecheck(dirname, NULL, NULL) != 0) 788185029Spjd return (EILSEQ); 789185029Spjd 790185029Spjd dmu_objset_name(zfsvfs->z_os, name); 791185029Spjd 792185029Spjd *vpp = NULL; 793185029Spjd 794185029Spjd err = zfs_secpolicy_snapshot_perms(name, cr); 795185029Spjd if (err) 796185029Spjd return (err); 797185029Spjd 798185029Spjd if (err == 0) { 799209962Smm err = dmu_objset_snapshot(name, dirname, NULL, B_FALSE); 800185029Spjd if (err) 801185029Spjd return (err); 802185029Spjd err = lookupnameat(dirname, seg, follow, NULL, vpp, dvp); 803185029Spjd } 804185029Spjd 805185029Spjd return (err); 806185029Spjd} 807185029Spjd 808185029Spjdstatic int 809185029Spjdzfsctl_freebsd_snapdir_mkdir(ap) 810185029Spjd struct vop_mkdir_args /* { 811185029Spjd struct vnode *a_dvp; 812185029Spjd struct vnode **a_vpp; 813185029Spjd struct componentname *a_cnp; 814185029Spjd struct vattr *a_vap; 815185029Spjd } */ *ap; 816185029Spjd{ 817185029Spjd 818185029Spjd ASSERT(ap->a_cnp->cn_flags & SAVENAME); 819185029Spjd 820185029Spjd return (zfsctl_snapdir_mkdir(ap->a_dvp, ap->a_cnp->cn_nameptr, NULL, 821185029Spjd ap->a_vpp, ap->a_cnp->cn_cred, NULL, 0, NULL)); 822185029Spjd} 823185029Spjd 824185029Spjd/* 825168404Spjd * Lookup entry point for the 'snapshot' directory. Try to open the 826168404Spjd * snapshot if it exist, creating the pseudo filesystem vnode as necessary. 827168404Spjd * Perform a mount of the associated dataset on top of the vnode. 828168404Spjd */ 829168404Spjd/* ARGSUSED */ 830168404Spjdint 831168404Spjdzfsctl_snapdir_lookup(ap) 832168404Spjd struct vop_lookup_args /* { 833168404Spjd struct vnode *a_dvp; 834168404Spjd struct vnode **a_vpp; 835168404Spjd struct componentname *a_cnp; 836168404Spjd } */ *ap; 837168404Spjd{ 838168404Spjd vnode_t *dvp = ap->a_dvp; 839168404Spjd vnode_t **vpp = ap->a_vpp; 840185029Spjd struct componentname *cnp = ap->a_cnp; 841168404Spjd char nm[NAME_MAX + 1]; 842168404Spjd zfsctl_snapdir_t *sdp = dvp->v_data; 843168404Spjd objset_t *snap; 844168404Spjd char snapname[MAXNAMELEN]; 845185029Spjd char real[MAXNAMELEN]; 846168404Spjd char *mountpoint; 847168404Spjd zfs_snapentry_t *sep, search; 848168404Spjd size_t mountpoint_len; 849168404Spjd avl_index_t where; 850168404Spjd zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 851168404Spjd int err; 852185029Spjd int flags = 0; 853168404Spjd 854185029Spjd /* 855185029Spjd * No extended attributes allowed under .zfs 856185029Spjd */ 857185029Spjd if (flags & LOOKUP_XATTR) 858185029Spjd return (EINVAL); 859168404Spjd ASSERT(ap->a_cnp->cn_namelen < sizeof(nm)); 860168404Spjd strlcpy(nm, ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen + 1); 861168404Spjd 862168404Spjd ASSERT(dvp->v_type == VDIR); 863168404Spjd 864168404Spjd *vpp = NULL; 865168404Spjd 866168404Spjd /* 867168404Spjd * If we get a recursive call, that means we got called 868168404Spjd * from the domount() code while it was trying to look up the 869168404Spjd * spec (which looks like a local path for zfs). We need to 870168404Spjd * add some flag to domount() to tell it not to do this lookup. 871168404Spjd */ 872168404Spjd if (MUTEX_HELD(&sdp->sd_lock)) 873168404Spjd return (ENOENT); 874168404Spjd 875168404Spjd ZFS_ENTER(zfsvfs); 876168404Spjd 877209962Smm if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0) { 878209962Smm ZFS_EXIT(zfsvfs); 879209962Smm return (0); 880209962Smm } 881209962Smm 882185029Spjd if (flags & FIGNORECASE) { 883185029Spjd boolean_t conflict = B_FALSE; 884185029Spjd 885185029Spjd err = dmu_snapshot_realname(zfsvfs->z_os, nm, real, 886185029Spjd MAXNAMELEN, &conflict); 887185029Spjd if (err == 0) { 888185029Spjd strlcpy(nm, real, sizeof(nm)); 889185029Spjd } else if (err != ENOTSUP) { 890185029Spjd ZFS_EXIT(zfsvfs); 891185029Spjd return (err); 892185029Spjd } 893185029Spjd#if 0 894185029Spjd if (realpnp) 895185029Spjd (void) strlcpy(realpnp->pn_buf, nm, 896185029Spjd realpnp->pn_bufsize); 897185029Spjd if (conflict && direntflags) 898185029Spjd *direntflags = ED_CASE_CONFLICT; 899185029Spjd#endif 900185029Spjd } 901185029Spjd 902168404Spjd mutex_enter(&sdp->sd_lock); 903168404Spjd search.se_name = (char *)nm; 904168404Spjd if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) != NULL) { 905168404Spjd *vpp = sep->se_root; 906168404Spjd VN_HOLD(*vpp); 907197513Spjd err = traverse(vpp, LK_EXCLUSIVE | LK_RETRY); 908197513Spjd if (err) { 909197513Spjd VN_RELE(*vpp); 910197513Spjd *vpp = NULL; 911197513Spjd } else if (*vpp == sep->se_root) { 912168404Spjd /* 913168404Spjd * The snapshot was unmounted behind our backs, 914168404Spjd * try to remount it. 915168404Spjd */ 916168404Spjd goto domount; 917185029Spjd } else { 918185029Spjd /* 919185029Spjd * VROOT was set during the traverse call. We need 920185029Spjd * to clear it since we're pretending to be part 921185029Spjd * of our parent's vfs. 922185029Spjd */ 923185029Spjd (*vpp)->v_flag &= ~VROOT; 924168404Spjd } 925168404Spjd mutex_exit(&sdp->sd_lock); 926168404Spjd ZFS_EXIT(zfsvfs); 927197513Spjd return (err); 928168404Spjd } 929168404Spjd 930168404Spjd /* 931168404Spjd * The requested snapshot is not currently mounted, look it up. 932168404Spjd */ 933168404Spjd err = zfsctl_snapshot_zname(dvp, nm, MAXNAMELEN, snapname); 934168404Spjd if (err) { 935168404Spjd mutex_exit(&sdp->sd_lock); 936168404Spjd ZFS_EXIT(zfsvfs); 937185029Spjd /* 938185029Spjd * handle "ls *" or "?" in a graceful manner, 939185029Spjd * forcing EILSEQ to ENOENT. 940185029Spjd * Since shell ultimately passes "*" or "?" as name to lookup 941185029Spjd */ 942185029Spjd return (err == EILSEQ ? ENOENT : err); 943168404Spjd } 944168404Spjd if (dmu_objset_open(snapname, DMU_OST_ZFS, 945185029Spjd DS_MODE_USER | DS_MODE_READONLY, &snap) != 0) { 946168404Spjd mutex_exit(&sdp->sd_lock); 947185029Spjd /* Translate errors and add SAVENAME when needed. */ 948185029Spjd if ((cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == CREATE) { 949185029Spjd err = EJUSTRETURN; 950185029Spjd cnp->cn_flags |= SAVENAME; 951185029Spjd } else { 952185029Spjd err = ENOENT; 953185029Spjd } 954168404Spjd ZFS_EXIT(zfsvfs); 955185029Spjd return (err); 956168404Spjd } 957168404Spjd 958168404Spjd sep = kmem_alloc(sizeof (zfs_snapentry_t), KM_SLEEP); 959168404Spjd sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP); 960168404Spjd (void) strcpy(sep->se_name, nm); 961168404Spjd *vpp = sep->se_root = zfsctl_snapshot_mknode(dvp, dmu_objset_id(snap)); 962168404Spjd VN_HOLD(*vpp); 963168404Spjd avl_insert(&sdp->sd_snaps, sep, where); 964168404Spjd 965168404Spjd dmu_objset_close(snap); 966168404Spjddomount: 967168404Spjd mountpoint_len = strlen(dvp->v_vfsp->mnt_stat.f_mntonname) + 968211900Spjd strlen("/" ZFS_CTLDIR_NAME "/snapshot/") + strlen(nm) + 1; 969168404Spjd mountpoint = kmem_alloc(mountpoint_len, KM_SLEEP); 970211900Spjd (void) snprintf(mountpoint, mountpoint_len, 971211900Spjd "%s/" ZFS_CTLDIR_NAME "/snapshot/%s", 972168404Spjd dvp->v_vfsp->mnt_stat.f_mntonname, nm); 973197201Spjd err = mount_snapshot(curthread, vpp, "zfs", mountpoint, snapname, 0); 974168404Spjd kmem_free(mountpoint, mountpoint_len); 975196980Spjd if (err == 0) { 976196980Spjd /* 977196980Spjd * Fix up the root vnode mounted on .zfs/snapshot/<snapname>. 978196980Spjd * 979196980Spjd * This is where we lie about our v_vfsp in order to 980196980Spjd * make .zfs/snapshot/<snapname> accessible over NFS 981196980Spjd * without requiring manual mounts of <snapname>. 982196980Spjd */ 983196980Spjd ASSERT(VTOZ(*vpp)->z_zfsvfs != zfsvfs); 984196980Spjd VTOZ(*vpp)->z_zfsvfs->z_parent = zfsvfs; 985196980Spjd } 986168404Spjd mutex_exit(&sdp->sd_lock); 987183037Spjd ZFS_EXIT(zfsvfs); 988197514Spjd if (err != 0) 989197514Spjd *vpp = NULL; 990168404Spjd return (err); 991168404Spjd} 992168404Spjd 993168404Spjd/* ARGSUSED */ 994209962Smmint 995209962Smmzfsctl_shares_lookup(ap) 996209962Smm struct vop_lookup_args /* { 997209962Smm struct vnode *a_dvp; 998209962Smm struct vnode **a_vpp; 999209962Smm struct componentname *a_cnp; 1000209962Smm } */ *ap; 1001209962Smm{ 1002209962Smm vnode_t *dvp = ap->a_dvp; 1003209962Smm vnode_t **vpp = ap->a_vpp; 1004209962Smm struct componentname *cnp = ap->a_cnp; 1005209962Smm zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 1006209962Smm char nm[NAME_MAX + 1]; 1007209962Smm znode_t *dzp; 1008209962Smm int error; 1009209962Smm 1010209962Smm ZFS_ENTER(zfsvfs); 1011209962Smm 1012209962Smm ASSERT(cnp->cn_namelen < sizeof(nm)); 1013209962Smm strlcpy(nm, cnp->cn_nameptr, cnp->cn_namelen + 1); 1014209962Smm 1015209962Smm if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0) { 1016209962Smm ZFS_EXIT(zfsvfs); 1017209962Smm return (0); 1018209962Smm } 1019209962Smm 1020209962Smm if (zfsvfs->z_shares_dir == 0) { 1021209962Smm ZFS_EXIT(zfsvfs); 1022209962Smm return (ENOTSUP); 1023209962Smm } 1024209962Smm if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) 1025209962Smm error = VOP_LOOKUP(ZTOV(dzp), vpp, cnp); 1026209962Smm 1027209962Smm VN_RELE(ZTOV(dzp)); 1028209962Smm ZFS_EXIT(zfsvfs); 1029209962Smm 1030209962Smm return (error); 1031209962Smm} 1032209962Smm 1033209962Smm/* ARGSUSED */ 1034168404Spjdstatic int 1035185029Spjdzfsctl_snapdir_readdir_cb(vnode_t *vp, void *dp, int *eofp, 1036185029Spjd offset_t *offp, offset_t *nextp, void *data, int flags) 1037168404Spjd{ 1038168404Spjd zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 1039168404Spjd char snapname[MAXNAMELEN]; 1040168404Spjd uint64_t id, cookie; 1041185029Spjd boolean_t case_conflict; 1042185029Spjd int error; 1043168404Spjd 1044168404Spjd ZFS_ENTER(zfsvfs); 1045168404Spjd 1046168404Spjd cookie = *offp; 1047185029Spjd error = dmu_snapshot_list_next(zfsvfs->z_os, MAXNAMELEN, snapname, &id, 1048185029Spjd &cookie, &case_conflict); 1049185029Spjd if (error) { 1050168404Spjd ZFS_EXIT(zfsvfs); 1051185029Spjd if (error == ENOENT) { 1052185029Spjd *eofp = 1; 1053185029Spjd return (0); 1054185029Spjd } 1055185029Spjd return (error); 1056168404Spjd } 1057168404Spjd 1058185029Spjd if (flags & V_RDDIR_ENTFLAGS) { 1059185029Spjd edirent_t *eodp = dp; 1060185029Spjd 1061185029Spjd (void) strcpy(eodp->ed_name, snapname); 1062185029Spjd eodp->ed_ino = ZFSCTL_INO_SNAP(id); 1063185029Spjd eodp->ed_eflags = case_conflict ? ED_CASE_CONFLICT : 0; 1064185029Spjd } else { 1065185029Spjd struct dirent64 *odp = dp; 1066185029Spjd 1067185029Spjd (void) strcpy(odp->d_name, snapname); 1068185029Spjd odp->d_ino = ZFSCTL_INO_SNAP(id); 1069185029Spjd } 1070168404Spjd *nextp = cookie; 1071168404Spjd 1072168404Spjd ZFS_EXIT(zfsvfs); 1073168404Spjd 1074168404Spjd return (0); 1075168404Spjd} 1076168404Spjd 1077209962Smm/* ARGSUSED */ 1078209962Smmstatic int 1079209962Smmzfsctl_shares_readdir(ap) 1080209962Smm struct vop_readdir_args /* { 1081209962Smm struct vnode *a_vp; 1082209962Smm struct uio *a_uio; 1083209962Smm struct ucred *a_cred; 1084209962Smm int *a_eofflag; 1085209962Smm int *a_ncookies; 1086209962Smm u_long **a_cookies; 1087209962Smm } */ *ap; 1088209962Smm{ 1089209962Smm vnode_t *vp = ap->a_vp; 1090209962Smm uio_t *uiop = ap->a_uio; 1091209962Smm cred_t *cr = ap->a_cred; 1092209962Smm int *eofp = ap->a_eofflag; 1093209962Smm zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 1094209962Smm znode_t *dzp; 1095209962Smm int error; 1096209962Smm 1097209962Smm ZFS_ENTER(zfsvfs); 1098209962Smm 1099209962Smm if (zfsvfs->z_shares_dir == 0) { 1100209962Smm ZFS_EXIT(zfsvfs); 1101209962Smm return (ENOTSUP); 1102209962Smm } 1103209962Smm if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) { 1104209962Smm error = VOP_READDIR(ZTOV(dzp), uiop, cr, eofp, ap->a_ncookies, ap->a_cookies); 1105209962Smm VN_RELE(ZTOV(dzp)); 1106209962Smm } else { 1107209962Smm *eofp = 1; 1108209962Smm error = ENOENT; 1109209962Smm } 1110209962Smm 1111209962Smm ZFS_EXIT(zfsvfs); 1112209962Smm return (error); 1113209962Smm} 1114209962Smm 1115185029Spjd/* 1116185029Spjd * pvp is the '.zfs' directory (zfsctl_node_t). 1117185029Spjd * Creates vp, which is '.zfs/snapshot' (zfsctl_snapdir_t). 1118185029Spjd * 1119185029Spjd * This function is the callback to create a GFS vnode for '.zfs/snapshot' 1120185029Spjd * when a lookup is performed on .zfs for "snapshot". 1121185029Spjd */ 1122168404Spjdvnode_t * 1123168404Spjdzfsctl_mknode_snapdir(vnode_t *pvp) 1124168404Spjd{ 1125168404Spjd vnode_t *vp; 1126168404Spjd zfsctl_snapdir_t *sdp; 1127168404Spjd 1128168404Spjd vp = gfs_dir_create(sizeof (zfsctl_snapdir_t), pvp, pvp->v_vfsp, 1129168404Spjd &zfsctl_ops_snapdir, NULL, NULL, MAXNAMELEN, 1130168404Spjd zfsctl_snapdir_readdir_cb, NULL); 1131168404Spjd sdp = vp->v_data; 1132168404Spjd sdp->sd_node.zc_id = ZFSCTL_INO_SNAPDIR; 1133168404Spjd sdp->sd_node.zc_cmtime = ((zfsctl_node_t *)pvp->v_data)->zc_cmtime; 1134168404Spjd mutex_init(&sdp->sd_lock, NULL, MUTEX_DEFAULT, NULL); 1135168404Spjd avl_create(&sdp->sd_snaps, snapentry_compare, 1136168404Spjd sizeof (zfs_snapentry_t), offsetof(zfs_snapentry_t, se_node)); 1137182781Spjd VOP_UNLOCK(vp, 0); 1138168404Spjd return (vp); 1139168404Spjd} 1140168404Spjd 1141209962Smmvnode_t * 1142209962Smmzfsctl_mknode_shares(vnode_t *pvp) 1143209962Smm{ 1144209962Smm vnode_t *vp; 1145209962Smm zfsctl_node_t *sdp; 1146209962Smm 1147209962Smm vp = gfs_dir_create(sizeof (zfsctl_node_t), pvp, pvp->v_vfsp, 1148209962Smm &zfsctl_ops_shares, NULL, NULL, MAXNAMELEN, 1149209962Smm NULL, NULL); 1150209962Smm sdp = vp->v_data; 1151209962Smm sdp->zc_cmtime = ((zfsctl_node_t *)pvp->v_data)->zc_cmtime; 1152209962Smm return (vp); 1153209962Smm 1154209962Smm} 1155209962Smm 1156168404Spjd/* ARGSUSED */ 1157168404Spjdstatic int 1158209962Smmzfsctl_shares_getattr(ap) 1159209962Smm struct vop_getattr_args /* { 1160209962Smm struct vnode *a_vp; 1161209962Smm struct vattr *a_vap; 1162209962Smm struct ucred *a_cred; 1163209962Smm struct thread *a_td; 1164209962Smm } */ *ap; 1165209962Smm{ 1166209962Smm vnode_t *vp = ap->a_vp; 1167209962Smm vattr_t *vap = ap->a_vap; 1168209962Smm cred_t *cr = ap->a_cred; 1169209962Smm zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 1170209962Smm znode_t *dzp; 1171209962Smm int error; 1172209962Smm 1173209962Smm ZFS_ENTER(zfsvfs); 1174209962Smm if (zfsvfs->z_shares_dir == 0) { 1175209962Smm ZFS_EXIT(zfsvfs); 1176209962Smm return (ENOTSUP); 1177209962Smm } 1178209962Smm if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) { 1179209962Smm error = VOP_GETATTR(ZTOV(dzp), vap, cr); 1180209962Smm VN_RELE(ZTOV(dzp)); 1181209962Smm } 1182209962Smm ZFS_EXIT(zfsvfs); 1183209962Smm return (error); 1184209962Smm} 1185209962Smm 1186209962Smm/* ARGSUSED */ 1187209962Smmstatic int 1188168404Spjdzfsctl_snapdir_getattr(ap) 1189168404Spjd struct vop_getattr_args /* { 1190168404Spjd struct vnode *a_vp; 1191168404Spjd struct vattr *a_vap; 1192168404Spjd struct ucred *a_cred; 1193185029Spjd struct thread *a_td; 1194168404Spjd } */ *ap; 1195168404Spjd{ 1196168404Spjd struct vnode *vp = ap->a_vp; 1197168404Spjd struct vattr *vap = ap->a_vap; 1198168404Spjd zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 1199168404Spjd zfsctl_snapdir_t *sdp = vp->v_data; 1200168404Spjd 1201168404Spjd ZFS_ENTER(zfsvfs); 1202168404Spjd zfsctl_common_getattr(vp, vap); 1203168404Spjd vap->va_nodeid = gfs_file_inode(vp); 1204168404Spjd vap->va_nlink = vap->va_size = avl_numnodes(&sdp->sd_snaps) + 2; 1205168404Spjd ZFS_EXIT(zfsvfs); 1206168404Spjd 1207168404Spjd return (0); 1208168404Spjd} 1209168404Spjd 1210168404Spjd/* ARGSUSED */ 1211168404Spjdstatic int 1212168404Spjdzfsctl_snapdir_inactive(ap) 1213168404Spjd struct vop_inactive_args /* { 1214168404Spjd struct vnode *a_vp; 1215168404Spjd struct thread *a_td; 1216168404Spjd } */ *ap; 1217168404Spjd{ 1218168404Spjd vnode_t *vp = ap->a_vp; 1219168404Spjd zfsctl_snapdir_t *sdp = vp->v_data; 1220197515Spjd zfs_snapentry_t *sep; 1221168404Spjd 1222197515Spjd /* 1223197515Spjd * On forced unmount we have to free snapshots from here. 1224197515Spjd */ 1225197515Spjd mutex_enter(&sdp->sd_lock); 1226197515Spjd while ((sep = avl_first(&sdp->sd_snaps)) != NULL) { 1227197515Spjd avl_remove(&sdp->sd_snaps, sep); 1228197515Spjd kmem_free(sep->se_name, strlen(sep->se_name) + 1); 1229197515Spjd kmem_free(sep, sizeof (zfs_snapentry_t)); 1230168404Spjd } 1231197515Spjd mutex_exit(&sdp->sd_lock); 1232197515Spjd gfs_dir_inactive(vp); 1233197515Spjd ASSERT(avl_numnodes(&sdp->sd_snaps) == 0); 1234197515Spjd mutex_destroy(&sdp->sd_lock); 1235197515Spjd avl_destroy(&sdp->sd_snaps); 1236197515Spjd kmem_free(sdp, sizeof (zfsctl_snapdir_t)); 1237197515Spjd 1238168404Spjd return (0); 1239168404Spjd} 1240168404Spjd 1241168404Spjdstatic struct vop_vector zfsctl_ops_snapdir = { 1242168404Spjd .vop_default = &default_vnodeops, 1243168404Spjd .vop_open = zfsctl_common_open, 1244168404Spjd .vop_close = zfsctl_common_close, 1245168404Spjd .vop_ioctl = VOP_EINVAL, 1246168404Spjd .vop_getattr = zfsctl_snapdir_getattr, 1247168404Spjd .vop_access = zfsctl_common_access, 1248185029Spjd .vop_mkdir = zfsctl_freebsd_snapdir_mkdir, 1249168404Spjd .vop_readdir = gfs_vop_readdir, 1250168404Spjd .vop_lookup = zfsctl_snapdir_lookup, 1251168404Spjd .vop_inactive = zfsctl_snapdir_inactive, 1252168404Spjd .vop_reclaim = zfsctl_common_reclaim, 1253168404Spjd .vop_fid = zfsctl_common_fid, 1254168404Spjd}; 1255168404Spjd 1256185029Spjd/* 1257185029Spjd * pvp is the GFS vnode '.zfs/snapshot'. 1258185029Spjd * 1259185029Spjd * This creates a GFS node under '.zfs/snapshot' representing each 1260185029Spjd * snapshot. This newly created GFS node is what we mount snapshot 1261185029Spjd * vfs_t's ontop of. 1262185029Spjd */ 1263168404Spjdstatic vnode_t * 1264168404Spjdzfsctl_snapshot_mknode(vnode_t *pvp, uint64_t objset) 1265168404Spjd{ 1266168404Spjd vnode_t *vp; 1267168404Spjd zfsctl_node_t *zcp; 1268168404Spjd 1269168404Spjd vp = gfs_dir_create(sizeof (zfsctl_node_t), pvp, pvp->v_vfsp, 1270168404Spjd &zfsctl_ops_snapshot, NULL, NULL, MAXNAMELEN, NULL, NULL); 1271185029Spjd VN_HOLD(vp); 1272168404Spjd zcp = vp->v_data; 1273168404Spjd zcp->zc_id = objset; 1274182781Spjd VOP_UNLOCK(vp, 0); 1275168404Spjd 1276168404Spjd return (vp); 1277168404Spjd} 1278168404Spjd 1279168404Spjdstatic int 1280168404Spjdzfsctl_snapshot_inactive(ap) 1281168404Spjd struct vop_inactive_args /* { 1282168404Spjd struct vnode *a_vp; 1283168404Spjd struct thread *a_td; 1284168404Spjd } */ *ap; 1285168404Spjd{ 1286168404Spjd vnode_t *vp = ap->a_vp; 1287185029Spjd cred_t *cr = ap->a_td->td_ucred; 1288168404Spjd struct vop_inactive_args iap; 1289168404Spjd zfsctl_snapdir_t *sdp; 1290168404Spjd zfs_snapentry_t *sep, *next; 1291168404Spjd int locked; 1292168404Spjd vnode_t *dvp; 1293168404Spjd 1294197515Spjd if (vp->v_count > 0) 1295197515Spjd goto end; 1296197515Spjd 1297185029Spjd VERIFY(gfs_dir_lookup(vp, "..", &dvp, cr, 0, NULL, NULL) == 0); 1298168404Spjd sdp = dvp->v_data; 1299175294Sattilio VOP_UNLOCK(dvp, 0); 1300168404Spjd 1301168404Spjd if (!(locked = MUTEX_HELD(&sdp->sd_lock))) 1302168404Spjd mutex_enter(&sdp->sd_lock); 1303168404Spjd 1304168404Spjd ASSERT(!vn_ismntpt(vp)); 1305168404Spjd 1306168404Spjd sep = avl_first(&sdp->sd_snaps); 1307168404Spjd while (sep != NULL) { 1308168404Spjd next = AVL_NEXT(&sdp->sd_snaps, sep); 1309168404Spjd 1310168404Spjd if (sep->se_root == vp) { 1311168404Spjd avl_remove(&sdp->sd_snaps, sep); 1312168404Spjd kmem_free(sep->se_name, strlen(sep->se_name) + 1); 1313168404Spjd kmem_free(sep, sizeof (zfs_snapentry_t)); 1314168404Spjd break; 1315168404Spjd } 1316168404Spjd sep = next; 1317168404Spjd } 1318168404Spjd ASSERT(sep != NULL); 1319168404Spjd 1320168404Spjd if (!locked) 1321168404Spjd mutex_exit(&sdp->sd_lock); 1322168404Spjd VN_RELE(dvp); 1323197515Spjdend: 1324168404Spjd 1325168404Spjd /* 1326168404Spjd * Dispose of the vnode for the snapshot mount point. 1327168404Spjd * This is safe to do because once this entry has been removed 1328168404Spjd * from the AVL tree, it can't be found again, so cannot become 1329168404Spjd * "active". If we lookup the same name again we will end up 1330168404Spjd * creating a new vnode. 1331168404Spjd */ 1332168404Spjd iap.a_vp = vp; 1333168404Spjd return (gfs_vop_inactive(&iap)); 1334168404Spjd} 1335168404Spjd 1336168404Spjdstatic int 1337182371Sattiliozfsctl_traverse_begin(vnode_t **vpp, int lktype) 1338168404Spjd{ 1339168404Spjd 1340168404Spjd VN_HOLD(*vpp); 1341168404Spjd /* Snapshot should be already mounted, but just in case. */ 1342168404Spjd if (vn_mountedvfs(*vpp) == NULL) 1343168404Spjd return (ENOENT); 1344170281Spjd return (traverse(vpp, lktype)); 1345168404Spjd} 1346168404Spjd 1347168404Spjdstatic void 1348168404Spjdzfsctl_traverse_end(vnode_t *vp, int err) 1349168404Spjd{ 1350168404Spjd 1351168404Spjd if (err == 0) 1352168404Spjd vput(vp); 1353168404Spjd else 1354168404Spjd VN_RELE(vp); 1355168404Spjd} 1356168404Spjd 1357168404Spjdstatic int 1358168404Spjdzfsctl_snapshot_getattr(ap) 1359168404Spjd struct vop_getattr_args /* { 1360168404Spjd struct vnode *a_vp; 1361168404Spjd struct vattr *a_vap; 1362168404Spjd struct ucred *a_cred; 1363168404Spjd } */ *ap; 1364168404Spjd{ 1365168404Spjd vnode_t *vp = ap->a_vp; 1366168404Spjd int err; 1367168404Spjd 1368182371Sattilio err = zfsctl_traverse_begin(&vp, LK_SHARED | LK_RETRY); 1369168404Spjd if (err == 0) 1370182371Sattilio err = VOP_GETATTR(vp, ap->a_vap, ap->a_cred); 1371168404Spjd zfsctl_traverse_end(vp, err); 1372168404Spjd return (err); 1373168404Spjd} 1374168404Spjd 1375168404Spjdstatic int 1376168404Spjdzfsctl_snapshot_fid(ap) 1377168404Spjd struct vop_fid_args /* { 1378168404Spjd struct vnode *a_vp; 1379168404Spjd struct fid *a_fid; 1380168404Spjd } */ *ap; 1381168404Spjd{ 1382168404Spjd vnode_t *vp = ap->a_vp; 1383168404Spjd int err; 1384168404Spjd 1385182371Sattilio err = zfsctl_traverse_begin(&vp, LK_SHARED | LK_RETRY); 1386168404Spjd if (err == 0) 1387168404Spjd err = VOP_VPTOFH(vp, (void *)ap->a_fid); 1388168404Spjd zfsctl_traverse_end(vp, err); 1389168404Spjd return (err); 1390168404Spjd} 1391168404Spjd 1392185029Spjdstatic int 1393185029Spjdzfsctl_snapshot_lookup(ap) 1394185029Spjd struct vop_lookup_args /* { 1395185029Spjd struct vnode *a_dvp; 1396185029Spjd struct vnode **a_vpp; 1397185029Spjd struct componentname *a_cnp; 1398185029Spjd } */ *ap; 1399185029Spjd{ 1400185029Spjd vnode_t *dvp = ap->a_dvp; 1401185029Spjd vnode_t **vpp = ap->a_vpp; 1402185029Spjd struct componentname *cnp = ap->a_cnp; 1403185029Spjd cred_t *cr = ap->a_cnp->cn_cred; 1404185029Spjd zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 1405185029Spjd int error; 1406185029Spjd 1407185029Spjd if (cnp->cn_namelen != 2 || cnp->cn_nameptr[0] != '.' || 1408185029Spjd cnp->cn_nameptr[1] != '.') { 1409185029Spjd return (ENOENT); 1410185029Spjd } 1411185029Spjd 1412185029Spjd ASSERT(dvp->v_type == VDIR); 1413185029Spjd ASSERT(zfsvfs->z_ctldir != NULL); 1414185029Spjd 1415185029Spjd error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", vpp, 1416185029Spjd NULL, 0, NULL, cr, NULL, NULL, NULL); 1417185029Spjd if (error == 0) 1418185029Spjd vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); 1419185029Spjd return (error); 1420185029Spjd} 1421185029Spjd 1422196309Spjdstatic int 1423196309Spjdzfsctl_snapshot_vptocnp(struct vop_vptocnp_args *ap) 1424196309Spjd{ 1425196309Spjd zfsvfs_t *zfsvfs = ap->a_vp->v_vfsp->vfs_data; 1426196309Spjd vnode_t *dvp, *vp; 1427196309Spjd zfsctl_snapdir_t *sdp; 1428196309Spjd zfs_snapentry_t *sep; 1429196309Spjd int error; 1430196309Spjd 1431196309Spjd ASSERT(zfsvfs->z_ctldir != NULL); 1432196309Spjd error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp, 1433196309Spjd NULL, 0, NULL, kcred, NULL, NULL, NULL); 1434196309Spjd if (error != 0) 1435196309Spjd return (error); 1436196309Spjd sdp = dvp->v_data; 1437196309Spjd 1438196309Spjd mutex_enter(&sdp->sd_lock); 1439196309Spjd sep = avl_first(&sdp->sd_snaps); 1440196309Spjd while (sep != NULL) { 1441196309Spjd vp = sep->se_root; 1442196309Spjd if (vp == ap->a_vp) 1443196309Spjd break; 1444196309Spjd sep = AVL_NEXT(&sdp->sd_snaps, sep); 1445196309Spjd } 1446196309Spjd if (sep == NULL) { 1447196309Spjd mutex_exit(&sdp->sd_lock); 1448196309Spjd error = ENOENT; 1449196309Spjd } else { 1450196309Spjd size_t len; 1451196309Spjd 1452196309Spjd len = strlen(sep->se_name); 1453196309Spjd *ap->a_buflen -= len; 1454196309Spjd bcopy(sep->se_name, ap->a_buf + *ap->a_buflen, len); 1455196309Spjd mutex_exit(&sdp->sd_lock); 1456196309Spjd vhold(dvp); 1457196309Spjd *ap->a_vpp = dvp; 1458196309Spjd } 1459196309Spjd VN_RELE(dvp); 1460196309Spjd 1461196309Spjd return (error); 1462196309Spjd} 1463196309Spjd 1464168404Spjd/* 1465168404Spjd * These VP's should never see the light of day. They should always 1466168404Spjd * be covered. 1467168404Spjd */ 1468168404Spjdstatic struct vop_vector zfsctl_ops_snapshot = { 1469168404Spjd .vop_default = &default_vnodeops, 1470168404Spjd .vop_inactive = zfsctl_snapshot_inactive, 1471185029Spjd .vop_lookup = zfsctl_snapshot_lookup, 1472168404Spjd .vop_reclaim = zfsctl_common_reclaim, 1473168404Spjd .vop_getattr = zfsctl_snapshot_getattr, 1474168404Spjd .vop_fid = zfsctl_snapshot_fid, 1475196309Spjd .vop_vptocnp = zfsctl_snapshot_vptocnp, 1476168404Spjd}; 1477168404Spjd 1478168404Spjdint 1479168404Spjdzfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t **zfsvfsp) 1480168404Spjd{ 1481168404Spjd zfsvfs_t *zfsvfs = vfsp->vfs_data; 1482168404Spjd vnode_t *dvp, *vp; 1483168404Spjd zfsctl_snapdir_t *sdp; 1484168404Spjd zfsctl_node_t *zcp; 1485168404Spjd zfs_snapentry_t *sep; 1486168404Spjd int error; 1487168404Spjd 1488168404Spjd ASSERT(zfsvfs->z_ctldir != NULL); 1489168404Spjd error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp, 1490185029Spjd NULL, 0, NULL, kcred, NULL, NULL, NULL); 1491168404Spjd if (error != 0) 1492168404Spjd return (error); 1493168404Spjd sdp = dvp->v_data; 1494168404Spjd 1495168404Spjd mutex_enter(&sdp->sd_lock); 1496168404Spjd sep = avl_first(&sdp->sd_snaps); 1497168404Spjd while (sep != NULL) { 1498168404Spjd vp = sep->se_root; 1499168404Spjd zcp = vp->v_data; 1500168404Spjd if (zcp->zc_id == objsetid) 1501168404Spjd break; 1502168404Spjd 1503168404Spjd sep = AVL_NEXT(&sdp->sd_snaps, sep); 1504168404Spjd } 1505168404Spjd 1506168404Spjd if (sep != NULL) { 1507168404Spjd VN_HOLD(vp); 1508185029Spjd /* 1509185029Spjd * Return the mounted root rather than the covered mount point. 1510185029Spjd * Takes the GFS vnode at .zfs/snapshot/<snapshot objsetid> 1511185029Spjd * and returns the ZFS vnode mounted on top of the GFS node. 1512185029Spjd * This ZFS vnode is the root of the vfs for objset 'objsetid'. 1513185029Spjd */ 1514170281Spjd error = traverse(&vp, LK_SHARED | LK_RETRY); 1515168404Spjd if (error == 0) { 1516168404Spjd if (vp == sep->se_root) 1517168404Spjd error = EINVAL; 1518168404Spjd else 1519168404Spjd *zfsvfsp = VTOZ(vp)->z_zfsvfs; 1520168404Spjd } 1521168404Spjd mutex_exit(&sdp->sd_lock); 1522170281Spjd if (error == 0) 1523170281Spjd VN_URELE(vp); 1524170281Spjd else 1525170281Spjd VN_RELE(vp); 1526168404Spjd } else { 1527168404Spjd error = EINVAL; 1528168404Spjd mutex_exit(&sdp->sd_lock); 1529168404Spjd } 1530168404Spjd 1531168404Spjd VN_RELE(dvp); 1532168404Spjd 1533168404Spjd return (error); 1534168404Spjd} 1535168404Spjd 1536168404Spjd/* 1537168404Spjd * Unmount any snapshots for the given filesystem. This is called from 1538168404Spjd * zfs_umount() - if we have a ctldir, then go through and unmount all the 1539168404Spjd * snapshots. 1540168404Spjd */ 1541168404Spjdint 1542168404Spjdzfsctl_umount_snapshots(vfs_t *vfsp, int fflags, cred_t *cr) 1543168404Spjd{ 1544168404Spjd zfsvfs_t *zfsvfs = vfsp->vfs_data; 1545185029Spjd vnode_t *dvp; 1546168404Spjd zfsctl_snapdir_t *sdp; 1547168404Spjd zfs_snapentry_t *sep, *next; 1548168404Spjd int error; 1549168404Spjd 1550168404Spjd ASSERT(zfsvfs->z_ctldir != NULL); 1551168404Spjd error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp, 1552185029Spjd NULL, 0, NULL, cr, NULL, NULL, NULL); 1553168404Spjd if (error != 0) 1554168404Spjd return (error); 1555168404Spjd sdp = dvp->v_data; 1556168404Spjd 1557168404Spjd mutex_enter(&sdp->sd_lock); 1558168404Spjd 1559168404Spjd sep = avl_first(&sdp->sd_snaps); 1560168404Spjd while (sep != NULL) { 1561168404Spjd next = AVL_NEXT(&sdp->sd_snaps, sep); 1562168404Spjd 1563168404Spjd /* 1564168404Spjd * If this snapshot is not mounted, then it must 1565168404Spjd * have just been unmounted by somebody else, and 1566168404Spjd * will be cleaned up by zfsctl_snapdir_inactive(). 1567168404Spjd */ 1568185029Spjd if (vn_ismntpt(sep->se_root)) { 1569185029Spjd error = zfsctl_unmount_snap(sep, fflags, cr); 1570185029Spjd if (error) { 1571196954Spjd avl_index_t where; 1572196954Spjd 1573196953Spjd /* 1574196953Spjd * Before reinserting snapshot to the tree, 1575196953Spjd * check if it was actually removed. For example 1576196953Spjd * when snapshot mount point is busy, we will 1577196953Spjd * have an error here, but there will be no need 1578196953Spjd * to reinsert snapshot. 1579196953Spjd */ 1580196954Spjd if (avl_find(&sdp->sd_snaps, sep, &where) == NULL) 1581196954Spjd avl_insert(&sdp->sd_snaps, sep, where); 1582185029Spjd break; 1583168404Spjd } 1584168404Spjd } 1585168404Spjd sep = next; 1586168404Spjd } 1587185029Spjd 1588168404Spjd mutex_exit(&sdp->sd_lock); 1589168404Spjd VN_RELE(dvp); 1590168404Spjd 1591168404Spjd return (error); 1592168404Spjd} 1593