zfs_ctldir.c revision 243495
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. 23229565Smm * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>. 24229565Smm * All rights reserved. 25168404Spjd */ 26168404Spjd 27168404Spjd/* 28168404Spjd * ZFS control directory (a.k.a. ".zfs") 29168404Spjd * 30168404Spjd * This directory provides a common location for all ZFS meta-objects. 31168404Spjd * Currently, this is only the 'snapshot' directory, but this may expand in the 32168404Spjd * future. The elements are built using the GFS primitives, as the hierarchy 33168404Spjd * does not actually exist on disk. 34168404Spjd * 35168404Spjd * For 'snapshot', we don't want to have all snapshots always mounted, because 36168404Spjd * this would take up a huge amount of space in /etc/mnttab. We have three 37168404Spjd * types of objects: 38168404Spjd * 39168404Spjd * ctldir ------> snapshotdir -------> snapshot 40168404Spjd * | 41168404Spjd * | 42168404Spjd * V 43168404Spjd * mounted fs 44168404Spjd * 45168404Spjd * The 'snapshot' node contains just enough information to lookup '..' and act 46168404Spjd * as a mountpoint for the snapshot. Whenever we lookup a specific snapshot, we 47168404Spjd * perform an automount of the underlying filesystem and return the 48168404Spjd * corresponding vnode. 49168404Spjd * 50168404Spjd * All mounts are handled automatically by the kernel, but unmounts are 51168404Spjd * (currently) handled from user land. The main reason is that there is no 52168404Spjd * reliable way to auto-unmount the filesystem when it's "no longer in use". 53168404Spjd * When the user unmounts a filesystem, we call zfsctl_unmount(), which 54168404Spjd * unmounts any snapshots within the snapshot directory. 55185029Spjd * 56185029Spjd * The '.zfs', '.zfs/snapshot', and all directories created under 57185029Spjd * '.zfs/snapshot' (ie: '.zfs/snapshot/<snapname>') are all GFS nodes and 58185029Spjd * share the same vfs_t as the head filesystem (what '.zfs' lives under). 59185029Spjd * 60185029Spjd * File systems mounted ontop of the GFS nodes '.zfs/snapshot/<snapname>' 61185029Spjd * (ie: snapshots) are ZFS nodes and have their own unique vfs_t. 62185029Spjd * However, vnodes within these mounted on file systems have their v_vfsp 63185029Spjd * fields set to the head filesystem to make NFS happy (see 64185029Spjd * zfsctl_snapdir_lookup()). We VFS_HOLD the head filesystem's vfs_t 65185029Spjd * so that it cannot be freed until all snapshots have been unmounted. 66168404Spjd */ 67168404Spjd 68168404Spjd#include <sys/zfs_context.h> 69168404Spjd#include <sys/zfs_ctldir.h> 70168404Spjd#include <sys/zfs_ioctl.h> 71168404Spjd#include <sys/zfs_vfsops.h> 72168404Spjd#include <sys/namei.h> 73168404Spjd#include <sys/gfs.h> 74168404Spjd#include <sys/stat.h> 75168404Spjd#include <sys/dmu.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) 306168404Spjd return (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) 339209962Smm return (EACCES); 340209962Smm } else { 341209962Smm#endif 342219089Spjd if (accmode & VWRITE) 343219089Spjd return (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 400168404Spjd fidp->fid_len = SHORT_FID_LEN; 401168404Spjd 402168404Spjd zfid = (zfid_short_t *)fidp; 403168404Spjd 404168404Spjd zfid->zf_len = SHORT_FID_LEN; 405168404Spjd 406168404Spjd for (i = 0; i < sizeof (zfid->zf_object); i++) 407168404Spjd zfid->zf_object[i] = (uint8_t)(object >> (8 * i)); 408168404Spjd 409168404Spjd /* .zfs znodes always have a generation number of 0 */ 410168404Spjd for (i = 0; i < sizeof (zfid->zf_gen); i++) 411168404Spjd zfid->zf_gen[i] = 0; 412168404Spjd 413168404Spjd ZFS_EXIT(zfsvfs); 414168404Spjd return (0); 415168404Spjd} 416168404Spjd 417219089Spjd 418209962Smm/*ARGSUSED*/ 419168404Spjdstatic int 420209962Smmzfsctl_shares_fid(ap) 421209962Smm struct vop_fid_args /* { 422209962Smm struct vnode *a_vp; 423209962Smm struct fid *a_fid; 424209962Smm } */ *ap; 425209962Smm{ 426209962Smm vnode_t *vp = ap->a_vp; 427209962Smm fid_t *fidp = (void *)ap->a_fid; 428209962Smm zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 429209962Smm znode_t *dzp; 430209962Smm int error; 431209962Smm 432209962Smm ZFS_ENTER(zfsvfs); 433209962Smm 434209962Smm if (zfsvfs->z_shares_dir == 0) { 435209962Smm ZFS_EXIT(zfsvfs); 436209962Smm return (ENOTSUP); 437209962Smm } 438209962Smm 439209962Smm if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) { 440209962Smm error = VOP_FID(ZTOV(dzp), fidp); 441209962Smm VN_RELE(ZTOV(dzp)); 442209962Smm } 443209962Smm 444209962Smm ZFS_EXIT(zfsvfs); 445209962Smm return (error); 446209962Smm} 447209962Smm 448209962Smmstatic int 449168404Spjdzfsctl_common_reclaim(ap) 450168404Spjd struct vop_reclaim_args /* { 451168404Spjd struct vnode *a_vp; 452168404Spjd struct thread *a_td; 453168404Spjd } */ *ap; 454168404Spjd{ 455168404Spjd vnode_t *vp = ap->a_vp; 456168404Spjd 457168404Spjd /* 458168404Spjd * Destroy the vm object and flush associated pages. 459168404Spjd */ 460168404Spjd vnode_destroy_vobject(vp); 461168404Spjd VI_LOCK(vp); 462168404Spjd vp->v_data = NULL; 463168404Spjd VI_UNLOCK(vp); 464168404Spjd return (0); 465168404Spjd} 466168404Spjd 467168404Spjd/* 468168404Spjd * .zfs inode namespace 469168404Spjd * 470168404Spjd * We need to generate unique inode numbers for all files and directories 471168404Spjd * within the .zfs pseudo-filesystem. We use the following scheme: 472168404Spjd * 473168404Spjd * ENTRY ZFSCTL_INODE 474168404Spjd * .zfs 1 475168404Spjd * .zfs/snapshot 2 476168404Spjd * .zfs/snapshot/<snap> objectid(snap) 477168404Spjd */ 478168404Spjd 479168404Spjd#define ZFSCTL_INO_SNAP(id) (id) 480168404Spjd 481168404Spjd/* 482168404Spjd * Get root directory attributes. 483168404Spjd */ 484168404Spjd/* ARGSUSED */ 485168404Spjdstatic int 486168404Spjdzfsctl_root_getattr(ap) 487168404Spjd struct vop_getattr_args /* { 488168404Spjd struct vnode *a_vp; 489168404Spjd struct vattr *a_vap; 490168404Spjd struct ucred *a_cred; 491168404Spjd } */ *ap; 492168404Spjd{ 493168404Spjd struct vnode *vp = ap->a_vp; 494168404Spjd struct vattr *vap = ap->a_vap; 495168404Spjd zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 496219089Spjd zfsctl_node_t *zcp = vp->v_data; 497168404Spjd 498168404Spjd ZFS_ENTER(zfsvfs); 499168404Spjd vap->va_nodeid = ZFSCTL_INO_ROOT; 500168404Spjd vap->va_nlink = vap->va_size = NROOT_ENTRIES; 501219089Spjd vap->va_mtime = vap->va_ctime = zcp->zc_cmtime; 502219089Spjd vap->va_birthtime = vap->va_ctime; 503168404Spjd 504168404Spjd zfsctl_common_getattr(vp, vap); 505168404Spjd ZFS_EXIT(zfsvfs); 506168404Spjd 507168404Spjd return (0); 508168404Spjd} 509168404Spjd 510219089Spjd/* 511219089Spjd * Special case the handling of "..". 512219089Spjd */ 513219089Spjd/* ARGSUSED */ 514219089Spjdint 515219089Spjdzfsctl_root_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp, 516219089Spjd int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct, 517219089Spjd int *direntflags, pathname_t *realpnp) 518219089Spjd{ 519219089Spjd zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 520219089Spjd int err; 521219089Spjd 522219089Spjd /* 523219089Spjd * No extended attributes allowed under .zfs 524219089Spjd */ 525219089Spjd if (flags & LOOKUP_XATTR) 526219089Spjd return (EINVAL); 527219089Spjd 528219089Spjd ZFS_ENTER(zfsvfs); 529219089Spjd 530219089Spjd if (strcmp(nm, "..") == 0) { 531219089Spjd err = VFS_ROOT(dvp->v_vfsp, LK_EXCLUSIVE, vpp); 532219089Spjd if (err == 0) 533219089Spjd VOP_UNLOCK(*vpp, 0); 534219089Spjd } else { 535219089Spjd err = gfs_vop_lookup(dvp, nm, vpp, pnp, flags, rdir, 536219089Spjd cr, ct, direntflags, realpnp); 537219089Spjd } 538219089Spjd 539219089Spjd ZFS_EXIT(zfsvfs); 540219089Spjd 541219089Spjd return (err); 542219089Spjd} 543219089Spjd 544209962Smm#ifdef sun 545209962Smmstatic int 546209962Smmzfsctl_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, 547209962Smm caller_context_t *ct) 548209962Smm{ 549209962Smm /* 550209962Smm * We only care about ACL_ENABLED so that libsec can 551209962Smm * display ACL correctly and not default to POSIX draft. 552209962Smm */ 553209962Smm if (cmd == _PC_ACL_ENABLED) { 554209962Smm *valp = _ACL_ACE_ENABLED; 555209962Smm return (0); 556209962Smm } 557209962Smm 558209962Smm return (fs_pathconf(vp, cmd, valp, cr, ct)); 559209962Smm} 560209962Smm#endif /* sun */ 561209962Smm 562209962Smm#ifdef sun 563209962Smmstatic const fs_operation_def_t zfsctl_tops_root[] = { 564209962Smm { VOPNAME_OPEN, { .vop_open = zfsctl_common_open } }, 565209962Smm { VOPNAME_CLOSE, { .vop_close = zfsctl_common_close } }, 566209962Smm { VOPNAME_IOCTL, { .error = fs_inval } }, 567209962Smm { VOPNAME_GETATTR, { .vop_getattr = zfsctl_root_getattr } }, 568209962Smm { VOPNAME_ACCESS, { .vop_access = zfsctl_common_access } }, 569209962Smm { VOPNAME_READDIR, { .vop_readdir = gfs_vop_readdir } }, 570209962Smm { VOPNAME_LOOKUP, { .vop_lookup = zfsctl_root_lookup } }, 571209962Smm { VOPNAME_SEEK, { .vop_seek = fs_seek } }, 572209962Smm { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } }, 573209962Smm { VOPNAME_PATHCONF, { .vop_pathconf = zfsctl_pathconf } }, 574209962Smm { VOPNAME_FID, { .vop_fid = zfsctl_common_fid } }, 575209962Smm { NULL } 576209962Smm}; 577209962Smm#endif /* sun */ 578209962Smm 579168404Spjd/* 580168404Spjd * Special case the handling of "..". 581168404Spjd */ 582168404Spjd/* ARGSUSED */ 583168404Spjdint 584185029Spjdzfsctl_freebsd_root_lookup(ap) 585168404Spjd struct vop_lookup_args /* { 586168404Spjd struct vnode *a_dvp; 587168404Spjd struct vnode **a_vpp; 588168404Spjd struct componentname *a_cnp; 589168404Spjd } */ *ap; 590168404Spjd{ 591168404Spjd vnode_t *dvp = ap->a_dvp; 592168404Spjd vnode_t **vpp = ap->a_vpp; 593168404Spjd cred_t *cr = ap->a_cnp->cn_cred; 594168404Spjd int flags = ap->a_cnp->cn_flags; 595168404Spjd int nameiop = ap->a_cnp->cn_nameiop; 596168404Spjd char nm[NAME_MAX + 1]; 597168404Spjd int err; 598168404Spjd 599168404Spjd if ((flags & ISLASTCN) && (nameiop == RENAME || nameiop == CREATE)) 600168404Spjd return (EOPNOTSUPP); 601168404Spjd 602168404Spjd ASSERT(ap->a_cnp->cn_namelen < sizeof(nm)); 603168404Spjd strlcpy(nm, ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen + 1); 604168404Spjd 605185029Spjd err = zfsctl_root_lookup(dvp, nm, vpp, NULL, 0, NULL, cr, NULL, NULL, NULL); 606168404Spjd if (err == 0 && (nm[0] != '.' || nm[1] != '\0')) 607175202Sattilio vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); 608168404Spjd return (err); 609168404Spjd} 610168404Spjd 611168404Spjdstatic struct vop_vector zfsctl_ops_root = { 612168404Spjd .vop_default = &default_vnodeops, 613168404Spjd .vop_open = zfsctl_common_open, 614168404Spjd .vop_close = zfsctl_common_close, 615168404Spjd .vop_ioctl = VOP_EINVAL, 616168404Spjd .vop_getattr = zfsctl_root_getattr, 617168404Spjd .vop_access = zfsctl_common_access, 618168404Spjd .vop_readdir = gfs_vop_readdir, 619185029Spjd .vop_lookup = zfsctl_freebsd_root_lookup, 620168404Spjd .vop_inactive = gfs_vop_inactive, 621168404Spjd .vop_reclaim = zfsctl_common_reclaim, 622219089Spjd#ifdef TODO 623219089Spjd .vop_pathconf = zfsctl_pathconf, 624219089Spjd#endif 625168404Spjd .vop_fid = zfsctl_common_fid, 626168404Spjd}; 627168404Spjd 628168404Spjdstatic int 629168404Spjdzfsctl_snapshot_zname(vnode_t *vp, const char *name, int len, char *zname) 630168404Spjd{ 631168404Spjd objset_t *os = ((zfsvfs_t *)((vp)->v_vfsp->vfs_data))->z_os; 632168404Spjd 633185029Spjd if (snapshot_namecheck(name, NULL, NULL) != 0) 634185029Spjd return (EILSEQ); 635168404Spjd dmu_objset_name(os, zname); 636168404Spjd if (strlen(zname) + 1 + strlen(name) >= len) 637168404Spjd return (ENAMETOOLONG); 638168404Spjd (void) strcat(zname, "@"); 639168404Spjd (void) strcat(zname, name); 640168404Spjd return (0); 641168404Spjd} 642168404Spjd 643168404Spjdstatic int 644185029Spjdzfsctl_unmount_snap(zfs_snapentry_t *sep, int fflags, cred_t *cr) 645168404Spjd{ 646185029Spjd vnode_t *svp = sep->se_root; 647185029Spjd int error; 648168404Spjd 649185029Spjd ASSERT(vn_ismntpt(svp)); 650168404Spjd 651168404Spjd /* this will be dropped by dounmount() */ 652185029Spjd if ((error = vn_vfswlock(svp)) != 0) 653185029Spjd return (error); 654168404Spjd 655219089Spjd#ifdef sun 656219089Spjd VN_HOLD(svp); 657219089Spjd error = dounmount(vn_mountedvfs(svp), fflags, cr); 658219089Spjd if (error) { 659219089Spjd VN_RELE(svp); 660219089Spjd return (error); 661219089Spjd } 662219089Spjd 663219089Spjd /* 664219089Spjd * We can't use VN_RELE(), as that will try to invoke 665219089Spjd * zfsctl_snapdir_inactive(), which would cause us to destroy 666219089Spjd * the sd_lock mutex held by our caller. 667219089Spjd */ 668219089Spjd ASSERT(svp->v_count == 1); 669219089Spjd gfs_vop_inactive(svp, cr, NULL); 670219089Spjd 671219089Spjd kmem_free(sep->se_name, strlen(sep->se_name) + 1); 672219089Spjd kmem_free(sep, sizeof (zfs_snapentry_t)); 673219089Spjd 674219089Spjd return (0); 675219089Spjd#else /* !sun */ 676185029Spjd return (dounmount(vn_mountedvfs(svp), fflags, curthread)); 677219089Spjd#endif /* !sun */ 678168404Spjd} 679168404Spjd 680219089Spjd#ifdef sun 681168404Spjdstatic void 682168404Spjdzfsctl_rename_snap(zfsctl_snapdir_t *sdp, zfs_snapentry_t *sep, const char *nm) 683168404Spjd{ 684168404Spjd avl_index_t where; 685168404Spjd vfs_t *vfsp; 686168404Spjd refstr_t *pathref; 687168404Spjd char newpath[MAXNAMELEN]; 688168404Spjd char *tail; 689168404Spjd 690168404Spjd ASSERT(MUTEX_HELD(&sdp->sd_lock)); 691168404Spjd ASSERT(sep != NULL); 692168404Spjd 693168404Spjd vfsp = vn_mountedvfs(sep->se_root); 694168404Spjd ASSERT(vfsp != NULL); 695168404Spjd 696168404Spjd vfs_lock_wait(vfsp); 697168404Spjd 698168404Spjd /* 699168404Spjd * Change the name in the AVL tree. 700168404Spjd */ 701168404Spjd avl_remove(&sdp->sd_snaps, sep); 702168404Spjd kmem_free(sep->se_name, strlen(sep->se_name) + 1); 703168404Spjd sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP); 704168404Spjd (void) strcpy(sep->se_name, nm); 705168404Spjd VERIFY(avl_find(&sdp->sd_snaps, sep, &where) == NULL); 706168404Spjd avl_insert(&sdp->sd_snaps, sep, where); 707168404Spjd 708168404Spjd /* 709168404Spjd * Change the current mountpoint info: 710168404Spjd * - update the tail of the mntpoint path 711168404Spjd * - update the tail of the resource path 712168404Spjd */ 713168404Spjd pathref = vfs_getmntpoint(vfsp); 714168404Spjd (void) strncpy(newpath, refstr_value(pathref), sizeof (newpath)); 715168404Spjd VERIFY((tail = strrchr(newpath, '/')) != NULL); 716168404Spjd *(tail+1) = '\0'; 717168404Spjd ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath)); 718168404Spjd (void) strcat(newpath, nm); 719168404Spjd refstr_rele(pathref); 720219089Spjd vfs_setmntpoint(vfsp, newpath, 0); 721168404Spjd 722168404Spjd pathref = vfs_getresource(vfsp); 723168404Spjd (void) strncpy(newpath, refstr_value(pathref), sizeof (newpath)); 724168404Spjd VERIFY((tail = strrchr(newpath, '@')) != NULL); 725168404Spjd *(tail+1) = '\0'; 726168404Spjd ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath)); 727168404Spjd (void) strcat(newpath, nm); 728168404Spjd refstr_rele(pathref); 729219089Spjd vfs_setresource(vfsp, newpath, 0); 730168404Spjd 731168404Spjd vfs_unlock(vfsp); 732168404Spjd} 733219089Spjd#endif /* sun */ 734168404Spjd 735219089Spjd#ifdef sun 736185029Spjd/*ARGSUSED*/ 737168404Spjdstatic int 738168404Spjdzfsctl_snapdir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, 739185029Spjd cred_t *cr, caller_context_t *ct, int flags) 740168404Spjd{ 741168404Spjd zfsctl_snapdir_t *sdp = sdvp->v_data; 742168404Spjd zfs_snapentry_t search, *sep; 743185029Spjd zfsvfs_t *zfsvfs; 744168404Spjd avl_index_t where; 745168404Spjd char from[MAXNAMELEN], to[MAXNAMELEN]; 746185029Spjd char real[MAXNAMELEN]; 747168404Spjd int err; 748168404Spjd 749185029Spjd zfsvfs = sdvp->v_vfsp->vfs_data; 750185029Spjd ZFS_ENTER(zfsvfs); 751185029Spjd 752185029Spjd if ((flags & FIGNORECASE) || zfsvfs->z_case == ZFS_CASE_INSENSITIVE) { 753185029Spjd err = dmu_snapshot_realname(zfsvfs->z_os, snm, real, 754185029Spjd MAXNAMELEN, NULL); 755185029Spjd if (err == 0) { 756185029Spjd snm = real; 757185029Spjd } else if (err != ENOTSUP) { 758185029Spjd ZFS_EXIT(zfsvfs); 759185029Spjd return (err); 760185029Spjd } 761185029Spjd } 762185029Spjd 763185029Spjd ZFS_EXIT(zfsvfs); 764185029Spjd 765168404Spjd err = zfsctl_snapshot_zname(sdvp, snm, MAXNAMELEN, from); 766185029Spjd if (!err) 767185029Spjd err = zfsctl_snapshot_zname(tdvp, tnm, MAXNAMELEN, to); 768185029Spjd if (!err) 769185029Spjd err = zfs_secpolicy_rename_perms(from, to, cr); 770168404Spjd if (err) 771168404Spjd return (err); 772168404Spjd 773168404Spjd /* 774168404Spjd * Cannot move snapshots out of the snapdir. 775168404Spjd */ 776168404Spjd if (sdvp != tdvp) 777168404Spjd return (EINVAL); 778168404Spjd 779168404Spjd if (strcmp(snm, tnm) == 0) 780168404Spjd return (0); 781168404Spjd 782168404Spjd mutex_enter(&sdp->sd_lock); 783168404Spjd 784168404Spjd search.se_name = (char *)snm; 785168404Spjd if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) == NULL) { 786168404Spjd mutex_exit(&sdp->sd_lock); 787168404Spjd return (ENOENT); 788168404Spjd } 789168404Spjd 790229565Smm err = dmu_objset_rename(from, to, 0); 791168404Spjd if (err == 0) 792168404Spjd zfsctl_rename_snap(sdp, sep, tnm); 793168404Spjd 794168404Spjd mutex_exit(&sdp->sd_lock); 795168404Spjd 796168404Spjd return (err); 797168404Spjd} 798219089Spjd#endif /* sun */ 799168404Spjd 800219089Spjd#ifdef sun 801168404Spjd/* ARGSUSED */ 802168404Spjdstatic int 803185029Spjdzfsctl_snapdir_remove(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr, 804185029Spjd caller_context_t *ct, int flags) 805168404Spjd{ 806169170Spjd zfsctl_snapdir_t *sdp = dvp->v_data; 807185029Spjd zfs_snapentry_t *sep; 808185029Spjd zfs_snapentry_t search; 809185029Spjd zfsvfs_t *zfsvfs; 810169170Spjd char snapname[MAXNAMELEN]; 811185029Spjd char real[MAXNAMELEN]; 812169170Spjd int err; 813168404Spjd 814185029Spjd zfsvfs = dvp->v_vfsp->vfs_data; 815185029Spjd ZFS_ENTER(zfsvfs); 816185029Spjd 817185029Spjd if ((flags & FIGNORECASE) || zfsvfs->z_case == ZFS_CASE_INSENSITIVE) { 818185029Spjd 819185029Spjd err = dmu_snapshot_realname(zfsvfs->z_os, name, real, 820185029Spjd MAXNAMELEN, NULL); 821185029Spjd if (err == 0) { 822185029Spjd name = real; 823185029Spjd } else if (err != ENOTSUP) { 824185029Spjd ZFS_EXIT(zfsvfs); 825185029Spjd return (err); 826185029Spjd } 827185029Spjd } 828185029Spjd 829185029Spjd ZFS_EXIT(zfsvfs); 830185029Spjd 831169170Spjd err = zfsctl_snapshot_zname(dvp, name, MAXNAMELEN, snapname); 832185029Spjd if (!err) 833185029Spjd err = zfs_secpolicy_destroy_perms(snapname, cr); 834169170Spjd if (err) 835169170Spjd return (err); 836168404Spjd 837169170Spjd mutex_enter(&sdp->sd_lock); 838168404Spjd 839185029Spjd search.se_name = name; 840185029Spjd sep = avl_find(&sdp->sd_snaps, &search, NULL); 841185029Spjd if (sep) { 842185029Spjd avl_remove(&sdp->sd_snaps, sep); 843185029Spjd err = zfsctl_unmount_snap(sep, MS_FORCE, cr); 844196954Spjd if (err) { 845196954Spjd avl_index_t where; 846196954Spjd 847196954Spjd if (avl_find(&sdp->sd_snaps, sep, &where) == NULL) 848196954Spjd avl_insert(&sdp->sd_snaps, sep, where); 849196954Spjd } else 850219089Spjd err = dmu_objset_destroy(snapname, B_FALSE); 851185029Spjd } else { 852185029Spjd err = ENOENT; 853169170Spjd } 854168404Spjd 855169170Spjd mutex_exit(&sdp->sd_lock); 856168404Spjd 857169170Spjd return (err); 858168404Spjd} 859219089Spjd#endif /* sun */ 860168404Spjd 861168404Spjd/* 862185029Spjd * This creates a snapshot under '.zfs/snapshot'. 863185029Spjd */ 864185029Spjd/* ARGSUSED */ 865185029Spjdstatic int 866185029Spjdzfsctl_snapdir_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, 867185029Spjd cred_t *cr, caller_context_t *cc, int flags, vsecattr_t *vsecp) 868185029Spjd{ 869185029Spjd zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 870185029Spjd char name[MAXNAMELEN]; 871185029Spjd int err; 872185029Spjd static enum symfollow follow = NO_FOLLOW; 873185029Spjd static enum uio_seg seg = UIO_SYSSPACE; 874185029Spjd 875185029Spjd if (snapshot_namecheck(dirname, NULL, NULL) != 0) 876185029Spjd return (EILSEQ); 877185029Spjd 878185029Spjd dmu_objset_name(zfsvfs->z_os, name); 879185029Spjd 880185029Spjd *vpp = NULL; 881185029Spjd 882185029Spjd err = zfs_secpolicy_snapshot_perms(name, cr); 883185029Spjd if (err) 884185029Spjd return (err); 885185029Spjd 886185029Spjd if (err == 0) { 887219089Spjd err = dmu_objset_snapshot(name, dirname, NULL, NULL, 888219089Spjd B_FALSE, B_FALSE, -1); 889185029Spjd if (err) 890185029Spjd return (err); 891185029Spjd err = lookupnameat(dirname, seg, follow, NULL, vpp, dvp); 892185029Spjd } 893185029Spjd 894185029Spjd return (err); 895185029Spjd} 896185029Spjd 897185029Spjdstatic int 898185029Spjdzfsctl_freebsd_snapdir_mkdir(ap) 899185029Spjd struct vop_mkdir_args /* { 900185029Spjd struct vnode *a_dvp; 901185029Spjd struct vnode **a_vpp; 902185029Spjd struct componentname *a_cnp; 903185029Spjd struct vattr *a_vap; 904185029Spjd } */ *ap; 905185029Spjd{ 906185029Spjd 907185029Spjd ASSERT(ap->a_cnp->cn_flags & SAVENAME); 908185029Spjd 909185029Spjd return (zfsctl_snapdir_mkdir(ap->a_dvp, ap->a_cnp->cn_nameptr, NULL, 910185029Spjd ap->a_vpp, ap->a_cnp->cn_cred, NULL, 0, NULL)); 911185029Spjd} 912185029Spjd 913185029Spjd/* 914168404Spjd * Lookup entry point for the 'snapshot' directory. Try to open the 915168404Spjd * snapshot if it exist, creating the pseudo filesystem vnode as necessary. 916168404Spjd * Perform a mount of the associated dataset on top of the vnode. 917168404Spjd */ 918168404Spjd/* ARGSUSED */ 919168404Spjdint 920168404Spjdzfsctl_snapdir_lookup(ap) 921168404Spjd struct vop_lookup_args /* { 922168404Spjd struct vnode *a_dvp; 923168404Spjd struct vnode **a_vpp; 924168404Spjd struct componentname *a_cnp; 925168404Spjd } */ *ap; 926168404Spjd{ 927168404Spjd vnode_t *dvp = ap->a_dvp; 928168404Spjd vnode_t **vpp = ap->a_vpp; 929185029Spjd struct componentname *cnp = ap->a_cnp; 930168404Spjd char nm[NAME_MAX + 1]; 931168404Spjd zfsctl_snapdir_t *sdp = dvp->v_data; 932168404Spjd objset_t *snap; 933168404Spjd char snapname[MAXNAMELEN]; 934185029Spjd char real[MAXNAMELEN]; 935168404Spjd char *mountpoint; 936168404Spjd zfs_snapentry_t *sep, search; 937168404Spjd size_t mountpoint_len; 938168404Spjd avl_index_t where; 939168404Spjd zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 940168404Spjd int err; 941185029Spjd int flags = 0; 942168404Spjd 943185029Spjd /* 944185029Spjd * No extended attributes allowed under .zfs 945185029Spjd */ 946185029Spjd if (flags & LOOKUP_XATTR) 947185029Spjd return (EINVAL); 948168404Spjd ASSERT(ap->a_cnp->cn_namelen < sizeof(nm)); 949168404Spjd strlcpy(nm, ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen + 1); 950168404Spjd 951168404Spjd ASSERT(dvp->v_type == VDIR); 952168404Spjd 953168404Spjd *vpp = NULL; 954168404Spjd 955168404Spjd /* 956168404Spjd * If we get a recursive call, that means we got called 957168404Spjd * from the domount() code while it was trying to look up the 958168404Spjd * spec (which looks like a local path for zfs). We need to 959168404Spjd * add some flag to domount() to tell it not to do this lookup. 960168404Spjd */ 961168404Spjd if (MUTEX_HELD(&sdp->sd_lock)) 962168404Spjd return (ENOENT); 963168404Spjd 964168404Spjd ZFS_ENTER(zfsvfs); 965168404Spjd 966209962Smm if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0) { 967209962Smm ZFS_EXIT(zfsvfs); 968209962Smm return (0); 969209962Smm } 970209962Smm 971185029Spjd if (flags & FIGNORECASE) { 972185029Spjd boolean_t conflict = B_FALSE; 973185029Spjd 974185029Spjd err = dmu_snapshot_realname(zfsvfs->z_os, nm, real, 975185029Spjd MAXNAMELEN, &conflict); 976185029Spjd if (err == 0) { 977185029Spjd strlcpy(nm, real, sizeof(nm)); 978185029Spjd } else if (err != ENOTSUP) { 979185029Spjd ZFS_EXIT(zfsvfs); 980185029Spjd return (err); 981185029Spjd } 982185029Spjd#if 0 983185029Spjd if (realpnp) 984185029Spjd (void) strlcpy(realpnp->pn_buf, nm, 985185029Spjd realpnp->pn_bufsize); 986185029Spjd if (conflict && direntflags) 987185029Spjd *direntflags = ED_CASE_CONFLICT; 988185029Spjd#endif 989185029Spjd } 990185029Spjd 991168404Spjd mutex_enter(&sdp->sd_lock); 992168404Spjd search.se_name = (char *)nm; 993168404Spjd if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) != NULL) { 994168404Spjd *vpp = sep->se_root; 995168404Spjd VN_HOLD(*vpp); 996197513Spjd err = traverse(vpp, LK_EXCLUSIVE | LK_RETRY); 997197513Spjd if (err) { 998197513Spjd VN_RELE(*vpp); 999197513Spjd *vpp = NULL; 1000197513Spjd } else if (*vpp == sep->se_root) { 1001168404Spjd /* 1002168404Spjd * The snapshot was unmounted behind our backs, 1003168404Spjd * try to remount it. 1004168404Spjd */ 1005243495Savg VERIFY(zfsctl_snapshot_zname(dvp, nm, MAXNAMELEN, snapname) == 0); 1006168404Spjd goto domount; 1007185029Spjd } else { 1008185029Spjd /* 1009185029Spjd * VROOT was set during the traverse call. We need 1010185029Spjd * to clear it since we're pretending to be part 1011185029Spjd * of our parent's vfs. 1012185029Spjd */ 1013185029Spjd (*vpp)->v_flag &= ~VROOT; 1014168404Spjd } 1015168404Spjd mutex_exit(&sdp->sd_lock); 1016168404Spjd ZFS_EXIT(zfsvfs); 1017197513Spjd return (err); 1018168404Spjd } 1019168404Spjd 1020168404Spjd /* 1021168404Spjd * The requested snapshot is not currently mounted, look it up. 1022168404Spjd */ 1023168404Spjd err = zfsctl_snapshot_zname(dvp, nm, MAXNAMELEN, snapname); 1024168404Spjd if (err) { 1025168404Spjd mutex_exit(&sdp->sd_lock); 1026168404Spjd ZFS_EXIT(zfsvfs); 1027185029Spjd /* 1028185029Spjd * handle "ls *" or "?" in a graceful manner, 1029185029Spjd * forcing EILSEQ to ENOENT. 1030185029Spjd * Since shell ultimately passes "*" or "?" as name to lookup 1031185029Spjd */ 1032185029Spjd return (err == EILSEQ ? ENOENT : err); 1033168404Spjd } 1034219089Spjd if (dmu_objset_hold(snapname, FTAG, &snap) != 0) { 1035168404Spjd mutex_exit(&sdp->sd_lock); 1036185029Spjd /* Translate errors and add SAVENAME when needed. */ 1037185029Spjd if ((cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == CREATE) { 1038185029Spjd err = EJUSTRETURN; 1039185029Spjd cnp->cn_flags |= SAVENAME; 1040185029Spjd } else { 1041185029Spjd err = ENOENT; 1042185029Spjd } 1043168404Spjd ZFS_EXIT(zfsvfs); 1044185029Spjd return (err); 1045168404Spjd } 1046168404Spjd 1047168404Spjd sep = kmem_alloc(sizeof (zfs_snapentry_t), KM_SLEEP); 1048168404Spjd sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP); 1049168404Spjd (void) strcpy(sep->se_name, nm); 1050168404Spjd *vpp = sep->se_root = zfsctl_snapshot_mknode(dvp, dmu_objset_id(snap)); 1051168404Spjd VN_HOLD(*vpp); 1052168404Spjd avl_insert(&sdp->sd_snaps, sep, where); 1053168404Spjd 1054219089Spjd dmu_objset_rele(snap, FTAG); 1055168404Spjddomount: 1056168404Spjd mountpoint_len = strlen(dvp->v_vfsp->mnt_stat.f_mntonname) + 1057211900Spjd strlen("/" ZFS_CTLDIR_NAME "/snapshot/") + strlen(nm) + 1; 1058168404Spjd mountpoint = kmem_alloc(mountpoint_len, KM_SLEEP); 1059211900Spjd (void) snprintf(mountpoint, mountpoint_len, 1060211900Spjd "%s/" ZFS_CTLDIR_NAME "/snapshot/%s", 1061168404Spjd dvp->v_vfsp->mnt_stat.f_mntonname, nm); 1062197201Spjd err = mount_snapshot(curthread, vpp, "zfs", mountpoint, snapname, 0); 1063168404Spjd kmem_free(mountpoint, mountpoint_len); 1064196980Spjd if (err == 0) { 1065196980Spjd /* 1066196980Spjd * Fix up the root vnode mounted on .zfs/snapshot/<snapname>. 1067196980Spjd * 1068196980Spjd * This is where we lie about our v_vfsp in order to 1069196980Spjd * make .zfs/snapshot/<snapname> accessible over NFS 1070196980Spjd * without requiring manual mounts of <snapname>. 1071196980Spjd */ 1072196980Spjd ASSERT(VTOZ(*vpp)->z_zfsvfs != zfsvfs); 1073196980Spjd VTOZ(*vpp)->z_zfsvfs->z_parent = zfsvfs; 1074196980Spjd } 1075168404Spjd mutex_exit(&sdp->sd_lock); 1076183037Spjd ZFS_EXIT(zfsvfs); 1077197514Spjd if (err != 0) 1078197514Spjd *vpp = NULL; 1079168404Spjd return (err); 1080168404Spjd} 1081168404Spjd 1082168404Spjd/* ARGSUSED */ 1083209962Smmint 1084209962Smmzfsctl_shares_lookup(ap) 1085209962Smm struct vop_lookup_args /* { 1086209962Smm struct vnode *a_dvp; 1087209962Smm struct vnode **a_vpp; 1088209962Smm struct componentname *a_cnp; 1089209962Smm } */ *ap; 1090209962Smm{ 1091209962Smm vnode_t *dvp = ap->a_dvp; 1092209962Smm vnode_t **vpp = ap->a_vpp; 1093209962Smm struct componentname *cnp = ap->a_cnp; 1094209962Smm zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 1095209962Smm char nm[NAME_MAX + 1]; 1096209962Smm znode_t *dzp; 1097209962Smm int error; 1098209962Smm 1099209962Smm ZFS_ENTER(zfsvfs); 1100209962Smm 1101209962Smm ASSERT(cnp->cn_namelen < sizeof(nm)); 1102209962Smm strlcpy(nm, cnp->cn_nameptr, cnp->cn_namelen + 1); 1103209962Smm 1104209962Smm if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0) { 1105209962Smm ZFS_EXIT(zfsvfs); 1106209962Smm return (0); 1107209962Smm } 1108209962Smm 1109209962Smm if (zfsvfs->z_shares_dir == 0) { 1110209962Smm ZFS_EXIT(zfsvfs); 1111209962Smm return (ENOTSUP); 1112209962Smm } 1113209962Smm if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) 1114209962Smm error = VOP_LOOKUP(ZTOV(dzp), vpp, cnp); 1115209962Smm 1116209962Smm VN_RELE(ZTOV(dzp)); 1117209962Smm ZFS_EXIT(zfsvfs); 1118209962Smm 1119209962Smm return (error); 1120209962Smm} 1121209962Smm 1122209962Smm/* ARGSUSED */ 1123168404Spjdstatic int 1124185029Spjdzfsctl_snapdir_readdir_cb(vnode_t *vp, void *dp, int *eofp, 1125185029Spjd offset_t *offp, offset_t *nextp, void *data, int flags) 1126168404Spjd{ 1127168404Spjd zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 1128168404Spjd char snapname[MAXNAMELEN]; 1129168404Spjd uint64_t id, cookie; 1130185029Spjd boolean_t case_conflict; 1131185029Spjd int error; 1132168404Spjd 1133168404Spjd ZFS_ENTER(zfsvfs); 1134168404Spjd 1135168404Spjd cookie = *offp; 1136185029Spjd error = dmu_snapshot_list_next(zfsvfs->z_os, MAXNAMELEN, snapname, &id, 1137185029Spjd &cookie, &case_conflict); 1138185029Spjd if (error) { 1139168404Spjd ZFS_EXIT(zfsvfs); 1140185029Spjd if (error == ENOENT) { 1141185029Spjd *eofp = 1; 1142185029Spjd return (0); 1143185029Spjd } 1144185029Spjd return (error); 1145168404Spjd } 1146168404Spjd 1147185029Spjd if (flags & V_RDDIR_ENTFLAGS) { 1148185029Spjd edirent_t *eodp = dp; 1149185029Spjd 1150185029Spjd (void) strcpy(eodp->ed_name, snapname); 1151185029Spjd eodp->ed_ino = ZFSCTL_INO_SNAP(id); 1152185029Spjd eodp->ed_eflags = case_conflict ? ED_CASE_CONFLICT : 0; 1153185029Spjd } else { 1154185029Spjd struct dirent64 *odp = dp; 1155185029Spjd 1156185029Spjd (void) strcpy(odp->d_name, snapname); 1157185029Spjd odp->d_ino = ZFSCTL_INO_SNAP(id); 1158185029Spjd } 1159168404Spjd *nextp = cookie; 1160168404Spjd 1161168404Spjd ZFS_EXIT(zfsvfs); 1162168404Spjd 1163168404Spjd return (0); 1164168404Spjd} 1165168404Spjd 1166209962Smm/* ARGSUSED */ 1167209962Smmstatic int 1168209962Smmzfsctl_shares_readdir(ap) 1169209962Smm struct vop_readdir_args /* { 1170209962Smm struct vnode *a_vp; 1171209962Smm struct uio *a_uio; 1172209962Smm struct ucred *a_cred; 1173209962Smm int *a_eofflag; 1174209962Smm int *a_ncookies; 1175209962Smm u_long **a_cookies; 1176209962Smm } */ *ap; 1177209962Smm{ 1178209962Smm vnode_t *vp = ap->a_vp; 1179209962Smm uio_t *uiop = ap->a_uio; 1180209962Smm cred_t *cr = ap->a_cred; 1181209962Smm int *eofp = ap->a_eofflag; 1182209962Smm zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 1183209962Smm znode_t *dzp; 1184209962Smm int error; 1185209962Smm 1186209962Smm ZFS_ENTER(zfsvfs); 1187209962Smm 1188209962Smm if (zfsvfs->z_shares_dir == 0) { 1189209962Smm ZFS_EXIT(zfsvfs); 1190209962Smm return (ENOTSUP); 1191209962Smm } 1192209962Smm if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) { 1193212605Smm vn_lock(ZTOV(dzp), LK_SHARED | LK_RETRY); 1194209962Smm error = VOP_READDIR(ZTOV(dzp), uiop, cr, eofp, ap->a_ncookies, ap->a_cookies); 1195212605Smm VN_URELE(ZTOV(dzp)); 1196209962Smm } else { 1197209962Smm *eofp = 1; 1198209962Smm error = ENOENT; 1199209962Smm } 1200209962Smm 1201209962Smm ZFS_EXIT(zfsvfs); 1202209962Smm return (error); 1203209962Smm} 1204209962Smm 1205185029Spjd/* 1206185029Spjd * pvp is the '.zfs' directory (zfsctl_node_t). 1207185029Spjd * Creates vp, which is '.zfs/snapshot' (zfsctl_snapdir_t). 1208185029Spjd * 1209185029Spjd * This function is the callback to create a GFS vnode for '.zfs/snapshot' 1210185029Spjd * when a lookup is performed on .zfs for "snapshot". 1211185029Spjd */ 1212168404Spjdvnode_t * 1213168404Spjdzfsctl_mknode_snapdir(vnode_t *pvp) 1214168404Spjd{ 1215168404Spjd vnode_t *vp; 1216168404Spjd zfsctl_snapdir_t *sdp; 1217168404Spjd 1218168404Spjd vp = gfs_dir_create(sizeof (zfsctl_snapdir_t), pvp, pvp->v_vfsp, 1219168404Spjd &zfsctl_ops_snapdir, NULL, NULL, MAXNAMELEN, 1220168404Spjd zfsctl_snapdir_readdir_cb, NULL); 1221168404Spjd sdp = vp->v_data; 1222168404Spjd sdp->sd_node.zc_id = ZFSCTL_INO_SNAPDIR; 1223168404Spjd sdp->sd_node.zc_cmtime = ((zfsctl_node_t *)pvp->v_data)->zc_cmtime; 1224168404Spjd mutex_init(&sdp->sd_lock, NULL, MUTEX_DEFAULT, NULL); 1225168404Spjd avl_create(&sdp->sd_snaps, snapentry_compare, 1226168404Spjd sizeof (zfs_snapentry_t), offsetof(zfs_snapentry_t, se_node)); 1227182781Spjd VOP_UNLOCK(vp, 0); 1228168404Spjd return (vp); 1229168404Spjd} 1230168404Spjd 1231209962Smmvnode_t * 1232209962Smmzfsctl_mknode_shares(vnode_t *pvp) 1233209962Smm{ 1234209962Smm vnode_t *vp; 1235209962Smm zfsctl_node_t *sdp; 1236209962Smm 1237209962Smm vp = gfs_dir_create(sizeof (zfsctl_node_t), pvp, pvp->v_vfsp, 1238209962Smm &zfsctl_ops_shares, NULL, NULL, MAXNAMELEN, 1239209962Smm NULL, NULL); 1240209962Smm sdp = vp->v_data; 1241209962Smm sdp->zc_cmtime = ((zfsctl_node_t *)pvp->v_data)->zc_cmtime; 1242212605Smm VOP_UNLOCK(vp, 0); 1243209962Smm return (vp); 1244209962Smm 1245209962Smm} 1246209962Smm 1247168404Spjd/* ARGSUSED */ 1248168404Spjdstatic int 1249209962Smmzfsctl_shares_getattr(ap) 1250209962Smm struct vop_getattr_args /* { 1251209962Smm struct vnode *a_vp; 1252209962Smm struct vattr *a_vap; 1253209962Smm struct ucred *a_cred; 1254209962Smm struct thread *a_td; 1255209962Smm } */ *ap; 1256209962Smm{ 1257209962Smm vnode_t *vp = ap->a_vp; 1258209962Smm vattr_t *vap = ap->a_vap; 1259209962Smm cred_t *cr = ap->a_cred; 1260209962Smm zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 1261209962Smm znode_t *dzp; 1262209962Smm int error; 1263209962Smm 1264209962Smm ZFS_ENTER(zfsvfs); 1265209962Smm if (zfsvfs->z_shares_dir == 0) { 1266209962Smm ZFS_EXIT(zfsvfs); 1267209962Smm return (ENOTSUP); 1268209962Smm } 1269209962Smm if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) { 1270212605Smm vn_lock(ZTOV(dzp), LK_SHARED | LK_RETRY); 1271209962Smm error = VOP_GETATTR(ZTOV(dzp), vap, cr); 1272212605Smm VN_URELE(ZTOV(dzp)); 1273209962Smm } 1274209962Smm ZFS_EXIT(zfsvfs); 1275209962Smm return (error); 1276219089Spjd 1277219089Spjd 1278209962Smm} 1279209962Smm 1280209962Smm/* ARGSUSED */ 1281209962Smmstatic int 1282168404Spjdzfsctl_snapdir_getattr(ap) 1283168404Spjd struct vop_getattr_args /* { 1284168404Spjd struct vnode *a_vp; 1285168404Spjd struct vattr *a_vap; 1286168404Spjd struct ucred *a_cred; 1287168404Spjd } */ *ap; 1288168404Spjd{ 1289219089Spjd vnode_t *vp = ap->a_vp; 1290219089Spjd vattr_t *vap = ap->a_vap; 1291168404Spjd zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data; 1292168404Spjd zfsctl_snapdir_t *sdp = vp->v_data; 1293168404Spjd 1294168404Spjd ZFS_ENTER(zfsvfs); 1295168404Spjd zfsctl_common_getattr(vp, vap); 1296168404Spjd vap->va_nodeid = gfs_file_inode(vp); 1297168404Spjd vap->va_nlink = vap->va_size = avl_numnodes(&sdp->sd_snaps) + 2; 1298219089Spjd vap->va_ctime = vap->va_mtime = dmu_objset_snap_cmtime(zfsvfs->z_os); 1299219089Spjd vap->va_birthtime = vap->va_ctime; 1300168404Spjd ZFS_EXIT(zfsvfs); 1301168404Spjd 1302168404Spjd return (0); 1303168404Spjd} 1304168404Spjd 1305168404Spjd/* ARGSUSED */ 1306168404Spjdstatic int 1307168404Spjdzfsctl_snapdir_inactive(ap) 1308168404Spjd struct vop_inactive_args /* { 1309168404Spjd struct vnode *a_vp; 1310168404Spjd struct thread *a_td; 1311168404Spjd } */ *ap; 1312168404Spjd{ 1313168404Spjd vnode_t *vp = ap->a_vp; 1314168404Spjd zfsctl_snapdir_t *sdp = vp->v_data; 1315197515Spjd zfs_snapentry_t *sep; 1316168404Spjd 1317197515Spjd /* 1318197515Spjd * On forced unmount we have to free snapshots from here. 1319197515Spjd */ 1320197515Spjd mutex_enter(&sdp->sd_lock); 1321197515Spjd while ((sep = avl_first(&sdp->sd_snaps)) != NULL) { 1322197515Spjd avl_remove(&sdp->sd_snaps, sep); 1323197515Spjd kmem_free(sep->se_name, strlen(sep->se_name) + 1); 1324197515Spjd kmem_free(sep, sizeof (zfs_snapentry_t)); 1325168404Spjd } 1326197515Spjd mutex_exit(&sdp->sd_lock); 1327197515Spjd gfs_dir_inactive(vp); 1328197515Spjd ASSERT(avl_numnodes(&sdp->sd_snaps) == 0); 1329197515Spjd mutex_destroy(&sdp->sd_lock); 1330197515Spjd avl_destroy(&sdp->sd_snaps); 1331197515Spjd kmem_free(sdp, sizeof (zfsctl_snapdir_t)); 1332197515Spjd 1333168404Spjd return (0); 1334168404Spjd} 1335168404Spjd 1336219089Spjd#ifdef sun 1337219089Spjdstatic const fs_operation_def_t zfsctl_tops_snapdir[] = { 1338219089Spjd { VOPNAME_OPEN, { .vop_open = zfsctl_common_open } }, 1339219089Spjd { VOPNAME_CLOSE, { .vop_close = zfsctl_common_close } }, 1340219089Spjd { VOPNAME_IOCTL, { .error = fs_inval } }, 1341219089Spjd { VOPNAME_GETATTR, { .vop_getattr = zfsctl_snapdir_getattr } }, 1342219089Spjd { VOPNAME_ACCESS, { .vop_access = zfsctl_common_access } }, 1343219089Spjd { VOPNAME_RENAME, { .vop_rename = zfsctl_snapdir_rename } }, 1344219089Spjd { VOPNAME_RMDIR, { .vop_rmdir = zfsctl_snapdir_remove } }, 1345219089Spjd { VOPNAME_MKDIR, { .vop_mkdir = zfsctl_snapdir_mkdir } }, 1346219089Spjd { VOPNAME_READDIR, { .vop_readdir = gfs_vop_readdir } }, 1347219089Spjd { VOPNAME_LOOKUP, { .vop_lookup = zfsctl_snapdir_lookup } }, 1348219089Spjd { VOPNAME_SEEK, { .vop_seek = fs_seek } }, 1349219089Spjd { VOPNAME_INACTIVE, { .vop_inactive = zfsctl_snapdir_inactive } }, 1350219089Spjd { VOPNAME_FID, { .vop_fid = zfsctl_common_fid } }, 1351219089Spjd { NULL } 1352219089Spjd}; 1353219089Spjd 1354219089Spjdstatic const fs_operation_def_t zfsctl_tops_shares[] = { 1355219089Spjd { VOPNAME_OPEN, { .vop_open = zfsctl_common_open } }, 1356219089Spjd { VOPNAME_CLOSE, { .vop_close = zfsctl_common_close } }, 1357219089Spjd { VOPNAME_IOCTL, { .error = fs_inval } }, 1358219089Spjd { VOPNAME_GETATTR, { .vop_getattr = zfsctl_shares_getattr } }, 1359219089Spjd { VOPNAME_ACCESS, { .vop_access = zfsctl_common_access } }, 1360219089Spjd { VOPNAME_READDIR, { .vop_readdir = zfsctl_shares_readdir } }, 1361219089Spjd { VOPNAME_LOOKUP, { .vop_lookup = zfsctl_shares_lookup } }, 1362219089Spjd { VOPNAME_SEEK, { .vop_seek = fs_seek } }, 1363219089Spjd { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } }, 1364219089Spjd { VOPNAME_FID, { .vop_fid = zfsctl_shares_fid } }, 1365219089Spjd { NULL } 1366219089Spjd}; 1367219089Spjd#else /* !sun */ 1368168404Spjdstatic struct vop_vector zfsctl_ops_snapdir = { 1369168404Spjd .vop_default = &default_vnodeops, 1370168404Spjd .vop_open = zfsctl_common_open, 1371168404Spjd .vop_close = zfsctl_common_close, 1372168404Spjd .vop_ioctl = VOP_EINVAL, 1373168404Spjd .vop_getattr = zfsctl_snapdir_getattr, 1374168404Spjd .vop_access = zfsctl_common_access, 1375185029Spjd .vop_mkdir = zfsctl_freebsd_snapdir_mkdir, 1376168404Spjd .vop_readdir = gfs_vop_readdir, 1377168404Spjd .vop_lookup = zfsctl_snapdir_lookup, 1378168404Spjd .vop_inactive = zfsctl_snapdir_inactive, 1379168404Spjd .vop_reclaim = zfsctl_common_reclaim, 1380168404Spjd .vop_fid = zfsctl_common_fid, 1381168404Spjd}; 1382168404Spjd 1383212605Smmstatic struct vop_vector zfsctl_ops_shares = { 1384212605Smm .vop_default = &default_vnodeops, 1385212605Smm .vop_open = zfsctl_common_open, 1386212605Smm .vop_close = zfsctl_common_close, 1387212605Smm .vop_ioctl = VOP_EINVAL, 1388212605Smm .vop_getattr = zfsctl_shares_getattr, 1389212605Smm .vop_access = zfsctl_common_access, 1390212605Smm .vop_readdir = zfsctl_shares_readdir, 1391212605Smm .vop_lookup = zfsctl_shares_lookup, 1392212605Smm .vop_inactive = gfs_vop_inactive, 1393212605Smm .vop_reclaim = zfsctl_common_reclaim, 1394212605Smm .vop_fid = zfsctl_shares_fid, 1395212605Smm}; 1396219089Spjd#endif /* !sun */ 1397212605Smm 1398185029Spjd/* 1399185029Spjd * pvp is the GFS vnode '.zfs/snapshot'. 1400185029Spjd * 1401185029Spjd * This creates a GFS node under '.zfs/snapshot' representing each 1402185029Spjd * snapshot. This newly created GFS node is what we mount snapshot 1403185029Spjd * vfs_t's ontop of. 1404185029Spjd */ 1405168404Spjdstatic vnode_t * 1406168404Spjdzfsctl_snapshot_mknode(vnode_t *pvp, uint64_t objset) 1407168404Spjd{ 1408168404Spjd vnode_t *vp; 1409168404Spjd zfsctl_node_t *zcp; 1410168404Spjd 1411168404Spjd vp = gfs_dir_create(sizeof (zfsctl_node_t), pvp, pvp->v_vfsp, 1412168404Spjd &zfsctl_ops_snapshot, NULL, NULL, MAXNAMELEN, NULL, NULL); 1413185029Spjd VN_HOLD(vp); 1414168404Spjd zcp = vp->v_data; 1415168404Spjd zcp->zc_id = objset; 1416182781Spjd VOP_UNLOCK(vp, 0); 1417168404Spjd 1418168404Spjd return (vp); 1419168404Spjd} 1420168404Spjd 1421168404Spjdstatic int 1422168404Spjdzfsctl_snapshot_inactive(ap) 1423168404Spjd struct vop_inactive_args /* { 1424168404Spjd struct vnode *a_vp; 1425168404Spjd struct thread *a_td; 1426168404Spjd } */ *ap; 1427168404Spjd{ 1428168404Spjd vnode_t *vp = ap->a_vp; 1429185029Spjd cred_t *cr = ap->a_td->td_ucred; 1430168404Spjd struct vop_inactive_args iap; 1431168404Spjd zfsctl_snapdir_t *sdp; 1432168404Spjd zfs_snapentry_t *sep, *next; 1433168404Spjd int locked; 1434168404Spjd vnode_t *dvp; 1435168404Spjd 1436197515Spjd if (vp->v_count > 0) 1437197515Spjd goto end; 1438197515Spjd 1439185029Spjd VERIFY(gfs_dir_lookup(vp, "..", &dvp, cr, 0, NULL, NULL) == 0); 1440168404Spjd sdp = dvp->v_data; 1441175294Sattilio VOP_UNLOCK(dvp, 0); 1442168404Spjd 1443168404Spjd if (!(locked = MUTEX_HELD(&sdp->sd_lock))) 1444168404Spjd mutex_enter(&sdp->sd_lock); 1445168404Spjd 1446168404Spjd ASSERT(!vn_ismntpt(vp)); 1447168404Spjd 1448168404Spjd sep = avl_first(&sdp->sd_snaps); 1449168404Spjd while (sep != NULL) { 1450168404Spjd next = AVL_NEXT(&sdp->sd_snaps, sep); 1451168404Spjd 1452168404Spjd if (sep->se_root == vp) { 1453168404Spjd avl_remove(&sdp->sd_snaps, sep); 1454168404Spjd kmem_free(sep->se_name, strlen(sep->se_name) + 1); 1455168404Spjd kmem_free(sep, sizeof (zfs_snapentry_t)); 1456168404Spjd break; 1457168404Spjd } 1458168404Spjd sep = next; 1459168404Spjd } 1460168404Spjd ASSERT(sep != NULL); 1461168404Spjd 1462168404Spjd if (!locked) 1463168404Spjd mutex_exit(&sdp->sd_lock); 1464168404Spjd VN_RELE(dvp); 1465219089Spjd 1466197515Spjdend: 1467168404Spjd /* 1468168404Spjd * Dispose of the vnode for the snapshot mount point. 1469168404Spjd * This is safe to do because once this entry has been removed 1470168404Spjd * from the AVL tree, it can't be found again, so cannot become 1471168404Spjd * "active". If we lookup the same name again we will end up 1472168404Spjd * creating a new vnode. 1473168404Spjd */ 1474168404Spjd iap.a_vp = vp; 1475168404Spjd return (gfs_vop_inactive(&iap)); 1476168404Spjd} 1477168404Spjd 1478168404Spjdstatic int 1479182371Sattiliozfsctl_traverse_begin(vnode_t **vpp, int lktype) 1480168404Spjd{ 1481168404Spjd 1482168404Spjd VN_HOLD(*vpp); 1483168404Spjd /* Snapshot should be already mounted, but just in case. */ 1484168404Spjd if (vn_mountedvfs(*vpp) == NULL) 1485168404Spjd return (ENOENT); 1486170281Spjd return (traverse(vpp, lktype)); 1487168404Spjd} 1488168404Spjd 1489168404Spjdstatic void 1490168404Spjdzfsctl_traverse_end(vnode_t *vp, int err) 1491168404Spjd{ 1492168404Spjd 1493168404Spjd if (err == 0) 1494168404Spjd vput(vp); 1495168404Spjd else 1496168404Spjd VN_RELE(vp); 1497168404Spjd} 1498168404Spjd 1499168404Spjdstatic int 1500168404Spjdzfsctl_snapshot_getattr(ap) 1501168404Spjd struct vop_getattr_args /* { 1502168404Spjd struct vnode *a_vp; 1503168404Spjd struct vattr *a_vap; 1504168404Spjd struct ucred *a_cred; 1505168404Spjd } */ *ap; 1506168404Spjd{ 1507168404Spjd vnode_t *vp = ap->a_vp; 1508168404Spjd int err; 1509168404Spjd 1510182371Sattilio err = zfsctl_traverse_begin(&vp, LK_SHARED | LK_RETRY); 1511168404Spjd if (err == 0) 1512182371Sattilio err = VOP_GETATTR(vp, ap->a_vap, ap->a_cred); 1513168404Spjd zfsctl_traverse_end(vp, err); 1514168404Spjd return (err); 1515168404Spjd} 1516168404Spjd 1517168404Spjdstatic int 1518168404Spjdzfsctl_snapshot_fid(ap) 1519168404Spjd struct vop_fid_args /* { 1520168404Spjd struct vnode *a_vp; 1521168404Spjd struct fid *a_fid; 1522168404Spjd } */ *ap; 1523168404Spjd{ 1524168404Spjd vnode_t *vp = ap->a_vp; 1525168404Spjd int err; 1526168404Spjd 1527182371Sattilio err = zfsctl_traverse_begin(&vp, LK_SHARED | LK_RETRY); 1528168404Spjd if (err == 0) 1529168404Spjd err = VOP_VPTOFH(vp, (void *)ap->a_fid); 1530168404Spjd zfsctl_traverse_end(vp, err); 1531168404Spjd return (err); 1532168404Spjd} 1533168404Spjd 1534185029Spjdstatic int 1535185029Spjdzfsctl_snapshot_lookup(ap) 1536185029Spjd struct vop_lookup_args /* { 1537185029Spjd struct vnode *a_dvp; 1538185029Spjd struct vnode **a_vpp; 1539185029Spjd struct componentname *a_cnp; 1540185029Spjd } */ *ap; 1541185029Spjd{ 1542185029Spjd vnode_t *dvp = ap->a_dvp; 1543185029Spjd vnode_t **vpp = ap->a_vpp; 1544185029Spjd struct componentname *cnp = ap->a_cnp; 1545185029Spjd cred_t *cr = ap->a_cnp->cn_cred; 1546185029Spjd zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; 1547185029Spjd int error; 1548185029Spjd 1549185029Spjd if (cnp->cn_namelen != 2 || cnp->cn_nameptr[0] != '.' || 1550185029Spjd cnp->cn_nameptr[1] != '.') { 1551185029Spjd return (ENOENT); 1552185029Spjd } 1553185029Spjd 1554185029Spjd ASSERT(dvp->v_type == VDIR); 1555185029Spjd ASSERT(zfsvfs->z_ctldir != NULL); 1556185029Spjd 1557185029Spjd error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", vpp, 1558185029Spjd NULL, 0, NULL, cr, NULL, NULL, NULL); 1559185029Spjd if (error == 0) 1560185029Spjd vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); 1561185029Spjd return (error); 1562185029Spjd} 1563185029Spjd 1564196309Spjdstatic int 1565196309Spjdzfsctl_snapshot_vptocnp(struct vop_vptocnp_args *ap) 1566196309Spjd{ 1567196309Spjd zfsvfs_t *zfsvfs = ap->a_vp->v_vfsp->vfs_data; 1568196309Spjd vnode_t *dvp, *vp; 1569196309Spjd zfsctl_snapdir_t *sdp; 1570196309Spjd zfs_snapentry_t *sep; 1571196309Spjd int error; 1572196309Spjd 1573196309Spjd ASSERT(zfsvfs->z_ctldir != NULL); 1574196309Spjd error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp, 1575196309Spjd NULL, 0, NULL, kcred, NULL, NULL, NULL); 1576196309Spjd if (error != 0) 1577196309Spjd return (error); 1578196309Spjd sdp = dvp->v_data; 1579196309Spjd 1580196309Spjd mutex_enter(&sdp->sd_lock); 1581196309Spjd sep = avl_first(&sdp->sd_snaps); 1582196309Spjd while (sep != NULL) { 1583196309Spjd vp = sep->se_root; 1584196309Spjd if (vp == ap->a_vp) 1585196309Spjd break; 1586196309Spjd sep = AVL_NEXT(&sdp->sd_snaps, sep); 1587196309Spjd } 1588196309Spjd if (sep == NULL) { 1589196309Spjd mutex_exit(&sdp->sd_lock); 1590196309Spjd error = ENOENT; 1591196309Spjd } else { 1592196309Spjd size_t len; 1593196309Spjd 1594196309Spjd len = strlen(sep->se_name); 1595196309Spjd *ap->a_buflen -= len; 1596196309Spjd bcopy(sep->se_name, ap->a_buf + *ap->a_buflen, len); 1597196309Spjd mutex_exit(&sdp->sd_lock); 1598229703Skib vref(dvp); 1599196309Spjd *ap->a_vpp = dvp; 1600196309Spjd } 1601196309Spjd VN_RELE(dvp); 1602196309Spjd 1603196309Spjd return (error); 1604196309Spjd} 1605196309Spjd 1606168404Spjd/* 1607168404Spjd * These VP's should never see the light of day. They should always 1608168404Spjd * be covered. 1609168404Spjd */ 1610168404Spjdstatic struct vop_vector zfsctl_ops_snapshot = { 1611168404Spjd .vop_default = &default_vnodeops, 1612168404Spjd .vop_inactive = zfsctl_snapshot_inactive, 1613185029Spjd .vop_lookup = zfsctl_snapshot_lookup, 1614168404Spjd .vop_reclaim = zfsctl_common_reclaim, 1615168404Spjd .vop_getattr = zfsctl_snapshot_getattr, 1616168404Spjd .vop_fid = zfsctl_snapshot_fid, 1617196309Spjd .vop_vptocnp = zfsctl_snapshot_vptocnp, 1618168404Spjd}; 1619168404Spjd 1620168404Spjdint 1621168404Spjdzfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t **zfsvfsp) 1622168404Spjd{ 1623168404Spjd zfsvfs_t *zfsvfs = vfsp->vfs_data; 1624168404Spjd vnode_t *dvp, *vp; 1625168404Spjd zfsctl_snapdir_t *sdp; 1626168404Spjd zfsctl_node_t *zcp; 1627168404Spjd zfs_snapentry_t *sep; 1628168404Spjd int error; 1629168404Spjd 1630168404Spjd ASSERT(zfsvfs->z_ctldir != NULL); 1631168404Spjd error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp, 1632185029Spjd NULL, 0, NULL, kcred, NULL, NULL, NULL); 1633168404Spjd if (error != 0) 1634168404Spjd return (error); 1635168404Spjd sdp = dvp->v_data; 1636168404Spjd 1637168404Spjd mutex_enter(&sdp->sd_lock); 1638168404Spjd sep = avl_first(&sdp->sd_snaps); 1639168404Spjd while (sep != NULL) { 1640168404Spjd vp = sep->se_root; 1641168404Spjd zcp = vp->v_data; 1642168404Spjd if (zcp->zc_id == objsetid) 1643168404Spjd break; 1644168404Spjd 1645168404Spjd sep = AVL_NEXT(&sdp->sd_snaps, sep); 1646168404Spjd } 1647168404Spjd 1648168404Spjd if (sep != NULL) { 1649168404Spjd VN_HOLD(vp); 1650185029Spjd /* 1651185029Spjd * Return the mounted root rather than the covered mount point. 1652185029Spjd * Takes the GFS vnode at .zfs/snapshot/<snapshot objsetid> 1653185029Spjd * and returns the ZFS vnode mounted on top of the GFS node. 1654185029Spjd * This ZFS vnode is the root of the vfs for objset 'objsetid'. 1655185029Spjd */ 1656170281Spjd error = traverse(&vp, LK_SHARED | LK_RETRY); 1657168404Spjd if (error == 0) { 1658168404Spjd if (vp == sep->se_root) 1659168404Spjd error = EINVAL; 1660168404Spjd else 1661168404Spjd *zfsvfsp = VTOZ(vp)->z_zfsvfs; 1662168404Spjd } 1663168404Spjd mutex_exit(&sdp->sd_lock); 1664170281Spjd if (error == 0) 1665170281Spjd VN_URELE(vp); 1666170281Spjd else 1667170281Spjd VN_RELE(vp); 1668168404Spjd } else { 1669168404Spjd error = EINVAL; 1670168404Spjd mutex_exit(&sdp->sd_lock); 1671168404Spjd } 1672168404Spjd 1673168404Spjd VN_RELE(dvp); 1674168404Spjd 1675168404Spjd return (error); 1676168404Spjd} 1677168404Spjd 1678168404Spjd/* 1679168404Spjd * Unmount any snapshots for the given filesystem. This is called from 1680168404Spjd * zfs_umount() - if we have a ctldir, then go through and unmount all the 1681168404Spjd * snapshots. 1682168404Spjd */ 1683168404Spjdint 1684168404Spjdzfsctl_umount_snapshots(vfs_t *vfsp, int fflags, cred_t *cr) 1685168404Spjd{ 1686168404Spjd zfsvfs_t *zfsvfs = vfsp->vfs_data; 1687185029Spjd vnode_t *dvp; 1688168404Spjd zfsctl_snapdir_t *sdp; 1689168404Spjd zfs_snapentry_t *sep, *next; 1690168404Spjd int error; 1691168404Spjd 1692168404Spjd ASSERT(zfsvfs->z_ctldir != NULL); 1693168404Spjd error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp, 1694185029Spjd NULL, 0, NULL, cr, NULL, NULL, NULL); 1695168404Spjd if (error != 0) 1696168404Spjd return (error); 1697168404Spjd sdp = dvp->v_data; 1698168404Spjd 1699168404Spjd mutex_enter(&sdp->sd_lock); 1700168404Spjd 1701168404Spjd sep = avl_first(&sdp->sd_snaps); 1702168404Spjd while (sep != NULL) { 1703168404Spjd next = AVL_NEXT(&sdp->sd_snaps, sep); 1704168404Spjd 1705168404Spjd /* 1706168404Spjd * If this snapshot is not mounted, then it must 1707168404Spjd * have just been unmounted by somebody else, and 1708168404Spjd * will be cleaned up by zfsctl_snapdir_inactive(). 1709168404Spjd */ 1710185029Spjd if (vn_ismntpt(sep->se_root)) { 1711185029Spjd error = zfsctl_unmount_snap(sep, fflags, cr); 1712185029Spjd if (error) { 1713196954Spjd avl_index_t where; 1714196954Spjd 1715196953Spjd /* 1716196953Spjd * Before reinserting snapshot to the tree, 1717196953Spjd * check if it was actually removed. For example 1718196953Spjd * when snapshot mount point is busy, we will 1719196953Spjd * have an error here, but there will be no need 1720196953Spjd * to reinsert snapshot. 1721196953Spjd */ 1722196954Spjd if (avl_find(&sdp->sd_snaps, sep, &where) == NULL) 1723196954Spjd avl_insert(&sdp->sd_snaps, sep, where); 1724185029Spjd break; 1725168404Spjd } 1726168404Spjd } 1727168404Spjd sep = next; 1728168404Spjd } 1729185029Spjd 1730168404Spjd mutex_exit(&sdp->sd_lock); 1731168404Spjd VN_RELE(dvp); 1732168404Spjd 1733168404Spjd return (error); 1734168404Spjd} 1735