zfs_ctldir.c revision 9e1320c015cea6985d2122bc1d654b79fa479f7a
1N/A * The contents of this file are subject to the terms of the 1N/A * Common Development and Distribution License (the "License"). 1N/A * You may not use this file except in compliance with the License. 1N/A * See the License for the specific language governing permissions 1N/A * and limitations under the License. 1N/A * When distributing Covered Code, include this CDDL HEADER in each 1N/A * If applicable, add the following below this CDDL HEADER, with the 1N/A * fields enclosed by brackets "[]" replaced with your own identifying 1N/A * information: Portions Copyright [yyyy] [name of copyright owner] 1N/A * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 1N/A * Use is subject to license terms. 1N/A * ZFS control directory (a.k.a. ".zfs") 1N/A * This directory provides a common location for all ZFS meta-objects. 1N/A * Currently, this is only the 'snapshot' directory, but this may expand in the 1N/A * future. The elements are built using the GFS primitives, as the hierarchy 1N/A * does not actually exist on disk. 1N/A * For 'snapshot', we don't want to have all snapshots always mounted, because 1N/A * this would take up a huge amount of space in /etc/mnttab. We have three 1N/A * ctldir ------> snapshotdir -------> snapshot 1N/A * The 'snapshot' node contains just enough information to lookup '..' and act 1N/A * as a mountpoint for the snapshot. Whenever we lookup a specific snapshot, we 1N/A * perform an automount of the underlying filesystem and return the 1N/A * corresponding vnode. 1N/A * All mounts are handled automatically by the kernel, but unmounts are 1N/A * (currently) handled from user land. The main reason is that there is no 1N/A * reliable way to auto-unmount the filesystem when it's "no longer in use". 1N/A * When the user unmounts a filesystem, we call zfsctl_unmount(), which 1N/A * unmounts any snapshots within the snapshot directory. 1N/A * share the same vfs_t as the head filesystem (what '.zfs' lives under). 1N/A * File systems mounted ontop of the GFS nodes '.zfs/snapshot/<snapname>' 1N/A * (ie: snapshots) are ZFS nodes and have their own unique vfs_t. 1N/A * However, vnodes within these mounted on file systems have their v_vfsp 1N/A * fields set to the head filesystem to make NFS happy (see 1N/A * zfsctl_snapdir_lookup()). We VFS_HOLD the head filesystem's vfs_t 1N/A * so that it cannot be freed until all snapshots have been unmounted. * Root directory elements. We only have two entries /* include . and .. in the calculation */ * Initialize the various GFS pieces we'll need to create and manipulate .zfs * directories. This is called from the ZFS init routine, and initializes the * vnode ops vectors that we'll be using. * Remove vfsctl vnode ops * Return the inode number associated with the 'snapshot' or * Create the '.zfs' directory. This directory is cached as part of the VFS * structure. This results in a hold on the vfs_t. The code in zfs_umount() * therefore checks against a vfs_count of 2 instead of 1. This reference * is removed when the ctldir is destroyed in the unmount. * We're only faking the fact that we have a root of a filesystem for * the sake of the GFS interfaces. Undo the flag manipulation it did * Destroy the '.zfs' directory. Only called when the filesystem is unmounted. * There might still be more references if we were force unmounted, but only * new zfs_inactive() calls can occur and they don't reference .zfs * Given a root znode, retrieve the associated .zfs directory. * Add a hold to the vnode and return it. * Common open routine. Disallow any write access. * Common close routine. Nothing to do here. * Common access routine. Disallow writes. * Common getattr function. Fill in basic information. * We are a purly virtual object, so we have no * blocksize or allocated blocks. * We live in the now (for atime). /* .zfs znodes always have a generation number of 0 */ * We need to generate unique inode numbers for all files and directories * within the .zfs pseudo-filesystem. We use the following scheme: * Get root directory attributes. * Special case the handling of "..". * No extended attributes allowed under .zfs * We only care about ACL_ENABLED so that libsec can * display ACL correctly and not default to POSIX draft. /* this will be dropped by dounmount() */ * We can't use VN_RELE(), as that will try to invoke * zfsctl_snapdir_inactive(), which would cause us to destroy * the sd_lock mutex held by our caller. * Change the name in the AVL tree. * Change the current mountpoint info: * - update the tail of the mntpoint path * - update the tail of the resource path * Cannot move snapshots out of the snapdir. * Lookup entry point for the 'snapshot' directory. Try to open the * snapshot if it exist, creating the pseudo filesystem vnode as necessary. * Perform a mount of the associated dataset on top of the vnode. * No extended attributes allowed under .zfs * If we get a recursive call, that means we got called * from the domount() code while it was trying to look up the * spec (which looks like a local path for zfs). We need to * add some flag to domount() to tell it not to do this lookup. * The snapshot was unmounted behind our backs, * VROOT was set during the traverse call. We need * to clear it since we're pretending to be part * The requested snapshot is not currently mounted, look it up. * handle "ls *" or "?" in a graceful manner, * forcing EILSEQ to ENOENT. * Since shell ultimately passes "*" or "?" as name to lookup * Return the mounted root rather than the covered mount point. * Takes the GFS vnode at .zfs/snapshot/<snapname> and returns * the ZFS vnode mounted on top of the GFS node. This ZFS * vnode is the root the newly created vfsp. * Fix up the root vnode mounted on .zfs/snapshot/<snapname>. * This is where we lie about our v_vfsp in order to * without requiring manual mounts of <snapname>. * If we had an error, drop our hold on the vnode and * zfsctl_snapshot_inactive() will clean up. * pvp is the '.zfs' directory (zfsctl_node_t). * Creates vp, which is '.zfs/snapshot' (zfsctl_snapdir_t). * This function is the callback to create a GFS vnode for '.zfs/snapshot' * when a lookup is performed on .zfs for "snapshot". * This creates a GFS node under '.zfs/snapshot' representing each * snapshot. This newly created GFS node is what we mount snapshot * Dispose of the vnode for the snapshot mount point. * This is safe to do because once this entry has been removed * from the AVL tree, it can't be found again, so cannot become * "active". If we lookup the same name again we will end up * These VP's should never see the light of day. They should always * Return the mounted root rather than the covered mount point. * Takes the GFS vnode at .zfs/snapshot/<snapshot objsetid> * and returns the ZFS vnode mounted on top of the GFS node. * This ZFS vnode is the root of the vfs for objset 'objsetid'. * Unmount any snapshots for the given filesystem. This is called from * zfs_umount() - if we have a ctldir, then go through and unmount all the * If this snapshot is not mounted, then it must * have just been unmounted by somebody else, and * will be cleaned up by zfsctl_snapdir_inactive().