From 2974eba0c37fd7574f74be5635fbec7be92d8d1e Mon Sep 17 00:00:00 2001 From: Artur Grabowski Date: Sun, 30 Aug 1998 16:47:23 +0000 Subject: xfs - a filesystem using a user-land cache manager. Designed for AFS. --- sys/xfs/xfs_common.c | 65 ++++ sys/xfs/xfs_dev.c | 774 +++++++++++++++++++++++++++++++++++++ sys/xfs/xfs_syscalls.c | 445 +++++++++++++++++++++ sys/xfs/xfs_vfsops.c | 441 +++++++++++++++++++++ sys/xfs/xfs_vnodeops.c | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 2725 insertions(+) create mode 100644 sys/xfs/xfs_common.c create mode 100644 sys/xfs/xfs_dev.c create mode 100644 sys/xfs/xfs_syscalls.c create mode 100644 sys/xfs/xfs_vfsops.c create mode 100644 sys/xfs/xfs_vnodeops.c 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 +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +RCSID("$KTH: xfs_syscalls.c,v 1.20 1998/07/19 21:18:30 art Exp $"); + +/* + * XFS system calls. + */ + +#include +#include +#include +#include +#include + +/* Misc syscalls */ +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include + +#include + +RCSID("$KTH: xfs_vfsops.c,v 1.22 1998/08/13 01:38:49 art Exp $"); + +/* + * XFS vfs operations. + */ + +#include +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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}; -- cgit v1.2.3