summaryrefslogtreecommitdiff
path: root/sys/xfs
diff options
context:
space:
mode:
authorArtur Grabowski <art@cvs.openbsd.org>1998-08-30 16:47:23 +0000
committerArtur Grabowski <art@cvs.openbsd.org>1998-08-30 16:47:23 +0000
commit2974eba0c37fd7574f74be5635fbec7be92d8d1e (patch)
tree6edab55bde782dad04fd6f44bde9237e8ee89e34 /sys/xfs
parent5f034f528bbf444042c1b833901b0ec1090cf9d1 (diff)
xfs - a filesystem using a user-land cache manager. Designed for AFS.
Diffstat (limited to 'sys/xfs')
-rw-r--r--sys/xfs/xfs_common.c65
-rw-r--r--sys/xfs/xfs_dev.c774
-rw-r--r--sys/xfs/xfs_syscalls.c445
-rw-r--r--sys/xfs/xfs_vfsops.c441
-rw-r--r--sys/xfs/xfs_vnodeops.c1000
5 files changed, 2725 insertions, 0 deletions
diff --git a/sys/xfs/xfs_common.c b/sys/xfs/xfs_common.c
new file mode 100644
index 00000000000..c40fc071b60
--- /dev/null
+++ b/sys/xfs/xfs_common.c
@@ -0,0 +1,65 @@
+/* $OpenBSD: xfs_common.c,v 1.1 1998/08/30 16:47:20 art Exp $ */
+/*
+ * Copyright (c) 1995, 1996, 1997 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.
+ */
+
+#ifdef DEBUG
+#include <sys/malloc.h>
+#include <xfs/xfs_common.h>
+#include <xfs/xfs_deb.h>
+
+RCSID("$KTH: xfs_common.c,v 1.6 1998/07/19 21:14:19 art Exp $");
+
+static u_int xfs_allocs;
+static u_int xfs_frees;
+
+void *
+xfs_alloc(u_int size)
+{
+ xfs_allocs++;
+ XFSDEB(XDEBMEM, ("xfs_alloc: xfs_allocs-xfs_frees %d\n",
+ xfs_allocs - xfs_frees));
+ return malloc(size, M_TEMP, M_WAITOK); /* XXX - What kind? */
+}
+
+void
+xfs_free(void *ptr, u_int size)
+{
+ xfs_frees++;
+ free(ptr, M_TEMP);
+}
+#endif
diff --git a/sys/xfs/xfs_dev.c b/sys/xfs/xfs_dev.c
new file mode 100644
index 00000000000..3b34ef61449
--- /dev/null
+++ b/sys/xfs/xfs_dev.c
@@ -0,0 +1,774 @@
+/* $OpenBSD: xfs_dev.c,v 1.1 1998/08/30 16:47:20 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/malloc.h>
+#include <sys/select.h>
+#include <sys/uio.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/fcntl.h>
+
+#include <xfs/xfs_common.h>
+#include <sys/xfs_message.h>
+#include <xfs/xfs_msg_locl.h>
+#include <xfs/xfs_dev.h>
+#include <xfs/xfs_fs.h>
+#include <xfs/xfs_deb.h>
+#include <xfs/xfs_extern.h>
+
+RCSID("$KTH: xfs_dev.c,v 1.14 1998/07/19 00:19:53 art Exp $");
+
+/*
+ * Queues of xfs_links hold outbound messages and processes sleeping
+ * for replies. The last field is used to return error to sleepers and
+ * to keep record of memory to be deallocated when messages have been
+ * delivered or dropped.
+ */
+struct xfs_link {
+ struct xfs_link *prev, *next;
+ struct xfs_message_header *message;
+ u_int error_or_size; /* error on sleepq and size on
+ * messageq */
+};
+
+struct xfs_channel {
+ struct xfs_link messageq; /* Messages not yet read */
+ struct xfs_link sleepq; /* Waiting for reply message */
+ u_int nsequence;
+ struct proc *selecting_proc;
+ struct xfs_message_header *message_buffer;
+ int status;
+#define CHANNEL_OPENED 0x1
+};
+
+static struct xfs_channel xfs_channel[NXFS];
+
+static void
+xfs_initq(struct xfs_link * q)
+{
+ q->next = q;
+ q->prev = q;
+}
+
+/* Is this queue empty? */
+#define xfs_emptyq(q) ((q)->next == (q))
+
+/* Is this link on any queue? Link *must* be inited! */
+#define xfs_onq(link) ((link)->next != 0 || (link)->prev != 0)
+
+/* Append q with p */
+static void
+xfs_appendq(struct xfs_link * q, struct xfs_link * p)
+{
+ p->next = q;
+ p->prev = q->prev;
+ p->prev->next = p;
+ q->prev = p;
+}
+
+static void
+xfs_outq(struct xfs_link * p)
+{
+ p->next->prev = p->prev;
+ p->prev->next = p->next;
+ p->next = p->prev = 0;
+}
+
+/*
+ * Only allow one open.
+ */
+int
+xfs_devopen(dev_t dev, int flags, int devtype, struct proc * p)
+{
+ struct xfs_channel *chan;
+
+ XFSDEB(XDEBDEV, ("xfs_devopen dev = %d.%d, flags = %d\n", major(dev),
+ minor(dev), flags));
+
+ if (minor(dev) < 0 || minor(dev) >= NXFS)
+ return ENXIO;
+
+ chan = &xfs_channel[minor(dev)];
+
+ /* Only allow one reader/writer */
+ if (chan->status & CHANNEL_OPENED) {
+ XFSDEB(XDEBDEV, ("xfs_devopen: already open\n"));
+ return EBUSY;
+ } else
+ chan->status |= CHANNEL_OPENED;
+
+ chan->message_buffer = xfs_alloc(MAX_XMSG_SIZE);
+
+ /* initalize the queues if they have not been initialized before */
+ xfs_initq(&chan->sleepq);
+ xfs_initq(&chan->messageq);
+
+ return 0;
+}
+
+/*
+ * Wakeup all sleepers and cleanup.
+ */
+int
+xfs_devclose(dev_t dev, int flags, int devtype, struct proc * p)
+{
+ struct xfs_channel *chan = &xfs_channel[minor(dev)];
+ struct xfs_link *first;
+
+ XFSDEB(XDEBDEV, ("xfs_devclose dev = %d, flags = %d\n", dev, flags));
+
+ /* Sanity check, paranoia? */
+ if (!(chan->status & CHANNEL_OPENED))
+ panic("xfs_devclose never opened?");
+
+ chan->status &= ~CHANNEL_OPENED;
+
+ /* No one is going to read those messages so empty queue! */
+ while (!xfs_emptyq(&chan->messageq)) {
+ XFSDEB(XDEBDEV, ("before outq(messageq)\n"));
+ first = chan->messageq.next;
+ xfs_outq(first);
+ if (first->error_or_size != 0) {
+ xfs_free(first, first->error_or_size);
+ first = NULL;
+ }
+ XFSDEB(XDEBDEV, ("after outq(messageq)\n"));
+ }
+
+ /* Wakeup those waiting for replies that will never arrive. */
+ while (!xfs_emptyq(&chan->sleepq)) {
+ XFSDEB(XDEBDEV, ("before outq(sleepq)\n"));
+ first = chan->sleepq.next;
+ xfs_outq(first);
+ first->error_or_size = ENODEV;
+ wakeup((caddr_t) first);
+ XFSDEB(XDEBDEV, ("after outq(sleepq)\n"));
+ }
+
+ if (chan->message_buffer) {
+ xfs_free(chan->message_buffer, MAX_XMSG_SIZE);
+ chan->message_buffer = NULL;
+ }
+
+ /*
+ * Free all xfs nodes.
+ * The force flag is set because we do not have any choice.
+ *
+ * Only try to unmount a mounted xfs...
+ */
+
+ if (xfs[minor(dev)].mp != NULL) {
+
+ if (vfs_busy(xfs[minor(dev)].mp, 0, 0, p)) {
+ XFSDEB(XDEBNODE, ("xfs_dev_close: vfs_busy() --> BUSY\n"));
+ return EBUSY;
+ }
+ free_all_xfs_nodes(&xfs[minor(dev)], FORCECLOSE);
+
+ vfs_unbusy(xfs[minor(dev)].mp, p);
+
+ }
+
+
+ return 0;
+}
+
+/*
+ * Move messages from kernel to user space.
+ */
+int
+xfs_devread(dev_t dev, struct uio * uiop, int ioflag)
+{
+ struct xfs_channel *chan = &xfs_channel[minor(dev)];
+ struct xfs_link *first;
+ int error = 0;
+
+ XFSDEB(XDEBDEV, ("xfs_devread dev = %d\n", dev));
+
+ XFSDEB(XDEBDEV, ("xfs_devread: m = %p, m->prev = %p, m->next = %p\n",
+ &chan->messageq, chan->messageq.prev, chan->messageq.next));
+
+ while (!xfs_emptyq (&chan->messageq)) {
+
+ /* Remove message */
+ first = chan->messageq.next;
+ XFSDEB(XDEBDEV, ("xfs_devread: first = %p, "
+ "first->prev = %p, first->next = %p\n",
+ first, first->prev, first->next));
+
+ XFSDEB(XDEBDEV, ("xfs_devread: message->size = %u\n",
+ first->message->size));
+
+ error = uiomove((caddr_t) first->message, first->message->size, uiop);
+ if (error)
+ break;
+
+ xfs_outq(first);
+
+ if (first->error_or_size != 0) {
+ xfs_free(first, first->error_or_size);
+ first = NULL;
+ }
+ }
+
+ XFSDEB(XDEBDEV, ("xfs_devread done error = %d\n", error));
+
+ return error;
+}
+
+/*
+ * Move messages from user space to kernel space,
+ * wakeup sleepers, insert new data in VFS.
+ */
+int
+xfs_devwrite(dev_t dev, struct uio *uiop, int ioflag)
+{
+ struct xfs_channel *chan = &xfs_channel[minor(dev)];
+ char *p;
+ int error;
+ u_int cnt;
+ struct xfs_message_header *msg_buf;
+
+ XFSDEB(XDEBDEV, ("xfs_devwrite dev = %d\n", dev));
+
+ cnt = uiop->uio_resid;
+ error = uiomove((caddr_t) chan->message_buffer, MAX_XMSG_SIZE, uiop);
+ if (error != 0)
+ return error;
+
+ cnt -= uiop->uio_resid;
+
+ /*
+ * This thread handles the received message.
+ */
+ for (p = (char *)chan->message_buffer;
+ cnt > 0;
+ p += msg_buf->size, cnt -= msg_buf->size) {
+ msg_buf = (struct xfs_message_header *)p;
+ error = xfs_message_receive (minor(dev),
+ msg_buf,
+ msg_buf->size,
+ uiop->uio_procp);
+ }
+ XFSDEB(XDEBDEV, ("xfs_devwrite error = %d\n", error));
+ return error;
+}
+
+/*
+ * Not used.
+ */
+
+int
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+xfs_devioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc * p)
+#elif defined(__FreeBSD__)
+xfs_devioctl(dev_t dev, int cmd, caddr_t data, int flags, struct proc * p)
+#endif
+{
+ XFSDEB(XDEBDEV, ("xfs_devioctl dev = %d, flags = %d\n", dev, flags));
+ return EINVAL;
+}
+
+/*
+ * Are there any messages on this filesystem?
+ */
+
+static int
+xfs_realselect(dev_t dev, struct proc * p)
+{
+ struct xfs_channel *chan = &xfs_channel[minor(dev)];
+
+ if (!xfs_emptyq(&chan->messageq))
+ return 1; /* Something to read */
+
+ /*
+ * No need to handle a "collission" since we only allow one
+ * concurrent open. */
+ chan->selecting_proc = p;
+ return 0;
+}
+
+
+#ifdef USE_POLL
+static int
+xfs_devpoll(dev_t dev, int events, struct proc * p)
+{
+ XFSDEB(XDEBDEV, ("xfs_devpoll dev = %d, events = %d\n", dev, events));
+
+ if (!(events & POLLRDNORM))
+ return 0;
+
+ return xfs_realselect(dev, p);
+}
+
+#endif
+
+#ifdef USE_SELECT
+int
+xfs_devselect(dev_t dev, int which, struct proc * p)
+{
+ XFSDEB(XDEBDEV, ("xfs_devselect dev = %d, which = %d\n", dev, which));
+
+ if (which != FREAD)
+ return 0;
+
+ return xfs_realselect(dev, p);
+}
+
+#endif
+
+/*
+ * Send a message to user space.
+ */
+int
+xfs_message_send(int fd, struct xfs_message_header * message, u_int size)
+{
+ struct xfs_channel *chan = &xfs_channel[fd];
+ struct {
+ struct xfs_link this_message;
+ struct xfs_message_header msg;
+ } *t;
+
+ XFSDEB(XDEBMSG, ("xfs_message_send opcode = %d\n", message->opcode));
+
+ if (!(chan->status & CHANNEL_OPENED)) /* No receiver? */
+ return ENODEV;
+
+ /* Prepare message and copy it later */
+ message->size = size;
+ message->sequence_num = chan->nsequence++;
+
+ t = xfs_alloc(sizeof(t->this_message) + size);
+ t->this_message.error_or_size = sizeof(t->this_message) + size;
+ bcopy(message, &t->msg, size);
+
+ t->this_message.message = &t->msg;
+ xfs_appendq(&chan->messageq, &t->this_message);
+ if (chan->selecting_proc != 0
+ && chan->selecting_proc->p_wchan == (caddr_t) & selwait) {
+ struct selinfo selinfo;
+
+#if defined(__NetBSD__) || defined(__FreeBSD__)
+ selinfo.si_pid = chan->selecting_proc->p_pid;
+#else
+ selinfo.si_selpid = chan->selecting_proc->p_pid;
+#endif
+ selinfo.si_flags = 0;
+
+ selwakeup(&selinfo);
+ chan->selecting_proc = 0;
+ }
+ return 0;
+}
+
+/*
+ * Send a message to user space and wait for reply.
+ */
+int
+xfs_message_rpc(int fd, struct xfs_message_header * message, u_int size)
+{
+ int ret;
+ struct xfs_channel *chan = &xfs_channel[fd];
+ struct xfs_link *this_message = xfs_alloc(sizeof(struct xfs_link));
+ struct xfs_link *this_process = xfs_alloc(sizeof(struct xfs_link));
+ struct xfs_message_header *msg;
+
+ XFSDEB(XDEBMSG, ("xfs_message_rpc opcode = %d\n", message->opcode));
+
+ if (!(chan->status & CHANNEL_OPENED)) /* No receiver? */
+ return ENODEV;
+
+ if (size < sizeof(struct xfs_message_wakeup)) {
+ printf("XFS PANIC Error: Message to small to receive wakeup, opcode = %d\n", message->opcode);
+ return ENOMEM;
+ }
+ msg = xfs_alloc(size);
+ bcopy(message, msg, size);
+
+ msg->size = size;
+ msg->sequence_num = chan->nsequence++;
+ this_message->error_or_size = 0;
+ this_message->message = msg; /* message; */
+ this_process->message = msg; /* message; */
+ xfs_appendq(&chan->messageq, this_message);
+ xfs_appendq(&chan->sleepq, this_process);
+ if (chan->selecting_proc != 0
+ && chan->selecting_proc->p_wchan == (caddr_t) & selwait) {
+ struct selinfo selinfo;
+
+#if defined(__NetBSD__) || defined(__FreeBSD__)
+ selinfo.si_pid = chan->selecting_proc->p_pid;
+#else
+ selinfo.si_selpid = chan->selecting_proc->p_pid;
+#endif
+ selinfo.si_flags = 0;
+
+ selwakeup(&selinfo);
+ chan->selecting_proc = 0;
+ }
+ this_process->error_or_size = 0;
+
+ if (tsleep((caddr_t) this_process, (PZERO + 1) | PCATCH, "hej", 0)) {
+ XFSDEB(XDEBMSG, ("caught signal\n"));
+ this_process->error_or_size = EINTR;
+ }
+ /*
+ * Caught signal, got reply message or device was closed.
+ * Need to clean up both messageq and sleepq.
+ */
+ if (xfs_onq(this_message)) {
+ xfs_outq(this_message);
+ }
+ if (xfs_onq(this_process)) {
+ xfs_outq(this_process);
+ }
+ ret = this_process->error_or_size;
+
+ XFSDEB(XDEBMSG, ("xfs_message_rpc opcode this_process->error_or_size = %d\n", this_process->error_or_size));
+ XFSDEB(XDEBMSG, ("xfs_message_rpc opcode ((xfs_message_wakeup*)(this_process->message))->error = %d\n", ((struct xfs_message_wakeup *) (this_process->message))->error));
+
+ bcopy(msg, message, size);
+
+ xfs_free(this_message, sizeof(*this_message));
+ this_message = NULL;
+ xfs_free(this_process, sizeof(*this_process));
+ this_process = NULL;
+ xfs_free(msg, size);
+ msg = NULL;
+ return ret;
+}
+
+/*
+ * For each message type there is a message handler
+ * that implements its action, xfs_message_receive
+ * invokes the correct function.
+ */
+int
+xfs_message_receive(int fd,
+ struct xfs_message_header *message,
+ u_int size,
+ struct proc *p)
+{
+ XFSDEB(XDEBMSG, ("xfs_message_receive opcode = %d\n", message->opcode));
+
+ /* Dispatch and coerce message type */
+ switch (message->opcode) {
+ case XFS_MSG_WAKEUP:
+ return xfs_message_wakeup(fd,
+ (struct xfs_message_wakeup *) message,
+ message->size,
+ p);
+ case XFS_MSG_WAKEUP_DATA:
+ return xfs_message_wakeup_data(fd,
+ (struct xfs_message_wakeup_data *) message,
+ message->size,
+ p);
+ case XFS_MSG_INSTALLROOT:
+ return xfs_message_installroot(fd,
+ (struct xfs_message_installroot *) message,
+ message->size,
+ p);
+ case XFS_MSG_INSTALLNODE:
+ return xfs_message_installnode(fd,
+ (struct xfs_message_installnode *) message,
+ message->size,
+ p);
+ case XFS_MSG_INSTALLATTR:
+ return xfs_message_installattr(fd,
+ (struct xfs_message_installattr *) message,
+ message->size,
+ p);
+ case XFS_MSG_INSTALLDATA:
+ return xfs_message_installdata(fd,
+ (struct xfs_message_installdata *) message,
+ message->size,
+ p);
+ case XFS_MSG_INVALIDNODE:
+ return xfs_message_invalidnode(fd,
+ (struct xfs_message_invalidnode *) message,
+ message->size,
+ p);
+ default:
+ printf("XFS PANIC Warning xfs_dev: Unknown message opcode == %d\n",
+ message->opcode);
+ return EINVAL;
+ }
+}
+
+int
+xfs_message_wakeup(int fd,
+ struct xfs_message_wakeup *message,
+ u_int size,
+ struct proc *p)
+{
+ struct xfs_channel *chan = &xfs_channel[fd];
+ struct xfs_link *sleepq = &chan->sleepq;
+ struct xfs_link *t = chan->sleepq.next; /* Really first in q */
+
+ XFSDEB(XDEBMSG, ("xfs_message_wakeup error: %d\n", message->error));
+
+ for (; t != sleepq; t = t->next)
+ if (t->message->sequence_num == message->sleepers_sequence_num) {
+ if (t->message->size < size) {
+ printf("XFS PANIC Error: Could not wakeup requestor with opcode = %d properly, to small receive buffer.\n", t->message->opcode);
+ t->error_or_size = ENOMEM;
+ } else
+ bcopy(message, t->message, size);
+ wakeup((caddr_t) t);
+ break;
+ }
+ return 0;
+}
+
+int
+xfs_message_wakeup_data(int fd,
+ struct xfs_message_wakeup_data * message,
+ u_int size,
+ struct proc *p)
+{
+ struct xfs_channel *chan = &xfs_channel[fd];
+ struct xfs_link *sleepq = &chan->sleepq;
+ struct xfs_link *t = chan->sleepq.next; /* Really first in q */
+
+ XFSDEB(XDEBMSG, ("xfs_message_wakeup_data error: %d\n", message->error));
+
+ for (; t != sleepq; t = t->next)
+ if (t->message->sequence_num == message->sleepers_sequence_num) {
+ if (t->message->size < size) {
+ printf("XFS PANIC Error: Could not wakeup requestor with opcode = %d properly, to small receive buffer.\n", t->message->opcode);
+ t->error_or_size = ENOMEM;
+ } else
+ bcopy(message, t->message, size);
+ wakeup((caddr_t) t);
+ break;
+ }
+ return 0;
+}
+
+#ifdef ACTUALLY_LKM_NOT_KERNEL
+/*
+ *
+ */
+static int
+xfs_uprintf_device(void)
+{
+#if 0
+ int i;
+
+ for (i = 0; i < NXFS; i++) {
+ uprintf("xfs_channel[%d] = {\n", i);
+ uprintf("messageq.next = 0x%x ", (u_int) xfs_channel[i].messageq.next);
+ uprintf("messageq.prev = 0x%x ", (u_int) xfs_channel[i].messageq.prev);
+ uprintf("sleepq.next = 0x%x ", (u_int) xfs_channel[i].sleepq.next);
+ uprintf("sleepq.prev = 0x%x ", (u_int) xfs_channel[i].sleepq.prev);
+ uprintf("nsequence = %d selecting_proc = 0x%x status = %d\n",
+ xfs_channel[i].nsequence,
+ (u_int) xfs_channel[i].selecting_proc,
+ xfs_channel[i].status);
+ uprintf("}\n");
+ }
+#endif
+ return 0;
+}
+
+/*
+ * Install and uninstall device.
+ */
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+static struct cdevsw xfs_dev = {
+ xfs_devopen,
+ xfs_devclose,
+ xfs_devread,
+ xfs_devwrite,
+ xfs_devioctl,
+ (dev_type_stop((*))) enodev,
+ 0,
+#ifdef __OpenBSD__
+ xfs_devselect,
+#else
+ xfs_devpoll,
+#endif
+ (dev_type_mmap((*))) enodev,
+ 0
+};
+#elif defined(__FreeBSD__)
+static struct cdevsw xfs_dev = {
+ xfs_devopen,
+ xfs_devclose,
+ xfs_devread,
+ xfs_devwrite,
+ xfs_devioctl,
+ nostop,
+ noreset,
+ nodevtotty,
+ xfs_devselect,
+ nommap,
+ nostrategy,
+ NULL,
+ 0
+};
+#endif
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+
+static int dev_offset;
+static struct cdevsw dev_olddev;
+
+int
+xfs_install_device(void)
+{
+ int i;
+
+ /*
+ * Search the table looking for a slot...
+ */
+ for (i = 0; i < nchrdev; i++)
+ if (cdevsw[i].d_open == (dev_type_open((*))) lkmenodev)
+ break; /* found it! */
+ /* out of allocable slots? */
+ if (i == nchrdev) {
+ XFSDEB(XDEBDEV, ("xfs_install_device: no available slots\n"));
+ return (ENFILE);
+ }
+
+ /* save old */
+ dev_olddev = cdevsw[i];
+
+ /* replace with new */
+ cdevsw[i] = xfs_dev;
+
+ printf("done installing cdev !\n");
+
+ /* done! */
+ dev_offset = i;
+
+ printf("Char device number %d\n", i);
+
+ for (i = 0; i < NXFS; i++) {
+ XFSDEB(XDEBDEV, ("before initq(messageq and sleepq)\n"));
+ xfs_initq(&xfs_channel[i].messageq);
+ xfs_initq(&xfs_channel[i].sleepq);
+ xfs_channel[i].status = 0;
+ }
+ return 0;
+}
+
+int
+xfs_uninstall_device(void)
+{
+ int i;
+ dev_t dev;
+ struct xfs_channel *chan;
+
+ for (i = 0; i < NXFS; i++) {
+ dev = makedev(dev_offset, i);
+ chan = &xfs_channel[minor(dev)];
+ if (chan->status & CHANNEL_OPENED)
+ xfs_devclose(dev, 0, 0, NULL);
+ }
+
+ /* replace current slot contents with old contents */
+ cdevsw[dev_offset] = dev_olddev;
+
+ return 0;
+}
+
+int
+xfs_stat_device(void)
+{
+ return xfs_uprintf_device();
+}
+
+#elif defined(__FreeBSD__)
+
+int
+xfs_install_device(void)
+{
+ int i;
+ int err;
+ dev_t dev = NODEV;
+
+ err = cdevsw_add(&dev,
+ &xfs_dev,
+ NULL);
+ if (err)
+ return err;
+ printf("char device number %d\n", major(dev));
+
+ for (i = 0; i < NXFS; i++) {
+ XFSDEB(XDEBDEV, ("before initq(messageq and sleepq)\n"));
+ xfs_initq(&xfs_channel[i].messageq);
+ xfs_initq(&xfs_channel[i].sleepq);
+ }
+
+ return 0;
+}
+
+int
+xfs_uninstall_device(void)
+{
+ int i;
+ struct xfs_channel *chan;
+ dev_t dev = makedev(xfs_dev.d_maj, 0);
+
+ for (i = 0; i < NXFS; i++) {
+ chan = &xfs_channel[minor(dev)];
+ if (chan->status & CHANNEL_OPENED)
+ xfs_devclose(dev, 0, 0, NULL);
+ }
+
+ /* replace current slot contents with old contents */
+ cdevsw_add(&dev, NULL, NULL);
+
+ return 0;
+}
+
+int
+xfs_stat_device(void)
+{
+ return xfs_uprintf_device();
+}
+
+#endif
+#endif /* ACTUALLY_LKM_NOT_KERNEL */
diff --git a/sys/xfs/xfs_syscalls.c b/sys/xfs/xfs_syscalls.c
new file mode 100644
index 00000000000..c652a24ccd3
--- /dev/null
+++ b/sys/xfs/xfs_syscalls.c
@@ -0,0 +1,445 @@
+/* $OpenBSD: xfs_syscalls.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/ucred.h>
+#include <sys/mount.h>
+#include <sys/signal.h>
+#include <sys/syscall.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+
+#include <xfs/xfs_common.h>
+
+RCSID("$KTH: xfs_syscalls.c,v 1.20 1998/07/19 21:18:30 art Exp $");
+
+/*
+ * XFS system calls.
+ */
+
+#include <sys/xfs_message.h>
+#include <xfs/xfs_syscalls.h>
+#include <xfs/xfs_dev.h>
+#include <xfs/xfs_node.h>
+#include <xfs/xfs_deb.h>
+
+/* Misc syscalls */
+#include <sys/pioctl.h>
+#include <sys/syscallargs.h>
+
+#ifdef ACTUALLY_LKM_NOT_KERNEL
+/* XXX really defined in kern/kern_lkm.c */
+extern int sys_lkmnosys(struct proc *p, void *v, register_t *retval);
+
+#ifndef SYS_MAXSYSCALL /* Workaround for OpenBSD */
+#define SYS_MAXSYSCALL 255
+#endif
+#endif /* ACTUALLY_LKM_NOT_KERNEL */
+
+
+/*
+ * Def pag:
+ * 33536 <= g0 <= 34560
+ * 32512 <= g1 <= 48896
+ */
+
+#define XFS_PAG1_LLIM 33536
+#define XFS_PAG1_ULIM 34560
+#define XFS_PAG2_LLIM 32512
+#define XFS_PAG2_ULIM 48896
+
+static gid_t pag_part_one = XFS_PAG1_LLIM;
+static gid_t pag_part_two = XFS_PAG2_LLIM;
+
+static int
+xfs_is_pag(struct ucred *cred)
+{
+ /* The first group is the gid of the user ? */
+
+ if (cred->cr_ngroups >= 3 &&
+ cred->cr_groups[1] >= XFS_PAG1_LLIM &&
+ cred->cr_groups[1] <= XFS_PAG1_ULIM &&
+ cred->cr_groups[2] >= XFS_PAG2_LLIM &&
+ cred->cr_groups[2] <= XFS_PAG2_ULIM)
+ return 1;
+ else
+ return 0;
+}
+
+
+pag_t
+xfs_get_pag(struct ucred *cred)
+{
+ if (xfs_is_pag(cred)) {
+
+ return (((cred->cr_groups[1] << 16) & 0xFFFF0000) |
+ ((cred->cr_groups[2] & 0x0000FFFF)));
+
+ } else
+ return cred->cr_uid; /* XXX */
+}
+
+static int
+xfs_setpag_call(struct ucred **ret_cred)
+{
+ struct ucred *cred = *ret_cred;
+ int i;
+
+ if (!xfs_is_pag(cred)) {
+
+ /* Check if it fits */
+ if (cred->cr_ngroups + 2 >= NGROUPS)
+ return E2BIG; /* XXX Hmmm, better error ? */
+
+ cred = crcopy (cred);
+
+ /* Copy the groups */
+ for (i = cred->cr_ngroups - 1; i > 0; i--) {
+ cred->cr_groups[i + 2] = cred->cr_groups[i];
+ }
+ cred->cr_ngroups += 2;
+
+ } else
+ cred = crcopy(cred);
+
+ cred->cr_groups[1] = pag_part_one;
+ cred->cr_groups[2] = pag_part_two++;
+
+ if (pag_part_two > XFS_PAG2_ULIM) {
+ pag_part_one++;
+ pag_part_two = XFS_PAG2_LLIM;
+ }
+ *ret_cred = cred;
+ return 0;
+}
+
+#ifdef ACTUALLY_LKM_NOT_KERNEL
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+
+#define syscallarg(x) union { x datum; register_t pad; }
+
+struct sys_pioctl_args {
+ syscallarg(int) operation;
+ syscallarg(char *) a_pathP;
+ syscallarg(int) a_opcode;
+ syscallarg(struct ViceIoctl *) a_paramsP;
+ syscallarg(int) a_followSymlinks;
+};
+
+#elif defined(__FreeBSD__)
+
+struct sys_pioctl_args {
+ int operation;
+ char *a_pathP;
+ int a_opcode;
+ struct ViceIoctl *a_paramsP;
+ int a_followSymlinks;
+};
+
+#ifndef SCARG
+#define SCARG(a, b) (a->b)
+#endif
+
+#endif
+#endif
+
+static int
+xfs_pioctl_call(struct proc *p, void *v, int *i)
+{
+ int error;
+ struct ViceIoctl vice_ioctl;
+ struct xfs_message_pioctl msg;
+ struct xfs_message_wakeup_data *msg2;
+ char *pathptr;
+
+ struct sys_pioctl_args *arg = (struct sys_pioctl_args *) v;
+
+ /* Copy in the data structure for us */
+
+ error = copyin(SCARG(arg, a_paramsP),
+ &vice_ioctl,
+ sizeof(vice_ioctl));
+
+ if (error)
+ return error;
+
+ if (vice_ioctl.in_size > 2048) {
+ printf("xfs_pioctl_call: got a humongous in packet: opcode: %d",
+ SCARG(arg, a_opcode));
+ return EINVAL;
+ }
+ if (vice_ioctl.in_size != 0) {
+ error = copyin(vice_ioctl.in,
+ &msg.msg,
+ vice_ioctl.in_size);
+
+ if (error)
+ return error;
+ }
+
+ pathptr = SCARG(arg, a_pathP);
+
+ if (pathptr != NULL) {
+ char path[MAXPATHLEN];
+ struct xfs_node *xn;
+ struct nameidata nd;
+ struct vnode *vp;
+ size_t done;
+
+ XFSDEB(XDEBSYS, ("xfs_syscall: looking up: %p\n", pathptr));
+
+ error = copyinstr(pathptr, path, MAXPATHLEN, &done);
+
+ XFSDEB(XDEBSYS, ("xfs_syscall: looking up: %s len: %d error: %d\n",
+ path, done, error));
+
+ if (error)
+ return error;
+
+ NDINIT(&nd, LOOKUP,
+ SCARG(arg, a_followSymlinks) ? FOLLOW : 0,
+ UIO_SYSSPACE, path, p);
+
+ error = namei(&nd);
+
+ if (error != 0) {
+ XFSDEB(XDEBSYS, ("xfs_syscall: error during namei: %d\n", error));
+ return EINVAL;
+ }
+
+ vp = nd.ni_vp;
+
+ if (vp->v_tag != VT_AFS) {
+ XFSDEB(XDEBSYS, ("xfs_syscall: %s not in afs\n", path));
+ vrele(vp);
+ return EINVAL;
+ }
+
+ xn = VNODE_TO_XNODE(vp);
+
+ msg.handle = xn->handle;
+ vrele(vp);
+ }
+
+ msg.header.opcode = XFS_MSG_PIOCTL;
+ msg.opcode = SCARG(arg, a_opcode);
+
+ msg.insize = vice_ioctl.in_size;
+ msg.outsize = vice_ioctl.out_size;
+ msg.cred.uid = p->p_cred->p_ruid;
+ msg.cred.pag = xfs_get_pag(p->p_ucred);
+
+ error = xfs_message_rpc(0, &msg.header, sizeof(msg)); /* XXX */
+ msg2 = (struct xfs_message_wakeup_data *) &msg;
+
+ if (error == 0)
+ error = msg2->error;
+ else
+ error = EINVAL; /* return EINVAL to not confuse applications */
+
+ if (error == 0 && msg2->header.opcode == XFS_MSG_WAKEUP_DATA)
+ error = copyout(msg2->msg, vice_ioctl.out,
+ min(msg2->len, vice_ioctl.out_size));
+ return error;
+}
+
+
+#ifdef ACTUALLY_LKM_NOT_KERNEL
+static int
+xfs_syscall(struct proc *p, void *v, int *i)
+#else
+int
+sys_pioctl(struct proc *p, void *v, int *i)
+#endif
+{
+ struct sys_pioctl_args *arg = (struct sys_pioctl_args *) v;
+ int error = EINVAL;
+
+ switch (SCARG(arg, operation)) {
+ case AFSCALL_PIOCTL:
+ error = xfs_pioctl_call(p, v, i);
+ break;
+ case AFSCALL_SETPAG:
+ error = xfs_setpag_call(&p->p_cred->pc_ucred);
+ break;
+ default:
+ uprintf("Unimplemeted call: %d\n", SCARG(arg, operation));
+ error = EINVAL;
+ break;
+ }
+
+ return error;
+}
+
+#ifdef ACTUALLY_LKM_NOT_KERNEL
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+
+static int syscall_offset;
+static struct sysent syscall_oldent;
+
+static struct sysent xfs_syscallent = {
+ 4, /* number of args */
+ sizeof(struct sys_pioctl_args), /* size of args */
+ xfs_syscall /* function pointer */
+};
+
+static int
+find_first_free_syscall(int *ret)
+{
+ int i;
+
+ /*
+ * Search the table looking for a slot...
+ */
+ for (i = 0; i < SYS_MAXSYSCALL; i++)
+ if (sysent[i].sy_call == sys_lkmnosys) {
+ *ret = i;
+ return 0;
+ }
+ return ENFILE;
+}
+
+int
+xfs_install_syscalls(void)
+{
+ int error;
+
+#ifdef AFS_SYSCALL
+ syscall_offset = AFS_SYSCALL;
+#else
+ error = find_first_free_syscall(&syscall_offset);
+ if (error)
+ return error;
+#endif
+
+ syscall_oldent = sysent[syscall_offset];
+
+ /* replace with new */
+
+ sysent[syscall_offset] = xfs_syscallent;
+
+ printf("syscall %d\n", syscall_offset);
+ return 0;
+}
+
+int
+xfs_uninstall_syscalls(void)
+{
+ /* replace current slot contents with old contents */
+ if (syscall_offset)
+ sysent[syscall_offset] = syscall_oldent;
+
+ return 0;
+}
+
+int
+xfs_stat_syscalls(void)
+{
+ return 0;
+}
+
+#elif defined(__FreeBSD__)
+
+static int syscall_offset;
+static struct sysent syscall_oldent;
+
+static struct sysent xfs_syscallent = {
+ 4,
+ xfs_syscall
+};
+
+static int
+find_first_free_syscall(int *ret)
+{
+ int i;
+
+ /*
+ * Search the table looking for a slot...
+ */
+ for (i = 0; i < aout_sysvec.sv_size; i++)
+ if (aout_sysvec.sv_table[i].sy_call == (sy_call_t *) lkmnosys) {
+ *ret = i;
+ return 0;
+ }
+ return ENFILE;
+}
+
+int
+xfs_install_syscalls(void)
+{
+ int i;
+ int error;
+
+#ifdef AFS_SYSCALL
+ i = AFS_SYSCALL;
+#else
+ error = find_first_free_syscall(&i);
+ if (error)
+ return error;
+#endif
+
+ syscall_oldent = aout_sysvec.sv_table[i];
+
+ aout_sysvec.sv_table[i] = xfs_syscallent;
+
+ syscall_offset = i;
+ printf("syscall %d\n", i);
+ return 0;
+}
+
+int
+xfs_uninstall_syscalls(void)
+{
+ if (syscall_offset) {
+ aout_sysvec.sv_table[syscall_offset].sy_call = (sy_call_t *) lkmnosys;
+ }
+ return 0;
+}
+
+int
+xfs_stat_syscalls(void)
+{
+ return 0;
+}
+
+#endif
+#endif /* ACTUALLY_LKM_NOT_KERNEL */
diff --git a/sys/xfs/xfs_vfsops.c b/sys/xfs/xfs_vfsops.c
new file mode 100644
index 00000000000..cc8a39dc536
--- /dev/null
+++ b/sys/xfs/xfs_vfsops.c
@@ -0,0 +1,441 @@
+/* $OpenBSD: xfs_vfsops.c,v 1.1 1998/08/30 16:47:22 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/mount.h>
+#include <sys/systm.h>
+#include <sys/namei.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+
+#include <xfs/xfs_common.h>
+
+RCSID("$KTH: xfs_vfsops.c,v 1.22 1998/08/13 01:38:49 art Exp $");
+
+/*
+ * XFS vfs operations.
+ */
+
+#include <xfs/xfs_common.h>
+#include <sys/xfs_message.h>
+#include <xfs/xfs_dev.h>
+#include <xfs/xfs_fs.h>
+#include <xfs/xfs_deb.h>
+
+static struct vnode *make_dead_vnode(struct mount * mp);
+
+struct xfs xfs[NXFS];
+
+static int
+xfs_mount(struct mount * mp,
+ const char *user_path,
+ caddr_t user_data,
+ struct nameidata * ndp,
+ struct proc * p)
+{
+ struct vnode *devvp;
+ dev_t dev;
+ int error;
+ struct vattr vat;
+ char path[MAXPATHLEN];
+ char data[MAXPATHLEN];
+ size_t len;
+
+ error = copyinstr(user_path, path, MAXPATHLEN, &len);
+ if (error)
+ return error;
+
+ error = copyinstr(user_data, data, MAXPATHLEN, &len);
+ if (error)
+ return error;
+
+ XFSDEB(XDEBVFOPS, ("xfs_mount: "
+ "struct mount mp = %p path = %s data = '%s'\n",
+ mp, path, data));
+
+ NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF,
+ UIO_SYSSPACE, data, p);
+ error = namei(ndp);
+ if (error)
+ return error;
+
+ devvp = ndp->ni_vp;
+
+ if (devvp->v_type != VCHR) {
+ vput(devvp);
+ return ENXIO;
+ }
+ error = VOP_GETATTR(devvp, &vat, p->p_ucred, p);
+ if (error) {
+ vput(devvp);
+ return error;
+ }
+ dev = vat.va_rdev;
+ vput(devvp);
+
+ /* Check that this device really is an xfs_dev */
+ if (major(dev) < 0 || nchrdev < major(dev))
+ return ENXIO;
+ if (minor(dev) < 0 || NXFS < minor(dev))
+ return ENXIO;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ if (cdevsw[major(dev)].d_open != xfs_devopen)
+ return ENXIO;
+#elif defined(__FreeBSD__)
+ if (cdevsw[major(dev)] == NULL
+ || cdevsw[major(dev)]->d_open != xfs_devopen)
+ return ENXIO;
+#endif
+
+ if (xfs[minor(dev)].status & XFS_MOUNTED)
+ return EBUSY;
+
+ xfs[minor(dev)].status = XFS_MOUNTED;
+ xfs[minor(dev)].mp = mp;
+ xfs[minor(dev)].root = 0;
+ xfs[minor(dev)].nnodes = 0;
+ xfs[minor(dev)].fd = minor(dev);
+
+ VFS_TO_XFS(mp) = &xfs[minor(dev)];
+ vfs_getnewfsid(mp);
+
+ mp->mnt_stat.f_bsize = DEV_BSIZE;
+ mp->mnt_stat.f_iosize = DEV_BSIZE;
+ mp->mnt_stat.f_blocks = 4711 * 4711;
+ mp->mnt_stat.f_bfree = 4711 * 4711;
+ mp->mnt_stat.f_bavail = 4711 * 4711;
+ mp->mnt_stat.f_files = 4711;
+ mp->mnt_stat.f_ffree = 4711;
+ mp->mnt_stat.f_owner = 0;
+ mp->mnt_stat.f_flags = mp->mnt_flag;
+
+ strncpy(mp->mnt_stat.f_mntonname,
+ path,
+ sizeof(mp->mnt_stat.f_mntonname));
+
+ strncpy(mp->mnt_stat.f_mntfromname,
+ "arla",
+ sizeof(mp->mnt_stat.f_mntfromname));
+
+ strncpy(mp->mnt_stat.f_fstypename,
+ "xfs",
+ sizeof(mp->mnt_stat.f_fstypename));
+
+ return 0;
+}
+
+static int
+xfs_start(struct mount * mp, int flags, struct proc * p)
+{
+ XFSDEB(XDEBVFOPS, ("xfs_start mp = 0x%x\n", (u_int) mp));
+ return 0;
+}
+
+static int
+xfs_unmount(struct mount * mp, int mntflags, struct proc * p)
+{
+ struct xfs *xfsp = VFS_TO_XFS(mp);
+ extern int doforce;
+ int flags = 0;
+ int error;
+
+ XFSDEB(XDEBVFOPS, ("xfs_unmount mp = 0x%x\n", (u_int) mp));
+
+ if (mntflags & MNT_FORCE) {
+ if (!doforce)
+ return EINVAL;
+ flags |= FORCECLOSE;
+ }
+
+ error = free_all_xfs_nodes(xfsp, flags);
+ if (error)
+ return error;
+
+ xfsp->status = 0;
+
+ return 0;
+}
+
+static int
+xfs_root(struct mount * mp, struct vnode ** vpp)
+{
+ struct xfs *xfsp = VFS_TO_XFS(mp);
+ struct xfs_message_getroot msg;
+ int error;
+
+ XFSDEB(XDEBVFOPS, ("xfs_root mp = 0x%x\n", (u_int) mp));
+
+ do {
+ if (xfsp->root != NULL) {
+ *vpp = XNODE_TO_VNODE(xfsp->root);
+ VREF(*vpp);
+ return 0;
+ }
+ msg.header.opcode = XFS_MSG_GETROOT;
+ msg.cred.uid = curproc->p_ucred->cr_uid;
+ msg.cred.pag = 0; /* XXX */
+ error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
+ if (error == 0)
+ error = ((struct xfs_message_wakeup *) & msg)->error;
+ } while (error == 0);
+ /*
+ * Failed to get message through, need to pretend that all went well
+ * and return a fake dead vnode to be able to unmount.
+ */
+ *vpp = make_dead_vnode(mp);
+ (*vpp)->v_flag |= VROOT;
+ return 0;
+}
+
+static int
+xfs_quotactl(struct mount * mp,
+ int cmd,
+ uid_t uid,
+ caddr_t arg,
+ struct proc * p)
+{
+ XFSDEB(XDEBVFOPS, ("xfs_quotactl\n"));
+ return (EOPNOTSUPP);
+}
+
+static int
+xfs_statfs(struct mount * mp,
+ struct statfs * sbp,
+ struct proc * p)
+{
+ XFSDEB(XDEBVFOPS, ("xfs_statfs\n"));
+
+ bcopy(&mp->mnt_stat, sbp, sizeof(*sbp));
+ return 0;
+}
+
+static int
+xfs_sync(struct mount * mp,
+ int waitfor,
+ struct ucred * cred,
+ struct proc * p)
+{
+ XFSDEB(XDEBVFOPS, ("xfs_sync\n"));
+ return 0;
+}
+
+static int
+xfs_vget(struct mount * mp,
+ ino_t ino,
+ struct vnode ** vpp)
+{
+ XFSDEB(XDEBVFOPS, ("xfs_vget\n"));
+ return EOPNOTSUPP;
+}
+
+static int
+xfs_fhtovp(struct mount * mp,
+ struct fid * fhp,
+ struct mbuf * nam,
+ struct vnode ** vpp,
+ int *exflagsp,
+ struct ucred ** credanonp)
+{
+ XFSDEB(XDEBVFOPS, ("xfs_fhtovp\n"));
+ return EOPNOTSUPP;
+}
+
+static int
+xfs_vptofh(struct vnode * vp,
+ struct fid * fhp)
+{
+ XFSDEB(XDEBVFOPS, ("xfs_vptofh\n"));
+ return EOPNOTSUPP;
+}
+
+
+/* sysctl()able variables :-) */
+static int
+xfs_sysctl(int *name, u_int namelen, void *oldp, size_t * oldlenp,
+ void *newp, size_t newlen, struct proc * p)
+{
+ /* Supposed to be terminal... */
+ if (namelen != 1)
+ return (ENOTDIR);
+
+ return (EOPNOTSUPP);
+}
+
+static int
+xfs_init(struct vfsconf * vfsp)
+{
+ XFSDEB(XDEBVFOPS, ("xfs_init\n"));
+
+ return (0);
+}
+
+
+struct vfsops xfs_vfsops = {
+ xfs_mount,
+ xfs_start,
+ xfs_unmount,
+ xfs_root,
+ xfs_quotactl,
+ xfs_statfs,
+ xfs_sync,
+ xfs_vget,
+ xfs_fhtovp,
+ xfs_vptofh,
+ xfs_init,
+ xfs_sysctl
+};
+
+/*
+ *
+ */
+static int
+xfs_uprintf_filsys(void)
+{
+ return 0;
+}
+
+/*
+ * Install and uninstall filesystem.
+ */
+
+extern struct vnodeopv_desc xfs_vnodeop_opv_desc;
+
+int
+xfs_install_filesys(void)
+{
+
+ struct vfsconf *vfsp;
+ struct vfsconf **vfspp;
+
+
+ /* Check if filesystem already known */
+ for (vfspp = &vfsconf, vfsp = vfsconf;
+ vfsp;
+ vfspp = &vfsp->vfc_next, vfsp = vfsp->vfc_next)
+ if (strncmp(vfsp->vfc_name,
+ "xfs", MFSNAMELEN) == 0)
+ return (EEXIST);
+
+ /* Allocate and initialize */
+ MALLOC(vfsp, struct vfsconf *, sizeof(struct vfsconf),
+ M_VFS, M_WAITOK);
+
+ vfsp->vfc_vfsops = &xfs_vfsops;
+ strncpy(vfsp->vfc_name, "xfs", MFSNAMELEN);
+ vfsp->vfc_typenum = 0;
+ vfsp->vfc_refcount = 0;
+ vfsp->vfc_flags = 0;
+ vfsp->vfc_mountroot = 0;
+ vfsp->vfc_next = NULL;
+
+ maxvfsconf++;
+
+ /* Add to the end of the list */
+ *vfspp = vfsp;
+
+ /* Call vfs_init() */
+ printf("Calling vfs_init()\n");
+ (*(vfsp->vfc_vfsops->vfs_init)) (vfsp);
+
+ /* done! */
+
+ return 0;
+}
+
+int
+xfs_uninstall_filesys(void)
+{
+
+ struct vfsconf *vfsp;
+ struct vfsconf **vfspp;
+
+
+ /* Find our vfsconf struct */
+ for (vfspp = &vfsconf, vfsp = vfsconf;
+ vfsp;
+ vfspp = &vfsp->vfc_next, vfsp = vfsp->vfc_next)
+ if (strncmp(vfsp->vfc_name,
+ "xfs",
+ MFSNAMELEN) == 0)
+ break;
+
+ if (!vfsp) /* Not found */
+ return (EEXIST);
+
+ if (vfsp->vfc_refcount) /* In use */
+ return (EBUSY);
+
+ /* Remove from list and free */
+ *vfspp = vfsp->vfc_next;
+ FREE(vfsp, M_VFS);
+
+ maxvfsconf--;
+
+ return 0;
+}
+
+
+
+int
+xfs_stat_filesys(void)
+{
+ return xfs_uprintf_filsys();
+}
+
+/*
+ * To be able to unmount when the XFS daemon is not
+ * responding we need a root vnode, use a dead vnode!
+ */
+extern int (**dead_vnodeop_p) (void *);
+
+static struct vnode *
+make_dead_vnode(struct mount * mp)
+{
+ struct vnode *dead;
+ int error;
+
+ XFSDEB(XDEBNODE, ("make_dead_vnode mp = 0x%x\n", (u_int) mp));
+
+ if ((error = getnewvnode(VT_NON, mp, dead_vnodeop_p, &dead)))
+ panic("make_dead_vnode: getnewvnode failed: error = %d\n", error);
+
+ return dead;
+}
diff --git a/sys/xfs/xfs_vnodeops.c b/sys/xfs/xfs_vnodeops.c
new file mode 100644
index 00000000000..67dcd4fdc67
--- /dev/null
+++ b/sys/xfs/xfs_vnodeops.c
@@ -0,0 +1,1000 @@
+/* $OpenBSD: xfs_vnodeops.c,v 1.1 1998/08/30 16:47:22 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.
+ */
+
+/*
+ * XFS operations.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/uio.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/mount.h>
+#include <sys/fcntl.h>
+
+#include <sys/xfs_message.h>
+#include <xfs/xfs_dev.h>
+#include <xfs/xfs_common.h>
+#include <xfs/xfs_fs.h>
+#include <xfs/xfs_deb.h>
+#include <xfs/xfs_syscalls.h>
+
+RCSID("$KTH: xfs_vnodeops.c,v 1.41 1998/08/14 04:54:09 art Exp $");
+
+static int
+xfs_open_valid(struct vnode * vp, struct ucred * cred, u_int tok)
+{
+ struct xfs *xfsp = XFS_FROM_VNODE(vp);
+ struct xfs_node *xn = VNODE_TO_XNODE(vp);
+ int error = 0;
+
+ XFSDEB(XDEBVFOPS, ("xfs_open_valid\n"));
+
+ do {
+ if (!XFS_TOKEN_GOT(xn, tok)) {
+ struct xfs_message_open msg;
+
+ msg.header.opcode = XFS_MSG_OPEN;
+ msg.cred.uid = cred->cr_uid;
+ msg.cred.pag = xfs_get_pag(cred);
+ msg.handle = xn->handle;
+ msg.tokens = tok;
+ error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
+ if (error == 0)
+ error = ((struct xfs_message_wakeup *) & msg)->error;
+ } else {
+ goto done;
+ }
+ } while (error == 0);
+
+done:
+ return error;
+}
+
+static int
+xfs_attr_valid(struct vnode * vp, struct ucred * cred, u_int tok)
+{
+ struct xfs *xfsp = XFS_FROM_VNODE(vp);
+ struct xfs_node *xn = VNODE_TO_XNODE(vp);
+ int error = 0;
+
+ pag_t pag = xfs_get_pag(cred);
+
+ do {
+ if (!XFS_TOKEN_GOT(xn, tok)) {
+ struct xfs_message_getattr msg;
+
+ msg.header.opcode = XFS_MSG_GETATTR;
+ msg.cred.uid = cred->cr_uid;
+ msg.cred.pag = pag;
+ msg.handle = xn->handle;
+ error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
+ if (error == 0)
+ error = ((struct xfs_message_wakeup *) & msg)->error;
+ } else {
+ goto done;
+ }
+ } while (error == 0);
+
+done:
+ return error;
+}
+
+static int
+xfs_rights_valid(struct vnode * vp, struct ucred * cred)
+{
+ struct xfs *xfsp = XFS_FROM_VNODE(vp);
+ struct xfs_node *xn = VNODE_TO_XNODE(vp);
+ int error = 0;
+
+ pag_t pag = xfs_get_pag(cred);
+
+ do {
+ if (!xfs_has_pag(xn, pag)) {
+ struct xfs_message_getattr msg;
+
+ msg.header.opcode = XFS_MSG_GETATTR;
+ msg.cred.uid = cred->cr_uid;
+ msg.cred.pag = pag;
+ msg.handle = xn->handle;
+ error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
+ if (error == 0)
+ error = ((struct xfs_message_wakeup *) & msg)->error;
+ } else {
+ goto done;
+ }
+ } while (error == 0);
+
+done:
+ return error;
+}
+
+static int
+xfs_data_valid(struct vnode * vp, struct ucred * cred, u_int tok)
+{
+ struct xfs *xfsp = XFS_FROM_VNODE(vp);
+ struct xfs_node *xn = VNODE_TO_XNODE(vp);
+ int error = 0;
+
+ do {
+ if (!XFS_TOKEN_GOT(xn, tok)) {
+ struct xfs_message_getdata msg;
+
+ msg.header.opcode = XFS_MSG_GETDATA;
+ msg.cred.uid = cred->cr_uid;
+ msg.cred.pag = xfs_get_pag(cred);
+ msg.handle = xn->handle;
+ msg.tokens = tok;
+ error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
+ if (error == 0)
+ error = ((struct xfs_message_wakeup *) & msg)->error;
+ } else {
+ goto done;
+ }
+ } while (error == 0);
+
+done:
+ return error;
+}
+
+static int
+do_fsync(struct xfs * xfsp,
+ struct xfs_node * xn,
+ struct ucred * cred,
+ u_int flag)
+{
+ int error;
+ struct xfs_message_putdata msg;
+
+ msg.header.opcode = XFS_MSG_PUTDATA;
+ if (cred != NOCRED) {
+ msg.cred.uid = cred->cr_uid;
+ msg.cred.pag = xfs_get_pag(cred);
+ } else {
+ msg.cred.uid = 0;
+ msg.cred.pag = XFS_ANONYMOUSID;
+ }
+ msg.handle = xn->handle;
+
+ msg.flag = flag;
+ error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
+ if (error == 0)
+ error = ((struct xfs_message_wakeup *) & msg)->error;
+
+ if (error == 0)
+ xn->flags &= ~XFS_DATA_DIRTY;
+
+ return error;
+}
+
+/*
+ * vnode functions
+ */
+
+static int
+xfs_open(void *vap)
+{
+ struct vop_open_args *ap = vap;
+
+ XFSDEB(XDEBVNOPS, ("xfs_open\n"));
+
+ if (ap->a_mode & FWRITE)
+ return xfs_open_valid(ap->a_vp, ap->a_cred, XFS_OPEN_NW);
+ else
+ return xfs_open_valid(ap->a_vp, ap->a_cred, XFS_OPEN_NR);
+}
+
+static int
+xfs_fsync(void *vap)
+{
+ struct vop_fsync_args *ap = vap;
+
+ struct xfs *xfsp = XFS_FROM_VNODE(ap->a_vp);
+ struct xfs_node *xn = VNODE_TO_XNODE(ap->a_vp);
+ int error = 0;
+
+ XFSDEB(XDEBVNOPS, ("xfs_fsync: 0x%x\n", (int) ap->a_vp));
+
+ /*
+ * It seems that fsync is sometimes called after reclaiming a node.
+ * In that case we just look happy.
+ */
+
+ if (xn == NULL) {
+ printf("XFS PANIC WARNING! xfs_fsync called after reclaiming!\n");
+ return 0;
+ }
+
+ if (xn->flags & XFS_DATA_DIRTY)
+ error = do_fsync(xfsp, xn, ap->a_cred, XFS_WRITE);
+
+ return error;
+}
+
+static int
+xfs_close(void *vap)
+{
+ struct vop_close_args *ap = vap;
+
+ struct xfs *xfsp = XFS_FROM_VNODE(ap->a_vp);
+ struct xfs_node *xn = VNODE_TO_XNODE(ap->a_vp);
+ int error = 0;
+
+ XFSDEB(XDEBVNOPS, ("xfs_close cred = %p\n", ap->a_cred));
+
+ if (ap->a_fflag & FWRITE && xn->flags & XFS_DATA_DIRTY)
+ error = do_fsync(xfsp, xn, ap->a_cred, XFS_WRITE);
+
+ return error;
+}
+
+static int
+xfs_read(void *vap)
+{
+ struct vop_read_args *ap = vap;
+
+ int error = 0;
+
+ XFSDEB(XDEBVNOPS, ("xfs_read\n"));
+
+ error = xfs_data_valid(ap->a_vp, ap->a_cred, XFS_DATA_R);
+
+ if (error == 0) {
+ struct vnode *t = DATA_FROM_VNODE(ap->a_vp);
+
+ vn_lock(t, LK_EXCLUSIVE | LK_RETRY, ap->a_uio->uio_procp);
+ error = VOP_READ(t, ap->a_uio, ap->a_ioflag, ap->a_cred);
+ VOP_UNLOCK(t, 0, ap->a_uio->uio_procp);
+ }
+ return error;
+}
+
+static int
+xfs_write(void *vap)
+{
+ struct vop_read_args *ap = vap;
+
+ struct vnode *vp = ap->a_vp;
+ struct uio *uiop = ap->a_uio;
+ int ioflag = ap->a_ioflag;
+ struct ucred *cred = ap->a_cred;
+ int error = 0;
+
+ XFSDEB(XDEBVNOPS, ("xfs_write\n"));
+
+ error = xfs_data_valid(vp, cred, XFS_DATA_W);
+
+ if (error == 0) {
+ struct xfs_node *xn = VNODE_TO_XNODE(vp);
+ struct vnode *t = DATA_FROM_XNODE(xn);
+ struct vattr sub_attr;
+ int error2 = 0;
+
+ vn_lock(t, LK_EXCLUSIVE | LK_RETRY, uiop->uio_procp);
+ error = VOP_WRITE(t, uiop, ioflag, cred);
+ VNODE_TO_XNODE(ap->a_vp)->flags |= XFS_DATA_DIRTY;
+
+ error2 = VOP_GETATTR(t, &sub_attr, cred, uiop->uio_procp);
+ if (error2 == 0) {
+ xn->attr.va_size = sub_attr.va_size;
+ xn->attr.va_mtime = sub_attr.va_mtime;
+ }
+
+ VOP_UNLOCK(t, 0, ap->a_uio->uio_procp);
+ }
+
+ return error;
+}
+
+static int
+xfs_getattr(void *vap)
+{
+ struct vop_getattr_args *ap = vap;
+ int error = 0;
+
+ struct xfs_node *xn = VNODE_TO_XNODE(ap->a_vp);
+
+ XFSDEB(XDEBVNOPS, ("xfs_getattr\n"));
+
+ error = xfs_attr_valid(ap->a_vp, ap->a_cred, XFS_ATTR_R);
+ if (error == 0) {
+ *ap->a_vap = xn->attr;
+ }
+ return error;
+}
+
+static int
+xfs_setattr(void *vap)
+{
+ struct vop_setattr_args *ap = vap;
+ struct xfs *xfsp = XFS_FROM_VNODE(ap->a_vp);
+ struct xfs_node *xn = VNODE_TO_XNODE(ap->a_vp);
+ int error = 0;
+
+ XFSDEB(XDEBVNOPS, ("xfs_setattr\n"));
+ if (XFS_TOKEN_GOT(xn, XFS_ATTR_W)) {
+ /* Update attributes and mark them dirty. */
+ VNODE_TO_XNODE(ap->a_vp)->flags |= XFS_ATTR_DIRTY;
+ error = EINVAL; /* XXX not yet implemented */
+ goto done;
+ } else {
+ struct xfs_message_putattr msg;
+
+ msg.header.opcode = XFS_MSG_PUTATTR;
+ if (ap->a_cred != NOCRED) {
+ msg.cred.uid = ap->a_cred->cr_uid;
+ msg.cred.pag = xfs_get_pag(ap->a_cred);
+ } else {
+ msg.cred.uid = 0;
+ msg.cred.pag = XFS_ANONYMOUSID;
+ }
+ msg.handle = xn->handle;
+ vattr2xfs_attr(ap->a_vap, &msg.attr);
+ error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
+ if (error == 0)
+ error = ((struct xfs_message_wakeup *) & msg)->error;
+ XFS_TOKEN_CLEAR(xn, XFS_ATTR_VALID, XFS_ATTR_MASK);
+ }
+
+done:
+ return error;
+}
+
+static int
+check_rights (u_char rights, int mode)
+{
+ int error = 0;
+
+ if (mode & VREAD)
+ if ((rights & XFS_RIGHT_R) == 0)
+ error = EACCES;
+ if (mode & VWRITE)
+ if ((rights & XFS_RIGHT_W) == 0)
+ error = EACCES;
+ if (mode & VEXEC)
+ if ((rights & XFS_RIGHT_X) == 0)
+ error = EACCES;
+ return error;
+}
+
+static int
+xfs_access(void *vap)
+{
+ struct vop_access_args *ap = vap;
+
+ int error = 0;
+ int mode = ap->a_mode;
+ pag_t pag = xfs_get_pag(ap->a_cred);
+
+ XFSDEB(XDEBVNOPS, ("xfs_access mode = 0%o\n", mode));
+
+ error = xfs_attr_valid(ap->a_vp, ap->a_cred, XFS_ATTR_R);
+ if (error == 0) {
+ struct xfs_node *xn = VNODE_TO_XNODE(ap->a_vp);
+ int i;
+
+ error = check_rights (xn->anonrights, mode);
+
+ if (error == 0)
+ goto done;
+
+ XFSDEB(XDEBVNOPS, ("xfs_access anonaccess failed\n"));
+
+ xfs_rights_valid(ap->a_vp, ap->a_cred); /* ignore error */
+
+ 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:
+ XFSDEB(XDEBVNOPS, ("xfs_access(0%o) = %d\n", mode, error));
+
+ return error;
+}
+
+/*
+ * Do the actual lookup. The locking state of dvp is not changed and vpp is
+ * returned locked and ref:d.
+ *
+ * This assumes that the cache doesn't change the locking state,
+ * which it shouldn't.
+ */
+static int
+do_actual_lookup(struct vnode *dvp, struct componentname *cnp,
+ struct vnode **vpp)
+{
+ int error;
+ struct xfs_node *d = VNODE_TO_XNODE(dvp);
+ struct xfs_message_getnode msg;
+ struct xfs *xfsp = XFS_FROM_VNODE(dvp);
+
+ if (dvp->v_type != VDIR)
+ return ENOTDIR;
+
+ do {
+ error = xfs_dnlc_lookup(dvp, cnp, vpp);
+ if (error == 0) {
+ msg.header.opcode = XFS_MSG_GETNODE;
+ if (cnp->cn_cred != NOCRED) {
+ msg.cred.uid = cnp->cn_cred->cr_uid;
+ msg.cred.pag = xfs_get_pag(cnp->cn_cred);
+ } else {
+ msg.cred.uid = 0;
+ msg.cred.pag = XFS_ANONYMOUSID;
+ }
+ msg.parent_handle = d->handle;
+
+ bcopy(cnp->cn_nameptr, msg.name, cnp->cn_namelen);
+ msg.name[cnp->cn_namelen] = '\0';
+
+ error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
+
+ if (error == 0)
+ error = ((struct xfs_message_wakeup *) & msg)->error;
+ if (error == ENOENT && cnp->cn_namelen <= NCHNAMLEN) {
+ XFSDEB(XDEBVNOPS, ("xfs_lookup: neg cache %p (%s, %ld)\n",
+ dvp,
+ cnp->cn_nameptr, cnp->cn_namelen));
+ cache_enter (dvp, NULL, cnp);
+ }
+
+ XFSDEB(XDEBVNOPS, ("xfs_lookup error: %d\n", error));
+ } else if (error == -1) {
+ vget(*vpp, 0, cnp->cn_proc);
+ error = 0;
+ goto done;
+ }
+ } while (error == 0);
+
+done:
+
+ return error;
+}
+
+static int
+xfs_lookup(void *vap)
+{
+ struct vop_lookup_args *ap = vap;
+
+ struct vnode *dvp = ap->a_dvp;
+ struct componentname *cnp = ap->a_cnp;
+ int nameiop = cnp->cn_nameiop;
+ int flags = cnp->cn_flags;
+ int islastcn = flags & ISLASTCN;
+ struct proc *p = cnp->cn_proc;
+ int error = 0;
+
+ XFSDEB(XDEBVNOPS, ("xfs_lookup: (%s, %ld)\n",
+ cnp->cn_nameptr,
+ cnp->cn_namelen));
+
+ *ap->a_vpp = NULL;
+
+ error = do_actual_lookup(dvp, cnp, ap->a_vpp);
+
+ if (error == ENOENT
+ && (nameiop == CREATE || nameiop == RENAME)
+ && islastcn) {
+ error = EJUSTRETURN;
+ }
+
+ if (nameiop != LOOKUP && islastcn)
+ cnp->cn_flags |= SAVENAME;
+
+ if ((error == EJUSTRETURN || error == 0) &&
+ !(islastcn && flags & LOCKPARENT))
+ VOP_UNLOCK(ap->a_dvp, 0, p);
+
+ XFSDEB(XDEBVNOPS, ("xfs_lookup() error = %d\n", error));
+ return error;
+}
+
+static int
+xfs_create(void *vap)
+{
+ struct vop_create_args *ap = vap;
+
+ struct xfs *xfsp = XFS_FROM_VNODE(ap->a_dvp);
+ struct xfs_node *xn = VNODE_TO_XNODE(ap->a_dvp);
+ struct componentname *cnp = ap->a_cnp;
+ int error = 0;
+
+ XFSDEB(XDEBVNOPS, ("xfs_create: (%s, %ld)\n",
+ cnp->cn_nameptr,
+ cnp->cn_namelen));
+ {
+ struct xfs_message_create msg;
+
+ msg.header.opcode = XFS_MSG_CREATE;
+ msg.parent_handle = xn->handle;
+ strncpy(msg.name, cnp->cn_nameptr, 256);
+ vattr2xfs_attr(ap->a_vap, &msg.attr);
+
+ msg.mode = 0; /* XXX - mode */
+ if (cnp->cn_cred != NOCRED) {
+ msg.cred.uid = cnp->cn_cred->cr_uid;
+ msg.cred.pag = xfs_get_pag(cnp->cn_cred);
+ } else {
+ msg.cred.uid = 0;
+ msg.cred.pag = XFS_ANONYMOUSID;
+ }
+ error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
+ if (error == 0)
+ error = ((struct xfs_message_wakeup *) & msg)->error;
+ }
+
+ if (error == 0) {
+ error = do_actual_lookup(ap->a_dvp, cnp, ap->a_vpp);
+ }
+
+ if (error != 0 || (cnp->cn_flags & SAVESTART) == 0)
+ free (cnp->cn_pnbuf, M_NAMEI);
+
+ vput(ap->a_dvp);
+
+ return error;
+}
+
+static int
+xfs_remove(void *vap)
+{
+ struct vop_remove_args *ap = vap;
+ struct vnode *dvp = ap->a_dvp;
+ struct vnode *vp = ap->a_vp;
+ struct xfs *xfsp = XFS_FROM_VNODE(dvp);
+ struct xfs_node *xn = VNODE_TO_XNODE(dvp);
+ struct componentname *cnp = ap->a_cnp;
+ struct xfs_message_remove msg;
+ int error;
+
+ XFSDEB(XDEBVNOPS, ("xfs_remove: (%s, %ld\n",
+ cnp->cn_nameptr,
+ cnp->cn_namelen));
+
+ msg.header.opcode = XFS_MSG_REMOVE;
+ msg.parent_handle = xn->handle;
+ strncpy(msg.name, cnp->cn_nameptr, 256);
+ msg.cred.uid = cnp->cn_cred->cr_uid;
+ msg.cred.pag = xfs_get_pag(cnp->cn_cred);
+ error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
+ if (error == 0)
+ error = ((struct xfs_message_wakeup *) &msg)->error;
+
+ if (error == 0)
+ cache_purge (vp);
+
+#ifdef DIAGNOSTIC
+ /*
+ * vp == dvp should not happen.
+ * 1. vp == dvp means that we are removing a directory and this is
+ * remove, not rmdir.
+ */
+ if (dvp == vp)
+ panic("vp == dvp");
+#endif
+
+ vput(vp);
+ vput(dvp);
+
+ if (error != 0 || (cnp->cn_flags & SAVESTART) == 0)
+ free (cnp->cn_pnbuf, M_NAMEI);
+
+ return error;
+}
+
+static int
+xfs_rename(void *vap)
+{
+ struct vop_rename_args *ap = vap;
+
+ struct vnode *fdvp = ap->a_fdvp;
+ struct vnode *fvp = ap->a_fvp;
+ struct componentname *fcnp = ap->a_fcnp;
+ struct vnode *tdvp = ap->a_tdvp;
+ struct vnode *tvp = ap->a_tvp;
+ struct componentname *tcnp = ap->a_tcnp;
+ struct xfs *xfsp = XFS_FROM_VNODE(fdvp);
+ int error;
+
+ XFSDEB(XDEBVNOPS, ("xfs_rename\n"));
+
+ if ((fvp->v_mount != tdvp->v_mount)
+ || (tvp && (fvp->v_mount != tvp->v_mount))) {
+ error = EXDEV;
+ goto abort;
+ }
+
+ if (tvp) {
+ struct xfs_message_remove msg;
+
+ msg.header.opcode = XFS_MSG_REMOVE;
+ msg.parent_handle = VNODE_TO_XNODE(tdvp)->handle;
+ strncpy(msg.name, tcnp->cn_nameptr, 256);
+ msg.cred.uid = tcnp->cn_cred->cr_uid;
+ msg.cred.pag = xfs_get_pag(tcnp->cn_cred);
+ error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
+ if (error == 0)
+ error = ((struct xfs_message_wakeup *) &msg)->error;
+
+ if (error)
+ goto abort;
+
+ vput(tvp);
+ tvp = NULL;
+ }
+
+ {
+ struct xfs_message_rename msg;
+
+ msg.header.opcode = XFS_MSG_RENAME;
+ msg.old_parent_handle = VNODE_TO_XNODE(fdvp)->handle;
+ strncpy(msg.old_name, fcnp->cn_nameptr, 256);
+ msg.new_parent_handle = VNODE_TO_XNODE(tdvp)->handle;
+ strncpy(msg.new_name, tcnp->cn_nameptr, 256);
+ msg.cred.uid = tcnp->cn_cred->cr_uid;
+ msg.cred.pag = xfs_get_pag(tcnp->cn_cred);
+ error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
+ if (error == 0)
+ error = ((struct xfs_message_wakeup *) &msg)->error;
+
+ }
+
+
+abort:
+ VOP_ABORTOP(tdvp, tcnp);
+ if(tdvp == tvp)
+ vrele(tdvp);
+ else
+ vput(tdvp);
+ if(tvp)
+ vput(tvp);
+ VOP_ABORTOP(fdvp, fcnp);
+ vrele(fdvp);
+ vrele(fvp);
+ return error;
+}
+
+static int
+xfs_mkdir(void *vap)
+{
+ struct vop_mkdir_args *ap = vap;
+
+ struct xfs *xfsp = XFS_FROM_VNODE(ap->a_dvp);
+ struct xfs_node *xn = VNODE_TO_XNODE(ap->a_dvp);
+ struct componentname *cnp = ap->a_cnp;
+ int error = 0;
+
+ XFSDEB(XDEBVNOPS, ("xfs_mkdir\n"));
+ {
+ struct xfs_message_mkdir msg;
+
+ msg.header.opcode = XFS_MSG_MKDIR;
+ msg.parent_handle = xn->handle;
+ strncpy(msg.name, cnp->cn_nameptr, 256);
+ vattr2xfs_attr(ap->a_vap, &msg.attr);
+ if (cnp->cn_cred != NOCRED) {
+ msg.cred.uid = cnp->cn_cred->cr_uid;
+ msg.cred.pag = xfs_get_pag(cnp->cn_cred);
+ } else {
+ msg.cred.uid = 0;
+ msg.cred.pag = XFS_ANONYMOUSID;
+ }
+ error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
+ if (error == 0)
+ error = ((struct xfs_message_wakeup *) & msg)->error;
+ }
+
+ if (error == 0) {
+ error = do_actual_lookup(ap->a_dvp, cnp, ap->a_vpp);
+ }
+
+ if (error != 0 || (cnp->cn_flags & SAVESTART) == 0)
+ free (cnp->cn_pnbuf, M_NAMEI);
+
+ vput(ap->a_dvp);
+ return error;
+}
+
+static int
+xfs_rmdir(void *vap)
+{
+ struct vop_rmdir_args *ap = vap;
+
+ struct vnode *dvp = ap->a_dvp;
+ struct vnode *vp = ap->a_vp;
+ struct xfs *xfsp = XFS_FROM_VNODE(dvp);
+ struct xfs_node *xn = VNODE_TO_XNODE(dvp);
+ struct componentname *cnp = ap->a_cnp;
+ struct xfs_message_rmdir msg;
+ int error;
+
+ XFSDEB(XDEBVNOPS, ("xfs_rmdir: (%s, %ld\n",
+ cnp->cn_nameptr,
+ cnp->cn_namelen));
+
+ msg.header.opcode = XFS_MSG_RMDIR;
+ msg.parent_handle = xn->handle;
+ strncpy(msg.name, cnp->cn_nameptr, 256);
+ msg.cred.uid = cnp->cn_cred->cr_uid;
+ msg.cred.pag = xfs_get_pag(cnp->cn_cred);
+ error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
+ if (error == 0)
+ error = ((struct xfs_message_wakeup *) &msg)->error;
+
+ if (error == 0)
+ cache_purge(vp);
+
+#ifdef DIAGNOSTIC
+ /*
+ * sys_rmdir should not allow this to happen.
+ */
+ if (dvp == vp)
+ panic("xfs_rmdir dvp == vp");
+#endif
+
+ vput(vp);
+ vput(dvp);
+
+ if (error != 0 || (cnp->cn_flags & SAVESTART) == 0)
+ free (cnp->cn_pnbuf, M_NAMEI);
+
+ return error;
+}
+
+static int
+xfs_readdir(void *vap)
+{
+ struct vop_readdir_args *ap = vap;
+
+ int error = 0;
+
+ XFSDEB(XDEBVNOPS, ("xfs_readdir\n"));
+
+ error = xfs_data_valid(ap->a_vp, ap->a_cred, XFS_DATA_R);
+ if (error == 0) {
+ struct vnode *t = DATA_FROM_VNODE(ap->a_vp);
+
+ vn_lock(t, LK_EXCLUSIVE | LK_RETRY, ap->a_uio->uio_procp);
+ error = VOP_READ(t, ap->a_uio, 0, ap->a_cred);
+ VOP_UNLOCK(t, 0, ap->a_uio->uio_procp);
+ }
+ return error;
+}
+
+static int
+xfs_link(void *vap)
+{
+ struct vop_link_args *ap = vap;
+
+ struct xfs *xfsp = XFS_FROM_VNODE(ap->a_dvp);
+ struct xfs_node *xn = VNODE_TO_XNODE(ap->a_dvp);
+ struct xfs_node *xn2 = VNODE_TO_XNODE(ap->a_vp);
+ struct componentname *cnp = ap->a_cnp;
+ struct xfs_message_link msg;
+ int error = 0;
+
+ XFSDEB(XDEBVNOPS, ("xfs_link: (%s, %ld\n",
+ cnp->cn_nameptr,
+ cnp->cn_namelen));
+
+ msg.header.opcode = XFS_MSG_LINK;
+ msg.parent_handle = xn->handle;
+ msg.from_handle = xn2->handle;
+ strncpy(msg.name, cnp->cn_nameptr, 256);
+ msg.cred.uid = cnp->cn_cred->cr_uid;
+ msg.cred.pag = xfs_get_pag(cnp->cn_cred);
+
+ error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
+ if (error == 0)
+ error = ((struct xfs_message_wakeup *) & msg)->error;
+
+ if (error != 0 || (cnp->cn_flags & SAVESTART) == 0)
+ free (cnp->cn_pnbuf, M_NAMEI);
+
+ vput(ap->a_dvp);
+ return error;
+}
+
+static int
+xfs_symlink(void *vap)
+{
+ struct vop_symlink_args *ap = vap;
+
+ struct xfs *xfsp = XFS_FROM_VNODE(ap->a_dvp);
+ struct xfs_node *xn = VNODE_TO_XNODE(ap->a_dvp);
+ struct componentname *cnp = ap->a_cnp;
+ struct xfs_message_symlink msg;
+ int error = 0;
+
+ XFSDEB(XDEBVNOPS, ("xfs_symlink: (%s, %ld)\n",
+ cnp->cn_nameptr,
+ cnp->cn_namelen));
+
+ msg.header.opcode = XFS_MSG_SYMLINK;
+ msg.parent_handle = xn->handle;
+ strncpy(msg.name, cnp->cn_nameptr, 256);
+ vattr2xfs_attr(ap->a_vap, &msg.attr);
+ msg.cred.uid = cnp->cn_cred->cr_uid;
+ msg.cred.pag = xfs_get_pag(cnp->cn_cred);
+ strncpy (msg.contents, ap->a_target, sizeof(msg.contents));
+
+ error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
+ if (error == 0)
+ error = ((struct xfs_message_wakeup *) & msg)->error;
+
+ if (error == 0) {
+ error = do_actual_lookup(ap->a_dvp, cnp, ap->a_vpp);
+ }
+
+ if (error != 0 || (cnp->cn_flags & SAVESTART) == 0)
+ free (cnp->cn_pnbuf, M_NAMEI);
+
+ vput(ap->a_dvp);
+ return error;
+}
+
+static int
+xfs_readlink(void *vap)
+{
+ struct vop_readlink_args *ap = vap;
+
+ int error = 0;
+
+ XFSDEB(XDEBVNOPS, ("xfs_readlink\n"));
+
+ error = xfs_data_valid(ap->a_vp, ap->a_cred, XFS_DATA_R);
+ if (error == 0) {
+ struct vnode *t = DATA_FROM_VNODE(ap->a_vp);
+
+ vn_lock(t, LK_EXCLUSIVE | LK_RETRY, ap->a_uio->uio_procp);
+ error = VOP_READ(t, ap->a_uio, 0, ap->a_cred);
+ VOP_UNLOCK(t, 0, ap->a_uio->uio_procp);
+ }
+ return error;
+}
+
+static int
+xfs_inactive(void *vap)
+{
+ struct vop_inactive_args *ap = vap;
+ struct xfs_message_inactivenode msg;
+ struct xfs *xfsp = XFS_FROM_VNODE(ap->a_vp);
+ struct xfs_node *xn = VNODE_TO_XNODE(ap->a_vp);
+
+ XFSDEB(XDEBVNOPS, ("xfs_inactive, 0x%x\n", (int) ap->a_vp));
+
+ xn->tokens = 0;
+ msg.header.opcode = XFS_MSG_INACTIVENODE;
+ msg.handle = xn->handle;
+ msg.flag = XFS_NOREFS;
+ xfs_message_send(xfsp->fd, &msg.header, sizeof(msg));
+
+ VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
+
+ return 0;
+}
+
+static int
+xfs_reclaim(void *vap)
+{
+ struct vop_reclaim_args *ap = vap;
+
+ struct xfs_message_inactivenode msg;
+ struct xfs *xfsp = XFS_FROM_VNODE(ap->a_vp);
+ struct xfs_node *xn = VNODE_TO_XNODE(ap->a_vp);
+
+ XFSDEB(XDEBVNOPS, ("xfs_reclaim, 0x%x\n", (int) ap->a_vp));
+
+ msg.header.opcode = XFS_MSG_INACTIVENODE;
+ msg.handle = xn->handle;
+ msg.flag = XFS_NOREFS | XFS_DELETE;
+ xfs_message_send(xfsp->fd, &msg.header, sizeof(msg));
+
+ cache_purge(ap->a_vp);
+ free_xfs_node(xn);
+
+ return 0;
+}
+
+static int
+xfs_abortop (void *vap)
+{
+ struct vop_abortop_args *ap = vap;
+ struct componentname *cnp = ap->a_cnp;
+
+ XFSDEB(XDEBVNOPS, ("xfs_abortop\n"));
+
+ if ((cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) {
+ FREE(cnp->cn_pnbuf, M_NAMEI);
+ cnp->cn_pnbuf = NULL;
+ }
+ return 0;
+}
+
+static int
+xfs_notsupp(void *vap)
+{
+ return EOPNOTSUPP;
+}
+
+int (**xfs_vnodeop_p) __P((void *));
+
+
+static struct vnodeopv_entry_desc xfs_vnodeop_entries[] = {
+ {&vop_default_desc, vn_default_error},
+ {&vop_lookup_desc, xfs_lookup},
+ {&vop_open_desc, xfs_open},
+ {&vop_fsync_desc, xfs_fsync},
+ {&vop_close_desc, xfs_close},
+ {&vop_read_desc, xfs_read},
+ {&vop_write_desc, xfs_write},
+ {&vop_mmap_desc, xfs_notsupp},
+ {&vop_bmap_desc, xfs_notsupp},
+ {&vop_ioctl_desc, xfs_notsupp},
+ {&vop_select_desc, xfs_notsupp},
+ {&vop_getattr_desc, xfs_getattr},
+ {&vop_setattr_desc, xfs_setattr},
+ {&vop_access_desc, xfs_access},
+ {&vop_create_desc, xfs_create},
+ {&vop_remove_desc, xfs_remove},
+ {&vop_link_desc, xfs_link},
+ {&vop_rename_desc, xfs_rename},
+ {&vop_mkdir_desc, xfs_mkdir},
+ {&vop_rmdir_desc, xfs_rmdir},
+ {&vop_readdir_desc, xfs_readdir},
+ {&vop_symlink_desc, xfs_symlink},
+ {&vop_readlink_desc, xfs_readlink},
+ {&vop_inactive_desc, xfs_inactive},
+ {&vop_reclaim_desc, xfs_reclaim},
+ {&vop_lock_desc, vop_generic_lock},
+ {&vop_unlock_desc, vop_generic_unlock},
+ {&vop_abortop_desc, xfs_abortop},
+ {(struct vnodeop_desc *) NULL, (int (*) __P((void *))) NULL}
+};
+
+
+struct vnodeopv_desc xfs_vnodeop_opv_desc =
+{&xfs_vnodeop_p, xfs_vnodeop_entries};