zfs_ctldir.c revision 170281
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/* 22168404Spjd * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23168404Spjd * Use is subject to license terms. 24168404Spjd */ 25168404Spjd 26168404Spjd#pragma ident "%Z%%M% %I% %E% SMI" 27168404Spjd 28168404Spjd/* 29168404Spjd * ZFS control directory (a.k.a. ".zfs") 30168404Spjd * 31168404Spjd * This directory provides a common location for all ZFS meta-objects. 32168404Spjd * Currently, this is only the 'snapshot' directory, but this may expand in the 33168404Spjd * future. The elements are built using the GFS primitives, as the hierarchy 34168404Spjd * does not actually exist on disk. 35168404Spjd * 36168404Spjd * For 'snapshot', we don't want to have all snapshots always mounted, because 37168404Spjd * this would take up a huge amount of space in /etc/mnttab. We have three 38168404Spjd * types of objects: 39168404Spjd * 40168404Spjd * ctldir ------> snapshotdir -------> snapshot 41168404Spjd * | 42168404Spjd * | 43168404Spjd * V 44168404Spjd * mounted fs 45168404Spjd * 46168404Spjd * The 'snapshot' node contains just enough information to lookup '..' and act 47168404Spjd * as a mountpoint for the snapshot. Whenever we lookup a specific snapshot, we 48168404Spjd * perform an automount of the underlying filesystem and return the 49168404Spjd * corresponding vnode. 50168404Spjd * 51168404Spjd * All mounts are handled automatically by the kernel, but unmounts are 52168404Spjd * (currently) handled from user land. The main reason is that there is no 53168404Spjd * reliable way to auto-unmount the filesystem when it's "no longer in use". 54168404Spjd * When the user unmounts a filesystem, we call zfsctl_unmount(), which 55168404Spjd * unmounts any snapshots within the snapshot directory. 56168404Spjd */ 57168404Spjd 58168404Spjd#include <sys/zfs_context.h> 59168404Spjd#include <sys/zfs_ctldir.h> 60168404Spjd#include <sys/zfs_ioctl.h> 61168404Spjd#include <sys/zfs_vfsops.h> 62168404Spjd#include <sys/namei.h> 63168404Spjd#include <sys/gfs.h> 64168404Spjd#include <sys/stat.h> 65168404Spjd#include <sys/dmu.h> 66168404Spjd#include <sys/mount.h> 67168404Spjd 68168404Spjdtypedef struct { 69168404Spjd char *se_name; 70168404Spjd vnode_t *se_root; 71168404Spjd avl_node_t se_node; 72168404Spjd} zfs_snapentry_t; 73168404Spjd 74168404Spjdstatic int 75168404Spjdsnapentry_compare(const void *a, const void *b) 76168404Spjd{ 77168404Spjd const zfs_snapentry_t *sa = a; 78168404Spjd const zfs_snapentry_t *sb = b; 79168404Spjd int ret = strcmp(sa->se_name, sb->se_name); 80168404Spjd 81168404Spjd if (ret < 0) 82168404Spjd return (-1); 83168404Spjd else if (ret > 0) 84168404Spjd return (1); 85168404Spjd else 86168404Spjd return (0); 87168404Spjd} 88168404Spjd 89168404Spjdstatic struct vop_vector zfsctl_ops_root; 90168404Spjdstatic struct vop_vector zfsctl_ops_snapdir; 91168404Spjdstatic struct vop_vector zfsctl_ops_snapshot; 92168404Spjd 93168404Spjdstatic vnode_t *zfsctl_mknode_snapdir(vnode_t *); 94168404Spjdstatic vnode_t *zfsctl_snapshot_mknode(vnode_t *, uint64_t objset); 95168404Spjd 96168404Spjdtypedef struct zfsctl_node { 97168404Spjd gfs_dir_t zc_gfs_private; 98168404Spjd uint64_t zc_id; 99168404Spjd timestruc_t zc_cmtime; /* ctime and mtime, always the same */ 100168404Spjd} zfsctl_node_t; 101168404Spjd 102168404Spjdtypedef struct zfsctl_snapdir { 103168404Spjd zfsctl_node_t sd_node; 104168404Spjd kmutex_t sd_lock; 105168404Spjd avl_tree_t sd_snaps; 106168404Spjd} zfsctl_snapdir_t; 107168404Spjd 108168404Spjd/* 109168404Spjd * Root directory elements. We have only a single static entry, 'snapshot'. 110168404Spjd */ 111168404Spjdstatic gfs_dirent_t zfsctl_root_entries[] = { 112168404Spjd { "snapshot", zfsctl_mknode_snapdir, GFS_CACHE_VNODE }, 113168404Spjd { NULL } 114168404Spjd}; 115168404Spjd 116168404Spjd/* include . and .. in the calculation */ 117168404Spjd#define NROOT_ENTRIES ((sizeof (zfsctl_root_entries) / \ 118168404Spjd sizeof (gfs_dirent_t)) + 1) 119168404Spjd 120168404Spjd 121168404Spjd/* 122168404Spjd * Initialize the various GFS pieces we'll need to create and manipulate .zfs 123168404Spjd * directories. This is called from the ZFS init routine, and initializes the 124168404Spjd * vnode ops vectors that we'll be using. 125168404Spjd */ 126168404Spjdvoid 127168404Spjdzfsctl_init(void) 128168404Spjd{ 129168404Spjd} 130168404Spjd 131168404Spjdvoid 132168404Spjdzfsctl_fini(void) 133168404Spjd{ 134168404Spjd} 135168404Spjd 136168404Spjd/* 137168404Spjd * Return the inode number associated with the 'snapshot' directory. 138168404Spjd */ 139168404Spjd/* ARGSUSED */ 140168404Spjdstatic ino64_t 141168404Spjdzfsctl_root_inode_cb(vnode_t *vp, int index) 142168404Spjd{ 143168404Spjd ASSERT(index == 0); 144168404Spjd return (ZFSCTL_INO_SNAPDIR); 145168404Spjd} 146168404Spjd 147168404Spjd/* 148168404Spjd * Create the '.zfs' directory. This directory is cached as part of the VFS 149168404Spjd * structure. This results in a hold on the vfs_t. The code in zfs_umount() 150168404Spjd * therefore checks against a vfs_count of 2 instead of 1. This reference 151168404Spjd * is removed when the ctldir is destroyed in the unmount. 152168404Spjd */ 153168404Spjdvoid 154168404Spjdzfsctl_create(zfsvfs_t *zfsvfs) 155168404Spjd{ 156168404Spjd vnode_t *vp, *rvp; 157168404Spjd zfsctl_node_t *zcp; 158168404Spjd 159168404Spjd ASSERT(zfsvfs->z_ctldir == NULL); 160168404Spjd 161168404Spjd vp = gfs_root_create(sizeof (zfsctl_node_t), zfsvfs->z_vfs, 162168404Spjd &zfsctl_ops_root, ZFSCTL_INO_ROOT, zfsctl_root_entries, 163168404Spjd zfsctl_root_inode_cb, MAXNAMELEN, NULL, NULL); 164168404Spjd zcp = vp->v_data; 165168404Spjd zcp->zc_id = ZFSCTL_INO_ROOT; 166168404Spjd 167168404Spjd VERIFY(VFS_ROOT(zfsvfs->z_vfs, LK_EXCLUSIVE, &rvp, curthread) == 0); 168168404Spjd ZFS_TIME_DECODE(&zcp->zc_cmtime, VTOZ(rvp)->z_phys->zp_crtime); 169168404Spjd VN_URELE(rvp); 170168404Spjd 171168404Spjd /* 172168404Spjd * We're only faking the fact that we have a root of a filesystem for 173168404Spjd * the sake of the GFS interfaces. Undo the flag manipulation it did 174168404Spjd * for us. 175168404Spjd */ 176168404Spjd vp->v_vflag &= ~VV_ROOT; 177168404Spjd 178168404Spjd zfsvfs->z_ctldir = vp; 179168404Spjd} 180168404Spjd 181168404Spjd/* 182168404Spjd * Destroy the '.zfs' directory. Only called when the filesystem is unmounted. 183168404Spjd * There might still be more references if we were force unmounted, but only 184168404Spjd * new zfs_inactive() calls can occur and they don't reference .zfs 185168404Spjd */ 186168404Spjdvoid 187168404Spjdzfsctl_destroy(zfsvfs_t *zfsvfs) 188168404Spjd{ 189168404Spjd VN_RELE(zfsvfs->z_ctldir); 190168404Spjd zfsvfs->z_ctldir = NULL; 191168404Spjd} 192168404Spjd 193168404Spjd/* 194168404Spjd * Given a root znode, retrieve the associated .zfs directory. 195168404Spjd * Add a hold to the vnode and return it. 196168404Spjd */ 197168404Spjdvnode_t * 198168404Spjdzfsctl_root(znode_t *zp) 199168404Spjd{ 200168404Spjd ASSERT(zfs_has_ctldir(zp)); 201168404Spjd VN_HOLD(zp->z_zfsvfs->z_ctldir); 202168404Spjd return (zp->z_zfsvfs->z_ctldir); 203168404Spjd} 204168404Spjd 205168404Spjd/* 206168404Spjd * Common open routine. Disallow any write access. 207168404Spjd */ 208168404Spjd/* ARGSUSED */ 209168404Spjdstatic int 210168404Spjdzfsctl_common_open(struct vop_open_args *ap) 211168404Spjd{ 212168404Spjd int flags = ap->a_mode; 213168404Spjd 214168404Spjd if (flags & FWRITE) 215168404Spjd return (EACCES); 216168404Spjd 217168404Spjd return (0); 218168404Spjd} 219168404Spjd 220168404Spjd/* 221168404Spjd * Common close routine. Nothing to do here. 222168404Spjd */ 223168404Spjd/* ARGSUSED */ 224168404Spjdstatic int 225168404Spjdzfsctl_common_close(struct vop_close_args *ap) 226168404Spjd{ 227168404Spjd return (0); 228168404Spjd} 229168404Spjd 230168404Spjd/* 231168404Spjd * Common access routine. Disallow writes. 232168404Spjd */ 233168404Spjd/* ARGSUSED */ 234168404Spjdstatic int 235168404Spjdzfsctl_common_access(ap) 236168404Spjd struct vop_access_args /* { 237168404Spjd struct vnode *a_vp; 238168404Spjd int a_mode; 239168404Spjd struct ucred *a_cred; 240168404Spjd struct thread *a_td; 241168404Spjd } */ *ap; 242168404Spjd{ 243168404Spjd int mode = ap->a_mode; 244168404Spjd 245168404Spjd if (mode & VWRITE) 246168404Spjd return (EACCES); 247168404Spjd 248168404Spjd return (0); 249168404Spjd} 250168404Spjd 251168404Spjd/* 252168404Spjd * Common getattr function. Fill in basic information. 253168404Spjd */ 254168404Spjdstatic void 255168404Spjdzfsctl_common_getattr(vnode_t *vp, vattr_t *vap) 256168404Spjd{ 257168404Spjd zfsctl_node_t *zcp = vp->v_data; 258168404Spjd timestruc_t now; 259168404Spjd 260168404Spjd vap->va_uid = 0; 261168404Spjd vap->va_gid = 0; 262168404Spjd vap->va_rdev = 0; 263168404Spjd /* 264168404Spjd * We are a purly virtual object, so we have no 265168404Spjd * blocksize or allocated blocks. 266168404Spjd */ 267168404Spjd vap->va_blksize = 0; 268168404Spjd vap->va_nblocks = 0; 269168404Spjd vap->va_seq = 0; 270168404Spjd vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 271168404Spjd vap->va_mode = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | 272168404Spjd S_IROTH | S_IXOTH; 273168404Spjd vap->va_type = VDIR; 274168404Spjd /* 275168404Spjd * We live in the now (for atime). 276168404Spjd */ 277168404Spjd gethrestime(&now); 278168404Spjd vap->va_atime = now; 279168404Spjd vap->va_mtime = vap->va_ctime = vap->va_birthtime = zcp->zc_cmtime; 280168404Spjd /* FreeBSD: Reset chflags(2) flags. */ 281168404Spjd vap->va_flags = 0; 282168404Spjd} 283168404Spjd 284168404Spjdstatic int 285168404Spjdzfsctl_common_fid(ap) 286168404Spjd struct vop_fid_args /* { 287168404Spjd struct vnode *a_vp; 288168404Spjd struct fid *a_fid; 289168404Spjd } */ *ap; 290168404Spjd{ 291168404Spjd vnode_t *vp = ap->a_vp; 292168404Spjd fid_t *fidp = (void *)ap->a_fid; 293168404Spjd zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 294168404Spjd zfsctl_node_t *zcp = vp->v_data; 295168404Spjd uint64_t object = zcp->zc_id; 296168404Spjd zfid_short_t *zfid; 297168404Spjd int i; 298168404Spjd 299168404Spjd ZFS_ENTER(zfsvfs); 300168404Spjd 301168404Spjd fidp->fid_len = SHORT_FID_LEN; 302168404Spjd 303168404Spjd zfid = (zfid_short_t *)fidp; 304168404Spjd 305168404Spjd zfid->zf_len = SHORT_FID_LEN; 306168404Spjd 307168404Spjd for (i = 0; i < sizeof (zfid->zf_object); i++) 308168404Spjd zfid->zf_object[i] = (uint8_t)(object >> (8 * i)); 309168404Spjd 310168404Spjd /* .zfs znodes always have a generation number of 0 */ 311168404Spjd for (i = 0; i < sizeof (zfid->zf_gen); i++) 312168404Spjd zfid->zf_gen[i] = 0; 313168404Spjd 314168404Spjd ZFS_EXIT(zfsvfs); 315168404Spjd return (0); 316168404Spjd} 317168404Spjd 318168404Spjdstatic int 319168404Spjdzfsctl_common_reclaim(ap) 320168404Spjd struct vop_reclaim_args /* { 321168404Spjd struct vnode *a_vp; 322168404Spjd struct thread *a_td; 323168404Spjd } */ *ap; 324168404Spjd{ 325168404Spjd vnode_t *vp = ap->a_vp; 326168404Spjd 327168404Spjd /* 328168404Spjd * Destroy the vm object and flush associated pages. 329168404Spjd */ 330168404Spjd vnode_destroy_vobject(vp); 331168404Spjd VI_LOCK(vp); 332168404Spjd vp->v_data = NULL; 333168404Spjd VI_UNLOCK(vp); 334168404Spjd return (0); 335168404Spjd} 336168404Spjd 337168404Spjd/* 338168404Spjd * .zfs inode namespace 339168404Spjd * 340168404Spjd * We need to generate unique inode numbers for all files and directories 341168404Spjd * within the .zfs pseudo-filesystem. We use the following scheme: 342168404Spjd * 343168404Spjd * ENTRY ZFSCTL_INODE 344168404Spjd * .zfs 1 345168404Spjd * .zfs/snapshot 2 346168404Spjd * .zfs/snapshot/<snap> objectid(snap) 347168404Spjd */ 348168404Spjd 349168404Spjd#define ZFSCTL_INO_SNAP(id) (id) 350168404Spjd 351168404Spjd/* 352168404Spjd * Get root directory attributes. 353168404Spjd */ 354168404Spjd/* ARGSUSED */ 355168404Spjdstatic int 356168404Spjdzfsctl_root_getattr(ap) 357168404Spjd struct vop_getattr_args /* { 358168404Spjd struct vnode *a_vp; 359168404Spjd struct vattr *a_vap; 360168404Spjd struct ucred *a_cred; 361168404Spjd struct thread *a_td; 362168404Spjd } */ *ap; 363168404Spjd{ 364168404Spjd struct vnode *vp = ap->a_vp; 365168404Spjd struct vattr *vap = ap->a_vap; 366168404Spjd zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 367168404Spjd 368168404Spjd ZFS_ENTER(zfsvfs); 369168404Spjd vap->va_nodeid = ZFSCTL_INO_ROOT; 370168404Spjd vap->va_nlink = vap->va_size = NROOT_ENTRIES; 371168404Spjd 372168404Spjd zfsctl_common_getattr(vp, vap); 373168404Spjd ZFS_EXIT(zfsvfs); 374168404Spjd 375168404Spjd return (0); 376168404Spjd} 377168404Spjd 378168404Spjd/* 379168404Spjd * Special case the handling of "..". 380168404Spjd */ 381168404Spjd/* ARGSUSED */ 382168404Spjdint 383168404Spjdzfsctl_root_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp, 384168404Spjd int flags, vnode_t *rdir, cred_t *cr) 385168404Spjd{ 386168404Spjd zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 387168404Spjd int err; 388168404Spjd 389168404Spjd ZFS_ENTER(zfsvfs); 390168404Spjd 391168404Spjd if (strcmp(nm, "..") == 0) { 392168404Spjd err = VFS_ROOT(dvp->v_vfsp, LK_EXCLUSIVE, vpp, curthread); 393168404Spjd if (err == 0) 394168404Spjd VOP_UNLOCK(*vpp, 0, curthread); 395168404Spjd } else { 396168404Spjd err = gfs_dir_lookup(dvp, nm, vpp); 397168404Spjd } 398168404Spjd 399168404Spjd ZFS_EXIT(zfsvfs); 400168404Spjd 401168404Spjd return (err); 402168404Spjd} 403168404Spjd 404168404Spjd/* 405168404Spjd * Special case the handling of "..". 406168404Spjd */ 407168404Spjd/* ARGSUSED */ 408168404Spjdint 409168404Spjdzfsctl_root_lookup_vop(ap) 410168404Spjd struct vop_lookup_args /* { 411168404Spjd struct vnode *a_dvp; 412168404Spjd struct vnode **a_vpp; 413168404Spjd struct componentname *a_cnp; 414168404Spjd } */ *ap; 415168404Spjd{ 416168404Spjd vnode_t *dvp = ap->a_dvp; 417168404Spjd vnode_t **vpp = ap->a_vpp; 418168404Spjd cred_t *cr = ap->a_cnp->cn_cred; 419168404Spjd int flags = ap->a_cnp->cn_flags; 420168404Spjd int nameiop = ap->a_cnp->cn_nameiop; 421168404Spjd char nm[NAME_MAX + 1]; 422168404Spjd int err; 423168404Spjd 424168404Spjd if ((flags & ISLASTCN) && (nameiop == RENAME || nameiop == CREATE)) 425168404Spjd return (EOPNOTSUPP); 426168404Spjd 427168404Spjd ASSERT(ap->a_cnp->cn_namelen < sizeof(nm)); 428168404Spjd strlcpy(nm, ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen + 1); 429168404Spjd 430168404Spjd err = zfsctl_root_lookup(dvp, nm, vpp, NULL, 0, NULL, cr); 431168404Spjd if (err == 0 && (nm[0] != '.' || nm[1] != '\0')) 432168404Spjd vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, ap->a_cnp->cn_thread); 433168404Spjd 434168404Spjd return (err); 435168404Spjd} 436168404Spjd 437168404Spjdstatic struct vop_vector zfsctl_ops_root = { 438168404Spjd .vop_default = &default_vnodeops, 439168404Spjd .vop_open = zfsctl_common_open, 440168404Spjd .vop_close = zfsctl_common_close, 441168404Spjd .vop_ioctl = VOP_EINVAL, 442168404Spjd .vop_getattr = zfsctl_root_getattr, 443168404Spjd .vop_access = zfsctl_common_access, 444168404Spjd .vop_readdir = gfs_vop_readdir, 445168404Spjd .vop_lookup = zfsctl_root_lookup_vop, 446168404Spjd .vop_inactive = gfs_vop_inactive, 447168404Spjd .vop_reclaim = zfsctl_common_reclaim, 448168404Spjd .vop_fid = zfsctl_common_fid, 449168404Spjd}; 450168404Spjd 451168404Spjdstatic int 452168404Spjdzfsctl_snapshot_zname(vnode_t *vp, const char *name, int len, char *zname) 453168404Spjd{ 454168404Spjd objset_t *os = ((zfsvfs_t *)((vp)->v_vfsp->vfs_data))->z_os; 455168404Spjd 456168404Spjd dmu_objset_name(os, zname); 457168404Spjd if (strlen(zname) + 1 + strlen(name) >= len) 458168404Spjd return (ENAMETOOLONG); 459168404Spjd (void) strcat(zname, "@"); 460168404Spjd (void) strcat(zname, name); 461168404Spjd return (0); 462168404Spjd} 463168404Spjd 464168404Spjdstatic int 465168404Spjdzfsctl_unmount_snap(vnode_t *dvp, const char *name, int force, cred_t *cr) 466168404Spjd{ 467168404Spjd zfsctl_snapdir_t *sdp = dvp->v_data; 468168404Spjd zfs_snapentry_t search, *sep; 469168404Spjd struct vop_inactive_args ap; 470168404Spjd avl_index_t where; 471168404Spjd int err; 472168404Spjd 473168404Spjd ASSERT(MUTEX_HELD(&sdp->sd_lock)); 474168404Spjd 475168404Spjd search.se_name = (char *)name; 476168404Spjd if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) == NULL) 477168404Spjd return (ENOENT); 478168404Spjd 479168404Spjd ASSERT(vn_ismntpt(sep->se_root)); 480168404Spjd 481168404Spjd /* this will be dropped by dounmount() */ 482168404Spjd if ((err = vn_vfswlock(sep->se_root)) != 0) 483168404Spjd return (err); 484168404Spjd 485168404Spjd err = dounmount(vn_mountedvfs(sep->se_root), force, curthread); 486168404Spjd if (err) 487168404Spjd return (err); 488168404Spjd ASSERT(sep->se_root->v_count == 1); 489168404Spjd ap.a_vp = sep->se_root; 490168404Spjd gfs_vop_inactive(&ap); 491168404Spjd 492168404Spjd avl_remove(&sdp->sd_snaps, sep); 493168404Spjd kmem_free(sep->se_name, strlen(sep->se_name) + 1); 494168404Spjd kmem_free(sep, sizeof (zfs_snapentry_t)); 495168404Spjd 496168404Spjd return (0); 497168404Spjd} 498168404Spjd 499168404Spjd#if 0 500168404Spjdstatic void 501168404Spjdzfsctl_rename_snap(zfsctl_snapdir_t *sdp, zfs_snapentry_t *sep, const char *nm) 502168404Spjd{ 503168404Spjd avl_index_t where; 504168404Spjd vfs_t *vfsp; 505168404Spjd refstr_t *pathref; 506168404Spjd char newpath[MAXNAMELEN]; 507168404Spjd char *tail; 508168404Spjd 509168404Spjd ASSERT(MUTEX_HELD(&sdp->sd_lock)); 510168404Spjd ASSERT(sep != NULL); 511168404Spjd 512168404Spjd vfsp = vn_mountedvfs(sep->se_root); 513168404Spjd ASSERT(vfsp != NULL); 514168404Spjd 515168404Spjd vfs_lock_wait(vfsp); 516168404Spjd 517168404Spjd /* 518168404Spjd * Change the name in the AVL tree. 519168404Spjd */ 520168404Spjd avl_remove(&sdp->sd_snaps, sep); 521168404Spjd kmem_free(sep->se_name, strlen(sep->se_name) + 1); 522168404Spjd sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP); 523168404Spjd (void) strcpy(sep->se_name, nm); 524168404Spjd VERIFY(avl_find(&sdp->sd_snaps, sep, &where) == NULL); 525168404Spjd avl_insert(&sdp->sd_snaps, sep, where); 526168404Spjd 527168404Spjd /* 528168404Spjd * Change the current mountpoint info: 529168404Spjd * - update the tail of the mntpoint path 530168404Spjd * - update the tail of the resource path 531168404Spjd */ 532168404Spjd pathref = vfs_getmntpoint(vfsp); 533168404Spjd (void) strncpy(newpath, refstr_value(pathref), sizeof (newpath)); 534168404Spjd VERIFY((tail = strrchr(newpath, '/')) != NULL); 535168404Spjd *(tail+1) = '\0'; 536168404Spjd ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath)); 537168404Spjd (void) strcat(newpath, nm); 538168404Spjd refstr_rele(pathref); 539168404Spjd vfs_setmntpoint(vfsp, newpath); 540168404Spjd 541168404Spjd pathref = vfs_getresource(vfsp); 542168404Spjd (void) strncpy(newpath, refstr_value(pathref), sizeof (newpath)); 543168404Spjd VERIFY((tail = strrchr(newpath, '@')) != NULL); 544168404Spjd *(tail+1) = '\0'; 545168404Spjd ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath)); 546168404Spjd (void) strcat(newpath, nm); 547168404Spjd refstr_rele(pathref); 548168404Spjd vfs_setresource(vfsp, newpath); 549168404Spjd 550168404Spjd vfs_unlock(vfsp); 551168404Spjd} 552168404Spjd#endif 553168404Spjd 554168404Spjd#if 0 555168404Spjdstatic int 556168404Spjdzfsctl_snapdir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, 557168404Spjd cred_t *cr) 558168404Spjd{ 559168404Spjd zfsctl_snapdir_t *sdp = sdvp->v_data; 560168404Spjd zfs_snapentry_t search, *sep; 561168404Spjd avl_index_t where; 562168404Spjd char from[MAXNAMELEN], to[MAXNAMELEN]; 563168404Spjd int err; 564168404Spjd 565168404Spjd err = zfsctl_snapshot_zname(sdvp, snm, MAXNAMELEN, from); 566168404Spjd if (err) 567168404Spjd return (err); 568168404Spjd err = zfs_secpolicy_write(from, cr); 569168404Spjd if (err) 570168404Spjd return (err); 571168404Spjd 572168404Spjd /* 573168404Spjd * Cannot move snapshots out of the snapdir. 574168404Spjd */ 575168404Spjd if (sdvp != tdvp) 576168404Spjd return (EINVAL); 577168404Spjd 578168404Spjd if (strcmp(snm, tnm) == 0) 579168404Spjd return (0); 580168404Spjd 581168404Spjd err = zfsctl_snapshot_zname(tdvp, tnm, MAXNAMELEN, to); 582168404Spjd if (err) 583168404Spjd return (err); 584168404Spjd 585168404Spjd mutex_enter(&sdp->sd_lock); 586168404Spjd 587168404Spjd search.se_name = (char *)snm; 588168404Spjd if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) == NULL) { 589168404Spjd mutex_exit(&sdp->sd_lock); 590168404Spjd return (ENOENT); 591168404Spjd } 592168404Spjd 593168676Spjd err = dmu_objset_rename(from, to, B_FALSE); 594168404Spjd if (err == 0) 595168404Spjd zfsctl_rename_snap(sdp, sep, tnm); 596168404Spjd 597168404Spjd mutex_exit(&sdp->sd_lock); 598168404Spjd 599168404Spjd return (err); 600168404Spjd} 601168404Spjd#endif 602168404Spjd 603168404Spjd#if 0 604168404Spjd/* ARGSUSED */ 605168404Spjdstatic int 606168404Spjdzfsctl_snapdir_remove(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr) 607168404Spjd{ 608169170Spjd zfsctl_snapdir_t *sdp = dvp->v_data; 609169170Spjd char snapname[MAXNAMELEN]; 610169170Spjd int err; 611168404Spjd 612169170Spjd err = zfsctl_snapshot_zname(dvp, name, MAXNAMELEN, snapname); 613169170Spjd if (err) 614169170Spjd return (err); 615169170Spjd err = zfs_secpolicy_write(snapname, cr); 616169170Spjd if (err) 617169170Spjd return (err); 618168404Spjd 619169170Spjd mutex_enter(&sdp->sd_lock); 620168404Spjd 621169170Spjd err = zfsctl_unmount_snap(dvp, name, 0, cr); 622169170Spjd if (err) { 623169170Spjd mutex_exit(&sdp->sd_lock); 624169170Spjd return (err); 625169170Spjd } 626168404Spjd 627169170Spjd err = dmu_objset_destroy(snapname); 628168404Spjd 629169170Spjd mutex_exit(&sdp->sd_lock); 630168404Spjd 631169170Spjd return (err); 632168404Spjd} 633168404Spjd#endif 634168404Spjd 635168404Spjd/* 636168404Spjd * Lookup entry point for the 'snapshot' directory. Try to open the 637168404Spjd * snapshot if it exist, creating the pseudo filesystem vnode as necessary. 638168404Spjd * Perform a mount of the associated dataset on top of the vnode. 639168404Spjd */ 640168404Spjd/* ARGSUSED */ 641168404Spjdint 642168404Spjdzfsctl_snapdir_lookup(ap) 643168404Spjd struct vop_lookup_args /* { 644168404Spjd struct vnode *a_dvp; 645168404Spjd struct vnode **a_vpp; 646168404Spjd struct componentname *a_cnp; 647168404Spjd } */ *ap; 648168404Spjd{ 649168404Spjd vnode_t *dvp = ap->a_dvp; 650168404Spjd vnode_t **vpp = ap->a_vpp; 651168404Spjd char nm[NAME_MAX + 1]; 652168404Spjd zfsctl_snapdir_t *sdp = dvp->v_data; 653168404Spjd objset_t *snap; 654168404Spjd char snapname[MAXNAMELEN]; 655168404Spjd char *mountpoint; 656168404Spjd zfs_snapentry_t *sep, search; 657168404Spjd size_t mountpoint_len; 658168404Spjd avl_index_t where; 659168404Spjd zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 660168404Spjd int err; 661168404Spjd 662168404Spjd ASSERT(ap->a_cnp->cn_namelen < sizeof(nm)); 663168404Spjd strlcpy(nm, ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen + 1); 664168404Spjd 665168404Spjd ASSERT(dvp->v_type == VDIR); 666168404Spjd 667168404Spjd if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0) 668168404Spjd return (0); 669168404Spjd 670168404Spjd *vpp = NULL; 671168404Spjd 672168404Spjd /* 673168404Spjd * If we get a recursive call, that means we got called 674168404Spjd * from the domount() code while it was trying to look up the 675168404Spjd * spec (which looks like a local path for zfs). We need to 676168404Spjd * add some flag to domount() to tell it not to do this lookup. 677168404Spjd */ 678168404Spjd if (MUTEX_HELD(&sdp->sd_lock)) 679168404Spjd return (ENOENT); 680168404Spjd 681168404Spjd ZFS_ENTER(zfsvfs); 682168404Spjd 683168404Spjd mutex_enter(&sdp->sd_lock); 684168404Spjd search.se_name = (char *)nm; 685168404Spjd if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) != NULL) { 686168404Spjd *vpp = sep->se_root; 687168404Spjd VN_HOLD(*vpp); 688168404Spjd if ((*vpp)->v_mountedhere == NULL) { 689168404Spjd /* 690168404Spjd * The snapshot was unmounted behind our backs, 691168404Spjd * try to remount it. 692168404Spjd */ 693168404Spjd goto domount; 694168404Spjd } 695168404Spjd vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, ap->a_cnp->cn_thread); 696168404Spjd mutex_exit(&sdp->sd_lock); 697168404Spjd ZFS_EXIT(zfsvfs); 698168404Spjd return (0); 699168404Spjd } 700168404Spjd 701168404Spjd /* 702168404Spjd * The requested snapshot is not currently mounted, look it up. 703168404Spjd */ 704168404Spjd err = zfsctl_snapshot_zname(dvp, nm, MAXNAMELEN, snapname); 705168404Spjd if (err) { 706168404Spjd mutex_exit(&sdp->sd_lock); 707168404Spjd ZFS_EXIT(zfsvfs); 708168404Spjd return (err); 709168404Spjd } 710168404Spjd if (dmu_objset_open(snapname, DMU_OST_ZFS, 711168404Spjd DS_MODE_STANDARD | DS_MODE_READONLY, &snap) != 0) { 712168404Spjd mutex_exit(&sdp->sd_lock); 713168404Spjd ZFS_EXIT(zfsvfs); 714168404Spjd return (ENOENT); 715168404Spjd } 716168404Spjd 717168404Spjd sep = kmem_alloc(sizeof (zfs_snapentry_t), KM_SLEEP); 718168404Spjd sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP); 719168404Spjd (void) strcpy(sep->se_name, nm); 720168404Spjd *vpp = sep->se_root = zfsctl_snapshot_mknode(dvp, dmu_objset_id(snap)); 721168404Spjd VN_HOLD(*vpp); 722168404Spjd avl_insert(&sdp->sd_snaps, sep, where); 723168404Spjd 724168404Spjd dmu_objset_close(snap); 725168404Spjddomount: 726168404Spjd mountpoint_len = strlen(dvp->v_vfsp->mnt_stat.f_mntonname) + 727168404Spjd strlen("/.zfs/snapshot/") + strlen(nm) + 1; 728168404Spjd mountpoint = kmem_alloc(mountpoint_len, KM_SLEEP); 729168404Spjd (void) snprintf(mountpoint, mountpoint_len, "%s/.zfs/snapshot/%s", 730168404Spjd dvp->v_vfsp->mnt_stat.f_mntonname, nm); 731168404Spjd err = domount(curthread, *vpp, "zfs", mountpoint, snapname, 0); 732168404Spjd kmem_free(mountpoint, mountpoint_len); 733168404Spjd /* FreeBSD: This line was moved from below to avoid a lock recursion. */ 734168404Spjd if (err == 0) 735168404Spjd vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, curthread); 736168404Spjd mutex_exit(&sdp->sd_lock); 737168404Spjd 738168404Spjd /* 739168404Spjd * If we had an error, drop our hold on the vnode and 740168404Spjd * zfsctl_snapshot_inactive() will clean up. 741168404Spjd */ 742168404Spjd if (err) { 743168404Spjd VN_RELE(*vpp); 744168404Spjd *vpp = NULL; 745168404Spjd } 746168404Spjd return (err); 747168404Spjd} 748168404Spjd 749168404Spjd/* ARGSUSED */ 750168404Spjdstatic int 751168404Spjdzfsctl_snapdir_readdir_cb(vnode_t *vp, struct dirent64 *dp, int *eofp, 752168404Spjd offset_t *offp, offset_t *nextp, void *data) 753168404Spjd{ 754168404Spjd zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 755168404Spjd char snapname[MAXNAMELEN]; 756168404Spjd uint64_t id, cookie; 757168404Spjd 758168404Spjd ZFS_ENTER(zfsvfs); 759168404Spjd 760168404Spjd cookie = *offp; 761168404Spjd if (dmu_snapshot_list_next(zfsvfs->z_os, MAXNAMELEN, snapname, &id, 762168404Spjd &cookie) == ENOENT) { 763168404Spjd *eofp = 1; 764168404Spjd ZFS_EXIT(zfsvfs); 765168404Spjd return (0); 766168404Spjd } 767168404Spjd 768168404Spjd (void) strcpy(dp->d_name, snapname); 769168404Spjd dp->d_ino = ZFSCTL_INO_SNAP(id); 770168404Spjd *nextp = cookie; 771168404Spjd 772168404Spjd ZFS_EXIT(zfsvfs); 773168404Spjd 774168404Spjd return (0); 775168404Spjd} 776168404Spjd 777168404Spjdvnode_t * 778168404Spjdzfsctl_mknode_snapdir(vnode_t *pvp) 779168404Spjd{ 780168404Spjd vnode_t *vp; 781168404Spjd zfsctl_snapdir_t *sdp; 782168404Spjd 783168404Spjd vp = gfs_dir_create(sizeof (zfsctl_snapdir_t), pvp, pvp->v_vfsp, 784168404Spjd &zfsctl_ops_snapdir, NULL, NULL, MAXNAMELEN, 785168404Spjd zfsctl_snapdir_readdir_cb, NULL); 786168404Spjd sdp = vp->v_data; 787168404Spjd sdp->sd_node.zc_id = ZFSCTL_INO_SNAPDIR; 788168404Spjd sdp->sd_node.zc_cmtime = ((zfsctl_node_t *)pvp->v_data)->zc_cmtime; 789168404Spjd mutex_init(&sdp->sd_lock, NULL, MUTEX_DEFAULT, NULL); 790168404Spjd avl_create(&sdp->sd_snaps, snapentry_compare, 791168404Spjd sizeof (zfs_snapentry_t), offsetof(zfs_snapentry_t, se_node)); 792168404Spjd return (vp); 793168404Spjd} 794168404Spjd 795168404Spjd/* ARGSUSED */ 796168404Spjdstatic int 797168404Spjdzfsctl_snapdir_getattr(ap) 798168404Spjd struct vop_getattr_args /* { 799168404Spjd struct vnode *a_vp; 800168404Spjd struct vattr *a_vap; 801168404Spjd struct ucred *a_cred; 802168404Spjd struct thread *a_td; 803168404Spjd } */ *ap; 804168404Spjd{ 805168404Spjd struct vnode *vp = ap->a_vp; 806168404Spjd struct vattr *vap = ap->a_vap; 807168404Spjd zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 808168404Spjd zfsctl_snapdir_t *sdp = vp->v_data; 809168404Spjd 810168404Spjd ZFS_ENTER(zfsvfs); 811168404Spjd zfsctl_common_getattr(vp, vap); 812168404Spjd vap->va_nodeid = gfs_file_inode(vp); 813168404Spjd vap->va_nlink = vap->va_size = avl_numnodes(&sdp->sd_snaps) + 2; 814168404Spjd ZFS_EXIT(zfsvfs); 815168404Spjd 816168404Spjd return (0); 817168404Spjd} 818168404Spjd 819168404Spjd/* ARGSUSED */ 820168404Spjdstatic int 821168404Spjdzfsctl_snapdir_inactive(ap) 822168404Spjd struct vop_inactive_args /* { 823168404Spjd struct vnode *a_vp; 824168404Spjd struct thread *a_td; 825168404Spjd } */ *ap; 826168404Spjd{ 827168404Spjd vnode_t *vp = ap->a_vp; 828168404Spjd zfsctl_snapdir_t *sdp = vp->v_data; 829168404Spjd void *private; 830168404Spjd 831168404Spjd private = gfs_dir_inactive(vp); 832168404Spjd if (private != NULL) { 833168404Spjd ASSERT(avl_numnodes(&sdp->sd_snaps) == 0); 834168404Spjd mutex_destroy(&sdp->sd_lock); 835168404Spjd avl_destroy(&sdp->sd_snaps); 836168404Spjd kmem_free(private, sizeof (zfsctl_snapdir_t)); 837168404Spjd } 838168404Spjd return (0); 839168404Spjd} 840168404Spjd 841168404Spjdstatic struct vop_vector zfsctl_ops_snapdir = { 842168404Spjd .vop_default = &default_vnodeops, 843168404Spjd .vop_open = zfsctl_common_open, 844168404Spjd .vop_close = zfsctl_common_close, 845168404Spjd .vop_ioctl = VOP_EINVAL, 846168404Spjd .vop_getattr = zfsctl_snapdir_getattr, 847168404Spjd .vop_access = zfsctl_common_access, 848168404Spjd .vop_readdir = gfs_vop_readdir, 849168404Spjd .vop_lookup = zfsctl_snapdir_lookup, 850168404Spjd .vop_inactive = zfsctl_snapdir_inactive, 851168404Spjd .vop_reclaim = zfsctl_common_reclaim, 852168404Spjd .vop_fid = zfsctl_common_fid, 853168404Spjd}; 854168404Spjd 855168404Spjdstatic vnode_t * 856168404Spjdzfsctl_snapshot_mknode(vnode_t *pvp, uint64_t objset) 857168404Spjd{ 858168404Spjd vnode_t *vp; 859168404Spjd zfsctl_node_t *zcp; 860168404Spjd 861168404Spjd vp = gfs_dir_create(sizeof (zfsctl_node_t), pvp, pvp->v_vfsp, 862168404Spjd &zfsctl_ops_snapshot, NULL, NULL, MAXNAMELEN, NULL, NULL); 863168404Spjd zcp = vp->v_data; 864168404Spjd zcp->zc_id = objset; 865168404Spjd 866168404Spjd return (vp); 867168404Spjd} 868168404Spjd 869168404Spjdstatic int 870168404Spjdzfsctl_snapshot_inactive(ap) 871168404Spjd struct vop_inactive_args /* { 872168404Spjd struct vnode *a_vp; 873168404Spjd struct thread *a_td; 874168404Spjd } */ *ap; 875168404Spjd{ 876168404Spjd vnode_t *vp = ap->a_vp; 877168404Spjd struct vop_inactive_args iap; 878168404Spjd zfsctl_snapdir_t *sdp; 879168404Spjd zfs_snapentry_t *sep, *next; 880168404Spjd int locked; 881168404Spjd vnode_t *dvp; 882168404Spjd 883168404Spjd VERIFY(gfs_dir_lookup(vp, "..", &dvp) == 0); 884168404Spjd sdp = dvp->v_data; 885168404Spjd VOP_UNLOCK(dvp, 0, ap->a_td); 886168404Spjd 887168404Spjd if (!(locked = MUTEX_HELD(&sdp->sd_lock))) 888168404Spjd mutex_enter(&sdp->sd_lock); 889168404Spjd 890168404Spjd if (vp->v_count > 1) { 891168404Spjd if (!locked) 892168404Spjd mutex_exit(&sdp->sd_lock); 893168404Spjd return (0); 894168404Spjd } 895168404Spjd ASSERT(!vn_ismntpt(vp)); 896168404Spjd 897168404Spjd sep = avl_first(&sdp->sd_snaps); 898168404Spjd while (sep != NULL) { 899168404Spjd next = AVL_NEXT(&sdp->sd_snaps, sep); 900168404Spjd 901168404Spjd if (sep->se_root == vp) { 902168404Spjd avl_remove(&sdp->sd_snaps, sep); 903168404Spjd kmem_free(sep->se_name, strlen(sep->se_name) + 1); 904168404Spjd kmem_free(sep, sizeof (zfs_snapentry_t)); 905168404Spjd break; 906168404Spjd } 907168404Spjd sep = next; 908168404Spjd } 909168404Spjd ASSERT(sep != NULL); 910168404Spjd 911168404Spjd if (!locked) 912168404Spjd mutex_exit(&sdp->sd_lock); 913168404Spjd VN_RELE(dvp); 914168404Spjd 915168404Spjd /* 916168404Spjd * Dispose of the vnode for the snapshot mount point. 917168404Spjd * This is safe to do because once this entry has been removed 918168404Spjd * from the AVL tree, it can't be found again, so cannot become 919168404Spjd * "active". If we lookup the same name again we will end up 920168404Spjd * creating a new vnode. 921168404Spjd */ 922168404Spjd iap.a_vp = vp; 923168404Spjd return (gfs_vop_inactive(&iap)); 924168404Spjd} 925168404Spjd 926168404Spjdstatic int 927170281Spjdzfsctl_traverse_begin(vnode_t **vpp, int lktype, kthread_t *td) 928168404Spjd{ 929168404Spjd 930168404Spjd VN_HOLD(*vpp); 931168404Spjd /* Snapshot should be already mounted, but just in case. */ 932168404Spjd if (vn_mountedvfs(*vpp) == NULL) 933168404Spjd return (ENOENT); 934170281Spjd return (traverse(vpp, lktype)); 935168404Spjd} 936168404Spjd 937168404Spjdstatic void 938168404Spjdzfsctl_traverse_end(vnode_t *vp, int err) 939168404Spjd{ 940168404Spjd 941168404Spjd if (err == 0) 942168404Spjd vput(vp); 943168404Spjd else 944168404Spjd VN_RELE(vp); 945168404Spjd} 946168404Spjd 947168404Spjdstatic int 948168404Spjdzfsctl_snapshot_getattr(ap) 949168404Spjd struct vop_getattr_args /* { 950168404Spjd struct vnode *a_vp; 951168404Spjd struct vattr *a_vap; 952168404Spjd struct ucred *a_cred; 953168404Spjd struct thread *a_td; 954168404Spjd } */ *ap; 955168404Spjd{ 956168404Spjd vnode_t *vp = ap->a_vp; 957168404Spjd int err; 958168404Spjd 959170281Spjd err = zfsctl_traverse_begin(&vp, LK_SHARED | LK_RETRY, ap->a_td); 960168404Spjd if (err == 0) 961168404Spjd err = VOP_GETATTR(vp, ap->a_vap, ap->a_cred, ap->a_td); 962168404Spjd zfsctl_traverse_end(vp, err); 963168404Spjd return (err); 964168404Spjd} 965168404Spjd 966168404Spjdstatic int 967168404Spjdzfsctl_snapshot_fid(ap) 968168404Spjd struct vop_fid_args /* { 969168404Spjd struct vnode *a_vp; 970168404Spjd struct fid *a_fid; 971168404Spjd } */ *ap; 972168404Spjd{ 973168404Spjd vnode_t *vp = ap->a_vp; 974168404Spjd int err; 975168404Spjd 976170281Spjd err = zfsctl_traverse_begin(&vp, LK_SHARED | LK_RETRY, curthread); 977168404Spjd if (err == 0) 978168404Spjd err = VOP_VPTOFH(vp, (void *)ap->a_fid); 979168404Spjd zfsctl_traverse_end(vp, err); 980168404Spjd return (err); 981168404Spjd} 982168404Spjd 983168404Spjd/* 984168404Spjd * These VP's should never see the light of day. They should always 985168404Spjd * be covered. 986168404Spjd */ 987168404Spjdstatic struct vop_vector zfsctl_ops_snapshot = { 988168404Spjd .vop_default = &default_vnodeops, 989168404Spjd .vop_inactive = zfsctl_snapshot_inactive, 990168404Spjd .vop_reclaim = zfsctl_common_reclaim, 991168404Spjd .vop_getattr = zfsctl_snapshot_getattr, 992168404Spjd .vop_fid = zfsctl_snapshot_fid, 993168404Spjd}; 994168404Spjd 995168404Spjdint 996168404Spjdzfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t **zfsvfsp) 997168404Spjd{ 998168404Spjd zfsvfs_t *zfsvfs = vfsp->vfs_data; 999168404Spjd vnode_t *dvp, *vp; 1000168404Spjd zfsctl_snapdir_t *sdp; 1001168404Spjd zfsctl_node_t *zcp; 1002168404Spjd zfs_snapentry_t *sep; 1003168404Spjd int error; 1004168404Spjd 1005168404Spjd ASSERT(zfsvfs->z_ctldir != NULL); 1006168404Spjd error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp, 1007168404Spjd NULL, 0, NULL, kcred); 1008168404Spjd if (error != 0) 1009168404Spjd return (error); 1010168404Spjd sdp = dvp->v_data; 1011168404Spjd 1012168404Spjd mutex_enter(&sdp->sd_lock); 1013168404Spjd sep = avl_first(&sdp->sd_snaps); 1014168404Spjd while (sep != NULL) { 1015168404Spjd vp = sep->se_root; 1016168404Spjd zcp = vp->v_data; 1017168404Spjd if (zcp->zc_id == objsetid) 1018168404Spjd break; 1019168404Spjd 1020168404Spjd sep = AVL_NEXT(&sdp->sd_snaps, sep); 1021168404Spjd } 1022168404Spjd 1023168404Spjd if (sep != NULL) { 1024168404Spjd VN_HOLD(vp); 1025170281Spjd error = traverse(&vp, LK_SHARED | LK_RETRY); 1026168404Spjd if (error == 0) { 1027168404Spjd if (vp == sep->se_root) 1028168404Spjd error = EINVAL; 1029168404Spjd else 1030168404Spjd *zfsvfsp = VTOZ(vp)->z_zfsvfs; 1031168404Spjd } 1032168404Spjd mutex_exit(&sdp->sd_lock); 1033170281Spjd if (error == 0) 1034170281Spjd VN_URELE(vp); 1035170281Spjd else 1036170281Spjd VN_RELE(vp); 1037168404Spjd } else { 1038168404Spjd error = EINVAL; 1039168404Spjd mutex_exit(&sdp->sd_lock); 1040168404Spjd } 1041168404Spjd 1042168404Spjd VN_RELE(dvp); 1043168404Spjd 1044168404Spjd return (error); 1045168404Spjd} 1046168404Spjd 1047168404Spjd/* 1048168404Spjd * Unmount any snapshots for the given filesystem. This is called from 1049168404Spjd * zfs_umount() - if we have a ctldir, then go through and unmount all the 1050168404Spjd * snapshots. 1051168404Spjd */ 1052168404Spjdint 1053168404Spjdzfsctl_umount_snapshots(vfs_t *vfsp, int fflags, cred_t *cr) 1054168404Spjd{ 1055168404Spjd struct vop_inactive_args ap; 1056168404Spjd zfsvfs_t *zfsvfs = vfsp->vfs_data; 1057168404Spjd vnode_t *dvp, *svp; 1058168404Spjd zfsctl_snapdir_t *sdp; 1059168404Spjd zfs_snapentry_t *sep, *next; 1060168404Spjd int error; 1061168404Spjd 1062168404Spjd ASSERT(zfsvfs->z_ctldir != NULL); 1063168404Spjd error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp, 1064168404Spjd NULL, 0, NULL, cr); 1065168404Spjd if (error != 0) 1066168404Spjd return (error); 1067168404Spjd sdp = dvp->v_data; 1068168404Spjd 1069168404Spjd mutex_enter(&sdp->sd_lock); 1070168404Spjd 1071168404Spjd sep = avl_first(&sdp->sd_snaps); 1072168404Spjd while (sep != NULL) { 1073168404Spjd svp = sep->se_root; 1074168404Spjd next = AVL_NEXT(&sdp->sd_snaps, sep); 1075168404Spjd 1076168404Spjd /* 1077168404Spjd * If this snapshot is not mounted, then it must 1078168404Spjd * have just been unmounted by somebody else, and 1079168404Spjd * will be cleaned up by zfsctl_snapdir_inactive(). 1080168404Spjd */ 1081168404Spjd if (vn_ismntpt(svp)) { 1082168404Spjd if ((error = vn_vfswlock(svp)) != 0) 1083168404Spjd goto out; 1084168404Spjd 1085168404Spjd /* 1086168404Spjd * Increase usecount, so dounmount() won't vrele() it 1087168404Spjd * to 0 and call zfsctl_snapdir_inactive(). 1088168404Spjd */ 1089168404Spjd VN_HOLD(svp); 1090168404Spjd vfsp = vn_mountedvfs(svp); 1091168404Spjd mtx_lock(&Giant); 1092168404Spjd error = dounmount(vfsp, fflags, curthread); 1093168404Spjd mtx_unlock(&Giant); 1094168404Spjd if (error != 0) { 1095168404Spjd VN_RELE(svp); 1096168404Spjd goto out; 1097168404Spjd } 1098168404Spjd 1099168404Spjd avl_remove(&sdp->sd_snaps, sep); 1100168404Spjd kmem_free(sep->se_name, strlen(sep->se_name) + 1); 1101168404Spjd kmem_free(sep, sizeof (zfs_snapentry_t)); 1102168404Spjd 1103168404Spjd /* 1104168404Spjd * We can't use VN_RELE(), as that will try to 1105168404Spjd * invoke zfsctl_snapdir_inactive(), and that 1106168404Spjd * would lead to an attempt to re-grab the sd_lock. 1107168404Spjd */ 1108168404Spjd ASSERT3U(svp->v_count, ==, 1); 1109168404Spjd ap.a_vp = svp; 1110168404Spjd gfs_vop_inactive(&ap); 1111168404Spjd } 1112168404Spjd sep = next; 1113168404Spjd } 1114168404Spjdout: 1115168404Spjd mutex_exit(&sdp->sd_lock); 1116168404Spjd VN_RELE(dvp); 1117168404Spjd 1118168404Spjd return (error); 1119168404Spjd} 1120