summaryrefslogtreecommitdiffstats
path: root/sys/contrib/opensolaris/uts/common/fs/gfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/opensolaris/uts/common/fs/gfs.c')
-rw-r--r--sys/contrib/opensolaris/uts/common/fs/gfs.c884
1 files changed, 0 insertions, 884 deletions
diff --git a/sys/contrib/opensolaris/uts/common/fs/gfs.c b/sys/contrib/opensolaris/uts/common/fs/gfs.c
deleted file mode 100644
index 738c9d4..0000000
--- a/sys/contrib/opensolaris/uts/common/fs/gfs.c
+++ /dev/null
@@ -1,884 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/* Portions Copyright 2007 Shivakumar GN */
-/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include <sys/types.h>
-#include <sys/cmn_err.h>
-#include <sys/debug.h>
-#include <sys/dirent.h>
-#include <sys/kmem.h>
-#include <sys/mman.h>
-#include <sys/mutex.h>
-#include <sys/sysmacros.h>
-#include <sys/systm.h>
-#include <sys/uio.h>
-#include <sys/vfs.h>
-#include <sys/vnode.h>
-#include <sys/cred.h>
-#include <sys/kdb.h>
-
-#include <sys/gfs.h>
-
-/*
- * Generic pseudo-filesystem routines.
- *
- * There are significant similarities between the implementation of certain file
- * system entry points across different filesystems. While one could attempt to
- * "choke up on the bat" and incorporate common functionality into a VOP
- * preamble or postamble, such an approach is limited in the benefit it can
- * provide. In this file we instead define a toolkit of routines which can be
- * called from a filesystem (with in-kernel pseudo-filesystems being the focus
- * of the exercise) in a more component-like fashion.
- *
- * There are three basic classes of routines:
- *
- * 1) Lowlevel support routines
- *
- * These routines are designed to play a support role for existing
- * pseudo-filesystems (such as procfs). They simplify common tasks,
- * without enforcing the filesystem to hand over management to GFS. The
- * routines covered are:
- *
- * gfs_readdir_init()
- * gfs_readdir_emit()
- * gfs_readdir_emitn()
- * gfs_readdir_pred()
- * gfs_readdir_fini()
- * gfs_lookup_dot()
- *
- * 2) Complete GFS management
- *
- * These routines take a more active role in management of the
- * pseudo-filesystem. They handle the relationship between vnode private
- * data and VFS data, as well as the relationship between vnodes in the
- * directory hierarchy.
- *
- * In order to use these interfaces, the first member of every private
- * v_data must be a gfs_file_t or a gfs_dir_t. This hands over all control
- * to GFS.
- *
- * gfs_file_create()
- * gfs_dir_create()
- * gfs_root_create()
- *
- * gfs_file_inactive()
- * gfs_dir_inactive()
- * gfs_dir_lookup()
- * gfs_dir_readdir()
- *
- * gfs_vop_inactive()
- * gfs_vop_lookup()
- * gfs_vop_readdir()
- * gfs_vop_map()
- *
- * 3) Single File pseudo-filesystems
- *
- * This routine creates a rooted file to be overlayed ontop of another
- * file in the physical filespace.
- *
- * Note that the parent is NULL (actually the vfs), but there is nothing
- * technically keeping such a file from utilizing the "Complete GFS
- * management" set of routines.
- *
- * gfs_root_create_file()
- */
-
-/*
- * Low level directory routines
- *
- * These routines provide some simple abstractions for reading directories.
- * They are designed to be used by existing pseudo filesystems (namely procfs)
- * that already have a complicated management infrastructure.
- */
-
-/*
- * gfs_readdir_init: initiate a generic readdir
- * st - a pointer to an uninitialized gfs_readdir_state_t structure
- * name_max - the directory's maximum file name length
- * ureclen - the exported file-space record length (1 for non-legacy FSs)
- * uiop - the uiop passed to readdir
- * parent - the parent directory's inode
- * self - this directory's inode
- *
- * Returns 0 or a non-zero errno.
- *
- * Typical VOP_READDIR usage of gfs_readdir_*:
- *
- * if ((error = gfs_readdir_init(...)) != 0)
- * return (error);
- * eof = 0;
- * while ((error = gfs_readdir_pred(..., &voffset)) != 0) {
- * if (!consumer_entry_at(voffset))
- * voffset = consumer_next_entry(voffset);
- * if (consumer_eof(voffset)) {
- * eof = 1
- * break;
- * }
- * if ((error = gfs_readdir_emit(..., voffset,
- * consumer_ino(voffset), consumer_name(voffset))) != 0)
- * break;
- * }
- * return (gfs_readdir_fini(..., error, eofp, eof));
- *
- * As you can see, a zero result from gfs_readdir_pred() or
- * gfs_readdir_emit() indicates that processing should continue,
- * whereas a non-zero result indicates that the loop should terminate.
- * Most consumers need do nothing more than let gfs_readdir_fini()
- * determine what the cause of failure was and return the appropriate
- * value.
- */
-int
-gfs_readdir_init(gfs_readdir_state_t *st, int name_max, int ureclen,
- uio_t *uiop, ino64_t parent, ino64_t self)
-{
- if (uiop->uio_loffset < 0 || uiop->uio_resid <= 0 ||
- (uiop->uio_loffset % ureclen) != 0)
- return (EINVAL);
-
- st->grd_ureclen = ureclen;
- st->grd_oresid = uiop->uio_resid;
- st->grd_namlen = name_max;
- st->grd_dirent = kmem_zalloc(DIRENT64_RECLEN(st->grd_namlen), KM_SLEEP);
- st->grd_parent = parent;
- st->grd_self = self;
-
- return (0);
-}
-
-/*
- * gfs_readdir_emit_int: internal routine to emit directory entry
- *
- * st - the current readdir state, which must have d_ino and d_name
- * set
- * uiop - caller-supplied uio pointer
- * next - the offset of the next entry
- */
-static int
-gfs_readdir_emit_int(gfs_readdir_state_t *st, uio_t *uiop, offset_t next,
- int *ncookies, u_long **cookies)
-{
- int reclen, namlen;
-
- namlen = strlen(st->grd_dirent->d_name);
- reclen = DIRENT64_RECLEN(namlen);
-
- if (reclen > uiop->uio_resid) {
- /*
- * Error if no entries were returned yet
- */
- if (uiop->uio_resid == st->grd_oresid)
- return (EINVAL);
- return (-1);
- }
-
- /* XXX: This can change in the future. */
- st->grd_dirent->d_type = DT_DIR;
- st->grd_dirent->d_reclen = (ushort_t)reclen;
- st->grd_dirent->d_namlen = namlen;
-
- if (uiomove((caddr_t)st->grd_dirent, reclen, UIO_READ, uiop))
- return (EFAULT);
-
- uiop->uio_loffset = next;
- if (*cookies != NULL) {
- **cookies = next;
- (*cookies)++;
- (*ncookies)--;
- KASSERT(*ncookies >= 0, ("ncookies=%d", *ncookies));
- }
-
- return (0);
-}
-
-/*
- * gfs_readdir_emit: emit a directory entry
- * voff - the virtual offset (obtained from gfs_readdir_pred)
- * ino - the entry's inode
- * name - the entry's name
- *
- * Returns a 0 on success, a non-zero errno on failure, or -1 if the
- * readdir loop should terminate. A non-zero result (either errno or
- * -1) from this function is typically passed directly to
- * gfs_readdir_fini().
- */
-int
-gfs_readdir_emit(gfs_readdir_state_t *st, uio_t *uiop, offset_t voff,
- ino64_t ino, const char *name, int *ncookies, u_long **cookies)
-{
- offset_t off = (voff + 2) * st->grd_ureclen;
-
- st->grd_dirent->d_ino = ino;
- (void) strncpy(st->grd_dirent->d_name, name, st->grd_namlen);
-
- /*
- * Inter-entry offsets are invalid, so we assume a record size of
- * grd_ureclen and explicitly set the offset appropriately.
- */
- return (gfs_readdir_emit_int(st, uiop, off + st->grd_ureclen, ncookies,
- cookies));
-}
-
-/*
- * gfs_readdir_pred: readdir loop predicate
- * voffp - a pointer in which the next virtual offset should be stored
- *
- * Returns a 0 on success, a non-zero errno on failure, or -1 if the
- * readdir loop should terminate. A non-zero result (either errno or
- * -1) from this function is typically passed directly to
- * gfs_readdir_fini().
- */
-int
-gfs_readdir_pred(gfs_readdir_state_t *st, uio_t *uiop, offset_t *voffp,
- int *ncookies, u_long **cookies)
-{
- offset_t off, voff;
- int error;
-
-top:
- if (uiop->uio_resid <= 0)
- return (-1);
-
- off = uiop->uio_loffset / st->grd_ureclen;
- voff = off - 2;
- if (off == 0) {
- if ((error = gfs_readdir_emit(st, uiop, voff, st->grd_self,
- ".", ncookies, cookies)) == 0)
- goto top;
- } else if (off == 1) {
- if ((error = gfs_readdir_emit(st, uiop, voff, st->grd_parent,
- "..", ncookies, cookies)) == 0)
- goto top;
- } else {
- *voffp = voff;
- return (0);
- }
-
- return (error);
-}
-
-/*
- * gfs_readdir_fini: generic readdir cleanup
- * error - if positive, an error to return
- * eofp - the eofp passed to readdir
- * eof - the eof value
- *
- * Returns a 0 on success, a non-zero errno on failure. This result
- * should be returned from readdir.
- */
-int
-gfs_readdir_fini(gfs_readdir_state_t *st, int error, int *eofp, int eof)
-{
- kmem_free(st->grd_dirent, DIRENT64_RECLEN(st->grd_namlen));
- if (error > 0)
- return (error);
- if (eofp)
- *eofp = eof;
- return (0);
-}
-
-/*
- * gfs_lookup_dot
- *
- * Performs a basic check for "." and ".." directory entries.
- */
-int
-gfs_lookup_dot(vnode_t **vpp, vnode_t *dvp, vnode_t *pvp, const char *nm)
-{
- if (*nm == '\0' || strcmp(nm, ".") == 0) {
- VN_HOLD(dvp);
- *vpp = dvp;
- return (0);
- } else if (strcmp(nm, "..") == 0) {
- if (pvp == NULL) {
- ASSERT(dvp->v_flag & VROOT);
- VN_HOLD(dvp);
- *vpp = dvp;
- } else {
- VN_HOLD(pvp);
- *vpp = pvp;
- }
- vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY);
- return (0);
- }
-
- return (-1);
-}
-
-/*
- * gfs_file_create(): create a new GFS file
- *
- * size - size of private data structure (v_data)
- * pvp - parent vnode (GFS directory)
- * ops - vnode operations vector
- *
- * In order to use this interface, the parent vnode must have been created by
- * gfs_dir_create(), and the private data stored in v_data must have a
- * 'gfs_file_t' as its first field.
- *
- * Given these constraints, this routine will automatically:
- *
- * - Allocate v_data for the vnode
- * - Initialize necessary fields in the vnode
- * - Hold the parent
- */
-vnode_t *
-gfs_file_create(size_t size, vnode_t *pvp, vfs_t *vfsp, vnodeops_t *ops)
-{
- gfs_file_t *fp;
- vnode_t *vp;
- int error;
-
- /*
- * Allocate vnode and internal data structure
- */
- fp = kmem_zalloc(size, KM_SLEEP);
- error = getnewvnode("zfs", vfsp, ops, &vp);
- ASSERT(error == 0);
- vp->v_data = (caddr_t)fp;
-
- /*
- * Set up various pointers
- */
- fp->gfs_vnode = vp;
- fp->gfs_parent = pvp;
- fp->gfs_size = size;
- fp->gfs_type = GFS_FILE;
-
- error = insmntque(vp, vfsp);
- KASSERT(error == 0, ("insmntque() failed: error %d", error));
-
- /*
- * Initialize vnode and hold parent.
- */
- if (pvp)
- VN_HOLD(pvp);
-
- return (vp);
-}
-
-/*
- * gfs_dir_create: creates a new directory in the parent
- *
- * size - size of private data structure (v_data)
- * pvp - parent vnode (GFS directory)
- * ops - vnode operations vector
- * entries - NULL-terminated list of static entries (if any)
- * maxlen - maximum length of a directory entry
- * readdir_cb - readdir callback (see gfs_dir_readdir)
- * inode_cb - inode callback (see gfs_dir_readdir)
- * lookup_cb - lookup callback (see gfs_dir_lookup)
- *
- * In order to use this function, the first member of the private vnode
- * structure (v_data) must be a gfs_dir_t. For each directory, there are
- * static entries, defined when the structure is initialized, and dynamic
- * entries, retrieved through callbacks.
- *
- * If a directory has static entries, then it must supply a inode callback,
- * which will compute the inode number based on the parent and the index.
- * For a directory with dynamic entries, the caller must supply a readdir
- * callback and a lookup callback. If a static lookup fails, we fall back to
- * the supplied lookup callback, if any.
- *
- * This function also performs the same initialization as gfs_file_create().
- */
-vnode_t *
-gfs_dir_create(size_t struct_size, vnode_t *pvp, vfs_t *vfsp, vnodeops_t *ops,
- gfs_dirent_t *entries, gfs_inode_cb inode_cb, int maxlen,
- gfs_readdir_cb readdir_cb, gfs_lookup_cb lookup_cb)
-{
- vnode_t *vp;
- gfs_dir_t *dp;
- gfs_dirent_t *de;
-
- vp = gfs_file_create(struct_size, pvp, vfsp, ops);
- vp->v_type = VDIR;
-
- dp = vp->v_data;
- dp->gfsd_file.gfs_type = GFS_DIR;
- dp->gfsd_maxlen = maxlen;
-
- if (entries != NULL) {
- for (de = entries; de->gfse_name != NULL; de++)
- dp->gfsd_nstatic++;
-
- dp->gfsd_static = kmem_alloc(
- dp->gfsd_nstatic * sizeof (gfs_dirent_t), KM_SLEEP);
- bcopy(entries, dp->gfsd_static,
- dp->gfsd_nstatic * sizeof (gfs_dirent_t));
- }
-
- dp->gfsd_readdir = readdir_cb;
- dp->gfsd_lookup = lookup_cb;
- dp->gfsd_inode = inode_cb;
-
- mutex_init(&dp->gfsd_lock, NULL, MUTEX_DEFAULT, NULL);
-
- return (vp);
-}
-
-/*
- * gfs_root_create(): create a root vnode for a GFS filesystem
- *
- * Similar to gfs_dir_create(), this creates a root vnode for a filesystem. The
- * only difference is that it takes a vfs_t instead of a vnode_t as its parent.
- */
-vnode_t *
-gfs_root_create(size_t size, vfs_t *vfsp, vnodeops_t *ops, ino64_t ino,
- gfs_dirent_t *entries, gfs_inode_cb inode_cb, int maxlen,
- gfs_readdir_cb readdir_cb, gfs_lookup_cb lookup_cb)
-{
- vnode_t *vp;
-
- VFS_HOLD(vfsp);
- vp = gfs_dir_create(size, NULL, vfsp, ops, entries, inode_cb,
- maxlen, readdir_cb, lookup_cb);
- /* Manually set the inode */
- ((gfs_file_t *)vp->v_data)->gfs_ino = ino;
- vp->v_flag |= VROOT;
-
- return (vp);
-}
-
-/*
- * gfs_file_inactive()
- *
- * Called from the VOP_INACTIVE() routine. If necessary, this routine will
- * remove the given vnode from the parent directory and clean up any references
- * in the VFS layer.
- *
- * If the vnode was not removed (due to a race with vget), then NULL is
- * returned. Otherwise, a pointer to the private data is returned.
- */
-void *
-gfs_file_inactive(vnode_t *vp)
-{
- int i;
- gfs_dirent_t *ge = NULL;
- gfs_file_t *fp = vp->v_data;
- gfs_dir_t *dp = NULL;
- void *data;
-
- if (fp->gfs_parent == NULL)
- goto found;
-
- dp = fp->gfs_parent->v_data;
-
- /*
- * First, see if this vnode is cached in the parent.
- */
- gfs_dir_lock(dp);
-
- /*
- * Find it in the set of static entries.
- */
- for (i = 0; i < dp->gfsd_nstatic; i++) {
- ge = &dp->gfsd_static[i];
-
- if (ge->gfse_vnode == vp)
- goto found;
- }
-
- /*
- * If 'ge' is NULL, then it is a dynamic entry.
- */
- ge = NULL;
-
-found:
- VI_LOCK(vp);
- ASSERT(vp->v_count < 2);
- /*
- * Really remove this vnode
- */
- data = vp->v_data;
- if (ge != NULL) {
- /*
- * If this was a statically cached entry, simply set the
- * cached vnode to NULL.
- */
- ge->gfse_vnode = NULL;
- }
- if (vp->v_count == 1) {
- vp->v_usecount--;
- vdropl(vp);
- } else {
- VI_UNLOCK(vp);
- }
-
- /*
- * Free vnode and release parent
- */
- if (fp->gfs_parent) {
- gfs_dir_unlock(dp);
- VI_LOCK(fp->gfs_parent);
- fp->gfs_parent->v_usecount--;
- VI_UNLOCK(fp->gfs_parent);
- } else {
- ASSERT(vp->v_vfsp != NULL);
- VFS_RELE(vp->v_vfsp);
- }
-
- return (data);
-}
-
-/*
- * gfs_dir_inactive()
- *
- * Same as above, but for directories.
- */
-void *
-gfs_dir_inactive(vnode_t *vp)
-{
- gfs_dir_t *dp;
-
- ASSERT(vp->v_type == VDIR);
-
- if ((dp = gfs_file_inactive(vp)) != NULL) {
- mutex_destroy(&dp->gfsd_lock);
- if (dp->gfsd_nstatic)
- kmem_free(dp->gfsd_static,
- dp->gfsd_nstatic * sizeof (gfs_dirent_t));
- }
-
- return (dp);
-}
-
-/*
- * gfs_dir_lookup()
- *
- * Looks up the given name in the directory and returns the corresponding vnode,
- * if found.
- *
- * First, we search statically defined entries, if any. If a match is found,
- * and GFS_CACHE_VNODE is set and the vnode exists, we simply return the
- * existing vnode. Otherwise, we call the static entry's callback routine,
- * caching the result if necessary.
- *
- * If no static entry is found, we invoke the lookup callback, if any. The
- * arguments to this callback are:
- *
- * int gfs_lookup_cb(vnode_t *pvp, const char *nm, vnode_t **vpp);
- *
- * pvp - parent vnode
- * nm - name of entry
- * vpp - pointer to resulting vnode
- *
- * Returns 0 on success, non-zero on error.
- */
-int
-gfs_dir_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp)
-{
- int i;
- gfs_dirent_t *ge;
- vnode_t *vp;
- gfs_dir_t *dp = dvp->v_data;
- int ret = 0;
-
- ASSERT(dvp->v_type == VDIR);
-
- if (gfs_lookup_dot(vpp, dvp, dp->gfsd_file.gfs_parent, nm) == 0)
- return (0);
-
- gfs_dir_lock(dp);
-
- /*
- * Search static entries.
- */
- for (i = 0; i < dp->gfsd_nstatic; i++) {
- ge = &dp->gfsd_static[i];
-
- if (strcmp(ge->gfse_name, nm) == 0) {
- if (ge->gfse_vnode) {
- ASSERT(ge->gfse_flags & GFS_CACHE_VNODE);
- vp = ge->gfse_vnode;
- VN_HOLD(vp);
- goto out;
- }
-
- /*
- * We drop the directory lock, as the constructor will
- * need to do KM_SLEEP allocations. If we return from
- * the constructor only to find that a parallel
- * operation has completed, and GFS_CACHE_VNODE is set
- * for this entry, we discard the result in favor of the
- * cached vnode.
- */
- gfs_dir_unlock(dp);
- vp = ge->gfse_ctor(dvp);
- gfs_dir_lock(dp);
-
- ((gfs_file_t *)vp->v_data)->gfs_index = i;
-
- /* Set the inode according to the callback. */
- ((gfs_file_t *)vp->v_data)->gfs_ino =
- dp->gfsd_inode(dvp, i);
-
- if (ge->gfse_flags & GFS_CACHE_VNODE) {
- if (ge->gfse_vnode == NULL) {
- ge->gfse_vnode = vp;
- } else {
- /*
- * A parallel constructor beat us to it;
- * return existing vnode. We have to be
- * careful because we can't release the
- * current vnode while holding the
- * directory lock; its inactive routine
- * will try to lock this directory.
- */
- vnode_t *oldvp = vp;
- vp = ge->gfse_vnode;
- VN_HOLD(vp);
-
- gfs_dir_unlock(dp);
- VN_RELE(oldvp);
- gfs_dir_lock(dp);
- }
- }
-
- goto out;
- }
- }
-
- /*
- * See if there is a dynamic constructor.
- */
- if (dp->gfsd_lookup) {
- ino64_t ino;
- gfs_file_t *fp;
-
- /*
- * Once again, drop the directory lock, as the lookup routine
- * will need to allocate memory, or otherwise deadlock on this
- * directory.
- */
- gfs_dir_unlock(dp);
- ret = dp->gfsd_lookup(dvp, nm, &vp, &ino);
- gfs_dir_lock(dp);
- if (ret != 0)
- goto out;
-
- fp = (gfs_file_t *)vp->v_data;
- fp->gfs_index = -1;
- fp->gfs_ino = ino;
- } else {
- /*
- * No static entry found, and there is no lookup callback, so
- * return ENOENT.
- */
- ret = ENOENT;
- }
-
-out:
- gfs_dir_unlock(dp);
-
- if (ret == 0)
- *vpp = vp;
- else
- *vpp = NULL;
-
- return (ret);
-}
-
-/*
- * gfs_dir_readdir: does a readdir() on the given directory
- *
- * dvp - directory vnode
- * uiop - uio structure
- * eofp - eof pointer
- * data - arbitrary data passed to readdir callback
- *
- * This routine does all the readdir() dirty work. Even so, the caller must
- * supply two callbacks in order to get full compatibility.
- *
- * If the directory contains static entries, an inode callback must be
- * specified. This avoids having to create every vnode and call VOP_GETATTR()
- * when reading the directory. This function has the following arguments:
- *
- * ino_t gfs_inode_cb(vnode_t *vp, int index);
- *
- * vp - vnode for the directory
- * index - index in original gfs_dirent_t array
- *
- * Returns the inode number for the given entry.
- *
- * For directories with dynamic entries, a readdir callback must be provided.
- * This is significantly more complex, thanks to the particulars of
- * VOP_READDIR().
- *
- * int gfs_readdir_cb(vnode_t *vp, struct dirent64 *dp, int *eofp,
- * offset_t *off, offset_t *nextoff, void *data)
- *
- * vp - directory vnode
- * dp - directory entry, sized according to maxlen given to
- * gfs_dir_create(). callback must fill in d_name and
- * d_ino.
- * eofp - callback must set to 1 when EOF has been reached
- * off - on entry, the last offset read from the directory. Callback
- * must set to the offset of the current entry, typically left
- * untouched.
- * nextoff - callback must set to offset of next entry. Typically
- * (off + 1)
- * data - caller-supplied data
- *
- * Return 0 on success, or error on failure.
- */
-int
-gfs_dir_readdir(vnode_t *dvp, uio_t *uiop, int *eofp, int *ncookies,
- u_long **cookies, void *data)
-{
- gfs_readdir_state_t gstate;
- int error, eof = 0;
- ino64_t ino, pino;
- offset_t off, next;
- gfs_dir_t *dp = dvp->v_data;
-
- ino = dp->gfsd_file.gfs_ino;
-
- if (dp->gfsd_file.gfs_parent == NULL)
- pino = ino; /* root of filesystem */
- else
- pino = ((gfs_file_t *)
- (dp->gfsd_file.gfs_parent->v_data))->gfs_ino;
-
- if ((error = gfs_readdir_init(&gstate, dp->gfsd_maxlen, 1, uiop,
- pino, ino)) != 0)
- return (error);
-
- while ((error = gfs_readdir_pred(&gstate, uiop, &off, ncookies,
- cookies)) == 0 && !eof) {
-
- if (off >= 0 && off < dp->gfsd_nstatic) {
- ino = dp->gfsd_inode(dvp, off);
-
- if ((error = gfs_readdir_emit(&gstate, uiop,
- off, ino, dp->gfsd_static[off].gfse_name, ncookies,
- cookies)) != 0)
- break;
-
- } else if (dp->gfsd_readdir) {
- off -= dp->gfsd_nstatic;
-
- if ((error = dp->gfsd_readdir(dvp,
- gstate.grd_dirent, &eof, &off, &next,
- data)) != 0 || eof)
- break;
-
- off += dp->gfsd_nstatic + 2;
- next += dp->gfsd_nstatic + 2;
-
- if ((error = gfs_readdir_emit_int(&gstate, uiop,
- next, ncookies, cookies)) != 0)
- break;
- } else {
- /*
- * Offset is beyond the end of the static entries, and
- * we have no dynamic entries. Set EOF.
- */
- eof = 1;
- }
- }
-
- return (gfs_readdir_fini(&gstate, error, eofp, eof));
-}
-
-/*
- * gfs_vop_readdir: VOP_READDIR() entry point
- *
- * For use directly in vnode ops table. Given a GFS directory, calls
- * gfs_dir_readdir() as necessary.
- */
-/* ARGSUSED */
-int
-gfs_vop_readdir(ap)
- struct vop_readdir_args /* {
- struct vnode *a_vp;
- struct uio *a_uio;
- struct ucred *a_cred;
- int *a_eofflag;
- int *ncookies;
- u_long **a_cookies;
- } */ *ap;
-{
- vnode_t *vp = ap->a_vp;
- uio_t *uiop = ap->a_uio;
- int *eofp = ap->a_eofflag;
- int ncookies = 0;
- u_long *cookies = NULL;
- int error;
-
- if (ap->a_ncookies) {
- /*
- * Minimum entry size is dirent size and 1 byte for a file name.
- */
- ncookies = uiop->uio_resid / (sizeof(struct dirent) - sizeof(((struct dirent *)NULL)->d_name) + 1);
- cookies = malloc(ncookies * sizeof(u_long), M_TEMP, M_WAITOK);
- *ap->a_cookies = cookies;
- *ap->a_ncookies = ncookies;
- }
-
- error = gfs_dir_readdir(vp, uiop, eofp, &ncookies, &cookies, NULL);
-
- if (error == 0) {
- /* Subtract unused cookies */
- if (ap->a_ncookies)
- *ap->a_ncookies -= ncookies;
- } else if (ap->a_ncookies) {
- free(*ap->a_cookies, M_TEMP);
- *ap->a_cookies = NULL;
- *ap->a_ncookies = 0;
- }
-
- return (error);
-}
-
-/*
- * gfs_vop_inactive: VOP_INACTIVE() entry point
- *
- * Given a vnode that is a GFS file or directory, call gfs_file_inactive() or
- * gfs_dir_inactive() as necessary, and kmem_free()s associated private data.
- */
-/* ARGSUSED */
-int
-gfs_vop_inactive(ap)
- struct vop_inactive_args /* {
- struct vnode *a_vp;
- struct thread *a_td;
- } */ *ap;
-{
- vnode_t *vp = ap->a_vp;
- gfs_file_t *fp = vp->v_data;
- void *data;
-
- if (fp->gfs_type == GFS_DIR)
- data = gfs_dir_inactive(vp);
- else
- data = gfs_file_inactive(vp);
-
- if (data != NULL)
- kmem_free(data, fp->gfs_size);
- vp->v_data = NULL;
- return (0);
-}
OpenPOWER on IntegriCloud