summaryrefslogtreecommitdiff
path: root/sys/nnpfs/nnpfs_vnodeops-common.c
diff options
context:
space:
mode:
authorJanne Johansson <jj@cvs.openbsd.org>2009-06-03 14:45:57 +0000
committerJanne Johansson <jj@cvs.openbsd.org>2009-06-03 14:45:57 +0000
commitea9bbf428f51194a52c45ac274c35dba174a741c (patch)
tree301aa894fd92a097d769b8cac575c8a0fce07329 /sys/nnpfs/nnpfs_vnodeops-common.c
parent0c52879fa54117b2bd312fe5fff17f310dbdb7eb (diff)
Arla client rename from xfs to nnpfs for later upgrades. Tested on various arches. ok todd@ beck@
Diffstat (limited to 'sys/nnpfs/nnpfs_vnodeops-common.c')
-rw-r--r--sys/nnpfs/nnpfs_vnodeops-common.c1146
1 files changed, 1146 insertions, 0 deletions
diff --git a/sys/nnpfs/nnpfs_vnodeops-common.c b/sys/nnpfs/nnpfs_vnodeops-common.c
new file mode 100644
index 00000000000..e8ed71842e9
--- /dev/null
+++ b/sys/nnpfs/nnpfs_vnodeops-common.c
@@ -0,0 +1,1146 @@
+/*
+ * Copyright (c) 1995 - 2002 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. 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.
+ */
+
+/*
+ * NNPFS operations.
+ */
+
+#include <nnpfs/nnpfs_locl.h>
+#include <nnpfs/nnpfs_message.h>
+#include <nnpfs/nnpfs_common.h>
+#include <nnpfs/nnpfs_fs.h>
+#include <nnpfs/nnpfs_dev.h>
+#include <nnpfs/nnpfs_deb.h>
+#include <nnpfs/nnpfs_syscalls.h>
+#include <nnpfs/nnpfs_vnodeops.h>
+
+RCSID("$arla: nnpfs_vnodeops-common.c,v 1.94 2003/01/27 11:58:50 lha Exp $");
+
+static void
+nnpfs_handle_stale(struct nnpfs_node *xn)
+{
+#if __APPLE__
+ struct vnode *vp = XNODE_TO_VNODE(xn);
+#endif
+
+ if ((xn->flags & NNPFS_STALE) == 0)
+ return;
+
+#if __APPLE__
+ if (UBCISVALID(vp) && !ubc_isinuse(vp, 1)) {
+ xn->flags &= ~NNPFS_STALE;
+ ubc_setsize(vp, 0);
+ NNPFS_TOKEN_CLEAR(xn, ~0,
+ NNPFS_OPEN_MASK | NNPFS_ATTR_MASK |
+ NNPFS_DATA_MASK | NNPFS_LOCK_MASK);
+ }
+#endif
+}
+
+int
+nnpfs_open_valid(struct vnode *vp, struct ucred *cred, d_thread_t *p,
+ u_int tok)
+{
+ struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
+ struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
+ int error = 0;
+
+ NNPFSDEB(XDEBVFOPS, ("nnpfs_open_valid\n"));
+
+ nnpfs_handle_stale(xn);
+
+ do {
+ if (!NNPFS_TOKEN_GOT(xn, tok)) {
+ struct nnpfs_message_open msg;
+
+ msg.header.opcode = NNPFS_MSG_OPEN;
+ msg.cred.uid = cred->cr_uid;
+ msg.cred.pag = nnpfs_get_pag(cred);
+ msg.handle = xn->handle;
+ msg.tokens = tok;
+
+ error = nnpfs_message_rpc(nnpfsp->fd, &msg.header, sizeof(msg), p);
+
+ if (error == 0)
+ error = ((struct nnpfs_message_wakeup *) & msg)->error;
+ } else {
+ goto done;
+ }
+ } while (error == 0);
+
+done:
+ NNPFSDEB(XDEBVFOPS, ("nnpfs_open_valid: error = %d\n", error));
+
+ return error;
+}
+
+int
+nnpfs_attr_valid(struct vnode *vp, struct ucred *cred, d_thread_t *p,
+ u_int tok)
+{
+ struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
+ struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
+ int error = 0;
+ nnpfs_pag_t pag = nnpfs_get_pag(cred);
+
+ do {
+ if (!NNPFS_TOKEN_GOT(xn, tok) || !nnpfs_has_pag(xn, pag)) {
+ struct nnpfs_message_getattr msg;
+
+ msg.header.opcode = NNPFS_MSG_GETATTR;
+ msg.cred.uid = cred->cr_uid;
+ msg.cred.pag = pag;
+ msg.handle = xn->handle;
+ error = nnpfs_message_rpc(nnpfsp->fd, &msg.header, sizeof(msg), p);
+ if (error == 0)
+ error = ((struct nnpfs_message_wakeup *) & msg)->error;
+ } else {
+ goto done;
+ }
+ } while (error == 0);
+
+done:
+ return error;
+}
+
+int
+nnpfs_data_valid(struct vnode *vp, struct ucred *cred, d_thread_t *p,
+ u_int tok, uint32_t want_offset)
+{
+ struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
+ struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
+ int error = 0;
+ uint32_t offset;
+ struct nnpfs_message_getdata msg;
+
+ do {
+ offset = want_offset;
+ if (NNPFS_TOKEN_GOT(xn, tok|NNPFS_ATTR_R) && offset > xn->attr.va_size) {
+ offset = xn->attr.va_size;
+ }
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_data_valid: offset: want %ld has %ld, "
+ "tokens: want %lx has %lx length: %ld\n",
+ (long) offset, (long) xn->offset,
+ (long) tok, (long) xn->tokens,
+ (long) xn->attr.va_size));
+
+ if (NNPFS_TOKEN_GOT(xn, tok)) {
+ if (offset <= xn->offset || xn->attr.va_type == VDIR) {
+ break;
+ }
+ }
+
+ msg.header.opcode = NNPFS_MSG_GETDATA;
+ msg.cred.uid = cred->cr_uid;
+ msg.cred.pag = nnpfs_get_pag(cred);
+ msg.handle = xn->handle;
+ msg.tokens = tok;
+ msg.offset = offset;
+
+ error = nnpfs_message_rpc(nnpfsp->fd, &msg.header, sizeof(msg), p);
+
+ if (error == 0)
+ error = ((struct nnpfs_message_wakeup *) & msg)->error;
+
+ } while (error == 0);
+
+ return error;
+}
+
+int
+nnpfs_open_common(struct vnode *vp,
+ int mode,
+ struct ucred *cred,
+ d_thread_t *p)
+{
+ struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
+ int ret;
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_open\n"));
+
+ if (mode & FWRITE) {
+ ret = nnpfs_open_valid(vp, cred, p, NNPFS_OPEN_NW);
+ } else {
+ ret = nnpfs_open_valid(vp, cred, p, NNPFS_OPEN_NR);
+ }
+
+ /* always update the read cred */
+
+ if (mode & FWRITE)
+ nnpfs_update_write_cred(xn, cred);
+ nnpfs_update_read_cred(xn, cred);
+
+ return ret;
+}
+
+static int
+do_fsync(struct nnpfs *nnpfsp,
+ struct nnpfs_node *xn,
+ struct ucred *cred,
+ d_thread_t *p,
+ u_int flag)
+{
+ int error;
+ struct nnpfs_message_putdata msg;
+
+ msg.header.opcode = NNPFS_MSG_PUTDATA;
+ if (cred != NOCRED) {
+ msg.cred.uid = cred->cr_uid;
+ msg.cred.pag = nnpfs_get_pag(cred);
+ } else {
+ msg.cred.uid = 0;
+ msg.cred.pag = NNPFS_ANONYMOUSID;
+ }
+ msg.handle = xn->handle;
+ vattr2nnpfs_attr(&xn->attr, &msg.attr);
+ msg.flag = flag;
+
+ error = nnpfs_message_rpc(nnpfsp->fd, &msg.header, sizeof(msg), p);
+
+ if (error == 0)
+ error = ((struct nnpfs_message_wakeup *) & msg)->error;
+
+ if (error == 0)
+ xn->flags &= ~NNPFS_DATA_DIRTY;
+
+ return error;
+}
+
+int
+nnpfs_fsync_common(struct vnode *vp, struct ucred *cred,
+ int waitfor, d_thread_t *proc)
+{
+ struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
+ struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
+ int error = 0;
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_fsync: %lx\n", (unsigned long)vp));
+
+ /*
+ * It seems that fsync is sometimes called after reclaiming a node.
+ * In that case we just look happy.
+ */
+
+ if (xn == NULL) {
+ printf("NNPFS PANIC WARNING! nnpfs_fsync called after reclaiming!\n");
+ return 0;
+ }
+
+ nnpfs_pushdirty(vp, cred, proc);
+
+ if (xn->flags & NNPFS_DATA_DIRTY) {
+#ifdef FSYNC_RECLAIM
+ /* writing back the data from this vnode failed */
+ if (waitfor & FSYNC_RECLAIM) {
+ printf("nnpfs_fsync: data lost, failed to write back\n");
+ xn->flags &= ~NNPFS_DATA_DIRTY;
+ return 0;
+ }
+#endif
+ error = do_fsync(nnpfsp, xn, cred, proc, NNPFS_WRITE | NNPFS_FSYNC);
+ }
+
+ return error;
+}
+
+int
+nnpfs_close_common(struct vnode *vp, int fflag,
+ d_thread_t *proc, struct ucred *cred)
+{
+ struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
+ struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
+ int error = 0;
+
+ NNPFSDEB(XDEBVNOPS,
+ ("nnpfs_close cred = %lx, fflag = %x, xn->flags = %x\n",
+ (unsigned long)cred, fflag, xn->flags));
+
+ if (vp->v_type == VREG)
+ nnpfs_pushdirty(vp, cred, proc);
+
+ if (fflag & FWRITE && xn->flags & NNPFS_DATA_DIRTY)
+ error = do_fsync(nnpfsp, xn, cred, proc, NNPFS_WRITE);
+
+ return error;
+}
+
+size_t
+nnpfs_uio_end_length (struct uio *uio)
+{
+#ifdef DIAGNOSTIC
+ size_t sz = 0;
+ int i;
+
+ for (i = 0; i < uio->uio_iovcnt; i++)
+ sz += uio->uio_iov[i].iov_len;
+ if (sz != uio->uio_resid)
+ panic("nnpfs_uio_end_length");
+#endif
+ return uio->uio_offset + uio->uio_resid;
+}
+
+
+int
+nnpfs_read_common(struct vnode *vp, struct uio *uio, int ioflag,
+ struct ucred *cred)
+{
+ int error = 0;
+ int i;
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_read\n"));
+
+ nnpfs_update_read_cred(VNODE_TO_XNODE(vp), cred);
+
+#ifdef HAVE_FREEBSD_THREAD
+ error = nnpfs_data_valid(vp, cred, nnpfs_uio_to_thread(uio), NNPFS_DATA_R,
+ nnpfs_uio_end_length(uio));
+#else
+ error = nnpfs_data_valid(vp, cred, nnpfs_uio_to_proc(uio), NNPFS_DATA_R,
+ nnpfs_uio_end_length(uio));
+#endif
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_read: iovcnt: %d\n", uio->uio_iovcnt));
+ for (i = 0; i < uio->uio_iovcnt; i++)
+ NNPFSDEB(XDEBVNOPS, (" base: %lx len: %lu\n",
+ (unsigned long)uio->uio_iov[i].iov_base,
+ (unsigned long)uio->uio_iov[i].iov_len));
+
+ if (error == 0) {
+ struct vnode *t = DATA_FROM_VNODE(vp);
+
+#ifdef HAVE_FREEBSD_THREAD
+ nnpfs_vfs_readlock(t, nnpfs_uio_to_thread(uio));
+ nnpfs_vop_read(t, uio, ioflag, cred, error);
+ nnpfs_vfs_unlock(t, nnpfs_uio_to_thread(uio));
+#else
+ nnpfs_vfs_readlock(t, nnpfs_uio_to_proc(uio));
+ nnpfs_vop_read(t, uio, ioflag, cred, error);
+ nnpfs_vfs_unlock(t, nnpfs_uio_to_proc(uio));
+#endif
+ }
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_read offset: %lu resid: %lu\n",
+ (unsigned long)uio->uio_offset,
+ (unsigned long)uio->uio_resid));
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_read error: %d\n", error));
+
+ return error;
+}
+
+int
+nnpfs_write_common(struct vnode *vp, struct uio *uiop, int ioflag,
+ struct ucred *cred)
+{
+ struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
+ int error = 0;
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_write\n"));
+
+ nnpfs_update_write_cred(xn, cred);
+
+#ifdef HAVE_FREEBSD_THREAD
+ error = nnpfs_data_valid(vp, cred, nnpfs_uio_to_thread(uiop), NNPFS_DATA_W,
+ VNODE_TO_XNODE(vp)->attr.va_size);
+#else
+ error = nnpfs_data_valid(vp, cred, nnpfs_uio_to_proc(uiop), NNPFS_DATA_W,
+ VNODE_TO_XNODE(vp)->attr.va_size);
+#endif
+
+ if (error == 0) {
+ struct vnode *t = DATA_FROM_XNODE(xn);
+ struct vattr sub_attr;
+ int error2 = 0;
+
+ #ifdef HAVE_FREEBSD_THREAD
+ nnpfs_vfs_writelock(t, nnpfs_uio_to_thread(uiop));
+ nnpfs_vop_write(t, uiop, ioflag, cred, error);
+ VNODE_TO_XNODE(vp)->flags |= NNPFS_DATA_DIRTY;
+ nnpfs_vop_getattr(t, &sub_attr, cred, nnpfs_uio_to_thread(uiop), error2);
+ #else
+ nnpfs_vfs_writelock(t, nnpfs_uio_to_proc(uiop));
+ nnpfs_vop_write(t, uiop, ioflag, cred, error);
+ VNODE_TO_XNODE(vp)->flags |= NNPFS_DATA_DIRTY;
+ nnpfs_vop_getattr(t, &sub_attr, cred, nnpfs_uio_to_proc(uiop), error2);
+ #endif
+
+ if (error2 == 0) {
+ xn->attr.va_size = sub_attr.va_size;
+ xn->attr.va_bytes = sub_attr.va_size;
+ xn->attr.va_mtime = sub_attr.va_mtime;
+ nnpfs_set_vp_size(vp, sub_attr.va_size);
+ xn->offset = sub_attr.va_size;
+ }
+#ifdef HAVE_FREEBSD_THREAD
+ nnpfs_vfs_unlock(t, nnpfs_uio_to_thread(uiop));
+#else
+ nnpfs_vfs_unlock(t, nnpfs_uio_to_proc(uiop));
+#endif
+ }
+
+ return error;
+}
+
+int
+nnpfs_getattr_common(struct vnode *vp, struct vattr *vap,
+ struct ucred *cred, d_thread_t *p)
+{
+ int error = 0;
+
+ struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_getattr\n"));
+
+ error = nnpfs_attr_valid(vp, cred, p, NNPFS_ATTR_R);
+ if (error == 0)
+ *vap = xn->attr;
+ return error;
+}
+
+int
+nnpfs_setattr_common(struct vnode *vp, struct vattr *vap,
+ struct ucred *cred, d_thread_t *p)
+{
+ struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
+ struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
+ int error = 0;
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_setattr\n"));
+
+#define CHECK_NNPFSATTR(A, cast) (vap->A == cast VNOVAL || vap->A == xn->attr.A)
+ if (CHECK_NNPFSATTR(va_mode,(mode_t)) &&
+ CHECK_NNPFSATTR(va_nlink,(short)) &&
+ CHECK_NNPFSATTR(va_size,(va_size_t)) &&
+ CHECK_NNPFSATTR(va_uid,(uid_t)) &&
+ CHECK_NNPFSATTR(va_gid,(gid_t)) &&
+ CHECK_NNPFSATTR(va_mtime.tv_sec,(unsigned int)) &&
+ CHECK_NNPFSATTR(va_fileid,(long)) &&
+ CHECK_NNPFSATTR(va_type,(enum vtype)))
+ return 0; /* Nothing to do */
+#undef CHECK_NNPFSATTR
+
+ if (NNPFS_TOKEN_GOT(xn, NNPFS_ATTR_W)) {
+ /* Update attributes and mark them dirty. */
+ VNODE_TO_XNODE(vp)->flags |= NNPFS_ATTR_DIRTY;
+ error = EINVAL; /* XXX not yet implemented */
+ goto done;
+ } else {
+ struct nnpfs_message_putattr msg;
+
+ msg.header.opcode = NNPFS_MSG_PUTATTR;
+ if (cred != NOCRED) {
+ msg.cred.uid = cred->cr_uid;
+ msg.cred.pag = nnpfs_get_pag(cred);
+ } else {
+ msg.cred.uid = 0;
+ msg.cred.pag = NNPFS_ANONYMOUSID;
+ }
+ msg.handle = xn->handle;
+ vattr2nnpfs_attr(vap, &msg.attr);
+ if (NNPFS_TOKEN_GOT(xn, NNPFS_DATA_R)) {
+ if (vp->v_type == VREG) {
+ if (vap->va_size != (va_size_t)VNOVAL)
+ XA_SET_SIZE(&msg.attr, vap->va_size);
+ else
+ XA_SET_SIZE(&msg.attr, xn->attr.va_size);
+#ifdef __APPLE__
+ /* XXX needed ? */
+ if (UBCINFOEXISTS(vp))
+ ubc_setsize(vp, msg.attr.xa_size);
+#endif
+ }
+ if (vap->va_mtime.tv_sec != (unsigned int)VNOVAL)
+ XA_SET_MTIME(&msg.attr, vap->va_mtime.tv_sec);
+ else
+ XA_SET_MTIME(&msg.attr, xn->attr.va_mtime.tv_sec);
+ }
+
+ NNPFS_TOKEN_CLEAR(xn, NNPFS_ATTR_VALID, NNPFS_ATTR_MASK);
+ error = nnpfs_message_rpc(nnpfsp->fd, &msg.header, sizeof(msg), p);
+ if (error == 0)
+ error = ((struct nnpfs_message_wakeup *) & msg)->error;
+ }
+
+done:
+ return error;
+}
+
+static int
+check_rights (u_char rights, int mode)
+{
+ int error = 0;
+
+ if (mode & VREAD)
+ if ((rights & NNPFS_RIGHT_R) == 0)
+ error = EACCES;
+ if (mode & VWRITE)
+ if ((rights & NNPFS_RIGHT_W) == 0)
+ error = EACCES;
+ if (mode & VEXEC)
+ if ((rights & NNPFS_RIGHT_X) == 0)
+ error = EACCES;
+ return error;
+}
+
+int
+nnpfs_access_common(struct vnode *vp, int mode, struct ucred *cred,
+ d_thread_t *p)
+{
+ int error = 0;
+ nnpfs_pag_t pag = nnpfs_get_pag(cred);
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_access mode = 0%o\n", mode));
+
+ error = nnpfs_attr_valid(vp, cred, p, NNPFS_ATTR_R);
+ if (error == 0) {
+ struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
+ int i;
+
+ error = check_rights (xn->anonrights, mode);
+
+ if (error == 0)
+ goto done;
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_access anonaccess failed\n"));
+
+ error = EACCES; /* default to EACCES if pag isn't in xn->id */
+
+ for (i = 0; i < MAXRIGHTS; i++)
+ if (xn->id[i] == pag) {
+ error = check_rights (xn->rights[i], mode);
+ break;
+ }
+ }
+
+done:
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_access(0%o) = %d\n", mode, error));
+
+ return error;
+}
+
+int
+nnpfs_lookup_common(struct vnode *dvp,
+ nnpfs_componentname *cnp,
+ struct vnode **vpp)
+{
+ struct nnpfs_message_getnode msg;
+ struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
+ struct nnpfs_node *d = VNODE_TO_XNODE(dvp);
+ int error = 0;
+#ifdef HAVE_FREEBSD_THREAD
+ d_thread_t *proc = nnpfs_cnp_to_thread(cnp);
+ struct ucred *cred = nnpfs_thread_to_cred(proc);
+#else
+ d_thread_t *proc = nnpfs_cnp_to_proc(cnp);
+ struct ucred *cred = nnpfs_proc_to_cred(proc);
+#endif
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_lookup_common: enter\n"));
+
+ *vpp = NULL;
+
+ if (cnp->cn_namelen >= NNPFS_MAX_NAME)
+ return ENAMETOOLONG;
+
+ if (dvp->v_type != VDIR)
+ return ENOTDIR;
+
+ if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
+ *vpp = dvp;
+ VREF(*vpp);
+ return 0;
+ }
+
+ do {
+ nnpfs_vop_access(dvp, VEXEC, cred, proc, error);
+ if (error != 0)
+ goto done;
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_lookup_common: dvp = %lx\n",
+ (unsigned long) dvp));
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_lookup_common: cnp = %lx, "
+ "cnp->cn_nameiop = %d\n",
+ (unsigned long) cnp, (int)cnp->cn_nameiop));
+
+
+ error = nnpfs_dnlc_lookup(dvp, cnp, vpp);
+ if (error == 0) {
+
+ /*
+ * Doesn't quite work.
+ */
+
+#if 0
+ if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)
+ && (cnp->cn_flags & ISLASTCN)) {
+ error = EJUSTRETURN;
+ goto done;
+ }
+#endif
+
+ msg.header.opcode = NNPFS_MSG_GETNODE;
+ if (cnp->cn_cred != NOCRED) {
+ msg.cred.uid = cnp->cn_cred->cr_uid;
+ msg.cred.pag = nnpfs_get_pag(cnp->cn_cred);
+ } else {
+ msg.cred.uid = 0;
+ msg.cred.pag = NNPFS_ANONYMOUSID;
+ }
+ msg.parent_handle = d->handle;
+ memcpy(msg.name, cnp->cn_nameptr, cnp->cn_namelen);
+ msg.name[cnp->cn_namelen] = '\0';
+ error = nnpfs_message_rpc(nnpfsp->fd, &msg.header,
+ sizeof(msg), proc);
+ if (error == 0)
+ error = ((struct nnpfs_message_wakeup *) & msg)->error;
+ if(error == ENOENT && cnp->cn_nameiop != CREATE) {
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_lookup: neg cache %lx (%s, %ld)\n",
+ (unsigned long)dvp,
+ cnp->cn_nameptr, cnp->cn_namelen));
+ nnpfs_dnlc_enter (dvp, cnp, NULL);
+ }
+ } else if (error == -1) {
+ error = 0;
+ goto done;
+ }
+ } while (error == 0);
+
+done:
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_lookup_common: return error = %d\n", error));
+ return error;
+}
+
+int
+nnpfs_create_common(struct vnode *dvp,
+ const char *name,
+ struct vattr *vap,
+ struct ucred *cred,
+ d_thread_t *p)
+{
+ struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
+ struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
+ int error = 0;
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_create: (%lx, %s)\n",
+ (unsigned long)dvp, name));
+ {
+ struct nnpfs_message_create msg;
+
+ msg.header.opcode = NNPFS_MSG_CREATE;
+ msg.parent_handle = xn->handle;
+ if (strlcpy(msg.name, name, sizeof(msg.name)) >= NNPFS_MAX_NAME)
+ return ENAMETOOLONG;
+ vattr2nnpfs_attr(vap, &msg.attr);
+
+ msg.mode = 0; /* XXX - mode */
+ if (cred != NOCRED) {
+ msg.cred.uid = cred->cr_uid;
+ msg.cred.pag = nnpfs_get_pag(cred);
+ } else {
+ msg.cred.uid = 0;
+ msg.cred.pag = NNPFS_ANONYMOUSID;
+ }
+
+
+ error = nnpfs_message_rpc(nnpfsp->fd, &msg.header, sizeof(msg), p);
+
+ if (error == 0)
+ error = ((struct nnpfs_message_wakeup *) & msg)->error;
+ }
+
+#if 0
+ if (error == EEXIST)
+ error = 0;
+#endif
+
+ return error;
+}
+
+int
+nnpfs_remove_common(struct vnode *dvp,
+ struct vnode *vp,
+ const char *name,
+ struct ucred *cred,
+ d_thread_t *p)
+{
+ struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
+ struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
+ struct nnpfs_message_remove msg;
+ int error;
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_remove: %s\n", name));
+
+ msg.header.opcode = NNPFS_MSG_REMOVE;
+ msg.parent_handle = xn->handle;
+ msg.cred.uid = cred->cr_uid;
+ msg.cred.pag = nnpfs_get_pag(cred);
+
+ if (strlcpy(msg.name, name, sizeof(msg.name)) >= NNPFS_MAX_NAME)
+ error = ENAMETOOLONG;
+ else
+ error = nnpfs_message_rpc(nnpfsp->fd, &msg.header, sizeof(msg), p);
+ if (error == 0)
+ error = ((struct nnpfs_message_wakeup *) &msg)->error;
+
+ if (error == 0)
+ nnpfs_dnlc_purge (vp);
+
+ return error;
+}
+
+int
+nnpfs_rename_common(struct vnode *fdvp,
+ struct vnode *fvp,
+ const char *fname,
+ struct vnode *tdvp,
+ struct vnode *tvp,
+ const char *tname,
+ struct ucred *cred,
+ d_thread_t *p)
+{
+ struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(fdvp);
+ int error;
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_rename: %s %s\n", fname, tname));
+
+ if ((fvp->v_mount != tdvp->v_mount)
+ || (tvp && (fvp->v_mount != tvp->v_mount))) {
+ return EXDEV;
+ }
+
+ {
+ struct nnpfs_message_rename msg;
+
+ msg.header.opcode = NNPFS_MSG_RENAME;
+ msg.old_parent_handle = VNODE_TO_XNODE(fdvp)->handle;
+ if (strlcpy(msg.old_name, fname, sizeof(msg.old_name)) >= NNPFS_MAX_NAME)
+ return ENAMETOOLONG;
+ msg.new_parent_handle = VNODE_TO_XNODE(tdvp)->handle;
+ if (strlcpy(msg.new_name, tname, sizeof(msg.new_name)) >= NNPFS_MAX_NAME)
+ return ENAMETOOLONG;
+ msg.cred.uid = cred->cr_uid;
+ msg.cred.pag = nnpfs_get_pag(cred);
+ error = nnpfs_message_rpc(nnpfsp->fd, &msg.header, sizeof(msg), p);
+ if (error == 0)
+ error = ((struct nnpfs_message_wakeup *) &msg)->error;
+
+ }
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_rename: error = %d\n", error));
+
+ return error;
+}
+
+int
+nnpfs_mkdir_common(struct vnode *dvp,
+ const char *name,
+ struct vattr *vap,
+ struct ucred *cred,
+ d_thread_t *p)
+{
+ struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
+ struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
+ int error = 0;
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_mkdir: %s\n", name));
+ {
+ struct nnpfs_message_mkdir msg;
+
+ msg.header.opcode = NNPFS_MSG_MKDIR;
+ msg.parent_handle = xn->handle;
+ if (strlcpy(msg.name, name, sizeof(msg.name)) >= NNPFS_MAX_NAME)
+ return ENAMETOOLONG;
+ vattr2nnpfs_attr(vap, &msg.attr);
+ if (cred != NOCRED) {
+ msg.cred.uid = cred->cr_uid;
+ msg.cred.pag = nnpfs_get_pag(cred);
+ } else {
+ msg.cred.uid = 0;
+ msg.cred.pag = NNPFS_ANONYMOUSID;
+ }
+ error = nnpfs_message_rpc(nnpfsp->fd, &msg.header, sizeof(msg), p);
+ if (error == 0)
+ error = ((struct nnpfs_message_wakeup *) & msg)->error;
+ }
+
+ return error;
+}
+
+int
+nnpfs_rmdir_common(struct vnode *dvp,
+ struct vnode *vp,
+ const char *name,
+ struct ucred *cred,
+ d_thread_t *p)
+{
+ struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
+ struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
+ struct nnpfs_message_rmdir msg;
+ int error;
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_rmdir: %s\n", name));
+
+ msg.header.opcode = NNPFS_MSG_RMDIR;
+ msg.parent_handle = xn->handle;
+ msg.cred.uid = cred->cr_uid;
+ msg.cred.pag = nnpfs_get_pag(cred);
+ if (strlcpy(msg.name, name, sizeof(msg.name)) >= NNPFS_MAX_NAME)
+ error = ENAMETOOLONG;
+ else
+ error = nnpfs_message_rpc(nnpfsp->fd, &msg.header, sizeof(msg), p);
+ if (error == 0)
+ error = ((struct nnpfs_message_wakeup *) &msg)->error;
+
+ if (error == 0)
+ nnpfs_dnlc_purge (vp);
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_rmdir error: %d\n", error));
+
+ return error;
+}
+
+int
+nnpfs_readdir_common(struct vnode *vp,
+ struct uio *uiop,
+ struct ucred *cred,
+ d_thread_t *p,
+ int *eofflag)
+{
+ int error = 0;
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_readdir\n"));
+
+ if(eofflag)
+ *eofflag = 0;
+#ifdef HAVE_FREEBSD_THREAD
+ error = nnpfs_data_valid(vp, cred, nnpfs_uio_to_thread(uiop), NNPFS_DATA_R,
+ nnpfs_uio_end_length(uiop));
+#else
+ error = nnpfs_data_valid(vp, cred, nnpfs_uio_to_proc(uiop), NNPFS_DATA_R,
+ nnpfs_uio_end_length(uiop));
+#endif
+ if (error == 0) {
+ struct vnode *t = DATA_FROM_VNODE(vp);
+
+#ifdef HAVE_FREEBSD_THREAD
+ nnpfs_vfs_readlock(t, nnpfs_uio_to_thread(uiop));
+#else
+ nnpfs_vfs_readlock(t, nnpfs_uio_to_proc(uiop));
+#endif
+ nnpfs_vop_read(t, uiop, 0, cred, error);
+ if (eofflag) {
+ struct vattr t_attr;
+ int error2;
+
+#ifdef HAVE_FREEBSD_THREAD
+ nnpfs_vop_getattr(t, &t_attr, cred, nnpfs_uio_to_thread(uiop), error2);
+#else
+ nnpfs_vop_getattr(t, &t_attr, cred, nnpfs_uio_to_proc(uiop), error2);
+#endif
+ if (error2 == 0)
+ *eofflag = t_attr.va_size <= uiop->uio_offset;
+ }
+#ifdef HAVE_FREEBSD_THREAD
+ nnpfs_vfs_unlock(t, nnpfs_uio_to_thread(uiop));
+#else
+ nnpfs_vfs_unlock(t, nnpfs_uio_to_proc(uiop));
+#endif
+ }
+ return error;
+}
+
+int
+nnpfs_link_common(struct vnode *dvp,
+ struct vnode *vp,
+ const char *name,
+ struct ucred *cred,
+ d_thread_t *p)
+{
+ struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
+ struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
+ struct nnpfs_node *xn2 = VNODE_TO_XNODE(vp);
+ struct nnpfs_message_link msg;
+ int error = 0;
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_link: %s\n", name));
+
+ msg.header.opcode = NNPFS_MSG_LINK;
+ msg.parent_handle = xn->handle;
+ msg.from_handle = xn2->handle;
+ if (strlcpy(msg.name, name, sizeof(msg.name)) >= NNPFS_MAX_NAME)
+ return ENAMETOOLONG;
+ msg.cred.uid = cred->cr_uid;
+ msg.cred.pag = nnpfs_get_pag(cred);
+
+ error = nnpfs_message_rpc(nnpfsp->fd, &msg.header, sizeof(msg), p);
+ if (error == 0)
+ error = ((struct nnpfs_message_wakeup *) & msg)->error;
+
+ return error;
+}
+
+int
+nnpfs_symlink_common(struct vnode *dvp,
+ struct vnode **vpp,
+ nnpfs_componentname *cnp,
+ struct vattr *vap,
+ char *target)
+{
+ struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
+ struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
+#ifdef HAVE_FREEBSD_THREAD
+ d_thread_t *proc = nnpfs_cnp_to_thread(cnp);
+ struct ucred *cred = nnpfs_thread_to_cred(proc);
+#else
+ d_thread_t *proc = nnpfs_cnp_to_proc(cnp);
+ struct ucred *cred = nnpfs_proc_to_cred(proc);
+#endif
+ struct nnpfs_message_symlink *msg = NULL;
+ const char *name = cnp->cn_nameptr;
+ int error = 0;
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_symlink: %s\n", name));
+
+ msg = malloc(sizeof(*msg), M_TEMP, M_WAITOK | M_ZERO);
+ if (msg == NULL) {
+ error = ENOMEM;
+ goto done;
+ }
+
+ msg->header.opcode = NNPFS_MSG_SYMLINK;
+ msg->parent_handle = xn->handle;
+ vattr2nnpfs_attr(vap, &msg->attr);
+ msg->cred.uid = cred->cr_uid;
+ msg->cred.pag = nnpfs_get_pag(cred);
+ if (strlcpy (msg->contents, target, sizeof(msg->contents)) >= NNPFS_MAX_SYMLINK_CONTENT) {
+ error = ENAMETOOLONG;
+ goto done;
+ }
+ if (strlcpy(msg->name, name, sizeof(msg->name)) >= NNPFS_MAX_NAME) {
+ error = ENAMETOOLONG;
+ goto done;
+ }
+ error = nnpfs_message_rpc(nnpfsp->fd, &msg->header, sizeof(*msg), proc);
+ if (error == 0)
+ error = ((struct nnpfs_message_wakeup *) msg)->error;
+
+ done:
+ free(msg, M_TEMP);
+ return error;
+}
+
+int
+nnpfs_readlink_common(struct vnode *vp, struct uio *uiop, struct ucred *cred)
+{
+ int error = 0;
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_readlink\n"));
+
+#ifdef HAVE_FREEBSD_THREAD
+ error = nnpfs_data_valid(vp, cred, nnpfs_uio_to_thread(uiop), NNPFS_DATA_R,
+ nnpfs_uio_end_length(uiop));
+#else
+ error = nnpfs_data_valid(vp, cred, nnpfs_uio_to_proc(uiop), NNPFS_DATA_R,
+ nnpfs_uio_end_length(uiop));
+#endif
+ if (error == 0) {
+ struct vnode *t = DATA_FROM_VNODE(vp);
+
+#ifdef HAVE_FREEBSD_THREAD
+ nnpfs_vfs_readlock(t, nnpfs_uio_to_thread(uiop));
+ nnpfs_vop_read(t, uiop, 0, cred, error);
+ nnpfs_vfs_unlock(t, nnpfs_uio_to_thread(uiop));
+#else
+ nnpfs_vfs_readlock(t, nnpfs_uio_to_proc(uiop));
+ nnpfs_vop_read(t, uiop, 0, cred, error);
+ nnpfs_vfs_unlock(t, nnpfs_uio_to_proc(uiop));
+#endif
+ }
+ return error;
+}
+
+int
+nnpfs_inactive_common(struct vnode *vp, d_thread_t *p)
+{
+ int error;
+ struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_inactive, %lx\n",
+ (unsigned long)vp));
+
+ /*
+ * This seems rather bogus, but sometimes we get an already
+ * cleaned node to be made inactive. Just ignoring it seems safe.
+ */
+
+ if (xn == NULL) {
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_inactive: clean node\n"));
+ return 0;
+ }
+
+ /* xn->wr_cred not set -> NOCRED */
+
+ if (vp->v_type == VREG)
+ nnpfs_pushdirty(vp, xn->wr_cred, p);
+
+ error = nnpfs_fsync_common(vp, xn->wr_cred, /* XXX */ 0, p);
+ if (error) {
+ printf ("nnpfs_inactive: failed writing back data: %d\n", error);
+ xn->flags &= ~NNPFS_DATA_DIRTY;
+ }
+
+ /* If this node is no longer valid, recycle immediately. */
+ if (!NNPFS_TOKEN_GOT(xn, NNPFS_ATTR_R | NNPFS_ATTR_W)
+ || (xn->flags & NNPFS_STALE) == NNPFS_STALE)
+ {
+#ifndef __osf__
+ nnpfs_vfs_unlock(vp, p);
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_inactive: vrecycle\n"));
+ vrecycle(vp, p);
+#else /* __osf__ */
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_inactive: vp = %lx vp->v_usecount= %d\n",
+ (unsigned long)vp, vp?vp->v_usecount:0));
+#endif /* __osf__ */
+ } else {
+#ifndef __osf__
+ nnpfs_vfs_unlock(vp, p);
+#endif
+ xn->flags &= ~NNPFS_STALE;
+ }
+
+ NNPFSDEB(XDEBVNOPS, ("return: nnpfs_inactive\n"));
+
+ return 0;
+}
+
+int
+nnpfs_reclaim_common(struct vnode *vp)
+{
+ struct nnpfs_message_inactivenode msg;
+ struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
+ struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_reclaim: %lx\n",
+ (unsigned long)vp));
+
+ NNPFS_TOKEN_CLEAR(xn,
+ ~0,
+ NNPFS_OPEN_MASK | NNPFS_ATTR_MASK |
+ NNPFS_DATA_MASK | NNPFS_LOCK_MASK);
+ /* Release, data if we still have it. */
+ if (DATA_FROM_XNODE(xn) != 0) {
+ vrele(DATA_FROM_XNODE(xn));
+ DATA_FROM_XNODE(xn) = 0;
+ }
+
+ nnpfs_remove_node(&nnpfsp->nodehead, xn);
+
+ msg.header.opcode = NNPFS_MSG_INACTIVENODE;
+ msg.handle = xn->handle;
+ msg.flag = NNPFS_NOREFS | NNPFS_DELETE;
+ nnpfs_message_send(nnpfsp->fd, &msg.header, sizeof(msg));
+
+ nnpfs_dnlc_purge(vp);
+ free_nnpfs_node(xn);
+ return 0;
+}
+
+/*
+ *
+ */
+
+#if 0
+
+int
+nnpfs_advlock_common(struct vnode *dvp,
+ int locktype,
+ unsigned long lockid, /* XXX this good ? */
+ struct ucred *cred)
+{
+ struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
+ struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
+ int error = 0;
+
+ NNPFSDEB(XDEBVNOPS, ("nnpfs_advlock\n"));
+ {
+ struct nnpfs_message_advlock msg;
+
+ msg.header.opcode = NNPFS_MSG_ADVLOCK;
+ msg.handle = xn->handle;
+ msg.locktype = locktype;
+ msg.lockid = lockid;
+
+ if (cred != NOCRED) {
+ msg.cred.uid = cred->cr_uid;
+ msg.cred.pag = nnpfs_get_pag(cred);
+ } else {
+ msg.cred.uid = 0;
+ msg.cred.pag = NNPFS_ANONYMOUSID;
+ }
+ error = nnpfs_message_rpc(nnpfsp->fd, &msg.header, sizeof(msg), p);
+ if (error == 0)
+ error = ((struct nnpfs_message_wakeup *) & msg)->error;
+ }
+
+ if (error == 0) {
+
+ /* sleep until woken */
+
+ } else {
+
+ /* die */
+ }
+
+ return error;
+}
+
+#endif
+
+/*
+ *
+ */
+
+void
+nnpfs_printnode_common (struct vnode *vp)
+{
+ struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
+
+ printf ("xnode: fid: %d.%d.%d.%d\n",
+ xn->handle.a, xn->handle.b, xn->handle.c, xn->handle.d);
+ printf ("\tattr: %svalid\n",
+ NNPFS_TOKEN_GOT(xn, NNPFS_ATTR_VALID) ? "": "in");
+ printf ("\tdata: %svalid\n",
+ NNPFS_TOKEN_GOT(xn, NNPFS_DATA_VALID) ? "": "in");
+ printf ("\tflags: 0x%x\n", xn->flags);
+ printf ("\toffset: %d\n", xn->offset);
+}