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/* 22212694Smm * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23249643Smm * Copyright (c) 2013 by Delphix. All rights reserved. 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> 75249643Smm#include <sys/dsl_destroy.h> 76185029Spjd#include <sys/dsl_deleg.h> 77168404Spjd#include <sys/mount.h> 78185029Spjd#include <sys/sunddi.h> 79168404Spjd 80185029Spjd#include "zfs_namecheck.h" 81185029Spjd 82185029Spjdtypedef struct zfsctl_node { 83185029Spjd gfs_dir_t zc_gfs_private; 84185029Spjd uint64_t zc_id; 85185029Spjd timestruc_t zc_cmtime; /* ctime and mtime, always the same */ 86185029Spjd} zfsctl_node_t; 87185029Spjd 88185029Spjdtypedef struct zfsctl_snapdir { 89185029Spjd zfsctl_node_t sd_node; 90185029Spjd kmutex_t sd_lock; 91185029Spjd avl_tree_t sd_snaps; 92185029Spjd} zfsctl_snapdir_t; 93185029Spjd 94168404Spjdtypedef struct { 95168404Spjd char *se_name; 96168404Spjd vnode_t *se_root; 97168404Spjd avl_node_t se_node; 98168404Spjd} zfs_snapentry_t; 99168404Spjd 100168404Spjdstatic int 101168404Spjdsnapentry_compare(const void *a, const void *b) 102168404Spjd{ 103168404Spjd const zfs_snapentry_t *sa = a; 104168404Spjd const zfs_snapentry_t *sb = b; 105168404Spjd int ret = strcmp(sa->se_name, sb->se_name); 106168404Spjd 107168404Spjd if (ret < 0) 108168404Spjd return (-1); 109168404Spjd else if (ret > 0) 110168404Spjd return (1); 111168404Spjd else 112168404Spjd return (0); 113168404Spjd} 114168404Spjd 115219089Spjd#ifdef sun 116219089Spjdvnodeops_t *zfsctl_ops_root; 117219089Spjdvnodeops_t *zfsctl_ops_snapdir; 118219089Spjdvnodeops_t *zfsctl_ops_snapshot; 119219089Spjdvnodeops_t *zfsctl_ops_shares; 120219089Spjdvnodeops_t *zfsctl_ops_shares_dir; 121219089Spjd 122219089Spjdstatic const fs_operation_def_t zfsctl_tops_root[]; 123219089Spjdstatic const fs_operation_def_t zfsctl_tops_snapdir[]; 124219089Spjdstatic const fs_operation_def_t zfsctl_tops_snapshot[]; 125219089Spjdstatic const fs_operation_def_t zfsctl_tops_shares[]; 126219089Spjd#else /* !sun */ 127168404Spjdstatic struct vop_vector zfsctl_ops_root; 128168404Spjdstatic struct vop_vector zfsctl_ops_snapdir; 129168404Spjdstatic struct vop_vector zfsctl_ops_snapshot; 130209962Smmstatic struct vop_vector zfsctl_ops_shares; 131209962Smmstatic struct vop_vector zfsctl_ops_shares_dir; 132219089Spjd#endif /* !sun */ 133168404Spjd 134168404Spjdstatic vnode_t *zfsctl_mknode_snapdir(vnode_t *); 135209962Smmstatic vnode_t *zfsctl_mknode_shares(vnode_t *); 136168404Spjdstatic vnode_t *zfsctl_snapshot_mknode(vnode_t *, uint64_t objset); 137185029Spjdstatic int zfsctl_unmount_snap(zfs_snapentry_t *, int, cred_t *); 138168404Spjd 139219089Spjd#ifdef sun 140219089Spjdstatic gfs_opsvec_t zfsctl_opsvec[] = { 141219089Spjd { ".zfs", zfsctl_tops_root, &zfsctl_ops_root }, 142219089Spjd { ".zfs/snapshot", zfsctl_tops_snapdir, &zfsctl_ops_snapdir }, 143219089Spjd { ".zfs/snapshot/vnode", zfsctl_tops_snapshot, &zfsctl_ops_snapshot }, 144219089Spjd { ".zfs/shares", zfsctl_tops_shares, &zfsctl_ops_shares_dir }, 145219089Spjd { ".zfs/shares/vnode", zfsctl_tops_shares, &zfsctl_ops_shares }, 146219089Spjd { NULL } 147219089Spjd}; 148219089Spjd#endif /* sun */ 149219089Spjd 150168404Spjd/* 151209962Smm * Root directory elements. We only have two entries 152209962Smm * snapshot and shares. 153168404Spjd */ 154168404Spjdstatic gfs_dirent_t zfsctl_root_entries[] = { 155168404Spjd { "snapshot", zfsctl_mknode_snapdir, GFS_CACHE_VNODE }, 156209962Smm { "shares", zfsctl_mknode_shares, GFS_CACHE_VNODE }, 157168404Spjd { NULL } 158168404Spjd}; 159168404Spjd 160168404Spjd/* include . and .. in the calculation */ 161168404Spjd#define NROOT_ENTRIES ((sizeof (zfsctl_root_entries) / \ 162168404Spjd sizeof (gfs_dirent_t)) + 1) 163168404Spjd 164168404Spjd 165168404Spjd/* 166168404Spjd * Initialize the various GFS pieces we'll need to create and manipulate .zfs 167168404Spjd * directories. This is called from the ZFS init routine, and initializes the 168168404Spjd * vnode ops vectors that we'll be using. 169168404Spjd */ 170168404Spjdvoid 171168404Spjdzfsctl_init(void) 172168404Spjd{ 173219089Spjd#ifdef sun 174219089Spjd VERIFY(gfs_make_opsvec(zfsctl_opsvec) == 0); 175219089Spjd#endif 176168404Spjd} 177168404Spjd 178168404Spjdvoid 179168404Spjdzfsctl_fini(void) 180168404Spjd{ 181219089Spjd#ifdef sun 182219089Spjd /* 183219089Spjd * Remove vfsctl vnode ops 184219089Spjd */ 185219089Spjd if (zfsctl_ops_root) 186219089Spjd vn_freevnodeops(zfsctl_ops_root); 187219089Spjd if (zfsctl_ops_snapdir) 188219089Spjd vn_freevnodeops(zfsctl_ops_snapdir); 189219089Spjd if (zfsctl_ops_snapshot) 190219089Spjd vn_freevnodeops(zfsctl_ops_snapshot); 191219089Spjd if (zfsctl_ops_shares) 192219089Spjd vn_freevnodeops(zfsctl_ops_shares); 193219089Spjd if (zfsctl_ops_shares_dir) 194219089Spjd vn_freevnodeops(zfsctl_ops_shares_dir); 195219089Spjd 196219089Spjd zfsctl_ops_root = NULL; 197219089Spjd zfsctl_ops_snapdir = NULL; 198219089Spjd zfsctl_ops_snapshot = NULL; 199219089Spjd zfsctl_ops_shares = NULL; 200219089Spjd zfsctl_ops_shares_dir = NULL; 201219089Spjd#endif /* sun */ 202168404Spjd} 203168404Spjd 204212694Smmboolean_t 205212694Smmzfsctl_is_node(vnode_t *vp) 206212694Smm{ 207212694Smm return (vn_matchops(vp, zfsctl_ops_root) || 208212694Smm vn_matchops(vp, zfsctl_ops_snapdir) || 209212694Smm vn_matchops(vp, zfsctl_ops_snapshot) || 210212694Smm vn_matchops(vp, zfsctl_ops_shares) || 211212694Smm vn_matchops(vp, zfsctl_ops_shares_dir)); 212212694Smm 213212694Smm} 214212694Smm 215168404Spjd/* 216209962Smm * Return the inode number associated with the 'snapshot' or 217209962Smm * 'shares' directory. 218168404Spjd */ 219168404Spjd/* ARGSUSED */ 220168404Spjdstatic ino64_t 221168404Spjdzfsctl_root_inode_cb(vnode_t *vp, int index) 222168404Spjd{ 223209962Smm zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 224209962Smm 225209962Smm ASSERT(index <= 2); 226209962Smm 227209962Smm if (index == 0) 228209962Smm return (ZFSCTL_INO_SNAPDIR); 229209962Smm 230209962Smm return (zfsvfs->z_shares_dir); 231168404Spjd} 232168404Spjd 233168404Spjd/* 234168404Spjd * Create the '.zfs' directory. This directory is cached as part of the VFS 235168404Spjd * structure. This results in a hold on the vfs_t. The code in zfs_umount() 236168404Spjd * therefore checks against a vfs_count of 2 instead of 1. This reference 237168404Spjd * is removed when the ctldir is destroyed in the unmount. 238168404Spjd */ 239168404Spjdvoid 240168404Spjdzfsctl_create(zfsvfs_t *zfsvfs) 241168404Spjd{ 242168404Spjd vnode_t *vp, *rvp; 243168404Spjd zfsctl_node_t *zcp; 244219089Spjd uint64_t crtime[2]; 245168404Spjd 246168404Spjd ASSERT(zfsvfs->z_ctldir == NULL); 247168404Spjd 248168404Spjd vp = gfs_root_create(sizeof (zfsctl_node_t), zfsvfs->z_vfs, 249168404Spjd &zfsctl_ops_root, ZFSCTL_INO_ROOT, zfsctl_root_entries, 250168404Spjd zfsctl_root_inode_cb, MAXNAMELEN, NULL, NULL); 251168404Spjd zcp = vp->v_data; 252168404Spjd zcp->zc_id = ZFSCTL_INO_ROOT; 253168404Spjd 254191990Sattilio VERIFY(VFS_ROOT(zfsvfs->z_vfs, LK_EXCLUSIVE, &rvp) == 0); 255219089Spjd VERIFY(0 == sa_lookup(VTOZ(rvp)->z_sa_hdl, SA_ZPL_CRTIME(zfsvfs), 256219089Spjd &crtime, sizeof (crtime))); 257219089Spjd ZFS_TIME_DECODE(&zcp->zc_cmtime, crtime); 258168404Spjd VN_URELE(rvp); 259168404Spjd 260168404Spjd /* 261168404Spjd * We're only faking the fact that we have a root of a filesystem for 262168404Spjd * the sake of the GFS interfaces. Undo the flag manipulation it did 263168404Spjd * for us. 264168404Spjd */ 265168404Spjd vp->v_vflag &= ~VV_ROOT; 266168404Spjd 267168404Spjd zfsvfs->z_ctldir = vp; 268182781Spjd 269182781Spjd VOP_UNLOCK(vp, 0); 270168404Spjd} 271168404Spjd 272168404Spjd/* 273168404Spjd * Destroy the '.zfs' directory. Only called when the filesystem is unmounted. 274168404Spjd * There might still be more references if we were force unmounted, but only 275168404Spjd * new zfs_inactive() calls can occur and they don't reference .zfs 276168404Spjd */ 277168404Spjdvoid 278168404Spjdzfsctl_destroy(zfsvfs_t *zfsvfs) 279168404Spjd{ 280168404Spjd VN_RELE(zfsvfs->z_ctldir); 281168404Spjd zfsvfs->z_ctldir = NULL; 282168404Spjd} 283168404Spjd 284168404Spjd/* 285168404Spjd * Given a root znode, retrieve the associated .zfs directory. 286168404Spjd * Add a hold to the vnode and return it. 287168404Spjd */ 288168404Spjdvnode_t * 289168404Spjdzfsctl_root(znode_t *zp) 290168404Spjd{ 291168404Spjd ASSERT(zfs_has_ctldir(zp)); 292168404Spjd VN_HOLD(zp->z_zfsvfs->z_ctldir); 293168404Spjd return (zp->z_zfsvfs->z_ctldir); 294168404Spjd} 295168404Spjd 296168404Spjd/* 297168404Spjd * Common open routine. Disallow any write access. 298168404Spjd */ 299168404Spjd/* ARGSUSED */ 300168404Spjdstatic int 301168404Spjdzfsctl_common_open(struct vop_open_args *ap) 302168404Spjd{ 303168404Spjd int flags = ap->a_mode; 304168404Spjd 305168404Spjd if (flags & FWRITE) 306249643Smm return (SET_ERROR(EACCES)); 307168404Spjd 308168404Spjd return (0); 309168404Spjd} 310168404Spjd 311168404Spjd/* 312168404Spjd * Common close routine. Nothing to do here. 313168404Spjd */ 314168404Spjd/* ARGSUSED */ 315168404Spjdstatic int 316168404Spjdzfsctl_common_close(struct vop_close_args *ap) 317168404Spjd{ 318168404Spjd return (0); 319168404Spjd} 320168404Spjd 321168404Spjd/* 322168404Spjd * Common access routine. Disallow writes. 323168404Spjd */ 324168404Spjd/* ARGSUSED */ 325168404Spjdstatic int 326168404Spjdzfsctl_common_access(ap) 327168404Spjd struct vop_access_args /* { 328168404Spjd struct vnode *a_vp; 329219089Spjd accmode_t a_accmode; 330168404Spjd struct ucred *a_cred; 331168404Spjd struct thread *a_td; 332168404Spjd } */ *ap; 333168404Spjd{ 334219089Spjd accmode_t accmode = ap->a_accmode; 335168404Spjd 336209962Smm#ifdef TODO 337209962Smm if (flags & V_ACE_MASK) { 338209962Smm if (accmode & ACE_ALL_WRITE_PERMS) 339249643Smm return (SET_ERROR(EACCES)); 340209962Smm } else { 341209962Smm#endif 342219089Spjd if (accmode & VWRITE) 343249643Smm return (SET_ERROR(EACCES)); 344209962Smm#ifdef TODO 345209962Smm } 346209962Smm#endif 347168404Spjd 348168404Spjd return (0); 349168404Spjd} 350168404Spjd 351168404Spjd/* 352168404Spjd * Common getattr function. Fill in basic information. 353168404Spjd */ 354168404Spjdstatic void 355168404Spjdzfsctl_common_getattr(vnode_t *vp, vattr_t *vap) 356168404Spjd{ 357168404Spjd timestruc_t now; 358168404Spjd 359168404Spjd vap->va_uid = 0; 360168404Spjd vap->va_gid = 0; 361168404Spjd vap->va_rdev = 0; 362168404Spjd /* 363219089Spjd * We are a purely virtual object, so we have no 364168404Spjd * blocksize or allocated blocks. 365168404Spjd */ 366168404Spjd vap->va_blksize = 0; 367168404Spjd vap->va_nblocks = 0; 368168404Spjd vap->va_seq = 0; 369168404Spjd vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 370168404Spjd vap->va_mode = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | 371168404Spjd S_IROTH | S_IXOTH; 372168404Spjd vap->va_type = VDIR; 373168404Spjd /* 374168404Spjd * We live in the now (for atime). 375168404Spjd */ 376168404Spjd gethrestime(&now); 377168404Spjd vap->va_atime = now; 378168404Spjd /* FreeBSD: Reset chflags(2) flags. */ 379168404Spjd vap->va_flags = 0; 380168404Spjd} 381168404Spjd 382185029Spjd/*ARGSUSED*/ 383168404Spjdstatic int 384168404Spjdzfsctl_common_fid(ap) 385168404Spjd struct vop_fid_args /* { 386168404Spjd struct vnode *a_vp; 387168404Spjd struct fid *a_fid; 388168404Spjd } */ *ap; 389168404Spjd{ 390168404Spjd vnode_t *vp = ap->a_vp; 391168404Spjd fid_t *fidp = (void *)ap->a_fid; 392168404Spjd zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 393168404Spjd zfsctl_node_t *zcp = vp->v_data; 394168404Spjd uint64_t object = zcp->zc_id; 395168404Spjd zfid_short_t *zfid; 396168404Spjd int i; 397168404Spjd 398168404Spjd ZFS_ENTER(zfsvfs); 399168404Spjd 400249643Smm#ifdef illumos 401249643Smm if (fidp->fid_len < SHORT_FID_LEN) { 402249643Smm fidp->fid_len = SHORT_FID_LEN; 403249643Smm ZFS_EXIT(zfsvfs); 404249643Smm return (SET_ERROR(ENOSPC)); 405249643Smm } 406249643Smm#else 407168404Spjd fidp->fid_len = SHORT_FID_LEN; 408249643Smm#endif 409168404Spjd 410168404Spjd zfid = (zfid_short_t *)fidp; 411168404Spjd 412168404Spjd zfid->zf_len = SHORT_FID_LEN; 413168404Spjd 414168404Spjd for (i = 0; i < sizeof (zfid->zf_object); i++) 415168404Spjd zfid->zf_object[i] = (uint8_t)(object >> (8 * i)); 416168404Spjd 417168404Spjd /* .zfs znodes always have a generation number of 0 */ 418168404Spjd for (i = 0; i < sizeof (zfid->zf_gen); i++) 419168404Spjd zfid->zf_gen[i] = 0; 420168404Spjd 421168404Spjd ZFS_EXIT(zfsvfs); 422168404Spjd return (0); 423168404Spjd} 424168404Spjd 425219089Spjd 426209962Smm/*ARGSUSED*/ 427168404Spjdstatic int 428209962Smmzfsctl_shares_fid(ap) 429209962Smm struct vop_fid_args /* { 430209962Smm struct vnode *a_vp; 431209962Smm struct fid *a_fid; 432209962Smm } */ *ap; 433209962Smm{ 434209962Smm vnode_t *vp = ap->a_vp; 435209962Smm fid_t *fidp = (void *)ap->a_fid; 436209962Smm zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 437209962Smm znode_t *dzp; 438209962Smm int error; 439209962Smm 440209962Smm ZFS_ENTER(zfsvfs); 441209962Smm 442209962Smm if (zfsvfs->z_shares_dir == 0) { 443209962Smm ZFS_EXIT(zfsvfs); 444249643Smm return (SET_ERROR(ENOTSUP)); 445209962Smm } 446209962Smm 447209962Smm if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) { 448209962Smm error = VOP_FID(ZTOV(dzp), fidp); 449209962Smm VN_RELE(ZTOV(dzp)); 450209962Smm } 451209962Smm 452209962Smm ZFS_EXIT(zfsvfs); 453209962Smm return (error); 454209962Smm} 455209962Smm 456209962Smmstatic int 457168404Spjdzfsctl_common_reclaim(ap) 458168404Spjd struct vop_reclaim_args /* { 459168404Spjd struct vnode *a_vp; 460168404Spjd struct thread *a_td; 461168404Spjd } */ *ap; 462168404Spjd{ 463168404Spjd vnode_t *vp = ap->a_vp; 464168404Spjd 465168404Spjd /* 466168404Spjd * Destroy the vm object and flush associated pages. 467168404Spjd */ 468168404Spjd vnode_destroy_vobject(vp); 469168404Spjd VI_LOCK(vp); 470168404Spjd vp->v_data = NULL; 471168404Spjd VI_UNLOCK(vp); 472168404Spjd return (0); 473168404Spjd} 474168404Spjd 475168404Spjd/* 476168404Spjd * .zfs inode namespace 477168404Spjd * 478168404Spjd * We need to generate unique inode numbers for all files and directories 479168404Spjd * within the .zfs pseudo-filesystem. We use the following scheme: 480168404Spjd * 481168404Spjd * ENTRY ZFSCTL_INODE 482168404Spjd * .zfs 1 483168404Spjd * .zfs/snapshot 2 484168404Spjd * .zfs/snapshot/<snap> objectid(snap) 485168404Spjd */ 486168404Spjd 487168404Spjd#define ZFSCTL_INO_SNAP(id) (id) 488168404Spjd 489168404Spjd/* 490168404Spjd * Get root directory attributes. 491168404Spjd */ 492168404Spjd/* ARGSUSED */ 493168404Spjdstatic int 494168404Spjdzfsctl_root_getattr(ap) 495168404Spjd struct vop_getattr_args /* { 496168404Spjd struct vnode *a_vp; 497168404Spjd struct vattr *a_vap; 498168404Spjd struct ucred *a_cred; 499168404Spjd } */ *ap; 500168404Spjd{ 501168404Spjd struct vnode *vp = ap->a_vp; 502168404Spjd struct vattr *vap = ap->a_vap; 503168404Spjd zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 504219089Spjd zfsctl_node_t *zcp = vp->v_data; 505168404Spjd 506168404Spjd ZFS_ENTER(zfsvfs); 507168404Spjd vap->va_nodeid = ZFSCTL_INO_ROOT; 508168404Spjd vap->va_nlink = vap->va_size = NROOT_ENTRIES; 509219089Spjd vap->va_mtime = vap->va_ctime = zcp->zc_cmtime; 510219089Spjd vap->va_birthtime = vap->va_ctime; 511168404Spjd 512168404Spjd zfsctl_common_getattr(vp, vap); 513168404Spjd ZFS_EXIT(zfsvfs); 514168404Spjd 515168404Spjd return (0); 516168404Spjd} 517168404Spjd 518219089Spjd/* 519219089Spjd * Special case the handling of "..". 520219089Spjd */ 521219089Spjd/* ARGSUSED */ 522219089Spjdint 523219089Spjdzfsctl_root_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp, 524219089Spjd int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct, 525219089Spjd int *direntflags, pathname_t *realpnp) 526219089Spjd{ 527219089Spjd zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 528219089Spjd int err; 529219089Spjd 530219089Spjd /* 531219089Spjd * No extended attributes allowed under .zfs 532219089Spjd */ 533219089Spjd if (flags & LOOKUP_XATTR) 534249643Smm return (SET_ERROR(EINVAL)); 535219089Spjd 536219089Spjd ZFS_ENTER(zfsvfs); 537219089Spjd 538219089Spjd if (strcmp(nm, "..") == 0) { 539219089Spjd err = VFS_ROOT(dvp->v_vfsp, LK_EXCLUSIVE, vpp); 540219089Spjd if (err == 0) 541219089Spjd VOP_UNLOCK(*vpp, 0); 542219089Spjd } else { 543219089Spjd err = gfs_vop_lookup(dvp, nm, vpp, pnp, flags, rdir, 544219089Spjd cr, ct, direntflags, realpnp); 545219089Spjd } 546219089Spjd 547219089Spjd ZFS_EXIT(zfsvfs); 548219089Spjd 549219089Spjd return (err); 550219089Spjd} 551219089Spjd 552209962Smm#ifdef sun 553209962Smmstatic int 554209962Smmzfsctl_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, 555209962Smm caller_context_t *ct) 556209962Smm{ 557209962Smm /* 558209962Smm * We only care about ACL_ENABLED so that libsec can 559209962Smm * display ACL correctly and not default to POSIX draft. 560209962Smm */ 561209962Smm if (cmd == _PC_ACL_ENABLED) { 562209962Smm *valp = _ACL_ACE_ENABLED; 563209962Smm return (0); 564209962Smm } 565209962Smm 566209962Smm return (fs_pathconf(vp, cmd, valp, cr, ct)); 567209962Smm} 568209962Smm#endif /* sun */ 569209962Smm 570209962Smm#ifdef sun 571209962Smmstatic const fs_operation_def_t zfsctl_tops_root[] = { 572209962Smm { VOPNAME_OPEN, { .vop_open = zfsctl_common_open } }, 573209962Smm { VOPNAME_CLOSE, { .vop_close = zfsctl_common_close } }, 574209962Smm { VOPNAME_IOCTL, { .error = fs_inval } }, 575209962Smm { VOPNAME_GETATTR, { .vop_getattr = zfsctl_root_getattr } }, 576209962Smm { VOPNAME_ACCESS, { .vop_access = zfsctl_common_access } }, 577209962Smm { VOPNAME_READDIR, { .vop_readdir = gfs_vop_readdir } }, 578209962Smm { VOPNAME_LOOKUP, { .vop_lookup = zfsctl_root_lookup } }, 579209962Smm { VOPNAME_SEEK, { .vop_seek = fs_seek } }, 580209962Smm { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } }, 581209962Smm { VOPNAME_PATHCONF, { .vop_pathconf = zfsctl_pathconf } }, 582209962Smm { VOPNAME_FID, { .vop_fid = zfsctl_common_fid } }, 583209962Smm { NULL } 584209962Smm}; 585209962Smm#endif /* sun */ 586209962Smm 587168404Spjd/* 588168404Spjd * Special case the handling of "..". 589168404Spjd */ 590168404Spjd/* ARGSUSED */ 591168404Spjdint 592185029Spjdzfsctl_freebsd_root_lookup(ap) 593168404Spjd struct vop_lookup_args /* { 594168404Spjd struct vnode *a_dvp; 595168404Spjd struct vnode **a_vpp; 596168404Spjd struct componentname *a_cnp; 597168404Spjd } */ *ap; 598168404Spjd{ 599168404Spjd vnode_t *dvp = ap->a_dvp; 600168404Spjd vnode_t **vpp = ap->a_vpp; 601168404Spjd cred_t *cr = ap->a_cnp->cn_cred; 602168404Spjd int flags = ap->a_cnp->cn_flags; 603168404Spjd int nameiop = ap->a_cnp->cn_nameiop; 604168404Spjd char nm[NAME_MAX + 1]; 605168404Spjd int err; 606168404Spjd 607168404Spjd if ((flags & ISLASTCN) && (nameiop == RENAME || nameiop == CREATE)) 608168404Spjd return (EOPNOTSUPP); 609168404Spjd 610168404Spjd ASSERT(ap->a_cnp->cn_namelen < sizeof(nm)); 611168404Spjd strlcpy(nm, ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen + 1); 612168404Spjd 613185029Spjd err = zfsctl_root_lookup(dvp, nm, vpp, NULL, 0, NULL, cr, NULL, NULL, NULL); 614168404Spjd if (err == 0 && (nm[0] != '.' || nm[1] != '\0')) 615175202Sattilio vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); 616168404Spjd return (err); 617168404Spjd} 618168404Spjd 619168404Spjdstatic struct vop_vector zfsctl_ops_root = { 620168404Spjd .vop_default = &default_vnodeops, 621168404Spjd .vop_open = zfsctl_common_open, 622168404Spjd .vop_close = zfsctl_common_close, 623168404Spjd .vop_ioctl = VOP_EINVAL, 624168404Spjd .vop_getattr = zfsctl_root_getattr, 625168404Spjd .vop_access = zfsctl_common_access, 626168404Spjd .vop_readdir = gfs_vop_readdir, 627185029Spjd .vop_lookup = zfsctl_freebsd_root_lookup, 628168404Spjd .vop_inactive = gfs_vop_inactive, 629168404Spjd .vop_reclaim = zfsctl_common_reclaim, 630219089Spjd#ifdef TODO 631219089Spjd .vop_pathconf = zfsctl_pathconf, 632219089Spjd#endif 633168404Spjd .vop_fid = zfsctl_common_fid, 634168404Spjd}; 635168404Spjd 636252749Sdelphij/* 637252749Sdelphij * Gets the full dataset name that corresponds to the given snapshot name 638252749Sdelphij * Example: 639252749Sdelphij * zfsctl_snapshot_zname("snap1") -> "mypool/myfs@snap1" 640252749Sdelphij */ 641168404Spjdstatic int 642168404Spjdzfsctl_snapshot_zname(vnode_t *vp, const char *name, int len, char *zname) 643168404Spjd{ 644168404Spjd objset_t *os = ((zfsvfs_t *)((vp)->v_vfsp->vfs_data))->z_os; 645168404Spjd 646263410Sdelphij if (zfs_component_namecheck(name, NULL, NULL) != 0) 647249643Smm return (SET_ERROR(EILSEQ)); 648168404Spjd dmu_objset_name(os, zname); 649168404Spjd if (strlen(zname) + 1 + strlen(name) >= len) 650249643Smm return (SET_ERROR(ENAMETOOLONG)); 651168404Spjd (void) strcat(zname, "@"); 652168404Spjd (void) strcat(zname, name); 653168404Spjd return (0); 654168404Spjd} 655168404Spjd 656168404Spjdstatic int 657185029Spjdzfsctl_unmount_snap(zfs_snapentry_t *sep, int fflags, cred_t *cr) 658168404Spjd{ 659185029Spjd vnode_t *svp = sep->se_root; 660185029Spjd int error; 661168404Spjd 662185029Spjd ASSERT(vn_ismntpt(svp)); 663168404Spjd 664168404Spjd /* this will be dropped by dounmount() */ 665185029Spjd if ((error = vn_vfswlock(svp)) != 0) 666185029Spjd return (error); 667168404Spjd 668219089Spjd#ifdef sun 669219089Spjd VN_HOLD(svp); 670219089Spjd error = dounmount(vn_mountedvfs(svp), fflags, cr); 671219089Spjd if (error) { 672219089Spjd VN_RELE(svp); 673219089Spjd return (error); 674219089Spjd } 675219089Spjd 676219089Spjd /* 677219089Spjd * We can't use VN_RELE(), as that will try to invoke 678219089Spjd * zfsctl_snapdir_inactive(), which would cause us to destroy 679219089Spjd * the sd_lock mutex held by our caller. 680219089Spjd */ 681219089Spjd ASSERT(svp->v_count == 1); 682219089Spjd gfs_vop_inactive(svp, cr, NULL); 683219089Spjd 684219089Spjd kmem_free(sep->se_name, strlen(sep->se_name) + 1); 685219089Spjd kmem_free(sep, sizeof (zfs_snapentry_t)); 686219089Spjd 687219089Spjd return (0); 688219089Spjd#else /* !sun */ 689185029Spjd return (dounmount(vn_mountedvfs(svp), fflags, curthread)); 690219089Spjd#endif /* !sun */ 691168404Spjd} 692168404Spjd 693219089Spjd#ifdef sun 694168404Spjdstatic void 695168404Spjdzfsctl_rename_snap(zfsctl_snapdir_t *sdp, zfs_snapentry_t *sep, const char *nm) 696168404Spjd{ 697168404Spjd avl_index_t where; 698168404Spjd vfs_t *vfsp; 699168404Spjd refstr_t *pathref; 700168404Spjd char newpath[MAXNAMELEN]; 701168404Spjd char *tail; 702168404Spjd 703168404Spjd ASSERT(MUTEX_HELD(&sdp->sd_lock)); 704168404Spjd ASSERT(sep != NULL); 705168404Spjd 706168404Spjd vfsp = vn_mountedvfs(sep->se_root); 707168404Spjd ASSERT(vfsp != NULL); 708168404Spjd 709168404Spjd vfs_lock_wait(vfsp); 710168404Spjd 711168404Spjd /* 712168404Spjd * Change the name in the AVL tree. 713168404Spjd */ 714168404Spjd avl_remove(&sdp->sd_snaps, sep); 715168404Spjd kmem_free(sep->se_name, strlen(sep->se_name) + 1); 716168404Spjd sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP); 717168404Spjd (void) strcpy(sep->se_name, nm); 718168404Spjd VERIFY(avl_find(&sdp->sd_snaps, sep, &where) == NULL); 719168404Spjd avl_insert(&sdp->sd_snaps, sep, where); 720168404Spjd 721168404Spjd /* 722168404Spjd * Change the current mountpoint info: 723168404Spjd * - update the tail of the mntpoint path 724168404Spjd * - update the tail of the resource path 725168404Spjd */ 726168404Spjd pathref = vfs_getmntpoint(vfsp); 727168404Spjd (void) strncpy(newpath, refstr_value(pathref), sizeof (newpath)); 728168404Spjd VERIFY((tail = strrchr(newpath, '/')) != NULL); 729168404Spjd *(tail+1) = '\0'; 730168404Spjd ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath)); 731168404Spjd (void) strcat(newpath, nm); 732168404Spjd refstr_rele(pathref); 733219089Spjd vfs_setmntpoint(vfsp, newpath, 0); 734168404Spjd 735168404Spjd pathref = vfs_getresource(vfsp); 736168404Spjd (void) strncpy(newpath, refstr_value(pathref), sizeof (newpath)); 737168404Spjd VERIFY((tail = strrchr(newpath, '@')) != NULL); 738168404Spjd *(tail+1) = '\0'; 739168404Spjd ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath)); 740168404Spjd (void) strcat(newpath, nm); 741168404Spjd refstr_rele(pathref); 742219089Spjd vfs_setresource(vfsp, newpath, 0); 743168404Spjd 744168404Spjd vfs_unlock(vfsp); 745168404Spjd} 746219089Spjd#endif /* sun */ 747168404Spjd 748219089Spjd#ifdef sun 749185029Spjd/*ARGSUSED*/ 750168404Spjdstatic int 751168404Spjdzfsctl_snapdir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, 752185029Spjd cred_t *cr, caller_context_t *ct, int flags) 753168404Spjd{ 754168404Spjd zfsctl_snapdir_t *sdp = sdvp->v_data; 755168404Spjd zfs_snapentry_t search, *sep; 756185029Spjd zfsvfs_t *zfsvfs; 757168404Spjd avl_index_t where; 758168404Spjd char from[MAXNAMELEN], to[MAXNAMELEN]; 759249643Smm char real[MAXNAMELEN], fsname[MAXNAMELEN]; 760168404Spjd int err; 761168404Spjd 762185029Spjd zfsvfs = sdvp->v_vfsp->vfs_data; 763185029Spjd ZFS_ENTER(zfsvfs); 764185029Spjd 765185029Spjd if ((flags & FIGNORECASE) || zfsvfs->z_case == ZFS_CASE_INSENSITIVE) { 766185029Spjd err = dmu_snapshot_realname(zfsvfs->z_os, snm, real, 767185029Spjd MAXNAMELEN, NULL); 768185029Spjd if (err == 0) { 769185029Spjd snm = real; 770185029Spjd } else if (err != ENOTSUP) { 771185029Spjd ZFS_EXIT(zfsvfs); 772185029Spjd return (err); 773185029Spjd } 774185029Spjd } 775185029Spjd 776185029Spjd ZFS_EXIT(zfsvfs); 777185029Spjd 778249643Smm dmu_objset_name(zfsvfs->z_os, fsname); 779249643Smm 780168404Spjd err = zfsctl_snapshot_zname(sdvp, snm, MAXNAMELEN, from); 781249643Smm if (err == 0) 782185029Spjd err = zfsctl_snapshot_zname(tdvp, tnm, MAXNAMELEN, to); 783249643Smm if (err == 0) 784185029Spjd err = zfs_secpolicy_rename_perms(from, to, cr); 785249643Smm if (err != 0) 786168404Spjd return (err); 787168404Spjd 788168404Spjd /* 789168404Spjd * Cannot move snapshots out of the snapdir. 790168404Spjd */ 791168404Spjd if (sdvp != tdvp) 792249643Smm return (SET_ERROR(EINVAL)); 793168404Spjd 794168404Spjd if (strcmp(snm, tnm) == 0) 795168404Spjd return (0); 796168404Spjd 797168404Spjd mutex_enter(&sdp->sd_lock); 798168404Spjd 799168404Spjd search.se_name = (char *)snm; 800168404Spjd if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) == NULL) { 801168404Spjd mutex_exit(&sdp->sd_lock); 802249643Smm return (SET_ERROR(ENOENT)); 803168404Spjd } 804168404Spjd 805249643Smm err = dsl_dataset_rename_snapshot(fsname, snm, tnm, 0); 806168404Spjd if (err == 0) 807168404Spjd zfsctl_rename_snap(sdp, sep, tnm); 808168404Spjd 809168404Spjd mutex_exit(&sdp->sd_lock); 810168404Spjd 811168404Spjd return (err); 812168404Spjd} 813219089Spjd#endif /* sun */ 814168404Spjd 815219089Spjd#ifdef sun 816168404Spjd/* ARGSUSED */ 817168404Spjdstatic int 818185029Spjdzfsctl_snapdir_remove(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr, 819185029Spjd caller_context_t *ct, int flags) 820168404Spjd{ 821169170Spjd zfsctl_snapdir_t *sdp = dvp->v_data; 822185029Spjd zfs_snapentry_t *sep; 823185029Spjd zfs_snapentry_t search; 824185029Spjd zfsvfs_t *zfsvfs; 825169170Spjd char snapname[MAXNAMELEN]; 826185029Spjd char real[MAXNAMELEN]; 827169170Spjd int err; 828168404Spjd 829185029Spjd zfsvfs = dvp->v_vfsp->vfs_data; 830185029Spjd ZFS_ENTER(zfsvfs); 831185029Spjd 832185029Spjd if ((flags & FIGNORECASE) || zfsvfs->z_case == ZFS_CASE_INSENSITIVE) { 833185029Spjd 834185029Spjd err = dmu_snapshot_realname(zfsvfs->z_os, name, real, 835185029Spjd MAXNAMELEN, NULL); 836185029Spjd if (err == 0) { 837185029Spjd name = real; 838185029Spjd } else if (err != ENOTSUP) { 839185029Spjd ZFS_EXIT(zfsvfs); 840185029Spjd return (err); 841185029Spjd } 842185029Spjd } 843185029Spjd 844185029Spjd ZFS_EXIT(zfsvfs); 845185029Spjd 846169170Spjd err = zfsctl_snapshot_zname(dvp, name, MAXNAMELEN, snapname); 847249643Smm if (err == 0) 848185029Spjd err = zfs_secpolicy_destroy_perms(snapname, cr); 849249643Smm if (err != 0) 850169170Spjd return (err); 851168404Spjd 852169170Spjd mutex_enter(&sdp->sd_lock); 853168404Spjd 854185029Spjd search.se_name = name; 855185029Spjd sep = avl_find(&sdp->sd_snaps, &search, NULL); 856185029Spjd if (sep) { 857185029Spjd avl_remove(&sdp->sd_snaps, sep); 858185029Spjd err = zfsctl_unmount_snap(sep, MS_FORCE, cr); 859249643Smm if (err != 0) 860249643Smm avl_add(&sdp->sd_snaps, sep); 861249643Smm else 862249643Smm err = dsl_destroy_snapshot(snapname, B_FALSE); 863185029Spjd } else { 864249643Smm err = SET_ERROR(ENOENT); 865169170Spjd } 866168404Spjd 867169170Spjd mutex_exit(&sdp->sd_lock); 868168404Spjd 869169170Spjd return (err); 870168404Spjd} 871219089Spjd#endif /* sun */ 872168404Spjd 873168404Spjd/* 874185029Spjd * This creates a snapshot under '.zfs/snapshot'. 875185029Spjd */ 876185029Spjd/* ARGSUSED */ 877185029Spjdstatic int 878185029Spjdzfsctl_snapdir_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, 879185029Spjd cred_t *cr, caller_context_t *cc, int flags, vsecattr_t *vsecp) 880185029Spjd{ 881185029Spjd zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 882185029Spjd char name[MAXNAMELEN]; 883185029Spjd int err; 884185029Spjd static enum symfollow follow = NO_FOLLOW; 885185029Spjd static enum uio_seg seg = UIO_SYSSPACE; 886185029Spjd 887263410Sdelphij if (zfs_component_namecheck(dirname, NULL, NULL) != 0) 888249643Smm return (SET_ERROR(EILSEQ)); 889185029Spjd 890185029Spjd dmu_objset_name(zfsvfs->z_os, name); 891185029Spjd 892185029Spjd *vpp = NULL; 893185029Spjd 894185029Spjd err = zfs_secpolicy_snapshot_perms(name, cr); 895249643Smm if (err != 0) 896185029Spjd return (err); 897185029Spjd 898185029Spjd if (err == 0) { 899249643Smm err = dmu_objset_snapshot_one(name, dirname); 900249643Smm if (err != 0) 901185029Spjd return (err); 902185029Spjd err = lookupnameat(dirname, seg, follow, NULL, vpp, dvp); 903185029Spjd } 904185029Spjd 905185029Spjd return (err); 906185029Spjd} 907185029Spjd 908185029Spjdstatic int 909185029Spjdzfsctl_freebsd_snapdir_mkdir(ap) 910185029Spjd struct vop_mkdir_args /* { 911185029Spjd struct vnode *a_dvp; 912185029Spjd struct vnode **a_vpp; 913185029Spjd struct componentname *a_cnp; 914185029Spjd struct vattr *a_vap; 915185029Spjd } */ *ap; 916185029Spjd{ 917185029Spjd 918185029Spjd ASSERT(ap->a_cnp->cn_flags & SAVENAME); 919185029Spjd 920185029Spjd return (zfsctl_snapdir_mkdir(ap->a_dvp, ap->a_cnp->cn_nameptr, NULL, 921185029Spjd ap->a_vpp, ap->a_cnp->cn_cred, NULL, 0, NULL)); 922185029Spjd} 923185029Spjd 924185029Spjd/* 925168404Spjd * Lookup entry point for the 'snapshot' directory. Try to open the 926168404Spjd * snapshot if it exist, creating the pseudo filesystem vnode as necessary. 927168404Spjd * Perform a mount of the associated dataset on top of the vnode. 928168404Spjd */ 929168404Spjd/* ARGSUSED */ 930168404Spjdint 931168404Spjdzfsctl_snapdir_lookup(ap) 932168404Spjd struct vop_lookup_args /* { 933168404Spjd struct vnode *a_dvp; 934168404Spjd struct vnode **a_vpp; 935168404Spjd struct componentname *a_cnp; 936168404Spjd } */ *ap; 937168404Spjd{ 938168404Spjd vnode_t *dvp = ap->a_dvp; 939168404Spjd vnode_t **vpp = ap->a_vpp; 940185029Spjd struct componentname *cnp = ap->a_cnp; 941168404Spjd char nm[NAME_MAX + 1]; 942168404Spjd zfsctl_snapdir_t *sdp = dvp->v_data; 943168404Spjd objset_t *snap; 944168404Spjd char snapname[MAXNAMELEN]; 945185029Spjd char real[MAXNAMELEN]; 946168404Spjd char *mountpoint; 947168404Spjd zfs_snapentry_t *sep, search; 948168404Spjd size_t mountpoint_len; 949168404Spjd avl_index_t where; 950168404Spjd zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 951168404Spjd int err; 952185029Spjd int flags = 0; 953168404Spjd 954185029Spjd /* 955185029Spjd * No extended attributes allowed under .zfs 956185029Spjd */ 957185029Spjd if (flags & LOOKUP_XATTR) 958249643Smm return (SET_ERROR(EINVAL)); 959168404Spjd ASSERT(ap->a_cnp->cn_namelen < sizeof(nm)); 960168404Spjd strlcpy(nm, ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen + 1); 961168404Spjd 962168404Spjd ASSERT(dvp->v_type == VDIR); 963168404Spjd 964168404Spjd *vpp = NULL; 965168404Spjd 966168404Spjd /* 967168404Spjd * If we get a recursive call, that means we got called 968168404Spjd * from the domount() code while it was trying to look up the 969168404Spjd * spec (which looks like a local path for zfs). We need to 970168404Spjd * add some flag to domount() to tell it not to do this lookup. 971168404Spjd */ 972168404Spjd if (MUTEX_HELD(&sdp->sd_lock)) 973249643Smm return (SET_ERROR(ENOENT)); 974168404Spjd 975168404Spjd ZFS_ENTER(zfsvfs); 976168404Spjd 977209962Smm if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0) { 978209962Smm ZFS_EXIT(zfsvfs); 979209962Smm return (0); 980209962Smm } 981209962Smm 982185029Spjd if (flags & FIGNORECASE) { 983185029Spjd boolean_t conflict = B_FALSE; 984185029Spjd 985185029Spjd err = dmu_snapshot_realname(zfsvfs->z_os, nm, real, 986185029Spjd MAXNAMELEN, &conflict); 987185029Spjd if (err == 0) { 988185029Spjd strlcpy(nm, real, sizeof(nm)); 989185029Spjd } else if (err != ENOTSUP) { 990185029Spjd ZFS_EXIT(zfsvfs); 991185029Spjd return (err); 992185029Spjd } 993185029Spjd#if 0 994185029Spjd if (realpnp) 995185029Spjd (void) strlcpy(realpnp->pn_buf, nm, 996185029Spjd realpnp->pn_bufsize); 997185029Spjd if (conflict && direntflags) 998185029Spjd *direntflags = ED_CASE_CONFLICT; 999185029Spjd#endif 1000185029Spjd } 1001185029Spjd 1002168404Spjd mutex_enter(&sdp->sd_lock); 1003168404Spjd search.se_name = (char *)nm; 1004168404Spjd if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) != NULL) { 1005168404Spjd *vpp = sep->se_root; 1006168404Spjd VN_HOLD(*vpp); 1007197513Spjd err = traverse(vpp, LK_EXCLUSIVE | LK_RETRY); 1008249643Smm if (err != 0) { 1009197513Spjd VN_RELE(*vpp); 1010197513Spjd *vpp = NULL; 1011197513Spjd } else if (*vpp == sep->se_root) { 1012168404Spjd /* 1013168404Spjd * The snapshot was unmounted behind our backs, 1014168404Spjd * try to remount it. 1015168404Spjd */ 1016243495Savg VERIFY(zfsctl_snapshot_zname(dvp, nm, MAXNAMELEN, snapname) == 0); 1017168404Spjd goto domount; 1018185029Spjd } else { 1019185029Spjd /* 1020185029Spjd * VROOT was set during the traverse call. We need 1021185029Spjd * to clear it since we're pretending to be part 1022185029Spjd * of our parent's vfs. 1023185029Spjd */ 1024185029Spjd (*vpp)->v_flag &= ~VROOT; 1025168404Spjd } 1026168404Spjd mutex_exit(&sdp->sd_lock); 1027168404Spjd ZFS_EXIT(zfsvfs); 1028197513Spjd return (err); 1029168404Spjd } 1030168404Spjd 1031168404Spjd /* 1032168404Spjd * The requested snapshot is not currently mounted, look it up. 1033168404Spjd */ 1034168404Spjd err = zfsctl_snapshot_zname(dvp, nm, MAXNAMELEN, snapname); 1035249643Smm if (err != 0) { 1036168404Spjd mutex_exit(&sdp->sd_lock); 1037168404Spjd ZFS_EXIT(zfsvfs); 1038185029Spjd /* 1039185029Spjd * handle "ls *" or "?" in a graceful manner, 1040185029Spjd * forcing EILSEQ to ENOENT. 1041185029Spjd * Since shell ultimately passes "*" or "?" as name to lookup 1042185029Spjd */ 1043185029Spjd return (err == EILSEQ ? ENOENT : err); 1044168404Spjd } 1045219089Spjd if (dmu_objset_hold(snapname, FTAG, &snap) != 0) { 1046168404Spjd mutex_exit(&sdp->sd_lock); 1047249643Smm#ifdef illumos 1048249643Smm ZFS_EXIT(zfsvfs); 1049249643Smm return (SET_ERROR(ENOENT)); 1050249643Smm#else /* !illumos */ 1051185029Spjd /* Translate errors and add SAVENAME when needed. */ 1052185029Spjd if ((cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == CREATE) { 1053185029Spjd err = EJUSTRETURN; 1054185029Spjd cnp->cn_flags |= SAVENAME; 1055185029Spjd } else { 1056249643Smm err = SET_ERROR(ENOENT); 1057185029Spjd } 1058168404Spjd ZFS_EXIT(zfsvfs); 1059185029Spjd return (err); 1060249643Smm#endif /* !illumos */ 1061168404Spjd } 1062168404Spjd 1063168404Spjd sep = kmem_alloc(sizeof (zfs_snapentry_t), KM_SLEEP); 1064168404Spjd sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP); 1065168404Spjd (void) strcpy(sep->se_name, nm); 1066168404Spjd *vpp = sep->se_root = zfsctl_snapshot_mknode(dvp, dmu_objset_id(snap)); 1067168404Spjd VN_HOLD(*vpp); 1068168404Spjd avl_insert(&sdp->sd_snaps, sep, where); 1069168404Spjd 1070219089Spjd dmu_objset_rele(snap, FTAG); 1071168404Spjddomount: 1072168404Spjd mountpoint_len = strlen(dvp->v_vfsp->mnt_stat.f_mntonname) + 1073211900Spjd strlen("/" ZFS_CTLDIR_NAME "/snapshot/") + strlen(nm) + 1; 1074168404Spjd mountpoint = kmem_alloc(mountpoint_len, KM_SLEEP); 1075211900Spjd (void) snprintf(mountpoint, mountpoint_len, 1076211900Spjd "%s/" ZFS_CTLDIR_NAME "/snapshot/%s", 1077168404Spjd dvp->v_vfsp->mnt_stat.f_mntonname, nm); 1078197201Spjd err = mount_snapshot(curthread, vpp, "zfs", mountpoint, snapname, 0); 1079168404Spjd kmem_free(mountpoint, mountpoint_len); 1080196980Spjd if (err == 0) { 1081196980Spjd /* 1082196980Spjd * Fix up the root vnode mounted on .zfs/snapshot/<snapname>. 1083196980Spjd * 1084196980Spjd * This is where we lie about our v_vfsp in order to 1085196980Spjd * make .zfs/snapshot/<snapname> accessible over NFS 1086196980Spjd * without requiring manual mounts of <snapname>. 1087196980Spjd */ 1088196980Spjd ASSERT(VTOZ(*vpp)->z_zfsvfs != zfsvfs); 1089196980Spjd VTOZ(*vpp)->z_zfsvfs->z_parent = zfsvfs; 1090196980Spjd } 1091168404Spjd mutex_exit(&sdp->sd_lock); 1092183037Spjd ZFS_EXIT(zfsvfs); 1093249643Smm 1094249643Smm#ifdef illumos 1095249643Smm /* 1096249643Smm * If we had an error, drop our hold on the vnode and 1097249643Smm * zfsctl_snapshot_inactive() will clean up. 1098249643Smm */ 1099249643Smm if (err != 0) { 1100249643Smm VN_RELE(*vpp); 1101249643Smm *vpp = NULL; 1102249643Smm } 1103249643Smm#else 1104197514Spjd if (err != 0) 1105197514Spjd *vpp = NULL; 1106249643Smm#endif 1107168404Spjd return (err); 1108168404Spjd} 1109168404Spjd 1110168404Spjd/* ARGSUSED */ 1111209962Smmint 1112209962Smmzfsctl_shares_lookup(ap) 1113209962Smm struct vop_lookup_args /* { 1114209962Smm struct vnode *a_dvp; 1115209962Smm struct vnode **a_vpp; 1116209962Smm struct componentname *a_cnp; 1117209962Smm } */ *ap; 1118209962Smm{ 1119209962Smm vnode_t *dvp = ap->a_dvp; 1120209962Smm vnode_t **vpp = ap->a_vpp; 1121209962Smm struct componentname *cnp = ap->a_cnp; 1122209962Smm zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 1123209962Smm char nm[NAME_MAX + 1]; 1124209962Smm znode_t *dzp; 1125209962Smm int error; 1126209962Smm 1127209962Smm ZFS_ENTER(zfsvfs); 1128209962Smm 1129209962Smm ASSERT(cnp->cn_namelen < sizeof(nm)); 1130209962Smm strlcpy(nm, cnp->cn_nameptr, cnp->cn_namelen + 1); 1131209962Smm 1132209962Smm if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0) { 1133209962Smm ZFS_EXIT(zfsvfs); 1134209962Smm return (0); 1135209962Smm } 1136209962Smm 1137209962Smm if (zfsvfs->z_shares_dir == 0) { 1138209962Smm ZFS_EXIT(zfsvfs); 1139249643Smm return (SET_ERROR(ENOTSUP)); 1140209962Smm } 1141209962Smm if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) 1142209962Smm error = VOP_LOOKUP(ZTOV(dzp), vpp, cnp); 1143209962Smm 1144209962Smm VN_RELE(ZTOV(dzp)); 1145209962Smm ZFS_EXIT(zfsvfs); 1146209962Smm 1147209962Smm return (error); 1148209962Smm} 1149209962Smm 1150209962Smm/* ARGSUSED */ 1151168404Spjdstatic int 1152185029Spjdzfsctl_snapdir_readdir_cb(vnode_t *vp, void *dp, int *eofp, 1153185029Spjd offset_t *offp, offset_t *nextp, void *data, int flags) 1154168404Spjd{ 1155168404Spjd zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 1156168404Spjd char snapname[MAXNAMELEN]; 1157168404Spjd uint64_t id, cookie; 1158185029Spjd boolean_t case_conflict; 1159185029Spjd int error; 1160168404Spjd 1161168404Spjd ZFS_ENTER(zfsvfs); 1162168404Spjd 1163168404Spjd cookie = *offp; 1164249643Smm dsl_pool_config_enter(dmu_objset_pool(zfsvfs->z_os), FTAG); 1165185029Spjd error = dmu_snapshot_list_next(zfsvfs->z_os, MAXNAMELEN, snapname, &id, 1166185029Spjd &cookie, &case_conflict); 1167249643Smm dsl_pool_config_exit(dmu_objset_pool(zfsvfs->z_os), FTAG); 1168185029Spjd if (error) { 1169168404Spjd ZFS_EXIT(zfsvfs); 1170185029Spjd if (error == ENOENT) { 1171185029Spjd *eofp = 1; 1172185029Spjd return (0); 1173185029Spjd } 1174185029Spjd return (error); 1175168404Spjd } 1176168404Spjd 1177185029Spjd if (flags & V_RDDIR_ENTFLAGS) { 1178185029Spjd edirent_t *eodp = dp; 1179185029Spjd 1180185029Spjd (void) strcpy(eodp->ed_name, snapname); 1181185029Spjd eodp->ed_ino = ZFSCTL_INO_SNAP(id); 1182185029Spjd eodp->ed_eflags = case_conflict ? ED_CASE_CONFLICT : 0; 1183185029Spjd } else { 1184185029Spjd struct dirent64 *odp = dp; 1185185029Spjd 1186185029Spjd (void) strcpy(odp->d_name, snapname); 1187185029Spjd odp->d_ino = ZFSCTL_INO_SNAP(id); 1188185029Spjd } 1189168404Spjd *nextp = cookie; 1190168404Spjd 1191168404Spjd ZFS_EXIT(zfsvfs); 1192168404Spjd 1193168404Spjd return (0); 1194168404Spjd} 1195168404Spjd 1196209962Smm/* ARGSUSED */ 1197209962Smmstatic int 1198209962Smmzfsctl_shares_readdir(ap) 1199209962Smm struct vop_readdir_args /* { 1200209962Smm struct vnode *a_vp; 1201209962Smm struct uio *a_uio; 1202209962Smm struct ucred *a_cred; 1203209962Smm int *a_eofflag; 1204209962Smm int *a_ncookies; 1205209962Smm u_long **a_cookies; 1206209962Smm } */ *ap; 1207209962Smm{ 1208209962Smm vnode_t *vp = ap->a_vp; 1209209962Smm uio_t *uiop = ap->a_uio; 1210209962Smm cred_t *cr = ap->a_cred; 1211209962Smm int *eofp = ap->a_eofflag; 1212209962Smm zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 1213209962Smm znode_t *dzp; 1214209962Smm int error; 1215209962Smm 1216209962Smm ZFS_ENTER(zfsvfs); 1217209962Smm 1218209962Smm if (zfsvfs->z_shares_dir == 0) { 1219209962Smm ZFS_EXIT(zfsvfs); 1220249643Smm return (SET_ERROR(ENOTSUP)); 1221209962Smm } 1222209962Smm if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) { 1223212605Smm vn_lock(ZTOV(dzp), LK_SHARED | LK_RETRY); 1224209962Smm error = VOP_READDIR(ZTOV(dzp), uiop, cr, eofp, ap->a_ncookies, ap->a_cookies); 1225212605Smm VN_URELE(ZTOV(dzp)); 1226209962Smm } else { 1227209962Smm *eofp = 1; 1228249643Smm error = SET_ERROR(ENOENT); 1229209962Smm } 1230209962Smm 1231209962Smm ZFS_EXIT(zfsvfs); 1232209962Smm return (error); 1233209962Smm} 1234209962Smm 1235185029Spjd/* 1236185029Spjd * pvp is the '.zfs' directory (zfsctl_node_t). 1237252751Sdelphij * 1238185029Spjd * Creates vp, which is '.zfs/snapshot' (zfsctl_snapdir_t). 1239185029Spjd * 1240185029Spjd * This function is the callback to create a GFS vnode for '.zfs/snapshot' 1241185029Spjd * when a lookup is performed on .zfs for "snapshot". 1242185029Spjd */ 1243168404Spjdvnode_t * 1244168404Spjdzfsctl_mknode_snapdir(vnode_t *pvp) 1245168404Spjd{ 1246168404Spjd vnode_t *vp; 1247168404Spjd zfsctl_snapdir_t *sdp; 1248168404Spjd 1249168404Spjd vp = gfs_dir_create(sizeof (zfsctl_snapdir_t), pvp, pvp->v_vfsp, 1250168404Spjd &zfsctl_ops_snapdir, NULL, NULL, MAXNAMELEN, 1251168404Spjd zfsctl_snapdir_readdir_cb, NULL); 1252168404Spjd sdp = vp->v_data; 1253168404Spjd sdp->sd_node.zc_id = ZFSCTL_INO_SNAPDIR; 1254168404Spjd sdp->sd_node.zc_cmtime = ((zfsctl_node_t *)pvp->v_data)->zc_cmtime; 1255168404Spjd mutex_init(&sdp->sd_lock, NULL, MUTEX_DEFAULT, NULL); 1256168404Spjd avl_create(&sdp->sd_snaps, snapentry_compare, 1257168404Spjd sizeof (zfs_snapentry_t), offsetof(zfs_snapentry_t, se_node)); 1258182781Spjd VOP_UNLOCK(vp, 0); 1259168404Spjd return (vp); 1260168404Spjd} 1261168404Spjd 1262209962Smmvnode_t * 1263209962Smmzfsctl_mknode_shares(vnode_t *pvp) 1264209962Smm{ 1265209962Smm vnode_t *vp; 1266209962Smm zfsctl_node_t *sdp; 1267209962Smm 1268209962Smm vp = gfs_dir_create(sizeof (zfsctl_node_t), pvp, pvp->v_vfsp, 1269209962Smm &zfsctl_ops_shares, NULL, NULL, MAXNAMELEN, 1270209962Smm NULL, NULL); 1271209962Smm sdp = vp->v_data; 1272209962Smm sdp->zc_cmtime = ((zfsctl_node_t *)pvp->v_data)->zc_cmtime; 1273212605Smm VOP_UNLOCK(vp, 0); 1274209962Smm return (vp); 1275209962Smm 1276209962Smm} 1277209962Smm 1278168404Spjd/* ARGSUSED */ 1279168404Spjdstatic int 1280209962Smmzfsctl_shares_getattr(ap) 1281209962Smm struct vop_getattr_args /* { 1282209962Smm struct vnode *a_vp; 1283209962Smm struct vattr *a_vap; 1284209962Smm struct ucred *a_cred; 1285209962Smm struct thread *a_td; 1286209962Smm } */ *ap; 1287209962Smm{ 1288209962Smm vnode_t *vp = ap->a_vp; 1289209962Smm vattr_t *vap = ap->a_vap; 1290209962Smm cred_t *cr = ap->a_cred; 1291209962Smm zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 1292209962Smm znode_t *dzp; 1293209962Smm int error; 1294209962Smm 1295209962Smm ZFS_ENTER(zfsvfs); 1296209962Smm if (zfsvfs->z_shares_dir == 0) { 1297209962Smm ZFS_EXIT(zfsvfs); 1298249643Smm return (SET_ERROR(ENOTSUP)); 1299209962Smm } 1300209962Smm if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) { 1301212605Smm vn_lock(ZTOV(dzp), LK_SHARED | LK_RETRY); 1302209962Smm error = VOP_GETATTR(ZTOV(dzp), vap, cr); 1303212605Smm VN_URELE(ZTOV(dzp)); 1304209962Smm } 1305209962Smm ZFS_EXIT(zfsvfs); 1306209962Smm return (error); 1307219089Spjd 1308219089Spjd 1309209962Smm} 1310209962Smm 1311209962Smm/* ARGSUSED */ 1312209962Smmstatic int 1313168404Spjdzfsctl_snapdir_getattr(ap) 1314168404Spjd struct vop_getattr_args /* { 1315168404Spjd struct vnode *a_vp; 1316168404Spjd struct vattr *a_vap; 1317168404Spjd struct ucred *a_cred; 1318168404Spjd } */ *ap; 1319168404Spjd{ 1320219089Spjd vnode_t *vp = ap->a_vp; 1321219089Spjd vattr_t *vap = ap->a_vap; 1322168404Spjd zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 1323168404Spjd zfsctl_snapdir_t *sdp = vp->v_data; 1324168404Spjd 1325168404Spjd ZFS_ENTER(zfsvfs); 1326168404Spjd zfsctl_common_getattr(vp, vap); 1327168404Spjd vap->va_nodeid = gfs_file_inode(vp); 1328168404Spjd vap->va_nlink = vap->va_size = avl_numnodes(&sdp->sd_snaps) + 2; 1329219089Spjd vap->va_ctime = vap->va_mtime = dmu_objset_snap_cmtime(zfsvfs->z_os); 1330219089Spjd vap->va_birthtime = vap->va_ctime; 1331168404Spjd ZFS_EXIT(zfsvfs); 1332168404Spjd 1333168404Spjd return (0); 1334168404Spjd} 1335168404Spjd 1336168404Spjd/* ARGSUSED */ 1337168404Spjdstatic int 1338168404Spjdzfsctl_snapdir_inactive(ap) 1339168404Spjd struct vop_inactive_args /* { 1340168404Spjd struct vnode *a_vp; 1341168404Spjd struct thread *a_td; 1342168404Spjd } */ *ap; 1343168404Spjd{ 1344168404Spjd vnode_t *vp = ap->a_vp; 1345168404Spjd zfsctl_snapdir_t *sdp = vp->v_data; 1346197515Spjd zfs_snapentry_t *sep; 1347168404Spjd 1348197515Spjd /* 1349197515Spjd * On forced unmount we have to free snapshots from here. 1350197515Spjd */ 1351197515Spjd mutex_enter(&sdp->sd_lock); 1352197515Spjd while ((sep = avl_first(&sdp->sd_snaps)) != NULL) { 1353197515Spjd avl_remove(&sdp->sd_snaps, sep); 1354197515Spjd kmem_free(sep->se_name, strlen(sep->se_name) + 1); 1355197515Spjd kmem_free(sep, sizeof (zfs_snapentry_t)); 1356168404Spjd } 1357197515Spjd mutex_exit(&sdp->sd_lock); 1358197515Spjd gfs_dir_inactive(vp); 1359197515Spjd ASSERT(avl_numnodes(&sdp->sd_snaps) == 0); 1360197515Spjd mutex_destroy(&sdp->sd_lock); 1361197515Spjd avl_destroy(&sdp->sd_snaps); 1362197515Spjd kmem_free(sdp, sizeof (zfsctl_snapdir_t)); 1363197515Spjd 1364168404Spjd return (0); 1365168404Spjd} 1366168404Spjd 1367219089Spjd#ifdef sun 1368219089Spjdstatic const fs_operation_def_t zfsctl_tops_snapdir[] = { 1369219089Spjd { VOPNAME_OPEN, { .vop_open = zfsctl_common_open } }, 1370219089Spjd { VOPNAME_CLOSE, { .vop_close = zfsctl_common_close } }, 1371219089Spjd { VOPNAME_IOCTL, { .error = fs_inval } }, 1372219089Spjd { VOPNAME_GETATTR, { .vop_getattr = zfsctl_snapdir_getattr } }, 1373219089Spjd { VOPNAME_ACCESS, { .vop_access = zfsctl_common_access } }, 1374219089Spjd { VOPNAME_RENAME, { .vop_rename = zfsctl_snapdir_rename } }, 1375219089Spjd { VOPNAME_RMDIR, { .vop_rmdir = zfsctl_snapdir_remove } }, 1376219089Spjd { VOPNAME_MKDIR, { .vop_mkdir = zfsctl_snapdir_mkdir } }, 1377219089Spjd { VOPNAME_READDIR, { .vop_readdir = gfs_vop_readdir } }, 1378219089Spjd { VOPNAME_LOOKUP, { .vop_lookup = zfsctl_snapdir_lookup } }, 1379219089Spjd { VOPNAME_SEEK, { .vop_seek = fs_seek } }, 1380219089Spjd { VOPNAME_INACTIVE, { .vop_inactive = zfsctl_snapdir_inactive } }, 1381219089Spjd { VOPNAME_FID, { .vop_fid = zfsctl_common_fid } }, 1382219089Spjd { NULL } 1383219089Spjd}; 1384219089Spjd 1385219089Spjdstatic const fs_operation_def_t zfsctl_tops_shares[] = { 1386219089Spjd { VOPNAME_OPEN, { .vop_open = zfsctl_common_open } }, 1387219089Spjd { VOPNAME_CLOSE, { .vop_close = zfsctl_common_close } }, 1388219089Spjd { VOPNAME_IOCTL, { .error = fs_inval } }, 1389219089Spjd { VOPNAME_GETATTR, { .vop_getattr = zfsctl_shares_getattr } }, 1390219089Spjd { VOPNAME_ACCESS, { .vop_access = zfsctl_common_access } }, 1391219089Spjd { VOPNAME_READDIR, { .vop_readdir = zfsctl_shares_readdir } }, 1392219089Spjd { VOPNAME_LOOKUP, { .vop_lookup = zfsctl_shares_lookup } }, 1393219089Spjd { VOPNAME_SEEK, { .vop_seek = fs_seek } }, 1394219089Spjd { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } }, 1395219089Spjd { VOPNAME_FID, { .vop_fid = zfsctl_shares_fid } }, 1396219089Spjd { NULL } 1397219089Spjd}; 1398219089Spjd#else /* !sun */ 1399168404Spjdstatic struct vop_vector zfsctl_ops_snapdir = { 1400168404Spjd .vop_default = &default_vnodeops, 1401168404Spjd .vop_open = zfsctl_common_open, 1402168404Spjd .vop_close = zfsctl_common_close, 1403168404Spjd .vop_ioctl = VOP_EINVAL, 1404168404Spjd .vop_getattr = zfsctl_snapdir_getattr, 1405168404Spjd .vop_access = zfsctl_common_access, 1406185029Spjd .vop_mkdir = zfsctl_freebsd_snapdir_mkdir, 1407168404Spjd .vop_readdir = gfs_vop_readdir, 1408168404Spjd .vop_lookup = zfsctl_snapdir_lookup, 1409168404Spjd .vop_inactive = zfsctl_snapdir_inactive, 1410168404Spjd .vop_reclaim = zfsctl_common_reclaim, 1411168404Spjd .vop_fid = zfsctl_common_fid, 1412168404Spjd}; 1413168404Spjd 1414212605Smmstatic struct vop_vector zfsctl_ops_shares = { 1415212605Smm .vop_default = &default_vnodeops, 1416212605Smm .vop_open = zfsctl_common_open, 1417212605Smm .vop_close = zfsctl_common_close, 1418212605Smm .vop_ioctl = VOP_EINVAL, 1419212605Smm .vop_getattr = zfsctl_shares_getattr, 1420212605Smm .vop_access = zfsctl_common_access, 1421212605Smm .vop_readdir = zfsctl_shares_readdir, 1422212605Smm .vop_lookup = zfsctl_shares_lookup, 1423212605Smm .vop_inactive = gfs_vop_inactive, 1424212605Smm .vop_reclaim = zfsctl_common_reclaim, 1425212605Smm .vop_fid = zfsctl_shares_fid, 1426212605Smm}; 1427219089Spjd#endif /* !sun */ 1428212605Smm 1429185029Spjd/* 1430185029Spjd * pvp is the GFS vnode '.zfs/snapshot'. 1431185029Spjd * 1432185029Spjd * This creates a GFS node under '.zfs/snapshot' representing each 1433185029Spjd * snapshot. This newly created GFS node is what we mount snapshot 1434185029Spjd * vfs_t's ontop of. 1435185029Spjd */ 1436168404Spjdstatic vnode_t * 1437168404Spjdzfsctl_snapshot_mknode(vnode_t *pvp, uint64_t objset) 1438168404Spjd{ 1439168404Spjd vnode_t *vp; 1440168404Spjd zfsctl_node_t *zcp; 1441168404Spjd 1442168404Spjd vp = gfs_dir_create(sizeof (zfsctl_node_t), pvp, pvp->v_vfsp, 1443168404Spjd &zfsctl_ops_snapshot, NULL, NULL, MAXNAMELEN, NULL, NULL); 1444185029Spjd VN_HOLD(vp); 1445168404Spjd zcp = vp->v_data; 1446168404Spjd zcp->zc_id = objset; 1447182781Spjd VOP_UNLOCK(vp, 0); 1448168404Spjd 1449168404Spjd return (vp); 1450168404Spjd} 1451168404Spjd 1452168404Spjdstatic int 1453168404Spjdzfsctl_snapshot_inactive(ap) 1454168404Spjd struct vop_inactive_args /* { 1455168404Spjd struct vnode *a_vp; 1456168404Spjd struct thread *a_td; 1457168404Spjd } */ *ap; 1458168404Spjd{ 1459168404Spjd vnode_t *vp = ap->a_vp; 1460185029Spjd cred_t *cr = ap->a_td->td_ucred; 1461168404Spjd struct vop_inactive_args iap; 1462168404Spjd zfsctl_snapdir_t *sdp; 1463168404Spjd zfs_snapentry_t *sep, *next; 1464168404Spjd int locked; 1465168404Spjd vnode_t *dvp; 1466168404Spjd 1467197515Spjd if (vp->v_count > 0) 1468197515Spjd goto end; 1469197515Spjd 1470185029Spjd VERIFY(gfs_dir_lookup(vp, "..", &dvp, cr, 0, NULL, NULL) == 0); 1471168404Spjd sdp = dvp->v_data; 1472175294Sattilio VOP_UNLOCK(dvp, 0); 1473168404Spjd 1474168404Spjd if (!(locked = MUTEX_HELD(&sdp->sd_lock))) 1475168404Spjd mutex_enter(&sdp->sd_lock); 1476168404Spjd 1477168404Spjd ASSERT(!vn_ismntpt(vp)); 1478168404Spjd 1479168404Spjd sep = avl_first(&sdp->sd_snaps); 1480168404Spjd while (sep != NULL) { 1481168404Spjd next = AVL_NEXT(&sdp->sd_snaps, sep); 1482168404Spjd 1483168404Spjd if (sep->se_root == vp) { 1484168404Spjd avl_remove(&sdp->sd_snaps, sep); 1485168404Spjd kmem_free(sep->se_name, strlen(sep->se_name) + 1); 1486168404Spjd kmem_free(sep, sizeof (zfs_snapentry_t)); 1487168404Spjd break; 1488168404Spjd } 1489168404Spjd sep = next; 1490168404Spjd } 1491168404Spjd ASSERT(sep != NULL); 1492168404Spjd 1493168404Spjd if (!locked) 1494168404Spjd mutex_exit(&sdp->sd_lock); 1495168404Spjd VN_RELE(dvp); 1496219089Spjd 1497197515Spjdend: 1498168404Spjd /* 1499168404Spjd * Dispose of the vnode for the snapshot mount point. 1500168404Spjd * This is safe to do because once this entry has been removed 1501168404Spjd * from the AVL tree, it can't be found again, so cannot become 1502168404Spjd * "active". If we lookup the same name again we will end up 1503168404Spjd * creating a new vnode. 1504168404Spjd */ 1505168404Spjd iap.a_vp = vp; 1506168404Spjd return (gfs_vop_inactive(&iap)); 1507168404Spjd} 1508168404Spjd 1509168404Spjdstatic int 1510182371Sattiliozfsctl_traverse_begin(vnode_t **vpp, int lktype) 1511168404Spjd{ 1512168404Spjd 1513168404Spjd VN_HOLD(*vpp); 1514168404Spjd /* Snapshot should be already mounted, but just in case. */ 1515168404Spjd if (vn_mountedvfs(*vpp) == NULL) 1516168404Spjd return (ENOENT); 1517170281Spjd return (traverse(vpp, lktype)); 1518168404Spjd} 1519168404Spjd 1520168404Spjdstatic void 1521168404Spjdzfsctl_traverse_end(vnode_t *vp, int err) 1522168404Spjd{ 1523168404Spjd 1524168404Spjd if (err == 0) 1525168404Spjd vput(vp); 1526168404Spjd else 1527168404Spjd VN_RELE(vp); 1528168404Spjd} 1529168404Spjd 1530168404Spjdstatic int 1531168404Spjdzfsctl_snapshot_getattr(ap) 1532168404Spjd struct vop_getattr_args /* { 1533168404Spjd struct vnode *a_vp; 1534168404Spjd struct vattr *a_vap; 1535168404Spjd struct ucred *a_cred; 1536168404Spjd } */ *ap; 1537168404Spjd{ 1538168404Spjd vnode_t *vp = ap->a_vp; 1539168404Spjd int err; 1540168404Spjd 1541182371Sattilio err = zfsctl_traverse_begin(&vp, LK_SHARED | LK_RETRY); 1542168404Spjd if (err == 0) 1543182371Sattilio err = VOP_GETATTR(vp, ap->a_vap, ap->a_cred); 1544168404Spjd zfsctl_traverse_end(vp, err); 1545168404Spjd return (err); 1546168404Spjd} 1547168404Spjd 1548168404Spjdstatic int 1549168404Spjdzfsctl_snapshot_fid(ap) 1550168404Spjd struct vop_fid_args /* { 1551168404Spjd struct vnode *a_vp; 1552168404Spjd struct fid *a_fid; 1553168404Spjd } */ *ap; 1554168404Spjd{ 1555168404Spjd vnode_t *vp = ap->a_vp; 1556168404Spjd int err; 1557168404Spjd 1558182371Sattilio err = zfsctl_traverse_begin(&vp, LK_SHARED | LK_RETRY); 1559168404Spjd if (err == 0) 1560168404Spjd err = VOP_VPTOFH(vp, (void *)ap->a_fid); 1561168404Spjd zfsctl_traverse_end(vp, err); 1562168404Spjd return (err); 1563168404Spjd} 1564168404Spjd 1565185029Spjdstatic int 1566185029Spjdzfsctl_snapshot_lookup(ap) 1567185029Spjd struct vop_lookup_args /* { 1568185029Spjd struct vnode *a_dvp; 1569185029Spjd struct vnode **a_vpp; 1570185029Spjd struct componentname *a_cnp; 1571185029Spjd } */ *ap; 1572185029Spjd{ 1573185029Spjd vnode_t *dvp = ap->a_dvp; 1574185029Spjd vnode_t **vpp = ap->a_vpp; 1575185029Spjd struct componentname *cnp = ap->a_cnp; 1576185029Spjd cred_t *cr = ap->a_cnp->cn_cred; 1577185029Spjd zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 1578185029Spjd int error; 1579185029Spjd 1580185029Spjd if (cnp->cn_namelen != 2 || cnp->cn_nameptr[0] != '.' || 1581185029Spjd cnp->cn_nameptr[1] != '.') { 1582185029Spjd return (ENOENT); 1583185029Spjd } 1584185029Spjd 1585185029Spjd ASSERT(dvp->v_type == VDIR); 1586185029Spjd ASSERT(zfsvfs->z_ctldir != NULL); 1587185029Spjd 1588185029Spjd error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", vpp, 1589185029Spjd NULL, 0, NULL, cr, NULL, NULL, NULL); 1590185029Spjd if (error == 0) 1591185029Spjd vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); 1592185029Spjd return (error); 1593185029Spjd} 1594185029Spjd 1595196309Spjdstatic int 1596196309Spjdzfsctl_snapshot_vptocnp(struct vop_vptocnp_args *ap) 1597196309Spjd{ 1598196309Spjd zfsvfs_t *zfsvfs = ap->a_vp->v_vfsp->vfs_data; 1599196309Spjd vnode_t *dvp, *vp; 1600196309Spjd zfsctl_snapdir_t *sdp; 1601196309Spjd zfs_snapentry_t *sep; 1602196309Spjd int error; 1603196309Spjd 1604196309Spjd ASSERT(zfsvfs->z_ctldir != NULL); 1605196309Spjd error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp, 1606196309Spjd NULL, 0, NULL, kcred, NULL, NULL, NULL); 1607196309Spjd if (error != 0) 1608196309Spjd return (error); 1609196309Spjd sdp = dvp->v_data; 1610196309Spjd 1611196309Spjd mutex_enter(&sdp->sd_lock); 1612196309Spjd sep = avl_first(&sdp->sd_snaps); 1613196309Spjd while (sep != NULL) { 1614196309Spjd vp = sep->se_root; 1615196309Spjd if (vp == ap->a_vp) 1616196309Spjd break; 1617196309Spjd sep = AVL_NEXT(&sdp->sd_snaps, sep); 1618196309Spjd } 1619196309Spjd if (sep == NULL) { 1620196309Spjd mutex_exit(&sdp->sd_lock); 1621196309Spjd error = ENOENT; 1622196309Spjd } else { 1623196309Spjd size_t len; 1624196309Spjd 1625196309Spjd len = strlen(sep->se_name); 1626196309Spjd *ap->a_buflen -= len; 1627196309Spjd bcopy(sep->se_name, ap->a_buf + *ap->a_buflen, len); 1628196309Spjd mutex_exit(&sdp->sd_lock); 1629229703Skib vref(dvp); 1630196309Spjd *ap->a_vpp = dvp; 1631196309Spjd } 1632196309Spjd VN_RELE(dvp); 1633196309Spjd 1634196309Spjd return (error); 1635196309Spjd} 1636196309Spjd 1637168404Spjd/* 1638168404Spjd * These VP's should never see the light of day. They should always 1639168404Spjd * be covered. 1640168404Spjd */ 1641168404Spjdstatic struct vop_vector zfsctl_ops_snapshot = { 1642168404Spjd .vop_default = &default_vnodeops, 1643168404Spjd .vop_inactive = zfsctl_snapshot_inactive, 1644185029Spjd .vop_lookup = zfsctl_snapshot_lookup, 1645168404Spjd .vop_reclaim = zfsctl_common_reclaim, 1646168404Spjd .vop_getattr = zfsctl_snapshot_getattr, 1647168404Spjd .vop_fid = zfsctl_snapshot_fid, 1648196309Spjd .vop_vptocnp = zfsctl_snapshot_vptocnp, 1649168404Spjd}; 1650168404Spjd 1651168404Spjdint 1652168404Spjdzfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t **zfsvfsp) 1653168404Spjd{ 1654168404Spjd zfsvfs_t *zfsvfs = vfsp->vfs_data; 1655168404Spjd vnode_t *dvp, *vp; 1656168404Spjd zfsctl_snapdir_t *sdp; 1657168404Spjd zfsctl_node_t *zcp; 1658168404Spjd zfs_snapentry_t *sep; 1659168404Spjd int error; 1660168404Spjd 1661168404Spjd ASSERT(zfsvfs->z_ctldir != NULL); 1662168404Spjd error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp, 1663185029Spjd NULL, 0, NULL, kcred, NULL, NULL, NULL); 1664168404Spjd if (error != 0) 1665168404Spjd return (error); 1666168404Spjd sdp = dvp->v_data; 1667168404Spjd 1668168404Spjd mutex_enter(&sdp->sd_lock); 1669168404Spjd sep = avl_first(&sdp->sd_snaps); 1670168404Spjd while (sep != NULL) { 1671168404Spjd vp = sep->se_root; 1672168404Spjd zcp = vp->v_data; 1673168404Spjd if (zcp->zc_id == objsetid) 1674168404Spjd break; 1675168404Spjd 1676168404Spjd sep = AVL_NEXT(&sdp->sd_snaps, sep); 1677168404Spjd } 1678168404Spjd 1679168404Spjd if (sep != NULL) { 1680168404Spjd VN_HOLD(vp); 1681185029Spjd /* 1682185029Spjd * Return the mounted root rather than the covered mount point. 1683185029Spjd * Takes the GFS vnode at .zfs/snapshot/<snapshot objsetid> 1684185029Spjd * and returns the ZFS vnode mounted on top of the GFS node. 1685185029Spjd * This ZFS vnode is the root of the vfs for objset 'objsetid'. 1686185029Spjd */ 1687170281Spjd error = traverse(&vp, LK_SHARED | LK_RETRY); 1688168404Spjd if (error == 0) { 1689168404Spjd if (vp == sep->se_root) 1690249643Smm error = SET_ERROR(EINVAL); 1691168404Spjd else 1692168404Spjd *zfsvfsp = VTOZ(vp)->z_zfsvfs; 1693168404Spjd } 1694168404Spjd mutex_exit(&sdp->sd_lock); 1695170281Spjd if (error == 0) 1696170281Spjd VN_URELE(vp); 1697170281Spjd else 1698170281Spjd VN_RELE(vp); 1699168404Spjd } else { 1700249643Smm error = SET_ERROR(EINVAL); 1701168404Spjd mutex_exit(&sdp->sd_lock); 1702168404Spjd } 1703168404Spjd 1704168404Spjd VN_RELE(dvp); 1705168404Spjd 1706168404Spjd return (error); 1707168404Spjd} 1708168404Spjd 1709168404Spjd/* 1710168404Spjd * Unmount any snapshots for the given filesystem. This is called from 1711168404Spjd * zfs_umount() - if we have a ctldir, then go through and unmount all the 1712168404Spjd * snapshots. 1713168404Spjd */ 1714168404Spjdint 1715168404Spjdzfsctl_umount_snapshots(vfs_t *vfsp, int fflags, cred_t *cr) 1716168404Spjd{ 1717168404Spjd zfsvfs_t *zfsvfs = vfsp->vfs_data; 1718185029Spjd vnode_t *dvp; 1719168404Spjd zfsctl_snapdir_t *sdp; 1720168404Spjd zfs_snapentry_t *sep, *next; 1721168404Spjd int error; 1722168404Spjd 1723168404Spjd ASSERT(zfsvfs->z_ctldir != NULL); 1724168404Spjd error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp, 1725185029Spjd NULL, 0, NULL, cr, NULL, NULL, NULL); 1726168404Spjd if (error != 0) 1727168404Spjd return (error); 1728168404Spjd sdp = dvp->v_data; 1729168404Spjd 1730168404Spjd mutex_enter(&sdp->sd_lock); 1731168404Spjd 1732168404Spjd sep = avl_first(&sdp->sd_snaps); 1733168404Spjd while (sep != NULL) { 1734168404Spjd next = AVL_NEXT(&sdp->sd_snaps, sep); 1735168404Spjd 1736168404Spjd /* 1737168404Spjd * If this snapshot is not mounted, then it must 1738168404Spjd * have just been unmounted by somebody else, and 1739168404Spjd * will be cleaned up by zfsctl_snapdir_inactive(). 1740168404Spjd */ 1741185029Spjd if (vn_ismntpt(sep->se_root)) { 1742185029Spjd error = zfsctl_unmount_snap(sep, fflags, cr); 1743185029Spjd if (error) { 1744196954Spjd avl_index_t where; 1745196954Spjd 1746196953Spjd /* 1747196953Spjd * Before reinserting snapshot to the tree, 1748196953Spjd * check if it was actually removed. For example 1749196953Spjd * when snapshot mount point is busy, we will 1750196953Spjd * have an error here, but there will be no need 1751196953Spjd * to reinsert snapshot. 1752196953Spjd */ 1753196954Spjd if (avl_find(&sdp->sd_snaps, sep, &where) == NULL) 1754196954Spjd avl_insert(&sdp->sd_snaps, sep, where); 1755185029Spjd break; 1756168404Spjd } 1757168404Spjd } 1758168404Spjd sep = next; 1759168404Spjd } 1760185029Spjd 1761168404Spjd mutex_exit(&sdp->sd_lock); 1762168404Spjd VN_RELE(dvp); 1763168404Spjd 1764168404Spjd return (error); 1765168404Spjd} 1766