summaryrefslogtreecommitdiff
path: root/sys/xfs/xfs_node.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/xfs/xfs_node.c')
-rw-r--r--sys/xfs/xfs_node.c453
1 files changed, 453 insertions, 0 deletions
diff --git a/sys/xfs/xfs_node.c b/sys/xfs/xfs_node.c
new file mode 100644
index 00000000000..3c063d0db33
--- /dev/null
+++ b/sys/xfs/xfs_node.c
@@ -0,0 +1,453 @@
+/* $OpenBSD: xfs_node.c,v 1.1 1998/08/30 16:47:21 art Exp $ */
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Kungliga Tekniska
+ * Högskolan and its contributors.
+ *
+ * 4. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/uio.h>
+#include <sys/namei.h>
+#include <sys/systm.h>
+#include <sys/dirent.h>
+#include <sys/mount.h>
+
+#include <xfs/xfs_common.h>
+#include <xfs/xfs_fs.h>
+#include <xfs/xfs_deb.h>
+
+RCSID("$KTH: xfs_node.c,v 1.16 1998/07/09 19:58:35 art Exp $");
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+extern int (**xfs_vnodeop_p) (void *);
+#elif defined(__FreeBSD__)
+extern vop_t **xfs_vnodeop_p;
+#endif
+
+/*
+ * Create a new xfs_node and make a VN_HOLD()!
+ *
+ * Also prevents creation of duplicates. This happens
+ * whenever there are more than one name to a file,
+ * "." and ".." are common cases.
+ */
+
+int
+new_xfs_node(struct xfs *xfsp,
+ struct xfs_msg_node *node,
+ struct xfs_node **xpp,
+ struct proc *p)
+{
+ int do_vget = 0;
+ struct xfs_node *result;
+
+ XFSDEB(XDEBNODE, ("new_xfs_node %d.%d.%d.%d\n",
+ node->handle.a,
+ node->handle.b,
+ node->handle.c,
+ node->handle.d));
+
+ /* Does not allow duplicates */
+ result = xfs_node_find(xfsp, &node->handle);
+
+ if (result == 0) {
+ int error;
+ struct vnode *v;
+
+ result = xfs_alloc(sizeof(*result));
+ if (result == 0) {
+ printf("xfs_alloc(%d) failed\n", (int) sizeof(*result));
+ panic("new_xfs_node: You Loose!");
+ }
+ bzero(result, sizeof(*result));
+
+ error = getnewvnode(VT_AFS, XFS_TO_VFS(xfsp), xfs_vnodeop_p, &v);
+ if (error) {
+ XFSDEB(XDEBVNOPS,
+ ("XFS PANIC! new_xfs_node: could not allocate node"));
+ return error;
+ }
+ v->v_data = result;
+ result->vn = v;
+
+ result->anonrights = node->anonrights;
+
+ result->handle = node->handle;
+ result->flags = 0;
+ result->tokens = 0;
+
+ xfsp->nnodes++;
+ } else {
+ /* Node is already cached */
+ do_vget = 1;
+ }
+
+ /* Init other fields */
+ xfs_attr2vattr(&node->attr, &result->attr);
+ result->vn->v_type = result->attr.va_type;
+ XFS_TOKEN_SET(result, XFS_ATTR_R, XFS_ATTR_MASK);
+ bcopy(node->id, result->id, sizeof(result->id));
+ bcopy(node->rights, result->rights, sizeof(result->rights));
+
+ /*
+ * We need to postpone this until here because (on FreeBSD) vget
+ * tries to install a pager on the vnode and for that it wants to
+ * retrieve the size with getattr.
+ */
+
+ if(do_vget)
+ vget(XNODE_TO_VNODE(result), 0, p);
+
+ *xpp = result;
+ XFSDEB(XDEBNODE, ("return: new_xfs_node\n"));
+ return 0;
+}
+
+void
+free_xfs_node(struct xfs_node *node)
+{
+ struct xfs *xfsp = XFS_FROM_XNODE(node);
+
+ XFSDEB(XDEBNODE, ("free_xfs_node starting\n"));
+
+ /* XXX Really need to put back dirty data first. */
+
+ if (DATA_FROM_XNODE(node)) {
+ vrele(DATA_FROM_XNODE(node));
+ DATA_FROM_XNODE(node) = NULL;
+ }
+ xfsp->nnodes--;
+ XNODE_TO_VNODE(node)->v_data = NULL;
+ xfs_free(node, sizeof(*node));
+
+ XFSDEB(XDEBNODE, ("free_xfs_node done\n"));
+}
+
+int
+free_all_xfs_nodes(struct xfs *xfsp, int flags)
+{
+ int error = 0;
+ struct mount *mp = XFS_TO_VFS(xfsp);
+
+ if (mp == NULL) {
+ XFSDEB(XDEBNODE, ("free_all_xfs_nodes already freed\n"));
+ return 0;
+ }
+
+ XFSDEB(XDEBNODE, ("free_all_xfs_nodes starting\n"));
+
+ xfs_dnlc_purge(mp);
+
+ XFSDEB(XDEBNODE, ("free_all_xfs_nodes now removing root\n"));
+
+ if (xfsp->root) {
+ vgone(XNODE_TO_VNODE(xfsp->root));
+ xfsp->root = 0;
+ }
+
+ XFSDEB(XDEBNODE, ("free_all_xfs_nodes root removed\n"));
+ XFSDEB(XDEBNODE, ("free_all_xfs_nodes now killing all remaining nodes\n"));
+
+ error = vflush(mp, NULL, flags);
+
+ if (error) {
+ XFSDEB(XDEBNODE, ("xfree_all_xfs_nodes: vflush() error == %d\n",
+ error));
+ return error;
+ }
+
+ XFSDEB(XDEBNODE, ("free_all_xfs_nodes done\n"));
+ return error;
+}
+
+struct xfs_node *
+xfs_node_find(struct xfs *xfsp, xfs_handle *handlep)
+{
+ struct vnode *t;
+ struct xfs_node *xn = NULL;
+
+ XFSDEB(XDEBNODE, ("xfs_node_find: xfsp = %p handlep = %p\n",
+ xfsp, handlep));
+
+ for (t = XFS_TO_VFS(xfsp)->mnt_vnodelist.lh_first;
+ t != NULL;
+ t = t->v_mntvnodes.le_next) {
+ xn = VNODE_TO_XNODE(t);
+
+ if (xn && xfs_handle_eq(&xn->handle, handlep))
+ break;
+ }
+
+ if (t != NULL)
+ return xn;
+ else
+ return NULL;
+}
+
+void
+vattr2xfs_attr(const struct vattr *va, struct xfs_attr *xa)
+{
+ bzero(xa, sizeof(*xa));
+ if (va->va_mode != (mode_t) VNOVAL)
+ XA_SET_MODE(xa, va->va_mode);
+ if (va->va_nlink != VNOVAL)
+ XA_SET_NLINK(xa, va->va_nlink);
+ if (va->va_size != (u_quad_t) VNOVAL)
+ XA_SET_SIZE(xa, va->va_size);
+ if (va->va_uid != VNOVAL)
+ XA_SET_UID(xa, va->va_uid);
+ if (va->va_gid != VNOVAL)
+ XA_SET_GID(xa, va->va_gid);
+ if (va->va_atime.tv_sec != VNOVAL)
+ XA_SET_ATIME(xa, va->va_atime.tv_sec);
+ if (va->va_mtime.tv_sec != VNOVAL)
+ XA_SET_MTIME(xa, va->va_mtime.tv_sec);
+ if (va->va_ctime.tv_sec != VNOVAL)
+ XA_SET_CTIME(xa, va->va_ctime.tv_sec);
+ if (va->va_fileid != VNOVAL)
+ XA_SET_FILEID(xa, va->va_fileid);
+ switch (va->va_type) {
+ case VNON:
+ xa->xa_type = XFS_FILE_NON;
+ break;
+ case VREG:
+ xa->xa_type = XFS_FILE_REG;
+ break;
+ case VDIR:
+ xa->xa_type = XFS_FILE_DIR;
+ break;
+ case VBLK:
+ xa->xa_type = XFS_FILE_BLK;
+ break;
+ case VCHR:
+ xa->xa_type = XFS_FILE_CHR;
+ break;
+ case VLNK:
+ xa->xa_type = XFS_FILE_LNK;
+ break;
+ case VSOCK:
+ xa->xa_type = XFS_FILE_SOCK;
+ break;
+ case VFIFO:
+ xa->xa_type = XFS_FILE_FIFO;
+ break;
+ case VBAD:
+ xa->xa_type = XFS_FILE_BAD;
+ break;
+ default:
+ panic("xfs_attr2attr: bad value");
+ }
+}
+
+void
+xfs_attr2vattr(const struct xfs_attr *xa, struct vattr *va)
+{
+ VATTR_NULL(va);
+ if (XA_VALID_MODE(xa))
+ va->va_mode = xa->xa_mode;
+ if (XA_VALID_NLINK(xa))
+ va->va_nlink = xa->xa_nlink;
+ if (XA_VALID_SIZE(xa))
+ va->va_size = xa->xa_size;
+ if (XA_VALID_UID(xa))
+ va->va_uid = xa->xa_uid;
+ if (XA_VALID_GID(xa))
+ va->va_gid = xa->xa_gid;
+ if (XA_VALID_ATIME(xa)) {
+ va->va_atime.tv_sec = xa->xa_atime;
+ va->va_atime.tv_nsec = 0;
+ }
+ if (XA_VALID_MTIME(xa)) {
+ va->va_mtime.tv_sec = xa->xa_mtime;
+ va->va_mtime.tv_nsec = 0;
+ }
+ if (XA_VALID_CTIME(xa)) {
+ va->va_ctime.tv_sec = xa->xa_ctime;
+ va->va_ctime.tv_nsec = 0;
+ }
+ if (XA_VALID_FILEID(xa)) {
+ va->va_fileid = xa->xa_fileid;
+ }
+ if (XA_VALID_TYPE(xa)) {
+ switch (xa->xa_type) {
+ case XFS_FILE_NON:
+ va->va_type = VNON;
+ break;
+ case XFS_FILE_REG:
+ va->va_type = VREG;
+ break;
+ case XFS_FILE_DIR:
+ va->va_type = VDIR;
+ break;
+ case XFS_FILE_BLK:
+ va->va_type = VBLK;
+ break;
+ case XFS_FILE_CHR:
+ va->va_type = VCHR;
+ break;
+ case XFS_FILE_LNK:
+ va->va_type = VLNK;
+ break;
+ case XFS_FILE_SOCK:
+ va->va_type = VSOCK;
+ break;
+ case XFS_FILE_FIFO:
+ va->va_type = VFIFO;
+ break;
+ case XFS_FILE_BAD:
+ va->va_type = VBAD;
+ break;
+ default:
+ panic("xfs_attr2vattr: bad value");
+ }
+ }
+ va->va_flags = 0;
+ va->va_blocksize = 8192;
+ va->va_bytes = va->va_size;
+}
+
+
+struct long_entry {
+ struct vnode *dvp, *vp;
+ char name[MAXNAMLEN + 1];
+ size_t len;
+ u_long dvpid, vpid;
+};
+
+static struct long_entry tbl;
+
+int
+xfs_dnlc_enter(struct vnode *dvp, char *name, struct vnode *vp)
+{
+ struct componentname cn;
+ char *p;
+
+ XFSDEB(XDEBDNLC, ("xfs_dnlc_enter(0x%x, \"%s\", 0x%x)\n",
+ (int) dvp, name, (int) vp));
+
+ XFSDEB(XDEBDNLC, ("xfs_dnlc_enter: v_id = %ld\n",
+ dvp->v_id));
+
+ cn.cn_namelen = strlen(name);
+ cn.cn_nameptr = name;
+ cn.cn_hash = 0;
+ for (p = name; *p; ++p)
+ cn.cn_hash += *p;
+
+ XFSDEB(XDEBDNLC, ("xfs_dnlc_enter: calling cache_enter:"
+ "dvp = %p, vp = %p, cnp = (%s, %ld, %lu)\n",
+ dvp, vp, cn.cn_nameptr, cn.cn_namelen, cn.cn_hash));
+
+ if (cn.cn_namelen <= NCHNAMLEN)
+ cache_enter(dvp, vp, &cn);
+
+ tbl.len = cn.cn_namelen;
+ bcopy(name, tbl.name, tbl.len);
+ tbl.dvp = dvp;
+ tbl.vp = vp;
+ tbl.dvpid = dvp->v_id;
+ tbl.vpid = vp->v_id;
+
+ return 0;
+}
+
+int
+xfs_dnlc_lookup(struct vnode *dvp,
+ struct componentname *cnp,
+ struct vnode **res)
+{
+ int error;
+
+ XFSDEB(XDEBDNLC, ("xfs_dnlc_lookup(0x%x, \"%s\")\n",
+ (int) dvp, cnp->cn_nameptr));
+
+ XFSDEB(XDEBDNLC, ("xfs_dnlc_lookup: v_id = %ld\n",
+ dvp->v_id));
+
+ XFSDEB(XDEBDNLC, ("xfs_dnlc_lookup: calling cache_lookup:"
+ "dvp = %p, cnp = (%s, %ld, %lu), flags = %lx\n",
+ dvp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_hash,
+ cnp->cn_flags));
+
+ cnp->cn_flags |= MAKEENTRY;
+
+ error = cache_lookup(dvp, res, cnp);
+
+ XFSDEB(XDEBDNLC, ("xfs_dnlc_lookup: cache_lookup returned. "
+ "error == %d, *res == %p\n", error, *res));
+
+ if (error == -1 || error == ENOENT)
+ return error;
+
+ if (tbl.dvp == dvp
+ && tbl.len == cnp->cn_namelen
+ && strncmp(tbl.name, cnp->cn_nameptr, cnp->cn_namelen) == 0
+ && tbl.dvpid == tbl.dvp->v_id
+ && tbl.vpid == tbl.vp->v_id) {
+ *res = tbl.vp;
+ return -1;
+ }
+
+ return 0;
+}
+
+void
+xfs_dnlc_purge(struct mount *mp)
+{
+ XFSDEB(XDEBDNLC, ("xfs_dnlc_purge()\n"));
+
+ tbl.dvp = tbl.vp = NULL;
+ tbl.name[0] = '\0';
+ tbl.len = 0;
+ tbl.dvpid = tbl.vpid = 0;
+
+ cache_purgevfs(mp);
+}
+
+/*
+ * Returns 1 if pag has any rights set in the node
+ */
+int
+xfs_has_pag(const struct xfs_node *xn, pag_t pag)
+{
+ int i;
+
+ for (i = 0; i < MAXRIGHTS; i++)
+ if (xn->id[i] == pag)
+ return 1;
+
+ return 0;
+}