FreeBSD ZFS
The Zettabyte File System

zfs_ctldir.c

Go to the documentation of this file.
00001 /*
00002  * CDDL HEADER START
00003  *
00004  * The contents of this file are subject to the terms of the
00005  * Common Development and Distribution License (the "License").
00006  * You may not use this file except in compliance with the License.
00007  *
00008  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
00009  * or http://www.opensolaris.org/os/licensing.
00010  * See the License for the specific language governing permissions
00011  * and limitations under the License.
00012  *
00013  * When distributing Covered Code, include this CDDL HEADER in each
00014  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
00015  * If applicable, add the following below this CDDL HEADER, with the
00016  * fields enclosed by brackets "[]" replaced with your own identifying
00017  * information: Portions Copyright [yyyy] [name of copyright owner]
00018  *
00019  * CDDL HEADER END
00020  */
00021 /*
00022  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
00023  * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>.
00024  * All rights reserved.
00025  */
00026 
00071 #include <sys/zfs_context.h>
00072 #include <sys/zfs_ctldir.h>
00073 #include <sys/zfs_ioctl.h>
00074 #include <sys/zfs_vfsops.h>
00075 #include <sys/namei.h>
00076 #include <sys/gfs.h>
00077 #include <sys/stat.h>
00078 #include <sys/dmu.h>
00079 #include <sys/dsl_deleg.h>
00080 #include <sys/mount.h>
00081 #include <sys/sunddi.h>
00082 
00083 #include "zfs_namecheck.h"
00084 
00085 typedef struct zfsctl_node {
00086         gfs_dir_t       zc_gfs_private;
00087         uint64_t        zc_id;
00088         timestruc_t     zc_cmtime;      
00089 } zfsctl_node_t;
00090 
00091 typedef struct zfsctl_snapdir {
00092         zfsctl_node_t   sd_node;
00093         kmutex_t        sd_lock;
00094         avl_tree_t      sd_snaps;
00095 } zfsctl_snapdir_t;
00096 
00097 typedef struct {
00098         char            *se_name;
00099         vnode_t         *se_root;
00100         avl_node_t      se_node;
00101 } zfs_snapentry_t;
00102 
00103 static int
00104 snapentry_compare(const void *a, const void *b)
00105 {
00106         const zfs_snapentry_t *sa = a;
00107         const zfs_snapentry_t *sb = b;
00108         int ret = strcmp(sa->se_name, sb->se_name);
00109 
00110         if (ret < 0)
00111                 return (-1);
00112         else if (ret > 0)
00113                 return (1);
00114         else
00115                 return (0);
00116 }
00117 
00118 #ifdef sun
00119 vnodeops_t *zfsctl_ops_root;
00120 vnodeops_t *zfsctl_ops_snapdir;
00121 vnodeops_t *zfsctl_ops_snapshot;
00122 vnodeops_t *zfsctl_ops_shares;
00123 vnodeops_t *zfsctl_ops_shares_dir;
00124 
00125 static const fs_operation_def_t zfsctl_tops_root[];
00126 static const fs_operation_def_t zfsctl_tops_snapdir[];
00127 static const fs_operation_def_t zfsctl_tops_snapshot[];
00128 static const fs_operation_def_t zfsctl_tops_shares[];
00129 #else   /* !sun */
00130 static struct vop_vector zfsctl_ops_root;
00131 static struct vop_vector zfsctl_ops_snapdir;
00132 static struct vop_vector zfsctl_ops_snapshot;
00133 static struct vop_vector zfsctl_ops_shares;
00134 static struct vop_vector zfsctl_ops_shares_dir;
00135 #endif  /* !sun */
00136 
00137 static vnode_t *zfsctl_mknode_snapdir(vnode_t *);
00138 static vnode_t *zfsctl_mknode_shares(vnode_t *);
00139 static vnode_t *zfsctl_snapshot_mknode(vnode_t *, uint64_t objset);
00140 static int zfsctl_unmount_snap(zfs_snapentry_t *, int, cred_t *);
00141 
00142 #ifdef sun
00143 static gfs_opsvec_t zfsctl_opsvec[] = {
00144         { ".zfs", zfsctl_tops_root, &zfsctl_ops_root },
00145         { ".zfs/snapshot", zfsctl_tops_snapdir, &zfsctl_ops_snapdir },
00146         { ".zfs/snapshot/vnode", zfsctl_tops_snapshot, &zfsctl_ops_snapshot },
00147         { ".zfs/shares", zfsctl_tops_shares, &zfsctl_ops_shares_dir },
00148         { ".zfs/shares/vnode", zfsctl_tops_shares, &zfsctl_ops_shares },
00149         { NULL }
00150 };
00151 #endif  /* sun */
00152 
00157 static gfs_dirent_t zfsctl_root_entries[] = {
00158         { "snapshot", zfsctl_mknode_snapdir, GFS_CACHE_VNODE },
00159         { "shares", zfsctl_mknode_shares, GFS_CACHE_VNODE },
00160         { NULL }
00161 };
00162 
00163 /* include . and .. in the calculation */
00164 #define NROOT_ENTRIES   ((sizeof (zfsctl_root_entries) / \
00165     sizeof (gfs_dirent_t)) + 1)
00166 
00167 
00173 void
00174 zfsctl_init(void)
00175 {
00176 #ifdef sun
00177         VERIFY(gfs_make_opsvec(zfsctl_opsvec) == 0);
00178 #endif
00179 }
00180 
00181 void
00182 zfsctl_fini(void)
00183 {
00184 #ifdef sun
00185         /*
00186          * Remove vfsctl vnode ops
00187          */
00188         if (zfsctl_ops_root)
00189                 vn_freevnodeops(zfsctl_ops_root);
00190         if (zfsctl_ops_snapdir)
00191                 vn_freevnodeops(zfsctl_ops_snapdir);
00192         if (zfsctl_ops_snapshot)
00193                 vn_freevnodeops(zfsctl_ops_snapshot);
00194         if (zfsctl_ops_shares)
00195                 vn_freevnodeops(zfsctl_ops_shares);
00196         if (zfsctl_ops_shares_dir)
00197                 vn_freevnodeops(zfsctl_ops_shares_dir);
00198 
00199         zfsctl_ops_root = NULL;
00200         zfsctl_ops_snapdir = NULL;
00201         zfsctl_ops_snapshot = NULL;
00202         zfsctl_ops_shares = NULL;
00203         zfsctl_ops_shares_dir = NULL;
00204 #endif  /* sun */
00205 }
00206 
00207 boolean_t
00208 zfsctl_is_node(vnode_t *vp)
00209 {
00210         return (vn_matchops(vp, zfsctl_ops_root) ||
00211             vn_matchops(vp, zfsctl_ops_snapdir) ||
00212             vn_matchops(vp, zfsctl_ops_snapshot) ||
00213             vn_matchops(vp, zfsctl_ops_shares) ||
00214             vn_matchops(vp, zfsctl_ops_shares_dir));
00215 
00216 }
00217 
00222 /* ARGSUSED */
00223 static ino64_t
00224 zfsctl_root_inode_cb(vnode_t *vp, int index)
00225 {
00226         zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
00227 
00228         ASSERT(index <= 2);
00229 
00230         if (index == 0)
00231                 return (ZFSCTL_INO_SNAPDIR);
00232 
00233         return (zfsvfs->z_shares_dir);
00234 }
00235 
00242 void
00243 zfsctl_create(zfsvfs_t *zfsvfs)
00244 {
00245         vnode_t *vp, *rvp;
00246         zfsctl_node_t *zcp;
00247         uint64_t crtime[2];
00248 
00249         ASSERT(zfsvfs->z_ctldir == NULL);
00250 
00251         vp = gfs_root_create(sizeof (zfsctl_node_t), zfsvfs->z_vfs,
00252             &zfsctl_ops_root, ZFSCTL_INO_ROOT, zfsctl_root_entries,
00253             zfsctl_root_inode_cb, MAXNAMELEN, NULL, NULL);
00254         zcp = vp->v_data;
00255         zcp->zc_id = ZFSCTL_INO_ROOT;
00256 
00257         VERIFY(VFS_ROOT(zfsvfs->z_vfs, LK_EXCLUSIVE, &rvp) == 0);
00258         VERIFY(0 == sa_lookup(VTOZ(rvp)->z_sa_hdl, SA_ZPL_CRTIME(zfsvfs),
00259             &crtime, sizeof (crtime)));
00260         ZFS_TIME_DECODE(&zcp->zc_cmtime, crtime);
00261         VN_URELE(rvp);
00262 
00263         /*
00264          * We're only faking the fact that we have a root of a filesystem for
00265          * the sake of the GFS interfaces.  Undo the flag manipulation it did
00266          * for us.
00267          */
00268         vp->v_vflag &= ~VV_ROOT;
00269 
00270         zfsvfs->z_ctldir = vp;
00271 
00272         VOP_UNLOCK(vp, 0);
00273 }
00274 
00280 void
00281 zfsctl_destroy(zfsvfs_t *zfsvfs)
00282 {
00283         VN_RELE(zfsvfs->z_ctldir);
00284         zfsvfs->z_ctldir = NULL;
00285 }
00286 
00291 vnode_t *
00292 zfsctl_root(znode_t *zp)
00293 {
00294         ASSERT(zfs_has_ctldir(zp));
00295         VN_HOLD(zp->z_zfsvfs->z_ctldir);
00296         return (zp->z_zfsvfs->z_ctldir);
00297 }
00298 
00302 /* ARGSUSED */
00303 static int
00304 zfsctl_common_open(struct vop_open_args *ap)
00305 {
00306         int flags = ap->a_mode;
00307 
00308         if (flags & FWRITE)
00309                 return (EACCES);
00310 
00311         return (0);
00312 }
00313 
00317 /* ARGSUSED */
00318 static int
00319 zfsctl_common_close(struct vop_close_args *ap)
00320 {
00321         return (0);
00322 }
00323 
00327 /* ARGSUSED */
00328 static int
00329 zfsctl_common_access(ap)
00330         struct vop_access_args /* {
00331                 struct vnode *a_vp;
00332                 accmode_t a_accmode;
00333                 struct ucred *a_cred;
00334                 struct thread *a_td;
00335         } */ *ap;
00336 {
00337         accmode_t accmode = ap->a_accmode;
00338 
00339 #ifdef TODO
00340         if (flags & V_ACE_MASK) {
00341                 if (accmode & ACE_ALL_WRITE_PERMS)
00342                         return (EACCES);
00343         } else {
00344 #endif
00345                 if (accmode & VWRITE)
00346                         return (EACCES);
00347 #ifdef TODO
00348         }
00349 #endif
00350 
00351         return (0);
00352 }
00353 
00357 static void
00358 zfsctl_common_getattr(vnode_t *vp, vattr_t *vap)
00359 {
00360         timestruc_t     now;
00361 
00362         vap->va_uid = 0;
00363         vap->va_gid = 0;
00364         vap->va_rdev = 0;
00365         /*
00366          * We are a purely virtual object, so we have no
00367          * blocksize or allocated blocks.
00368          */
00369         vap->va_blksize = 0;
00370         vap->va_nblocks = 0;
00371         vap->va_seq = 0;
00372         vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
00373         vap->va_mode = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP |
00374             S_IROTH | S_IXOTH;
00375         vap->va_type = VDIR;
00376         /*
00377          * We live in the now (for atime).
00378          */
00379         gethrestime(&now);
00380         vap->va_atime = now;
00381         /* FreeBSD: Reset chflags(2) flags. */
00382         vap->va_flags = 0;
00383 }
00384 
00385 /*ARGSUSED*/
00386 static int
00387 zfsctl_common_fid(ap)
00388         struct vop_fid_args /* {
00389                 struct vnode *a_vp;
00390                 struct fid *a_fid;
00391         } */ *ap;
00392 {
00393         vnode_t         *vp = ap->a_vp;
00394         fid_t           *fidp = (void *)ap->a_fid;
00395         zfsvfs_t        *zfsvfs = vp->v_vfsp->vfs_data;
00396         zfsctl_node_t   *zcp = vp->v_data;
00397         uint64_t        object = zcp->zc_id;
00398         zfid_short_t    *zfid;
00399         int             i;
00400 
00401         ZFS_ENTER(zfsvfs);
00402 
00403         fidp->fid_len = SHORT_FID_LEN;
00404 
00405         zfid = (zfid_short_t *)fidp;
00406 
00407         zfid->zf_len = SHORT_FID_LEN;
00408 
00409         for (i = 0; i < sizeof (zfid->zf_object); i++)
00410                 zfid->zf_object[i] = (uint8_t)(object >> (8 * i));
00411 
00412         /* .zfs znodes always have a generation number of 0 */
00413         for (i = 0; i < sizeof (zfid->zf_gen); i++)
00414                 zfid->zf_gen[i] = 0;
00415 
00416         ZFS_EXIT(zfsvfs);
00417         return (0);
00418 }
00419 
00420 
00421 /*ARGSUSED*/
00422 static int
00423 zfsctl_shares_fid(ap)
00424         struct vop_fid_args /* {
00425                 struct vnode *a_vp;
00426                 struct fid *a_fid;
00427         } */ *ap;
00428 {
00429         vnode_t         *vp = ap->a_vp;
00430         fid_t           *fidp = (void *)ap->a_fid;
00431         zfsvfs_t        *zfsvfs = vp->v_vfsp->vfs_data;
00432         znode_t         *dzp;
00433         int             error;
00434 
00435         ZFS_ENTER(zfsvfs);
00436 
00437         if (zfsvfs->z_shares_dir == 0) {
00438                 ZFS_EXIT(zfsvfs);
00439                 return (ENOTSUP);
00440         }
00441 
00442         if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) {
00443                 error = VOP_FID(ZTOV(dzp), fidp);
00444                 VN_RELE(ZTOV(dzp));
00445         }
00446 
00447         ZFS_EXIT(zfsvfs);
00448         return (error);
00449 }
00450 
00451 static int
00452 zfsctl_common_reclaim(ap)
00453         struct vop_reclaim_args /* {
00454                 struct vnode *a_vp;
00455                 struct thread *a_td;
00456         } */ *ap;
00457 {
00458         vnode_t *vp = ap->a_vp;
00459 
00460         /*
00461          * Destroy the vm object and flush associated pages.
00462          */
00463         vnode_destroy_vobject(vp);
00464         VI_LOCK(vp);
00465         vp->v_data = NULL;
00466         VI_UNLOCK(vp);
00467         return (0);
00468 }
00469 
00482 #define ZFSCTL_INO_SNAP(id)     (id)
00483 
00487 /* ARGSUSED */
00488 static int
00489 zfsctl_root_getattr(ap)
00490         struct vop_getattr_args /* {
00491                 struct vnode *a_vp;
00492                 struct vattr *a_vap;
00493                 struct ucred *a_cred;
00494         } */ *ap;
00495 {
00496         struct vnode *vp = ap->a_vp;
00497         struct vattr *vap = ap->a_vap;
00498         zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
00499         zfsctl_node_t *zcp = vp->v_data;
00500 
00501         ZFS_ENTER(zfsvfs);
00502         vap->va_nodeid = ZFSCTL_INO_ROOT;
00503         vap->va_nlink = vap->va_size = NROOT_ENTRIES;
00504         vap->va_mtime = vap->va_ctime = zcp->zc_cmtime;
00505         vap->va_birthtime = vap->va_ctime;
00506 
00507         zfsctl_common_getattr(vp, vap);
00508         ZFS_EXIT(zfsvfs);
00509 
00510         return (0);
00511 }
00512 
00516 /* ARGSUSED */
00517 int
00518 zfsctl_root_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
00519     int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
00520     int *direntflags, pathname_t *realpnp)
00521 {
00522         zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
00523         int err;
00524 
00525         /*
00526          * No extended attributes allowed under .zfs
00527          */
00528         if (flags & LOOKUP_XATTR)
00529                 return (EINVAL);
00530 
00531         ZFS_ENTER(zfsvfs);
00532 
00533         if (strcmp(nm, "..") == 0) {
00534                 err = VFS_ROOT(dvp->v_vfsp, LK_EXCLUSIVE, vpp);
00535                 if (err == 0)
00536                         VOP_UNLOCK(*vpp, 0);
00537         } else {
00538                 err = gfs_vop_lookup(dvp, nm, vpp, pnp, flags, rdir,
00539                     cr, ct, direntflags, realpnp);
00540         }
00541 
00542         ZFS_EXIT(zfsvfs);
00543 
00544         return (err);
00545 }
00546 
00547 #ifdef sun
00548 static int
00549 zfsctl_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
00550     caller_context_t *ct)
00551 {
00552         /*
00553          * We only care about ACL_ENABLED so that libsec can
00554          * display ACL correctly and not default to POSIX draft.
00555          */
00556         if (cmd == _PC_ACL_ENABLED) {
00557                 *valp = _ACL_ACE_ENABLED;
00558                 return (0);
00559         }
00560 
00561         return (fs_pathconf(vp, cmd, valp, cr, ct));
00562 }
00563 #endif  /* sun */
00564 
00565 #ifdef sun
00566 static const fs_operation_def_t zfsctl_tops_root[] = {
00567         { VOPNAME_OPEN,         { .vop_open = zfsctl_common_open }      },
00568         { VOPNAME_CLOSE,        { .vop_close = zfsctl_common_close }    },
00569         { VOPNAME_IOCTL,        { .error = fs_inval }                   },
00570         { VOPNAME_GETATTR,      { .vop_getattr = zfsctl_root_getattr }  },
00571         { VOPNAME_ACCESS,       { .vop_access = zfsctl_common_access }  },
00572         { VOPNAME_READDIR,      { .vop_readdir = gfs_vop_readdir }      },
00573         { VOPNAME_LOOKUP,       { .vop_lookup = zfsctl_root_lookup }    },
00574         { VOPNAME_SEEK,         { .vop_seek = fs_seek }                 },
00575         { VOPNAME_INACTIVE,     { .vop_inactive = gfs_vop_inactive }    },
00576         { VOPNAME_PATHCONF,     { .vop_pathconf = zfsctl_pathconf }     },
00577         { VOPNAME_FID,          { .vop_fid = zfsctl_common_fid  }       },
00578         { NULL }
00579 };
00580 #endif  /* sun */
00581 
00585 /* ARGSUSED */
00586 int
00587 zfsctl_freebsd_root_lookup(ap)
00588         struct vop_lookup_args /* {
00589                 struct vnode *a_dvp;
00590                 struct vnode **a_vpp;
00591                 struct componentname *a_cnp;
00592         } */ *ap;
00593 {
00594         vnode_t *dvp = ap->a_dvp;
00595         vnode_t **vpp = ap->a_vpp;
00596         cred_t *cr = ap->a_cnp->cn_cred;
00597         int flags = ap->a_cnp->cn_flags;
00598         int nameiop = ap->a_cnp->cn_nameiop;
00599         char nm[NAME_MAX + 1];
00600         int err;
00601 
00602         if ((flags & ISLASTCN) && (nameiop == RENAME || nameiop == CREATE))
00603                 return (EOPNOTSUPP);
00604 
00605         ASSERT(ap->a_cnp->cn_namelen < sizeof(nm));
00606         strlcpy(nm, ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen + 1);
00607 
00608         err = zfsctl_root_lookup(dvp, nm, vpp, NULL, 0, NULL, cr, NULL, NULL, NULL);
00609         if (err == 0 && (nm[0] != '.' || nm[1] != '\0'))
00610                 vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY);
00611         return (err);
00612 }
00613 
00614 static struct vop_vector zfsctl_ops_root = {
00615         .vop_default =  &default_vnodeops,
00616         .vop_open =     zfsctl_common_open,
00617         .vop_close =    zfsctl_common_close,
00618         .vop_ioctl =    VOP_EINVAL,
00619         .vop_getattr =  zfsctl_root_getattr,
00620         .vop_access =   zfsctl_common_access,
00621         .vop_readdir =  gfs_vop_readdir,
00622         .vop_lookup =   zfsctl_freebsd_root_lookup,
00623         .vop_inactive = gfs_vop_inactive,
00624         .vop_reclaim =  zfsctl_common_reclaim,
00625 #ifdef TODO
00626         .vop_pathconf = zfsctl_pathconf,
00627 #endif
00628         .vop_fid =      zfsctl_common_fid,
00629 };
00630 
00631 static int
00632 zfsctl_snapshot_zname(vnode_t *vp, const char *name, int len, char *zname)
00633 {
00634         objset_t *os = ((zfsvfs_t *)((vp)->v_vfsp->vfs_data))->z_os;
00635 
00636         if (snapshot_namecheck(name, NULL, NULL) != 0)
00637                 return (EILSEQ);
00638         dmu_objset_name(os, zname);
00639         if (strlen(zname) + 1 + strlen(name) >= len)
00640                 return (ENAMETOOLONG);
00641         (void) strcat(zname, "@");
00642         (void) strcat(zname, name);
00643         return (0);
00644 }
00645 
00646 static int
00647 zfsctl_unmount_snap(zfs_snapentry_t *sep, int fflags, cred_t *cr)
00648 {
00649         vnode_t *svp = sep->se_root;
00650         int error;
00651 
00652         ASSERT(vn_ismntpt(svp));
00653 
00654         /* this will be dropped by dounmount() */
00655         if ((error = vn_vfswlock(svp)) != 0)
00656                 return (error);
00657 
00658 #ifdef sun
00659         VN_HOLD(svp);
00660         error = dounmount(vn_mountedvfs(svp), fflags, cr);
00661         if (error) {
00662                 VN_RELE(svp);
00663                 return (error);
00664         }
00665 
00666         /*
00667          * We can't use VN_RELE(), as that will try to invoke
00668          * zfsctl_snapdir_inactive(), which would cause us to destroy
00669          * the sd_lock mutex held by our caller.
00670          */
00671         ASSERT(svp->v_count == 1);
00672         gfs_vop_inactive(svp, cr, NULL);
00673 
00674         kmem_free(sep->se_name, strlen(sep->se_name) + 1);
00675         kmem_free(sep, sizeof (zfs_snapentry_t));
00676 
00677         return (0);
00678 #else   /* !sun */
00679         return (dounmount(vn_mountedvfs(svp), fflags, curthread));
00680 #endif  /* !sun */
00681 }
00682 
00683 #ifdef sun
00684 static void
00685 zfsctl_rename_snap(zfsctl_snapdir_t *sdp, zfs_snapentry_t *sep, const char *nm)
00686 {
00687         avl_index_t where;
00688         vfs_t *vfsp;
00689         refstr_t *pathref;
00690         char newpath[MAXNAMELEN];
00691         char *tail;
00692 
00693         ASSERT(MUTEX_HELD(&sdp->sd_lock));
00694         ASSERT(sep != NULL);
00695 
00696         vfsp = vn_mountedvfs(sep->se_root);
00697         ASSERT(vfsp != NULL);
00698 
00699         vfs_lock_wait(vfsp);
00700 
00701         /*
00702          * Change the name in the AVL tree.
00703          */
00704         avl_remove(&sdp->sd_snaps, sep);
00705         kmem_free(sep->se_name, strlen(sep->se_name) + 1);
00706         sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP);
00707         (void) strcpy(sep->se_name, nm);
00708         VERIFY(avl_find(&sdp->sd_snaps, sep, &where) == NULL);
00709         avl_insert(&sdp->sd_snaps, sep, where);
00710 
00711         /*
00712          * Change the current mountpoint info:
00713          *      - update the tail of the mntpoint path
00714          *      - update the tail of the resource path
00715          */
00716         pathref = vfs_getmntpoint(vfsp);
00717         (void) strncpy(newpath, refstr_value(pathref), sizeof (newpath));
00718         VERIFY((tail = strrchr(newpath, '/')) != NULL);
00719         *(tail+1) = '\0';
00720         ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath));
00721         (void) strcat(newpath, nm);
00722         refstr_rele(pathref);
00723         vfs_setmntpoint(vfsp, newpath, 0);
00724 
00725         pathref = vfs_getresource(vfsp);
00726         (void) strncpy(newpath, refstr_value(pathref), sizeof (newpath));
00727         VERIFY((tail = strrchr(newpath, '@')) != NULL);
00728         *(tail+1) = '\0';
00729         ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath));
00730         (void) strcat(newpath, nm);
00731         refstr_rele(pathref);
00732         vfs_setresource(vfsp, newpath, 0);
00733 
00734         vfs_unlock(vfsp);
00735 }
00736 #endif  /* sun */
00737 
00738 #ifdef sun
00739 /*ARGSUSED*/
00740 static int
00741 zfsctl_snapdir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
00742     cred_t *cr, caller_context_t *ct, int flags)
00743 {
00744         zfsctl_snapdir_t *sdp = sdvp->v_data;
00745         zfs_snapentry_t search, *sep;
00746         zfsvfs_t *zfsvfs;
00747         avl_index_t where;
00748         char from[MAXNAMELEN], to[MAXNAMELEN];
00749         char real[MAXNAMELEN];
00750         int err;
00751 
00752         zfsvfs = sdvp->v_vfsp->vfs_data;
00753         ZFS_ENTER(zfsvfs);
00754 
00755         if ((flags & FIGNORECASE) || zfsvfs->z_case == ZFS_CASE_INSENSITIVE) {
00756                 err = dmu_snapshot_realname(zfsvfs->z_os, snm, real,
00757                     MAXNAMELEN, NULL);
00758                 if (err == 0) {
00759                         snm = real;
00760                 } else if (err != ENOTSUP) {
00761                         ZFS_EXIT(zfsvfs);
00762                         return (err);
00763                 }
00764         }
00765 
00766         ZFS_EXIT(zfsvfs);
00767 
00768         err = zfsctl_snapshot_zname(sdvp, snm, MAXNAMELEN, from);
00769         if (!err)
00770                 err = zfsctl_snapshot_zname(tdvp, tnm, MAXNAMELEN, to);
00771         if (!err)
00772                 err = zfs_secpolicy_rename_perms(from, to, cr);
00773         if (err)
00774                 return (err);
00775 
00776         /*
00777          * Cannot move snapshots out of the snapdir.
00778          */
00779         if (sdvp != tdvp)
00780                 return (EINVAL);
00781 
00782         if (strcmp(snm, tnm) == 0)
00783                 return (0);
00784 
00785         mutex_enter(&sdp->sd_lock);
00786 
00787         search.se_name = (char *)snm;
00788         if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) == NULL) {
00789                 mutex_exit(&sdp->sd_lock);
00790                 return (ENOENT);
00791         }
00792 
00793         err = dmu_objset_rename(from, to, 0);
00794         if (err == 0)
00795                 zfsctl_rename_snap(sdp, sep, tnm);
00796 
00797         mutex_exit(&sdp->sd_lock);
00798 
00799         return (err);
00800 }
00801 #endif  /* sun */
00802 
00803 #ifdef sun
00804 /* ARGSUSED */
00805 static int
00806 zfsctl_snapdir_remove(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr,
00807     caller_context_t *ct, int flags)
00808 {
00809         zfsctl_snapdir_t *sdp = dvp->v_data;
00810         zfs_snapentry_t *sep;
00811         zfs_snapentry_t search;
00812         zfsvfs_t *zfsvfs;
00813         char snapname[MAXNAMELEN];
00814         char real[MAXNAMELEN];
00815         int err;
00816 
00817         zfsvfs = dvp->v_vfsp->vfs_data;
00818         ZFS_ENTER(zfsvfs);
00819 
00820         if ((flags & FIGNORECASE) || zfsvfs->z_case == ZFS_CASE_INSENSITIVE) {
00821 
00822                 err = dmu_snapshot_realname(zfsvfs->z_os, name, real,
00823                     MAXNAMELEN, NULL);
00824                 if (err == 0) {
00825                         name = real;
00826                 } else if (err != ENOTSUP) {
00827                         ZFS_EXIT(zfsvfs);
00828                         return (err);
00829                 }
00830         }
00831 
00832         ZFS_EXIT(zfsvfs);
00833 
00834         err = zfsctl_snapshot_zname(dvp, name, MAXNAMELEN, snapname);
00835         if (!err)
00836                 err = zfs_secpolicy_destroy_perms(snapname, cr);
00837         if (err)
00838                 return (err);
00839 
00840         mutex_enter(&sdp->sd_lock);
00841 
00842         search.se_name = name;
00843         sep = avl_find(&sdp->sd_snaps, &search, NULL);
00844         if (sep) {
00845                 avl_remove(&sdp->sd_snaps, sep);
00846                 err = zfsctl_unmount_snap(sep, MS_FORCE, cr);
00847                 if (err) {
00848                         avl_index_t where;
00849 
00850                         if (avl_find(&sdp->sd_snaps, sep, &where) == NULL)
00851                                 avl_insert(&sdp->sd_snaps, sep, where);
00852                 } else
00853                         err = dmu_objset_destroy(snapname, B_FALSE);
00854         } else {
00855                 err = ENOENT;
00856         }
00857 
00858         mutex_exit(&sdp->sd_lock);
00859 
00860         return (err);
00861 }
00862 #endif  /* sun */
00863 
00867 /* ARGSUSED */
00868 static int
00869 zfsctl_snapdir_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t  **vpp,
00870     cred_t *cr, caller_context_t *cc, int flags, vsecattr_t *vsecp)
00871 {
00872         zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
00873         char name[MAXNAMELEN];
00874         int err;
00875         static enum symfollow follow = NO_FOLLOW;
00876         static enum uio_seg seg = UIO_SYSSPACE;
00877 
00878         if (snapshot_namecheck(dirname, NULL, NULL) != 0)
00879                 return (EILSEQ);
00880 
00881         dmu_objset_name(zfsvfs->z_os, name);
00882 
00883         *vpp = NULL;
00884 
00885         err = zfs_secpolicy_snapshot_perms(name, cr);
00886         if (err)
00887                 return (err);
00888 
00889         if (err == 0) {
00890                 err = dmu_objset_snapshot(name, dirname, NULL, NULL,
00891                     B_FALSE, B_FALSE, -1);
00892                 if (err)
00893                         return (err);
00894                 err = lookupnameat(dirname, seg, follow, NULL, vpp, dvp);
00895         }
00896 
00897         return (err);
00898 }
00899 
00900 static int
00901 zfsctl_freebsd_snapdir_mkdir(ap)
00902         struct vop_mkdir_args /* {
00903                 struct vnode *a_dvp;
00904                 struct vnode **a_vpp;
00905                 struct componentname *a_cnp;
00906                 struct vattr *a_vap;
00907         } */ *ap;
00908 {
00909 
00910         ASSERT(ap->a_cnp->cn_flags & SAVENAME);
00911 
00912         return (zfsctl_snapdir_mkdir(ap->a_dvp, ap->a_cnp->cn_nameptr, NULL,
00913             ap->a_vpp, ap->a_cnp->cn_cred, NULL, 0, NULL));
00914 }
00915 
00921 /* ARGSUSED */
00922 int
00923 zfsctl_snapdir_lookup(ap)
00924         struct vop_lookup_args /* {
00925                 struct vnode *a_dvp;
00926                 struct vnode **a_vpp;
00927                 struct componentname *a_cnp;
00928         } */ *ap;
00929 {
00930         vnode_t *dvp = ap->a_dvp;
00931         vnode_t **vpp = ap->a_vpp;
00932         struct componentname *cnp = ap->a_cnp;
00933         char nm[NAME_MAX + 1];
00934         zfsctl_snapdir_t *sdp = dvp->v_data;
00935         objset_t *snap;
00936         char snapname[MAXNAMELEN];
00937         char real[MAXNAMELEN];
00938         char *mountpoint;
00939         zfs_snapentry_t *sep, search;
00940         size_t mountpoint_len;
00941         avl_index_t where;
00942         zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
00943         int err;
00944         int flags = 0;
00945 
00946         /*
00947          * No extended attributes allowed under .zfs
00948          */
00949         if (flags & LOOKUP_XATTR)
00950                 return (EINVAL);
00951         ASSERT(ap->a_cnp->cn_namelen < sizeof(nm));
00952         strlcpy(nm, ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen + 1);
00953 
00954         ASSERT(dvp->v_type == VDIR);
00955 
00956         *vpp = NULL;
00957 
00958         /*
00959          * If we get a recursive call, that means we got called
00960          * from the domount() code while it was trying to look up the
00961          * spec (which looks like a local path for zfs).  We need to
00962          * add some flag to domount() to tell it not to do this lookup.
00963          */
00964         if (MUTEX_HELD(&sdp->sd_lock))
00965                 return (ENOENT);
00966 
00967         ZFS_ENTER(zfsvfs);
00968 
00969         if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0) {
00970                 ZFS_EXIT(zfsvfs);
00971                 return (0);
00972         }
00973 
00974         if (flags & FIGNORECASE) {
00975                 boolean_t conflict = B_FALSE;
00976 
00977                 err = dmu_snapshot_realname(zfsvfs->z_os, nm, real,
00978                     MAXNAMELEN, &conflict);
00979                 if (err == 0) {
00980                         strlcpy(nm, real, sizeof(nm));
00981                 } else if (err != ENOTSUP) {
00982                         ZFS_EXIT(zfsvfs);
00983                         return (err);
00984                 }
00985 #if 0
00986                 if (realpnp)
00987                         (void) strlcpy(realpnp->pn_buf, nm,
00988                             realpnp->pn_bufsize);
00989                 if (conflict && direntflags)
00990                         *direntflags = ED_CASE_CONFLICT;
00991 #endif
00992         }
00993 
00994         mutex_enter(&sdp->sd_lock);
00995         search.se_name = (char *)nm;
00996         if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) != NULL) {
00997                 *vpp = sep->se_root;
00998                 VN_HOLD(*vpp);
00999                 err = traverse(vpp, LK_EXCLUSIVE | LK_RETRY);
01000                 if (err) {
01001                         VN_RELE(*vpp);
01002                         *vpp = NULL;
01003                 } else if (*vpp == sep->se_root) {
01004                         /*
01005                          * The snapshot was unmounted behind our backs,
01006                          * try to remount it.
01007                          */
01008                         VERIFY(zfsctl_snapshot_zname(dvp, nm, MAXNAMELEN, snapname) == 0);
01009                         goto domount;
01010                 } else {
01011                         /*
01012                          * VROOT was set during the traverse call.  We need
01013                          * to clear it since we're pretending to be part
01014                          * of our parent's vfs.
01015                          */
01016                         (*vpp)->v_flag &= ~VROOT;
01017                 }
01018                 mutex_exit(&sdp->sd_lock);
01019                 ZFS_EXIT(zfsvfs);
01020                 return (err);
01021         }
01022 
01023         /*
01024          * The requested snapshot is not currently mounted, look it up.
01025          */
01026         err = zfsctl_snapshot_zname(dvp, nm, MAXNAMELEN, snapname);
01027         if (err) {
01028                 mutex_exit(&sdp->sd_lock);
01029                 ZFS_EXIT(zfsvfs);
01030                 /*
01031                  * handle "ls *" or "?" in a graceful manner,
01032                  * forcing EILSEQ to ENOENT.
01033                  * Since shell ultimately passes "*" or "?" as name to lookup
01034                  */
01035                 return (err == EILSEQ ? ENOENT : err);
01036         }
01037         if (dmu_objset_hold(snapname, FTAG, &snap) != 0) {
01038                 mutex_exit(&sdp->sd_lock);
01039                 /* Translate errors and add SAVENAME when needed. */
01040                 if ((cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == CREATE) {
01041                         err = EJUSTRETURN;
01042                         cnp->cn_flags |= SAVENAME;
01043                 } else {
01044                         err = ENOENT;
01045                 }
01046                 ZFS_EXIT(zfsvfs);
01047                 return (err);
01048         }
01049 
01050         sep = kmem_alloc(sizeof (zfs_snapentry_t), KM_SLEEP);
01051         sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP);
01052         (void) strcpy(sep->se_name, nm);
01053         *vpp = sep->se_root = zfsctl_snapshot_mknode(dvp, dmu_objset_id(snap));
01054         VN_HOLD(*vpp);
01055         avl_insert(&sdp->sd_snaps, sep, where);
01056 
01057         dmu_objset_rele(snap, FTAG);
01058 domount:
01059         mountpoint_len = strlen(dvp->v_vfsp->mnt_stat.f_mntonname) +
01060             strlen("/" ZFS_CTLDIR_NAME "/snapshot/") + strlen(nm) + 1;
01061         mountpoint = kmem_alloc(mountpoint_len, KM_SLEEP);
01062         (void) snprintf(mountpoint, mountpoint_len,
01063             "%s/" ZFS_CTLDIR_NAME "/snapshot/%s",
01064             dvp->v_vfsp->mnt_stat.f_mntonname, nm);
01065         err = mount_snapshot(curthread, vpp, "zfs", mountpoint, snapname, 0);
01066         kmem_free(mountpoint, mountpoint_len);
01067         if (err == 0) {
01068                 /*
01069                  * Fix up the root vnode mounted on .zfs/snapshot/<snapname>.
01070                  *
01071                  * This is where we lie about our v_vfsp in order to
01072                  * make .zfs/snapshot/<snapname> accessible over NFS
01073                  * without requiring manual mounts of <snapname>.
01074                  */
01075                 ASSERT(VTOZ(*vpp)->z_zfsvfs != zfsvfs);
01076                 VTOZ(*vpp)->z_zfsvfs->z_parent = zfsvfs;
01077         }
01078         mutex_exit(&sdp->sd_lock);
01079         ZFS_EXIT(zfsvfs);
01080         if (err != 0)
01081                 *vpp = NULL;
01082         return (err);
01083 }
01084 
01085 /* ARGSUSED */
01086 int
01087 zfsctl_shares_lookup(ap)
01088         struct vop_lookup_args /* {
01089                 struct vnode *a_dvp;
01090                 struct vnode **a_vpp;
01091                 struct componentname *a_cnp;
01092         } */ *ap;
01093 {
01094         vnode_t *dvp = ap->a_dvp;
01095         vnode_t **vpp = ap->a_vpp;
01096         struct componentname *cnp = ap->a_cnp;
01097         zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
01098         char nm[NAME_MAX + 1];
01099         znode_t *dzp;
01100         int error;
01101 
01102         ZFS_ENTER(zfsvfs);
01103 
01104         ASSERT(cnp->cn_namelen < sizeof(nm));
01105         strlcpy(nm, cnp->cn_nameptr, cnp->cn_namelen + 1);
01106 
01107         if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0) {
01108                 ZFS_EXIT(zfsvfs);
01109                 return (0);
01110         }
01111 
01112         if (zfsvfs->z_shares_dir == 0) {
01113                 ZFS_EXIT(zfsvfs);
01114                 return (ENOTSUP);
01115         }
01116         if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0)
01117                 error = VOP_LOOKUP(ZTOV(dzp), vpp, cnp);
01118 
01119         VN_RELE(ZTOV(dzp));
01120         ZFS_EXIT(zfsvfs);
01121 
01122         return (error);
01123 }
01124 
01125 /* ARGSUSED */
01126 static int
01127 zfsctl_snapdir_readdir_cb(vnode_t *vp, void *dp, int *eofp,
01128     offset_t *offp, offset_t *nextp, void *data, int flags)
01129 {
01130         zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
01131         char snapname[MAXNAMELEN];
01132         uint64_t id, cookie;
01133         boolean_t case_conflict;
01134         int error;
01135 
01136         ZFS_ENTER(zfsvfs);
01137 
01138         cookie = *offp;
01139         error = dmu_snapshot_list_next(zfsvfs->z_os, MAXNAMELEN, snapname, &id,
01140             &cookie, &case_conflict);
01141         if (error) {
01142                 ZFS_EXIT(zfsvfs);
01143                 if (error == ENOENT) {
01144                         *eofp = 1;
01145                         return (0);
01146                 }
01147                 return (error);
01148         }
01149 
01150         if (flags & V_RDDIR_ENTFLAGS) {
01151                 edirent_t *eodp = dp;
01152 
01153                 (void) strcpy(eodp->ed_name, snapname);
01154                 eodp->ed_ino = ZFSCTL_INO_SNAP(id);
01155                 eodp->ed_eflags = case_conflict ? ED_CASE_CONFLICT : 0;
01156         } else {
01157                 struct dirent64 *odp = dp;
01158 
01159                 (void) strcpy(odp->d_name, snapname);
01160                 odp->d_ino = ZFSCTL_INO_SNAP(id);
01161         }
01162         *nextp = cookie;
01163 
01164         ZFS_EXIT(zfsvfs);
01165 
01166         return (0);
01167 }
01168 
01169 /* ARGSUSED */
01170 static int
01171 zfsctl_shares_readdir(ap)
01172         struct vop_readdir_args /* {
01173                 struct vnode *a_vp;
01174                 struct uio *a_uio;
01175                 struct ucred *a_cred;
01176                 int *a_eofflag;
01177                 int *a_ncookies;
01178                 u_long **a_cookies;
01179         } */ *ap;
01180 {
01181         vnode_t *vp = ap->a_vp;
01182         uio_t *uiop = ap->a_uio;
01183         cred_t *cr = ap->a_cred;
01184         int *eofp = ap->a_eofflag;
01185         zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
01186         znode_t *dzp;
01187         int error;
01188 
01189         ZFS_ENTER(zfsvfs);
01190 
01191         if (zfsvfs->z_shares_dir == 0) {
01192                 ZFS_EXIT(zfsvfs);
01193                 return (ENOTSUP);
01194         }
01195         if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) {
01196                 vn_lock(ZTOV(dzp), LK_SHARED | LK_RETRY);
01197                 error = VOP_READDIR(ZTOV(dzp), uiop, cr, eofp, ap->a_ncookies, ap->a_cookies);
01198                 VN_URELE(ZTOV(dzp));
01199         } else {
01200                 *eofp = 1;
01201                 error = ENOENT;
01202         }
01203 
01204         ZFS_EXIT(zfsvfs);
01205         return (error);
01206 }
01207 
01216 vnode_t *
01217 zfsctl_mknode_snapdir(vnode_t *pvp)
01218 {
01219         vnode_t *vp;
01220         zfsctl_snapdir_t *sdp;
01221 
01222         vp = gfs_dir_create(sizeof (zfsctl_snapdir_t), pvp, pvp->v_vfsp,
01223             &zfsctl_ops_snapdir, NULL, NULL, MAXNAMELEN,
01224             zfsctl_snapdir_readdir_cb, NULL);
01225         sdp = vp->v_data;
01226         sdp->sd_node.zc_id = ZFSCTL_INO_SNAPDIR;
01227         sdp->sd_node.zc_cmtime = ((zfsctl_node_t *)pvp->v_data)->zc_cmtime;
01228         mutex_init(&sdp->sd_lock, NULL, MUTEX_DEFAULT, NULL);
01229         avl_create(&sdp->sd_snaps, snapentry_compare,
01230             sizeof (zfs_snapentry_t), offsetof(zfs_snapentry_t, se_node));
01231         VOP_UNLOCK(vp, 0);
01232         return (vp);
01233 }
01234 
01235 vnode_t *
01236 zfsctl_mknode_shares(vnode_t *pvp)
01237 {
01238         vnode_t *vp;
01239         zfsctl_node_t *sdp;
01240 
01241         vp = gfs_dir_create(sizeof (zfsctl_node_t), pvp, pvp->v_vfsp,
01242             &zfsctl_ops_shares, NULL, NULL, MAXNAMELEN,
01243             NULL, NULL);
01244         sdp = vp->v_data;
01245         sdp->zc_cmtime = ((zfsctl_node_t *)pvp->v_data)->zc_cmtime;
01246         VOP_UNLOCK(vp, 0);
01247         return (vp);
01248 
01249 }
01250 
01251 /* ARGSUSED */
01252 static int
01253 zfsctl_shares_getattr(ap)
01254         struct vop_getattr_args /* {
01255                 struct vnode *a_vp;
01256                 struct vattr *a_vap;
01257                 struct ucred *a_cred;
01258                 struct thread *a_td;
01259         } */ *ap;
01260 {
01261         vnode_t *vp = ap->a_vp;
01262         vattr_t *vap = ap->a_vap;
01263         cred_t *cr = ap->a_cred;
01264         zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
01265         znode_t *dzp;
01266         int error;
01267 
01268         ZFS_ENTER(zfsvfs);
01269         if (zfsvfs->z_shares_dir == 0) {
01270                 ZFS_EXIT(zfsvfs);
01271                 return (ENOTSUP);
01272         }
01273         if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) {
01274                 vn_lock(ZTOV(dzp), LK_SHARED | LK_RETRY);
01275                 error = VOP_GETATTR(ZTOV(dzp), vap, cr);
01276                 VN_URELE(ZTOV(dzp));
01277         }
01278         ZFS_EXIT(zfsvfs);
01279         return (error);
01280 
01281 
01282 }
01283 
01284 /* ARGSUSED */
01285 static int
01286 zfsctl_snapdir_getattr(ap)
01287         struct vop_getattr_args /* {
01288                 struct vnode *a_vp;
01289                 struct vattr *a_vap;
01290                 struct ucred *a_cred;
01291         } */ *ap;
01292 {
01293         vnode_t *vp = ap->a_vp;
01294         vattr_t *vap = ap->a_vap;
01295         zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
01296         zfsctl_snapdir_t *sdp = vp->v_data;
01297 
01298         ZFS_ENTER(zfsvfs);
01299         zfsctl_common_getattr(vp, vap);
01300         vap->va_nodeid = gfs_file_inode(vp);
01301         vap->va_nlink = vap->va_size = avl_numnodes(&sdp->sd_snaps) + 2;
01302         vap->va_ctime = vap->va_mtime = dmu_objset_snap_cmtime(zfsvfs->z_os);
01303         vap->va_birthtime = vap->va_ctime;
01304         ZFS_EXIT(zfsvfs);
01305 
01306         return (0);
01307 }
01308 
01309 /* ARGSUSED */
01310 static int
01311 zfsctl_snapdir_inactive(ap)
01312         struct vop_inactive_args /* {
01313                 struct vnode *a_vp;
01314                 struct thread *a_td;
01315         } */ *ap;
01316 {
01317         vnode_t *vp = ap->a_vp;
01318         zfsctl_snapdir_t *sdp = vp->v_data;
01319         zfs_snapentry_t *sep;
01320 
01321         /*
01322          * On forced unmount we have to free snapshots from here.
01323          */
01324         mutex_enter(&sdp->sd_lock);
01325         while ((sep = avl_first(&sdp->sd_snaps)) != NULL) {
01326                 avl_remove(&sdp->sd_snaps, sep);
01327                 kmem_free(sep->se_name, strlen(sep->se_name) + 1);
01328                 kmem_free(sep, sizeof (zfs_snapentry_t));
01329         }
01330         mutex_exit(&sdp->sd_lock);
01331         gfs_dir_inactive(vp);
01332         ASSERT(avl_numnodes(&sdp->sd_snaps) == 0);
01333         mutex_destroy(&sdp->sd_lock);
01334         avl_destroy(&sdp->sd_snaps);
01335         kmem_free(sdp, sizeof (zfsctl_snapdir_t));
01336 
01337         return (0);
01338 }
01339 
01340 #ifdef sun
01341 static const fs_operation_def_t zfsctl_tops_snapdir[] = {
01342         { VOPNAME_OPEN,         { .vop_open = zfsctl_common_open }      },
01343         { VOPNAME_CLOSE,        { .vop_close = zfsctl_common_close }    },
01344         { VOPNAME_IOCTL,        { .error = fs_inval }                   },
01345         { VOPNAME_GETATTR,      { .vop_getattr = zfsctl_snapdir_getattr } },
01346         { VOPNAME_ACCESS,       { .vop_access = zfsctl_common_access }  },
01347         { VOPNAME_RENAME,       { .vop_rename = zfsctl_snapdir_rename } },
01348         { VOPNAME_RMDIR,        { .vop_rmdir = zfsctl_snapdir_remove }  },
01349         { VOPNAME_MKDIR,        { .vop_mkdir = zfsctl_snapdir_mkdir }   },
01350         { VOPNAME_READDIR,      { .vop_readdir = gfs_vop_readdir }      },
01351         { VOPNAME_LOOKUP,       { .vop_lookup = zfsctl_snapdir_lookup } },
01352         { VOPNAME_SEEK,         { .vop_seek = fs_seek }                 },
01353         { VOPNAME_INACTIVE,     { .vop_inactive = zfsctl_snapdir_inactive } },
01354         { VOPNAME_FID,          { .vop_fid = zfsctl_common_fid }        },
01355         { NULL }
01356 };
01357 
01358 static const fs_operation_def_t zfsctl_tops_shares[] = {
01359         { VOPNAME_OPEN,         { .vop_open = zfsctl_common_open }      },
01360         { VOPNAME_CLOSE,        { .vop_close = zfsctl_common_close }    },
01361         { VOPNAME_IOCTL,        { .error = fs_inval }                   },
01362         { VOPNAME_GETATTR,      { .vop_getattr = zfsctl_shares_getattr } },
01363         { VOPNAME_ACCESS,       { .vop_access = zfsctl_common_access }  },
01364         { VOPNAME_READDIR,      { .vop_readdir = zfsctl_shares_readdir } },
01365         { VOPNAME_LOOKUP,       { .vop_lookup = zfsctl_shares_lookup }  },
01366         { VOPNAME_SEEK,         { .vop_seek = fs_seek }                 },
01367         { VOPNAME_INACTIVE,     { .vop_inactive = gfs_vop_inactive } },
01368         { VOPNAME_FID,          { .vop_fid = zfsctl_shares_fid } },
01369         { NULL }
01370 };
01371 #else   /* !sun */
01372 static struct vop_vector zfsctl_ops_snapdir = {
01373         .vop_default =  &default_vnodeops,
01374         .vop_open =     zfsctl_common_open,
01375         .vop_close =    zfsctl_common_close,
01376         .vop_ioctl =    VOP_EINVAL,
01377         .vop_getattr =  zfsctl_snapdir_getattr,
01378         .vop_access =   zfsctl_common_access,
01379         .vop_mkdir =    zfsctl_freebsd_snapdir_mkdir,
01380         .vop_readdir =  gfs_vop_readdir,
01381         .vop_lookup =   zfsctl_snapdir_lookup,
01382         .vop_inactive = zfsctl_snapdir_inactive,
01383         .vop_reclaim =  zfsctl_common_reclaim,
01384         .vop_fid =      zfsctl_common_fid,
01385 };
01386 
01387 static struct vop_vector zfsctl_ops_shares = {
01388         .vop_default =  &default_vnodeops,
01389         .vop_open =     zfsctl_common_open,
01390         .vop_close =    zfsctl_common_close,
01391         .vop_ioctl =    VOP_EINVAL,
01392         .vop_getattr =  zfsctl_shares_getattr,
01393         .vop_access =   zfsctl_common_access,
01394         .vop_readdir =  zfsctl_shares_readdir,
01395         .vop_lookup =   zfsctl_shares_lookup,
01396         .vop_inactive = gfs_vop_inactive,
01397         .vop_reclaim =  zfsctl_common_reclaim,
01398         .vop_fid =      zfsctl_shares_fid,
01399 };
01400 #endif  /* !sun */
01401 
01409 static vnode_t *
01410 zfsctl_snapshot_mknode(vnode_t *pvp, uint64_t objset)
01411 {
01412         vnode_t *vp;
01413         zfsctl_node_t *zcp;
01414 
01415         vp = gfs_dir_create(sizeof (zfsctl_node_t), pvp, pvp->v_vfsp,
01416             &zfsctl_ops_snapshot, NULL, NULL, MAXNAMELEN, NULL, NULL);
01417         VN_HOLD(vp);
01418         zcp = vp->v_data;
01419         zcp->zc_id = objset;
01420         VOP_UNLOCK(vp, 0);
01421 
01422         return (vp);
01423 }
01424 
01425 static int
01426 zfsctl_snapshot_inactive(ap)
01427         struct vop_inactive_args /* {
01428                 struct vnode *a_vp;
01429                 struct thread *a_td;
01430         } */ *ap;
01431 {
01432         vnode_t *vp = ap->a_vp;
01433         cred_t *cr = ap->a_td->td_ucred;
01434         struct vop_inactive_args iap;
01435         zfsctl_snapdir_t *sdp;
01436         zfs_snapentry_t *sep, *next;
01437         int locked;
01438         vnode_t *dvp;
01439 
01440         if (vp->v_count > 0)
01441                 goto end;
01442 
01443         VERIFY(gfs_dir_lookup(vp, "..", &dvp, cr, 0, NULL, NULL) == 0);
01444         sdp = dvp->v_data;
01445         VOP_UNLOCK(dvp, 0);
01446 
01447         if (!(locked = MUTEX_HELD(&sdp->sd_lock)))
01448                 mutex_enter(&sdp->sd_lock);
01449 
01450         ASSERT(!vn_ismntpt(vp));
01451 
01452         sep = avl_first(&sdp->sd_snaps);
01453         while (sep != NULL) {
01454                 next = AVL_NEXT(&sdp->sd_snaps, sep);
01455 
01456                 if (sep->se_root == vp) {
01457                         avl_remove(&sdp->sd_snaps, sep);
01458                         kmem_free(sep->se_name, strlen(sep->se_name) + 1);
01459                         kmem_free(sep, sizeof (zfs_snapentry_t));
01460                         break;
01461                 }
01462                 sep = next;
01463         }
01464         ASSERT(sep != NULL);
01465 
01466         if (!locked)
01467                 mutex_exit(&sdp->sd_lock);
01468         VN_RELE(dvp);
01469 
01470 end:
01471         /*
01472          * Dispose of the vnode for the snapshot mount point.
01473          * This is safe to do because once this entry has been removed
01474          * from the AVL tree, it can't be found again, so cannot become
01475          * "active".  If we lookup the same name again we will end up
01476          * creating a new vnode.
01477          */
01478         iap.a_vp = vp;
01479         return (gfs_vop_inactive(&iap));
01480 }
01481 
01482 static int
01483 zfsctl_traverse_begin(vnode_t **vpp, int lktype)
01484 {
01485 
01486         VN_HOLD(*vpp);
01487         /* Snapshot should be already mounted, but just in case. */
01488         if (vn_mountedvfs(*vpp) == NULL)
01489                 return (ENOENT);
01490         return (traverse(vpp, lktype));
01491 }
01492 
01493 static void
01494 zfsctl_traverse_end(vnode_t *vp, int err)
01495 {
01496 
01497         if (err == 0)
01498                 vput(vp);
01499         else
01500                 VN_RELE(vp);
01501 }
01502 
01503 static int
01504 zfsctl_snapshot_getattr(ap)
01505         struct vop_getattr_args /* {
01506                 struct vnode *a_vp;
01507                 struct vattr *a_vap;
01508                 struct ucred *a_cred;
01509         } */ *ap;
01510 {
01511         vnode_t *vp = ap->a_vp;
01512         int err;
01513 
01514         err = zfsctl_traverse_begin(&vp, LK_SHARED | LK_RETRY);
01515         if (err == 0)
01516                 err = VOP_GETATTR(vp, ap->a_vap, ap->a_cred);
01517         zfsctl_traverse_end(vp, err);
01518         return (err);
01519 }
01520 
01521 static int
01522 zfsctl_snapshot_fid(ap)
01523         struct vop_fid_args /* {
01524                 struct vnode *a_vp;
01525                 struct fid *a_fid;
01526         } */ *ap;
01527 {
01528         vnode_t *vp = ap->a_vp;
01529         int err;
01530 
01531         err = zfsctl_traverse_begin(&vp, LK_SHARED | LK_RETRY);
01532         if (err == 0)
01533                 err = VOP_VPTOFH(vp, (void *)ap->a_fid);
01534         zfsctl_traverse_end(vp, err);
01535         return (err);
01536 }
01537 
01538 static int
01539 zfsctl_snapshot_lookup(ap)
01540         struct vop_lookup_args /* {
01541                 struct vnode *a_dvp;
01542                 struct vnode **a_vpp;
01543                 struct componentname *a_cnp;
01544         } */ *ap;
01545 {
01546         vnode_t *dvp = ap->a_dvp;
01547         vnode_t **vpp = ap->a_vpp;
01548         struct componentname *cnp = ap->a_cnp;
01549         cred_t *cr = ap->a_cnp->cn_cred;
01550         zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
01551         int error;
01552 
01553         if (cnp->cn_namelen != 2 || cnp->cn_nameptr[0] != '.' ||
01554             cnp->cn_nameptr[1] != '.') {
01555                 return (ENOENT);
01556         }
01557 
01558         ASSERT(dvp->v_type == VDIR);
01559         ASSERT(zfsvfs->z_ctldir != NULL);
01560 
01561         error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", vpp,
01562             NULL, 0, NULL, cr, NULL, NULL, NULL);
01563         if (error == 0)
01564                 vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY);
01565         return (error);
01566 }
01567 
01568 static int
01569 zfsctl_snapshot_vptocnp(struct vop_vptocnp_args *ap)
01570 {
01571         zfsvfs_t *zfsvfs = ap->a_vp->v_vfsp->vfs_data;
01572         vnode_t *dvp, *vp;
01573         zfsctl_snapdir_t *sdp;
01574         zfs_snapentry_t *sep;
01575         int error;
01576 
01577         ASSERT(zfsvfs->z_ctldir != NULL);
01578         error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp,
01579             NULL, 0, NULL, kcred, NULL, NULL, NULL);
01580         if (error != 0)
01581                 return (error);
01582         sdp = dvp->v_data;
01583 
01584         mutex_enter(&sdp->sd_lock);
01585         sep = avl_first(&sdp->sd_snaps);
01586         while (sep != NULL) {
01587                 vp = sep->se_root;
01588                 if (vp == ap->a_vp)
01589                         break;
01590                 sep = AVL_NEXT(&sdp->sd_snaps, sep);
01591         }
01592         if (sep == NULL) {
01593                 mutex_exit(&sdp->sd_lock);
01594                 error = ENOENT;
01595         } else {
01596                 size_t len;
01597 
01598                 len = strlen(sep->se_name);
01599                 *ap->a_buflen -= len;
01600                 bcopy(sep->se_name, ap->a_buf + *ap->a_buflen, len);
01601                 mutex_exit(&sdp->sd_lock);
01602                 vref(dvp);
01603                 *ap->a_vpp = dvp;
01604         }
01605         VN_RELE(dvp);
01606 
01607         return (error);
01608 }
01609 
01614 static struct vop_vector zfsctl_ops_snapshot = {
01615         .vop_default =  &default_vnodeops,
01616         .vop_inactive = zfsctl_snapshot_inactive,
01617         .vop_lookup =   zfsctl_snapshot_lookup,
01618         .vop_reclaim =  zfsctl_common_reclaim,
01619         .vop_getattr =  zfsctl_snapshot_getattr,
01620         .vop_fid =      zfsctl_snapshot_fid,
01621         .vop_vptocnp =  zfsctl_snapshot_vptocnp,
01622 };
01623 
01624 int
01625 zfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t **zfsvfsp)
01626 {
01627         zfsvfs_t *zfsvfs = vfsp->vfs_data;
01628         vnode_t *dvp, *vp;
01629         zfsctl_snapdir_t *sdp;
01630         zfsctl_node_t *zcp;
01631         zfs_snapentry_t *sep;
01632         int error;
01633 
01634         ASSERT(zfsvfs->z_ctldir != NULL);
01635         error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp,
01636             NULL, 0, NULL, kcred, NULL, NULL, NULL);
01637         if (error != 0)
01638                 return (error);
01639         sdp = dvp->v_data;
01640 
01641         mutex_enter(&sdp->sd_lock);
01642         sep = avl_first(&sdp->sd_snaps);
01643         while (sep != NULL) {
01644                 vp = sep->se_root;
01645                 zcp = vp->v_data;
01646                 if (zcp->zc_id == objsetid)
01647                         break;
01648 
01649                 sep = AVL_NEXT(&sdp->sd_snaps, sep);
01650         }
01651 
01652         if (sep != NULL) {
01653                 VN_HOLD(vp);
01654                 /*
01655                  * Return the mounted root rather than the covered mount point.
01656                  * Takes the GFS vnode at .zfs/snapshot/<snapshot objsetid>
01657                  * and returns the ZFS vnode mounted on top of the GFS node.
01658                  * This ZFS vnode is the root of the vfs for objset 'objsetid'.
01659                  */
01660                 error = traverse(&vp, LK_SHARED | LK_RETRY);
01661                 if (error == 0) {
01662                         if (vp == sep->se_root)
01663                                 error = EINVAL;
01664                         else
01665                                 *zfsvfsp = VTOZ(vp)->z_zfsvfs;
01666                 }
01667                 mutex_exit(&sdp->sd_lock);
01668                 if (error == 0)
01669                         VN_URELE(vp);
01670                 else
01671                         VN_RELE(vp);
01672         } else {
01673                 error = EINVAL;
01674                 mutex_exit(&sdp->sd_lock);
01675         }
01676 
01677         VN_RELE(dvp);
01678 
01679         return (error);
01680 }
01681 
01687 int
01688 zfsctl_umount_snapshots(vfs_t *vfsp, int fflags, cred_t *cr)
01689 {
01690         zfsvfs_t *zfsvfs = vfsp->vfs_data;
01691         vnode_t *dvp;
01692         zfsctl_snapdir_t *sdp;
01693         zfs_snapentry_t *sep, *next;
01694         int error;
01695 
01696         ASSERT(zfsvfs->z_ctldir != NULL);
01697         error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp,
01698             NULL, 0, NULL, cr, NULL, NULL, NULL);
01699         if (error != 0)
01700                 return (error);
01701         sdp = dvp->v_data;
01702 
01703         mutex_enter(&sdp->sd_lock);
01704 
01705         sep = avl_first(&sdp->sd_snaps);
01706         while (sep != NULL) {
01707                 next = AVL_NEXT(&sdp->sd_snaps, sep);
01708 
01709                 /*
01710                  * If this snapshot is not mounted, then it must
01711                  * have just been unmounted by somebody else, and
01712                  * will be cleaned up by zfsctl_snapdir_inactive().
01713                  */
01714                 if (vn_ismntpt(sep->se_root)) {
01715                         error = zfsctl_unmount_snap(sep, fflags, cr);
01716                         if (error) {
01717                                 avl_index_t where;
01718 
01719                                 /*
01720                                  * Before reinserting snapshot to the tree,
01721                                  * check if it was actually removed. For example
01722                                  * when snapshot mount point is busy, we will
01723                                  * have an error here, but there will be no need
01724                                  * to reinsert snapshot.
01725                                  */
01726                                 if (avl_find(&sdp->sd_snaps, sep, &where) == NULL)
01727                                         avl_insert(&sdp->sd_snaps, sep, where);
01728                                 break;
01729                         }
01730                 }
01731                 sep = next;
01732         }
01733 
01734         mutex_exit(&sdp->sd_lock);
01735         VN_RELE(dvp);
01736 
01737         return (error);
01738 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines