From 80c4685324a699659771f9ff1023578968316222 Mon Sep 17 00:00:00 2001 From: Thomas Veerman Date: Mon, 13 Feb 2012 15:28:04 +0000 Subject: [PATCH] VFS: replace VFS with AVFS --- docs/UPDATING | 7 + servers/Makefile | 12 +- servers/apfs/Makefile | 18 - servers/apfs/buf.h | 26 - servers/apfs/buffer.c | 103 -- servers/apfs/const.h | 42 - servers/apfs/dev_uds.c | 1177 -------------------- servers/apfs/fs.h | 31 - servers/apfs/glo.h | 29 - servers/apfs/inc.h | 41 - servers/apfs/inode.c | 338 ------ servers/apfs/inode.h | 39 - servers/apfs/link.c | 50 - servers/apfs/main.c | 197 ---- servers/apfs/misc.c | 12 - servers/apfs/open.c | 52 - servers/apfs/proto.h | 107 -- servers/apfs/read.c | 89 -- servers/apfs/stadir.c | 70 -- servers/apfs/super.c | 75 -- servers/apfs/table.c | 82 -- servers/apfs/uds.c | 1623 ---------------------------- servers/apfs/uds.h | 251 ----- servers/apfs/utility.c | 33 - servers/avfs/Makefile | 29 - servers/avfs/const.h | 50 - servers/avfs/device.c | 1193 -------------------- servers/avfs/dmap.c | 266 ----- servers/avfs/dmap.h | 28 - servers/avfs/exec.c | 721 ------------ servers/avfs/exec.h | 19 - servers/avfs/file.h | 48 - servers/avfs/filedes.c | 578 ---------- servers/avfs/fproc.h | 73 -- servers/avfs/fs.h | 51 - servers/avfs/fscall.c | 132 --- servers/avfs/gcov.c | 66 -- servers/avfs/glo.h | 57 - servers/avfs/link.c | 455 -------- servers/avfs/lock.c | 191 ---- servers/avfs/lock.h | 15 - servers/avfs/main.c | 990 ----------------- servers/avfs/misc.c | 663 ------------ servers/avfs/mount.c | 614 ----------- servers/avfs/open.c | 744 ------------- servers/avfs/param.h | 61 -- servers/avfs/path.c | 814 -------------- servers/avfs/pipe.c | 645 ----------- servers/avfs/protect.c | 276 ----- servers/avfs/proto.h | 390 ------- servers/avfs/read.c | 347 ------ servers/avfs/request.c | 1093 ------------------- servers/avfs/request.h | 41 - servers/avfs/select.c | 1071 ------------------ servers/avfs/select.h | 9 - servers/avfs/stadir.c | 287 ----- servers/avfs/table.c | 145 --- servers/avfs/time.c | 66 -- servers/avfs/utility.c | 153 --- servers/avfs/vmnt.c | 201 ---- servers/avfs/vmnt.h | 26 - servers/avfs/vnode.c | 389 ------- servers/avfs/vnode.h | 40 - servers/avfs/write.c | 19 - servers/is/Makefile | 6 - servers/is/dmp_fs.c | 23 +- servers/pfs/Makefile | 7 +- servers/pfs/buf.h | 2 +- servers/pfs/buffer.c | 36 +- servers/pfs/const.h | 3 +- servers/pfs/dev_uds.c | 333 +++--- servers/pfs/glo.h | 3 +- servers/pfs/inc.h | 1 - servers/pfs/inode.c | 39 +- servers/pfs/inode.h | 8 +- servers/pfs/link.c | 9 +- servers/pfs/main.c | 46 +- servers/pfs/misc.c | 2 - servers/{apfs => pfs}/mount.c | 0 servers/pfs/open.c | 5 +- servers/pfs/proto.h | 9 +- servers/pfs/read.c | 9 +- servers/pfs/stadir.c | 7 +- servers/pfs/super.c | 26 +- servers/pfs/table.c | 30 +- servers/pfs/uds.c | 138 ++- servers/pfs/uds.h | 27 +- servers/pfs/utility.c | 3 +- servers/procfs/Makefile | 4 - servers/procfs/inc.h | 12 +- servers/vfs/Makefile | 11 +- servers/{avfs => vfs}/comm.c | 0 servers/{avfs => vfs}/comm.h | 0 servers/vfs/const.h | 16 +- servers/{avfs => vfs}/coredump.c | 0 servers/vfs/device.c | 806 +++++++------- servers/vfs/dmap.c | 223 ++-- servers/vfs/dmap.h | 4 +- servers/vfs/elf_core_dump.c | 314 ------ servers/vfs/exec.c | 258 +++-- servers/vfs/file.h | 9 +- servers/vfs/filedes.c | 385 +++++-- servers/vfs/fproc.h | 65 +- servers/vfs/fs.h | 8 + servers/vfs/fscall.c | 76 +- servers/vfs/gcov.c | 85 +- servers/vfs/glo.h | 36 +- servers/{avfs => vfs}/job.h | 0 servers/vfs/link.c | 319 ++++-- servers/vfs/lock.c | 51 +- servers/vfs/lock.h | 5 +- servers/vfs/main.c | 1122 ++++++++++++------- servers/vfs/misc.c | 513 ++++----- servers/vfs/mount.c | 580 +++++----- servers/vfs/open.c | 480 +++++--- servers/vfs/param.h | 5 + servers/vfs/path.c | 678 ++++++++---- servers/{avfs => vfs}/path.h | 0 servers/vfs/pipe.c | 366 +++---- servers/vfs/protect.c | 118 +- servers/vfs/proto.h | 183 +++- servers/vfs/read.c | 167 ++- servers/vfs/request.c | 201 ++-- servers/vfs/request.h | 44 +- servers/{avfs => vfs}/scratchpad.h | 0 servers/vfs/select.c | 250 +++-- servers/vfs/select.h | 5 +- servers/vfs/stadir.c | 132 ++- servers/vfs/table.c | 18 +- servers/{avfs => vfs}/threads.h | 0 servers/vfs/time.c | 24 +- servers/{avfs => vfs}/tll.c | 0 servers/{avfs => vfs}/tll.h | 0 servers/vfs/utility.c | 41 +- servers/vfs/vmnt.c | 180 ++- servers/vfs/vmnt.h | 27 +- servers/vfs/vnode.c | 207 +++- servers/vfs/vnode.h | 11 +- servers/{avfs => vfs}/worker.c | 0 servers/vfs/write.c | 4 +- share/mk/bsd.own.mk | 2 - tools/Makefile | 11 +- 142 files changed, 5137 insertions(+), 21251 deletions(-) delete mode 100644 servers/apfs/Makefile delete mode 100644 servers/apfs/buf.h delete mode 100644 servers/apfs/buffer.c delete mode 100644 servers/apfs/const.h delete mode 100644 servers/apfs/dev_uds.c delete mode 100644 servers/apfs/fs.h delete mode 100644 servers/apfs/glo.h delete mode 100644 servers/apfs/inc.h delete mode 100644 servers/apfs/inode.c delete mode 100644 servers/apfs/inode.h delete mode 100644 servers/apfs/link.c delete mode 100644 servers/apfs/main.c delete mode 100644 servers/apfs/misc.c delete mode 100644 servers/apfs/open.c delete mode 100644 servers/apfs/proto.h delete mode 100644 servers/apfs/read.c delete mode 100644 servers/apfs/stadir.c delete mode 100644 servers/apfs/super.c delete mode 100644 servers/apfs/table.c delete mode 100644 servers/apfs/uds.c delete mode 100644 servers/apfs/uds.h delete mode 100644 servers/apfs/utility.c delete mode 100644 servers/avfs/Makefile delete mode 100644 servers/avfs/const.h delete mode 100644 servers/avfs/device.c delete mode 100644 servers/avfs/dmap.c delete mode 100644 servers/avfs/dmap.h delete mode 100644 servers/avfs/exec.c delete mode 100644 servers/avfs/exec.h delete mode 100644 servers/avfs/file.h delete mode 100644 servers/avfs/filedes.c delete mode 100644 servers/avfs/fproc.h delete mode 100644 servers/avfs/fs.h delete mode 100644 servers/avfs/fscall.c delete mode 100644 servers/avfs/gcov.c delete mode 100644 servers/avfs/glo.h delete mode 100644 servers/avfs/link.c delete mode 100644 servers/avfs/lock.c delete mode 100644 servers/avfs/lock.h delete mode 100644 servers/avfs/main.c delete mode 100644 servers/avfs/misc.c delete mode 100644 servers/avfs/mount.c delete mode 100644 servers/avfs/open.c delete mode 100644 servers/avfs/param.h delete mode 100644 servers/avfs/path.c delete mode 100644 servers/avfs/pipe.c delete mode 100644 servers/avfs/protect.c delete mode 100644 servers/avfs/proto.h delete mode 100644 servers/avfs/read.c delete mode 100644 servers/avfs/request.c delete mode 100644 servers/avfs/request.h delete mode 100644 servers/avfs/select.c delete mode 100644 servers/avfs/select.h delete mode 100644 servers/avfs/stadir.c delete mode 100644 servers/avfs/table.c delete mode 100644 servers/avfs/time.c delete mode 100644 servers/avfs/utility.c delete mode 100644 servers/avfs/vmnt.c delete mode 100644 servers/avfs/vmnt.h delete mode 100644 servers/avfs/vnode.c delete mode 100644 servers/avfs/vnode.h delete mode 100644 servers/avfs/write.c rename servers/{apfs => pfs}/mount.c (100%) rename servers/{avfs => vfs}/comm.c (100%) rename servers/{avfs => vfs}/comm.h (100%) rename servers/{avfs => vfs}/coredump.c (100%) delete mode 100644 servers/vfs/elf_core_dump.c rename servers/{avfs => vfs}/job.h (100%) rename servers/{avfs => vfs}/path.h (100%) rename servers/{avfs => vfs}/scratchpad.h (100%) rename servers/{avfs => vfs}/threads.h (100%) rename servers/{avfs => vfs}/tll.c (100%) rename servers/{avfs => vfs}/tll.h (100%) rename servers/{avfs => vfs}/worker.c (100%) diff --git a/docs/UPDATING b/docs/UPDATING index 53f5544ea..195edad46 100644 --- a/docs/UPDATING +++ b/docs/UPDATING @@ -1,3 +1,10 @@ +20120213 + Replace VFS with AVFS + + In case you were running AVFS by doing + 'BUILDAVFS=yes make clean world', you now have to do a + 'make clean cleandepend world' instead of a normal 'make clean world'. + 20120202 Rename installboot to installboot_minix. diff --git a/servers/Makefile b/servers/Makefile index 05a2bc6ce..f5e7140e7 100644 --- a/servers/Makefile +++ b/servers/Makefile @@ -3,22 +3,14 @@ .include -.if ${BUILDAVFS} == "yes" -VFS= "avfs" -PFS= "apfs" -.else -VFS= "vfs" -PFS= "pfs" -.endif - .if ${MKIMAGEONLY} == "yes" -SUBDIR= ds init mfs ${PFS} pm rs sched ${VFS} vm +SUBDIR= ds init mfs pfs pm rs sched vfs vm .else SUBDIR= ds ext2 hgfs inet init ipc is iso9660fs \ - mfs ${PFS} pm procfs rs sched ${VFS} vm devman + mfs pfs pm procfs rs sched vfs vm devman .endif diff --git a/servers/apfs/Makefile b/servers/apfs/Makefile deleted file mode 100644 index 18f5305f5..000000000 --- a/servers/apfs/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# Makefile for Pipe File System (PFS) -PROG= pfs -SRCS= open.c table.c inode.c main.c super.c link.c \ - buffer.c read.c misc.c mount.c utility.c stadir.c \ - uds.c dev_uds.c - -DPADD+= ${LIBSYS} -LDADD+= -lsys - -.if ${COMPILER_TYPE} == "gnu" -LDADD+= -lc -.endif - -MAN= - -BINDIR?= /usr/sbin - -.include diff --git a/servers/apfs/buf.h b/servers/apfs/buf.h deleted file mode 100644 index cd31f7e84..000000000 --- a/servers/apfs/buf.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef __PFS_BUF_H__ -#define __PFS_BUF_H__ - -/* Buffer (block) cache. - */ - -struct buf { - /* Data portion of the buffer. */ - char b_data[PIPE_BUF]; /* ordinary user data */ - - /* Header portion of the buffer. */ - struct buf *b_next; /* used to link all free bufs in a chain */ - struct buf *b_prev; /* used to link all free bufs the other way */ - ino_t b_num; /* inode number on minor device */ - dev_t b_dev; /* major | minor device where block resides */ - int b_bytes; /* Number of bytes allocated in bp */ - int b_count; /* Number of users of this buffer */ -}; - -/* A block is free if b_dev == NO_DEV. */ - - -EXTERN struct buf *front; /* points to least recently used free block */ -EXTERN struct buf *rear; /* points to most recently used free block */ - -#endif diff --git a/servers/apfs/buffer.c b/servers/apfs/buffer.c deleted file mode 100644 index a5c77b4a6..000000000 --- a/servers/apfs/buffer.c +++ /dev/null @@ -1,103 +0,0 @@ -#include "fs.h" -#include "buf.h" -#include "inode.h" -#include -#include -#include - -FORWARD _PROTOTYPE( struct buf *new_block, (dev_t dev, ino_t inum) ); - -/*===========================================================================* - * buf_pool * - *===========================================================================*/ -PUBLIC void buf_pool(void) -{ -/* Initialize the buffer pool. */ - - front = NULL; - rear = NULL; -} - - - -/*===========================================================================* - * get_block * - *===========================================================================*/ -PUBLIC struct buf *get_block(dev_t dev, ino_t inum) -{ - struct buf *bp = front; - - while(bp != NULL) { - if (bp->b_dev == dev && bp->b_num == inum) { - bp->b_count++; - return(bp); - } - bp = bp->b_next; - } - - /* Buffer was not found. Try to allocate a new one */ - return new_block(dev, inum); -} - - -/*===========================================================================* - * new_block * - *===========================================================================*/ -PRIVATE struct buf *new_block(dev_t dev, ino_t inum) -{ -/* Allocate a new buffer and add it to the double linked buffer list */ - struct buf *bp; - - bp = malloc(sizeof(struct buf)); - if (bp == NULL) { - err_code = ENOSPC; - return(NULL); - } - bp->b_num = inum; - bp->b_dev = dev; - bp->b_bytes = 0; - bp->b_count = 1; - memset(bp->b_data, 0 , PIPE_BUF); - - /* Add at the end of the buffer */ - if (front == NULL) { /* Empty list? */ - front = bp; - bp->b_prev = NULL; - } else { - rear->b_next = bp; - bp->b_prev = rear; - } - bp->b_next = NULL; - rear = bp; - - return(bp); -} - - -/*===========================================================================* - * put_block * - *===========================================================================*/ -PUBLIC void put_block(dev_t dev, ino_t inum) -{ - struct buf *bp; - - bp = get_block(dev, inum); - if (bp == NULL) return; /* We didn't find the block. Nothing to put. */ - - bp->b_count--; /* Compensate for above 'get_block'. */ - if (--bp->b_count > 0) return; - - /* Cut bp out of the loop */ - if (bp->b_prev == NULL) - front = bp->b_next; - else - bp->b_prev->b_next = bp->b_next; - - if (bp->b_next == NULL) - rear = bp->b_prev; - else - bp->b_next->b_prev = bp->b_prev; - - /* Buffer administration is done. Now it's safe to free up bp. */ - free(bp); -} diff --git a/servers/apfs/const.h b/servers/apfs/const.h deleted file mode 100644 index f89a239be..000000000 --- a/servers/apfs/const.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef __PFS_CONST_H__ -#define __PFS_CONST_H__ - -#define NR_INODES 256 /* # slots in "in core" inode table */ - -/* Size of descriptor table for unix domain sockets. This should be - * equal to the maximum number of minor devices (currently 256). - */ -#define NR_FDS 256 - -#define INODE_HASH_LOG2 7 /* 2 based logarithm of the inode hash size */ -#define INODE_HASH_SIZE ((unsigned long)1<USER_ENDPT); -#endif - - /* - * Find a slot in the descriptor table for the new descriptor. - * The index of the descriptor in the table will be returned. - * Subsequent calls to read/write/close/ioctl/etc will use this - * minor number. The minor number must be different from the - * the /dev/uds device's minor number (currently 0). - */ - - minor = -1; /* to trap error */ - - for (i = 1; i < NR_FDS; i++) { - if (uds_fd_table[i].state == UDS_FREE) { - minor = i; - break; - } - } - - if (minor == -1) { - - /* descriptor table full */ - uds_set_reply(dev_m_out, DEV_OPEN_REPL, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, ENFILE); - return ENFILE; - } - - /* - * We found a slot in uds_fd_table, now initialize the descriptor - */ - - /* mark this one as 'in use' so that it doesn't get assigned to - * another socket - */ - uds_fd_table[minor].state = UDS_INUSE; - - /* track the system call we are performing in case it gets cancelled */ - uds_fd_table[minor].call_nr = dev_m_in->m_type; - uds_fd_table[minor].ioctl = 0; - uds_fd_table[minor].syscall_done = 0; - - /* set the socket owner */ - uds_fd_table[minor].owner = dev_m_in->USER_ENDPT; - uds_fd_table[minor].endpoint = dev_m_in->USER_ENDPT; - - /* setup select(2) framework */ - uds_fd_table[minor].selecting = 0; - uds_fd_table[minor].select_proc = 0; - uds_fd_table[minor].sel_ops_in = 0; - uds_fd_table[minor].sel_ops_out = 0; - uds_fd_table[minor].status_updated = 0; - - /* initialize the data pointer (pos) to the start of the PIPE */ - uds_fd_table[minor].pos = 0; - - /* the PIPE is initially empty */ - uds_fd_table[minor].size = 0; - - /* the default for a new socket is to allow reading and writing. - * shutdown(2) will remove one or both flags. - */ - uds_fd_table[minor].mode = S_IRUSR|S_IWUSR; - - /* In libc socket(2) sets this to the actual value later with the - * NWIOSUDSTYPE ioctl(). - */ - uds_fd_table[minor].type = -1; - - /* Clear the backlog by setting each entry to -1 */ - for (i = 0; i < UDS_SOMAXCONN; i++) { - /* initially no connections are pending */ - uds_fd_table[minor].backlog[i] = -1; - } - - memset(&uds_fd_table[minor].ancillary_data, '\0', sizeof(struct - ancillary)); - for (i = 0; i < OPEN_MAX; i++) { - uds_fd_table[minor].ancillary_data.fds[i] = -1; - } - - /* default the size to UDS_SOMAXCONN */ - uds_fd_table[minor].backlog_size = UDS_SOMAXCONN; - - /* the socket isn't listening for incoming connections until - * listen(2) is called - */ - uds_fd_table[minor].listening = 0; - - /* initially the socket is not connected to a peer */ - uds_fd_table[minor].peer = -1; - - /* there isn't a child waiting to be accept(2)'d */ - uds_fd_table[minor].child = -1; - - /* initially the socket is not bound or listening on an address */ - memset(&(uds_fd_table[minor].addr), '\0', sizeof(struct sockaddr_un)); - memset(&(uds_fd_table[minor].source), '\0', sizeof(struct sockaddr_un)); - memset(&(uds_fd_table[minor].target), '\0', sizeof(struct sockaddr_un)); - - /* Initially the socket isn't suspended. */ - uds_fd_table[minor].suspended = UDS_NOT_SUSPENDED; - - /* and the socket doesn't have an I/O grant initially */ - uds_fd_table[minor].io_gr = (cp_grant_id_t) 0; - - /* since there is no I/O grant it effectively has no size either */ - uds_fd_table[minor].io_gr_size = 0; - - /* The process isn't suspended so we don't flag it as revivable */ - uds_fd_table[minor].ready_to_revive = 0; - - /* get the effective user id and effective group id from the endpoint */ - /* this is needed in the REQ_NEWNODE request to PFS. */ - rc = getnucred(uds_fd_table[minor].endpoint, &ucred); - if (rc == -1) { - /* roll back the changes we made to the descriptor */ - memset(&(uds_fd_table[minor]), '\0', sizeof(uds_fd_t)); - - /* likely error: invalid endpoint / proc doesn't exist */ - uds_set_reply(dev_m_out, DEV_OPEN_REPL, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, errno); - return errno; - } - - /* Prepare Request to the FS side of PFS */ - - fs_m_in.m_type = REQ_NEWNODE; - fs_m_in.REQ_MODE = I_NAMED_PIPE; - fs_m_in.REQ_DEV = NO_DEV; - fs_m_in.REQ_UID = ucred.uid; - fs_m_in.REQ_GID = ucred.gid; - - /* Request a new inode on the pipe file system */ - - rc = fs_newnode(&fs_m_in, &fs_m_out); - if (rc != OK) { - /* roll back the changes we made to the descriptor */ - memset(&(uds_fd_table[minor]), '\0', sizeof(uds_fd_t)); - - /* likely error: get_block() failed */ - uds_set_reply(dev_m_out, DEV_OPEN_REPL, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, rc); - return rc; - } - - /* Process the response */ - - uds_fd_table[minor].inode_nr = fs_m_out.RES_INODE_NR; - - /* prepare the reply */ - - uds_fd_table[minor].syscall_done = 1; - uds_set_reply(dev_m_out, DEV_OPEN_REPL, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, minor); - return minor; -} - -PUBLIC int uds_close(message *dev_m_in, message *dev_m_out) -{ - int minor; - message fs_m_in, fs_m_out; - int rc; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] uds_close() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); - printf("Endpoint: 0x%x\n", dev_m_in->USER_ENDPT); -#endif - - minor = uds_minor(dev_m_in); - - if (uds_fd_table[minor].state != UDS_INUSE) { - /* attempted to close a socket that hasn't been opened -- - * something is very wrong :( - */ - uds_set_reply(dev_m_out, DEV_CLOSE_REPL, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); - return EINVAL; - } - - /* no need to track the syscall in case of cancellation. close() is - * atomic and can't be cancelled. no need to update the endpoint here, - * we won't be needing it to kill the socket - */ - - /* if the socket is connected, disconnect it */ - if (uds_fd_table[minor].peer != -1) { - - /* set peer of this peer to -1 */ - uds_fd_table[uds_fd_table[minor].peer].peer = -1; - - /* error to pass to peer */ - uds_fd_table[uds_fd_table[minor].peer].err = ECONNRESET; - - /* if peer was blocked on I/O revive peer */ - if (uds_fd_table[uds_fd_table[minor].peer].suspended) { - int peer = uds_fd_table[minor].peer; - - uds_fd_table[peer].ready_to_revive = 1; - uds_unsuspend(dev_m_in->m_source, peer); - } - } - - if (uds_fd_table[minor].ancillary_data.nfiledes > 0) { - clear_fds(minor, &(uds_fd_table[minor].ancillary_data)); - } - - /* Prepare Request to the FS side of PFS */ - - fs_m_in.m_type = REQ_PUTNODE; - fs_m_in.REQ_INODE_NR = uds_fd_table[minor].inode_nr; - fs_m_in.REQ_COUNT = 1; - - /* set the socket back to its original UDS_FREE state */ - memset(&(uds_fd_table[minor]), '\0', sizeof(uds_fd_t)); - - /* Request the removal of the inode from the pipe file system */ - - rc = fs_putnode(&fs_m_in, &fs_m_out); - if (rc != OK) { - perror("fs_putnode"); - /* likely error: get_block() failed */ - return rc; - } - - uds_set_reply(dev_m_out, DEV_CLOSE_REPL, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, OK); - return OK; -} - -PUBLIC int uds_select(message *dev_m_in, message *dev_m_out) -{ - int i, bytes; - int minor; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] uds_select() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); - printf("Endpoint: 0x%x\n", dev_m_in->USER_ENDPT); -#endif - - minor = uds_minor(dev_m_in); - - if (uds_fd_table[minor].state != UDS_INUSE) { - - /* attempted to close a socket that hasn't been opened -- - * something is very wrong :( - */ - - uds_sel_reply(dev_m_out, DEV_SEL_REPL1, minor, EINVAL); - return EINVAL; - } - - /* setup select(2) framework */ - uds_fd_table[minor].selecting = 1; - uds_fd_table[minor].select_proc = dev_m_in->m_source; - - /* track the system call we are performing in case it gets cancelled */ - uds_fd_table[minor].call_nr = dev_m_in->m_type; - uds_fd_table[minor].ioctl = 0; - uds_fd_table[minor].syscall_done = 0; - - /* Can't update the process endpoint here, no info. */ - - uds_fd_table[minor].sel_ops_in = dev_m_in->USER_ENDPT; - uds_fd_table[minor].sel_ops_out = 0; - - /* check if there is data available to read */ - bytes = uds_perform_read(minor, dev_m_in->m_source, 1, 1); - if (bytes > 0) { - - /* there is data in the pipe for us to read */ - uds_fd_table[minor].sel_ops_out |= SEL_RD; - - } else if (uds_fd_table[minor].listening == 1) { - - /* check for pending connections */ - for (i = 0; i < uds_fd_table[minor].backlog_size; i++) { - if (uds_fd_table[minor].backlog[i] != -1) { - uds_fd_table[minor].sel_ops_out |= SEL_RD; - break; - } - } - } - - /* check if we can write without blocking */ - bytes = uds_perform_write(minor, dev_m_in->m_source, PIPE_BUF, 1); - if (bytes > 0) { - uds_fd_table[minor].sel_ops_out |= SEL_WR; - } - - uds_fd_table[minor].syscall_done = 1; - uds_sel_reply(dev_m_out, DEV_SEL_REPL1, minor, - uds_fd_table[minor].sel_ops_out); - - return uds_fd_table[minor].sel_ops_out; -} - -PRIVATE int uds_perform_read(int minor, endpoint_t m_source, - size_t size, int pretend) -{ - int rc; - message fs_m_in; - message fs_m_out; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] uds_perform_read() call_count=%d\n", minor, - ++call_count); -#endif - - /* skip reads and writes of 0 (or less!) bytes */ - if (size <= 0) { - return 0; - } - - /* check if we are allowed to read */ - if (!(uds_fd_table[minor].mode & S_IRUSR)) { - - /* socket is shutdown for reading */ - return EPIPE; - } - - if (uds_fd_table[minor].size == 0) { - - if (pretend) { - return SUSPEND; - } - - /* maybe a process is blocked waiting to write? if - * needed revive the writer - */ - if (uds_fd_table[minor].peer != -1 && - uds_fd_table[uds_fd_table[minor].peer].suspended) { - int peer = uds_fd_table[minor].peer; - - uds_fd_table[peer].ready_to_revive = 1; - uds_unsuspend(m_source, peer); - } - -#if DEBUG == 1 - printf("(uds) [%d] suspending read request\n", minor); -#endif - - /* Process is reading from an empty pipe, - * suspend it so some bytes can be written - */ - uds_fd_table[minor].suspended = UDS_SUSPENDED_READ; - return SUSPEND; - } - - if (pretend) { - - return (size > uds_fd_table[minor].size) ? - uds_fd_table[minor].size : size; - } - - - /* Prepare Request to the FS side of PFS */ - fs_m_in.m_type = REQ_READ; - fs_m_in.REQ_INODE_NR = uds_fd_table[minor].inode_nr; - fs_m_in.REQ_GRANT = uds_fd_table[minor].io_gr; - fs_m_in.REQ_SEEK_POS_HI = 0; - fs_m_in.REQ_SEEK_POS_LO = uds_fd_table[minor].pos; - fs_m_in.REQ_NBYTES = (size > uds_fd_table[minor].size) ? - uds_fd_table[minor].size : size; - - /* perform the read */ - rc = fs_readwrite(&fs_m_in, &fs_m_out); - if (rc != OK) { - perror("fs_readwrite"); - return rc; - } - - /* Process the response */ -#if DEBUG == 1 - printf("(uds) [%d] read complete\n", minor); -#endif - - /* move the position of the data pointer up to data we haven't - * read yet - */ - uds_fd_table[minor].pos += fs_m_out.RES_NBYTES; - - /* decrease the number of unread bytes */ - uds_fd_table[minor].size -= fs_m_out.RES_NBYTES; - - /* if we have 0 unread bytes, move the data pointer back to the - * start of the buffer - */ - if (uds_fd_table[minor].size == 0) { - uds_fd_table[minor].pos = 0; - } - - /* maybe a big write was waiting for us to read some data, if - * needed revive the writer - */ - if (uds_fd_table[minor].peer != -1 && - uds_fd_table[uds_fd_table[minor].peer].suspended) { - int peer = uds_fd_table[minor].peer; - - uds_fd_table[peer].ready_to_revive = 1; - uds_unsuspend(m_source, peer); - } - - /* see if peer is blocked on select() and a write is possible - * (from peer to minor) - */ - if (uds_fd_table[minor].peer != -1 && - uds_fd_table[uds_fd_table[minor].peer].selecting == 1 && - (uds_fd_table[minor].size + uds_fd_table[minor].pos + 1 - < PIPE_BUF)) { - - int peer = uds_fd_table[minor].peer; - - /* if the peer wants to know about write being possible - * and it doesn't know about it already, then let the peer know. - */ - if ((uds_fd_table[peer].sel_ops_in & SEL_WR) && - !(uds_fd_table[peer].sel_ops_out & SEL_WR)) { - - /* a write on peer is possible now */ - uds_fd_table[peer].sel_ops_out |= SEL_WR; - uds_fd_table[peer].status_updated = 1; - uds_unsuspend(m_source, peer); - } - } - - return fs_m_out.RES_NBYTES; /* return number of bytes read */ -} - -PRIVATE int uds_perform_write(int minor, endpoint_t m_source, - size_t size, int pretend) -{ - int rc, peer, i; - message fs_m_in; - message fs_m_out; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] uds_perform_write() call_count=%d\n", minor, - ++call_count); -#endif - - /* skip reads and writes of 0 (or less!) bytes */ - if (size <= 0) { - return 0; - } - - /* check if we are allowed to write */ - if (!(uds_fd_table[minor].mode & S_IWUSR)) { - - /* socket is shutdown for writing */ - return EPIPE; - } - - if (size > PIPE_BUF) { - - /* message is too big to ever write to the PIPE */ - return EMSGSIZE; - } - - if (uds_fd_table[minor].type == SOCK_STREAM || - uds_fd_table[minor].type == SOCK_SEQPACKET) { - - /* if we're writing with a connection oriented socket, - * then it needs a peer to write to - */ - if (uds_fd_table[minor].peer == -1) { - if (uds_fd_table[minor].err == ECONNRESET) { - - uds_fd_table[minor].err = 0; - return ECONNRESET; - } else { - return ENOTCONN; - } - } else { - - peer = uds_fd_table[minor].peer; - } - - } else /* uds_fd_table[minor].type == SOCK_DGRAM */ { - - peer = -1; - - /* locate the "peer" we want to write to */ - for (i = 0; i < NR_FDS; i++) { - - /* look for a SOCK_DGRAM socket that is bound on - * the target address - */ - if (uds_fd_table[i].type == SOCK_DGRAM && - uds_fd_table[i].addr.sun_family == AF_UNIX && - !strncmp(uds_fd_table[minor].target.sun_path, - uds_fd_table[i].addr.sun_path, UNIX_PATH_MAX)) { - - peer = i; - break; - } - } - - if (peer == -1) { - return ENOENT; - } - } - - /* check if write would overrun buffer. check if message - * boundry preserving types (SEQPACKET and DGRAM) wouldn't write - * to an empty buffer. check if connectionless sockets have a - * target to write to. - */ - if ((uds_fd_table[peer].pos+uds_fd_table[peer].size+size > PIPE_BUF) || - ((uds_fd_table[minor].type == SOCK_SEQPACKET || - uds_fd_table[minor].type == SOCK_DGRAM) && - uds_fd_table[peer].size > 0) || (peer == -1)) { - - if (pretend) { - return SUSPEND; - } - - /* if needed revive the reader */ - if (uds_fd_table[peer].suspended) { - uds_fd_table[peer].ready_to_revive = 1; - uds_unsuspend(m_source, peer); - } - -#if DEBUG == 1 - printf("(uds) [%d] suspending write request\n", minor); -#endif - - /* Process is reading from an empty pipe, - * suspend it so some bytes can be written - */ - uds_fd_table[minor].suspended = UDS_SUSPENDED_WRITE; - return SUSPEND; - } - - if (pretend) { - return size; - } - - /* Prepare Request to the FS side of PFS */ - fs_m_in.m_type = REQ_WRITE; - fs_m_in.REQ_INODE_NR = uds_fd_table[peer].inode_nr; - fs_m_in.REQ_GRANT = uds_fd_table[minor].io_gr; - fs_m_in.REQ_SEEK_POS_HI = 0; - fs_m_in.REQ_SEEK_POS_LO = uds_fd_table[peer].pos + - uds_fd_table[peer].size; - fs_m_in.REQ_NBYTES = size; - - /* Request the write */ - rc = fs_readwrite(&fs_m_in, &fs_m_out); - if (rc != OK) { - perror("fs_readwrite"); - return rc; - } - - /* Process the response */ -#if DEBUG == 1 - printf("(uds) [%d] write complete\n", minor); -#endif - /* increase the count of unread bytes */ - uds_fd_table[peer].size += fs_m_out.RES_NBYTES; - - - /* fill in the source address to be returned by recvfrom & recvmsg */ - if (uds_fd_table[minor].type == SOCK_DGRAM) { - memcpy(&uds_fd_table[peer].source, &uds_fd_table[minor].addr, - sizeof(struct sockaddr_un)); - } - - /* revive peer that was waiting for us to write */ - if (uds_fd_table[peer].suspended) { - uds_fd_table[peer].ready_to_revive = 1; - uds_unsuspend(m_source, peer); - } - - /* see if peer is blocked on select()*/ - if (uds_fd_table[peer].selecting == 1 && fs_m_out.RES_NBYTES > 0) { - - /* if the peer wants to know about data ready to read - * and it doesn't know about it already, then let the peer - * know we have data for it. - */ - if ((uds_fd_table[peer].sel_ops_in & SEL_RD) && - !(uds_fd_table[peer].sel_ops_out & SEL_RD)) { - - /* a read on peer is possible now */ - uds_fd_table[peer].sel_ops_out |= SEL_RD; - uds_fd_table[peer].status_updated = 1; - uds_unsuspend(m_source, peer); - } - } - - return fs_m_out.RES_NBYTES; /* return number of bytes written */ -} - -PUBLIC int uds_read(message *dev_m_in, message *dev_m_out) -{ - int bytes; - int minor; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] uds_read() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); - printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT, - dev_m_in->POSITION); -#endif - - minor = uds_minor(dev_m_in); - - if (uds_fd_table[minor].state != UDS_INUSE) { - - /* attempted to close a socket that hasn't been opened -- - * something is very wrong :( - */ - uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); - - return EINVAL; - } - - /* track the system call we are performing in case it gets cancelled */ - uds_fd_table[minor].call_nr = dev_m_in->m_type; - uds_fd_table[minor].ioctl = 0; - uds_fd_table[minor].syscall_done = 0; - - /* Update the process endpoint. */ - uds_fd_table[minor].endpoint = dev_m_in->USER_ENDPT; - - /* setup select(2) framework */ - uds_fd_table[minor].selecting = 0; - - /* save I/O Grant info */ - uds_fd_table[minor].io_gr = (cp_grant_id_t) dev_m_in->IO_GRANT; - uds_fd_table[minor].io_gr_size = dev_m_in->COUNT; - - bytes = uds_perform_read(minor, dev_m_in->m_source, - uds_fd_table[minor].io_gr_size, 0); - - uds_set_reply(dev_m_out, DEV_REVIVE, uds_fd_table[minor].endpoint, - uds_fd_table[minor].io_gr, bytes); - - return bytes; -} - -PUBLIC int uds_write(message *dev_m_in, message *dev_m_out) -{ - int bytes; - int minor; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] uds_write() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); - printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT, - dev_m_in->POSITION); -#endif - - minor = uds_minor(dev_m_in); - - if (uds_fd_table[minor].state != UDS_INUSE) { - - /* attempted to close a socket that hasn't been opened -- - * something is very wrong :( - */ - uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); - - return EINVAL; - } - - /* track the system call we are performing in case it gets cancelled */ - uds_fd_table[minor].call_nr = dev_m_in->m_type; - uds_fd_table[minor].ioctl = 0; - uds_fd_table[minor].syscall_done = 0; - - /* Update the process endpoint. */ - uds_fd_table[minor].endpoint = dev_m_in->USER_ENDPT; - - /* setup select(2) framework */ - uds_fd_table[minor].selecting = 0; - - /* save I/O Grant info */ - uds_fd_table[minor].io_gr = (cp_grant_id_t) dev_m_in->IO_GRANT; - uds_fd_table[minor].io_gr_size = dev_m_in->COUNT; - - bytes = uds_perform_write(minor, dev_m_in->m_source, - uds_fd_table[minor].io_gr_size, 0); - - uds_set_reply(dev_m_out, DEV_REVIVE, uds_fd_table[minor].endpoint, - uds_fd_table[minor].io_gr, bytes); - - return bytes; -} - -PUBLIC int uds_ioctl(message *dev_m_in, message *dev_m_out) -{ - int rc, minor; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] uds_ioctl() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); - printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT, - dev_m_in->POSITION); -#endif - - minor = uds_minor(dev_m_in); - - if (uds_fd_table[minor].state != UDS_INUSE) { - - /* attempted to close a socket that hasn't been opened -- - * something is very wrong :( - */ - uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); - - return EINVAL; - } - - /* track the system call we are performing in case it gets cancelled */ - uds_fd_table[minor].call_nr = dev_m_in->m_type; - uds_fd_table[minor].ioctl = dev_m_in->COUNT; - uds_fd_table[minor].syscall_done = 0; - - /* setup select(2) framework */ - uds_fd_table[minor].selecting = 0; - - /* update the owner endpoint - yes it's really stored in POSITION */ - uds_fd_table[minor].owner = dev_m_in->POSITION; - - switch (dev_m_in->COUNT) { /* Handle the ioctl(2) command */ - - case NWIOSUDSCONN: - - /* connect to a listening socket -- connect() */ - rc = do_connect(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSACCEPT: - - /* accept an incoming connection -- accept() */ - rc = do_accept(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSBLOG: - - /* set the backlog_size and put the socket into the - * listening state -- listen() - */ - rc = do_listen(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSTYPE: - - /* set the type for this socket (i.e. - * SOCK_STREAM, SOCK_DGRAM, etc) -- socket() - */ - rc = do_socket(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSADDR: - - /* set the address for this socket -- bind() */ - rc = do_bind(dev_m_in, dev_m_out); - - break; - - case NWIOGUDSADDR: - - /* get the address for this socket -- getsockname() */ - rc = do_getsockname(dev_m_in, dev_m_out); - - break; - - case NWIOGUDSPADDR: - - /* get the address for the peer -- getpeername() */ - rc = do_getpeername(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSSHUT: - - /* shutdown a socket for reading, writing, or - * both -- shutdown() - */ - rc = do_shutdown(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSPAIR: - - /* connect two sockets -- socketpair() */ - rc = do_socketpair(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSPAIROLD: - - /* connect two sockets -- socketpair() */ - rc = do_socketpair_old(dev_m_in, dev_m_out); - - break; - - case NWIOGUDSSOTYPE: - - /* get socket type -- getsockopt(SO_TYPE) */ - rc = do_getsockopt_sotype(dev_m_in, dev_m_out); - - break; - - case NWIOGUDSPEERCRED: - - /* get peer endpoint -- getsockopt(SO_PEERCRED) */ - rc = do_getsockopt_peercred(dev_m_in, dev_m_out); - - break; - - case NWIOGUDSPEERCREDOLD: - - /* get peer endpoint -- getsockopt(SO_PEERCRED) */ - rc = do_getsockopt_peercred_old(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSTADDR: - - /* set target address -- sendto() */ - rc = do_sendto(dev_m_in, dev_m_out); - - break; - - case NWIOGUDSFADDR: - - /* get from address -- recvfrom() */ - rc = do_recvfrom(dev_m_in, dev_m_out); - - break; - - case NWIOGUDSSNDBUF: - - /* get the send buffer size -- getsockopt(SO_SNDBUF) */ - rc = do_getsockopt_sndbuf(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSSNDBUF: - - /* set the send buffer size -- setsockopt(SO_SNDBUF) */ - rc = do_setsockopt_sndbuf(dev_m_in, dev_m_out); - - break; - - case NWIOGUDSRCVBUF: - - /* get the send buffer size -- getsockopt(SO_SNDBUF) */ - rc = do_getsockopt_rcvbuf(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSRCVBUF: - - /* set the send buffer size -- setsockopt(SO_SNDBUF) */ - rc = do_setsockopt_rcvbuf(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSCTRL: - - /* set the control data -- sendmsg() */ - rc = do_sendmsg(dev_m_in, dev_m_out); - - break; - - case NWIOGUDSCTRL: - - /* set the control data -- recvmsg() */ - rc = do_recvmsg(dev_m_in, dev_m_out); - - break; - - default: - - /* the IOCTL command is not valid for /dev/uds -- - * this happens a lot and is normal. a lot of - * libc functions determine the socket type with - * IOCTLs. Any not for us simply get a EBADIOCTL - * response. - */ - - rc = EBADIOCTL; - } - - if (rc != SUSPEND) - uds_fd_table[minor].syscall_done = 1; - - uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, rc); - - return rc; -} - -PUBLIC int uds_unsuspend(endpoint_t m_source, int minor) -{ - int r = OK, bytes; - message m_out; - uds_fd_t *fdp; - - fdp = &uds_fd_table[minor]; - - if (fdp->status_updated == 1) { - - /* clear the status_updated flag */ - fdp->status_updated = 0; - fdp->selecting = 0; - - /* prepare the response */ - uds_sel_reply(&m_out, DEV_SEL_REPL2, minor, fdp->sel_ops_out); - } else if (fdp->ready_to_revive == 1) { - - /* clear the ready to revive flag */ - fdp->ready_to_revive = 0; - - switch (fdp->suspended) { - - case UDS_SUSPENDED_READ: - - bytes = uds_perform_read(minor, m_source, - fdp->io_gr_size, 0); - - if (bytes == SUSPEND) { - r = SUSPEND; - break; - } - - fdp->suspended = UDS_NOT_SUSPENDED; - - uds_set_reply(&m_out, DEV_REVIVE, fdp->endpoint, - fdp->io_gr, bytes); - - break; - - case UDS_SUSPENDED_WRITE: - - bytes = uds_perform_write(minor, m_source, - fdp->io_gr_size, 0); - - if (bytes == SUSPEND) { - r = SUSPEND; - break; - } - - fdp->suspended = UDS_NOT_SUSPENDED; - - uds_set_reply(&m_out, DEV_REVIVE, fdp->endpoint, - fdp->io_gr, bytes); - - break; - - case UDS_SUSPENDED_CONNECT: - case UDS_SUSPENDED_ACCEPT: - - /* In both cases, the process - * that send the notify() - * already performed the connection. - * The only thing to do here is - * unblock. - */ - - fdp->suspended = UDS_NOT_SUSPENDED; - - uds_set_reply(&m_out, DEV_REVIVE, fdp->endpoint, - fdp->io_gr, OK); - - break; - - default: - return(OK); - } - - } - - if (r == OK) reply(m_source, &m_out); - return(r); -} - -PUBLIC int uds_cancel(message *dev_m_in, message *dev_m_out) -{ - int i, j; - int minor; - /* XXX: should become a noop? */ -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] uds_cancel() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); - printf("Endpoint: 0x%x\n", dev_m_in->USER_ENDPT); -#endif - - minor = uds_minor(dev_m_in); - - if (uds_fd_table[minor].state != UDS_INUSE) { - - /* attempted to close a socket that hasn't been opened -- - * something is very wrong :( - */ - uds_set_reply(dev_m_out, DEV_NO_STATUS, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); - - return EINVAL; - } - - /* Update the process endpoint. */ - uds_fd_table[minor].endpoint = dev_m_in->USER_ENDPT; - - /* setup select(2) framework */ - uds_fd_table[minor].selecting = 0; - - /* the system call was cancelled, so if the socket was suspended - * (which is likely the case), then it is not suspended anymore. - */ - uds_fd_table[minor].suspended = UDS_NOT_SUSPENDED; - - /* If there is a system call and it isn't complete, roll back */ - if (uds_fd_table[minor].call_nr && !uds_fd_table[minor].syscall_done) { - - - if (uds_fd_table[minor].call_nr == DEV_IOCTL_S) { - - switch (uds_fd_table[minor].ioctl) { - - case NWIOSUDSACCEPT: /* accept() */ - - /* partial accept() only changes - * uds_fd_table[minorparent].child - */ - - for (i = 0; i < NR_FDS; i++) { - if (uds_fd_table[i].child == - minor) { - - uds_fd_table[i].child = -1; - - } - } - - break; - - case NWIOSUDSCONN: /* connect() */ - - /* partial connect() sets addr - * and adds minor to server backlog - */ - - for (i = 0; i < NR_FDS; i++) { - - /* find a socket that is in - * use. - */ - if (uds_fd_table[i].state == - UDS_INUSE) { - - /* see if minor is in - * the backlog - */ - for (j = 0; j < uds_fd_table[i].backlog_size; j++) { - - if (uds_fd_table[i].backlog[j] == minor) { - - /* remove from backlog */ - uds_fd_table[i].backlog[j] = -1; - } - } - - } - } - - /* clear the address */ - memset(&(uds_fd_table[minor].addr), - '\0', - sizeof(struct sockaddr_un)); - - break; - - case NWIOSUDSTADDR: /* sendto() */ - case NWIOSUDSADDR: /* bind() */ - case NWIOGUDSADDR: /* getsockname() */ - case NWIOGUDSPADDR: /* getpeername() */ - case NWIOSUDSTYPE: /* socket() */ - case NWIOSUDSBLOG: /* listen() */ - case NWIOSUDSSHUT: /* shutdown() */ - case NWIOSUDSPAIR: /* socketpair() */ - case NWIOGUDSSOTYPE: /* SO_TYPE */ - case NWIOGUDSPEERCRED: /* SO_PEERCRED */ - default: - /* these are atomic, never suspend, - * and can't be cancelled once called - */ - break; - } - - } - - /* DEV_READ_S or DEV_WRITE_S don't need to do anything - * when cancelled. DEV_OPEN, DEV_REOPEN, DEV_SELECT, - * DEV_CLOSE are atomic, never suspend, and can't - * be cancelled once called. - */ - - uds_fd_table[minor].syscall_done = 1; - } - - - uds_set_reply(dev_m_out, DEV_NO_STATUS, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, EINTR); - - return EINTR; -} diff --git a/servers/apfs/fs.h b/servers/apfs/fs.h deleted file mode 100644 index 2bc006af3..000000000 --- a/servers/apfs/fs.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef __PFS_FS_H__ -#define __PFS_FS_H__ - -/* This is the master header for pfs. It includes some other files - * and defines the principal constants. - */ -#define _POSIX_SOURCE 1 /* tell headers to include POSIX stuff */ -#define _MINIX 1 /* tell headers to include MINIX stuff */ -#define _SYSTEM 1 /* tell headers that this is the kernel */ - -/* The following are so basic, all the *.c files get them automatically. */ -#include /* MUST be first */ -#include /* MUST be second */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "const.h" -#include "proto.h" -#include "glo.h" - -#endif diff --git a/servers/apfs/glo.h b/servers/apfs/glo.h deleted file mode 100644 index 175b4fc8e..000000000 --- a/servers/apfs/glo.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef __PFS_GLO_H__ -#define __PFS_GLO_H__ - -/* EXTERN should be extern except for the table file */ -#ifdef _TABLE -#undef EXTERN -#define EXTERN -#endif - -#include - -/* The following variables are used for returning results to the caller. */ -EXTERN int err_code; /* temporary storage for error number */ - -EXTERN _PROTOTYPE (int (*fs_call_vec[]), (message *fs_m_in, message *fs_m_out) ); /* fs call table */ -EXTERN _PROTOTYPE (int (*dev_call_vec[]), (message *fs_m_in, message *fs_m_out) ); /* dev call table */ - -EXTERN uid_t caller_uid; -EXTERN gid_t caller_gid; -EXTERN int req_nr; -EXTERN int SELF_E; -EXTERN int exitsignaled; -EXTERN int busy; -EXTERN int unmountdone; - -/* Inode map. */ -EXTERN bitchunk_t inodemap[FS_BITMAP_CHUNKS(NR_INODES)]; - -#endif diff --git a/servers/apfs/inc.h b/servers/apfs/inc.h deleted file mode 100644 index 4484e8038..000000000 --- a/servers/apfs/inc.h +++ /dev/null @@ -1,41 +0,0 @@ - -#define _SYSTEM 1 /* get OK and negative error codes */ -#define _MINIX 1 /* tell headers to include MINIX stuff */ - -#define VERBOSE 0 /* display diagnostics */ - -#ifdef __NBSD_LIBC -#include -#else -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "proto.h" diff --git a/servers/apfs/inode.c b/servers/apfs/inode.c deleted file mode 100644 index 98be69203..000000000 --- a/servers/apfs/inode.c +++ /dev/null @@ -1,338 +0,0 @@ -/* This file manages the inode table. There are procedures to allocate and - * deallocate inodes, acquire, erase, and release them, and read and write - * them from the disk. - * - * The entry points into this file are - * get_inode: search inode table for a given inode; if not there, - * read it - * put_inode: indicate that an inode is no longer needed in memory - * alloc_inode: allocate a new, unused inode - * wipe_inode: erase some fields of a newly allocated inode - * free_inode: mark an inode as available for a new file - * update_times: update atime, ctime, and mtime - * find_inode: retrieve pointer to inode in inode cache - * - */ - -#include "fs.h" -#include "buf.h" -#include "inode.h" -#include - -FORWARD _PROTOTYPE( void addhash_inode, (struct inode * const node) ); -FORWARD _PROTOTYPE( void unhash_inode, (struct inode * const node) ); - - -/*===========================================================================* - * fs_putnode * - *===========================================================================*/ -PUBLIC int fs_putnode(message *fs_m_in, message *fs_m_out) -{ -/* Find the inode specified by the request message and decrease its counter.*/ - - struct inode *rip; - int count; - dev_t dev; - ino_t inum; - - rip = find_inode( (ino_t) fs_m_in->REQ_INODE_NR); - - if(!rip) { - printf("%s:%d put_inode: inode #%ld dev: %d not found\n", __FILE__, - __LINE__, fs_m_in->REQ_INODE_NR, (dev_t) fs_m_in->REQ_DEV); - panic("fs_putnode failed"); - } - - count = fs_m_in->REQ_COUNT; - if (count <= 0) { - printf("%s:%d put_inode: bad value for count: %d\n", __FILE__, - __LINE__, count); - panic("fs_putnode failed"); - } else if(count > rip->i_count) { - printf("%s:%d put_inode: count too high: %d > %d\n", __FILE__, - __LINE__, count, rip->i_count); - panic("fs_putnode failed"); - } - - /* Decrease reference counter, but keep one reference; it will be consumed by - * put_inode(). */ - rip->i_count -= count - 1; - dev = rip->i_dev; - inum = rip->i_num; - put_inode(rip); - if (rip->i_count == 0) put_block(dev, inum); - return(OK); -} - - -/*===========================================================================* - * init_inode_cache * - *===========================================================================*/ -PUBLIC void init_inode_cache() -{ - struct inode *rip; - struct inodelist *rlp; - - /* init free/unused list */ - TAILQ_INIT(&unused_inodes); - - /* init hash lists */ - for (rlp = &hash_inodes[0]; rlp < &hash_inodes[INODE_HASH_SIZE]; ++rlp) - LIST_INIT(rlp); - - /* add free inodes to unused/free list */ - for (rip = &inode[0]; rip < &inode[NR_INODES]; ++rip) { - rip->i_num = NO_ENTRY; - TAILQ_INSERT_HEAD(&unused_inodes, rip, i_unused); - } - - /* Reserve the first inode (bit 0) to prevent it from being allocated later*/ - if (alloc_bit() != NO_BIT) printf("PFS could not reserve NO_BIT\n"); - busy = 0; /* This bit does not make the server 'in use/busy'. */ -} - - -/*===========================================================================* - * addhash_inode * - *===========================================================================*/ -PRIVATE void addhash_inode(struct inode * const node) -{ - int hashi = (int) (node->i_num & INODE_HASH_MASK); - - /* insert into hash table */ - LIST_INSERT_HEAD(&hash_inodes[hashi], node, i_hash); -} - - -/*===========================================================================* - * unhash_inode * - *===========================================================================*/ -PRIVATE void unhash_inode(struct inode * const node) -{ - /* remove from hash table */ - LIST_REMOVE(node, i_hash); -} - - -/*===========================================================================* - * get_inode * - *===========================================================================*/ -PUBLIC struct inode *get_inode( - dev_t dev, /* device on which inode resides */ - ino_t numb /* inode number */ -) -{ -/* Find the inode in the hash table. If it is not there, get a free inode - * load it from the disk if it's necessary and put on the hash list - */ - register struct inode *rip; - int hashi; - - hashi = (int) (numb & INODE_HASH_MASK); - - /* Search inode in the hash table */ - LIST_FOREACH(rip, &hash_inodes[hashi], i_hash) { - if (rip->i_num == numb && rip->i_dev == dev) { - /* If unused, remove it from the unused/free list */ - if (rip->i_count == 0) { - TAILQ_REMOVE(&unused_inodes, rip, i_unused); - } - ++rip->i_count; - - return(rip); - } - } - - /* Inode is not on the hash, get a free one */ - if (TAILQ_EMPTY(&unused_inodes)) { - err_code = ENFILE; - return(NULL); - } - rip = TAILQ_FIRST(&unused_inodes); - - /* If not free unhash it */ - if (rip->i_num != NO_ENTRY) unhash_inode(rip); - - /* Inode is not unused any more */ - TAILQ_REMOVE(&unused_inodes, rip, i_unused); - - /* Load the inode. */ - rip->i_dev = dev; - rip->i_num = numb; - rip->i_count = 1; - rip->i_update = 0; /* all the times are initially up-to-date */ - - /* Add to hash */ - addhash_inode(rip); - - - return(rip); -} - - -/*===========================================================================* - * find_inode * - *===========================================================================*/ -PUBLIC struct inode *find_inode(numb) -ino_t numb; /* inode number */ -{ -/* Find the inode specified by the inode and device number. - */ - struct inode *rip; - int hashi; - - hashi = (int) (numb & INODE_HASH_MASK); - - /* Search inode in the hash table */ - LIST_FOREACH(rip, &hash_inodes[hashi], i_hash) { - if (rip->i_count > 0 && rip->i_num == numb) { - return(rip); - } - } - - return(NULL); -} - - -/*===========================================================================* - * put_inode * - *===========================================================================*/ -PUBLIC void put_inode(rip) -struct inode *rip; /* pointer to inode to be released */ -{ -/* The caller is no longer using this inode. If no one else is using it either - * write it back to the disk immediately. If it has no links, truncate it and - * return it to the pool of available inodes. - */ - - if (rip == NULL) return; /* checking here is easier than in caller */ - - if (rip->i_count < 1) - panic("put_inode: i_count already below 1: %d", rip->i_count); - - if (--rip->i_count == 0) { /* i_count == 0 means no one is using it now */ - if (rip->i_nlinks == NO_LINK) { /* Are there links to this file? */ - /* no links, free the inode. */ - truncate_inode(rip, 0); /* return all the disk blocks */ - rip->i_mode = I_NOT_ALLOC; /* clear I_TYPE field */ - free_inode(rip); - } else { - truncate_inode(rip, (off_t) 0); - } - - if (rip->i_nlinks == NO_LINK) { - /* free, put at the front of the LRU list */ - unhash_inode(rip); - rip->i_num = NO_ENTRY; - rip->i_dev = NO_DEV; - rip->i_rdev = NO_DEV; - TAILQ_INSERT_HEAD(&unused_inodes, rip, i_unused); - } else { - /* unused, put at the back of the LRU (cache it) */ - TAILQ_INSERT_TAIL(&unused_inodes, rip, i_unused); - } - } -} - - -/*===========================================================================* - * alloc_inode * - *===========================================================================*/ -PUBLIC struct inode *alloc_inode(dev_t dev, mode_t bits) -{ -/* Allocate a free inode on 'dev', and return a pointer to it. */ - - register struct inode *rip; - bit_t b; - ino_t i_num; - int print_oos_msg = 1; - - b = alloc_bit(); - if (b == NO_BIT) { - err_code = ENOSPC; - if (print_oos_msg) - printf("PipeFS is out of inodes\n"); - print_oos_msg = 0; /* Don't repeat message */ - return(NULL); - } - i_num = (ino_t) b; - print_oos_msg = 1; - - - /* Try to acquire a slot in the inode table. */ - if ((rip = get_inode(dev, i_num)) == NULL) { - /* No inode table slots available. Free the inode if just allocated.*/ - if (dev == NO_DEV) free_bit(b); - } else { - /* An inode slot is available. */ - - rip->i_mode = bits; /* set up RWX bits */ - rip->i_nlinks = NO_LINK; /* initial no links */ - rip->i_uid = caller_uid; /* file's uid is owner's */ - rip->i_gid = caller_gid; /* ditto group id */ - - /* Fields not cleared already are cleared in wipe_inode(). They have - * been put there because truncate() needs to clear the same fields if - * the file happens to be open while being truncated. It saves space - * not to repeat the code twice. - */ - wipe_inode(rip); - } - - return(rip); -} - - -/*===========================================================================* - * wipe_inode * - *===========================================================================*/ -PUBLIC void wipe_inode(rip) -struct inode *rip; /* the inode to be erased */ -{ -/* Erase some fields in the inode. This function is called from alloc_inode() - * when a new inode is to be allocated, and from truncate(), when an existing - * inode is to be truncated. - */ - - rip->i_size = 0; - rip->i_update = ATIME | CTIME | MTIME; /* update all times later */ -} - - -/*===========================================================================* - * free_inode * - *===========================================================================*/ -PUBLIC void free_inode(rip) -struct inode *rip; -{ -/* Return an inode to the pool of unallocated inodes. */ - - bit_t b; - - if (rip->i_num <= (ino_t) 0 || rip->i_num >= (ino_t) NR_INODES) return; - b = (bit_t) rip->i_num; - free_bit(b); -} - - -/*===========================================================================* - * update_times * - *===========================================================================*/ -PUBLIC void update_times(rip) -struct inode *rip; /* pointer to inode to be read/written */ -{ -/* Various system calls are required by the standard to update atime, ctime, - * or mtime. Since updating a time requires sending a message to the clock - * task--an expensive business--the times are marked for update by setting - * bits in i_update. When a stat, fstat, or sync is done, or an inode is - * released, update_times() may be called to actually fill in the times. - */ - - time_t cur_time; - - cur_time = clock_time(); - if (rip->i_update & ATIME) rip->i_atime = cur_time; - if (rip->i_update & CTIME) rip->i_ctime = cur_time; - if (rip->i_update & MTIME) rip->i_mtime = cur_time; - rip->i_update = 0; /* they are all up-to-date now */ -} diff --git a/servers/apfs/inode.h b/servers/apfs/inode.h deleted file mode 100644 index 19e582593..000000000 --- a/servers/apfs/inode.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef __PFS_INODE_H__ -#define __PFS_INODE_H__ - -/* Inode table. This table holds inodes that are currently in use. - */ - -#include - -EXTERN struct inode { - mode_t i_mode; /* file type, protection, etc. */ - nlink_t i_nlinks; /* how many links to this file */ - uid_t i_uid; /* user id of the file's owner */ - gid_t i_gid; /* group number */ - off_t i_size; /* current file size in bytes */ - time_t i_atime; /* time of last access (V2 only) */ - time_t i_mtime; /* when was file data last changed */ - time_t i_ctime; /* when was inode itself changed (V2 only)*/ - - /* The following items are not present on the disk. */ - dev_t i_dev; /* which device is the inode on */ - dev_t i_rdev; /* which special device is the inode on */ - ino_t i_num; /* inode number on its (minor) device */ - int i_count; /* # times inode used; 0 means slot is free */ - char i_update; /* the ATIME, CTIME, and MTIME bits are here */ - - LIST_ENTRY(inode) i_hash; /* hash list */ - TAILQ_ENTRY(inode) i_unused; /* free and unused list */ - - -} inode[NR_INODES]; - -/* list of unused/free inodes */ -EXTERN TAILQ_HEAD(unused_inodes_t, inode) unused_inodes; - -/* inode hashtable */ -EXTERN LIST_HEAD(inodelist, inode) hash_inodes[INODE_HASH_SIZE]; - - -#endif diff --git a/servers/apfs/link.c b/servers/apfs/link.c deleted file mode 100644 index 4ec064ef9..000000000 --- a/servers/apfs/link.c +++ /dev/null @@ -1,50 +0,0 @@ -#include "fs.h" -#include "buf.h" -#include "inode.h" -#include - -/*===========================================================================* - * fs_ftrunc * - *===========================================================================*/ -PUBLIC int fs_ftrunc(message *fs_m_in, message *fs_m_out) -{ - struct inode *rip; - off_t start, end; - ino_t inumb; - - inumb = (ino_t) fs_m_in->REQ_INODE_NR; - - if( (rip = find_inode(inumb)) == NULL) return(EINVAL); - - start = fs_m_in->REQ_TRC_START_LO; - end = fs_m_in->REQ_TRC_END_LO; - - return truncate_inode(rip, start); -} - - -/*===========================================================================* - * truncate_inode * - *===========================================================================*/ -PUBLIC int truncate_inode(rip, newsize) -register struct inode *rip; /* pointer to inode to be truncated */ -off_t newsize; /* inode must become this size */ -{ -/* Set inode to a certain size, freeing any zones no longer referenced - * and updating the size in the inode. If the inode is extended, the - * extra space is a hole that reads as zeroes. - * - * Nothing special has to happen to file pointers if inode is opened in - * O_APPEND mode, as this is different per fd and is checked when - * writing is done. - */ - - /* Pipes can shrink, so adjust size to make sure all zones are removed. */ - if(newsize != 0) return(EINVAL); /* Only truncate pipes to 0. */ - rip->i_size = newsize; - - /* Next correct the inode size. */ - wipe_inode(rip); /* Pipes can only be truncated to 0. */ - - return(OK); -} diff --git a/servers/apfs/main.c b/servers/apfs/main.c deleted file mode 100644 index f4f20f8dd..000000000 --- a/servers/apfs/main.c +++ /dev/null @@ -1,197 +0,0 @@ -#include "fs.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "buf.h" -#include "inode.h" -#include "uds.h" - -FORWARD _PROTOTYPE(void get_work, (message *m_in) ); - -/* SEF functions and variables. */ -FORWARD _PROTOTYPE( void sef_local_startup, (void) ); -FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) ); -FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) ); - -/*===========================================================================* - * main * - *===========================================================================*/ -PUBLIC int main(int argc, char *argv[]) -{ -/* This is the main routine of this service. The main loop consists of - * three major activities: getting new work, processing the work, and - * sending the reply. The loop never terminates, unless a panic occurs. - */ - int ind, do_reply, transid; - message pfs_m_in; - message pfs_m_out; - - /* SEF local startup. */ - env_setargs(argc, argv); - sef_local_startup(); - - while(!unmountdone || !exitsignaled) { - endpoint_t src; - - do_reply = 1; - /* Wait for request message. */ - get_work(&pfs_m_in); - - transid = TRNS_GET_ID(pfs_m_in.m_type); - pfs_m_in.m_type = TRNS_DEL_ID(pfs_m_in.m_type); - if (pfs_m_in.m_type == 0) { - assert(!IS_VFS_FS_TRANSID(transid)); - pfs_m_in.m_type = transid; - transid = 0; - } else - assert(IS_VFS_FS_TRANSID(transid) || transid == 0); - - src = pfs_m_in.m_source; - caller_uid = INVAL_UID; /* To trap errors */ - caller_gid = INVAL_GID; - req_nr = pfs_m_in.m_type; - - if (IS_DEV_RQ(req_nr)) { - ind = req_nr - DEV_RQ_BASE; - if (ind < 0 || ind >= DEV_CALL_VEC_SIZE) { - printf("pfs: bad DEV request %d\n", req_nr); - pfs_m_out.m_type = EINVAL; - } else { - int result; - result = (*dev_call_vec[ind])(&pfs_m_in, &pfs_m_out); - if (pfs_m_out.REP_STATUS == SUSPEND || - result == SUSPEND) { - /* Nothing to tell, so not replying */ - do_reply = 0; - } - } - } else if (IS_VFS_RQ(req_nr)) { - ind = req_nr - VFS_BASE; - if (ind < 0 || ind >= FS_CALL_VEC_SIZE) { - printf("pfs: bad FS request %d\n", req_nr); - pfs_m_out.m_type = EINVAL; - } else { - pfs_m_out.m_type = - (*fs_call_vec[ind])(&pfs_m_in, &pfs_m_out); - } - } else { - printf("pfs: bad request %d\n", req_nr); - pfs_m_out.m_type = EINVAL; - } - - if (do_reply) { - if (IS_VFS_RQ(req_nr) && IS_VFS_FS_TRANSID(transid)) { - pfs_m_out.m_type = TRNS_ADD_ID(pfs_m_out.m_type, - transid); - } - reply(src, &pfs_m_out); - } - } - return(OK); -} - -/*===========================================================================* - * sef_local_startup * - *===========================================================================*/ -PRIVATE void sef_local_startup() -{ - /* Register init callbacks. */ - sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fail); - - /* No live update support for now. */ - - /* Register signal callbacks. */ - sef_setcb_signal_handler(sef_cb_signal_handler); - - /* Let SEF perform startup. */ - sef_startup(); -} - -/*===========================================================================* - * sef_cb_init_fresh * - *===========================================================================*/ -PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) -{ -/* Initialize the pipe file server. */ - int i; - struct passwd *pw; - - /* Initialize main loop parameters. */ - exitsignaled = 0; /* No exit request seen yet. */ - busy = 0; /* Server is not 'busy' (i.e., inodes in use). */ - - /* Init inode table */ - for (i = 0; i < NR_INODES; ++i) { - inode[i].i_count = 0; - } - - init_inode_cache(); - uds_init(); - buf_pool(); - - - /* Drop root privileges */ - if ((pw = getpwnam(SERVICE_LOGIN)) == NULL) { - printf("PFS: unable to retrieve uid of SERVICE_LOGIN, " - "still running as root"); - } else if (setuid(pw->pw_uid) != 0) { - panic("unable to drop privileges"); - } - - SELF_E = getprocnr(); - - return(OK); -} - -/*===========================================================================* - * sef_cb_signal_handler * - *===========================================================================*/ -PRIVATE void sef_cb_signal_handler(int signo) -{ - /* Only check for termination signal, ignore anything else. */ - if (signo != SIGTERM) return; - - - exitsignaled = 1; -} - -/*===========================================================================* - * get_work * - *===========================================================================*/ -PRIVATE void get_work(m_in) -message *m_in; /* pointer to message */ -{ - int r, srcok = 0, status; - endpoint_t src; - - do { - /* wait for a message */ - if ((r = sef_receive_status(ANY, m_in, &status)) != OK) - panic("sef_receive_status failed: %d", r); - src = m_in->m_source; - - if(src == VFS_PROC_NR) { - srcok = 1; /* Normal FS request. */ - } else - printf("PFS: unexpected source %d\n", src); - } while(!srcok); -} - - -/*===========================================================================* - * reply * - *===========================================================================*/ -PUBLIC void reply(who, m_out) -endpoint_t who; -message *m_out; /* report result */ -{ - if (OK != send(who, m_out)) /* send the message */ - printf("PFS(%d) was unable to send reply\n", SELF_E); -} diff --git a/servers/apfs/misc.c b/servers/apfs/misc.c deleted file mode 100644 index 2f8e3010d..000000000 --- a/servers/apfs/misc.c +++ /dev/null @@ -1,12 +0,0 @@ -#include "fs.h" - - -/*===========================================================================* - * fs_sync * - *===========================================================================*/ -PUBLIC int fs_sync(message *fs_m_in, message *fs_m_out) -{ -/* Perform the sync() system call. No-op on this FS. */ - - return(OK); /* sync() can't fail */ -} diff --git a/servers/apfs/open.c b/servers/apfs/open.c deleted file mode 100644 index a7e275757..000000000 --- a/servers/apfs/open.c +++ /dev/null @@ -1,52 +0,0 @@ -#include "fs.h" -#include -#include "buf.h" -#include "inode.h" -#include - - -/*===========================================================================* - * fs_newnode * - *===========================================================================*/ -PUBLIC int fs_newnode(message *fs_m_in, message *fs_m_out) -{ - register int r = OK; - mode_t bits; - struct inode *rip; - dev_t dev; - - caller_uid = (uid_t) fs_m_in->REQ_UID; - caller_gid = (gid_t) fs_m_in->REQ_GID; - bits = (mode_t) fs_m_in->REQ_MODE; - dev = (dev_t) fs_m_in->REQ_DEV; - - /* Try to allocate the inode */ - if( (rip = alloc_inode(dev, bits) ) == NULL) return(err_code); - - switch (bits & S_IFMT) { - case S_IFBLK: - case S_IFCHR: - rip->i_rdev = dev; /* Major/minor dev numbers */ - break; - case S_IFIFO: - if ((get_block(dev, rip->i_num)) == NULL) - r = EIO; - break; - default: - r = EIO; /* Unsupported file type */ - } - - if (r != OK) { - free_inode(rip); - } else { - /* Fill in the fields of the response message */ - fs_m_out->RES_INODE_NR = rip->i_num; - fs_m_out->RES_MODE = rip->i_mode; - fs_m_out->RES_FILE_SIZE_LO = rip->i_size; - fs_m_out->RES_UID = rip->i_uid; - fs_m_out->RES_GID = rip->i_gid; - fs_m_out->RES_DEV = dev; - } - - return(r); -} diff --git a/servers/apfs/proto.h b/servers/apfs/proto.h deleted file mode 100644 index 210e9d1d4..000000000 --- a/servers/apfs/proto.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef __PFS_PROTO_H__ -#define __PFS_PROTO_H__ - -/* Function prototypes. */ - -/* Structs used in prototypes must be declared as such first. */ -struct buf; -struct inode; -struct sockaddr_un; -struct ancillary; - -/* buffer.c */ -_PROTOTYPE( struct buf *get_block, (dev_t dev, ino_t inum) ); -_PROTOTYPE( void put_block, (dev_t dev, ino_t inum) ); - -/* cache.c */ -_PROTOTYPE( void buf_pool, (void) ); - -/* inode.c */ -_PROTOTYPE( struct inode *alloc_inode, (dev_t dev, mode_t mode) ); -_PROTOTYPE( void dup_inode, (struct inode *ip) ); -_PROTOTYPE( struct inode *find_inode, (ino_t numb) ); -_PROTOTYPE( void free_inode, (struct inode *rip) ); -_PROTOTYPE( int fs_putnode, (message *fs_m_in, message *fs_m_out) ); -_PROTOTYPE( void init_inode_cache, (void) ); -_PROTOTYPE( struct inode *get_inode, (dev_t dev, ino_t numb) ); -_PROTOTYPE( void put_inode, (struct inode *rip) ); -_PROTOTYPE( void update_times, (struct inode *rip) ); -_PROTOTYPE( void wipe_inode, (struct inode *rip) ); - -/* link.c */ -_PROTOTYPE( int fs_ftrunc, (message *fs_m_in, message *fs_m_out) ); -_PROTOTYPE( int truncate_inode, (struct inode *rip, off_t newsize) ); - - -/* main.c */ -_PROTOTYPE( void reply, (endpoint_t who, message *m_out) ); - -/* misc.c */ -_PROTOTYPE( int fs_sync, (message *fs_m_in, message *fs_m_out) ); - -/* mount.c */ -_PROTOTYPE( int fs_unmount, (message *fs_m_in, message *fs_m_out) ); - -/* open.c */ -_PROTOTYPE( int fs_newnode, (message *fs_m_in, message *fs_m_out) ); - -/* read.c */ -_PROTOTYPE( int fs_readwrite, (message *fs_m_in, message *fs_m_out) ); - -/* utility.c */ -_PROTOTYPE( time_t clock_time, (void) ); -_PROTOTYPE( int no_sys, (message *pfs_m_in, message *pfs_m_out) ); - -/* stadir.c */ -_PROTOTYPE( int fs_stat, (message *fs_m_in, message *fs_m_out) ); - -/* super.c */ -_PROTOTYPE( bit_t alloc_bit, (void) ); -_PROTOTYPE( void free_bit, (bit_t bit_returned) ); - -/* dev_uds.c */ -_PROTOTYPE( int uds_open, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int uds_close, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int uds_read, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int uds_write, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int uds_ioctl, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int uds_select, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int uds_unsuspend, (endpoint_t m_source, int minor) ); -_PROTOTYPE( int uds_cancel, (message *dev_m_in, message *dev_m_out) ); - -/* uds.c */ -_PROTOTYPE( void uds_init, (void) ); -_PROTOTYPE( int do_accept, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int do_connect, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int do_listen, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int do_socket, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int do_bind, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int do_getsockname, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int do_getpeername, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int do_shutdown, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int do_socketpair, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int do_socketpair_old, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int do_getsockopt_sotype, - (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int do_getsockopt_peercred, - (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int do_getsockopt_peercred_old, - (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int do_getsockopt_sndbuf, - (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int do_setsockopt_sndbuf, - (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int do_getsockopt_rcvbuf, - (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int do_setsockopt_rcvbuf, - (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int do_sendto, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int do_recvfrom, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int do_sendmsg, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int do_recvmsg, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int perform_connection, - (message *dev_m_in, message *dev_m_out, - struct sockaddr_un *addr, int minorx, - int minory) ); -_PROTOTYPE( int clear_fds, (int minor, struct ancillary *data) ); -#endif diff --git a/servers/apfs/read.c b/servers/apfs/read.c deleted file mode 100644 index b4f06b846..000000000 --- a/servers/apfs/read.c +++ /dev/null @@ -1,89 +0,0 @@ -#include "fs.h" -#include "buf.h" -#include -#include "inode.h" - - -/*===========================================================================* - * fs_readwrite * - *===========================================================================*/ -PUBLIC int fs_readwrite(message *fs_m_in, message *fs_m_out) -{ - int r, rw_flag; - struct buf *bp; - cp_grant_id_t gid; - off_t position, f_size; - unsigned int nrbytes, cum_io; - mode_t mode_word; - struct inode *rip; - ino_t inumb; - - r = OK; - cum_io = 0; - inumb = (ino_t) fs_m_in->REQ_INODE_NR; - - /* Find the inode referred */ - if ((rip = find_inode(inumb)) == NULL) return(EINVAL); - - mode_word = rip->i_mode & I_TYPE; - if (mode_word != I_NAMED_PIPE) return(EIO); - f_size = rip->i_size; - - /* Get the values from the request message */ - rw_flag = (fs_m_in->m_type == REQ_READ ? READING : WRITING); - gid = (cp_grant_id_t) fs_m_in->REQ_GRANT; - position = fs_m_in->REQ_SEEK_POS_LO; - nrbytes = (unsigned) fs_m_in->REQ_NBYTES; - - /* We can't read beyond the max file position */ - if (nrbytes > MAX_FILE_POS) return(EFBIG); - - if (rw_flag == WRITING) { - /* Check in advance to see if file will grow too big. */ - /* Casting nrbytes to signed is safe, because it's guaranteed not to - be beyond max signed value (i.e., MAX_FILE_POS). */ - if (position > PIPE_BUF - (signed) nrbytes) return(EFBIG); - } - - /* Mark inode in use */ - if ((get_inode(rip->i_dev, rip->i_num)) == NULL) return(err_code); - if ((bp = get_block(rip->i_dev, rip->i_num)) == NULL) return(err_code); - - if (rw_flag == READING) { - /* Copy a chunk from the block buffer to user space. */ - r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) 0, - (vir_bytes) (bp->b_data+position), (size_t) nrbytes, D); - } else { - /* Copy a chunk from user space to the block buffer. */ - r = sys_safecopyfrom(VFS_PROC_NR, gid, (vir_bytes) 0, - (vir_bytes) (bp->b_data+position), (size_t) nrbytes, D); - } - - if (r == OK) { - position += (signed) nrbytes; /* Update position */ - cum_io += nrbytes; - } - - fs_m_out->RES_SEEK_POS_LO = position; /* It might change later and the VFS - has to know this value */ - - /* On write, update file size and access time. */ - if (rw_flag == WRITING) { - if (position > f_size) rip->i_size = position; - } else { - if(position >= rip->i_size) { - /* All data in the pipe is read, so reset pipe pointers */ - rip->i_size = 0; /* no data left */ - position = 0; /* reset reader(s) */ - } - } - - bp->b_bytes = position; - if (rw_flag == READING) rip->i_update |= ATIME; - if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME; - fs_m_out->RES_NBYTES = (size_t) cum_io; - put_inode(rip); - put_block(rip->i_dev, rip->i_num); - - return(r); -} diff --git a/servers/apfs/stadir.c b/servers/apfs/stadir.c deleted file mode 100644 index 7a49caff5..000000000 --- a/servers/apfs/stadir.c +++ /dev/null @@ -1,70 +0,0 @@ -#include "fs.h" -#include "inode.h" -#include -#include - - -/*===========================================================================* - * stat_inode * - *===========================================================================*/ -PRIVATE int stat_inode( - register struct inode *rip, /* pointer to inode to stat */ - endpoint_t who_e, /* Caller endpoint */ - cp_grant_id_t gid /* grant for the stat buf */ -) -{ -/* Common code for stat and fstat system calls. */ - mode_t type; - struct stat statbuf; - u32_t blocks; /* The unit of this is 512 */ - int r, s; - - type = rip->i_mode & I_TYPE; - s = (type == I_CHAR_SPECIAL || type == I_BLOCK_SPECIAL); - - /* Update the atime, ctime, and mtime fields in the inode, if need be. */ - if (rip->i_update) update_times(rip); - - blocks = rip->i_size / S_BLKSIZE; - if (rip->i_size % S_BLKSIZE != 0) - blocks += 1; - - memset(&statbuf, 0, sizeof(struct stat)); - - statbuf.st_dev = rip->i_dev; - statbuf.st_ino = rip->i_num; - statbuf.st_mode = rip->i_mode; - statbuf.st_nlink = rip->i_nlinks; - statbuf.st_uid = rip->i_uid; - statbuf.st_gid = (short int) rip->i_gid; - statbuf.st_rdev = (dev_t) (s ? rip->i_rdev : NO_DEV); - statbuf.st_size = rip->i_size; - if (!s) statbuf.st_mode &= ~I_REGULAR;/* wipe out I_REGULAR bit for pipes */ - statbuf.st_atime = rip->i_atime; - statbuf.st_mtime = rip->i_mtime; - statbuf.st_ctime = rip->i_ctime; - statbuf.st_blksize = PIPE_BUF; - statbuf.st_blocks = blocks; - - /* Copy the struct to user space. */ - r = sys_safecopyto(who_e, gid, (vir_bytes) 0, (vir_bytes) &statbuf, - (size_t) sizeof(statbuf), D); - - return(r); -} - - -/*===========================================================================* - * fs_stat * - *===========================================================================*/ -PUBLIC int fs_stat(message *fs_m_in, message *fs_m_out) -{ - register int r; /* return value */ - register struct inode *rip; /* target inode */ - - if( (rip = find_inode(fs_m_in->REQ_INODE_NR)) == NULL) return(EINVAL); - get_inode(rip->i_dev, rip->i_num); /* mark inode in use */ - r = stat_inode(rip, fs_m_in->m_source, (cp_grant_id_t) fs_m_in->REQ_GRANT); - put_inode(rip); /* release the inode */ - return(r); -} diff --git a/servers/apfs/super.c b/servers/apfs/super.c deleted file mode 100644 index 50f4e0ba5..000000000 --- a/servers/apfs/super.c +++ /dev/null @@ -1,75 +0,0 @@ -/* This file manages the super block table and the related data structures, - * namely, the bit maps that keep track of which zones and which inodes are - * allocated and which are free. When a new inode or zone is needed, the - * appropriate bit map is searched for a free entry. - * - * The entry points into this file are - * alloc_bit: somebody wants to allocate a zone or inode; find one - * free_bit: indicate that a zone or inode is available for allocation - */ - -#include "fs.h" -#include "buf.h" -#include "inode.h" -#include "const.h" - - -/*===========================================================================* - * alloc_bit * - *===========================================================================*/ -PUBLIC bit_t alloc_bit(void) -{ -/* Allocate a bit from a bit map and return its bit number. */ - bitchunk_t *wptr, *wlim; - bit_t b; - unsigned int i, bcount; - - bcount = FS_BITMAP_CHUNKS(NR_INODES); /* Inode map has this many chunks. */ - wlim = &inodemap[bcount]; /* Point to last chunk in inodemap. */ - - for (wptr = &inodemap[0]; wptr < wlim; wptr++) { - /* Does this word contain a free bit? */ - if (*wptr == (bitchunk_t) ~0) continue; /* No. Go to next word */ - - /* Find and allocate the free bit. */ - for (i = 0; (*wptr & (1 << i)) != 0; ++i) {} - - /* Get inode number */ - b = (bit_t) ((wptr - &inodemap[0]) * FS_BITCHUNK_BITS + i); - - /* Don't allocate bits beyond end of map. */ - if (b >= NR_INODES) break; - - /* Allocate and return bit number. */ - *wptr |= 1 << i; - - /* Mark server 'busy' */ - busy++; - return(b); - } - - return(NO_BIT); /* no bit could be allocated */ -} - - -/*===========================================================================* - * free_bit * - *===========================================================================*/ -PUBLIC void free_bit(bit_returned) -bit_t bit_returned; /* number of bit to insert into the inode map*/ -{ - bitchunk_t *k, mask; - bit_t bit; - unsigned word; - - /* Get word offset and bit within offset */ - word = (unsigned) (bit_returned / (bit_t) FS_BITCHUNK_BITS); - bit = bit_returned % (bit_t) FS_BITCHUNK_BITS; - - /* Unset bit */ - k = &inodemap[word]; - mask = (unsigned) 1 << bit; - *k &= ~mask; - - busy--; /* One inode less in use. */ -} diff --git a/servers/apfs/table.c b/servers/apfs/table.c deleted file mode 100644 index 760e5b21e..000000000 --- a/servers/apfs/table.c +++ /dev/null @@ -1,82 +0,0 @@ - -/* This file contains the table used to map system call numbers onto the - * routines that perform them. - */ - -#define _TABLE - -#include "fs.h" -#include "inode.h" -#include "buf.h" -#include "uds.h" - -/* File System Handlers (pfs) */ -PUBLIC _PROTOTYPE (int (*fs_call_vec[]), - (message *fs_m_in, message *fs_m_out) ) = { - - no_sys, /* 0 not used */ - no_sys, /* 1 */ - fs_putnode, /* 2 */ - no_sys, /* 3 */ - fs_ftrunc, /* 4 */ - no_sys, /* 5 */ - no_sys, /* 6 */ - no_sys, /* 7 */ - fs_stat, /* 8 */ - no_sys, /* 9 */ - no_sys, /* 10 */ - no_sys, /* 11 */ - no_sys, /* 12 */ - no_sys, /* 13 */ - no_sys, /* 14 */ - fs_unmount, /* 15 */ - fs_sync, /* 16 */ - no_sys, /* 17 */ - no_sys, /* 18 */ - fs_readwrite, /* 19 */ - fs_readwrite, /* 20 */ - no_sys, /* 21 */ - no_sys, /* 22 */ - no_sys, /* 23 */ - no_sys, /* 24 */ - no_sys, /* 25 */ - no_sys, /* 26 */ - no_sys, /* 27 */ - no_sys, /* 28 */ - fs_newnode, /* 29 */ - no_sys, /* 30 */ - no_sys, /* 31 */ - no_sys, /* 32 */ -}; - -/* Device Handlers (/dev/uds) */ -PUBLIC _PROTOTYPE (int (*dev_call_vec[]), - (message *dev_m_in, message *dev_m_out) ) = { - - uds_cancel, /* 0 CANCEL */ - no_sys, /* 1 */ - no_sys, /* 2 */ - no_sys, /* 3 */ - no_sys, /* 4 */ - no_sys, /* 5 */ - uds_open, /* 6 DEV_OPEN */ - uds_close, /* 7 DEV_CLOSE */ - no_sys, /* 8 */ - no_sys, /* 9 */ - no_sys, /* 10 TTY_SETPGRP */ - no_sys, /* 11 TTY_EXIT */ - uds_select, /* 12 DEV_SELECT */ - no_sys, /* 13 DEV_STATUS */ - uds_open, /* 14 DEV_REOPEN */ - no_sys, /* 15 */ - no_sys, /* 16 */ - no_sys, /* 17 */ - no_sys, /* 18 */ - no_sys, /* 19 */ - uds_read, /* 20 DEV_READ_S */ - uds_write, /* 21 DEV_WRITE_S */ - no_sys, /* 22 DEV_SCATTER_S */ - no_sys, /* 23 DEV_GATHER_S */ - uds_ioctl, /* 24 DEV_IOCTL_S */ - no_sys, /* 25 DEV_MMAP_S */ -}; diff --git a/servers/apfs/uds.c b/servers/apfs/uds.c deleted file mode 100644 index 18c70e103..000000000 --- a/servers/apfs/uds.c +++ /dev/null @@ -1,1623 +0,0 @@ -/* - * Unix Domain Sockets Implementation (PF_UNIX, PF_LOCAL) - * This code handles ioctl(2) commands to implement the socket API. - * Some helper functions are also present. - * - * The entry points into this file are... - * - * uds_init: initialize the descriptor table. - * do_accept: handles the accept(2) syscall. - * do_connect: handles the connect(2) syscall. - * do_listen: handles the listen(2) syscall. - * do_socket: handles the socket(2) syscall. - * do_bind: handles the bind(2) syscall. - * do_getsockname: handles the getsockname(2) syscall. - * do_getpeername: handles the getpeername(2) syscall. - * do_shutdown: handles the shutdown(2) syscall. - * do_socketpair: handles the socketpair(2) syscall. - * do_getsockopt_sotype: handles the getsockopt(2) syscall. - * do_getsockopt_peercred: handles the getsockopt(2) syscall. - * do_getsockopt_sndbuf: handles the getsockopt(2) syscall. - * do_setsockopt_sndbuf: handles the setsockopt(2) syscall. - * do_getsockopt_rcvbuf: handles the getsockopt(2) syscall. - * do_setsockopt_rcvbuf: handles the setsockopt(2) syscall. - * do_sendto: handles the sendto(2) syscall. - * do_recvfrom: handles the recvfrom(2) syscall. - * do_sendmsg: handles the sendmsg(2) syscall. - * do_recvmsg: handles the recvmsg(2) syscall. - * perform_connection: performs the connection of two descriptors. - * clear_fds: calls put_filp for undelivered FDs. - * - * Also see... - * - * table.c, dev_uds.c, uds.h - */ - -#define DEBUG 0 - -#include "inc.h" -#include "const.h" -#include "glo.h" -#include "uds.h" - -/* File Descriptor Table */ -uds_fd_t uds_fd_table[NR_FDS]; - -/* initialize the descriptor table */ -PUBLIC void uds_init(void) -{ - /* - * Setting everything to NULL implicitly sets the - * state to UDS_FREE. - */ - memset(uds_fd_table, '\0', sizeof(uds_fd_t) * NR_FDS); -} - -/* check the permissions of a socket file */ -PRIVATE int check_perms(int minor, struct sockaddr_un *addr) -{ - int rc; - message vfs_m; - cp_grant_id_t grant_id; - - grant_id = cpf_grant_direct(VFS_PROC_NR, (vir_bytes) addr->sun_path, - UNIX_PATH_MAX, CPF_READ | CPF_WRITE); - - /* ask the VFS to verify the permissions */ - memset(&vfs_m, '\0', sizeof(message)); - - vfs_m.m_type = PFS_REQ_CHECK_PERMS; - vfs_m.USER_ENDPT = uds_fd_table[minor].owner; - vfs_m.IO_GRANT = (char *) grant_id; - vfs_m.COUNT = UNIX_PATH_MAX; - - rc = sendrec(VFS_PROC_NR, &vfs_m); - cpf_revoke(grant_id); - if (OK != rc) { - printf("(uds) sendrec error... req_nr: %d err: %d\n", - vfs_m.m_type, rc); - - return EIO; - } - -#if DEBUG == 1 - printf("(uds) VFS reply => %d\n", vfs_m.m_type); - printf("(uds) Canonical Path => %s\n", addr->sun_path); -#endif - - return vfs_m.m_type; /* return reply code OK, ELOOP, etc. */ -} - -PRIVATE filp_id_t verify_fd(endpoint_t ep, int fd) -{ - int rc; - message vfs_m; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) verify_fd(%d,%d) call_count=%d\n", ep, fd, - ++call_count); -#endif - - memset(&vfs_m, '\0', sizeof(message)); - - vfs_m.m_type = PFS_REQ_VERIFY_FD; - vfs_m.USER_ENDPT = ep; - vfs_m.COUNT = fd; - - rc = sendrec(VFS_PROC_NR, &vfs_m); - if (OK != rc) { - printf("(uds) sendrec error... req_nr: %d err: %d\n", - vfs_m.m_type, rc); - return NULL; - } - -#if DEBUG == 1 - printf("(uds) VFS reply => %d\n", vfs_m.m_type); -#endif - - return vfs_m.ADDRESS; -} - -PRIVATE int set_filp(filp_id_t sfilp) -{ - int rc; - message vfs_m; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) set_filp(0x%x) call_count=%d\n", sfilp, ++call_count); -#endif - - memset(&vfs_m, '\0', sizeof(message)); - - vfs_m.m_type = PFS_REQ_SET_FILP; - vfs_m.ADDRESS = sfilp; - - rc = sendrec(VFS_PROC_NR, &vfs_m); - if (OK != rc) { - printf("(uds) sendrec error... req_nr: %d err: %d\n", - vfs_m.m_type, rc); - return EIO; - } - -#if DEBUG == 1 - printf("(uds) VFS reply => %d\n", vfs_m.m_type); -#endif - return vfs_m.m_type; /* return reply code OK, ELOOP, etc. */ -} - -PRIVATE int copy_filp(endpoint_t to_ep, filp_id_t cfilp) -{ - int rc; - message vfs_m; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) copy_filp(%d, 0x%x) call_count=%d\n",to_ep, cfilp, - ++call_count); -#endif - - memset(&vfs_m, '\0', sizeof(message)); - - vfs_m.m_type = PFS_REQ_COPY_FILP; - vfs_m.USER_ENDPT = to_ep; - vfs_m.ADDRESS = cfilp; - - rc = sendrec(VFS_PROC_NR, &vfs_m); - if (OK != rc) { - printf("(uds) sendrec error... req_nr: %d err: %d\n", - vfs_m.m_type, rc); - return EIO; - } - -#if DEBUG == 1 - printf("(uds) VFS reply => %d\n", vfs_m.m_type); -#endif - return vfs_m.m_type; -} - -PRIVATE int put_filp(filp_id_t pfilp) -{ - int rc; - message vfs_m; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) put_filp(0x%x) call_count=%d\n", pfilp, ++call_count); -#endif - - memset(&vfs_m, '\0', sizeof(message)); - - vfs_m.m_type = PFS_REQ_PUT_FILP; - vfs_m.ADDRESS = pfilp; - - rc = sendrec(VFS_PROC_NR, &vfs_m); - if (OK != rc) { - printf("(uds) sendrec error... req_nr: %d err: %d\n", - vfs_m.m_type, rc); - return EIO; - } - -#if DEBUG == 1 - printf("(uds) VFS reply => %d\n", vfs_m.m_type); -#endif - return vfs_m.m_type; /* return reply code OK, ELOOP, etc. */ -} - -PRIVATE int cancel_fd(endpoint_t ep, int fd) -{ - int rc; - message vfs_m; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) cancel_fd(%d,%d) call_count=%d\n", ep, fd, ++call_count); -#endif - - memset(&vfs_m, '\0', sizeof(message)); - - vfs_m.m_type = PFS_REQ_CANCEL_FD; - vfs_m.USER_ENDPT = ep; - vfs_m.COUNT = fd; - - rc = sendrec(VFS_PROC_NR, &vfs_m); - if (OK != rc) { - printf("(uds) sendrec error... req_nr: %d err: %d\n", - vfs_m.m_type, rc); - return EIO; - } - -#if DEBUG == 1 - printf("(uds) VFS reply => %d\n", vfs_m.m_type); -#endif - return vfs_m.m_type; /* return reply code OK, ELOOP, etc. */ -} - -PUBLIC int perform_connection(message *dev_m_in, message *dev_m_out, - struct sockaddr_un *addr, int minorx, int minory) -{ - /* there are several places were a connection is established. */ - /* accept(2), connect(2), uds_status(2), socketpair(2) */ - /* This is a helper function to make sure it is done in the */ - /* same way in each place with the same validation checks. */ - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] perform_connection() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); -#endif - - /* only connection oriented types are acceptable and only like - * types can connect to each other - */ - if ((uds_fd_table[minorx].type != SOCK_SEQPACKET && - uds_fd_table[minorx].type != SOCK_STREAM) || - uds_fd_table[minorx].type != uds_fd_table[minory].type) { - - /* sockets are not in a valid state */ - return EINVAL; - } - - /* connect the pair of sockets */ - uds_fd_table[minorx].peer = minory; - uds_fd_table[minory].peer = minorx; - - /* Set the address of both sockets */ - memcpy(&(uds_fd_table[minorx].addr), addr, sizeof(struct sockaddr_un)); - memcpy(&(uds_fd_table[minory].addr), addr, sizeof(struct sockaddr_un)); - - return OK; -} - - -PUBLIC int do_accept(message *dev_m_in, message *dev_m_out) -{ - int minor; - int minorparent; /* minor number of parent (server) */ - int minorpeer; - int rc, i; - struct sockaddr_un addr; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_accept() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); -#endif - - /* Somewhat weird logic is used in this function, so here's an - * overview... The minor number is the server's client socket - * (the socket to be returned by accept()). The data waiting - * for us in the IO Grant is the address that the server is - * listening on. This function uses the address to find the - * server's descriptor. From there we can perform the - * connection or suspend and wait for a connect(). - */ - - minor = uds_minor(dev_m_in); - - if (uds_fd_table[minor].type != -1) { - /* this IOCTL must be called on a 'fresh' socket */ - return EINVAL; - } - - /* Get the server's address */ - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &addr, sizeof(struct sockaddr_un), - D); - - if (rc != OK) { - return EIO; - } - - /* locate server socket */ - rc = -1; /* to trap error */ - - for (i = 0; i < NR_FDS; i++) { - - if (uds_fd_table[i].addr.sun_family == AF_UNIX && - !strncmp(addr.sun_path, - uds_fd_table[i].addr.sun_path, - UNIX_PATH_MAX) && - uds_fd_table[i].listening == 1) { - - rc = 0; - break; - } - } - - if (rc == -1) { - /* there is no server listening on addr. Maybe someone - * screwed up the ioctl()? - */ - return EINVAL; - } - - minorparent = i; /* parent */ - - /* we are the parent's child */ - uds_fd_table[minorparent].child = minor; - - /* the peer has the same type as the parent. we need to be that - * type too. - */ - uds_fd_table[minor].type = uds_fd_table[minorparent].type; - - /* locate peer to accept in the parent's backlog */ - minorpeer = -1; /* to trap error */ - for (i = 0; i < uds_fd_table[minorparent].backlog_size; i++) { - if (uds_fd_table[minorparent].backlog[i] != -1) { - minorpeer = uds_fd_table[minorparent].backlog[i]; - uds_fd_table[minorparent].backlog[i] = -1; - rc = 0; - break; - } - } - - if (minorpeer == -1) { - -#if DEBUG == 1 - printf("(uds) [%d] {do_accept} suspend\n", minor); -#endif - - /* there are no peers in the backlog, suspend and wait - * for some to show up - */ - uds_fd_table[minor].suspended = UDS_SUSPENDED_ACCEPT; - - return SUSPEND; - } - -#if DEBUG == 1 - printf("(uds) [%d] connecting to %d -- parent is %d\n", minor, - minorpeer, minorparent); -#endif - - rc = perform_connection(dev_m_in, dev_m_out, &addr, minor, minorpeer); - if (rc != OK) { -#if DEBUG == 1 - printf("(uds) [%d] {do_accept} connection not performed\n", - minor); -#endif - return rc; - } - - uds_fd_table[minorparent].child = -1; - - /* if peer is blocked on connect() revive peer */ - if (uds_fd_table[minorpeer].suspended) { -#if DEBUG == 1 - printf("(uds) [%d] {do_accept} revive %d\n", minor, - minorpeer); -#endif - uds_fd_table[minorpeer].ready_to_revive = 1; - uds_unsuspend(dev_m_in->m_source, minorpeer); - } - - return OK; -} - -PUBLIC int do_connect(message *dev_m_in, message *dev_m_out) -{ - int minor; - struct sockaddr_un addr; - int rc, i, j; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_connect() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); -#endif - - minor = uds_minor(dev_m_in); - - /* only connection oriented sockets can connect */ - if (uds_fd_table[minor].type != SOCK_STREAM && - uds_fd_table[minor].type != SOCK_SEQPACKET) { - return EINVAL; - } - - if (uds_fd_table[minor].peer != -1) { - /* socket is already connected */ - return EISCONN; - } - - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &addr, - sizeof(struct sockaddr_un), D); - - if (rc != OK) { - return EIO; - } - - rc = check_perms(minor, &addr); - if (rc != OK) { - /* permission denied, socket file doesn't exist, etc. */ - return rc; - } - - /* look for a socket of the same type that is listening on the - * address we want to connect to - */ - for (i = 0; i < NR_FDS; i++) { - - if (uds_fd_table[minor].type == uds_fd_table[i].type && - uds_fd_table[i].listening && - uds_fd_table[i].addr.sun_family == AF_UNIX && - !strncmp(addr.sun_path, uds_fd_table[i].addr.sun_path, - UNIX_PATH_MAX)) { - - if (uds_fd_table[i].child != -1) { - - /* the server is blocked on accept(2) -- - * perform connection to the child - */ - - rc = perform_connection(dev_m_in, dev_m_out, - &addr, minor, uds_fd_table[i].child); - - if (rc == OK) { - - uds_fd_table[i].child = -1; - -#if DEBUG == 1 - printf("(uds) [%d] {do_connect} revive %d\n", minor, i); -#endif - - /* wake the parent (server) */ - uds_fd_table[i].ready_to_revive = 1; - uds_unsuspend(dev_m_in->m_source, i); - } - - return rc; - - } else { - -#if DEBUG == 1 - printf("(uds) [%d] adding to %d's backlog\n", - minor, i); -#endif - - /* tell the server were waiting to be served */ - - /* look for a free slot in the backlog */ - rc = -1; /* to trap error */ - for (j = 0; j < uds_fd_table[i].backlog_size; - j++) { - - if (uds_fd_table[i].backlog[j] == -1) { - - uds_fd_table[i].backlog[j] = - minor; - - rc = 0; - break; - } - } - - if (rc == -1) { - - /* backlog is full */ - break; - } - - /* see if the server is blocked on select() */ - if (uds_fd_table[i].selecting == 1) { - - /* if the server wants to know - * about data ready to read and - * it doesn't know about it - * already, then let the server - * know we have data for it. - */ - if ((uds_fd_table[i].sel_ops_in & - SEL_RD) && - !(uds_fd_table[i].sel_ops_out & - SEL_RD)) { - - uds_fd_table[i].sel_ops_out |= - SEL_RD; - uds_fd_table[i].status_updated - = 1; - - uds_unsuspend( - dev_m_in->m_source, i); - } - } - - /* we found our server */ - uds_fd_table[minor].peer = i; - - /* set the address */ - memcpy(&(uds_fd_table[minor].addr), &addr, - sizeof(struct sockaddr_un)); - - break; - } - } - } - - if (uds_fd_table[minor].peer == -1) { - /* could not find another open socket listening on the - * specified address with room in the backlog - */ - return ECONNREFUSED; - } - -#if DEBUG == 1 - printf("(uds) [%d] {do_connect} suspend\n", minor); -#endif - - /* suspend until the server side completes the connection with accept() - */ - - uds_fd_table[minor].suspended = UDS_SUSPENDED_CONNECT; - - return SUSPEND; -} - -PUBLIC int do_listen(message *dev_m_in, message *dev_m_out) -{ - int minor; - int rc; - int backlog_size; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_listen() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); -#endif - - minor = uds_minor(dev_m_in); - - /* ensure the socket has a type and is bound */ - if (uds_fd_table[minor].type == -1 || - uds_fd_table[minor].addr.sun_family != AF_UNIX) { - - /* probably trying to call listen() before bind() */ - return EINVAL; - } - - /* the two supported types for listen(2) are SOCK_STREAM and - * SOCK_SEQPACKET - */ - if (uds_fd_table[minor].type != SOCK_STREAM && - uds_fd_table[minor].type != SOCK_SEQPACKET) { - - /* probably trying to call listen() with a SOCK_DGRAM */ - return EOPNOTSUPP; - } - - /* The POSIX standard doesn't say what to do if listen() has - * already been called. Well, there isn't an errno. we silently - * let it happen, but if listen() has already been called, we - * don't allow the backlog to shrink - */ - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &backlog_size, sizeof(int), D); - - if (rc != OK) { - return EIO; - } - - if (uds_fd_table[minor].listening == 0) { - - /* See if backlog_size is between 0 and UDS_SOMAXCONN */ - if (backlog_size >= 0 && backlog_size < UDS_SOMAXCONN) { - - /* use the user provided backlog_size */ - uds_fd_table[minor].backlog_size = backlog_size; - - } else { - - /* the user gave an invalid size, use - * UDS_SOMAXCONN instead - */ - uds_fd_table[minor].backlog_size = UDS_SOMAXCONN; - } - } else { - - /* See if the user is trying to expand the backlog_size */ - if (backlog_size > uds_fd_table[minor].backlog_size && - backlog_size < UDS_SOMAXCONN) { - - /* expand backlog_size */ - uds_fd_table[minor].backlog_size = backlog_size; - } - - /* Don't let the user shrink the backlog_size (we might - * have clients waiting in those slots - */ - } - - /* perform listen(2) */ - uds_fd_table[minor].listening = 1; - - return OK; -} - -PUBLIC int do_socket(message *dev_m_in, message *dev_m_out) -{ - int rc; - int minor; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_socket() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); -#endif - - minor = uds_minor(dev_m_in); - - /* see if this socket already has a type */ - if (uds_fd_table[minor].type != -1) { - /* socket type can only be set once */ - return EINVAL; - } - - /* get the requested type */ - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].type), - sizeof(int), D); - - if (rc != OK) { - - /* something went wrong and we couldn't get the type */ - return EIO; - } - - /* validate the type */ - switch (uds_fd_table[minor].type) { - case SOCK_STREAM: - case SOCK_DGRAM: - case SOCK_SEQPACKET: - - /* the type is one of the 3 valid socket types */ - return OK; - - default: - - /* if the type isn't one of the 3 valid socket - * types, then it must be invalid. - */ - - /* set the type back to '-1' (no type set) */ - uds_fd_table[minor].type = -1; - - return EINVAL; - } -} - -PUBLIC int do_bind(message *dev_m_in, message *dev_m_out) -{ - int minor; - struct sockaddr_un addr; - int rc, i; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_bind() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); -#endif - - minor = uds_minor(dev_m_in); - - if ((uds_fd_table[minor].type == -1) || - (uds_fd_table[minor].addr.sun_family == AF_UNIX && - uds_fd_table[minor].type != SOCK_DGRAM)) { - - /* the type hasn't been set by do_socket() yet OR attempting - * to re-bind() a non-SOCK_DGRAM socket - */ - return EINVAL; - } - - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &addr, sizeof(struct sockaddr_un), - D); - - if (rc != OK) { - return EIO; - } - - /* do some basic sanity checks on the address */ - if (addr.sun_family != AF_UNIX) { - - /* bad family */ - return EAFNOSUPPORT; - } - - if (addr.sun_path[0] == '\0') { - - /* bad address */ - return ENOENT; - } - - rc = check_perms(minor, &addr); - if (rc != OK) { - /* permission denied, socket file doesn't exist, etc. */ - return rc; - } - - /* make sure the address isn't already in use by another socket. */ - for (i = 0; i < NR_FDS; i++) { - if ((uds_fd_table[i].addr.sun_family == AF_UNIX) && - !strncmp(addr.sun_path, - uds_fd_table[i].addr.sun_path, UNIX_PATH_MAX)) { - - /* another socket is bound to this sun_path */ - return EADDRINUSE; - } - } - - /* looks good, perform the bind() */ - memcpy(&(uds_fd_table[minor].addr), &addr, sizeof(struct sockaddr_un)); - - return OK; -} - -PUBLIC int do_getsockname(message *dev_m_in, message *dev_m_out) -{ - int minor; - int rc; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_getsockname() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); -#endif - - minor = uds_minor(dev_m_in); - - /* Unconditionally send the address we have assigned to this socket. - * The POSIX standard doesn't say what to do if the address - * hasn't been set. If the address isn't currently set, then - * the user will get NULL bytes. Note: libc depends on this - * behavior. - */ - rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].addr), - sizeof(struct sockaddr_un), D); - - return rc ? EIO : OK; -} - -PUBLIC int do_getpeername(message *dev_m_in, message *dev_m_out) -{ - int minor; - int rc; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_getpeername() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); -#endif - - minor = uds_minor(dev_m_in); - - /* check that the socket is connected with a valid peer */ - if (uds_fd_table[minor].peer != -1) { - int peer_minor; - - peer_minor = uds_fd_table[minor].peer; - - /* copy the address from the peer */ - rc = sys_safecopyto(VFS_PROC_NR, - (cp_grant_id_t) dev_m_in->IO_GRANT, (vir_bytes) 0, - (vir_bytes) &(uds_fd_table[peer_minor].addr), - sizeof(struct sockaddr_un), D); - - return rc ? EIO : OK; - } else { - if (uds_fd_table[minor].err == ECONNRESET) { - uds_fd_table[minor].err = 0; - - return ECONNRESET; - } else { - return ENOTCONN; - } - } -} - -PUBLIC int do_shutdown(message *dev_m_in, message *dev_m_out) -{ - int minor; - int rc, how; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_shutdown() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); -#endif - - minor = uds_minor(dev_m_in); - - if (uds_fd_table[minor].type != SOCK_STREAM && - uds_fd_table[minor].type != SOCK_SEQPACKET) { - - /* socket must be a connection oriented socket */ - return EINVAL; - } - - if (uds_fd_table[minor].peer == -1) { - /* shutdown(2) is only valid for connected sockets */ - if (uds_fd_table[minor].err == ECONNRESET) { - return ECONNRESET; - } else { - return ENOTCONN; - } - } - - /* get the 'how' parameter from the process */ - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &how, sizeof(int), D); - - if (rc != OK) { - return EIO; - } - - switch (how) { - case SHUT_RD: - /* take away read permission */ - uds_fd_table[minor].mode = - uds_fd_table[minor].mode ^ S_IRUSR; - break; - - case SHUT_WR: - /* take away write permission */ - uds_fd_table[minor].mode = - uds_fd_table[minor].mode ^ S_IWUSR; - break; - - case SHUT_RDWR: - /* completely shutdown */ - uds_fd_table[minor].mode = 0; - break; - - default: - /* the 'how' parameter is invalid */ - return EINVAL; - } - - return OK; -} - -PUBLIC int do_socketpair_old(message *dev_m_in, message *dev_m_out) -{ - int rc; - short minorin; - int minorx, minory; - struct sockaddr_un addr; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_socketpair() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); -#endif - - /* first ioctl param is the first socket */ - minorx = uds_minor_old(dev_m_in); - - /* third ioctl param is the minor number of the second socket */ - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &minorin, sizeof(short), D); - - if (rc != OK) { - return EIO; - } - - minory = minor(minorin); - -#if DEBUG == 1 - printf("socketpair() %d - %d\n", minorx, minory); -#endif - - /* security check - both sockets must have the same endpoint (owner) */ - if (uds_fd_table[minorx].owner != uds_fd_table[minory].owner) { - - /* we won't allow you to magically connect your socket to - * someone elses socket - */ - return EPERM; - } - - addr.sun_family = AF_UNIX; - addr.sun_path[0] = 'X'; - addr.sun_path[1] = '\0'; - - uds_fd_table[minorx].syscall_done = 1; - return perform_connection(dev_m_in, dev_m_out, &addr, minorx, minory); -} - -PUBLIC int do_socketpair(message *dev_m_in, message *dev_m_out) -{ - int rc; - dev_t minorin; - int minorx, minory; - struct sockaddr_un addr; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_socketpair() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); -#endif - - /* first ioctl param is the first socket */ - minorx = uds_minor(dev_m_in); - - /* third ioctl param is the minor number of the second socket */ - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &minorin, sizeof(dev_t), D); - - if (rc != OK) { - return EIO; - } - - minory = minor(minorin); - -#if DEBUG == 1 - printf("socketpair() %d - %d\n", minorx, minory); -#endif - - /* security check - both sockets must have the same endpoint (owner) */ - if (uds_fd_table[minorx].owner != uds_fd_table[minory].owner) { - - /* we won't allow you to magically connect your socket to - * someone elses socket - */ - return EPERM; - } - - addr.sun_family = AF_UNIX; - addr.sun_path[0] = 'X'; - addr.sun_path[1] = '\0'; - - uds_fd_table[minorx].syscall_done = 1; - return perform_connection(dev_m_in, dev_m_out, &addr, minorx, minory); -} - -PUBLIC int do_getsockopt_sotype(message *dev_m_in, message *dev_m_out) -{ - int minor; - int rc; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_getsockopt_sotype() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); -#endif - - minor = uds_minor(dev_m_in); - - if (uds_fd_table[minor].type == -1) { - - /* the type hasn't been set yet. instead of returning an - * invalid type, we fail with EINVAL - */ - return EINVAL; - } - - rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].type), - sizeof(int), D); - - return rc ? EIO : OK; -} - -PUBLIC int do_getsockopt_peercred(message *dev_m_in, message *dev_m_out) -{ - int minor; - int peer_minor; - int rc; - struct ucred cred; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_getsockopt_peercred() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); -#endif - - minor = uds_minor(dev_m_in); - - if (uds_fd_table[minor].peer == -1) { - - if (uds_fd_table[minor].err == ECONNRESET) { - uds_fd_table[minor].err = 0; - - return ECONNRESET; - } else { - return ENOTCONN; - } - } - - peer_minor = uds_fd_table[minor].peer; - - /* obtain the peer's credentials */ - rc = getnucred(uds_fd_table[peer_minor].owner, &cred); - if (rc == -1) { - /* likely error: invalid endpoint / proc doesn't exist */ - return errno; - } - - rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &cred, sizeof(struct ucred), D); - - return rc ? EIO : OK; -} - -PUBLIC int do_getsockopt_peercred_old(message *dev_m_in, message *dev_m_out) -{ - int minor; - int peer_minor; - int rc; - struct ucred cred; - struct ucred_old cred_old; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_getsockopt_peercred() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); -#endif - - minor = uds_minor(dev_m_in); - - if (uds_fd_table[minor].peer == -1) { - - if (uds_fd_table[minor].err == ECONNRESET) { - uds_fd_table[minor].err = 0; - - return ECONNRESET; - } else { - return ENOTCONN; - } - } - - peer_minor = uds_fd_table[minor].peer; - - /* obtain the peer's credentials */ - rc = getnucred(uds_fd_table[peer_minor].owner, &cred); - if (rc == -1) { - /* likely error: invalid endpoint / proc doesn't exist */ - return errno; - } - - /* copy to old structure */ - cred_old.pid = cred.pid; - cred_old.uid = (short) cred.uid; - cred_old.gid = (char) cred.gid; - - rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &cred_old, sizeof(struct ucred_old), - D); - - return rc ? EIO : OK; -} - -int do_getsockopt_sndbuf(message *dev_m_in, message *dev_m_out) -{ - int minor; - int rc; - size_t sndbuf = PIPE_BUF; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_getsockopt_sndbuf() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); -#endif - - minor = uds_minor(dev_m_in); - - rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &(sndbuf), - sizeof(size_t), D); - - return rc ? EIO : OK; -} - -int do_setsockopt_sndbuf(message *dev_m_in, message *dev_m_out) -{ - int minor; - int rc; - size_t sndbuf; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_setsockopt_rcvbuf() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); -#endif - - minor = uds_minor(dev_m_in); - - - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &sndbuf, - sizeof(size_t), D); - - if (rc != OK) { - return EIO; - } - - if (sndbuf > PIPE_BUF) { - /* The send buffer is limited to 32K at the moment. */ - return ENOSYS; - } - - /* There is no way to reduce the send buffer, do we have to - * let this call fail for smaller buffers? - */ - return OK; -} - -int do_getsockopt_rcvbuf(message *dev_m_in, message *dev_m_out) -{ - int minor; - int rc; - size_t rcvbuf = PIPE_BUF; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_getsockopt_rcvbuf() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); -#endif - - minor = uds_minor(dev_m_in); - - rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &(rcvbuf), - sizeof(size_t), D); - - return rc ? EIO : OK; -} - -int do_setsockopt_rcvbuf(message *dev_m_in, message *dev_m_out) -{ - int minor; - int rc; - size_t rcvbuf; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_setsockopt_rcvbuf() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); -#endif - - minor = uds_minor(dev_m_in); - - - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &rcvbuf, - sizeof(size_t), D); - - if (rc != OK) { - return EIO; - } - - if (rcvbuf > PIPE_BUF) { - /* The send buffer is limited to 32K at the moment. */ - return ENOSYS; - } - - /* There is no way to reduce the send buffer, do we have to - * let this call fail for smaller buffers? - */ - return OK; -} - - -PUBLIC int do_sendto(message *dev_m_in, message *dev_m_out) -{ - int minor; - int rc; - struct sockaddr_un addr; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_sendto() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); -#endif - - minor = uds_minor(dev_m_in); - - if (uds_fd_table[minor].type != SOCK_DGRAM) { - /* This IOCTL is only for SOCK_DGRAM sockets */ - return EINVAL; - } - - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &addr, sizeof(struct sockaddr_un), - D); - - if (rc != OK) { - return EIO; - } - - /* do some basic sanity checks on the address */ - if (addr.sun_family != AF_UNIX || addr.sun_path[0] == '\0') { - /* bad address */ - return EINVAL; - } - - rc = check_perms(minor, &addr); - if (rc != OK) { - return rc; - } - - memcpy(&(uds_fd_table[minor].target), &addr, - sizeof(struct sockaddr_un)); - - return OK; -} - -PUBLIC int do_recvfrom(message *dev_m_in, message *dev_m_out) -{ - int minor; - int rc; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_recvfrom() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); -#endif - - minor = uds_minor(dev_m_in); - - rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].source), - sizeof(struct sockaddr_un), D); - - return rc ? EIO : OK; -} - -int msg_control_read(struct msg_control *msg_ctrl, struct ancillary *data, - int minor) -{ - int rc; - struct msghdr msghdr; - struct cmsghdr *cmsg = NULL; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] msg_control_read() call_count=%d\n", minor, - ++call_count); -#endif - - data->nfiledes = 0; - - memset(&msghdr, '\0', sizeof(struct msghdr)); - msghdr.msg_control = msg_ctrl->msg_control; - msghdr.msg_controllen = msg_ctrl->msg_controllen; - - for(cmsg = CMSG_FIRSTHDR(&msghdr); cmsg != NULL; - cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { - - if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_RIGHTS) { - - int i; - int nfds = - MIN((cmsg->cmsg_len-CMSG_LEN(0))/sizeof(int), - OPEN_MAX); - - for (i = 0; i < nfds; i++) { - if (data->nfiledes == OPEN_MAX) { - return EOVERFLOW; - } - - data->fds[data->nfiledes] = - ((int *) CMSG_DATA(cmsg))[i]; -#if DEBUG == 1 - printf("(uds) [%d] fd[%d]=%d\n", minor, - data->nfiledes, data->fds[data->nfiledes]); -#endif - data->nfiledes++; - } - } - } - - /* obtain this socket's credentials */ - rc = getnucred(uds_fd_table[minor].owner, &(data->cred)); - if (rc == -1) { - return errno; - } -#if DEBUG == 1 - printf("(uds) [%d] cred={%d,%d,%d}\n", minor, - data->cred.pid, data->cred.uid, - data->cred.gid); -#endif - return OK; -} - -PRIVATE int send_fds(int minor, struct ancillary *data) -{ - int rc, i, j; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] send_fds() call_count=%d\n", minor, ++call_count); -#endif - - /* verify the file descriptors and get their filps. */ - for (i = 0; i < data->nfiledes; i++) { - data->filps[i] = verify_fd(uds_fd_table[minor].owner, - data->fds[i]); - - if (data->filps[i] == NULL) { - return EINVAL; - } - } - - /* set them as in-flight */ - for (i = 0; i < data->nfiledes; i++) { - rc = set_filp(data->filps[i]); - if (rc != OK) { - /* revert set_filp() calls */ - for (j = i; j >= 0; j--) { - put_filp(data->filps[j]); - } - return rc; - } - } - - return OK; -} - -PUBLIC int clear_fds(int minor, struct ancillary *data) -{ -/* This function calls put_filp() for all of the FDs in data. - * This is used when a Unix Domain Socket is closed and there - * exists references to file descriptors that haven't been received - * with recvmsg(). - */ - int i; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] recv_fds() call_count=%d\n", minor, - ++call_count); -#endif - - for (i = 0; i < data->nfiledes; i++) { - put_filp(data->filps[i]); -#if DEBUG == 1 - printf("(uds) clear_fds() => %d\n", data->fds[i]); -#endif - data->fds[i] = -1; - data->filps[i] = NULL; - } - - data->nfiledes = 0; - - return OK; -} - -PRIVATE int recv_fds(int minor, struct ancillary *data, - struct msg_control *msg_ctrl) -{ - int rc, i, j; - struct msghdr msghdr; - struct cmsghdr *cmsg; - endpoint_t to_ep; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] recv_fds() call_count=%d\n", minor, - ++call_count); -#endif - - msghdr.msg_control = msg_ctrl->msg_control; - msghdr.msg_controllen = msg_ctrl->msg_controllen; - - cmsg = CMSG_FIRSTHDR(&msghdr); - cmsg->cmsg_len = CMSG_LEN(sizeof(int) * data->nfiledes); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - - to_ep = uds_fd_table[minor].owner; - - /* copy to the target endpoint */ - for (i = 0; i < data->nfiledes; i++) { - rc = copy_filp(to_ep, data->filps[i]); - if (rc < 0) { - /* revert set_filp() calls */ - for (j = 0; j < data->nfiledes; j++) { - put_filp(data->filps[j]); - } - /* revert copy_filp() calls */ - for (j = i; j >= 0; j--) { - cancel_fd(to_ep, data->fds[j]); - } - return rc; - } - data->fds[i] = rc; /* data->fds[i] now has the new FD */ - } - - for (i = 0; i < data->nfiledes; i++) { - put_filp(data->filps[i]); -#if DEBUG == 1 - printf("(uds) recv_fds() => %d\n", data->fds[i]); -#endif - ((int *)CMSG_DATA(cmsg))[i] = data->fds[i]; - data->fds[i] = -1; - data->filps[i] = NULL; - } - - data->nfiledes = 0; - - return OK; -} - -PRIVATE int recv_cred(int minor, struct ancillary *data, - struct msg_control *msg_ctrl) -{ - struct msghdr msghdr; - struct cmsghdr *cmsg; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] recv_cred() call_count=%d\n", minor, - ++call_count); -#endif - - msghdr.msg_control = msg_ctrl->msg_control; - msghdr.msg_controllen = msg_ctrl->msg_controllen; - - cmsg = CMSG_FIRSTHDR(&msghdr); - if (cmsg->cmsg_len > 0) { - cmsg = CMSG_NXTHDR(&msghdr, cmsg); - } - - cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_CREDENTIALS; - memcpy(CMSG_DATA(cmsg), &(data->cred), sizeof(struct ucred)); - - return OK; -} - -PUBLIC int do_sendmsg(message *dev_m_in, message *dev_m_out) -{ - int minor, peer, rc, i; - struct msg_control msg_ctrl; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_sendmsg() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); -#endif - - minor = uds_minor(dev_m_in); - - memset(&msg_ctrl, '\0', sizeof(struct msg_control)); - - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &msg_ctrl, - sizeof(struct msg_control), D); - - if (rc != OK) { - return EIO; - } - - /* locate peer */ - peer = -1; - if (uds_fd_table[minor].type == SOCK_DGRAM) { - if (uds_fd_table[minor].target.sun_path[0] == '\0' || - uds_fd_table[minor].target.sun_family != AF_UNIX) { - - return EDESTADDRREQ; - } - - for (i = 0; i < NR_FDS; i++) { - - /* look for a SOCK_DGRAM socket that is bound on - * the target address - */ - if (uds_fd_table[i].type == SOCK_DGRAM && - uds_fd_table[i].addr.sun_family == AF_UNIX && - !strncmp(uds_fd_table[minor].target.sun_path, - uds_fd_table[i].addr.sun_path, UNIX_PATH_MAX)){ - - peer = i; - break; - } - } - - if (peer == -1) { - return ENOENT; - } - } else { - peer = uds_fd_table[minor].peer; - if (peer == -1) { - return ENOTCONN; - } - } - -#if DEBUG == 1 - printf("(uds) [%d] sendmsg() -- peer=%d\n", minor, peer); -#endif - /* note: it's possible that there is already some file - * descriptors in ancillary_data if the peer didn't call - * recvmsg() yet. That's okay. The receiver will - * get the current file descriptors plus the new ones. - */ - rc = msg_control_read(&msg_ctrl, &uds_fd_table[peer].ancillary_data, - minor); - if (rc != OK) { - return rc; - } - - return send_fds(minor, &uds_fd_table[peer].ancillary_data); -} - -PUBLIC int do_recvmsg(message *dev_m_in, message *dev_m_out) -{ - int minor; - int rc; - struct msg_control msg_ctrl; - socklen_t controllen_avail = 0; - socklen_t controllen_needed = 0; - socklen_t controllen_desired = 0; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] do_sendmsg() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); -#endif - - minor = uds_minor(dev_m_in); - - -#if DEBUG == 1 - printf("(uds) [%d] CREDENTIALS {pid:%d,uid:%d,gid:%d}\n", minor, - uds_fd_table[minor].ancillary_data.cred.pid, - uds_fd_table[minor].ancillary_data.cred.uid, - uds_fd_table[minor].ancillary_data.cred.gid); -#endif - - memset(&msg_ctrl, '\0', sizeof(struct msg_control)); - - /* get the msg_control from the user, it will include the - * amount of space the user has allocated for control data. - */ - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &msg_ctrl, - sizeof(struct msg_control), D); - - if (rc != OK) { - return EIO; - } - - controllen_avail = MIN(msg_ctrl.msg_controllen, MSG_CONTROL_MAX); - - if (uds_fd_table[minor].ancillary_data.nfiledes > 0) { - controllen_needed = CMSG_LEN(sizeof(int) * - (uds_fd_table[minor].ancillary_data.nfiledes)); - } - - /* if there is room we also include credentials */ - controllen_desired = controllen_needed + - CMSG_LEN(sizeof(struct ucred)); - - if (controllen_needed > controllen_avail) { - return EOVERFLOW; - } - - rc = recv_fds(minor, &uds_fd_table[minor].ancillary_data, &msg_ctrl); - if (rc != OK) { - return rc; - } - - if (controllen_desired <= controllen_avail) { - rc = recv_cred(minor, &uds_fd_table[minor].ancillary_data, - &msg_ctrl); - if (rc != OK) { - return rc; - } - } - - /* send the user the control data */ - rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &msg_ctrl, - sizeof(struct msg_control), D); - - return rc ? EIO : OK; -} diff --git a/servers/apfs/uds.h b/servers/apfs/uds.h deleted file mode 100644 index efcb9c1da..000000000 --- a/servers/apfs/uds.h +++ /dev/null @@ -1,251 +0,0 @@ -#ifndef __PFS_UDS_H__ -#define __PFS_UDS_H__ - -/* - * Unix Domain Sockets Implementation (PF_UNIX, PF_LOCAL) - * - * Also See... - * - * dev_uds.c, table.c, uds.c - */ - -#include -#include -#include -#include - -#include - -/* max connection backlog for incoming connections */ -#define UDS_SOMAXCONN 64 - -typedef void* filp_id_t; - -/* ancillary data to be sent */ -struct ancillary { - filp_id_t filps[OPEN_MAX]; - int fds[OPEN_MAX]; - int nfiledes; - struct ucred cred; -}; - -/* - * Internal State Information for a socket descriptor. - */ -struct uds_fd { - -/* Flags */ - - enum UDS_STATE { - /* This file descriptor is UDS_FREE and can be allocated. */ - UDS_FREE = 0, - - /* OR it is UDS_INUSE and can't be allocated. */ - UDS_INUSE = 1 - - /* state is set to UDS_INUSE in uds_open(). state is Set to - * UDS_FREE in uds_init() and uds_close(). state should be - * checked prior to all operations. - */ - } state; - -/* Owner Info */ - - /* Socket Owner */ - endpoint_t owner; - - /* endpoint for suspend/resume */ - endpoint_t endpoint; - -/* Pipe Housekeeping */ - - /* inode number on PFS -- each descriptor is backed by 1 - * PIPE which is allocated in uds_open() and freed in - * uds_close(). Data is sent/written to a peer's PIPE. - * Data is recv/read from this PIPE. - */ - ino_t inode_nr; - - - /* position in the PIPE where the data starts */ - off_t pos; - - /* size of data in the PIPE */ - size_t size; - - /* control read/write, set by uds_open() and shutdown(2). - * Can be set to S_IRUSR|S_IWUSR, S_IRUSR, S_IWUSR, or 0 - * for read and write, read only, write only, or neither. - * default is S_IRUSR|S_IWUSR. - */ - mode_t mode; - -/* Socket Info */ - - - /* socket type - SOCK_STREAM, SOCK_DGRAM, or SOCK_SEQPACKET - * Set by uds_ioctl(NWIOSUDSTYPE). It defaults to -1 in - * uds_open(). Any action on a socket with type -1 besides - * uds_ioctl(NWIOSUDSTYPE) and uds_close() will result in - * an error. - */ - int type; - - /* queue of pending connections for server sockets. - * connect(2) inserts and accept(2) removes from the queue - */ - int backlog[UDS_SOMAXCONN]; - - /* requested connection backlog size. Set by listen(2) - * Bounds (0 <= backlog_size <= UDS_SOMAXCONN) - * Defaults to UDS_SOMAXCONN which is defined above. - */ - unsigned char backlog_size; - - /* index of peer in uds_fd_table for connected sockets. - * -1 is used to mean no peer. Assumptions: peer != -1 means - * connected. - */ - int peer; - - /* index of child (client sd returned by accept(2)) - * -1 is used to mean no child. - */ - int child; - - /* address -- the address the socket is bound to. - * Assumptions: addr.sun_family == AF_UNIX means its bound. - */ - struct sockaddr_un addr; - - /* target -- where DGRAMs are sent to on the next uds_write(). */ - struct sockaddr_un target; - - /* source -- address where DGRAMs are from. used to fill in the - * from address in recvfrom(2) and recvmsg(2). - */ - struct sockaddr_un source; - - /* Flag (1 or 0) - listening for incoming connections. - * Default to 0. Set to 1 by do_listen() - */ - int listening; - - /* stores file pointers and credentials being sent between - * processes with sendmsg(2) and recvmsg(2). - */ - struct ancillary ancillary_data; - - /* Holds an errno. This is set when a connected socket is - * closed and we need to pass ECONNRESET on to a suspended - * peer. - */ - int err; - -/* Suspend/Revive Housekeeping */ - - - /* SUSPEND State Flags */ - enum UDS_SUSPENDED { - - /* Socket isn't blocked. */ - UDS_NOT_SUSPENDED = 0, - - /* Socket is blocked on read(2) waiting for data to read. */ - UDS_SUSPENDED_READ = 1, - - /* Socket is blocked on write(2) for space to write data. */ - UDS_SUSPENDED_WRITE = 2, - - /* Socket is blocked on connect(2) waiting for the server. */ - UDS_SUSPENDED_CONNECT = 4, - - /* Socket is blocked on accept(2) waiting for clients. */ - UDS_SUSPENDED_ACCEPT = 8 - } suspended; - - /* Flag (1 or 0) - thing socket was waiting for is ready. - * If 1, then uds_status() will attempt the operation that - * the socket was blocked on. - */ - int ready_to_revive; - - /* i/o grant, saved for later use by suspended procs */ - cp_grant_id_t io_gr; - - /* is of i/o grant, saved for later use by suspended procs */ - size_t io_gr_size; - - /* Save the call number so that uds_cancel() can unwind the - * call properly. - */ - int call_nr; - - /* Save the IOCTL so uds_cancel() knows what got cancelled. */ - int ioctl; - - /* Flag (1 or 0) - the system call completed. - * A doc I read said DEV_CANCEL might be called even though - * the operation is finished. We use this variable to - * determine if we should rollback the changes or not. - */ - int syscall_done; - -/* select() */ - - /* Flag (1 or 0) - the process blocked on select(2). When - * selecting is 1 and I/O happens on this socket, then - * select_proc should be notified. - */ - int selecting; - - /* when a select is in progress, we notify() this endpoint - * of new data. - */ - endpoint_t select_proc; - - /* Options (SEL_RD, SEL_WR, SEL_ERR) that are requested. */ - int sel_ops_in; - - /* Options that are available for this socket. */ - int sel_ops_out; - - /* Flag (1 or 0) to be set to one before calling notify(). - * uds_status() will use the flag to locate this descriptor. - */ - int status_updated; -}; - -typedef struct uds_fd uds_fd_t; - -/* File Descriptor Table -- Defined in uds.c */ -EXTERN uds_fd_t uds_fd_table[NR_FDS]; - -/* - * Take message m and get the index in uds_fd_table. - */ -#define uds_minor(m) (minor((dev_t) m->DEVICE)) -#define uds_minor_old(m) (minor((short) m->DEVICE)) - -/* - * Fill in a reply message. - */ -#define uds_set_reply(msg,type,endpoint,io_gr,status) \ - do { \ - (msg)->m_type = type; \ - (msg)->REP_ENDPT = endpoint; \ - (msg)->REP_IO_GRANT = io_gr; \ - (msg)->REP_STATUS = status; \ - } while (0) - -#define uds_sel_reply(msg,type,minor,ops) \ - do { \ - (msg)->m_type = type; \ - (msg)->DEV_MINOR = minor; \ - (msg)->DEV_SEL_OPS = ops; \ - } while (0) - - - - -#endif diff --git a/servers/apfs/utility.c b/servers/apfs/utility.c deleted file mode 100644 index fac9ec625..000000000 --- a/servers/apfs/utility.c +++ /dev/null @@ -1,33 +0,0 @@ -#include "fs.h" - - -/*===========================================================================* - * no_sys * - *===========================================================================*/ -PUBLIC int no_sys(message *pfs_m_in, message *pfs_m_out) -{ -/* Somebody has used an illegal system call number */ - printf("no_sys: invalid call 0x%x to pfs\n", req_nr); - return(EINVAL); -} - - -/*===========================================================================* - * clock_time * - *===========================================================================*/ -PUBLIC time_t clock_time() -{ -/* This routine returns the time in seconds since 1.1.1970. MINIX is an - * astrophysically naive system that assumes the earth rotates at a constant - * rate and that such things as leap seconds do not exist. - */ - - int r; - clock_t uptime; /* Uptime in ticks */ - time_t boottime; - - if ((r = getuptime2(&uptime, &boottime)) != OK) - panic("clock_time: getuptme2 failed: %d", r); - - return( (time_t) (boottime + (uptime/sys_hz()))); -} diff --git a/servers/avfs/Makefile b/servers/avfs/Makefile deleted file mode 100644 index ec0553f98..000000000 --- a/servers/avfs/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -# Makefile for Virtual File System (VFS) -.include - -PROG= vfs -SRCS= main.c open.c read.c write.c pipe.c dmap.c \ - path.c device.c mount.c link.c exec.c \ - filedes.c stadir.c protect.c time.c \ - lock.c misc.c utility.c select.c table.c \ - vnode.c vmnt.c request.c fscall.c \ - tll.c comm.c worker.c coredump.c - -.if ${MKCOVERAGE} != "no" -SRCS+= gcov.c -CPPFLAGS+= -DUSE_COVERAGE -.endif - -DPADD+= ${LIBSYS} ${LIBTIMERS} ${LIBEXEC} -LDADD+= -lsys -ltimers -lexec -lmthread - -.if ${COMPILER_TYPE} == "gnu" -LDADD+= -lc -.endif - -MAN= - -BINDIR?= /usr/sbin -INSTALLFLAGS+= -S 16k - -.include diff --git a/servers/avfs/const.h b/servers/avfs/const.h deleted file mode 100644 index 44a339d7c..000000000 --- a/servers/avfs/const.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef __VFS_CONST_H__ -#define __VFS_CONST_H__ - -/* Tables sizes */ -#define NR_FILPS 512 /* # slots in filp table */ -#define NR_LOCKS 8 /* # slots in the file locking table */ -#define NR_MNTS 16 /* # slots in mount table */ -#define NR_VNODES 512 /* # slots in vnode table */ -#define NR_WTHREADS 8 /* # slots in worker thread table */ - -#define NR_NONEDEVS NR_MNTS /* # slots in nonedev bitmap */ - -/* Miscellaneous constants */ -#define SU_UID ((uid_t) 0) /* super_user's uid_t */ -#define SYS_UID ((uid_t) 0) /* uid_t for system processes and INIT */ -#define SYS_GID ((gid_t) 0) /* gid_t for system processes and INIT */ - -#define FP_BLOCKED_ON_NONE 0 /* not blocked */ -#define FP_BLOCKED_ON_PIPE 1 /* susp'd on pipe */ -#define FP_BLOCKED_ON_LOCK 2 /* susp'd on lock */ -#define FP_BLOCKED_ON_POPEN 3 /* susp'd on pipe open */ -#define FP_BLOCKED_ON_SELECT 4 /* susp'd on select */ -#define FP_BLOCKED_ON_DOPEN 5 /* susp'd on device open */ -#define FP_BLOCKED_ON_OTHER 6 /* blocked on other process, check - fp_task to find out */ - -/* test if the process is blocked on something */ -#define fp_is_blocked(fp) ((fp)->fp_blocked_on != FP_BLOCKED_ON_NONE) - -#define DUP_MASK 0100 /* mask to distinguish dup2 from dup */ - -#define LOOK_UP 0 /* tells search_dir to lookup string */ -#define ENTER 1 /* tells search_dir to make dir entry */ -#define DELETE 2 /* tells search_dir to delete entry */ -#define IS_EMPTY 3 /* tells search_dir to ret. OK or ENOTEMPTY */ - -#define SYMLOOP 16 - -#define LABEL_MAX 16 /* maximum label size (including '\0'). Should - * not be smaller than 16 or bigger than - * M3_LONG_STRING. - */ - -/* Args to dev_io */ -#define VFS_DEV_READ 2001 -#define VFS_DEV_WRITE 2002 -#define VFS_DEV_IOCTL 2005 -#define VFS_DEV_SELECT 2006 - -#endif diff --git a/servers/avfs/device.c b/servers/avfs/device.c deleted file mode 100644 index 926cf322a..000000000 --- a/servers/avfs/device.c +++ /dev/null @@ -1,1193 +0,0 @@ -/* When a needed block is not in the cache, it must be fetched from the disk. - * Special character files also require I/O. The routines for these are here. - * - * The entry points in this file are: - * dev_open: open a character device - * dev_reopen: reopen a character device after a driver crash - * dev_close: close a character device - * bdev_open: open a block device - * bdev_close: close a block device - * dev_io: FS does a read or write on a device - * dev_status: FS processes callback request alert - * gen_opcl: generic call to a task to perform an open/close - * gen_io: generic call to a task to perform an I/O operation - * no_dev: open/close processing for devices that don't exist - * no_dev_io: i/o processing for devices that don't exist - * tty_opcl: perform tty-specific processing for open/close - * ctty_opcl: perform controlling-tty-specific processing for open/close - * ctty_io: perform controlling-tty-specific processing for I/O - * pm_setsid: perform VFS's side of setsid system call - * do_ioctl: perform the IOCTL system call - */ - -#include "fs.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "file.h" -#include "fproc.h" -#include "scratchpad.h" -#include "dmap.h" -#include -#include "vnode.h" -#include "vmnt.h" -#include "param.h" - -FORWARD _PROTOTYPE( void restart_reopen, (int major) ); -FORWARD _PROTOTYPE( int safe_io_conversion, (endpoint_t, cp_grant_id_t *, - int *, - endpoint_t *, void **, - size_t, u32_t *) ); - -PRIVATE int dummyproc; - - -/*===========================================================================* - * dev_open * - *===========================================================================*/ -PUBLIC int dev_open( - dev_t dev, /* device to open */ - endpoint_t proc_e, /* process to open for */ - int flags /* mode bits and flags */ -) -{ -/* Open a character device. */ - int major, r; - - /* Determine the major device number so as to call the device class specific - * open/close routine. (This is the only routine that must check the - * device number for being in range. All others can trust this check.) - */ - major = major(dev); - if (major < 0 || major >= NR_DEVICES) major = 0; - if (dmap[major].dmap_driver == NONE) return(ENXIO); - r = (*dmap[major].dmap_opcl)(DEV_OPEN, dev, proc_e, flags); - return(r); -} - - -/*===========================================================================* - * dev_reopen * - *===========================================================================*/ -PUBLIC int dev_reopen( - dev_t dev, /* device to open */ - int filp_no, /* filp to reopen for */ - int flags /* mode bits and flags */ -) -{ -/* Reopen a character device after a failing device driver. */ - - int major, r; - struct dmap *dp; - - /* Determine the major device number and call the device class specific - * open/close routine. (This is the only routine that must check the device - * number for being in range. All others can trust this check.) - */ - - major = major(dev); - if (major < 0 || major >= NR_DEVICES) major = 0; - dp = &dmap[major]; - if (dp->dmap_driver == NONE) return(ENXIO); - r = (*dp->dmap_opcl)(DEV_REOPEN, dev, filp_no, flags); - if (r == SUSPEND) r = OK; - return(r); -} - - -/*===========================================================================* - * dev_close * - *===========================================================================*/ -PUBLIC int dev_close( - dev_t dev, /* device to close */ - int filp_no -) -{ -/* Close a character device. */ - int r, major; - - /* See if driver is roughly valid. */ - major = major(dev); - if (major < 0 || major >= NR_DEVICES) return(ENXIO); - if (dmap[major].dmap_driver == NONE) return(ENXIO); - r = (*dmap[major].dmap_opcl)(DEV_CLOSE, dev, filp_no, 0); - return(r); -} - - -/*===========================================================================* - * dev_open * - *===========================================================================*/ -PUBLIC int bdev_open(dev_t dev, int access) -{ -/* Open a block device. */ - int major; - - major = major(dev); - if (major < 0 || major >= NR_DEVICES) return(ENXIO); - if (dmap[major].dmap_driver == NONE) return(ENXIO); - - return (*dmap[major].dmap_opcl)(BDEV_OPEN, dev, 0, access); -} - - -/*===========================================================================* - * bdev_close * - *===========================================================================*/ -PUBLIC int bdev_close(dev_t dev) -{ -/* Close a block device. */ - int major; - - major = major(dev); - if (major < 0 || major >= NR_DEVICES) return(ENXIO); - if (dmap[major].dmap_driver == NONE) return(ENXIO); - - return (*dmap[major].dmap_opcl)(BDEV_CLOSE, dev, 0, 0); -} - - -/*===========================================================================* - * bdev_ioctl * - *===========================================================================*/ -PRIVATE int bdev_ioctl(dev_t dev, endpoint_t proc_e, int req, void *buf) -{ -/* Perform an I/O control operation on a block device. */ - struct dmap *dp; - u32_t dummy; - cp_grant_id_t gid; - message dev_mess; - int op, major_dev, minor_dev; - - major_dev = major(dev); - minor_dev = minor(dev); - - /* Determine task dmap. */ - dp = &dmap[major_dev]; - if (dp->dmap_driver == NONE) { - printf("VFS: dev_io: no driver for major %d\n", major_dev); - return(ENXIO); - } - - /* Set up a grant if necessary. */ - op = VFS_DEV_IOCTL; - (void) safe_io_conversion(dp->dmap_driver, &gid, &op, &proc_e, &buf, 0, - &dummy); - - /* Set up the message passed to the task. */ - memset(&dev_mess, 0, sizeof(dev_mess)); - - dev_mess.m_type = BDEV_IOCTL; - dev_mess.BDEV_MINOR = minor_dev; - dev_mess.BDEV_REQUEST = req; - dev_mess.BDEV_GRANT = gid; - dev_mess.BDEV_ID = 0; - - /* Call the task. */ - (*dp->dmap_io)(dp->dmap_driver, &dev_mess); - - /* Clean up. */ - if (GRANT_VALID(gid)) cpf_revoke(gid); - - if (dp->dmap_driver == NONE) { - printf("VFS: block driver gone!?\n"); - return(EIO); - } - - /* Return the result. */ - return(dev_mess.BDEV_STATUS); -} - - -/*===========================================================================* - * find_suspended_ep * - *===========================================================================*/ -endpoint_t find_suspended_ep(endpoint_t driver, cp_grant_id_t g) -{ -/* A process is suspended on a driver for which VFS issued a grant. Find out - * which process it was. - */ - struct fproc *rfp; - for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - if(rfp->fp_pid == PID_FREE) - continue; - - if(rfp->fp_blocked_on == FP_BLOCKED_ON_OTHER && - rfp->fp_task == driver && rfp->fp_grant == g) - return(rfp->fp_endpoint); - } - - return(NONE); -} - - -/*===========================================================================* - * dev_status * - *===========================================================================*/ -PUBLIC void dev_status(message *m) -{ -/* A device sent us a notification it has something for us. Retrieve it. */ - - message st; - int major, get_more = 1; - endpoint_t endpt; - - for (major = 0; major < NR_DEVICES; major++) - if (dmap_driver_match(m->m_source, major)) - break; /* 'major' is the device that sent the message */ - - if (major >= NR_DEVICES) /* Device endpoint not found; nothing to do */ - return; - - if (dmap[major].dmap_style == STYLE_DEVA || - dmap[major].dmap_style == STYLE_CLONE_A) { - printf("VFS: not doing dev_status for async driver %d\n", m->m_source); - return; - } - - /* Continuously send DEV_STATUS messages until the device has nothing to - * say to us anymore. */ - do { - int r; - st.m_type = DEV_STATUS; - r = sendrec(m->m_source, &st); - if (r == OK && st.REP_STATUS == ERESTART) r = EDEADEPT; - if (r != OK) { - printf("VFS: DEV_STATUS failed to %d: %d\n", m->m_source, r); - if (r == EDEADSRCDST || r == EDEADEPT) return; - panic("VFS: couldn't sendrec for DEV_STATUS: %d", r); - } - - switch(st.m_type) { - case DEV_REVIVE: - /* We've got results for a read/write/ioctl call to a - * synchronous character driver */ - endpt = st.REP_ENDPT; - if (endpt == VFS_PROC_NR) { - endpt = find_suspended_ep(m->m_source,st.REP_IO_GRANT); - if(endpt == NONE) { - printf("VFS: proc with grant %d from %d not found\n", - st.REP_IO_GRANT, st.m_source); - continue; - } - } - revive(endpt, st.REP_STATUS); - break; - case DEV_IO_READY: - /* Reply to a select request: driver is ready for I/O */ - select_reply2(st.m_source, st.DEV_MINOR, st.DEV_SEL_OPS); - break; - default: - printf("VFS: unrecognized reply %d to DEV_STATUS\n",st.m_type); - /* Fall through. */ - case DEV_NO_STATUS: - get_more = 0; - break; - } - } while(get_more); -} - -/*===========================================================================* - * safe_io_conversion * - *===========================================================================*/ -PRIVATE int safe_io_conversion(driver, gid, op, io_ept, buf, bytes, pos_lo) -endpoint_t driver; -cp_grant_id_t *gid; -int *op; -endpoint_t *io_ept; -void **buf; -size_t bytes; -u32_t *pos_lo; -{ -/* Convert operation to the 'safe' variant (i.e., grant based) if applicable. - * If no copying of data is involved, there is also no need to convert. */ - - int access = 0; - size_t size; - - *gid = GRANT_INVALID; /* Grant to buffer */ - - switch(*op) { - case VFS_DEV_READ: - case VFS_DEV_WRITE: - /* Change to safe op. */ - *op = (*op == VFS_DEV_READ) ? DEV_READ_S : DEV_WRITE_S; - *gid = cpf_grant_magic(driver, *io_ept, (vir_bytes) *buf, bytes, - *op == DEV_READ_S ? CPF_WRITE : CPF_READ); - if (*gid < 0) - panic("VFS: cpf_grant_magic of READ/WRITE buffer failed"); - break; - case VFS_DEV_IOCTL: - *pos_lo = *io_ept; /* Old endpoint in POSITION field. */ - *op = DEV_IOCTL_S; - if(_MINIX_IOCTL_IOR(m_in.REQUEST)) access |= CPF_WRITE; - if(_MINIX_IOCTL_IOW(m_in.REQUEST)) access |= CPF_READ; - if(_MINIX_IOCTL_BIG(m_in.REQUEST)) - size = _MINIX_IOCTL_SIZE_BIG(m_in.REQUEST); - else - size = _MINIX_IOCTL_SIZE(m_in.REQUEST); - - /* Grant access to the buffer even if no I/O happens with the ioctl, in - * order to disambiguate requests with DEV_IOCTL_S. - */ - *gid = cpf_grant_magic(driver, *io_ept, (vir_bytes) *buf, size, access); - if (*gid < 0) - panic("VFS: cpf_grant_magic IOCTL buffer failed"); - - break; - case VFS_DEV_SELECT: - *op = DEV_SELECT; - break; - default: - panic("VFS: unknown operation %d for safe I/O conversion", *op); - } - - /* If we have converted to a safe operation, I/O endpoint becomes VFS if it - * wasn't already. - */ - if(GRANT_VALID(*gid)) { - *io_ept = VFS_PROC_NR; - return(1); - } - - /* Not converted to a safe operation (because there is no copying involved in - * this operation). - */ - return(0); -} - -/*===========================================================================* - * dev_io * - *===========================================================================*/ -PUBLIC int dev_io( - int op, /* DEV_READ, DEV_WRITE, DEV_IOCTL, etc. */ - dev_t dev, /* major-minor device number */ - int proc_e, /* in whose address space is buf? */ - void *buf, /* virtual address of the buffer */ - u64_t pos, /* byte position */ - size_t bytes, /* how many bytes to transfer */ - int flags, /* special flags, like O_NONBLOCK */ - int suspend_reopen /* Just suspend the process */ -) -{ -/* Read from or write to a device. The parameter 'dev' tells which one. */ - struct dmap *dp; - u32_t pos_lo, pos_high; - message dev_mess; - cp_grant_id_t gid = GRANT_INVALID; - int safe, minor_dev, major_dev; - void *buf_used; - endpoint_t ioproc; - - pos_lo = ex64lo(pos); - pos_high = ex64hi(pos); - major_dev = major(dev); - minor_dev = minor(dev); - - /* Determine task dmap. */ - dp = &dmap[major_dev]; - - /* See if driver is roughly valid. */ - if (dp->dmap_driver == NONE) { - printf("VFS: dev_io: no driver for major %d\n", major_dev); - return(ENXIO); - } - - if (suspend_reopen) { - /* Suspend user. */ - fp->fp_grant = GRANT_INVALID; - fp->fp_ioproc = NONE; - wait_for(dp->dmap_driver); - fp->fp_flags |= FP_SUSP_REOPEN; - return(SUSPEND); - } - - if(isokendpt(dp->dmap_driver, &dummyproc) != OK) { - printf("VFS: dev_io: old driver for major %x (%d)\n", major_dev, - dp->dmap_driver); - return(ENXIO); - } - - /* By default, these are right. */ - dev_mess.USER_ENDPT = proc_e; - dev_mess.ADDRESS = buf; - - /* Convert DEV_* to DEV_*_S variants. */ - buf_used = buf; - safe = safe_io_conversion(dp->dmap_driver, &gid, &op, - (endpoint_t *) &dev_mess.USER_ENDPT, &buf_used, - bytes, &pos_lo); - - /* If the safe conversion was done, set the IO_GRANT to - * the grant id. - */ - if(safe) dev_mess.IO_GRANT = (char *) gid; - - /* Set up the rest of the message passed to task. */ - dev_mess.m_type = op; - dev_mess.DEVICE = minor_dev; - dev_mess.POSITION = pos_lo; - dev_mess.COUNT = bytes; - dev_mess.HIGHPOS = pos_high; - - /* This will be used if the i/o is suspended. */ - ioproc = dev_mess.USER_ENDPT; - - /* Call the task. */ - (*dp->dmap_io)(dp->dmap_driver, &dev_mess); - - if(dp->dmap_driver == NONE) { - /* Driver has vanished. */ - printf("VFS: driver gone?!\n"); - if(safe) cpf_revoke(gid); - return(EIO); - } - - /* Task has completed. See if call completed. */ - if (dev_mess.REP_STATUS == SUSPEND) { - if ((flags & O_NONBLOCK) && !(dp->dmap_style == STYLE_DEVA || - dp->dmap_style == STYLE_CLONE_A)) { - /* Not supposed to block. */ - dev_mess.m_type = CANCEL; - dev_mess.USER_ENDPT = ioproc; - dev_mess.IO_GRANT = (char *) gid; - - /* This R_BIT/W_BIT check taken from suspend()/unpause() - * logic. Mode is expected in the COUNT field. - */ - dev_mess.COUNT = 0; - if (call_nr == READ) dev_mess.COUNT = R_BIT; - else if (call_nr == WRITE) dev_mess.COUNT = W_BIT; - dev_mess.DEVICE = minor_dev; - (*dp->dmap_io)(dp->dmap_driver, &dev_mess); - if (dev_mess.REP_STATUS == EINTR) dev_mess.REP_STATUS = EAGAIN; - } else { - /* select() will do suspending itself. */ - if(op != DEV_SELECT) { - /* Suspend user. */ - wait_for(dp->dmap_driver); - } - assert(!GRANT_VALID(fp->fp_grant)); - fp->fp_grant = gid; /* revoke this when unsuspended. */ - fp->fp_ioproc = ioproc; - - if (flags & O_NONBLOCK) { - /* Not supposed to block, send cancel message */ - dev_mess.m_type = CANCEL; - dev_mess.USER_ENDPT = ioproc; - dev_mess.IO_GRANT = (char *) gid; - - /* This R_BIT/W_BIT check taken from suspend()/unpause() - * logic. Mode is expected in the COUNT field. - */ - dev_mess.COUNT = 0; - if(call_nr == READ) dev_mess.COUNT = R_BIT; - else if(call_nr == WRITE) dev_mess.COUNT = W_BIT; - dev_mess.DEVICE = minor_dev; - (*dp->dmap_io)(dp->dmap_driver, &dev_mess); - - /* Should do something about EINTR -> EAGAIN mapping */ - } - return(SUSPEND); - } - } - - /* No suspend, or cancelled suspend, so I/O is over and can be cleaned up. */ - if(safe) cpf_revoke(gid); - - return(dev_mess.REP_STATUS); -} - -/*===========================================================================* - * gen_opcl * - *===========================================================================*/ -PUBLIC int gen_opcl( - int op, /* operation, (B)DEV_OPEN or (B)DEV_CLOSE */ - dev_t dev, /* device to open or close */ - endpoint_t proc_e, /* process to open/close for */ - int flags /* mode bits and flags */ -) -{ -/* Called from the dmap struct on opens & closes of special files.*/ - int r, minor_dev, major_dev, is_bdev; - struct dmap *dp; - message dev_mess; - - /* Determine task dmap. */ - major_dev = major(dev); - minor_dev = minor(dev); - assert(major_dev >= 0 && major_dev < NR_DEVICES); - dp = &dmap[major_dev]; - assert(dp->dmap_driver != NONE); - - is_bdev = IS_BDEV_RQ(op); - - if (is_bdev) { - memset(&dev_mess, 0, sizeof(dev_mess)); - dev_mess.m_type = op; - dev_mess.BDEV_MINOR = minor_dev; - dev_mess.BDEV_ACCESS = flags; - dev_mess.BDEV_ID = 0; - } else { - dev_mess.m_type = op; - dev_mess.DEVICE = minor_dev; - dev_mess.USER_ENDPT = proc_e; - dev_mess.COUNT = flags; - } - - /* Call the task. */ - r = (*dp->dmap_io)(dp->dmap_driver, &dev_mess); - if (r != OK) return(r); - - if (op == DEV_OPEN && dp->dmap_style == STYLE_DEVA) { - fp->fp_task = dp->dmap_driver; - worker_wait(); - } - - if (is_bdev) - return(dev_mess.BDEV_STATUS); - else - return(dev_mess.REP_STATUS); -} - -/*===========================================================================* - * tty_opcl * - *===========================================================================*/ -PUBLIC int tty_opcl( - int op, /* operation, DEV_OPEN or DEV_CLOSE */ - dev_t dev, /* device to open or close */ - endpoint_t proc_e, /* process to open/close for */ - int flags /* mode bits and flags */ -) -{ -/* This procedure is called from the dmap struct on tty open/close. */ - - int r; - register struct fproc *rfp; - - assert(!IS_BDEV_RQ(op)); - - /* Add O_NOCTTY to the flags if this process is not a session leader, or - * if it already has a controlling tty, or if it is someone elses - * controlling tty. - */ - if (!(fp->fp_flags & FP_SESLDR) || fp->fp_tty != 0) { - flags |= O_NOCTTY; - } else { - for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - if(rfp->fp_pid == PID_FREE) continue; - if (rfp->fp_tty == dev) flags |= O_NOCTTY; - } - } - - r = gen_opcl(op, dev, proc_e, flags); - - /* Did this call make the tty the controlling tty? */ - if (r == 1) { - fp->fp_tty = dev; - r = OK; - } - - return(r); -} - - -/*===========================================================================* - * ctty_opcl * - *===========================================================================*/ -PUBLIC int ctty_opcl( - int op, /* operation, DEV_OPEN or DEV_CLOSE */ - dev_t UNUSED(dev), /* device to open or close */ - endpoint_t UNUSED(proc_e), /* process to open/close for */ - int UNUSED(flags) /* mode bits and flags */ -) -{ -/* This procedure is called from the dmap struct on opening or closing - * /dev/tty, the magic device that translates to the controlling tty. - */ - - assert(!IS_BDEV_RQ(op)); - - return(fp->fp_tty == 0 ? ENXIO : OK); -} - - -/*===========================================================================* - * pm_setsid * - *===========================================================================*/ -PUBLIC void pm_setsid(proc_e) -int proc_e; -{ -/* Perform the VFS side of the SETSID call, i.e. get rid of the controlling - * terminal of a process, and make the process a session leader. - */ - register struct fproc *rfp; - int slot; - - /* Make the process a session leader with no controlling tty. */ - okendpt(proc_e, &slot); - rfp = &fproc[slot]; - rfp->fp_flags |= FP_SESLDR; - rfp->fp_tty = 0; -} - - -/*===========================================================================* - * do_ioctl * - *===========================================================================*/ -PUBLIC int do_ioctl() -{ -/* Perform the ioctl(ls_fd, request, argx) system call (uses m2 fmt). */ - - int r = OK, suspend_reopen; - struct filp *f; - register struct vnode *vp; - dev_t dev; - - scratch(fp).file.fd_nr = m_in.ls_fd; - - if ((f = get_filp(scratch(fp).file.fd_nr, VNODE_READ)) == NULL) - return(err_code); - vp = f->filp_vno; /* get vnode pointer */ - if ((vp->v_mode & I_TYPE) != I_CHAR_SPECIAL && - (vp->v_mode & I_TYPE) != I_BLOCK_SPECIAL) { - r = ENOTTY; - } - - if (r == OK) { - suspend_reopen = (f->filp_state != FS_NORMAL); - dev = (dev_t) vp->v_sdev; - - if ((vp->v_mode & I_TYPE) == I_BLOCK_SPECIAL) - r = bdev_ioctl(dev, who_e, m_in.REQUEST, m_in.ADDRESS); - else - r = dev_io(VFS_DEV_IOCTL, dev, who_e, m_in.ADDRESS, cvu64(0), - m_in.REQUEST, f->filp_flags, suspend_reopen); - } - - unlock_filp(f); - - return(r); -} - - -/*===========================================================================* - * gen_io * - *===========================================================================*/ -PUBLIC int gen_io(driver_e, mess_ptr) -endpoint_t driver_e; /* which endpoint to call */ -message *mess_ptr; /* pointer to message for task */ -{ -/* All file system I/O ultimately comes down to I/O on major/minor device - * pairs. These lead to calls on the following routines via the dmap table. - */ - int r, status, proc_e = NONE, is_bdev; - - is_bdev = IS_BDEV_RQ(mess_ptr->m_type); - - if (!is_bdev) proc_e = mess_ptr->USER_ENDPT; - - r = sendrec(driver_e, mess_ptr); - if (r == OK) { - if (is_bdev) - status = mess_ptr->BDEV_STATUS; - else - status = mess_ptr->REP_STATUS; - if (status == ERESTART) - r = EDEADEPT; - } - if (r != OK) { - if (r == EDEADSRCDST || r == EDEADEPT) { - printf("VFS: dead driver %d\n", driver_e); - dmap_unmap_by_endpt(driver_e); - return(r); - } else if (r == ELOCKED) { - printf("VFS: ELOCKED talking to %d\n", driver_e); - return(r); - } - panic("call_task: can't send/receive: %d", r); - } - - /* Did the process we did the sendrec() for get a result? */ - if (!is_bdev && mess_ptr->REP_ENDPT != proc_e) { - printf("VFS: strange device reply from %d, type = %d, " - "proc = %d (not %d) (2) ignored\n", mess_ptr->m_source, - mess_ptr->m_type, proc_e, mess_ptr->REP_ENDPT); - - return(EIO); - } - - return(OK); -} - - -/*===========================================================================* - * asyn_io * - *===========================================================================*/ -PUBLIC int asyn_io(task_nr, mess_ptr) -int task_nr; /* which task to call */ -message *mess_ptr; /* pointer to message for task */ -{ -/* All file system I/O ultimately comes down to I/O on major/minor device - * pairs. These lead to calls on the following routines via the dmap table. - */ - - int r; - - assert(!IS_BDEV_RQ(mess_ptr->m_type)); - - fp->fp_sendrec = mess_ptr; /* Remember where result should be stored */ - r = asynsend3(task_nr, mess_ptr, AMF_NOREPLY); - - if (r != OK) panic("VFS: asynsend in asyn_io failed: %d", r); - - /* Fake a SUSPEND */ - mess_ptr->REP_STATUS = SUSPEND; - return(OK); -} - - -/*===========================================================================* - * ctty_io * - *===========================================================================*/ -PUBLIC int ctty_io( - endpoint_t UNUSED(task_nr), /* not used - for compatibility with dmap_t */ - message *mess_ptr /* pointer to message for task */ -) -{ -/* This routine is only called for one device, namely /dev/tty. Its job - * is to change the message to use the controlling terminal, instead of the - * major/minor pair for /dev/tty itself. - */ - - struct dmap *dp; - - if (fp->fp_tty == 0) { - /* No controlling tty present anymore, return an I/O error. */ - mess_ptr->REP_STATUS = EIO; - } else { - /* Substitute the controlling terminal device. */ - dp = &dmap[major(fp->fp_tty)]; - mess_ptr->DEVICE = minor(fp->fp_tty); - - if (dp->dmap_driver == NONE) { - printf("FS: ctty_io: no driver for dev\n"); - return(EIO); - } - - if (isokendpt(dp->dmap_driver, &dummyproc) != OK) { - printf("VFS: ctty_io: old driver %d\n", dp->dmap_driver); - return(EIO); - } - - (*dp->dmap_io)(dp->dmap_driver, mess_ptr); - } - - return(OK); -} - - -/*===========================================================================* - * no_dev * - *===========================================================================*/ -PUBLIC int no_dev( - int UNUSED(op), /* operation, DEV_OPEN or DEV_CLOSE */ - dev_t UNUSED(dev), /* device to open or close */ - int UNUSED(proc), /* process to open/close for */ - int UNUSED(flags) /* mode bits and flags */ -) -{ -/* Called when opening a nonexistent device. */ - return(ENODEV); -} - -/*===========================================================================* - * no_dev_io * - *===========================================================================*/ -PUBLIC int no_dev_io(endpoint_t UNUSED(proc), message *UNUSED(m)) -{ -/* Called when doing i/o on a nonexistent device. */ - printf("VFS: I/O on unmapped device number\n"); - return(EIO); -} - - -/*===========================================================================* - * clone_opcl * - *===========================================================================*/ -PUBLIC int clone_opcl( - int op, /* operation, DEV_OPEN or DEV_CLOSE */ - dev_t dev, /* device to open or close */ - int proc_e, /* process to open/close for */ - int flags /* mode bits and flags */ -) -{ -/* Some devices need special processing upon open. Such a device is "cloned", - * i.e. on a succesful open it is replaced by a new device with a new unique - * minor device number. This new device number identifies a new object (such - * as a new network connection) that has been allocated within a task. - */ - struct dmap *dp; - int r, minor_dev, major_dev; - message dev_mess; - - assert(!IS_BDEV_RQ(op)); - - /* Determine task dmap. */ - minor_dev = minor(dev); - major_dev = major(dev); - assert(major_dev >= 0 && major_dev < NR_DEVICES); - dp = &dmap[major_dev]; - assert(dp->dmap_driver != NONE); - - dev_mess.m_type = op; - dev_mess.DEVICE = minor_dev; - dev_mess.USER_ENDPT = proc_e; - dev_mess.COUNT = flags; - - if(isokendpt(dp->dmap_driver, &dummyproc) != OK) { - printf("VFS clone_opcl: bad driver endpoint for major %d (%d)\n", - major_dev, dp->dmap_driver); - return(ENXIO); - } - - /* Call the task. */ - r = (*dp->dmap_io)(dp->dmap_driver, &dev_mess); - if (r != OK) return(r); - - if (op == DEV_OPEN && dp->dmap_style == STYLE_CLONE_A) { - /* Wait for reply when driver is asynchronous */ - fp->fp_task = dp->dmap_driver; - worker_wait(); - } - - if (op == DEV_OPEN && dev_mess.REP_STATUS >= 0) { - if (dev_mess.REP_STATUS != minor_dev) { - struct vnode *vp; - struct node_details res; - - /* A new minor device number has been returned. - * Request PFS to create a temporary device file to hold it. - */ - - /* Device number of the new device. */ - dev = (dev & ~(BYTE << MINOR)) | (dev_mess.REP_STATUS << MINOR); - - /* Issue request */ - r = req_newnode(PFS_PROC_NR, fp->fp_effuid, fp->fp_effgid, - ALL_MODES | I_CHAR_SPECIAL, dev, &res); - if (r != OK) { - (void) clone_opcl(DEV_CLOSE, dev, proc_e, 0); - return r; - } - - /* Drop old node and use the new values */ - assert(FD_ISSET(scratch(fp).file.fd_nr, &fp->fp_filp_inuse)); - vp = fp->fp_filp[scratch(fp).file.fd_nr]->filp_vno; - - unlock_vnode(vp); - put_vnode(vp); - if ((vp = get_free_vnode()) == NULL) - return(err_code); - - lock_vnode(vp, VNODE_OPCL); - - vp->v_fs_e = res.fs_e; - vp->v_vmnt = NULL; - vp->v_dev = NO_DEV; - vp->v_fs_e = res.fs_e; - vp->v_inode_nr = res.inode_nr; - vp->v_mode = res.fmode; - vp->v_sdev = dev; - vp->v_fs_count = 1; - vp->v_ref_count = 1; - fp->fp_filp[scratch(fp).file.fd_nr]->filp_vno = vp; - } - dev_mess.REP_STATUS = OK; - } - return(dev_mess.REP_STATUS); -} - - -/*===========================================================================* - * bdev_up * - *===========================================================================*/ -PUBLIC void bdev_up(int maj) -{ - /* A new block device driver has been mapped in. This may affect both mounted - * file systems and open block-special files. - */ - int r, found, bits; - struct filp *rfilp; - struct vmnt *vmp; - struct vnode *vp; - char *label; - - if (maj < 0 || maj >= NR_DEVICES) panic("VFS: out-of-bound major"); - label = dmap[maj].dmap_label; - - /* Tell each affected mounted file system about the new endpoint. This code - * is currently useless, as driver endpoints do not change across restarts. - */ - for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) { - if (major(vmp->m_dev) != maj) continue; - - /* Send the driver label to the mounted file system. */ - if (OK != req_newdriver(vmp->m_fs_e, vmp->m_dev, label)) - printf("VFS dev_up: error sending new driver label to %d\n", - vmp->m_fs_e); - } - - /* For each block-special file that was previously opened on the affected - * device, we need to reopen it on the new driver. - */ - found = 0; - for (rfilp = filp; rfilp < &filp[NR_FILPS]; rfilp++) { - if (rfilp->filp_count < 1 || !(vp = rfilp->filp_vno)) continue; - if (major(vp->v_sdev) != maj) continue; - if (!S_ISBLK(vp->v_mode)) continue; - - /* Reopen the device on the driver, once per filp. */ - bits = mode_map[rfilp->filp_mode & O_ACCMODE]; - if ((r = bdev_open(vp->v_sdev, bits)) != OK) - printf("VFS: mounted dev %d/%d re-open failed: %d.\n", - maj, minor(vp->v_sdev), r); - - found = 1; - } - - /* If any block-special file was open for this major at all, also inform the - * root file system about the new driver. We do this even if the - * block-special file is linked to another mounted file system, merely - * because it is more work to check for that case. - */ - if (found) { - if (OK != req_newdriver(ROOT_FS_E, makedev(maj, 0), label)) - printf("VFSdev_up: error sending new driver label to %d\n", - ROOT_FS_E); - } -} - - -/*===========================================================================* - * cdev_up * - *===========================================================================*/ -PUBLIC void cdev_up(int maj) -{ - /* A new character device driver has been mapped in. - */ - int needs_reopen, fd_nr; - struct filp *rfilp; - struct fproc *rfp; - struct vnode *vp; - - /* Look for processes that are suspened in an OPEN call. Set FP_SUSP_REOPEN - * to indicate that this process was suspended before the call to dev_up. - */ - for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - if(rfp->fp_pid == PID_FREE) continue; - if(rfp->fp_blocked_on != FP_BLOCKED_ON_DOPEN) continue; - - fd_nr = scratch(rfp).file.fd_nr; - printf("VFS: dev_up: found process in FP_BLOCKED_ON_DOPEN, fd %d\n", - fd_nr); - rfilp = rfp->fp_filp[fd_nr]; - vp = rfilp->filp_vno; - if (!vp) panic("VFS: cdev_up: no vp"); - if ((vp->v_mode & I_TYPE) != I_CHAR_SPECIAL) continue; - if (major(vp->v_sdev) != maj) continue; - - rfp->fp_flags |= FP_SUSP_REOPEN; - } - - needs_reopen= FALSE; - for (rfilp = filp; rfilp < &filp[NR_FILPS]; rfilp++) { - if (rfilp->filp_count < 1 || !(vp = rfilp->filp_vno)) continue; - if (major(vp->v_sdev) != maj) continue; - if (!S_ISCHR(vp->v_mode)) continue; - - rfilp->filp_state = FS_NEEDS_REOPEN; - needs_reopen = TRUE; - } - - if (needs_reopen) - restart_reopen(maj); -} - -/*===========================================================================* - * open_reply * - *===========================================================================*/ -PUBLIC void open_reply(void) -{ - struct fproc *rfp; - endpoint_t proc_e; - int slot; - - proc_e = m_in.REP_ENDPT; - if (isokendpt(proc_e, &slot) != OK) return; - rfp = &fproc[slot]; - *rfp->fp_sendrec = m_in; - worker_signal(worker_get(rfp->fp_wtid)); /* Continue open */ -} - -/*===========================================================================* - * restart_reopen * - *===========================================================================*/ -PRIVATE void restart_reopen(maj) -int maj; -{ - int n, r, minor_dev, major_dev, fd_nr; - endpoint_t driver_e; - struct vnode *vp; - struct filp *rfilp; - struct fproc *rfp; - - if (maj < 0 || maj >= NR_DEVICES) panic("VFS: out-of-bound major"); - for (rfilp = filp; rfilp < &filp[NR_FILPS]; rfilp++) { - if (rfilp->filp_count < 1 || !(vp = rfilp->filp_vno)) continue; - if (rfilp->filp_state != FS_NEEDS_REOPEN) continue; - if ((vp->v_mode & I_TYPE) != I_CHAR_SPECIAL) continue; - - major_dev = major(vp->v_sdev); - minor_dev = minor(vp->v_sdev); - if (major_dev != maj) continue; - - if (!(rfilp->filp_flags & O_REOPEN)) { - /* File descriptor is to be closed when driver restarts. */ - n = invalidate_filp(rfilp); - if (n != rfilp->filp_count) { - printf("VFS: warning: invalidate/count " - "discrepancy (%d, %d)\n", n, rfilp->filp_count); - } - rfilp->filp_count = 0; - continue; - } - - r = dev_reopen(vp->v_sdev, rfilp-filp, vp->v_mode & (R_BIT|W_BIT)); - if (r == OK) return; - - /* Device could not be reopened. Invalidate all filps on that device.*/ - n = invalidate_filp(rfilp); - if (n != rfilp->filp_count) { - printf("VFS: warning: invalidate/count " - "discrepancy (%d, %d)\n", n, rfilp->filp_count); - } - rfilp->filp_count = 0; - printf("VFS: file on dev %d/%d re-open failed: %d; " - "invalidated %d fd's.\n", major_dev, minor_dev, r, n); - } - - /* Nothing more to re-open. Restart suspended processes */ - driver_e = dmap[maj].dmap_driver; - - for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - if(rfp->fp_pid == PID_FREE) continue; - if(rfp->fp_blocked_on == FP_BLOCKED_ON_OTHER && - rfp->fp_task == driver_e && (rfp->fp_flags & FP_SUSP_REOPEN)) { - rfp->fp_flags &= ~FP_SUSP_REOPEN; - rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; - reply(rfp->fp_endpoint, ERESTART); - } - } - - /* Look for processes that are suspened in an OPEN call */ - for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - if (rfp->fp_pid == PID_FREE) continue; - if (rfp->fp_blocked_on == FP_BLOCKED_ON_DOPEN || - !(rfp->fp_flags & FP_SUSP_REOPEN)) continue; - - fd_nr = scratch(rfp).file.fd_nr; - printf("VFS: restart_reopen: process in FP_BLOCKED_ON_DOPEN fd=%d\n", - fd_nr); - rfilp = rfp->fp_filp[fd_nr]; - - if (!rfilp) { - /* Open failed, and automatic reopen was not requested */ - rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; - FD_CLR(fd_nr, &rfp->fp_filp_inuse); - reply(rfp->fp_endpoint, EIO); - continue; - } - - vp = rfilp->filp_vno; - if (!vp) panic("VFS: restart_reopen: no vp"); - if ((vp->v_mode & I_TYPE) != I_CHAR_SPECIAL) continue; - if (major(vp->v_sdev) != maj) continue; - - rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; - reply(rfp->fp_endpoint, fd_nr); - } -} - - -/*===========================================================================* - * reopen_reply * - *===========================================================================*/ -PUBLIC void reopen_reply() -{ - endpoint_t driver_e; - int filp_no, status, maj; - struct filp *rfilp; - struct vnode *vp; - struct dmap *dp; - - driver_e = m_in.m_source; - filp_no = m_in.REP_ENDPT; - status = m_in.REP_STATUS; - - if (filp_no < 0 || filp_no >= NR_FILPS) { - printf("VFS: reopen_reply: bad filp number %d from driver %d\n", - filp_no, driver_e); - return; - } - - rfilp = &filp[filp_no]; - if (rfilp->filp_count < 1) { - printf("VFS: reopen_reply: filp number %d not inuse (from driver %d)\n", - filp_no, driver_e); - return; - } - - vp = rfilp->filp_vno; - if (!vp) { - printf("VFS: reopen_reply: no vnode for filp number %d (from driver " - "%d)\n", filp_no, driver_e); - return; - } - - if (rfilp->filp_state != FS_NEEDS_REOPEN) { - printf("VFS: reopen_reply: bad state %d for filp number %d" - " (from driver %d)\n", rfilp->filp_state, filp_no, driver_e); - return; - } - - if ((vp->v_mode & I_TYPE) != I_CHAR_SPECIAL) { - printf("VFS: reopen_reply: bad mode 0%o for filp number %d" - " (from driver %d)\n", vp->v_mode, filp_no, driver_e); - return; - } - - maj = major(vp->v_sdev); - dp = &dmap[maj]; - if (dp->dmap_driver != driver_e) { - printf("VFS: reopen_reply: bad major %d for filp number %d " - "(from driver %d, current driver is %d)\n", maj, filp_no, - driver_e, dp->dmap_driver); - return; - } - - if (status == OK) { - rfilp->filp_state= FS_NORMAL; - } else { - printf("VFS: reopen_reply: should handle error status\n"); - return; - } - - restart_reopen(maj); -} diff --git a/servers/avfs/dmap.c b/servers/avfs/dmap.c deleted file mode 100644 index eb5d13b1b..000000000 --- a/servers/avfs/dmap.c +++ /dev/null @@ -1,266 +0,0 @@ -/* This file contains the table with device <-> driver mappings. It also - * contains some routines to dynamically add and/ or remove device drivers - * or change mappings. - */ - -#include "fs.h" -#include -#include -#include -#include -#include -#include -#include "fproc.h" -#include "dmap.h" -#include "param.h" - -/* The order of the entries in the table determines the mapping between major - * device numbers and device drivers. Character and block devices - * can be intermixed at random. The ordering determines the device numbers in - * /dev. Note that the major device numbers used in /dev are NOT the same as - * the process numbers of the device drivers. See for mappings. - */ - -struct dmap dmap[NR_DEVICES]; - -#define DT_EMPTY { no_dev, no_dev_io, NONE, "", 0, STYLE_NDEV, NULL } - -/*===========================================================================* - * do_mapdriver * - *===========================================================================*/ -PUBLIC int do_mapdriver() -{ -/* Create a device->driver mapping. RS will tell us which major is driven by - * this driver, what type of device it is (regular, TTY, asynchronous, clone, - * etc), and its label. This label is registered with DS, and allows us to - * retrieve the driver's endpoint. - */ - int r, flags, major; - endpoint_t endpoint; - vir_bytes label_vir; - size_t label_len; - char label[LABEL_MAX]; - - /* Only RS can map drivers. */ - if (who_e != RS_PROC_NR) return(EPERM); - - /* Get the label */ - label_vir = (vir_bytes) m_in.md_label; - label_len = (size_t) m_in.md_label_len; - - if (label_len+1 > sizeof(label)) { /* Can we store this label? */ - printf("VFS: do_mapdriver: label too long\n"); - return(EINVAL); - } - r = sys_vircopy(who_e, D, label_vir, SELF, D, (vir_bytes) label, label_len); - if (r != OK) { - printf("VFS: do_mapdriver: sys_vircopy failed: %d\n", r); - return(EINVAL); - } - label[label_len] = '\0'; /* Terminate label */ - - /* Now we know how the driver is called, fetch its endpoint */ - r = ds_retrieve_label_endpt(label, &endpoint); - if (r != OK) { - printf("VFS: do_mapdriver: label '%s' unknown\n", label); - return(EINVAL); - } - - /* Try to update device mapping. */ - major = m_in.md_major; - flags = m_in.md_flags; - - return map_driver(label, major, endpoint, m_in.md_style, flags); -} - -/*===========================================================================* - * map_driver * - *===========================================================================*/ -PUBLIC int map_driver(label, major, proc_nr_e, style, flags) -const char *label; /* name of the driver */ -int major; /* major number of the device */ -endpoint_t proc_nr_e; /* process number of the driver */ -int style; /* style of the device */ -int flags; /* device flags */ -{ -/* Add a new device driver mapping in the dmap table. If the proc_nr is set to - * NONE, we're supposed to unmap it. - */ - - int slot; - size_t len; - struct dmap *dp; - - /* Get pointer to device entry in the dmap table. */ - if (major < 0 || major >= NR_DEVICES) return(ENODEV); - dp = &dmap[major]; - - /* Check if we're supposed to unmap it. */ - if (proc_nr_e == NONE) { - dp->dmap_opcl = no_dev; - dp->dmap_io = no_dev_io; - dp->dmap_driver = NONE; - dp->dmap_flags = flags; - return(OK); - } - - /* Check process number of new driver if it was alive before mapping */ - if (! (flags & DRV_FORCED)) { - struct fproc *rfp; - - if (isokendpt(proc_nr_e, &slot) != OK) - return(EINVAL); - - rfp = &fproc[slot]; - rfp->fp_flags |= FP_SYS_PROC; /* Process is a driver */ - } - - if (label != NULL) { - len = strlen(label); - if (len+1 > sizeof(dp->dmap_label)) - panic("VFS: map_driver: label too long: %d", len); - strcpy(dp->dmap_label, label); - } - - /* Store driver I/O routines based on type of device */ - switch (style) { - case STYLE_DEV: - dp->dmap_opcl = gen_opcl; - dp->dmap_io = gen_io; - break; - case STYLE_DEVA: - dp->dmap_opcl = gen_opcl; - dp->dmap_io = asyn_io; - break; - case STYLE_TTY: - dp->dmap_opcl = tty_opcl; - dp->dmap_io = gen_io; - break; - case STYLE_CTTY: - dp->dmap_opcl = ctty_opcl; - dp->dmap_io = ctty_io; - break; - case STYLE_CLONE: - dp->dmap_opcl = clone_opcl; - dp->dmap_io = gen_io; - break; - case STYLE_CLONE_A: - dp->dmap_opcl = clone_opcl; - dp->dmap_io = asyn_io; - break; - default: - return(EINVAL); - } - - dp->dmap_driver = proc_nr_e; - dp->dmap_flags = flags; - dp->dmap_style = style; - - return(OK); -} - -/*===========================================================================* - * dmap_unmap_by_endpt * - *===========================================================================*/ -PUBLIC void dmap_unmap_by_endpt(endpoint_t proc_e) -{ -/* Lookup driver in dmap table by endpoint and unmap it */ - int major, r; - - for (major = 0; major < NR_DEVICES; major++) { - if (dmap_driver_match(proc_e, major)) { - /* Found driver; overwrite it with a NULL entry */ - if ((r = map_driver(NULL, major, NONE, 0, 0)) != OK) { - printf("VFS: unmapping driver %d for major %d failed:" - " %d\n", proc_e, major, r); - } - } - } -} - -/*===========================================================================* - * map_service * - *===========================================================================*/ -PUBLIC int map_service(struct rprocpub *rpub) -{ -/* Map a new service by storing its device driver properties. */ - int r; - - /* Not a driver, nothing more to do. */ - if(rpub->dev_nr == NO_DEV) return(OK); - - /* Map driver. */ - r = map_driver(rpub->label, rpub->dev_nr, rpub->endpoint, rpub->dev_style, - rpub->dev_flags); - if(r != OK) return(r); - - /* If driver has two major numbers associated, also map the other one. */ - if(rpub->dev_style2 != STYLE_NDEV) { - r = map_driver(rpub->label, rpub->dev_nr+1, rpub->endpoint, - rpub->dev_style2, rpub->dev_flags); - if(r != OK) return(r); - } - - return(OK); -} - -/*===========================================================================* - * init_dmap * - *===========================================================================*/ -PUBLIC void init_dmap() -{ -/* Initialize the table with empty device <-> driver mappings. */ - int i; - struct dmap dmap_default = DT_EMPTY; - - for (i = 0; i < NR_DEVICES; i++) - dmap[i] = dmap_default; -} - -/*===========================================================================* - * dmap_driver_match * - *===========================================================================*/ -PUBLIC int dmap_driver_match(endpoint_t proc, int major) -{ - if (major < 0 || major >= NR_DEVICES) return(0); - if (dmap[major].dmap_driver != NONE && dmap[major].dmap_driver == proc) - return(1); - - return(0); -} - -/*===========================================================================* - * dmap_endpt_up * - *===========================================================================*/ -PUBLIC void dmap_endpt_up(endpoint_t proc_e, int is_blk) -{ -/* A device driver with endpoint proc_e has been restarted. Go tell everyone - * that might be blocking on it that this device is 'up'. - */ - - int major; - for (major = 0; major < NR_DEVICES; major++) { - if (dmap_driver_match(proc_e, major)) { - if (is_blk) - bdev_up(major); - else - cdev_up(major); - } - } -} - -/*===========================================================================* - * get_dmap * - *===========================================================================*/ -PUBLIC struct dmap *get_dmap(endpoint_t proc_e) -{ -/* See if 'proc_e' endpoint belongs to a valid dmap entry. If so, return a - * pointer */ - - int major; - for (major = 0; major < NR_DEVICES; major++) - if (dmap_driver_match(proc_e, major)) - return(&dmap[major]); - - return(NULL); -} diff --git a/servers/avfs/dmap.h b/servers/avfs/dmap.h deleted file mode 100644 index 6a83bf551..000000000 --- a/servers/avfs/dmap.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __VFS_DMAP_H__ -#define __VFS_DMAP_H__ - -/* -dmap.h -*/ - -/*===========================================================================* - * Device <-> Driver Table * - *===========================================================================*/ - -/* Device table. This table is indexed by major device number. It provides - * the link between major device numbers and the routines that process them. - * The table can be update dynamically. The field 'dmap_flags' describe an - * entry's current status and determines what control options are possible. - */ - -extern struct dmap { - int _PROTOTYPE ((*dmap_opcl), (int, dev_t, int, int) ); - int _PROTOTYPE ((*dmap_io), (int, message *) ); - endpoint_t dmap_driver; - char dmap_label[LABEL_MAX]; - int dmap_flags; - int dmap_style; - struct filp *dmap_sel_filp; -} dmap[]; - -#endif diff --git a/servers/avfs/exec.c b/servers/avfs/exec.c deleted file mode 100644 index 3f6e4a7e2..000000000 --- a/servers/avfs/exec.c +++ /dev/null @@ -1,721 +0,0 @@ -/* This file handles the EXEC system call. It performs the work as follows: - * - see if the permissions allow the file to be executed - * - read the header and extract the sizes - * - fetch the initial args and environment from the user space - * - allocate the memory for the new process - * - copy the initial stack from PM to the process - * - read in the text and data segments and copy to the process - * - take care of setuid and setgid bits - * - fix up 'mproc' table - * - tell kernel about EXEC - * - save offset to initial argc (for ps) - * - * The entry points into this file are: - * pm_exec: perform the EXEC system call - */ - -#include "fs.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "fproc.h" -#include "path.h" -#include "param.h" -#include "vnode.h" -#include -#include -#include -#include "exec.h" - -FORWARD _PROTOTYPE( void lock_exec, (void) ); -FORWARD _PROTOTYPE( void unlock_exec, (void) ); -FORWARD _PROTOTYPE( int exec_newmem, (int proc_e, vir_bytes text_addr, vir_bytes text_bytes, - vir_bytes data_addr, vir_bytes data_bytes, - vir_bytes tot_bytes, vir_bytes frame_len, int sep_id, - int is_elf, dev_t st_dev, ino_t st_ino, time_t ctime, - char *progname, int new_uid, int new_gid, - vir_bytes *stack_topp, int *load_textp, - int *setugidp) ); -FORWARD _PROTOTYPE( int is_script, (const char *exec_hdr, size_t exec_len)); -FORWARD _PROTOTYPE( int patch_stack, (struct vnode *vp, char stack[ARG_MAX], - vir_bytes *stk_bytes, char path[PATH_MAX]) ); -FORWARD _PROTOTYPE( int insert_arg, (char stack[ARG_MAX], vir_bytes *stk_bytes, - char *arg, int replace) ); -FORWARD _PROTOTYPE( void patch_ptr, (char stack[ARG_MAX], vir_bytes base)); -FORWARD _PROTOTYPE( void clo_exec, (struct fproc *rfp) ); -FORWARD _PROTOTYPE( int read_seg, (struct vnode *vp, off_t off, int proc_e, - int seg, vir_bytes seg_addr, - phys_bytes seg_bytes) ); -FORWARD _PROTOTYPE( int load_aout, (struct exec_info *execi) ); -FORWARD _PROTOTYPE( int load_elf, (struct exec_info *execi) ); -FORWARD _PROTOTYPE( int map_header, (char **exec_hdr, - const struct vnode *vp) ); - -#define PTRSIZE sizeof(char *) /* Size of pointers in argv[] and envp[]. */ - -/* Array of loaders for different object file formats */ -struct exec_loaders { - int (*load_object)(struct exec_info *); -}; - -PRIVATE const struct exec_loaders exec_loaders[] = { - { load_aout }, - { load_elf }, - { NULL } -}; - -PRIVATE char hdr[PAGE_SIZE]; /* Assume that header is not larger than a page */ - -/*===========================================================================* - * lock_exec * - *===========================================================================*/ -PRIVATE void lock_exec(void) -{ - message org_m_in; - struct fproc *org_fp; - struct worker_thread *org_self; - - /* First try to get it right off the bat */ - if (mutex_trylock(&exec_lock) == 0) - return; - - org_m_in = m_in; - org_fp = fp; - org_self = self; - - if (mutex_lock(&exec_lock) != 0) - panic("Could not obtain lock on exec"); - - m_in = org_m_in; - fp = org_fp; - self = org_self; -} - -/*===========================================================================* - * unlock_exec * - *===========================================================================*/ -PRIVATE void unlock_exec(void) -{ - if (mutex_unlock(&exec_lock) != 0) - panic("Could not release lock on exec"); -} - -/*===========================================================================* - * pm_exec * - *===========================================================================*/ -PUBLIC int pm_exec(int proc_e, char *path, vir_bytes path_len, char *frame, - vir_bytes frame_len, vir_bytes *pc) -{ -/* Perform the execve(name, argv, envp) call. The user library builds a - * complete stack image, including pointers, args, environ, etc. The stack - * is copied to a buffer inside VFS, and then to the new core image. - */ - int r, r1, round, slot; - vir_bytes vsp; - struct fproc *rfp; - struct vnode *vp; - struct vmnt *vmp; - char *cp; - static char mbuf[ARG_MAX]; /* buffer for stack and zeroes */ - struct exec_info execi; - int i; - char fullpath[PATH_MAX]; - struct lookup resolve; - - lock_exec(); - - okendpt(proc_e, &slot); - rfp = fp = &fproc[slot]; - vp = NULL; - - lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); - resolve.l_vmnt_lock = VMNT_READ; - resolve.l_vnode_lock = VNODE_READ; - - /* Get the exec file name. */ - if ((r = fetch_name(path, path_len, 0, fullpath)) != OK) - goto pm_execfinal; - - /* Fetch the stack from the user before destroying the old core image. */ - if (frame_len > ARG_MAX) { - r = ENOMEM; /* stack too big */ - goto pm_execfinal; - } - r = sys_datacopy(proc_e, (vir_bytes) frame, SELF, (vir_bytes) mbuf, - (phys_bytes) frame_len); - if (r != OK) { /* can't fetch stack (e.g. bad virtual addr) */ - printf("VFS: pm_exec: sys_datacopy failed\n"); - goto pm_execfinal; - } - - /* The default is to keep the original user and group IDs */ - execi.new_uid = rfp->fp_effuid; - execi.new_gid = rfp->fp_effgid; - - for (round = 0; round < 2; round++) { - /* round = 0 (first attempt), or 1 (interpreted script) */ - /* Save the name of the program */ - (cp = strrchr(fullpath, '/')) ? cp++ : (cp = fullpath); - - strncpy(execi.progname, cp, PROC_NAME_LEN-1); - execi.progname[PROC_NAME_LEN-1] = '\0'; - execi.setugid = 0; - - /* Open executable */ - if ((vp = eat_path(&resolve, fp)) == NULL) { - r = err_code; - goto pm_execfinal; - } - execi.vp = vp; - unlock_vmnt(vmp); - - if ((vp->v_mode & I_TYPE) != I_REGULAR) - r = ENOEXEC; - else if ((r1 = forbidden(fp, vp, X_BIT)) != OK) - r = r1; - else - r = req_stat(vp->v_fs_e, vp->v_inode_nr, VFS_PROC_NR, - (char *) &(execi.sb), 0, 0); - if (r != OK) goto pm_execfinal; - - if (round == 0) { - /* Deal with setuid/setgid executables */ - if (vp->v_mode & I_SET_UID_BIT) { - execi.new_uid = vp->v_uid; - execi.setugid = 1; - } - if (vp->v_mode & I_SET_GID_BIT) { - execi.new_gid = vp->v_gid; - execi.setugid = 1; - } - } - - r = map_header(&execi.hdr, execi.vp); - if (r != OK) goto pm_execfinal; - - if (!is_script(execi.hdr, execi.vp->v_size) || round != 0) - break; - - /* Get fresh copy of the file name. */ - if ((r = fetch_name(path, path_len, 0, fullpath)) != OK) - printf("VFS pm_exec: 2nd fetch_name failed\n"); - else - r = patch_stack(vp, mbuf, &frame_len, fullpath); - - unlock_vnode(vp); - put_vnode(vp); - vp = NULL; - if (r != OK) goto pm_execfinal; - } - - execi.proc_e = proc_e; - execi.frame_len = frame_len; - - for (i = 0; exec_loaders[i].load_object != NULL; i++) { - r = (*exec_loaders[i].load_object)(&execi); - /* Loaded successfully, so no need to try other loaders */ - if (r == OK) break; - } - - if (r != OK) { /* No exec loader could load the object */ - r = ENOEXEC; - goto pm_execfinal; - } - - /* Save off PC */ - *pc = execi.pc; - - /* Patch up stack and copy it from VFS to new core image. */ - vsp = execi.stack_top; - vsp -= frame_len; - patch_ptr(mbuf, vsp); - if ((r = sys_datacopy(SELF, (vir_bytes) mbuf, proc_e, (vir_bytes) vsp, - (phys_bytes)frame_len)) != OK) { - printf("VFS: datacopy failed (%d) trying to copy to %lu\n", r, vsp); - goto pm_execfinal; - } - - if (r != OK) goto pm_execfinal; - clo_exec(rfp); - - if (execi.setugid) { - /* If after loading the image we're still allowed to run with - * setuid or setgid, change credentials now */ - rfp->fp_effuid = execi.new_uid; - rfp->fp_effgid = execi.new_gid; - } - -pm_execfinal: - if (vp != NULL) { - unlock_vnode(vp); - put_vnode(vp); - } - unlock_exec(); - return(r); -} - -/*===========================================================================* - * load_aout * - *===========================================================================*/ -PRIVATE int load_aout(struct exec_info *execi) -{ - int r; - struct vnode *vp; - int proc_e; - off_t off; - int hdrlen; - int sep_id; - vir_bytes text_bytes, data_bytes, bss_bytes; - phys_bytes tot_bytes; /* total space for program, including gap */ - - assert(execi != NULL); - assert(execi->hdr != NULL); - assert(execi->vp != NULL); - - proc_e = execi->proc_e; - vp = execi->vp; - - /* Read the file header and extract the segment sizes. */ - r = read_header_aout(execi->hdr, execi->vp->v_size, &sep_id, - &text_bytes, &data_bytes, &bss_bytes, - &tot_bytes, &execi->pc, &hdrlen); - if (r != OK) return(r); - - r = exec_newmem(proc_e, 0 /* text_addr */, text_bytes, - 0 /* data_addr */, data_bytes + bss_bytes, tot_bytes, - execi->frame_len, sep_id, 0 /* is_elf */, vp->v_dev, vp->v_inode_nr, - execi->sb.st_ctime, - execi->progname, execi->new_uid, execi->new_gid, - &execi->stack_top, &execi->load_text, &execi->setugid); - - if (r != OK) { - printf("VFS: load_aout: exec_newmem failed: %d\n", r); - return(r); - } - - off = hdrlen; - - /* Read in text and data segments. */ - if (execi->load_text) - r = read_seg(vp, off, proc_e, T, 0, text_bytes); - off += text_bytes; - if (r == OK) - r = read_seg(vp, off, proc_e, D, 0, data_bytes); - - return(r); -} - -/*===========================================================================* - * load_elf * - *===========================================================================*/ -PRIVATE int load_elf(struct exec_info *execi) -{ - int r; - struct vnode *vp; - int proc_e; - phys_bytes tot_bytes; /* total space for program, including gap */ - vir_bytes text_vaddr, text_paddr, text_filebytes, text_membytes; - vir_bytes data_vaddr, data_paddr, data_filebytes, data_membytes; - off_t text_offset, data_offset; - int sep_id, is_elf; - - assert(execi != NULL); - assert(execi->hdr != NULL); - assert(execi->vp != NULL); - - proc_e = execi->proc_e; - vp = execi->vp; - - /* Read the file header and extract the segment sizes. */ - r = read_header_elf(execi->hdr, &text_vaddr, &text_paddr, - &text_filebytes, &text_membytes, - &data_vaddr, &data_paddr, - &data_filebytes, &data_membytes, - &execi->pc, &text_offset, &data_offset); - if (r != OK) return(r); - - sep_id = 0; - is_elf = 1; - tot_bytes = 0; /* Use default stack size */ - r = exec_newmem(proc_e, - trunc_page(text_vaddr), text_membytes, - trunc_page(data_vaddr), data_membytes, - tot_bytes, execi->frame_len, sep_id, is_elf, - vp->v_dev, vp->v_inode_nr, execi->sb.st_ctime, - execi->progname, execi->new_uid, execi->new_gid, - &execi->stack_top, &execi->load_text, &execi->setugid); - - if (r != OK) { - printf("VFS: load_elf: exec_newmem failed: %d\n", r); - return(r); - } - - /* Read in text and data segments. */ - if (execi->load_text) - r = read_seg(vp, text_offset, proc_e, T, text_vaddr, text_filebytes); - - if (r == OK) - r = read_seg(vp, data_offset, proc_e, D, data_vaddr, data_filebytes); - - return(r); -} - -/*===========================================================================* - * exec_newmem * - *===========================================================================*/ -PRIVATE int exec_newmem( - int proc_e, - vir_bytes text_addr, - vir_bytes text_bytes, - vir_bytes data_addr, - vir_bytes data_bytes, - vir_bytes tot_bytes, - vir_bytes frame_len, - int sep_id, - int is_elf, - dev_t st_dev, - ino_t st_ino, - time_t ctime, - char *progname, - int new_uid, - int new_gid, - vir_bytes *stack_topp, - int *load_textp, - int *setugidp -) -{ -/* Allocate a new memory map for a process that tries to exec */ - int r; - struct exec_newmem e; - message m; - - assert(setugidp != NULL); - - e.text_addr = text_addr; - e.text_bytes = text_bytes; - e.data_addr = data_addr; - e.data_bytes = data_bytes; - e.tot_bytes = tot_bytes; - e.args_bytes = frame_len; - e.sep_id = sep_id; - e.is_elf = is_elf; - e.st_dev = st_dev; - e.st_ino = st_ino; - e.enst_ctime = ctime; - e.new_uid = new_uid; - e.new_gid = new_gid; - e.setugid = *setugidp; - strncpy(e.progname, progname, sizeof(e.progname)-1); - e.progname[sizeof(e.progname)-1] = '\0'; - - m.m_type = EXEC_NEWMEM; - m.EXC_NM_PROC = proc_e; - m.EXC_NM_PTR = (char *)&e; - if ((r = sendrec(PM_PROC_NR, &m)) != OK) return(r); - - *stack_topp = m.m1_i1; - *load_textp = !!(m.m1_i2 & EXC_NM_RF_LOAD_TEXT); - *setugidp = !!(m.m1_i2 & EXC_NM_RF_ALLOW_SETUID); - - return(m.m_type); -} - -/*===========================================================================* - * is_script * - *===========================================================================*/ -PRIVATE int is_script(const char *exec_hdr, size_t exec_len) -{ -/* Is Interpreted script? */ - assert(exec_hdr != NULL); - - return(exec_hdr[0] == '#' && exec_hdr[1] == '!' && exec_len >= 2); -} - -/*===========================================================================* - * patch_stack * - *===========================================================================*/ -PRIVATE int patch_stack(vp, stack, stk_bytes, path) -struct vnode *vp; /* pointer for open script file */ -char stack[ARG_MAX]; /* pointer to stack image within VFS */ -vir_bytes *stk_bytes; /* size of initial stack */ -char path[PATH_MAX]; /* path to script file */ -{ -/* Patch the argument vector to include the path name of the script to be - * interpreted, and all strings on the #! line. Returns the path name of - * the interpreter. - */ - enum { INSERT=FALSE, REPLACE=TRUE }; - int n, r; - off_t pos; - char *sp, *interp = NULL; - u64_t new_pos; - unsigned int cum_io; - char buf[_MAX_BLOCK_SIZE]; - - /* Make 'path' the new argv[0]. */ - if (!insert_arg(stack, stk_bytes, path, REPLACE)) return(ENOMEM); - - pos = 0; /* Read from the start of the file */ - - /* Issue request */ - r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, cvul64(pos), READING, - VFS_PROC_NR, buf, _MAX_BLOCK_SIZE, &new_pos, &cum_io); - if (r != OK) return(r); - - n = vp->v_size; - if (n > _MAX_BLOCK_SIZE) - n = _MAX_BLOCK_SIZE; - if (n < 2) return ENOEXEC; - - sp = &(buf[2]); /* just behind the #! */ - n -= 2; - if (n > PATH_MAX) n = PATH_MAX; - - /* Use the 'path' variable for temporary storage */ - memcpy(path, sp, n); - - if ((sp = memchr(path, '\n', n)) == NULL) /* must be a proper line */ - return(ENOEXEC); - - /* Move sp backwards through script[], prepending each string to stack. */ - for (;;) { - /* skip spaces behind argument. */ - while (sp > path && (*--sp == ' ' || *sp == '\t')) {} - if (sp == path) break; - - sp[1] = 0; - /* Move to the start of the argument. */ - while (sp > path && sp[-1] != ' ' && sp[-1] != '\t') --sp; - - interp = sp; - if (!insert_arg(stack, stk_bytes, sp, INSERT)) { - printf("VFS: patch_stack: insert_arg failed\n"); - return(ENOMEM); - } - } - - if(!interp) - return ENOEXEC; - - /* Round *stk_bytes up to the size of a pointer for alignment contraints. */ - *stk_bytes= ((*stk_bytes + PTRSIZE - 1) / PTRSIZE) * PTRSIZE; - - if (interp != path) - memmove(path, interp, strlen(interp)+1); - return(OK); -} - -/*===========================================================================* - * insert_arg * - *===========================================================================*/ -PRIVATE int insert_arg( -char stack[ARG_MAX], /* pointer to stack image within PM */ -vir_bytes *stk_bytes, /* size of initial stack */ -char *arg, /* argument to prepend/replace as new argv[0] */ -int replace -) -{ -/* Patch the stack so that arg will become argv[0]. Be careful, the stack may - * be filled with garbage, although it normally looks like this: - * nargs argv[0] ... argv[nargs-1] NULL envp[0] ... NULL - * followed by the strings "pointed" to by the argv[i] and the envp[i]. The - * pointers are really offsets from the start of stack. - * Return true iff the operation succeeded. - */ - int offset, a0, a1, old_bytes = *stk_bytes; - - /* Prepending arg adds at least one string and a zero byte. */ - offset = strlen(arg) + 1; - - a0 = (int) ((char **) stack)[1]; /* argv[0] */ - if (a0 < 4 * PTRSIZE || a0 >= old_bytes) return(FALSE); - - a1 = a0; /* a1 will point to the strings to be moved */ - if (replace) { - /* Move a1 to the end of argv[0][] (argv[1] if nargs > 1). */ - do { - if (a1 == old_bytes) return(FALSE); - --offset; - } while (stack[a1++] != 0); - } else { - offset += PTRSIZE; /* new argv[0] needs new pointer in argv[] */ - a0 += PTRSIZE; /* location of new argv[0][]. */ - } - - /* stack will grow by offset bytes (or shrink by -offset bytes) */ - if ((*stk_bytes += offset) > ARG_MAX) return(FALSE); - - /* Reposition the strings by offset bytes */ - memmove(stack + a1 + offset, stack + a1, old_bytes - a1); - - strcpy(stack + a0, arg); /* Put arg in the new space. */ - - if (!replace) { - /* Make space for a new argv[0]. */ - memmove(stack + 2 * PTRSIZE, stack + 1 * PTRSIZE, a0 - 2 * PTRSIZE); - - ((char **) stack)[0]++; /* nargs++; */ - } - /* Now patch up argv[] and envp[] by offset. */ - patch_ptr(stack, (vir_bytes) offset); - ((char **) stack)[1] = (char *) a0; /* set argv[0] correctly */ - return(TRUE); -} - - -/*===========================================================================* - * patch_ptr * - *===========================================================================*/ -PRIVATE void patch_ptr( -char stack[ARG_MAX], /* pointer to stack image within PM */ -vir_bytes base /* virtual address of stack base inside user */ -) -{ -/* When doing an exec(name, argv, envp) call, the user builds up a stack - * image with arg and env pointers relative to the start of the stack. Now - * these pointers must be relocated, since the stack is not positioned at - * address 0 in the user's address space. - */ - - char **ap, flag; - vir_bytes v; - - flag = 0; /* counts number of 0-pointers seen */ - ap = (char **) stack; /* points initially to 'nargs' */ - ap++; /* now points to argv[0] */ - while (flag < 2) { - if (ap >= (char **) &stack[ARG_MAX]) return; /* too bad */ - if (*ap != NULL) { - v = (vir_bytes) *ap; /* v is relative pointer */ - v += base; /* relocate it */ - *ap = (char *) v; /* put it back */ - } else { - flag++; - } - ap++; - } -} - -/*===========================================================================* - * read_seg * - *===========================================================================*/ -PRIVATE int read_seg( -struct vnode *vp, /* inode descriptor to read from */ -off_t off, /* offset in file */ -int proc_e, /* process number (endpoint) */ -int seg, /* T, D, or S */ -vir_bytes seg_addr, /* address to load segment */ -phys_bytes seg_bytes /* how much is to be transferred? */ -) -{ -/* - * The byte count on read is usually smaller than the segment count, because - * a segment is padded out to a click multiple, and the data segment is only - * partially initialized. - */ - int r; - unsigned n, o; - u64_t new_pos; - unsigned int cum_io; - static char buf[128 * 1024]; - - assert((seg == T)||(seg == D)); - - /* Make sure that the file is big enough */ - if (vp->v_size < off+seg_bytes) return(EIO); - - if (seg == T) { - /* We have to use a copy loop until safecopies support segments */ - o = 0; - while (o < seg_bytes) { - n = seg_bytes - o; - if (n > sizeof(buf)) - n = sizeof(buf); - - if ((r = req_readwrite(vp->v_fs_e,vp->v_inode_nr,cvul64(off+o), - READING, VFS_PROC_NR, buf, - n, &new_pos, &cum_io)) != OK) { - printf("VFS: read_seg: req_readwrite failed (text)\n"); - return(r); - } - - if (cum_io != n) { - printf( - "VFSread_seg segment has not been read properly by exec() \n"); - return(EIO); - } - - if ((r = sys_vircopy(VFS_PROC_NR, D, (vir_bytes)buf, proc_e, - seg, seg_addr + o, n)) != OK) { - printf("VFS: read_seg: copy failed (text)\n"); - return(r); - } - - o += n; - } - return(OK); - } else if (seg == D) { - - if ((r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, cvul64(off), READING, - proc_e, (char*)seg_addr, seg_bytes, - &new_pos, &cum_io)) != OK) { - printf("VFS: read_seg: req_readwrite failed (data)\n"); - return(r); - } - - if (r == OK && cum_io != seg_bytes) - printf("VFS: read_seg segment has not been read properly by exec()\n"); - - return(r); - } - - return(OK); -} - - -/*===========================================================================* - * clo_exec * - *===========================================================================*/ -PRIVATE void clo_exec(struct fproc *rfp) -{ -/* Files can be marked with the FD_CLOEXEC bit (in fp->fp_cloexec). - */ - int i; - - /* Check the file desriptors one by one for presence of FD_CLOEXEC. */ - for (i = 0; i < OPEN_MAX; i++) - if ( FD_ISSET(i, &rfp->fp_cloexec_set)) - (void) close_fd(rfp, i); -} - -/*===========================================================================* - * map_header * - *===========================================================================*/ -PRIVATE int map_header(char **exec_hdr, const struct vnode *vp) -{ - int r; - u64_t new_pos; - unsigned int cum_io; - off_t pos; - - pos = 0; /* Read from the start of the file */ - - r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, cvul64(pos), READING, - VFS_PROC_NR, hdr, MIN(vp->v_size, PAGE_SIZE), - &new_pos, &cum_io); - if (r != OK) { - printf("VFS: exec: map_header: req_readwrite failed\n"); - return(r); - } - - *exec_hdr = hdr; - return(OK); -} diff --git a/servers/avfs/exec.h b/servers/avfs/exec.h deleted file mode 100644 index ddf6e5a5f..000000000 --- a/servers/avfs/exec.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _VFS_EXEC_H_ -#define _VFS_EXEC_H_ 1 - -struct exec_info { - int proc_e; /* Process endpoint */ - char *hdr; /* Exec file's header */ - vir_bytes pc; /* Entry point of exec file */ - vir_bytes stack_top; /* Top of the stack */ - vir_bytes frame_len; /* Stack size */ - uid_t new_uid; /* Process UID after exec */ - gid_t new_gid; /* Process GID after exec */ - int load_text; /* Load text section? */ - int setugid; /* Allow set{u,g}id execution? */ - struct vnode *vp; /* Exec file's vnode */ - struct stat sb; /* Exec file's stat structure */ - char progname[PROC_NAME_LEN]; /* Program name */ -}; - -#endif /* !_VFS_EXEC_H_ */ diff --git a/servers/avfs/file.h b/servers/avfs/file.h deleted file mode 100644 index 52a5773c6..000000000 --- a/servers/avfs/file.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef __VFS_FILE_H__ -#define __VFS_FILE_H__ - -/* This is the filp table. It is an intermediary between file descriptors and - * inodes. A slot is free if filp_count == 0. - */ - -EXTERN struct filp { - mode_t filp_mode; /* RW bits, telling how file is opened */ - int filp_flags; /* flags from open and fcntl */ - int filp_state; /* state for crash recovery */ - int filp_count; /* how many file descriptors share this slot?*/ - struct vnode *filp_vno; /* vnode belonging to this file */ - u64_t filp_pos; /* file position */ - mutex_t filp_lock; /* lock to gain exclusive access */ - struct fproc *filp_softlock; /* if not NULL; this filp didn't lock the - * vnode. Another filp already holds a lock - * for this thread */ - - /* the following fields are for select() and are owned by the generic - * select() code (i.e., fd-type-specific select() code can't touch these). - */ - int filp_selectors; /* select()ing processes blocking on this fd */ - int filp_select_ops; /* interested in these SEL_* operations */ - int filp_select_flags; /* Select flags for the filp */ - - /* following are for fd-type-specific select() */ - int filp_pipe_select_ops; -} filp[NR_FILPS]; - -#define FILP_CLOSED 0 /* filp_mode: associated device closed */ - -#define FS_NORMAL 0 /* file descriptor can be used normally */ -#define FS_NEEDS_REOPEN 1 /* file descriptor needs to be re-opened */ - -#define FSF_UPDATE 001 /* The driver should be informed about new - * state. - */ -#define FSF_BUSY 002 /* Select operation sent to driver but no - * reply yet. - */ -#define FSF_RD_BLOCK 010 /* Read request is blocking, the driver should - * keep state. - */ -#define FSF_WR_BLOCK 020 /* Write request is blocking */ -#define FSF_ERR_BLOCK 040 /* Exception request is blocking */ -#define FSF_BLOCKED 070 -#endif diff --git a/servers/avfs/filedes.c b/servers/avfs/filedes.c deleted file mode 100644 index 1d3cbc076..000000000 --- a/servers/avfs/filedes.c +++ /dev/null @@ -1,578 +0,0 @@ -/* This file contains the procedures that manipulate file descriptors. - * - * The entry points into this file are - * get_fd: look for free file descriptor and free filp slots - * get_filp: look up the filp entry for a given file descriptor - * find_filp: find a filp slot that points to a given vnode - * inval_filp: invalidate a filp and associated fd's, only let close() - * happen on it - * do_verify_fd: verify whether the given file descriptor is valid for - * the given endpoint. - * do_set_filp: marks a filp as in-flight. - * do_copy_filp: copies a filp to another endpoint. - * do_put_filp: marks a filp as not in-flight anymore. - * do_cancel_fd: cancel the transaction when something goes wrong for - * the receiver. - */ - -#include -#include -#include -#include -#include "fs.h" -#include "file.h" -#include "fproc.h" -#include "vnode.h" - - -FORWARD _PROTOTYPE( filp_id_t verify_fd, (endpoint_t ep, int fd) ); - -#if LOCK_DEBUG -/*===========================================================================* - * check_filp_locks * - *===========================================================================*/ -PUBLIC void check_filp_locks_by_me(void) -{ -/* Check whether this thread still has filp locks held */ - struct filp *f; - int r; - - for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { - r = mutex_trylock(&f->filp_lock); - if (r == -EDEADLK) - panic("Thread %d still holds filp lock on filp %p call_nr=%d\n", - mthread_self(), f, call_nr); - else if (r == 0) { - /* We just obtained the lock, release it */ - mutex_unlock(&f->filp_lock); - } - } -} -#endif - -/*===========================================================================* - * check_filp_locks * - *===========================================================================*/ -PUBLIC void check_filp_locks(void) -{ - struct filp *f; - int r, count = 0; - - for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { - r = mutex_trylock(&f->filp_lock); - if (r == -EBUSY) { - /* Mutex is still locked */ - count++; - } else if (r == 0) { - /* We just obtained a lock, don't want it */ - mutex_unlock(&f->filp_lock); - } else - panic("filp_lock weird state"); - } - if (count) panic("locked filps"); -#if 0 - else printf("check_filp_locks OK\n"); -#endif -} - -/*===========================================================================* - * init_filps * - *===========================================================================*/ -PUBLIC void init_filps(void) -{ -/* Initialize filps */ - struct filp *f; - - for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { - mutex_init(&f->filp_lock, NULL); - } - -} - -/*===========================================================================* - * get_fd * - *===========================================================================*/ -PUBLIC int get_fd(int start, mode_t bits, int *k, struct filp **fpt) -{ -/* Look for a free file descriptor and a free filp slot. Fill in the mode word - * in the latter, but don't claim either one yet, since the open() or creat() - * may yet fail. - */ - - register struct filp *f; - register int i; - - /* Search the fproc fp_filp table for a free file descriptor. */ - for (i = start; i < OPEN_MAX; i++) { - if (fp->fp_filp[i] == NULL && !FD_ISSET(i, &fp->fp_filp_inuse)) { - /* A file descriptor has been located. */ - *k = i; - break; - } - } - - /* Check to see if a file descriptor has been found. */ - if (i >= OPEN_MAX) return(EMFILE); - - /* If we don't care about a filp, return now */ - if (fpt == NULL) return(OK); - - /* Now that a file descriptor has been found, look for a free filp slot. */ - for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { - assert(f->filp_count >= 0); - if (f->filp_count == 0 && mutex_trylock(&f->filp_lock) == 0) { - f->filp_mode = bits; - f->filp_pos = cvu64(0); - f->filp_selectors = 0; - f->filp_select_ops = 0; - f->filp_pipe_select_ops = 0; - f->filp_flags = 0; - f->filp_state = FS_NORMAL; - f->filp_select_flags = 0; - f->filp_softlock = NULL; - *fpt = f; - return(OK); - } - } - - /* If control passes here, the filp table must be full. Report that back. */ - return(ENFILE); -} - - -/*===========================================================================* - * get_filp * - *===========================================================================*/ -PUBLIC struct filp *get_filp(fild, locktype) -int fild; /* file descriptor */ -tll_access_t locktype; -{ -/* See if 'fild' refers to a valid file descr. If so, return its filp ptr. */ - - return get_filp2(fp, fild, locktype); -} - - -/*===========================================================================* - * get_filp2 * - *===========================================================================*/ -PUBLIC struct filp *get_filp2(rfp, fild, locktype) -register struct fproc *rfp; -int fild; /* file descriptor */ -tll_access_t locktype; -{ -/* See if 'fild' refers to a valid file descr. If so, return its filp ptr. */ - struct filp *filp; - - err_code = EBADF; - if (fild < 0 || fild >= OPEN_MAX ) return(NULL); - if (rfp->fp_filp[fild] == NULL && FD_ISSET(fild, &rfp->fp_filp_inuse)) - err_code = EIO; /* The filedes is not there, but is not closed either. - */ - if ((filp = rfp->fp_filp[fild]) != NULL) lock_filp(filp, locktype); - - return(filp); /* may also be NULL */ -} - - -/*===========================================================================* - * find_filp * - *===========================================================================*/ -PUBLIC struct filp *find_filp(struct vnode *vp, mode_t bits) -{ -/* Find a filp slot that refers to the vnode 'vp' in a way as described - * by the mode bit 'bits'. Used for determining whether somebody is still - * interested in either end of a pipe. Also used when opening a FIFO to - * find partners to share a filp field with (to shared the file position). - * Like 'get_fd' it performs its job by linear search through the filp table. - */ - - struct filp *f; - - for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { - if (f->filp_count != 0 && f->filp_vno == vp && (f->filp_mode & bits)) { - return(f); - } - } - - /* If control passes here, the filp wasn't there. Report that back. */ - return(NULL); -} - -/*===========================================================================* - * invalidate_filp * - *===========================================================================*/ -PUBLIC int invalidate_filp(struct filp *rfilp) -{ -/* Invalidate filp. fp_filp_inuse is not cleared, so filp can't be reused - until it is closed first. */ - - int f, fd, n = 0; - for (f = 0; f < NR_PROCS; f++) { - if (fproc[f].fp_pid == PID_FREE) continue; - for (fd = 0; fd < OPEN_MAX; fd++) { - if(fproc[f].fp_filp[fd] && fproc[f].fp_filp[fd] == rfilp) { - fproc[f].fp_filp[fd] = NULL; - n++; - } - } - } - - return(n); /* Report back how often this filp has been invalidated. */ -} - -/*===========================================================================* - * invalidate_filp_by_endpt * - *===========================================================================*/ -PUBLIC void invalidate_filp_by_endpt(endpoint_t proc_e) -{ - struct filp *f; - - for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { - if (f->filp_count != 0 && f->filp_vno != NULL) { - if (f->filp_vno->v_fs_e == proc_e) - (void) invalidate_filp(f); - } - } -} - -/*===========================================================================* - * lock_filp * - *===========================================================================*/ -PUBLIC void lock_filp(filp, locktype) -struct filp *filp; -tll_access_t locktype; -{ - message org_m_in; - struct fproc *org_fp; - struct worker_thread *org_self; - struct vnode *vp; - - assert(filp->filp_count > 0); - vp = filp->filp_vno; - assert(vp != NULL); - - /* Lock vnode only if we haven't already locked it. If already locked by us, - * we're allowed to have one additional 'soft' lock. */ - if (tll_locked_by_me(&vp->v_lock)) { - assert(filp->filp_softlock == NULL); - filp->filp_softlock = fp; - } else { - lock_vnode(vp, locktype); - } - - assert(vp->v_ref_count > 0); /* vnode still in use? */ - assert(filp->filp_vno == vp); /* vnode still what we think it is? */ - assert(filp->filp_count > 0); /* filp still in use? */ - - /* First try to get filp lock right off the bat */ - if (mutex_trylock(&filp->filp_lock) != 0) { - - /* Already in use, let's wait for our turn */ - org_m_in = m_in; - org_fp = fp; - org_self = self; - - if (mutex_lock(&filp->filp_lock) != 0) - panic("unable to obtain lock on filp"); - - m_in = org_m_in; - fp = org_fp; - self = org_self; - } - - assert(filp->filp_count > 0); /* Yet again; filp still in use? */ -} - -/*===========================================================================* - * unlock_filp * - *===========================================================================*/ -PUBLIC void unlock_filp(filp) -struct filp *filp; -{ - /* If this filp holds a soft lock on the vnode, we must be the owner */ - if (filp->filp_softlock != NULL) - assert(filp->filp_softlock == fp); - - if (filp->filp_count > 0) { - /* Only unlock vnode if filp is still in use */ - - /* and if we don't hold a soft lock */ - if (filp->filp_softlock == NULL) { - assert(tll_islocked(&(filp->filp_vno->v_lock))); - unlock_vnode(filp->filp_vno); - } - } - - filp->filp_softlock = NULL; - if (mutex_unlock(&filp->filp_lock) != 0) - panic("unable to release lock on filp"); -} - -/*===========================================================================* - * unlock_filps * - *===========================================================================*/ -PUBLIC void unlock_filps(filp1, filp2) -struct filp *filp1; -struct filp *filp2; -{ -/* Unlock two filps that are tied to the same vnode. As a thread can lock a - * vnode only once, unlocking the vnode twice would result in an error. */ - - /* No NULL pointers and not equal */ - assert(filp1); - assert(filp2); - assert(filp1 != filp2); - - /* Must be tied to the same vnode and not NULL */ - assert(filp1->filp_vno == filp2->filp_vno); - assert(filp1->filp_vno != NULL); - - if (filp1->filp_count > 0 && filp2->filp_count > 0) { - /* Only unlock vnode if filps are still in use */ - unlock_vnode(filp1->filp_vno); - } - - filp1->filp_softlock = NULL; - filp2->filp_softlock = NULL; - if (mutex_unlock(&filp2->filp_lock) != 0) - panic("unable to release filp lock on filp2"); - if (mutex_unlock(&filp1->filp_lock) != 0) - panic("unable to release filp lock on filp1"); -} - -/*===========================================================================* - * verify_fd * - *===========================================================================*/ -PRIVATE filp_id_t verify_fd(ep, fd) -endpoint_t ep; -int fd; -{ -/* Verify whether the file descriptor 'fd' is valid for the endpoint 'ep'. When - * the file descriptor is valid, verify_fd returns a pointer to that filp, else - * it returns NULL. - */ - int slot; - struct filp *rfilp; - - if (isokendpt(ep, &slot) != OK) - return(NULL); - - rfilp = get_filp2(&fproc[slot], fd, VNODE_READ); - - return(rfilp); -} - -/*===========================================================================* - * do_verify_fd * - *===========================================================================*/ -PUBLIC int do_verify_fd(void) -{ - struct filp *rfilp; - rfilp = (struct filp *) verify_fd(m_in.USER_ENDPT, m_in.COUNT); - m_out.ADDRESS = (void *) rfilp; - if (rfilp != NULL) unlock_filp(rfilp); - return (rfilp != NULL) ? OK : EINVAL; -} - -/*===========================================================================* - * set_filp * - *===========================================================================*/ -PUBLIC int set_filp(sfilp) -filp_id_t sfilp; -{ - if (sfilp == NULL) return(EINVAL); - - lock_filp(sfilp, VNODE_READ); - sfilp->filp_count++; - unlock_filp(sfilp); - - return(OK); -} - -/*===========================================================================* - * do_set_filp * - *===========================================================================*/ -PUBLIC int do_set_filp(void) -{ - return set_filp((filp_id_t) m_in.ADDRESS); -} - -/*===========================================================================* - * copy_filp * - *===========================================================================*/ -PUBLIC int copy_filp(to_ep, cfilp) -endpoint_t to_ep; -filp_id_t cfilp; -{ - int fd; - int slot; - struct fproc *rfp; - - if (isokendpt(to_ep, &slot) != OK) return(EINVAL); - rfp = &fproc[slot]; - - /* Find an open slot in fp_filp */ - for (fd = 0; fd < OPEN_MAX; fd++) { - if (rfp->fp_filp[fd] == NULL && - !FD_ISSET(fd, &rfp->fp_filp_inuse)) { - - /* Found a free slot, add descriptor */ - FD_SET(fd, &rfp->fp_filp_inuse); - rfp->fp_filp[fd] = cfilp; - rfp->fp_filp[fd]->filp_count++; - return(fd); - } - } - - /* File descriptor table is full */ - return(EMFILE); -} - -/*===========================================================================* - * do_copy_filp * - *===========================================================================*/ -PUBLIC int do_copy_filp(void) -{ - return copy_filp(m_in.USER_ENDPT, (filp_id_t) m_in.ADDRESS); -} - -/*===========================================================================* - * put_filp * - *===========================================================================*/ -PUBLIC int put_filp(pfilp) -filp_id_t pfilp; -{ - if (pfilp == NULL) { - return EINVAL; - } else { - lock_filp(pfilp, VNODE_OPCL); - close_filp(pfilp); - return(OK); - } -} - -/*===========================================================================* - * do_put_filp * - *===========================================================================*/ -PUBLIC int do_put_filp(void) -{ - return put_filp((filp_id_t) m_in.ADDRESS); -} - -/*===========================================================================* - * cancel_fd * - *===========================================================================*/ -PUBLIC int cancel_fd(ep, fd) -endpoint_t ep; -int fd; -{ - int slot; - struct fproc *rfp; - struct filp *rfilp; - - if (isokendpt(ep, &slot) != OK) return(EINVAL); - rfp = &fproc[slot]; - - /* Check that the input 'fd' is valid */ - rfilp = (struct filp *) verify_fd(ep, fd); - if (rfilp != NULL) { - /* Found a valid descriptor, remove it */ - FD_CLR(fd, &rfp->fp_filp_inuse); - if (rfp->fp_filp[fd]->filp_count == 0) { - unlock_filp(rfilp); - printf("VFS: filp_count for slot %d fd %d already zero", slot, - fd); - return(EINVAL); - } - rfp->fp_filp[fd]->filp_count--; - rfp->fp_filp[fd] = NULL; - unlock_filp(rfilp); - return(fd); - } - - /* File descriptor is not valid for the endpoint. */ - return(EINVAL); -} - -/*===========================================================================* - * do_cancel_fd * - *===========================================================================*/ -PUBLIC int do_cancel_fd(void) -{ - return cancel_fd(m_in.USER_ENDPT, m_in.COUNT); -} - -/*===========================================================================* - * close_filp * - *===========================================================================*/ -PUBLIC void close_filp(f) -struct filp *f; -{ -/* Close a file. Will also unlock filp when done */ - - int mode_word, rw; - dev_t dev; - struct vnode *vp; - - /* Must be locked */ - assert(mutex_trylock(&f->filp_lock) == -EDEADLK); - assert(tll_islocked(&f->filp_vno->v_lock)); - - vp = f->filp_vno; - - if (f->filp_count - 1 == 0 && f->filp_mode != FILP_CLOSED) { - /* Check to see if the file is special. */ - mode_word = vp->v_mode & I_TYPE; - if (mode_word == I_CHAR_SPECIAL || mode_word == I_BLOCK_SPECIAL) { - dev = (dev_t) vp->v_sdev; - if (mode_word == I_BLOCK_SPECIAL) { - lock_bsf(); - if (vp->v_bfs_e == ROOT_FS_E) { - /* Invalidate the cache unless the special is - * mounted. Assume that the root filesystem's - * is open only for fsck. - */ - req_flush(vp->v_bfs_e, dev); - } - unlock_bsf(); - } - - /* Do any special processing on device close. - * Ignore any errors, even SUSPEND. - */ - if (mode_word == I_BLOCK_SPECIAL) - (void) bdev_close(dev); - else - (void) dev_close(dev, f-filp); - - f->filp_mode = FILP_CLOSED; - } - } - - /* If the inode being closed is a pipe, release everyone hanging on it. */ - if (vp->v_pipe == I_PIPE) { - rw = (f->filp_mode & R_BIT ? WRITE : READ); - release(vp, rw, NR_PROCS); - } - - /* If a write has been done, the inode is already marked as DIRTY. */ - if (--f->filp_count == 0) { - if (vp->v_pipe == I_PIPE) { - /* Last reader or writer is going. Tell PFS about latest - * pipe size. - */ - truncate_vnode(vp, vp->v_size); - } - - unlock_vnode(f->filp_vno); - put_vnode(f->filp_vno); - } else if (f->filp_count < 0) { - panic("VFS: invalid filp count: %d ino %d/%d", f->filp_count, - vp->v_dev, vp->v_inode_nr); - } else { - unlock_vnode(f->filp_vno); - } - - mutex_unlock(&f->filp_lock); -} diff --git a/servers/avfs/fproc.h b/servers/avfs/fproc.h deleted file mode 100644 index 79ede32f7..000000000 --- a/servers/avfs/fproc.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef __VFS_FPROC_H__ -#define __VFS_FPROC_H__ - -#include "threads.h" - -#include -#include - -/* This is the per-process information. A slot is reserved for each potential - * process. Thus NR_PROCS must be the same as in the kernel. It is not - * possible or even necessary to tell when a slot is free here. - */ -#define LOCK_DEBUG 0 -EXTERN struct fproc { - unsigned fp_flags; - - pid_t fp_pid; /* process id */ - endpoint_t fp_endpoint; /* kernel endpoint number of this process */ - - struct vnode *fp_wd; /* working directory; NULL during reboot */ - struct vnode *fp_rd; /* root directory; NULL during reboot */ - - struct filp *fp_filp[OPEN_MAX];/* the file descriptor table */ - fd_set fp_filp_inuse; /* which fd's are in use? */ - fd_set fp_cloexec_set; /* bit map for POSIX Table 6-2 FD_CLOEXEC */ - - dev_t fp_tty; /* major/minor of controlling tty */ - - int fp_blocked_on; /* what is it blocked on */ - int fp_block_callnr; /* blocked call if rd/wr can't finish */ - int fp_cum_io_partial; /* partial byte count if rd/wr can't finish */ - endpoint_t fp_task; /* which task is proc suspended on */ - endpoint_t fp_ioproc; /* proc no. in suspended-on i/o message */ - - cp_grant_id_t fp_grant; /* revoke this grant on unsuspend if > -1 */ - - uid_t fp_realuid; /* real user id */ - uid_t fp_effuid; /* effective user id */ - gid_t fp_realgid; /* real group id */ - gid_t fp_effgid; /* effective group id */ - int fp_ngroups; /* number of supplemental groups */ - gid_t fp_sgroups[NGROUPS_MAX];/* supplemental groups */ - mode_t fp_umask; /* mask set by umask system call */ - - message *fp_sendrec; /* request/reply to/from FS/driver */ - mutex_t fp_lock; /* mutex to lock fproc object */ - struct job fp_job; /* pending job */ - thread_t fp_wtid; /* Thread ID of worker */ -#if LOCK_DEBUG - int fp_vp_rdlocks; /* number of read-only locks on vnodes */ - int fp_vmnt_rdlocks; /* number of read-only locks on vmnts */ -#endif -} fproc[NR_PROCS]; - -/* fp_flags */ -#define FP_NOFLAGS 00 -#define FP_SUSP_REOPEN 01 /* Process is suspended until the reopens are - * completed (after the restart of a driver). - */ -#define FP_REVIVED 0002 /* Indicates process is being revived */ -#define FP_SESLDR 0004 /* Set if process is session leader */ -#define FP_PENDING 0010 /* Set if process has pending work */ -#define FP_EXITING 0020 /* Set if process is exiting */ -#define FP_PM_PENDING 0040 /* Set if process has pending PM request */ -#define FP_SYS_PROC 0100 /* Set if process is a driver or FS */ -#define FP_DROP_WORK 0200 /* Set if process won't accept new work */ - -/* Field values. */ -#define NOT_REVIVING 0xC0FFEEE /* process is not being revived */ -#define REVIVING 0xDEEAD /* process is being revived from suspension */ -#define PID_FREE 0 /* process slot free */ - -#endif /* __VFS_FPROC_H__ */ diff --git a/servers/avfs/fs.h b/servers/avfs/fs.h deleted file mode 100644 index 9531c2207..000000000 --- a/servers/avfs/fs.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef __VFS_FS_H__ -#define __VFS_FS_H__ - -/* This is the master header for fs. It includes some other files - * and defines the principal constants. - */ -#define _POSIX_SOURCE 1 /* tell headers to include POSIX stuff */ -#define _MINIX 1 /* tell headers to include MINIX stuff */ -#define _SYSTEM 1 /* tell headers that this is the kernel */ - -#define DO_SANITYCHECKS 0 - -#if DO_SANITYCHECKS -#define SANITYCHECK do { \ - if(!check_vrefs() || !check_pipe()) { \ - printf("VFS:%s:%d: call_nr %d who_e %d\n", \ - __FILE__, __LINE__, call_nr, who_e); \ - panic("sanity check failed"); \ - } \ -} while(0) -#else -#define SANITYCHECK -#endif - -/* The following are so basic, all the *.c files get them automatically. */ -#include /* MUST be first */ -#include /* MUST be second */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include "const.h" -#include "dmap.h" -#include "proto.h" -#include "threads.h" -#include "glo.h" -#include "comm.h" -#include "vmnt.h" - -#endif diff --git a/servers/avfs/fscall.c b/servers/avfs/fscall.c deleted file mode 100644 index 257afb32e..000000000 --- a/servers/avfs/fscall.c +++ /dev/null @@ -1,132 +0,0 @@ -/* This file handles nested counter-request calls to VFS sent by file system - * (FS) servers in response to VFS requests. - * - * The entry points into this file are - * nested_fs_call perform a nested call from a file system server - * nested_dev_call perform a nested call from a device driver server - * - */ - -#include "fs.h" -#include "fproc.h" -#include -#include -#include -#include -#include - -/* maximum nested call stack depth */ -#define MAX_DEPTH 1 - -/* global variables stack */ -PRIVATE struct { - struct fproc *g_fp; /* pointer to caller process */ - message g_m_in; /* request message */ - message g_m_out; /* reply message */ - int g_who_e; /* endpoint of caller process */ - int g_who_p; /* slot number of caller process */ - int g_call_nr; /* call number */ - int g_super_user; /* is the caller root? */ - char g_user_fullpath[PATH_MAX]; /* path to look up */ -} globals[MAX_DEPTH]; - -PRIVATE int depth = 0; /* current globals stack level */ - -FORWARD _PROTOTYPE( int push_globals, (void) ); -FORWARD _PROTOTYPE( void pop_globals, (void) ); -FORWARD _PROTOTYPE( void set_globals, (message *m) ); - -/*===========================================================================* - * push_globals * - *===========================================================================*/ -PRIVATE int push_globals() -{ -/* Save the global variables of the current call onto the globals stack. - */ - - if (depth == MAX_DEPTH) - return(EPERM); - - globals[depth].g_fp = fp; - globals[depth].g_m_in = m_in; - globals[depth].g_m_out = m_out; - globals[depth].g_super_user = super_user; - - /* err_code is not used across blocking calls */ - depth++; - return(OK); -} - -/*===========================================================================* - * pop_globals * - *===========================================================================*/ -PRIVATE void pop_globals() -{ -/* Restore the global variables of a call from the globals stack. - */ - - if (depth == 0) - panic("Popping from empty globals stack!"); - - depth--; - - fp = globals[depth].g_fp; - m_in = globals[depth].g_m_in; - m_out = globals[depth].g_m_out; - -} - -/*===========================================================================* - * set_globals * - *===========================================================================*/ -PRIVATE void set_globals(m) -message *m; /* request message */ -{ -/* Initialize global variables based on a request message. - */ - int proc_p; - - m_in = *m; - - proc_p = _ENDPOINT_P(m_in.m_source); - fp = &fproc[proc_p]; - - /* the rest need not be initialized */ -} - -/*===========================================================================* - * nested_fs_call * - *===========================================================================*/ -PUBLIC void nested_fs_call(m) -message *m; /* request/reply message pointer */ -{ -/* Handle a nested call from a file system server. - */ - int r; - - /* Save global variables of the current call */ - if ((r = push_globals()) != OK) { - printf("VFS: error saving global variables in call %d from FS %d\n", - m->m_type, m->m_source); - } else { - /* Initialize global variables for the nested call */ - set_globals(m); - - /* Perform the nested call - only getsysinfo() is allowed right now */ - if (call_nr == COMMON_GETSYSINFO) { - r = do_getsysinfo(); - } else { - printf("VFS: invalid nested call %d from FS %d\n", call_nr, - who_e); - - r = ENOSYS; - } - - /* Store the result, and restore original global variables */ - *m = m_out; - - pop_globals(); - } - - m->m_type = r; -} diff --git a/servers/avfs/gcov.c b/servers/avfs/gcov.c deleted file mode 100644 index 50bed6451..000000000 --- a/servers/avfs/gcov.c +++ /dev/null @@ -1,66 +0,0 @@ - -#include "fs.h" -#include "file.h" -#include "fproc.h" - -_PROTOTYPE( int gcov_flush, (cp_grant_id_t grantid, size_t size )); - -/*===========================================================================* - * do_gcov_flush * - *===========================================================================*/ -PUBLIC int do_gcov_flush() -{ -/* A userland tool has requested the gcov data from another - * process (possibly vfs itself). Grant the target process - * access to the supplied buffer, and perform the call that - * makes the target copy its buffer to the caller (incl vfs - * itself). - */ - struct fproc *rfp; - ssize_t size; - cp_grant_id_t grantid; - int r, n; - pid_t target; - message m; - - size = m_in.GCOV_BUFF_SZ; - target = m_in.GCOV_PID; - - /* If the wrong process is sent to, the system hangs; so make this root-only. - */ - - if (!super_user) return(EPERM); - - /* Find target gcov process. */ - for(n = 0; n < NR_PROCS; n++) { - if(fproc[n].fp_endpoint != NONE && fproc[n].fp_pid == target) - break; - } - if(n >= NR_PROCS) { - printf("VFS: gcov process %d not found\n", target); - return(ESRCH); - } - rfp = &fproc[n]; - - /* Grant target process to requestor's buffer. */ - if ((grantid = cpf_grant_magic(rfp->fp_endpoint, who_e, - (vir_bytes) m_in.GCOV_BUFF_P, size, - CPF_WRITE)) < 0) { - printf("VFS: gcov_flush: grant failed\n"); - return(ENOMEM); - } - - if(rfp->fp_endpoint == VFS_PROC_NR) { - /* Request is for VFS itself. */ - r = gcov_flush(grantid, size); - } else { - /* Perform generic GCOV request. */ - m.GCOV_GRANT = grantid; - m.GCOV_BUFF_SZ = size; - r = _taskcall(rfp->fp_endpoint, COMMON_REQ_GCOV_DATA, &m); - } - - cpf_revoke(grantid); - - return(r); -} diff --git a/servers/avfs/glo.h b/servers/avfs/glo.h deleted file mode 100644 index c07220aa0..000000000 --- a/servers/avfs/glo.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef __VFS_GLO_H__ -#define __VFS_GLO_H__ - -/* EXTERN should be extern except for the table file */ -#ifdef _TABLE -#undef EXTERN -#define EXTERN -#endif - -/* File System global variables */ -EXTERN struct fproc *fp; /* pointer to caller's fproc struct */ -EXTERN int susp_count; /* number of procs suspended on pipe */ -EXTERN int nr_locks; /* number of locks currently in place */ -EXTERN int reviving; /* number of pipe processes to be revived */ -EXTERN int pending; -EXTERN int sending; - -EXTERN dev_t ROOT_DEV; /* device number of the root device */ -EXTERN int ROOT_FS_E; /* kernel endpoint of the root FS proc */ -EXTERN u32_t system_hz; /* system clock frequency. */ - -/* The parameters of the call are kept here. */ -EXTERN message m_in; /* the input message itself */ -EXTERN message m_out; /* the output message used for reply */ -# define who_p ((int) (fp - fproc)) -# define isokslot(p) (p >= 0 && \ - p < (int)(sizeof(fproc) / sizeof(struct fproc))) -#if 0 -# define who_e (isokslot(who_p) ? fp->fp_endpoint : m_in.m_source) -#else -# define who_e (isokslot(who_p) && fp->fp_endpoint != NONE ? \ - fp->fp_endpoint : m_in.m_source) -#endif -# define call_nr (m_in.m_type) -# define super_user (fp->fp_effuid == SU_UID ? 1 : 0) -# define scratch(p) (scratchpad[((int) ((p) - fproc))]) -EXTERN struct worker_thread *self; -EXTERN int force_sync; /* toggle forced synchronous communication */ -EXTERN int deadlock_resolving; -EXTERN mutex_t exec_lock; -EXTERN mutex_t bsf_lock;/* Global lock for access to block special files */ -EXTERN struct worker_thread workers[NR_WTHREADS]; -EXTERN struct worker_thread sys_worker; -EXTERN struct worker_thread dl_worker; -EXTERN char mount_label[LABEL_MAX]; /* label of file system to mount */ - -/* The following variables are used for returning results to the caller. */ -EXTERN int err_code; /* temporary storage for error number */ - -/* Data initialized elsewhere. */ -extern _PROTOTYPE (int (*call_vec[]), (void) ); /* sys call table */ -extern _PROTOTYPE (int (*pfs_call_vec[]), (void) ); /* pfs callback table */ -extern char dot1[2]; /* dot1 (&dot1[0]) and dot2 (&dot2[0]) have a special */ -extern char dot2[3]; /* meaning to search_dir: no access permission check. */ -extern char mode_map[]; /* mapping from O_ACCMODE mask to R_BIT/W_BIT flags */ - -#endif diff --git a/servers/avfs/link.c b/servers/avfs/link.c deleted file mode 100644 index 1c0b4af86..000000000 --- a/servers/avfs/link.c +++ /dev/null @@ -1,455 +0,0 @@ -/* This file handles the LINK and UNLINK system calls. It also deals with - * deallocating the storage used by a file when the last UNLINK is done to a - * file and the blocks must be returned to the free block pool. - * - * The entry points into this file are - * do_link: perform the LINK system call - * do_unlink: perform the UNLINK and RMDIR system calls - * do_rename: perform the RENAME system call - * do_truncate: perform the TRUNCATE system call - * do_ftruncate: perform the FTRUNCATE system call - * do_rdlink: perform the RDLNK system call - */ - -#include "fs.h" -#include -#include -#include -#include -#include -#include -#include -#include "file.h" -#include "fproc.h" -#include "path.h" -#include "vnode.h" -#include "param.h" - -/*===========================================================================* - * do_link * - *===========================================================================*/ -PUBLIC int do_link() -{ -/* Perform the link(name1, name2) system call. */ - int r = OK; - struct vnode *vp = NULL, *dirp = NULL; - struct vmnt *vmp1 = NULL, *vmp2 = NULL; - char fullpath[PATH_MAX]; - struct lookup resolve; - - lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp1, &vp); - resolve.l_vmnt_lock = VMNT_WRITE; - resolve.l_vnode_lock = VNODE_READ; - - /* See if 'name1' (file to be linked to) exists. */ - if (fetch_name(m_in.name1, m_in.name1_length, M1, fullpath) != OK) - return(err_code); - if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); - - /* Does the final directory of 'name2' exist? */ - lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp2, &dirp); - resolve.l_vmnt_lock = VMNT_READ; - resolve.l_vnode_lock = VNODE_READ; - if (fetch_name(m_in.name2, m_in.name2_length, M1, fullpath) != OK) - r = err_code; - else if ((dirp = last_dir(&resolve, fp)) == NULL) - r = err_code; - - if (r != OK) { - unlock_vnode(vp); - unlock_vmnt(vmp1); - put_vnode(vp); - return(r); - } - - /* Check for links across devices. */ - if (vp->v_fs_e != dirp->v_fs_e) - r = EXDEV; - else - r = forbidden(fp, dirp, W_BIT | X_BIT); - - if (r == OK) - r = req_link(vp->v_fs_e, dirp->v_inode_nr, fullpath, - vp->v_inode_nr); - - unlock_vnode(vp); - unlock_vnode(dirp); - if (vmp2 != NULL) unlock_vmnt(vmp2); - unlock_vmnt(vmp1); - put_vnode(vp); - put_vnode(dirp); - return(r); -} - - -/*===========================================================================* - * do_unlink * - *===========================================================================*/ -PUBLIC int do_unlink() -{ -/* Perform the unlink(name) or rmdir(name) system call. The code for these two - * is almost the same. They differ only in some condition testing. Unlink() - * may be used by the superuser to do dangerous things; rmdir() may not. - */ - struct vnode *dirp, *vp; - struct vmnt *vmp, *vmp2; - int r; - char fullpath[PATH_MAX]; - struct lookup resolve; - - lookup_init(&resolve, fullpath, PATH_RET_SYMLINK, &vmp, &dirp); - resolve.l_vmnt_lock = VMNT_WRITE; - resolve.l_vnode_lock = VNODE_READ; - - /* Get the last directory in the path. */ - if (fetch_name(m_in.name, m_in.name_length, M3, fullpath) != OK) - return(err_code); - - if ((dirp = last_dir(&resolve, fp)) == NULL) return(err_code); - assert(vmp != NULL); - - /* Make sure that the object is a directory */ - if ((dirp->v_mode & I_TYPE) != I_DIRECTORY) { - unlock_vnode(dirp); - unlock_vmnt(vmp); - put_vnode(dirp); - return(ENOTDIR); - } - - /* The caller must have both search and execute permission */ - if ((r = forbidden(fp, dirp, X_BIT | W_BIT)) != OK) { - unlock_vnode(dirp); - unlock_vmnt(vmp); - put_vnode(dirp); - return(r); - } - - /* Also, if the sticky bit is set, only the owner of the file or a privileged - user is allowed to unlink */ - if ((dirp->v_mode & S_ISVTX) == S_ISVTX) { - /* Look up inode of file to unlink to retrieve owner */ - resolve.l_flags = PATH_RET_SYMLINK; - resolve.l_vmp = &vmp2; /* Shouldn't actually get locked */ - resolve.l_vmnt_lock = VMNT_READ; - resolve.l_vnode = &vp; - resolve.l_vnode_lock = VNODE_READ; - vp = advance(dirp, &resolve, fp); - assert(vmp2 == NULL); - if (vp != NULL) { - if (vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID) - r = EPERM; - unlock_vnode(vp); - put_vnode(vp); - } else - r = err_code; - if (r != OK) { - unlock_vnode(dirp); - unlock_vmnt(vmp); - put_vnode(dirp); - return(r); - } - } - - assert(vmp != NULL); - tll_upgrade(&vmp->m_lock); - - if (call_nr == UNLINK) - r = req_unlink(dirp->v_fs_e, dirp->v_inode_nr, fullpath); - else - r = req_rmdir(dirp->v_fs_e, dirp->v_inode_nr, fullpath); - unlock_vnode(dirp); - unlock_vmnt(vmp); - put_vnode(dirp); - return(r); -} - -/*===========================================================================* - * do_rename * - *===========================================================================*/ -PUBLIC int do_rename() -{ -/* Perform the rename(name1, name2) system call. */ - int r = OK, r1; - struct vnode *old_dirp, *new_dirp = NULL, *vp; - struct vmnt *oldvmp, *newvmp, *vmp2; - char old_name[PATH_MAX]; - char fullpath[PATH_MAX]; - struct lookup resolve; - - lookup_init(&resolve, fullpath, PATH_NOFLAGS, &oldvmp, &old_dirp); - /* Do not yet request exclusive lock on vmnt to prevent deadlocks later on */ - resolve.l_vmnt_lock = VMNT_WRITE; - resolve.l_vnode_lock = VNODE_READ; - - /* See if 'name1' (existing file) exists. Get dir and file inodes. */ - if (fetch_name(m_in.name1, m_in.name1_length, M1, fullpath) != OK) - return(err_code); - if ((old_dirp = last_dir(&resolve, fp)) == NULL) - return(err_code); - - /* If the sticky bit is set, only the owner of the file or a privileged - user is allowed to rename */ - if ((old_dirp->v_mode & S_ISVTX) == S_ISVTX) { - /* Look up inode of file to unlink to retrieve owner */ - lookup_init(&resolve, resolve.l_path, PATH_RET_SYMLINK, &vmp2, &vp); - resolve.l_vmnt_lock = VMNT_READ; - resolve.l_vnode_lock = VNODE_READ; - vp = advance(old_dirp, &resolve, fp); - assert(vmp2 == NULL); - if (vp != NULL) { - if(vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID) - r = EPERM; - unlock_vnode(vp); - put_vnode(vp); - } else - r = err_code; - if (r != OK) { - unlock_vnode(old_dirp); - unlock_vmnt(oldvmp); - put_vnode(old_dirp); - return(r); - } - } - - /* Save the last component of the old name */ - if(strlen(fullpath) >= sizeof(old_name)) { - unlock_vnode(old_dirp); - unlock_vmnt(oldvmp); - put_vnode(old_dirp); - return(ENAMETOOLONG); - } - strcpy(old_name, fullpath); - - /* See if 'name2' (new name) exists. Get dir inode */ - lookup_init(&resolve, fullpath, PATH_NOFLAGS, &newvmp, &new_dirp); - resolve.l_vmnt_lock = VMNT_READ; - resolve.l_vnode_lock = VNODE_READ; - if (fetch_name(m_in.name2, m_in.name2_length, M1, fullpath) != OK) - r = err_code; - else if ((new_dirp = last_dir(&resolve, fp)) == NULL) - r = err_code; - - if (r != OK) { - unlock_vnode(old_dirp); - unlock_vmnt(oldvmp); - put_vnode(old_dirp); - return(r); - } - - /* Both parent directories must be on the same device. */ - if (old_dirp->v_fs_e != new_dirp->v_fs_e) r = EXDEV; - - /* Parent dirs must be writable, searchable and on a writable device */ - if ((r1 = forbidden(fp, old_dirp, W_BIT|X_BIT)) != OK || - (r1 = forbidden(fp, new_dirp, W_BIT|X_BIT)) != OK) r = r1; - - if (r == OK) { - tll_upgrade(&oldvmp->m_lock); /* Upgrade to exclusive access */ - r = req_rename(old_dirp->v_fs_e, old_dirp->v_inode_nr, old_name, - new_dirp->v_inode_nr, fullpath); - } - unlock_vnode(old_dirp); - unlock_vnode(new_dirp); - unlock_vmnt(oldvmp); - if (newvmp) unlock_vmnt(newvmp); - - put_vnode(old_dirp); - put_vnode(new_dirp); - - return(r); -} - -/*===========================================================================* - * do_truncate * - *===========================================================================*/ -PUBLIC int do_truncate() -{ -/* truncate_vnode() does the actual work of do_truncate() and do_ftruncate(). - * do_truncate() and do_ftruncate() have to get hold of the inode, either - * by name or fd, do checks on it, and call truncate_inode() to do the - * work. - */ - struct vnode *vp; - struct vmnt *vmp; - int r; - char fullpath[PATH_MAX]; - struct lookup resolve; - - lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); - resolve.l_vmnt_lock = VMNT_EXCL; - resolve.l_vnode_lock = VNODE_WRITE; - - if ((off_t) m_in.flength < 0) return(EINVAL); - - /* Temporarily open file */ - if (fetch_name(m_in.m2_p1, m_in.m2_i1, M1, fullpath) != OK) return(err_code); - if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); - - /* Ask FS to truncate the file */ - if ((r = forbidden(fp, vp, W_BIT)) == OK) - r = truncate_vnode(vp, m_in.flength); - - unlock_vnode(vp); - unlock_vmnt(vmp); - put_vnode(vp); - return(r); -} - -/*===========================================================================* - * do_ftruncate * - *===========================================================================*/ -PUBLIC int do_ftruncate() -{ -/* As with do_truncate(), truncate_vnode() does the actual work. */ - struct filp *rfilp; - int r; - - if ((off_t) m_in.flength < 0) return(EINVAL); - - /* File is already opened; get a vnode pointer from filp */ - if ((rfilp = get_filp(m_in.m2_i1, VNODE_WRITE)) == NULL) return(err_code); - - if (!(rfilp->filp_mode & W_BIT)) - r = EBADF; - else - r = truncate_vnode(rfilp->filp_vno, m_in.flength); - - unlock_filp(rfilp); - return(r); -} - - -/*===========================================================================* - * truncate_vnode * - *===========================================================================*/ -PUBLIC int truncate_vnode(vp, newsize) -struct vnode *vp; -off_t newsize; -{ -/* Truncate a regular file or a pipe */ - int r, file_type; - - assert(tll_locked_by_me(&vp->v_lock)); - file_type = vp->v_mode & I_TYPE; - if (file_type != I_REGULAR && file_type != I_NAMED_PIPE) return(EINVAL); - if ((r = req_ftrunc(vp->v_fs_e, vp->v_inode_nr, newsize, 0)) == OK) - vp->v_size = newsize; - return(r); -} - - -/*===========================================================================* - * do_slink * - *===========================================================================*/ -PUBLIC int do_slink() -{ -/* Perform the symlink(name1, name2) system call. */ - int r; - struct vnode *vp; - struct vmnt *vmp; - char fullpath[PATH_MAX]; - struct lookup resolve; - - lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); - resolve.l_vmnt_lock = VMNT_WRITE; - resolve.l_vnode_lock = VNODE_READ; - - if (m_in.name1_length <= 1) return(ENOENT); - if (m_in.name1_length >= SYMLINK_MAX) return(ENAMETOOLONG); - - /* Get dir inode of 'name2' */ - if (fetch_name(m_in.name2, m_in.name2_length, M1, fullpath) != OK) - return(err_code); - - if ((vp = last_dir(&resolve, fp)) == NULL) return(err_code); - - if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) { - r = req_slink(vp->v_fs_e, vp->v_inode_nr, fullpath, who_e, - m_in.name1, m_in.name1_length - 1, fp->fp_effuid, - fp->fp_effgid); - } - - unlock_vnode(vp); - unlock_vmnt(vmp); - put_vnode(vp); - - return(r); -} - -/*===========================================================================* - * rdlink_direct * - *===========================================================================*/ -PUBLIC int rdlink_direct(orig_path, link_path, rfp) -char *orig_path; -char link_path[PATH_MAX]; /* should have length PATH_MAX */ -struct fproc *rfp; -{ -/* Perform a readlink()-like call from within the VFS */ - int r; - struct vnode *vp; - struct vmnt *vmp; - struct lookup resolve; - - lookup_init(&resolve, link_path, PATH_RET_SYMLINK, &vmp, &vp); - resolve.l_vmnt_lock = VMNT_READ; - resolve.l_vnode_lock = VNODE_READ; - - /* Temporarily open the file containing the symbolic link. Use link_path - * for temporary storage to keep orig_path untouched. */ - strncpy(link_path, orig_path, PATH_MAX); /* PATH_MAX includes '\0' */ - link_path[PATH_MAX - 1] = '\0'; - if ((vp = eat_path(&resolve, rfp)) == NULL) return(err_code); - - /* Make sure this is a symbolic link */ - if ((vp->v_mode & I_TYPE) != I_SYMBOLIC_LINK) - r = EINVAL; - else - r = req_rdlink(vp->v_fs_e, vp->v_inode_nr, NONE, link_path, - PATH_MAX - 1, 1); - - if (r > 0) link_path[r] = '\0'; /* Terminate string when succesful */ - - unlock_vnode(vp); - unlock_vmnt(vmp); - put_vnode(vp); - - return r; -} - -/*===========================================================================* - * do_rdlink * - *===========================================================================*/ -PUBLIC int do_rdlink() -{ -/* Perform the readlink(name, buf, bufsize) system call. */ - int r, copylen; - struct vnode *vp; - struct vmnt *vmp; - char fullpath[PATH_MAX]; - struct lookup resolve; - - lookup_init(&resolve, fullpath, PATH_RET_SYMLINK, &vmp, &vp); - resolve.l_vmnt_lock = VMNT_READ; - resolve.l_vnode_lock = VNODE_READ; - - copylen = m_in.nbytes; - if (copylen < 0) return(EINVAL); - - /* Temporarily open the file containing the symbolic link */ - if (fetch_name(m_in.name1, m_in.name1_length, M1, fullpath) != OK) - return(err_code); - if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); - - /* Make sure this is a symbolic link */ - if ((vp->v_mode & I_TYPE) != I_SYMBOLIC_LINK) - r = EINVAL; - else - r = req_rdlink(vp->v_fs_e, vp->v_inode_nr, who_e, m_in.name2, - copylen, 0); - - unlock_vnode(vp); - unlock_vmnt(vmp); - put_vnode(vp); - - return(r); -} diff --git a/servers/avfs/lock.c b/servers/avfs/lock.c deleted file mode 100644 index 36ab59351..000000000 --- a/servers/avfs/lock.c +++ /dev/null @@ -1,191 +0,0 @@ -/* This file handles advisory file locking as required by POSIX. - * - * The entry points into this file are - * lock_op: perform locking operations for FCNTL system call - * lock_revive: revive processes when a lock is released - */ - -#include "fs.h" -#include -#include -#include -#include -#include "file.h" -#include "fproc.h" -#include "scratchpad.h" -#include "lock.h" -#include "vnode.h" -#include "param.h" - -/*===========================================================================* - * lock_op * - *===========================================================================*/ -PUBLIC int lock_op(f, req) -struct filp *f; -int req; /* either F_SETLK or F_SETLKW */ -{ -/* Perform the advisory locking required by POSIX. */ - - int r, ltype, i, conflict = 0, unlocking = 0; - mode_t mo; - off_t first, last; - struct flock flock; - struct file_lock *flp, *flp2, *empty; - - /* Fetch the flock structure from user space. */ - r = sys_datacopy(who_e, (vir_bytes) scratch(fp).io.io_buffer, VFS_PROC_NR, - (vir_bytes) &flock, sizeof(flock)); - if (r != OK) return(EINVAL); - - /* Make some error checks. */ - ltype = flock.l_type; - mo = f->filp_mode; - if (ltype != F_UNLCK && ltype != F_RDLCK && ltype != F_WRLCK) return(EINVAL); - if (req == F_GETLK && ltype == F_UNLCK) return(EINVAL); - if ( (f->filp_vno->v_mode & I_TYPE) != I_REGULAR && - (f->filp_vno->v_mode & I_TYPE) != I_BLOCK_SPECIAL) return(EINVAL); - if (req != F_GETLK && ltype == F_RDLCK && (mo & R_BIT) == 0) return(EBADF); - if (req != F_GETLK && ltype == F_WRLCK && (mo & W_BIT) == 0) return(EBADF); - - /* Compute the first and last bytes in the lock region. */ - switch (flock.l_whence) { - case SEEK_SET: first = 0; break; - case SEEK_CUR: - if (ex64hi(f->filp_pos) != 0) - panic("lock_op: position in file too high"); - first = ex64lo(f->filp_pos); - break; - case SEEK_END: first = f->filp_vno->v_size; break; - default: return(EINVAL); - } - - /* Check for overflow. */ - if (((long) flock.l_start > 0) && ((first + flock.l_start) < first)) - return(EINVAL); - if (((long) flock.l_start < 0) && ((first + flock.l_start) > first)) - return(EINVAL); - first = first + flock.l_start; - last = first + flock.l_len - 1; - if (flock.l_len == 0) last = MAX_FILE_POS; - if (last < first) return(EINVAL); - - /* Check if this region conflicts with any existing lock. */ - empty = NULL; - for (flp = &file_lock[0]; flp < &file_lock[NR_LOCKS]; flp++) { - if (flp->lock_type == 0) { - if (empty == NULL) empty = flp; - continue; /* 0 means unused slot */ - } - if (flp->lock_vnode != f->filp_vno) continue; /* different file */ - if (last < flp->lock_first) continue; /* new one is in front */ - if (first > flp->lock_last) continue; /* new one is afterwards */ - if (ltype == F_RDLCK && flp->lock_type == F_RDLCK) continue; - if (ltype != F_UNLCK && flp->lock_pid == fp->fp_pid) continue; - - /* There might be a conflict. Process it. */ - conflict = 1; - if (req == F_GETLK) break; - - /* If we are trying to set a lock, it just failed. */ - if (ltype == F_RDLCK || ltype == F_WRLCK) { - if (req == F_SETLK) { - /* For F_SETLK, just report back failure. */ - return(EAGAIN); - } else { - /* For F_SETLKW, suspend the process. */ - suspend(FP_BLOCKED_ON_LOCK); - return(SUSPEND); - } - } - - /* We are clearing a lock and we found something that overlaps. */ - unlocking = 1; - if (first <= flp->lock_first && last >= flp->lock_last) { - flp->lock_type = 0; /* mark slot as unused */ - nr_locks--; /* number of locks is now 1 less */ - continue; - } - - /* Part of a locked region has been unlocked. */ - if (first <= flp->lock_first) { - flp->lock_first = last + 1; - continue; - } - - if (last >= flp->lock_last) { - flp->lock_last = first - 1; - continue; - } - - /* Bad luck. A lock has been split in two by unlocking the middle. */ - if (nr_locks == NR_LOCKS) return(ENOLCK); - for (i = 0; i < NR_LOCKS; i++) - if (file_lock[i].lock_type == 0) break; - flp2 = &file_lock[i]; - flp2->lock_type = flp->lock_type; - flp2->lock_pid = flp->lock_pid; - flp2->lock_vnode = flp->lock_vnode; - flp2->lock_first = last + 1; - flp2->lock_last = flp->lock_last; - flp->lock_last = first - 1; - nr_locks++; - } - if (unlocking) lock_revive(); - - if (req == F_GETLK) { - if (conflict) { - /* GETLK and conflict. Report on the conflicting lock. */ - flock.l_type = flp->lock_type; - flock.l_whence = SEEK_SET; - flock.l_start = flp->lock_first; - flock.l_len = flp->lock_last - flp->lock_first + 1; - flock.l_pid = flp->lock_pid; - - } else { - /* It is GETLK and there is no conflict. */ - flock.l_type = F_UNLCK; - } - - /* Copy the flock structure back to the caller. */ - r = sys_datacopy(VFS_PROC_NR, (vir_bytes) &flock, - who_e, (vir_bytes) scratch(fp).io.io_buffer, sizeof(flock)); - return(r); - } - - if (ltype == F_UNLCK) return(OK); /* unlocked a region with no locks */ - - /* There is no conflict. If space exists, store new lock in the table. */ - if (empty == NULL) return(ENOLCK); /* table full */ - empty->lock_type = ltype; - empty->lock_pid = fp->fp_pid; - empty->lock_vnode = f->filp_vno; - empty->lock_first = first; - empty->lock_last = last; - nr_locks++; - return(OK); -} - - -/*===========================================================================* - * lock_revive * - *===========================================================================*/ -PUBLIC void lock_revive() -{ -/* Go find all the processes that are waiting for any kind of lock and - * revive them all. The ones that are still blocked will block again when - * they run. The others will complete. This strategy is a space-time - * tradeoff. Figuring out exactly which ones to unblock now would take - * extra code, and the only thing it would win would be some performance in - * extremely rare circumstances (namely, that somebody actually used - * locking). - */ - - struct fproc *fptr; - - for (fptr = &fproc[0]; fptr < &fproc[NR_PROCS]; fptr++){ - if (fptr->fp_pid == PID_FREE) continue; - if (fptr->fp_blocked_on == FP_BLOCKED_ON_LOCK) { - revive(fptr->fp_endpoint, 0); - } - } -} diff --git a/servers/avfs/lock.h b/servers/avfs/lock.h deleted file mode 100644 index c2baa651e..000000000 --- a/servers/avfs/lock.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __VFS_LOCK_H__ -#define __VFS_LOCK_H__ - -/* This is the file locking table. Like the filp table, it points to the - * inode table, however, in this case to achieve advisory locking. - */ -EXTERN struct file_lock { - short lock_type; /* F_RDLOCK or F_WRLOCK; 0 means unused slot */ - pid_t lock_pid; /* pid of the process holding the lock */ - struct vnode *lock_vnode; - off_t lock_first; /* offset of first byte locked */ - off_t lock_last; /* offset of last byte locked */ -} file_lock[NR_LOCKS]; - -#endif diff --git a/servers/avfs/main.c b/servers/avfs/main.c deleted file mode 100644 index 337cc8383..000000000 --- a/servers/avfs/main.c +++ /dev/null @@ -1,990 +0,0 @@ -/* - * a loop that gets messages requesting work, carries out the work, and sends - * replies. - * - * The entry points into this file are: - * main: main program of the Virtual File System - * reply: send a reply to a process after the requested work is done - * - */ - -#include "fs.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "file.h" -#include "dmap.h" -#include "fproc.h" -#include "scratchpad.h" -#include "vmnt.h" -#include "vnode.h" -#include "job.h" -#include "param.h" - -#if ENABLE_SYSCALL_STATS -EXTERN unsigned long calls_stats[NCALLS]; -#endif - -/* Thread related prototypes */ -FORWARD _PROTOTYPE( void thread_cleanup_f, (struct fproc *rfp, char *f, - int l) ); -#define thread_cleanup(x) thread_cleanup_f(x, __FILE__, __LINE__) -FORWARD _PROTOTYPE( void *do_async_dev_result, (void *arg) ); -FORWARD _PROTOTYPE( void *do_control_msgs, (void *arg) ); -FORWARD _PROTOTYPE( void *do_fs_reply, (struct job *job) ); -FORWARD _PROTOTYPE( void *do_work, (void *arg) ); -FORWARD _PROTOTYPE( void *do_pm, (void *arg) ); -FORWARD _PROTOTYPE( void *do_init_root, (void *arg) ); -FORWARD _PROTOTYPE( void handle_work, (void *(*func)(void *arg)) ); - -FORWARD _PROTOTYPE( void get_work, (void) ); -FORWARD _PROTOTYPE( void lock_pm, (void) ); -FORWARD _PROTOTYPE( void unlock_pm, (void) ); -FORWARD _PROTOTYPE( void service_pm, (void) ); -FORWARD _PROTOTYPE( void service_pm_postponed, (void) ); -FORWARD _PROTOTYPE( int unblock, (struct fproc *rfp) ); - -/* SEF functions and variables. */ -FORWARD _PROTOTYPE( void sef_local_startup, (void) ); -FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) ); -PRIVATE mutex_t pm_lock; -PRIVATE endpoint_t receive_from; - -/*===========================================================================* - * main * - *===========================================================================*/ -PUBLIC int main(void) -{ -/* This is the main program of the file system. The main loop consists of - * three major activities: getting new work, processing the work, and sending - * the reply. This loop never terminates as long as the file system runs. - */ - int transid, req; - struct job *job; - - /* SEF local startup. */ - sef_local_startup(); - - printf("Started AVFS: %d worker thread(s)\n", NR_WTHREADS); - - /* This is the main loop that gets work, processes it, and sends replies. */ - while (TRUE) { - yield_all(); /* let other threads run */ - send_work(); - get_work(); - - transid = TRNS_GET_ID(m_in.m_type); - req = TRNS_DEL_ID(m_in.m_type); - job = worker_getjob( (thread_t) transid - VFS_TRANSID); - - /* Transaction encoding changes original m_type value; restore. */ - if (job == NULL) - m_in.m_type = transid; - else - m_in.m_type = req; - - if (job != NULL) { - do_fs_reply(job); - continue; - } else if (who_e == PM_PROC_NR) { /* Calls from PM */ - /* Special control messages from PM */ - sys_worker_start(do_pm); - continue; - } else if (is_notify(call_nr)) { - /* A task notify()ed us */ - sys_worker_start(do_control_msgs); - continue; - } else if (who_p < 0) { /* i.e., message comes from a task */ - /* We're going to ignore this message. Tasks should - * send notify()s only. - */ - printf("VFS: ignoring message from %d (%d)\n", who_e, call_nr); - continue; - } - - /* At this point we either have results from an asynchronous device - * or a new system call. In both cases a new worker thread has to be - * started and there might not be one available from the pool. This is - * not a problem (requests/replies are simply queued), except when - * they're from an FS endpoint, because these can cause a deadlock. - * handle_work() takes care of the details. */ - if (IS_DEV_RS(call_nr)) { - /* We've got results for a device request */ - handle_work(do_async_dev_result); - continue; - } else { - /* Normal syscall. */ - handle_work(do_work); - } - } - return(OK); /* shouldn't come here */ -} - -/*===========================================================================* - * handle_work * - *===========================================================================*/ -PRIVATE void handle_work(void *(*func)(void *arg)) -{ -/* Handle asynchronous device replies and new system calls. If the originating - * endpoint is an FS endpoint, take extra care not to get in deadlock. */ - struct vmnt *vmp = NULL; - - if ((vmp = find_vmnt(who_e)) != NULL) { - /* A call back or dev result from an FS endpoint */ - - /* Set call back flag. We assume that an FS does only one call back - * at a time */ - vmp->m_flags |= VMNT_CALLBACK; - - /* When an FS point has to make a call back in order to mount, force - * its device to a "none device" so block reads/writes will be handled - * by ROOT_FS_E. - */ - if (vmp->m_flags & VMNT_MOUNTING) - vmp->m_flags |= VMNT_FORCEROOTBSF; - - if (worker_available() == 0) { - /* No worker threads available to handle call */ - if (deadlock_resolving) { - /* Already trying to resolve a deadlock, can't - * handle more, sorry */ - vmp->m_flags &= ~VMNT_CALLBACK; - reply(who_e, EAGAIN); - return; - } - deadlock_resolving = 1; - dl_worker_start(func); - return; - } - } - - worker_start(func); -} - -/*===========================================================================* - * do_async_dev_result * - *===========================================================================*/ -PRIVATE void *do_async_dev_result(void *arg) -{ - endpoint_t endpt; - struct job my_job; - - my_job = *((struct job *) arg); - fp = my_job.j_fp; - m_in = my_job.j_m_in; - - /* An asynchronous character driver has results for us */ - if (call_nr == DEV_REVIVE) { - endpt = m_in.REP_ENDPT; - if (endpt == VFS_PROC_NR) - endpt = find_suspended_ep(m_in.m_source, m_in.REP_IO_GRANT); - - if (endpt == NONE) { - printf("VFS: proc with grant %d from %d not found\n", - m_in.REP_IO_GRANT, m_in.m_source); - } else if (m_in.REP_STATUS == SUSPEND) { - printf("VFS: got SUSPEND on DEV_REVIVE: not reviving proc\n"); - } else - revive(endpt, m_in.REP_STATUS); - } - else if (call_nr == DEV_OPEN_REPL) open_reply(); - else if (call_nr == DEV_REOPEN_REPL) reopen_reply(); - else if (call_nr == DEV_CLOSE_REPL) close_reply(); - else if (call_nr == DEV_SEL_REPL1) - select_reply1(m_in.m_source, m_in.DEV_MINOR, m_in.DEV_SEL_OPS); - else if (call_nr == DEV_SEL_REPL2) - select_reply2(m_in.m_source, m_in.DEV_MINOR, m_in.DEV_SEL_OPS); - - if (deadlock_resolving) { - if (fp != NULL && fp->fp_wtid == dl_worker.w_tid) - deadlock_resolving = 0; - } - - if (fp != NULL && (fp->fp_flags & FP_SYS_PROC)) { - struct vmnt *vmp; - - if ((vmp = find_vmnt(fp->fp_endpoint)) != NULL) - vmp->m_flags &= ~VMNT_CALLBACK; - } - - thread_cleanup(NULL); - return(NULL); -} - -/*===========================================================================* - * do_control_msgs * - *===========================================================================*/ -PRIVATE void *do_control_msgs(void *arg) -{ - struct job my_job; - - my_job = *((struct job *) arg); - fp = my_job.j_fp; - m_in = my_job.j_m_in; - - /* Check for special control messages. */ - if (who_e == CLOCK) { - /* Alarm timer expired. Used only for select(). Check it. */ - expire_timers(m_in.NOTIFY_TIMESTAMP); - } else if (who_e == DS_PROC_NR) { - /* DS notifies us of an event. */ - ds_event(); - } else { - /* Device notifies us of an event. */ - dev_status(&m_in); - } - - thread_cleanup(NULL); - return(NULL); -} - -/*===========================================================================* - * do_fs_reply * - *===========================================================================*/ -PRIVATE void *do_fs_reply(struct job *job) -{ - struct vmnt *vmp; - struct fproc *rfp; - - if ((vmp = find_vmnt(who_e)) == NULL) - panic("Couldn't find vmnt for endpoint %d", who_e); - - rfp = job->j_fp; - - if (rfp == NULL || rfp->fp_endpoint == NONE) { - printf("VFS: spurious reply from %d\n", who_e); - return(NULL); - } - - if (rfp->fp_task != who_e) - printf("AVFS: expected %d to reply, not %d\n", rfp->fp_task, who_e); - *rfp->fp_sendrec = m_in; - rfp->fp_task = NONE; - vmp->m_comm.c_cur_reqs--; /* We've got our reply, make room for others */ - worker_signal(worker_get(rfp->fp_wtid));/* Continue this worker thread */ - return(NULL); -} - -/*===========================================================================* - * lock_pm * - *===========================================================================*/ -PRIVATE void lock_pm(void) -{ - message org_m_in; - struct fproc *org_fp; - struct worker_thread *org_self; - - /* First try to get it right off the bat */ - if (mutex_trylock(&pm_lock) == 0) - return; - - org_m_in = m_in; - org_fp = fp; - org_self = self; - - if (mutex_lock(&pm_lock) != 0) - panic("Could not obtain lock on pm\n"); - - m_in = org_m_in; - fp = org_fp; - self = org_self; -} - -/*===========================================================================* - * unlock_pm * - *===========================================================================*/ -PRIVATE void unlock_pm(void) -{ - if (mutex_unlock(&pm_lock) != 0) - panic("Could not release lock on pm"); -} - -/*===========================================================================* - * do_pm * - *===========================================================================*/ -PRIVATE void *do_pm(void *arg) -{ - struct job my_job; - struct fproc *rfp; - - my_job = *((struct job *) arg); - rfp = fp = my_job.j_fp; - m_in = my_job.j_m_in; - - lock_pm(); - service_pm(); - unlock_pm(); - - thread_cleanup(NULL); - return(NULL); -} - -/*===========================================================================* - * do_pending_pipe * - *===========================================================================*/ -PRIVATE void *do_pending_pipe(void *arg) -{ - int r, op; - struct job my_job; - struct filp *f; - tll_access_t locktype; - - my_job = *((struct job *) arg); - fp = my_job.j_fp; - m_in = my_job.j_m_in; - - lock_proc(fp, 1 /* force lock */); - - f = scratch(fp).file.filp; - assert(f != NULL); - scratch(fp).file.filp = NULL; - - locktype = (call_nr == READ) ? VNODE_READ : VNODE_WRITE; - op = (call_nr == READ) ? READING : WRITING; - lock_filp(f, locktype); - - r = rw_pipe(op, who_e, f, scratch(fp).io.io_buffer, scratch(fp).io.io_nbytes); - - if (r != SUSPEND) /* Do we have results to report? */ - reply(who_e, r); - - unlock_filp(f); - - thread_cleanup(fp); - return(NULL); -} - -/*===========================================================================* - * do_dummy * - *===========================================================================*/ -PUBLIC void *do_dummy(void *arg) -{ - struct job my_job; - int r; - - my_job = *((struct job *) arg); - fp = my_job.j_fp; - m_in = my_job.j_m_in; - - if ((r = mutex_trylock(&fp->fp_lock)) == 0) { - thread_cleanup(fp); - } else { - /* Proc is busy, let that worker thread carry out the work */ - thread_cleanup(NULL); - } - return(NULL); -} - -/*===========================================================================* - * do_work * - *===========================================================================*/ -PRIVATE void *do_work(void *arg) -{ - int error; - struct job my_job; - - my_job = *((struct job *) arg); - fp = my_job.j_fp; - m_in = my_job.j_m_in; - - lock_proc(fp, 0); /* This proc is busy */ - - if (call_nr == MAPDRIVER) { - error = do_mapdriver(); - } else if (call_nr == COMMON_GETSYSINFO) { - error = do_getsysinfo(); - } else if (IS_PFS_VFS_RQ(call_nr)) { - if (who_e != PFS_PROC_NR) { - printf("VFS: only PFS is allowed to make nested VFS calls\n"); - error = ENOSYS; - } else if (call_nr <= PFS_BASE || call_nr >= PFS_BASE + PFS_NREQS) { - error = ENOSYS; - } else { - call_nr -= PFS_BASE; - error = (*pfs_call_vec[call_nr])(); - } - } else { - /* We're dealing with a POSIX system call from a normal - * process. Call the internal function that does the work. - */ - if (call_nr < 0 || call_nr >= NCALLS) { - error = ENOSYS; - } else if (fp->fp_pid == PID_FREE) { - /* Process vanished before we were able to handle request. - * Replying has no use. Just drop it. */ - error = SUSPEND; - } else { -#if ENABLE_SYSCALL_STATS - calls_stats[call_nr]++; -#endif - error = (*call_vec[call_nr])(); - } - } - - /* Copy the results back to the user and send reply. */ - if (error != SUSPEND) { - - if ((fp->fp_flags & FP_SYS_PROC)) { - struct vmnt *vmp; - - if ((vmp = find_vmnt(fp->fp_endpoint)) != NULL) - vmp->m_flags &= ~VMNT_CALLBACK; - } - - if (deadlock_resolving) { - if (fp->fp_wtid == dl_worker.w_tid) - deadlock_resolving = 0; - } - reply(who_e, error); - } - - thread_cleanup(fp); - return(NULL); -} - -/*===========================================================================* - * sef_local_startup * - *===========================================================================*/ -PRIVATE void sef_local_startup() -{ - /* Register init callbacks. */ - sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fail); - - /* No live update support for now. */ - - /* Let SEF perform startup. */ - sef_startup(); -} - -/*===========================================================================* - * sef_cb_init_fresh * - *===========================================================================*/ -PRIVATE int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info) -{ -/* Initialize the virtual file server. */ - int s, i; - struct fproc *rfp; - message mess; - struct rprocpub rprocpub[NR_BOOT_PROCS]; - - force_sync = 0; - receive_from = ANY; - - /* Initialize proc endpoints to NONE */ - for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - rfp->fp_endpoint = NONE; - rfp->fp_pid = PID_FREE; - } - - /* Initialize the process table with help of the process manager messages. - * Expect one message for each system process with its slot number and pid. - * When no more processes follow, the magic process number NONE is sent. - * Then, stop and synchronize with the PM. - */ - do { - if ((s = sef_receive(PM_PROC_NR, &mess)) != OK) - panic("VFS: couldn't receive from PM: %d", s); - - if (mess.m_type != PM_INIT) - panic("unexpected message from PM: %d", mess.m_type); - - if (NONE == mess.PM_PROC) break; - - rfp = &fproc[mess.PM_SLOT]; - rfp->fp_flags = FP_NOFLAGS; - rfp->fp_pid = mess.PM_PID; - rfp->fp_endpoint = mess.PM_PROC; - rfp->fp_grant = GRANT_INVALID; - rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; - rfp->fp_realuid = (uid_t) SYS_UID; - rfp->fp_effuid = (uid_t) SYS_UID; - rfp->fp_realgid = (gid_t) SYS_GID; - rfp->fp_effgid = (gid_t) SYS_GID; - rfp->fp_umask = ~0; - } while (TRUE); /* continue until process NONE */ - mess.m_type = OK; /* tell PM that we succeeded */ - s = send(PM_PROC_NR, &mess); /* send synchronization message */ - - /* All process table entries have been set. Continue with initialization. */ - fp = &fproc[_ENDPOINT_P(VFS_PROC_NR)];/* During init all communication with - * FSes is on behalf of myself */ - init_dmap(); /* Initialize device table. */ - system_hz = sys_hz(); - - /* Map all the services in the boot image. */ - if ((s = sys_safecopyfrom(RS_PROC_NR, info->rproctab_gid, 0, - (vir_bytes) rprocpub, sizeof(rprocpub), S)) != OK){ - panic("sys_safecopyfrom failed: %d", s); - } - for (i = 0; i < NR_BOOT_PROCS; i++) { - if (rprocpub[i].in_use) { - if ((s = map_service(&rprocpub[i])) != OK) { - panic("VFS: unable to map service: %d", s); - } - } - } - - /* Subscribe to block and character driver events. */ - s = ds_subscribe("drv\\.[bc]..\\..*", DSF_INITIAL | DSF_OVERWRITE); - if (s != OK) panic("VFS: can't subscribe to driver events (%d)", s); - -#if DO_SANITYCHECKS - FIXME("VFS: DO_SANITYCHECKS is on"); -#endif - - /* Initialize worker threads */ - for (i = 0; i < NR_WTHREADS; i++) { - worker_init(&workers[i]); - } - worker_init(&sys_worker); /* exclusive system worker thread */ - worker_init(&dl_worker); /* exclusive worker thread to resolve deadlocks */ - - /* Initialize global locks */ - if (mthread_mutex_init(&pm_lock, NULL) != 0) - panic("VFS: couldn't initialize pm lock mutex"); - if (mthread_mutex_init(&exec_lock, NULL) != 0) - panic("VFS: couldn't initialize exec lock"); - if (mthread_mutex_init(&bsf_lock, NULL) != 0) - panic("VFS: couldn't initialize block special file lock"); - - /* Initialize event resources for boot procs and locks for all procs */ - for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - if (mutex_init(&rfp->fp_lock, NULL) != 0) - panic("unable to initialize fproc lock"); -#if LOCK_DEBUG - rfp->fp_vp_rdlocks = 0; - rfp->fp_vmnt_rdlocks = 0; -#endif - } - - init_vnodes(); /* init vnodes */ - init_vmnts(); /* init vmnt structures */ - init_select(); /* init select() structures */ - init_filps(); /* Init filp structures */ - mount_pfs(); /* mount Pipe File Server */ - worker_start(do_init_root); /* mount initial ramdisk as file system root */ - yield(); /* force do_init_root to start */ - - return(OK); -} - -/*===========================================================================* - * do_init_root * - *===========================================================================*/ -PRIVATE void *do_init_root(void *arg) -{ - struct fproc *rfp; - struct job my_job; - int r; - char *mount_label = "fs_imgrd"; /* FIXME: obtain this from RS */ - - my_job = *((struct job *) arg); - fp = my_job.j_fp; - - lock_proc(fp, 1 /* force lock */); /* This proc is busy */ - lock_pm(); - - /* Initialize process directories. mount_fs will set them to the correct - * values */ - for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - FD_ZERO(&(rfp->fp_filp_inuse)); - rfp->fp_rd = NULL; - rfp->fp_wd = NULL; - } - - receive_from = MFS_PROC_NR; - if ((r = mount_fs(DEV_IMGRD, "/", MFS_PROC_NR, 0, mount_label)) != OK) - panic("Failed to initialize root"); - receive_from = ANY; - - unlock_pm(); - thread_cleanup(fp); - return(NULL); -} - -/*===========================================================================* - * lock_proc * - *===========================================================================*/ -PUBLIC void lock_proc(struct fproc *rfp, int force_lock) -{ - int r; - message org_m_in; - struct fproc *org_fp; - struct worker_thread *org_self; - - r = mutex_trylock(&rfp->fp_lock); - - /* Were we supposed to obtain this lock immediately? */ - if (force_lock) { - assert(r == 0); - return; - } - - if (r == 0) return; - - org_m_in = m_in; - org_fp = fp; - org_self = self; - if ((r = mutex_lock(&rfp->fp_lock)) != 0) - panic("unable to lock fproc lock: %d", r); - m_in = org_m_in; - fp = org_fp; - self = org_self; -} - -/*===========================================================================* - * unlock_proc * - *===========================================================================*/ -PUBLIC void unlock_proc(struct fproc *rfp) -{ - int r; - - if ((r = mutex_unlock(&rfp->fp_lock)) != 0) - panic("Failed to unlock: %d", r); -} - -/*===========================================================================* - * thread_cleanup * - *===========================================================================*/ -PRIVATE void thread_cleanup_f(struct fproc *rfp, char *f, int l) -{ -/* Clean up worker thread. Skip parts if this thread is not associated - * with a particular process (i.e., rfp is NULL) */ - - assert(mthread_self() != -1); - -#if LOCK_DEBUG - if (rfp != NULL) { - check_filp_locks_by_me(); - check_vnode_locks_by_me(rfp); - check_vmnt_locks_by_me(rfp); - } -#endif - - if (rfp != NULL && rfp->fp_flags & FP_PM_PENDING) { /* Postponed PM call */ - m_in = rfp->fp_job.j_m_in; - rfp->fp_flags &= ~FP_PM_PENDING; - service_pm_postponed(); - } - -#if LOCK_DEBUG - if (rfp != NULL) { - check_filp_locks_by_me(); - check_vnode_locks_by_me(rfp); - check_vmnt_locks_by_me(rfp); - } -#endif - - if (rfp != NULL) { - rfp->fp_flags &= ~FP_DROP_WORK; - unlock_proc(rfp); - } - -#if 0 - mthread_exit(NULL); -#endif -} - -/*===========================================================================* - * get_work * - *===========================================================================*/ -PRIVATE void get_work() -{ - /* Normally wait for new input. However, if 'reviving' is - * nonzero, a suspended process must be awakened. - */ - int r, found_one, proc_p; - register struct fproc *rp; - - while (reviving != 0) { - found_one = FALSE; - - /* Find a suspended process. */ - for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) - if (rp->fp_pid != PID_FREE && (rp->fp_flags & FP_REVIVED)) { - found_one = TRUE; /* Found a suspended process */ - if (unblock(rp)) - return; /* So main loop can process job */ - send_work(); - } - - if (!found_one) /* Consistency error */ - panic("VFS: get_work couldn't revive anyone"); - } - - for(;;) { - /* Normal case. No one to revive. Get a useful request. */ - if ((r = sef_receive(receive_from, &m_in)) != OK) { - panic("VFS: sef_receive error: %d", r); - } - - proc_p = _ENDPOINT_P(m_in.m_source); - if (proc_p < 0) fp = NULL; - else fp = &fproc[proc_p]; - - if (m_in.m_type == EDEADSRCDST) return; /* Failed 'sendrec' */ - - /* Negative who_p is never used to access the fproc array. Negative - * numbers (kernel tasks) are treated in a special way. - */ - if (who_p >= (int)(sizeof(fproc) / sizeof(struct fproc))) - panic("receive process out of range: %d", who_p); - if (who_p >= 0 && fproc[who_p].fp_endpoint == NONE) { - printf("VFS: ignoring request from %d, endpointless slot %d (%d)\n", - m_in.m_source, who_p, m_in.m_type); - continue; - } - - /* Internal consistency check; our mental image of process numbers and - * endpoints must match with how the rest of the system thinks of them. - */ - if (who_p >= 0 && fproc[who_p].fp_endpoint != who_e) { - if (fproc[who_p].fp_endpoint == NONE) - printf("slot unknown even\n"); - - printf("VFS: receive endpoint inconsistent (source %d, who_p " - "%d, stored ep %d, who_e %d).\n", m_in.m_source, who_p, - fproc[who_p].fp_endpoint, who_e); - panic("VFS: inconsistent endpoint "); - } - - return; - } -} - - -/*===========================================================================* - * reply * - *===========================================================================*/ -PUBLIC void reply(whom, result) -int whom; /* process to reply to */ -int result; /* result of the call (usually OK or error #) */ -{ -/* Send a reply to a user process. If the send fails, just ignore it. */ - int r; - - m_out.reply_type = result; - r = sendnb(whom, &m_out); - if (r != OK) { - printf("VFS: couldn't send reply %d to %d: %d\n", result, whom, r); - } -} - -/*===========================================================================* - * service_pm_postponed * - *===========================================================================*/ -PRIVATE void service_pm_postponed(void) -{ - int r; - vir_bytes pc; - - switch(call_nr) { - case PM_EXEC: - r = pm_exec(m_in.PM_PROC, m_in.PM_PATH, m_in.PM_PATH_LEN, - m_in.PM_FRAME, m_in.PM_FRAME_LEN, &pc); - - /* Reply status to PM */ - m_out.m_type = PM_EXEC_REPLY; - m_out.PM_PROC = m_in.PM_PROC; - m_out.PM_PC = (void*)pc; - m_out.PM_STATUS = r; - - break; - - case PM_EXIT: - pm_exit(m_in.PM_PROC); - - /* Reply dummy status to PM for synchronization */ - m_out.m_type = PM_EXIT_REPLY; - m_out.PM_PROC = m_in.PM_PROC; - - break; - - case PM_DUMPCORE: - /* Copy parameters first. m_in gets overwritten when creating core - * file. - */ - - r = pm_dumpcore(m_in.PM_PROC, m_in.PM_TERM_SIG, - (vir_bytes) m_in.PM_PATH); - - /* Reply status to PM */ - m_out.m_type = PM_CORE_REPLY; - m_out.PM_PROC = m_in.PM_PROC; - m_out.PM_TRACED_PROC = m_in.PM_TRACED_PROC; - m_out.PM_STATUS = r; - - break; - - default: - panic("Unhandled postponed PM call %d", m_in.m_type); - } - - r = send(PM_PROC_NR, &m_out); - if (r != OK) - panic("service_pm_postponed: send failed: %d", r); -} - -/*===========================================================================* - * service_pm * - *===========================================================================*/ -PRIVATE void service_pm() -{ - int r, slot; - - switch (call_nr) { - case PM_SETUID: - pm_setuid(m_in.PM_PROC, m_in.PM_EID, m_in.PM_RID); - - m_out.m_type = PM_SETUID_REPLY; - m_out.PM_PROC = m_in.PM_PROC; - - break; - - case PM_SETGID: - pm_setgid(m_in.PM_PROC, m_in.PM_EID, m_in.PM_RID); - - m_out.m_type = PM_SETGID_REPLY; - m_out.PM_PROC = m_in.PM_PROC; - - break; - - case PM_SETSID: - pm_setsid(m_in.PM_PROC); - - m_out.m_type = PM_SETSID_REPLY; - m_out.PM_PROC = m_in.PM_PROC; - - break; - - case PM_EXEC: - case PM_EXIT: - case PM_DUMPCORE: - okendpt(m_in.PM_PROC, &slot); - fp = &fproc[slot]; - - if (fp->fp_flags & FP_PENDING) { - /* This process has a request pending, but PM wants it gone. - * Forget about the pending request and satisfy PM's request - * instead. Note that a pending request AND an EXEC request - * are mutually exclusive. Also, PM should send only one - * request/process at a time. - */ - assert(fp->fp_job.j_m_in.m_source != PM_PROC_NR); - } - - /* PM requests on behalf of a proc are handled after the system call - * that might be in progress for that proc has finished. If the proc - * is not busy, we start a dummy call */ - if (!(fp->fp_flags & FP_PENDING) && mutex_trylock(&fp->fp_lock) == 0) { - mutex_unlock(&fp->fp_lock); - worker_start(do_dummy); - fp->fp_flags |= FP_DROP_WORK; - } - - fp->fp_job.j_m_in = m_in; - fp->fp_flags |= FP_PM_PENDING; - - return; - - case PM_FORK: - case PM_SRV_FORK: - pm_fork(m_in.PM_PPROC, m_in.PM_PROC, m_in.PM_CPID); - m_out.m_type = PM_FORK_REPLY; - - if (call_nr == PM_SRV_FORK) { - m_out.m_type = PM_SRV_FORK_REPLY; - pm_setuid(m_in.PM_PROC, m_in.PM_REUID, m_in.PM_REUID); - pm_setgid(m_in.PM_PROC, m_in.PM_REGID, m_in.PM_REGID); - } - - m_out.PM_PROC = m_in.PM_PROC; - - break; - case PM_SETGROUPS: - pm_setgroups(m_in.PM_PROC, m_in.PM_GROUP_NO, - (gid_t *) m_in.PM_GROUP_ADDR); - - m_out.m_type = PM_SETGROUPS_REPLY; - m_out.PM_PROC = m_in.PM_PROC; - - break; - - case PM_UNPAUSE: - unpause(m_in.PM_PROC); - - m_out.m_type = PM_UNPAUSE_REPLY; - m_out.PM_PROC = m_in.PM_PROC; - - break; - - case PM_REBOOT: - pm_reboot(); - - /* Reply dummy status to PM for synchronization */ - m_out.m_type = PM_REBOOT_REPLY; - - break; - - default: - printf("VFS: don't know how to handle PM request %d\n", call_nr); - - return; - } - - r = send(PM_PROC_NR, &m_out); - if (r != OK) - panic("service_pm: send failed: %d", r); - -} - - -/*===========================================================================* - * unblock * - *===========================================================================*/ -PRIVATE int unblock(rfp) -struct fproc *rfp; -{ - int blocked_on; - - fp = rfp; - blocked_on = rfp->fp_blocked_on; - m_in.m_type = rfp->fp_block_callnr; - m_in.fd = scratch(fp).file.fd_nr; - m_in.buffer = scratch(fp).io.io_buffer; - m_in.nbytes = scratch(fp).io.io_nbytes; - - rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; /* no longer blocked */ - rfp->fp_flags &= ~FP_REVIVED; - reviving--; - assert(reviving >= 0); - - /* This should be a pipe I/O, not a device I/O. If it is, it'll 'leak' - * grants. - */ - assert(!GRANT_VALID(rfp->fp_grant)); - - /* Pending pipe reads/writes can be handled directly */ - if (blocked_on == FP_BLOCKED_ON_PIPE) { - worker_start(do_pending_pipe); - yield(); /* Give thread a chance to run */ - return(0); /* Retrieve more work */ - } - - return(1); /* We've unblocked a process */ -} diff --git a/servers/avfs/misc.c b/servers/avfs/misc.c deleted file mode 100644 index 5497bf76e..000000000 --- a/servers/avfs/misc.c +++ /dev/null @@ -1,663 +0,0 @@ -/* This file contains a collection of miscellaneous procedures. Some of them - * perform simple system calls. Some others do a little part of system calls - * that are mostly performed by the Memory Manager. - * - * The entry points into this file are - * do_dup: perform the DUP system call - * do_fcntl: perform the FCNTL system call - * do_sync: perform the SYNC system call - * do_fsync: perform the FSYNC system call - * pm_reboot: sync disks and prepare for shutdown - * pm_fork: adjust the tables after PM has performed a FORK system call - * do_exec: handle files with FD_CLOEXEC on after PM has done an EXEC - * do_exit: a process has exited; note that in the tables - * do_set: set uid or gid for some process - * do_revive: revive a process that was waiting for something (e.g. TTY) - * do_svrctl: file system control - * do_getsysinfo: request copy of FS data structure - * pm_dumpcore: create a core dump - */ - -#include "fs.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "file.h" -#include "fproc.h" -#include "scratchpad.h" -#include "dmap.h" -#include -#include "vnode.h" -#include "vmnt.h" -#include "param.h" - -#define CORE_NAME "core" -#define CORE_MODE 0777 /* mode to use on core image files */ - -#if ENABLE_SYSCALL_STATS -PUBLIC unsigned long calls_stats[NCALLS]; -#endif - -FORWARD _PROTOTYPE( void free_proc, (struct fproc *freed, int flags) ); -/* -FORWARD _PROTOTYPE( int dumpcore, (int proc_e, struct mem_map *seg_ptr) ); -FORWARD _PROTOTYPE( int write_bytes, (struct inode *rip, off_t off, - char *buf, size_t bytes) ); -FORWARD _PROTOTYPE( int write_seg, (struct inode *rip, off_t off, int proc_e, - int seg, off_t seg_off, phys_bytes seg_bytes) ); -*/ - -/*===========================================================================* - * do_getsysinfo * - *===========================================================================*/ -PUBLIC int do_getsysinfo() -{ - vir_bytes src_addr, dst_addr; - size_t len; - - /* Only su may call do_getsysinfo. This call may leak information (and is not - * stable enough to be part of the API/ABI). In the future, requests from - * non-system processes should be denied. - */ - - if (!super_user) return(EPERM); - - switch(m_in.SI_WHAT) { - case SI_PROC_TAB: - src_addr = (vir_bytes) fproc; - len = sizeof(struct fproc) * NR_PROCS; - break; - case SI_DMAP_TAB: - src_addr = (vir_bytes) dmap; - len = sizeof(struct dmap) * NR_DEVICES; - break; -#if ENABLE_SYSCALL_STATS - case SI_CALL_STATS: - src_addr = (vir_bytes) calls_stats; - len = sizeof(calls_stats); - break; -#endif - default: - return(EINVAL); - } - - if (len != m_in.SI_SIZE) - return(EINVAL); - - dst_addr = (vir_bytes) m_in.SI_WHERE; - return sys_datacopy(SELF, src_addr, who_e, dst_addr, len); -} - -/*===========================================================================* - * do_dup * - *===========================================================================*/ -PUBLIC int do_dup() -{ -/* Perform the dup(fd) or dup2(fd,fd2) system call. These system calls are - * obsolete. In fact, it is not even possible to invoke them using the - * current library because the library routines call fcntl(). They are - * provided to permit old binary programs to continue to run. - */ - - register int rfd; - register struct filp *f; - int r = OK; - - /* Is the file descriptor valid? */ - rfd = m_in.fd & ~DUP_MASK; /* kill off dup2 bit, if on */ - if ((f = get_filp(rfd, VNODE_READ)) == NULL) return(err_code); - - /* Distinguish between dup and dup2. */ - if (m_in.fd == rfd) { /* bit not on */ - /* dup(fd) */ - r = get_fd(0, 0, &m_in.fd2, NULL); - } else { - /* dup2(old_fd, new_fd) */ - if (m_in.fd2 < 0 || m_in.fd2 >= OPEN_MAX) { - r = EBADF; - } else if (rfd == m_in.fd2) { /* ignore the call: dup2(x, x) */ - r = m_in.fd2; - } else { - /* All is fine, close new_fd if necessary */ - m_in.fd = m_in.fd2; /* prepare to close fd2 */ - unlock_filp(f); /* or it might deadlock on do_close */ - (void) do_close(); /* cannot fail */ - f = get_filp(rfd, VNODE_READ); /* lock old_fd again */ - } - } - - if (r == OK) { - /* Success. Set up new file descriptors. */ - f->filp_count++; - fp->fp_filp[m_in.fd2] = f; - FD_SET(m_in.fd2, &fp->fp_filp_inuse); - r = m_in.fd2; - } - - unlock_filp(f); - return(r); -} - -/*===========================================================================* - * do_fcntl * - *===========================================================================*/ -PUBLIC int do_fcntl() -{ -/* Perform the fcntl(fd, request, ...) system call. */ - - register struct filp *f; - int new_fd, fl, r = OK; - tll_access_t locktype; - - scratch(fp).file.fd_nr = m_in.fd; - scratch(fp).io.io_buffer = m_in.buffer; - scratch(fp).io.io_nbytes = m_in.nbytes; /* a.k.a. m_in.request */ - - /* Is the file descriptor valid? */ - locktype = (m_in.request == F_FREESP) ? VNODE_WRITE : VNODE_READ; - if ((f = get_filp(scratch(fp).file.fd_nr, locktype)) == NULL) - return(err_code); - - switch (m_in.request) { - case F_DUPFD: - /* This replaces the old dup() system call. */ - if (m_in.addr < 0 || m_in.addr >= OPEN_MAX) r = EINVAL; - else if ((r = get_fd(m_in.addr, 0, &new_fd, NULL)) == OK) { - f->filp_count++; - fp->fp_filp[new_fd] = f; - FD_SET(new_fd, &fp->fp_filp_inuse); - r = new_fd; - } - break; - - case F_GETFD: - /* Get close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */ - r = 0; - if (FD_ISSET(scratch(fp).file.fd_nr, &fp->fp_cloexec_set)) - r = FD_CLOEXEC; - break; - - case F_SETFD: - /* Set close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */ - if(m_in.addr & FD_CLOEXEC) - FD_SET(scratch(fp).file.fd_nr, &fp->fp_cloexec_set); - else - FD_CLR(scratch(fp).file.fd_nr, &fp->fp_cloexec_set); - break; - - case F_GETFL: - /* Get file status flags (O_NONBLOCK and O_APPEND). */ - fl = f->filp_flags & (O_NONBLOCK | O_APPEND | O_ACCMODE); - r = fl; - break; - - case F_SETFL: - /* Set file status flags (O_NONBLOCK and O_APPEND). */ - fl = O_NONBLOCK | O_APPEND | O_REOPEN; - f->filp_flags = (f->filp_flags & ~fl) | (m_in.addr & fl); - break; - - case F_GETLK: - case F_SETLK: - case F_SETLKW: - /* Set or clear a file lock. */ - r = lock_op(f, m_in.request); - break; - - case F_FREESP: - { - /* Free a section of a file */ - off_t start, end; - struct flock flock_arg; - signed long offset; - - /* Check if it's a regular file. */ - if ((f->filp_vno->v_mode & I_TYPE) != I_REGULAR) r = EINVAL; - else if (!(f->filp_mode & W_BIT)) r = EBADF; - else - /* Copy flock data from userspace. */ - r = sys_datacopy(who_e, (vir_bytes) m_in.name1, SELF, - (vir_bytes) &flock_arg, - (phys_bytes) sizeof(flock_arg)); - - if (r != OK) break; - - /* Convert starting offset to signed. */ - offset = (signed long) flock_arg.l_start; - - /* Figure out starting position base. */ - switch(flock_arg.l_whence) { - case SEEK_SET: start = 0; break; - case SEEK_CUR: - if (ex64hi(f->filp_pos) != 0) - panic("do_fcntl: position in file too high"); - start = ex64lo(f->filp_pos); - break; - case SEEK_END: start = f->filp_vno->v_size; break; - default: r = EINVAL; - } - if (r != OK) break; - - /* Check for overflow or underflow. */ - if (offset > 0 && start + offset < start) r = EINVAL; - else if (offset < 0 && start + offset > start) r = EINVAL; - else { - start += offset; - if (start < 0) r = EINVAL; - } - if (r != OK) break; - - if (flock_arg.l_len != 0) { - if (start >= f->filp_vno->v_size) r = EINVAL; - else if ((end = start + flock_arg.l_len) <= start) r = EINVAL; - else if (end > f->filp_vno->v_size) end = f->filp_vno->v_size; - } else { - end = 0; - } - if (r != OK) break; - - r = req_ftrunc(f->filp_vno->v_fs_e, f->filp_vno->v_inode_nr,start,end); - - if (r == OK && flock_arg.l_len == 0) - f->filp_vno->v_size = start; - - break; - } - - default: - r = EINVAL; - } - - unlock_filp(f); - return(r); -} - -/*===========================================================================* - * do_sync * - *===========================================================================*/ -PUBLIC int do_sync() -{ - struct vmnt *vmp; - int r = OK; - - for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) { - if (vmp->m_dev != NO_DEV && vmp->m_fs_e != NONE && - vmp->m_root_node != NULL) { - if ((r = lock_vmnt(vmp, VMNT_EXCL)) != OK) - break; - req_sync(vmp->m_fs_e); - unlock_vmnt(vmp); - } - } - - return(r); -} - -/*===========================================================================* - * do_fsync * - *===========================================================================*/ -PUBLIC int do_fsync() -{ -/* Perform the fsync() system call. */ - struct filp *rfilp; - struct vmnt *vmp; - dev_t dev; - int r = OK; - - if ((rfilp = get_filp(m_in.m1_i1, VNODE_READ)) == NULL) return(err_code); - dev = rfilp->filp_vno->v_dev; - for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) { - if (vmp->m_dev != NO_DEV && vmp->m_dev == dev && - vmp->m_fs_e != NONE && vmp->m_root_node != NULL) { - - if ((r = lock_vmnt(vmp, VMNT_EXCL)) != OK) - break; - req_sync(vmp->m_fs_e); - unlock_vmnt(vmp); - } - } - - unlock_filp(rfilp); - - return(r); -} - -/*===========================================================================* - * pm_reboot * - *===========================================================================*/ -PUBLIC void pm_reboot() -{ - /* Perform the VFS side of the reboot call. */ - int i; - struct fproc *rfp; - - do_sync(); - - /* Do exit processing for all leftover processes and servers, - * but don't actually exit them (if they were really gone, PM - * will tell us about it). - */ - for (i = 0; i < NR_PROCS; i++) { - rfp = &fproc[i]; - if (rfp->fp_endpoint == NONE) continue; - - /* Don't just free the proc right away, but let it finish what it was - * doing first */ - lock_proc(rfp, 0); - free_proc(rfp, 0); - unlock_proc(rfp); - } - - do_sync(); - unmount_all(); -} - -/*===========================================================================* - * pm_fork * - *===========================================================================*/ -PUBLIC void pm_fork(pproc, cproc, cpid) -int pproc; /* Parent process */ -int cproc; /* Child process */ -int cpid; /* Child process id */ -{ -/* Perform those aspects of the fork() system call that relate to files. - * In particular, let the child inherit its parent's file descriptors. - * The parent and child parameters tell who forked off whom. The file - * system uses the same slot numbers as the kernel. Only PM makes this call. - */ - - register struct fproc *cp, *pp; - int i, parentno, childno; - mutex_t c_fp_lock; - - /* Check up-to-dateness of fproc. */ - okendpt(pproc, &parentno); - - /* PM gives child endpoint, which implies process slot information. - * Don't call isokendpt, because that will verify if the endpoint - * number is correct in fproc, which it won't be. - */ - childno = _ENDPOINT_P(cproc); - if (childno < 0 || childno >= NR_PROCS) - panic("VFS: bogus child for forking: %d", m_in.child_endpt); - if (fproc[childno].fp_pid != PID_FREE) - panic("VFS: forking on top of in-use child: %d", childno); - - /* Copy the parent's fproc struct to the child. */ - /* However, the mutex variables belong to a slot and must stay the same. */ - c_fp_lock = fproc[childno].fp_lock; - fproc[childno] = fproc[parentno]; - fproc[childno].fp_lock = c_fp_lock; - - /* Increase the counters in the 'filp' table. */ - cp = &fproc[childno]; - pp = &fproc[parentno]; - - for (i = 0; i < OPEN_MAX; i++) - if (cp->fp_filp[i] != NULL) cp->fp_filp[i]->filp_count++; - - /* Fill in new process and endpoint id. */ - cp->fp_pid = cpid; - cp->fp_endpoint = cproc; - - /* A forking process never has an outstanding grant, as it isn't blocking on - * I/O. */ - if(GRANT_VALID(pp->fp_grant)) { - panic("VFS: fork: pp (endpoint %d) has grant %d\n", pp->fp_endpoint, - pp->fp_grant); - } - if(GRANT_VALID(cp->fp_grant)) { - panic("VFS: fork: cp (endpoint %d) has grant %d\n", cp->fp_endpoint, - cp->fp_grant); - } - - /* A child is not a process leader, not being revived, etc. */ - cp->fp_flags = FP_NOFLAGS; - - /* Record the fact that both root and working dir have another user. */ - if (cp->fp_rd) dup_vnode(cp->fp_rd); - if (cp->fp_wd) dup_vnode(cp->fp_wd); -} - -/*===========================================================================* - * free_proc * - *===========================================================================*/ -PRIVATE void free_proc(struct fproc *exiter, int flags) -{ - int i; - register struct fproc *rfp; - register struct filp *rfilp; - register struct vnode *vp; - dev_t dev; - - if (exiter->fp_endpoint == NONE) - panic("free_proc: already free"); - - if (fp_is_blocked(exiter)) - unpause(exiter->fp_endpoint); - - /* Loop on file descriptors, closing any that are open. */ - for (i = 0; i < OPEN_MAX; i++) { - (void) close_fd(exiter, i); - } - - /* Release root and working directories. */ - if (exiter->fp_rd) { put_vnode(exiter->fp_rd); exiter->fp_rd = NULL; } - if (exiter->fp_wd) { put_vnode(exiter->fp_wd); exiter->fp_wd = NULL; } - - /* The rest of these actions is only done when processes actually exit. */ - if (!(flags & FP_EXITING)) return; - - exiter->fp_flags |= FP_EXITING; - - /* Check if any process is SUSPENDed on this driver. - * If a driver exits, unmap its entries in the dmap table. - * (unmapping has to be done after the first step, because the - * dmap table is used in the first step.) - */ - unsuspend_by_endpt(exiter->fp_endpoint); - dmap_unmap_by_endpt(exiter->fp_endpoint); - - worker_stop_by_endpt(exiter->fp_endpoint); /* Unblock waiting threads */ - vmnt_unmap_by_endpt(exiter->fp_endpoint); /* Invalidate open files if this - * was an active FS */ - - /* Invalidate endpoint number for error and sanity checks. */ - exiter->fp_endpoint = NONE; - - /* If a session leader exits and it has a controlling tty, then revoke - * access to its controlling tty from all other processes using it. - */ - if ((exiter->fp_flags & FP_SESLDR) && exiter->fp_tty != 0) { - dev = exiter->fp_tty; - for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - if(rfp->fp_pid == PID_FREE) continue; - if (rfp->fp_tty == dev) rfp->fp_tty = 0; - - for (i = 0; i < OPEN_MAX; i++) { - if ((rfilp = rfp->fp_filp[i]) == NULL) continue; - if (rfilp->filp_mode == FILP_CLOSED) continue; - vp = rfilp->filp_vno; - if ((vp->v_mode & I_TYPE) != I_CHAR_SPECIAL) continue; - if ((dev_t) vp->v_sdev != dev) continue; - lock_filp(rfilp, VNODE_READ); - (void) dev_close(dev, rfilp-filp); /* Ignore any errors, even - * SUSPEND. */ - - rfilp->filp_mode = FILP_CLOSED; - unlock_filp(rfilp); - } - } - } - - /* Exit done. Mark slot as free. */ - exiter->fp_pid = PID_FREE; - if (exiter->fp_flags & FP_PENDING) - pending--; /* No longer pending job, not going to do it */ - exiter->fp_flags = FP_NOFLAGS; -} - -/*===========================================================================* - * pm_exit * - *===========================================================================*/ -PUBLIC void pm_exit(proc) -int proc; -{ -/* Perform the file system portion of the exit(status) system call. */ - int exitee_p; - - /* Nevertheless, pretend that the call came from the user. */ - okendpt(proc, &exitee_p); - fp = &fproc[exitee_p]; - free_proc(fp, FP_EXITING); -} - -/*===========================================================================* - * pm_setgid * - *===========================================================================*/ -PUBLIC void pm_setgid(proc_e, egid, rgid) -int proc_e; -int egid; -int rgid; -{ - register struct fproc *tfp; - int slot; - - okendpt(proc_e, &slot); - tfp = &fproc[slot]; - - tfp->fp_effgid = egid; - tfp->fp_realgid = rgid; -} - - -/*===========================================================================* - * pm_setgroups * - *===========================================================================*/ -PUBLIC void pm_setgroups(proc_e, ngroups, groups) -int proc_e; -int ngroups; -gid_t *groups; -{ - struct fproc *rfp; - int slot; - - okendpt(proc_e, &slot); - rfp = &fproc[slot]; - if (ngroups * sizeof(gid_t) > sizeof(rfp->fp_sgroups)) - panic("VFS: pm_setgroups: too much data to copy"); - if (sys_datacopy(who_e, (vir_bytes) groups, SELF, (vir_bytes) rfp->fp_sgroups, - ngroups * sizeof(gid_t)) == OK) { - rfp->fp_ngroups = ngroups; - } else - panic("VFS: pm_setgroups: datacopy failed"); -} - - -/*===========================================================================* - * pm_setuid * - *===========================================================================*/ -PUBLIC void pm_setuid(proc_e, euid, ruid) -int proc_e; -int euid; -int ruid; -{ - struct fproc *tfp; - int slot; - - okendpt(proc_e, &slot); - tfp = &fproc[slot]; - - tfp->fp_effuid = euid; - tfp->fp_realuid = ruid; -} - -/*===========================================================================* - * do_svrctl * - *===========================================================================*/ -PUBLIC int do_svrctl() -{ - switch (m_in.svrctl_req) { - /* No control request implemented yet. */ - default: - return(EINVAL); - } -} - -/*===========================================================================* - * pm_dumpcore * - *===========================================================================*/ -PUBLIC int pm_dumpcore(endpoint_t proc_e, int csig, vir_bytes exe_name) -{ - int slot, r, core_fd; - struct filp *f; - char core_path[PATH_MAX]; - char proc_name[PROC_NAME_LEN]; - - okendpt(proc_e, &slot); - fp = &fproc[slot]; - - /* open core file */ - snprintf(core_path, PATH_MAX, "%s.%d", CORE_NAME, fp->fp_pid); - core_fd = common_open(core_path, O_WRONLY | O_CREAT | O_TRUNC, CORE_MODE); - if (core_fd < 0) return(core_fd); - - /* get process' name */ - r = sys_datacopy(PM_PROC_NR, exe_name, VFS_PROC_NR, (vir_bytes) proc_name, - PROC_NAME_LEN); - if (r != OK) return(r); - proc_name[PROC_NAME_LEN - 1] = '\0'; - - if ((f = get_filp(core_fd, VNODE_WRITE)) == NULL) return(EBADF); - write_elf_core_file(f, csig, proc_name); - unlock_filp(f); - (void) close_fd(fp, core_fd); /* ignore failure, we're exiting anyway */ - - free_proc(fp, FP_EXITING); - return(OK); -} - -/*===========================================================================* - * ds_event * - *===========================================================================*/ -PUBLIC void ds_event(void) -{ - char key[DS_MAX_KEYLEN]; - char *blkdrv_prefix = "drv.blk."; - char *chrdrv_prefix = "drv.chr."; - u32_t value; - int type, r, is_blk; - endpoint_t owner_endpoint; - - /* Get the event and the owner from DS. */ - while ((r = ds_check(key, &type, &owner_endpoint)) == OK) { - /* Only check for block and character driver up events. */ - if (!strncmp(key, blkdrv_prefix, strlen(blkdrv_prefix))) { - is_blk = TRUE; - } else if (!strncmp(key, chrdrv_prefix, strlen(chrdrv_prefix))) { - is_blk = FALSE; - } else { - continue; - } - - if ((r = ds_retrieve_u32(key, &value)) != OK) { - printf("VFS: ds_event: ds_retrieve_u32 failed\n"); - return; - } - if (value != DS_DRIVER_UP) continue; - - /* Perform up. */ - dmap_endpt_up(owner_endpoint, is_blk); - } - - if (r != ENOENT) printf("VFS: ds_event: ds_check failed: %d\n", r); -} diff --git a/servers/avfs/mount.c b/servers/avfs/mount.c deleted file mode 100644 index 4e4666d5a..000000000 --- a/servers/avfs/mount.c +++ /dev/null @@ -1,614 +0,0 @@ -/* This file performs the MOUNT and UMOUNT system calls. - * - * The entry points into this file are - * do_fsready: perform the FS_READY system call - * do_mount: perform the MOUNT system call - * do_umount: perform the UMOUNT system call - * unmount: unmount a file system - */ - -#include "fs.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "file.h" -#include "fproc.h" -#include "dmap.h" -#include -#include "vnode.h" -#include "vmnt.h" -#include "path.h" -#include "param.h" - -/* Allow the root to be replaced before the first 'real' mount. */ -PRIVATE int have_root = 0; - -/* Bitmap of in-use "none" pseudo devices. */ -PRIVATE bitchunk_t nonedev[BITMAP_CHUNKS(NR_NONEDEVS)] = { 0 }; - -#define alloc_nonedev(dev) SET_BIT(nonedev, minor(dev) - 1) -#define free_nonedev(dev) UNSET_BIT(nonedev, minor(dev) - 1) - -FORWARD _PROTOTYPE( dev_t name_to_dev, (int allow_mountpt, - char path[PATH_MAX]) ); -FORWARD _PROTOTYPE( dev_t find_free_nonedev, (void) ); -FORWARD _PROTOTYPE( void update_bspec, (dev_t dev, endpoint_t fs_e, - int send_drv_e) ); - -/*===========================================================================* - * update_bspec * - *===========================================================================*/ -PRIVATE void update_bspec(dev_t dev, endpoint_t fs_e, int send_drv_e) -{ -/* Update all block special files for a certain device, to use a new FS endpt - * to route raw block I/O requests through. - */ - struct vnode *vp; - struct dmap *dp; - int r, major; - - for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; ++vp) - if (vp->v_ref_count > 0 && S_ISBLK(vp->v_mode) && vp->v_sdev == dev) { - vp->v_bfs_e = fs_e; - if (send_drv_e) { - major = major(dev); - if (major < 0 || major >= NR_DEVICES) { - /* Can't update for out-of-range major */ - continue; - } - dp = &dmap[major(dev)]; - if (dp->dmap_driver == NONE) { - /* Can't update for vanished driver */ - printf("VFS: can't send new driver label\n"); - continue; - } - - if ((r = req_newdriver(fs_e, vp->v_sdev, - dp->dmap_label)) != OK) { - printf("VFS: Failed to send new driver label" - " for moved block special file to %d\n", - fs_e); - } - } - } -} - -/*===========================================================================* - * do_fsready * - *===========================================================================*/ -PUBLIC int do_fsready() -{ - /* deprecated */ - return(SUSPEND); -} - -/*===========================================================================* - * do_mount * - *===========================================================================*/ -PUBLIC int do_mount() -{ -/* Perform the mount(name, mfile, mount_flags) system call. */ - endpoint_t fs_e; - int r, slot, rdonly, nodev; - char fullpath[PATH_MAX]; - char mount_label[LABEL_MAX]; - dev_t dev; - - /* Only the super-user may do MOUNT. */ - if (!super_user) return(EPERM); - - /* FS process' endpoint number */ - if (m_in.mount_flags & MS_LABEL16) { - /* Get the label from the caller, and ask DS for the endpoint. */ - r = sys_datacopy(who_e, (vir_bytes) m_in.fs_label, SELF, - (vir_bytes) mount_label, (phys_bytes) sizeof(mount_label)); - if (r != OK) return(r); - - mount_label[sizeof(mount_label)-1] = 0; - - r = ds_retrieve_label_endpt(mount_label, &fs_e); - if (r != OK) return(r); - } else { - /* Legacy support: get the endpoint from the request itself. */ - fs_e = (endpoint_t) m_in.fs_label; - mount_label[0] = 0; - } - - /* Sanity check on process number. */ - if (isokendpt(fs_e, &slot) != OK) return(EINVAL); - - /* Should the file system be mounted read-only? */ - rdonly = (m_in.mount_flags & MS_RDONLY); - - /* A null string for block special device means don't use a device at all. */ - nodev = (m_in.name1_length == 0); - if (!nodev) { - /* If 'name' is not for a block special file, return error. */ - if (fetch_name(m_in.name1, m_in.name1_length, M1, fullpath) != OK) - return(err_code); - if ((dev = name_to_dev(FALSE /*allow_mountpt*/, fullpath)) == NO_DEV) - return(err_code); - } else { - /* Find a free pseudo-device as substitute for an actual device. */ - if ((dev = find_free_nonedev()) == NO_DEV) - return(err_code); - } - - /* Fetch the name of the mountpoint */ - if (fetch_name(m_in.name2, m_in.name2_length, M1, fullpath) != OK) - return(err_code); - - /* Do the actual job */ - return mount_fs(dev, fullpath, fs_e, rdonly, mount_label); -} - - -/*===========================================================================* - * mount_fs * - *===========================================================================*/ -PUBLIC int mount_fs( -dev_t dev, -char mountpoint[PATH_MAX], -endpoint_t fs_e, -int rdonly, -char mount_label[LABEL_MAX] ) -{ - int rdir, mdir; /* TRUE iff {root|mount} file is dir */ - int i, r = OK, found, isroot, mount_root, con_reqs, slot; - struct fproc *tfp, *rfp; - struct dmap *dp; - struct vnode *root_node, *vp = NULL; - struct vmnt *new_vmp, *parent_vmp; - char *label; - struct node_details res; - struct lookup resolve; - - /* Look up block device driver label when dev is not a pseudo-device */ - label = ""; - if (!is_nonedev(dev)) { - /* Get driver process' endpoint */ - dp = &dmap[major(dev)]; - if (dp->dmap_driver == NONE) { - printf("VFS: no driver for dev %d\n", dev); - return(EINVAL); - } - - label = dp->dmap_label; - assert(strlen(label) > 0); - } - - /* Scan vmnt table to see if dev already mounted. If not, find a free slot.*/ - found = FALSE; - for (i = 0; i < NR_MNTS; ++i) { - if (vmnt[i].m_dev == dev) found = TRUE; - } - if (found) { - return(EBUSY); - } else if ((new_vmp = get_free_vmnt()) == NULL) { - return(ENOMEM); - } - - if ((r = lock_vmnt(new_vmp, VMNT_EXCL)) != OK) return(r); - - isroot = (strcmp(mountpoint, "/") == 0); - mount_root = (isroot && have_root < 2); /* Root can be mounted twice: - * 1: ramdisk - * 2: boot disk (e.g., harddisk) - */ - - if (!mount_root) { - /* Get vnode of mountpoint */ - lookup_init(&resolve, mountpoint, PATH_NOFLAGS, &parent_vmp, &vp); - resolve.l_vmnt_lock = VMNT_EXCL; - resolve.l_vnode_lock = VNODE_WRITE; - if ((vp = eat_path(&resolve, fp)) == NULL) - r = err_code; - else if (vp->v_ref_count == 1) { - /*Tell FS on which vnode it is mounted (glue into mount tree)*/ - r = req_mountpoint(vp->v_fs_e, vp->v_inode_nr); - } else - r = EBUSY; - - if (vp != NULL) { - /* Quickly unlock to allow back calls (from e.g. FUSE) to - * relock */ - unlock_vmnt(parent_vmp); - } - - if (r != OK) { - if (vp != NULL) { - unlock_vnode(vp); - put_vnode(vp); - } - unlock_vmnt(new_vmp); - return(r); - } - } - - /* We'll need a vnode for the root inode */ - if ((root_node = get_free_vnode()) == NULL) { - if (vp != NULL) { - unlock_vnode(vp); - put_vnode(vp); - } - unlock_vmnt(new_vmp); - return(err_code); - } - lock_vnode(root_node, VNODE_OPCL); - - /* Record process as a system process */ - if (isokendpt(fs_e, &slot) != OK) { - if (vp != NULL) { - unlock_vnode(vp); - put_vnode(vp); - } - unlock_vnode(root_node); - unlock_vmnt(new_vmp); - return(EINVAL); - } - rfp = &fproc[slot]; - rfp->fp_flags |= FP_SYS_PROC; /* Process is an FS */ - - /* Store some essential vmnt data first */ - new_vmp->m_fs_e = fs_e; - new_vmp->m_dev = dev; - if (rdonly) new_vmp->m_flags |= VMNT_READONLY; - else new_vmp->m_flags &= ~VMNT_READONLY; - - /* Tell FS which device to mount */ - new_vmp->m_flags |= VMNT_MOUNTING; - r = req_readsuper(fs_e, label, dev, rdonly, isroot, &res, &con_reqs); - new_vmp->m_flags &= ~VMNT_MOUNTING; - - if (r != OK) { - new_vmp->m_fs_e = NONE; - new_vmp->m_dev = NO_DEV; - unlock_vnode(root_node); - if (vp != NULL) { - unlock_vnode(vp); - put_vnode(vp); - } - unlock_vmnt(new_vmp); - return(r); - } - - lock_bsf(); - - /* Fill in root node's fields */ - root_node->v_fs_e = res.fs_e; - root_node->v_inode_nr = res.inode_nr; - root_node->v_mode = res.fmode; - root_node->v_uid = res.uid; - root_node->v_gid = res.gid; - root_node->v_size = res.fsize; - root_node->v_sdev = NO_DEV; - root_node->v_fs_count = 1; - root_node->v_ref_count = 1; - - /* Root node is indeed on the partition */ - root_node->v_vmnt = new_vmp; - root_node->v_dev = new_vmp->m_dev; - if (con_reqs == 0) - new_vmp->m_comm.c_max_reqs = 1; /* Default if FS doesn't tell us */ - else - new_vmp->m_comm.c_max_reqs = con_reqs; - new_vmp->m_comm.c_cur_reqs = 0; - - if (mount_root) { - /* Superblock and root node already read. - * Nothing else can go wrong. Perform the mount. */ - new_vmp->m_root_node = root_node; - new_vmp->m_mounted_on = NULL; - strcpy(new_vmp->m_label, mount_label); - if (is_nonedev(dev)) alloc_nonedev(dev); - update_bspec(dev, fs_e, 0 /* Don't send new driver endpoint */); - - ROOT_DEV = dev; - ROOT_FS_E = fs_e; - - /* Replace all root and working directories */ - for (i = 0, tfp = fproc; i < NR_PROCS; i++, tfp++) { - if (tfp->fp_pid == PID_FREE) - continue; - -#define MAKEROOT(what) { \ - if (what) put_vnode(what); \ - dup_vnode(root_node); \ - what = root_node; \ - } - - MAKEROOT(tfp->fp_rd); - MAKEROOT(tfp->fp_wd); - } - - unlock_vnode(root_node); - unlock_vmnt(new_vmp); - have_root++; /* We have a (new) root */ - unlock_bsf(); - return(OK); - } - - /* File types may not conflict. */ - mdir = ((vp->v_mode & I_TYPE) == I_DIRECTORY); /*TRUE iff dir*/ - rdir = ((root_node->v_mode & I_TYPE) == I_DIRECTORY); - if (!mdir && rdir) r = EISDIR; - - /* If error, return the super block and both inodes; release the vmnt. */ - if (r != OK) { - unlock_vnode(vp); - unlock_vnode(root_node); - unlock_vmnt(new_vmp); - put_vnode(vp); - put_vnode(root_node); - new_vmp->m_dev = NO_DEV; - new_vmp->m_flags = 0; - unlock_bsf(); - return(r); - } - - /* Nothing else can go wrong. Perform the mount. */ - new_vmp->m_mounted_on = vp; - new_vmp->m_root_node = root_node; - strcpy(new_vmp->m_label, mount_label); - - /* Allocate the pseudo device that was found, if not using a real device. */ - if (is_nonedev(dev)) alloc_nonedev(dev); - - /* The new FS will handle block I/O requests for its device now. */ - if (!(new_vmp->m_flags & VMNT_FORCEROOTBSF)) - update_bspec(dev, fs_e, 0 /* Don't send new driver endpoint */); - - unlock_vnode(vp); - unlock_vnode(root_node); - unlock_vmnt(new_vmp); - unlock_bsf(); - - return(OK); -} - - -/*===========================================================================* - * mount_pfs * - *===========================================================================*/ -PUBLIC void mount_pfs(void) -{ -/* Mount the Pipe File Server. It's not really mounted onto the file system, - but it's necessary it has a vmnt entry to make locking easier */ - - dev_t dev; - struct vmnt *vmp; - struct fproc *rfp; - - if ((dev = find_free_nonedev()) == NO_DEV) - panic("VFS: no nonedev to initialize PFS"); - - if ((vmp = get_free_vmnt()) == NULL) - panic("VFS: no vmnt to initialize PFS"); - - alloc_nonedev(dev); - - vmp->m_dev = dev; - vmp->m_fs_e = PFS_PROC_NR; - strcpy(vmp->m_label, "pfs"); - - rfp = &fproc[_ENDPOINT_P(PFS_PROC_NR)]; - rfp->fp_flags |= FP_SYS_PROC; /* PFS is a driver and an FS */ -} - -/*===========================================================================* - * do_umount * - *===========================================================================*/ -PUBLIC int do_umount(void) -{ -/* Perform the umount(name) system call. */ - char label[LABEL_MAX]; - dev_t dev; - int r; - char fullpath[PATH_MAX]; - - /* Only the super-user may do umount. */ - if (!super_user) return(EPERM); - - /* If 'name' is not for a block special file or mountpoint, return error. */ - if (fetch_name(m_in.name, m_in.name_length, M3, fullpath) != OK) - return(err_code); - if ((dev = name_to_dev(TRUE /*allow_mountpt*/, fullpath)) == NO_DEV) - return(err_code); - - if ((r = unmount(dev, label)) != OK) return(r); - - /* Return the label of the mounted file system, so that the caller - * can shut down the corresponding server process. - */ - if (strlen(label) >= M3_LONG_STRING) /* should never evaluate to true */ - label[M3_LONG_STRING-1] = 0; - strcpy(m_out.umount_label, label); - return(OK); -} - - -/*===========================================================================* - * unmount * - *===========================================================================*/ -PUBLIC int unmount( - dev_t dev, /* block-special device */ - char *label /* buffer to retrieve label, or NULL */ -) -{ - struct vnode *vp; - struct vmnt *vmp_i = NULL, *vmp = NULL; - int count, locks, r; - - /* Find vmnt that is to be unmounted */ - for (vmp_i = &vmnt[0]; vmp_i < &vmnt[NR_MNTS]; ++vmp_i) { - if (vmp_i->m_dev == dev) { - if(vmp) panic("device mounted more than once: %d", dev); - vmp = vmp_i; - } - } - - /* Did we find the vmnt (i.e., was dev a mounted device)? */ - if(!vmp) return(EINVAL); - - if ((r = lock_vmnt(vmp, VMNT_EXCL)) != OK) return(r); - - /* See if the mounted device is busy. Only 1 vnode using it should be - * open -- the root vnode -- and that inode only 1 time. */ - locks = count = 0; - for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; vp++) - if (vp->v_ref_count > 0 && vp->v_dev == dev) { - count += vp->v_ref_count; - if (is_vnode_locked(vp)) locks++; - } - - if (count > 1 || locks > 1 || tll_haspendinglock(&vmp->m_lock)) { - unlock_vmnt(vmp); - return(EBUSY); /* can't umount a busy file system */ - } - - /* Tell FS to drop all inode references for root inode except 1. */ - vnode_clean_refs(vmp->m_root_node); - - if (vmp->m_mounted_on) { - put_vnode(vmp->m_mounted_on); - vmp->m_mounted_on = NULL; - } - - vmp->m_comm.c_max_reqs = 1; /* Force max concurrent reqs to just one, so - * we won't send any messages after the - * unmount request */ - - /* Tell FS to unmount */ - if ((r = req_unmount(vmp->m_fs_e)) != OK) /* Not recoverable. */ - printf("VFS: ignoring failed umount attempt FS endpoint: %d (%d)\n", - vmp->m_fs_e, r); - - if (is_nonedev(vmp->m_dev)) free_nonedev(vmp->m_dev); - - if (label != NULL) strcpy(label, vmp->m_label); - - if (vmp->m_root_node) { /* PFS lacks a root node */ - vmp->m_root_node->v_ref_count = 0; - vmp->m_root_node->v_fs_count = 0; - vmp->m_root_node->v_sdev = NO_DEV; - vmp->m_root_node = NULL; - } - vmp->m_dev = NO_DEV; - vmp->m_fs_e = NONE; - - unlock_vmnt(vmp); - - /* The root FS will handle block I/O requests for this device now. */ - lock_bsf(); - update_bspec(dev, ROOT_FS_E, 1 /* send new driver endpoint */); - unlock_bsf(); - - return(OK); -} - - -/*===========================================================================* - * unmount_all * - *===========================================================================*/ -PUBLIC void unmount_all(void) -{ -/* Unmount all filesystems. File systems are mounted on other file systems, - * so you have to pull off the loose bits repeatedly to get it all undone. - */ - - int i; - struct vmnt *vmp; - - /* Now unmount the rest */ - for (i = 0; i < NR_MNTS; i++) { - /* Unmount at least one. */ - for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) { - if (vmp->m_dev != NO_DEV) - unmount(vmp->m_dev, NULL); - } - } - check_vnode_locks(); - check_vmnt_locks(); - check_filp_locks(); - check_bsf_lock(); -} - -/*===========================================================================* - * name_to_dev * - *===========================================================================*/ -PRIVATE dev_t name_to_dev(int allow_mountpt, char path[PATH_MAX]) -{ -/* Convert the block special file in 'user_fullpath' to a device number. - * If the given path is not a block special file, but 'allow_mountpt' is set - * and the path is the root node of a mounted file system, return that device - * number. In all other cases, return NO_DEV and an error code in 'err_code'. - */ - dev_t dev; - struct vnode *vp; - struct vmnt *vmp; - struct lookup resolve; - - lookup_init(&resolve, path, PATH_NOFLAGS, &vmp, &vp); - resolve.l_vmnt_lock = VMNT_READ; - resolve.l_vnode_lock = VNODE_READ; - - /* Request lookup */ - if ((vp = eat_path(&resolve, fp)) == NULL) return(NO_DEV); - - if ((vp->v_mode & I_TYPE) == I_BLOCK_SPECIAL) { - dev = vp->v_sdev; - } else if (allow_mountpt && vp->v_vmnt->m_root_node == vp) { - dev = vp->v_dev; - } else { - err_code = ENOTBLK; - dev = NO_DEV; - } - - unlock_vnode(vp); - unlock_vmnt(vmp); - put_vnode(vp); - return(dev); -} - - -/*===========================================================================* - * is_nonedev * - *===========================================================================*/ -PUBLIC int is_nonedev(dev_t dev) -{ -/* Return whether the given device is a "none" pseudo device. - */ - - return (major(dev) == NONE_MAJOR && - minor(dev) > 0 && minor(dev) <= NR_NONEDEVS); -} - - -/*===========================================================================* - * find_free_nonedev * - *===========================================================================*/ -PRIVATE dev_t find_free_nonedev(void) -{ -/* Find a free "none" pseudo device. Do not allocate it yet. - */ - int i; - - for (i = 0; i < NR_NONEDEVS; i++) - if (!GET_BIT(nonedev, i)) - return makedev(NONE_MAJOR, i + 1); - - err_code = EMFILE; - return NO_DEV; -} diff --git a/servers/avfs/open.c b/servers/avfs/open.c deleted file mode 100644 index a3fd9dc24..000000000 --- a/servers/avfs/open.c +++ /dev/null @@ -1,744 +0,0 @@ -/* This file contains the procedures for creating, opening, closing, and - * seeking on files. - * - * The entry points into this file are - * do_creat: perform the CREAT system call - * do_open: perform the OPEN system call - * do_mknod: perform the MKNOD system call - * do_mkdir: perform the MKDIR system call - * do_close: perform the CLOSE system call - * do_lseek: perform the LSEEK system call - * do_llseek: perform the LLSEEK system call - */ - -#include "fs.h" -#include -#include -#include -#include -#include -#include -#include -#include "file.h" -#include "fproc.h" -#include "scratchpad.h" -#include "dmap.h" -#include "lock.h" -#include "param.h" -#include -#include -#include -#include "vnode.h" -#include "vmnt.h" -#include "path.h" - -PUBLIC char mode_map[] = {R_BIT, W_BIT, R_BIT|W_BIT, 0}; - -FORWARD _PROTOTYPE( struct vnode *new_node, (struct lookup *resolve, - int oflags, mode_t bits) ); -FORWARD _PROTOTYPE( int pipe_open, (struct vnode *vp, mode_t bits, - int oflags) ); - - -/*===========================================================================* - * do_creat * - *===========================================================================*/ -PUBLIC int do_creat() -{ -/* Perform the creat(name, mode) system call. */ - int r; - char fullpath[PATH_MAX]; - - if (fetch_name(m_in.name, m_in.name_length, M3, fullpath) != OK) - return(err_code); - r = common_open(fullpath, O_WRONLY | O_CREAT | O_TRUNC, (mode_t) m_in.mode); - return(r); -} - - -/*===========================================================================* - * do_open * - *===========================================================================*/ -PUBLIC int do_open() -{ -/* Perform the open(name, flags,...) system call. */ - int create_mode = 0; /* is really mode_t but this gives problems */ - int r; - char fullpath[PATH_MAX]; - - /* If O_CREAT is set, open has three parameters, otherwise two. */ - if (m_in.mode & O_CREAT) { - create_mode = m_in.c_mode; - r = fetch_name(m_in.c_name, m_in.name1_length, M1, fullpath); - } else { - r = fetch_name(m_in.name, m_in.name_length, M3, fullpath); - } - - if (r != OK) return(err_code); /* name was bad */ - r = common_open(fullpath, m_in.mode, create_mode); - return(r); -} - - -/*===========================================================================* - * common_open * - *===========================================================================*/ -PUBLIC int common_open(char path[PATH_MAX], int oflags, mode_t omode) -{ -/* Common code from do_creat and do_open. */ - int b, r, exist = TRUE, major_dev; - dev_t dev; - mode_t bits; - struct filp *filp, *filp2; - struct vnode *vp; - struct vmnt *vmp; - struct dmap *dp; - struct lookup resolve; - - /* Remap the bottom two bits of oflags. */ - bits = (mode_t) mode_map[oflags & O_ACCMODE]; - if (!bits) return(EINVAL); - - /* See if file descriptor and filp slots are available. */ - if ((r = get_fd(0, bits, &(scratch(fp).file.fd_nr), &filp)) != OK) return(r); - - lookup_init(&resolve, path, PATH_NOFLAGS, &vmp, &vp); - - /* If O_CREATE is set, try to make the file. */ - if (oflags & O_CREAT) { - omode = I_REGULAR | (omode & ALL_MODES & fp->fp_umask); - vp = new_node(&resolve, oflags, omode); - r = err_code; - if (r == OK) exist = FALSE; /* We just created the file */ - else if (r != EEXIST) { /* other error */ - if (vp) unlock_vnode(vp); - unlock_filp(filp); - return(r); - } - else exist = !(oflags & O_EXCL);/* file exists, if the O_EXCL - flag is set this is an error */ - } else { - /* Scan path name */ - resolve.l_vmnt_lock = VMNT_READ; - resolve.l_vnode_lock = VNODE_OPCL; - if ((vp = eat_path(&resolve, fp)) == NULL) { - unlock_filp(filp); - return(err_code); - } - - if (vmp != NULL) unlock_vmnt(vmp); - } - - /* Claim the file descriptor and filp slot and fill them in. */ - fp->fp_filp[scratch(fp).file.fd_nr] = filp; - FD_SET(scratch(fp).file.fd_nr, &fp->fp_filp_inuse); - filp->filp_count = 1; - filp->filp_vno = vp; - filp->filp_flags = oflags; - - /* Only do the normal open code if we didn't just create the file. */ - if (exist) { - /* Check protections. */ - if ((r = forbidden(fp, vp, bits)) == OK) { - /* Opening reg. files, directories, and special files differ */ - switch (vp->v_mode & I_TYPE) { - case I_REGULAR: - /* Truncate regular file if O_TRUNC. */ - if (oflags & O_TRUNC) { - if ((r = forbidden(fp, vp, W_BIT)) != OK) - break; - truncate_vnode(vp, 0); - } - break; - case I_DIRECTORY: - /* Directories may be read but not written. */ - r = (bits & W_BIT ? EISDIR : OK); - break; - case I_CHAR_SPECIAL: - /* Invoke the driver for special processing. */ - dev = (dev_t) vp->v_sdev; - /* TTY needs to know about the O_NOCTTY flag. */ - r = dev_open(dev, who_e, bits | (oflags & O_NOCTTY)); - if (r == SUSPEND) suspend(FP_BLOCKED_ON_DOPEN); - else vp = filp->filp_vno; /* Might be updated by - * dev_open/clone_opcl */ - break; - case I_BLOCK_SPECIAL: - - lock_bsf(); - - /* Invoke the driver for special processing. */ - dev = (dev_t) vp->v_sdev; - r = bdev_open(dev, bits); - if (r != OK) { - unlock_bsf(); - break; - } - - major_dev = major(vp->v_sdev); - dp = &dmap[major_dev]; - if (dp->dmap_driver == NONE) { - printf("VFS: block driver disappeared!\n"); - unlock_bsf(); - r = ENXIO; - break; - } - - /* Check whether the device is mounted or not. If so, - * then that FS is responsible for this device. - * Otherwise we default to ROOT_FS. - */ - vp->v_bfs_e = ROOT_FS_E; /* By default */ - for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) - if (vmp->m_dev == vp->v_sdev && - !(vmp->m_flags & VMNT_FORCEROOTBSF)) { - vp->v_bfs_e = vmp->m_fs_e; - } - - /* Send the driver label to the file system that will - * handle the block I/O requests (even when its label - * and endpoint are known already), but only when it is - * the root file system. Other file systems will - * already have it anyway. - */ - if (vp->v_bfs_e != ROOT_FS_E) { - unlock_bsf(); - break; - } - - if (req_newdriver(vp->v_bfs_e, vp->v_sdev, - dp->dmap_label) != OK) { - printf("VFS: error sending driver label\n"); - bdev_close(dev); - r = ENXIO; - } - unlock_bsf(); - break; - - case I_NAMED_PIPE: - /* Create a mapped inode on PFS which handles reads - and writes to this named pipe. */ - tll_upgrade(&vp->v_lock); - r = map_vnode(vp, PFS_PROC_NR); - if (r == OK) { - vp->v_pipe = I_PIPE; - if (vp->v_ref_count == 1) { - vp->v_pipe_rd_pos = 0; - vp->v_pipe_wr_pos = 0; - if (vp->v_size != 0) - r = truncate_vnode(vp, 0); - } - oflags |= O_APPEND; /* force append mode */ - filp->filp_flags = oflags; - } - if (r == OK) { - r = pipe_open(vp, bits, oflags); - } - if (r != ENXIO) { - /* See if someone else is doing a rd or wt on - * the FIFO. If so, use its filp entry so the - * file position will be automatically shared. - */ - b = (bits & R_BIT ? R_BIT : W_BIT); - filp->filp_count = 0; /* don't find self */ - if ((filp2 = find_filp(vp, b)) != NULL) { - /* Co-reader or writer found. Use it.*/ - fp->fp_filp[scratch(fp).file.fd_nr] = filp2; - filp2->filp_count++; - filp2->filp_vno = vp; - filp2->filp_flags = oflags; - - /* v_count was incremented after the - * vnode has been found. i_count was - * incremented incorrectly in FS, not - * knowing that we were going to use an - * existing filp entry. Correct this - * error. - */ - unlock_vnode(vp); - put_vnode(vp); - } else { - /* Nobody else found. Restore filp. */ - filp->filp_count = 1; - } - } - break; - } - } - } - - unlock_filp(filp); - - /* If error, release inode. */ - if (r != OK) { - if (r != SUSPEND) { - fp->fp_filp[scratch(fp).file.fd_nr] = NULL; - FD_CLR(scratch(fp).file.fd_nr, &fp->fp_filp_inuse); - filp->filp_count = 0; - filp->filp_vno = NULL; - put_vnode(vp); - } - } else { - r = scratch(fp).file.fd_nr; - } - - return(r); -} - - -/*===========================================================================* - * new_node * - *===========================================================================*/ -PRIVATE struct vnode *new_node(struct lookup *resolve, int oflags, mode_t bits) -{ -/* Try to create a new inode and return a pointer to it. If the inode already - exists, return a pointer to it as well, but set err_code accordingly. - NULL is returned if the path cannot be resolved up to the last - directory, or when the inode cannot be created due to permissions or - otherwise. */ - struct vnode *dirp, *vp; - struct vmnt *dir_vmp, *vp_vmp; - int r; - struct node_details res; - struct lookup findnode; - char *path; - - path = resolve->l_path; /* For easy access */ - - lookup_init(&findnode, path, resolve->l_flags, &dir_vmp, &dirp); - findnode.l_vmnt_lock = VMNT_WRITE; - findnode.l_vnode_lock = VNODE_WRITE; /* dir node */ - - /* When O_CREAT and O_EXCL flags are set, the path may not be named by a - * symbolic link. */ - if (oflags & O_EXCL) findnode.l_flags |= PATH_RET_SYMLINK; - - /* See if the path can be opened down to the last directory. */ - if ((dirp = last_dir(&findnode, fp)) == NULL) return(NULL); - - /* The final directory is accessible. Get final component of the path. */ - lookup_init(&findnode, findnode.l_path, findnode.l_flags, &vp_vmp, &vp); - findnode.l_vmnt_lock = VMNT_WRITE; - findnode.l_vnode_lock = (oflags & O_TRUNC) ? VNODE_WRITE : VNODE_OPCL; - vp = advance(dirp, &findnode, fp); - assert(vp_vmp == NULL); /* Lookup to last dir should have yielded lock - * on vmp or final component does not exist. - * Either way, vp_vmp ought to be not set. - */ - - /* The combination of a symlink with absolute path followed by a danglink - * symlink results in a new path that needs to be re-resolved entirely. */ - if (path[0] == '/') { - unlock_vnode(dirp); - unlock_vmnt(dir_vmp); - put_vnode(dirp); - if (vp != NULL) { - unlock_vnode(vp); - put_vnode(vp); - } - return new_node(resolve, oflags, bits); - } - - if (vp == NULL && err_code == ENOENT) { - /* Last path component does not exist. Make a new directory entry. */ - if ((vp = get_free_vnode()) == NULL) { - /* Can't create new entry: out of vnodes. */ - unlock_vnode(dirp); - unlock_vmnt(dir_vmp); - put_vnode(dirp); - return(NULL); - } - - lock_vnode(vp, VNODE_OPCL); - - if ((r = forbidden(fp, dirp, W_BIT|X_BIT)) != OK || - (r = req_create(dirp->v_fs_e, dirp->v_inode_nr,bits, fp->fp_effuid, - fp->fp_effgid, path, &res)) != OK ) { - /* Can't create inode either due to permissions or some other - * problem. In case r is EEXIST, we might be dealing with a - * dangling symlink.*/ - if (r == EEXIST) { - struct vnode *slp, *old_wd; - - /* Resolve path up to symlink */ - findnode.l_flags = PATH_RET_SYMLINK; - findnode.l_vnode_lock = VNODE_READ; - findnode.l_vnode = &slp; - slp = advance(dirp, &findnode, fp); - if (slp != NULL) { - if (S_ISLNK(slp->v_mode)) { - /* Get contents of link */ - - r = req_rdlink(slp->v_fs_e, - slp->v_inode_nr, - VFS_PROC_NR, - path, - PATH_MAX - 1, 0); - if (r < 0) { - /* Failed to read link */ - unlock_vnode(slp); - unlock_vnode(dirp); - unlock_vmnt(dir_vmp); - put_vnode(slp); - put_vnode(dirp); - err_code = r; - return(NULL); - } - path[r] = '\0'; /* Terminate path */ - } - unlock_vnode(slp); - put_vnode(slp); - } - - /* Try to create the inode the dangling symlink was - * pointing to. We have to use dirp as starting point - * as there might be multiple successive symlinks - * crossing multiple mountpoints. - * Unlock vnodes and vmnts as we're going to recurse. - */ - unlock_vnode(dirp); - unlock_vnode(vp); - unlock_vmnt(dir_vmp); - - old_wd = fp->fp_wd; /* Save orig. working dirp */ - fp->fp_wd = dirp; - vp = new_node(resolve, oflags, bits); - fp->fp_wd = old_wd; /* Restore */ - - if (vp != NULL) { - put_vnode(dirp); - *(resolve->l_vnode) = vp; - return(vp); - } - r = err_code; - } - - if (r == EEXIST) - err_code = EIO; /* Impossible, we have verified that - * the last component doesn't exist and - * is not a dangling symlink. */ - else - err_code = r; - - unlock_vnode(dirp); - unlock_vnode(vp); - unlock_vmnt(dir_vmp); - put_vnode(dirp); - return(NULL); - } - - /* Store results and mark vnode in use */ - - vp->v_fs_e = res.fs_e; - vp->v_inode_nr = res.inode_nr; - vp->v_mode = res.fmode; - vp->v_size = res.fsize; - vp->v_uid = res.uid; - vp->v_gid = res.gid; - vp->v_sdev = res.dev; - vp->v_vmnt = dirp->v_vmnt; - vp->v_dev = vp->v_vmnt->m_dev; - vp->v_fs_count = 1; - vp->v_ref_count = 1; - } else { - /* Either last component exists, or there is some other problem. */ - if (vp != NULL) { - r = EEXIST; /* File exists or a symlink names a file while - * O_EXCL is set. */ - } else - r = err_code; /* Other problem. */ - } - - err_code = r; - /* When dirp equals vp, we shouldn't release the lock as a vp is locked only - * once. Releasing the lock would cause the resulting vp not be locked and - * cause mayhem later on. */ - if (dirp != vp) { - unlock_vnode(dirp); - } - unlock_vmnt(dir_vmp); - put_vnode(dirp); - - *(resolve->l_vnode) = vp; - return(vp); -} - - -/*===========================================================================* - * pipe_open * - *===========================================================================*/ -PRIVATE int pipe_open(struct vnode *vp, mode_t bits, int oflags) -{ -/* This function is called from common_open. It checks if - * there is at least one reader/writer pair for the pipe, if not - * it suspends the caller, otherwise it revives all other blocked - * processes hanging on the pipe. - */ - - vp->v_pipe = I_PIPE; - - if ((bits & (R_BIT|W_BIT)) == (R_BIT|W_BIT)) return(ENXIO); - - /* Find the reader/writer at the other end of the pipe */ - if (find_filp(vp, bits & W_BIT ? R_BIT : W_BIT) == NULL) { - /* Not found */ - if (oflags & O_NONBLOCK) { - if (bits & W_BIT) return(ENXIO); - } else { - /* Let's wait for the other side to show up */ - suspend(FP_BLOCKED_ON_POPEN); - return(SUSPEND); - } - } else if (susp_count > 0) { /* revive blocked processes */ - release(vp, OPEN, susp_count); - release(vp, CREAT, susp_count); - } - return(OK); -} - - -/*===========================================================================* - * do_mknod * - *===========================================================================*/ -PUBLIC int do_mknod() -{ -/* Perform the mknod(name, mode, addr) system call. */ - register mode_t bits, mode_bits; - int r; - struct vnode *vp; - struct vmnt *vmp; - char fullpath[PATH_MAX]; - struct lookup resolve; - - lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); - resolve.l_vmnt_lock = VMNT_WRITE; - resolve.l_vnode_lock = VNODE_READ; - - /* Only the super_user may make nodes other than fifos. */ - mode_bits = (mode_t) m_in.mk_mode; /* mode of the inode */ - if (!super_user && (((mode_bits & I_TYPE) != I_NAMED_PIPE) && - ((mode_bits & I_TYPE) != I_UNIX_SOCKET))) { - return(EPERM); - } - bits = (mode_bits & I_TYPE) | (mode_bits & ALL_MODES & fp->fp_umask); - - /* Open directory that's going to hold the new node. */ - if (fetch_name(m_in.name1, m_in.name1_length, M1, fullpath) != OK) - return(err_code); - if ((vp = last_dir(&resolve, fp)) == NULL) return(err_code); - - /* Make sure that the object is a directory */ - if ((vp->v_mode & I_TYPE) != I_DIRECTORY) { - r = ENOTDIR; - } else if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) { - r = req_mknod(vp->v_fs_e, vp->v_inode_nr, fullpath, fp->fp_effuid, - fp->fp_effgid, bits, m_in.mk_z0); - } - - unlock_vnode(vp); - unlock_vmnt(vmp); - put_vnode(vp); - return(r); -} - -/*===========================================================================* - * do_mkdir * - *===========================================================================*/ -PUBLIC int do_mkdir() -{ -/* Perform the mkdir(name, mode) system call. */ - mode_t bits; /* mode bits for the new inode */ - int r; - struct vnode *vp; - struct vmnt *vmp; - char fullpath[PATH_MAX]; - struct lookup resolve; - - lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); - resolve.l_vmnt_lock = VMNT_WRITE; - resolve.l_vnode_lock = VNODE_READ; - - if (fetch_name(m_in.name1, m_in.name1_length, M1, fullpath) != OK) - return(err_code); - bits = I_DIRECTORY | (m_in.mode & RWX_MODES & fp->fp_umask); - if ((vp = last_dir(&resolve, fp)) == NULL) return(err_code); - - /* Make sure that the object is a directory */ - if ((vp->v_mode & I_TYPE) != I_DIRECTORY) { - r = ENOTDIR; - } else if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) { - r = req_mkdir(vp->v_fs_e, vp->v_inode_nr, fullpath, fp->fp_effuid, - fp->fp_effgid, bits); - } - - unlock_vnode(vp); - unlock_vmnt(vmp); - put_vnode(vp); - return(r); -} - -/*===========================================================================* - * do_lseek * - *===========================================================================*/ -PUBLIC int do_lseek() -{ -/* Perform the lseek(ls_fd, offset, whence) system call. */ - register struct filp *rfilp; - int r = OK; - long offset; - u64_t pos, newpos; - - /* Check to see if the file descriptor is valid. */ - if ( (rfilp = get_filp(m_in.ls_fd, VNODE_READ)) == NULL) return(err_code); - - /* No lseek on pipes. */ - if (rfilp->filp_vno->v_pipe == I_PIPE) { - unlock_filp(rfilp); - return(ESPIPE); - } - - /* The value of 'whence' determines the start position to use. */ - switch(m_in.whence) { - case SEEK_SET: pos = cvu64(0); break; - case SEEK_CUR: pos = rfilp->filp_pos; break; - case SEEK_END: pos = cvul64(rfilp->filp_vno->v_size); break; - default: unlock_filp(rfilp); return(EINVAL); - } - - offset = m_in.offset_lo; - if (offset >= 0) - newpos = add64ul(pos, offset); - else - newpos = sub64ul(pos, -offset); - - /* Check for overflow. */ - if (ex64hi(newpos) != 0) { - r = EOVERFLOW; - } else if ((off_t) ex64lo(newpos) < 0) { /* no negative file size */ - r = EOVERFLOW; - } else { - rfilp->filp_pos = newpos; - - /* insert the new position into the output message */ - m_out.reply_l1 = ex64lo(newpos); - - if (cmp64(newpos, rfilp->filp_pos) != 0) { - /* Inhibit read ahead request */ - r = req_inhibread(rfilp->filp_vno->v_fs_e, - rfilp->filp_vno->v_inode_nr); - } - } - - unlock_filp(rfilp); - return(r); -} - -/*===========================================================================* - * do_llseek * - *===========================================================================*/ -PUBLIC int do_llseek() -{ -/* Perform the llseek(ls_fd, offset, whence) system call. */ - register struct filp *rfilp; - u64_t pos, newpos; - int r = OK; - - /* Check to see if the file descriptor is valid. */ - if ( (rfilp = get_filp(m_in.ls_fd, VNODE_READ)) == NULL) return(err_code); - - /* No lseek on pipes. */ - if (rfilp->filp_vno->v_pipe == I_PIPE) { - unlock_filp(rfilp); - return(ESPIPE); - } - - /* The value of 'whence' determines the start position to use. */ - switch(m_in.whence) { - case SEEK_SET: pos = cvu64(0); break; - case SEEK_CUR: pos = rfilp->filp_pos; break; - case SEEK_END: pos = cvul64(rfilp->filp_vno->v_size); break; - default: unlock_filp(rfilp); return(EINVAL); - } - - newpos = add64(pos, make64(m_in.offset_lo, m_in.offset_high)); - - /* Check for overflow. */ - if (( (long) m_in.offset_high > 0) && cmp64(newpos, pos) < 0) - r = EINVAL; - else if (( (long) m_in.offset_high < 0) && cmp64(newpos, pos) > 0) - r = EINVAL; - else { - rfilp->filp_pos = newpos; - - /* insert the new position into the output message */ - m_out.reply_l1 = ex64lo(newpos); - m_out.reply_l2 = ex64hi(newpos); - - if (cmp64(newpos, rfilp->filp_pos) != 0) { - /* Inhibit read ahead request */ - r = req_inhibread(rfilp->filp_vno->v_fs_e, - rfilp->filp_vno->v_inode_nr); - } - } - - unlock_filp(rfilp); - return(r); -} - -/*===========================================================================* - * do_close * - *===========================================================================*/ -PUBLIC int do_close() -{ -/* Perform the close(fd) system call. */ - - return close_fd(fp, m_in.fd); -} - - -/*===========================================================================* - * close_fd * - *===========================================================================*/ -PUBLIC int close_fd(rfp, fd_nr) -struct fproc *rfp; -int fd_nr; -{ -/* Perform the close(fd) system call. */ - register struct filp *rfilp; - register struct vnode *vp; - struct file_lock *flp; - int lock_count; - - /* First locate the vnode that belongs to the file descriptor. */ - if ( (rfilp = get_filp2(rfp, fd_nr, VNODE_OPCL)) == NULL) return(err_code); - vp = rfilp->filp_vno; - - close_filp(rfilp); - rfp->fp_filp[fd_nr] = NULL; - FD_CLR(fd_nr, &rfp->fp_cloexec_set); - FD_CLR(fd_nr, &rfp->fp_filp_inuse); - - /* Check to see if the file is locked. If so, release all locks. */ - if (nr_locks > 0) { - lock_count = nr_locks; /* save count of locks */ - for (flp = &file_lock[0]; flp < &file_lock[NR_LOCKS]; flp++) { - if (flp->lock_type == 0) continue; /* slot not in use */ - if (flp->lock_vnode == vp && flp->lock_pid == rfp->fp_pid) { - flp->lock_type = 0; - nr_locks--; - } - } - if (nr_locks < lock_count) - lock_revive(); /* one or more locks released */ - } - - return(OK); -} - -/*===========================================================================* - * close_reply * - *===========================================================================*/ -PUBLIC void close_reply() -{ - /* No need to do anything */ -} diff --git a/servers/avfs/param.h b/servers/avfs/param.h deleted file mode 100644 index ea05621bb..000000000 --- a/servers/avfs/param.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef __VFS_PARAM_H__ -#define __VFS_PARAM_H__ - -/* The following names are synonyms for the variables in the input message. */ -#define addr m1_i3 -#define buffer m1_p1 -#define child_endpt m1_i2 -#define co_mode m1_i1 -#define fd m1_i1 -#define fd2 m1_i2 -#define group m1_i3 -#define ls_fd m2_i1 -#define mk_mode m1_i2 -#define mk_z0 m1_i3 -#define mode m3_i2 -#define c_mode m1_i3 -#define c_name m1_p1 -#define name m3_p1 -#define flength m2_l1 -#define name1 m1_p1 -#define name2 m1_p2 -#define name_length m3_i1 -#define name1_length m1_i1 -#define name2_length m1_i2 -#define nbytes m1_i2 -#define owner m1_i2 -#define pathname m3_ca1 -#define pid m1_i3 -#define ENDPT m1_i1 -#define offset_lo m2_l1 -#define offset_high m2_l2 -#define ctl_req m4_l1 -#define mount_flags m1_i3 -#define request m1_i2 -#define sig m1_i2 -#define endpt1 m1_i1 -#define fs_label m1_p3 -#define umount_label m3_ca1 -#define tp m2_l1 -#define utime_actime m2_l1 -#define utime_modtime m2_l2 -#define utime_file m2_p1 -#define utime_length m2_i1 -#define utime_strlen m2_i2 -#define whence m2_i2 -#define svrctl_req m2_i1 -#define svrctl_argp m2_p1 -#define md_label m2_p1 -#define md_label_len m2_l1 -#define md_major m2_i1 -#define md_style m2_i2 -#define md_flags m2_i3 - -/* The following names are synonyms for the variables in the output message. */ -#define reply_type m_type -#define reply_l1 m2_l1 -#define reply_l2 m2_l2 -#define reply_i1 m1_i1 -#define reply_i2 m1_i2 - -#endif diff --git a/servers/avfs/path.c b/servers/avfs/path.c deleted file mode 100644 index a6945458f..000000000 --- a/servers/avfs/path.c +++ /dev/null @@ -1,814 +0,0 @@ -/* lookup() is the main routine that controls the path name lookup. It - * handles mountpoints and symbolic links. The actual lookup requests - * are sent through the req_lookup wrapper function. - */ - -#include "fs.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "threads.h" -#include "vmnt.h" -#include "vnode.h" -#include "path.h" -#include "fproc.h" -#include "param.h" - -/* Set to following define to 1 if you really want to use the POSIX definition - * (IEEE Std 1003.1, 2004) of pathname resolution. POSIX requires pathnames - * with a traling slash (and that do not entirely consist of slash characters) - * to be treated as if a single dot is appended. This means that for example - * mkdir("dir/", ...) and rmdir("dir/") will fail because the call tries to - * create or remove the directory '.'. Historically, Unix systems just ignore - * trailing slashes. - */ -#define DO_POSIX_PATHNAME_RES 0 - -FORWARD _PROTOTYPE( int lookup, (struct vnode *dirp, struct lookup *resolve, - node_details_t *node, struct fproc *rfp)); -FORWARD _PROTOTYPE( int check_perms, (endpoint_t ep, cp_grant_id_t io_gr, - size_t pathlen) ); - -/*===========================================================================* - * advance * - *===========================================================================*/ -PUBLIC struct vnode *advance(dirp, resolve, rfp) -struct vnode *dirp; -struct lookup *resolve; -struct fproc *rfp; -{ -/* Resolve a path name starting at dirp to a vnode. */ - int r; - int do_downgrade = 1; - struct vnode *new_vp, *vp; - struct vmnt *vmp; - struct node_details res = {0,0,0,0,0,0,0}; - tll_access_t initial_locktype; - - assert(dirp); - assert(resolve->l_vnode_lock != TLL_NONE); - assert(resolve->l_vmnt_lock != TLL_NONE); - - if (resolve->l_vnode_lock == VNODE_READ) - initial_locktype = VNODE_OPCL; - else - initial_locktype = resolve->l_vnode_lock; - - /* Get a free vnode and lock it */ - if ((new_vp = get_free_vnode()) == NULL) return(NULL); - lock_vnode(new_vp, initial_locktype); - - /* Lookup vnode belonging to the file. */ - if ((r = lookup(dirp, resolve, &res, rfp)) != OK) { - err_code = r; - unlock_vnode(new_vp); - return(NULL); - } - - /* Check whether we already have a vnode for that file */ - if ((vp = find_vnode(res.fs_e, res.inode_nr)) != NULL) { - unlock_vnode(new_vp); /* Don't need this anymore */ - do_downgrade = (lock_vnode(vp, initial_locktype) != EBUSY); - - /* Unfortunately, by the time we get the lock, another thread might've - * rid of the vnode (e.g., find_vnode found the vnode while a - * req_putnode was being processed). */ - if (vp->v_ref_count == 0) { /* vnode vanished! */ - /* As the lookup before increased the usage counters in the FS, - * we can simply set the usage counters to 1 and proceed as - * normal, because the putnode resulted in a use count of 1 in - * the FS. Other data is still valid, because the vnode was - * marked as pending lock, so get_free_vnode hasn't - * reinitialized the vnode yet. */ - vp->v_fs_count = 1; - if (vp->v_mapfs_e != NONE) vp->v_mapfs_count = 1; - } else { - vp->v_fs_count++; /* We got a reference from the FS */ - } - - } else { - /* Vnode not found, fill in the free vnode's fields */ - - new_vp->v_fs_e = res.fs_e; - new_vp->v_inode_nr = res.inode_nr; - new_vp->v_mode = res.fmode; - new_vp->v_size = res.fsize; - new_vp->v_uid = res.uid; - new_vp->v_gid = res.gid; - new_vp->v_sdev = res.dev; - - if( (vmp = find_vmnt(new_vp->v_fs_e)) == NULL) - panic("advance: vmnt not found"); - - new_vp->v_vmnt = vmp; - new_vp->v_dev = vmp->m_dev; - new_vp->v_fs_count = 1; - - vp = new_vp; - } - - dup_vnode(vp); - if (do_downgrade) { - /* Only downgrade a lock if we managed to lock it in the first place */ - *(resolve->l_vnode) = vp; - - if (initial_locktype != resolve->l_vnode_lock) - tll_downgrade(&vp->v_lock); - -#if LOCK_DEBUG - if (resolve->l_vnode_lock == VNODE_READ) - fp->fp_vp_rdlocks++; -#endif - } - - return(vp); -} - -/*===========================================================================* - * eat_path * - *===========================================================================*/ -PUBLIC struct vnode *eat_path(resolve, rfp) -struct lookup *resolve; -struct fproc *rfp; -{ -/* Resolve path to a vnode. advance does the actual work. */ - struct vnode *start_dir; - - start_dir = (resolve->l_path[0] == '/' ? rfp->fp_rd : rfp->fp_wd); - return advance(start_dir, resolve, rfp); -} - -/*===========================================================================* - * last_dir * - *===========================================================================*/ -PUBLIC struct vnode *last_dir(resolve, rfp) -struct lookup *resolve; -struct fproc *rfp; -{ -/* Parse a path, as far as the last directory, fetch the vnode - * for the last directory into the vnode table, and return a pointer to the - * vnode. In addition, return the final component of the path in 'string'. If - * the last directory can't be opened, return NULL and the reason for - * failure in 'err_code'. We can't parse component by component as that would - * be too expensive. Alternatively, we cut off the last component of the path, - * and parse the path up to the penultimate component. - */ - - size_t len; - char *cp; - char dir_entry[NAME_MAX+1]; - struct vnode *start_dir, *res_vp, *sym_vp, *loop_start; - struct vmnt *sym_vmp = NULL; - int r, symloop = 0, ret_on_symlink = 0; - struct lookup symlink; - - *resolve->l_vnode = NULL; - *resolve->l_vmp = NULL; - loop_start = NULL; - sym_vp = NULL; - - ret_on_symlink = !!(resolve->l_flags & PATH_RET_SYMLINK); - - do { - /* Is the path absolute or relative? Initialize 'start_dir' - * accordingly. Use loop_start in case we're looping. - */ - if (loop_start != NULL) - start_dir = loop_start; - else - start_dir = (resolve->l_path[0] == '/' ? rfp->fp_rd:rfp->fp_wd); - - len = strlen(resolve->l_path); - - /* If path is empty, return ENOENT. */ - if (len == 0) { - err_code = ENOENT; - res_vp = NULL; - break; - } - -#if !DO_POSIX_PATHNAME_RES - /* Remove trailing slashes */ - while (len > 1 && resolve->l_path[len-1] == '/') { - len--; - resolve->l_path[len]= '\0'; - } -#endif - - cp = strrchr(resolve->l_path, '/'); - if (cp == NULL) { - /* Just an entry in the current working directory */ - struct vmnt *vmp; - - vmp = find_vmnt(start_dir->v_fs_e); - if (vmp == NULL) { - r = EIO; - res_vp = NULL; - break; - } - r = lock_vmnt(vmp, resolve->l_vmnt_lock); - if (r == EDEADLK) { - res_vp = NULL; - break; - } else if (r == OK) - *resolve->l_vmp = vmp; - - lock_vnode(start_dir, resolve->l_vnode_lock); - *resolve->l_vnode = start_dir; - dup_vnode(start_dir); - if (loop_start != NULL) { - unlock_vnode(loop_start); - put_vnode(loop_start); - } - return(start_dir); - } else if (cp[1] == '\0') { - /* Path ends in a slash. The directory entry is '.' */ - strcpy(dir_entry, "."); - } else { - /* A path name for the directory and a directory entry */ - strncpy(dir_entry, cp+1, NAME_MAX); - cp[1] = '\0'; - dir_entry[NAME_MAX] = '\0'; - } - - /* Remove trailing slashes */ - while (cp > resolve->l_path && cp[0] == '/') { - cp[0]= '\0'; - cp--; - } - - /* Resolve up to and including the last directory of the path. Turn off - * PATH_RET_SYMLINK, because we do want to follow the symlink in this - * case. That is, the flag is meant for the actual filename of the path, - * not the last directory. - */ - resolve->l_flags &= ~PATH_RET_SYMLINK; - if ((res_vp = advance(start_dir, resolve, rfp)) == NULL) { - break; - } - - /* If the directory entry is not a symlink we're done now. If it is a - * symlink, then we're not at the last directory, yet. */ - - /* Copy the directory entry back to user_fullpath */ - strncpy(resolve->l_path, dir_entry, NAME_MAX + 1); - - /* Look up the directory entry, but do not follow the symlink when it - * is one. - */ - lookup_init(&symlink, resolve->l_path, - resolve->l_flags|PATH_RET_SYMLINK, &sym_vmp, &sym_vp); - symlink.l_vnode_lock = VNODE_READ; - symlink.l_vmnt_lock = VMNT_READ; - sym_vp = advance(res_vp, &symlink, rfp); - - /* Advance caused us to either switch to a different vmnt or we're - * still at the same vmnt. The former might've yielded a new vmnt lock, - * the latter should not have. Verify. */ - if (sym_vmp != NULL) { - /* We got a vmnt lock, so the endpoints of the vnodes must - * differ. - */ - assert(sym_vp->v_fs_e != res_vp->v_fs_e); - } - - if (sym_vp != NULL && S_ISLNK(sym_vp->v_mode)) { - /* Last component is a symlink, but if we've been asked to not - * resolve it, return now. - */ - if (ret_on_symlink) { - break; - } - - r = req_rdlink(sym_vp->v_fs_e, sym_vp->v_inode_nr, NONE, - resolve->l_path, PATH_MAX - 1, 1); - - if (r < 0) { - /* Failed to read link */ - err_code = r; - unlock_vnode(res_vp); - unlock_vmnt(*resolve->l_vmp); - put_vnode(res_vp); - *resolve->l_vmp = NULL; - *resolve->l_vnode = NULL; - res_vp = NULL; - break; - } - resolve->l_path[r] = '\0'; - - if (strrchr(resolve->l_path, '/') != NULL) { - unlock_vnode(sym_vp); - unlock_vmnt(*resolve->l_vmp); - if (sym_vmp != NULL) - unlock_vmnt(sym_vmp); - *resolve->l_vmp = NULL; - put_vnode(sym_vp); - sym_vp = NULL; - - symloop++; - - /* Relative symlinks are relative to res_vp, not cwd */ - if (resolve->l_path[0] != '/') { - loop_start = res_vp; - } else { - /* Absolute symlink, forget about res_vp */ - unlock_vnode(res_vp); - put_vnode(res_vp); - } - - continue; - } - } - break; - } while (symloop < SYMLOOP_MAX); - - if (symloop >= SYMLOOP_MAX) { - err_code = ELOOP; - res_vp = NULL; - } - - if (sym_vp != NULL) { - unlock_vnode(sym_vp); - if (sym_vmp != NULL) { - unlock_vmnt(sym_vmp); - } - put_vnode(sym_vp); - } - - if (loop_start != NULL) { - unlock_vnode(loop_start); - put_vnode(loop_start); - } - - /* Copy the directory entry back to user_fullpath */ - strncpy(resolve->l_path, dir_entry, NAME_MAX + 1); - return(res_vp); -} - -/*===========================================================================* - * lookup * - *===========================================================================*/ -PRIVATE int lookup(start_node, resolve, result_node, rfp) -struct vnode *start_node; -struct lookup *resolve; -node_details_t *result_node; -struct fproc *rfp; -{ -/* Resolve a path name relative to start_node. */ - - int r, symloop; - endpoint_t fs_e; - size_t path_off, path_left_len; - ino_t dir_ino, root_ino; - uid_t uid; - gid_t gid; - struct vnode *dir_vp; - struct vmnt *vmp, *vmpres; - struct lookup_res res; - - assert(resolve->l_vmp); - assert(resolve->l_vnode); - - *(resolve->l_vmp) = vmpres = NULL; /* No vmnt found nor locked yet */ - - /* Empty (start) path? */ - if (resolve->l_path[0] == '\0') { - result_node->inode_nr = 0; - return(ENOENT); - } - - if (!rfp->fp_rd || !rfp->fp_wd) { - printf("VFS: lookup %d: no rd/wd\n", rfp->fp_endpoint); - return(ENOENT); - } - - fs_e = start_node->v_fs_e; - dir_ino = start_node->v_inode_nr; - vmpres = find_vmnt(fs_e); - - if (vmpres == NULL) return(EIO); /* mountpoint vanished? */ - - /* Is the process' root directory on the same partition?, - * if so, set the chroot directory too. */ - if (rfp->fp_rd->v_dev == rfp->fp_wd->v_dev) - root_ino = rfp->fp_rd->v_inode_nr; - else - root_ino = 0; - - /* Set user and group ids according to the system call */ - uid = (call_nr == ACCESS ? rfp->fp_realuid : rfp->fp_effuid); - gid = (call_nr == ACCESS ? rfp->fp_realgid : rfp->fp_effgid); - - symloop = 0; /* Number of symlinks seen so far */ - - /* Lock vmnt */ - if ((r = lock_vmnt(vmpres, resolve->l_vmnt_lock)) != OK) { - if (r == EBUSY) /* vmnt already locked */ - vmpres = NULL; - else - return(r); - } - *(resolve->l_vmp) = vmpres; - - /* Issue the request */ - r = req_lookup(fs_e, dir_ino, root_ino, uid, gid, resolve, &res, rfp); - - if (r != OK && r != EENTERMOUNT && r != ELEAVEMOUNT && r != ESYMLINK) { - if (vmpres) unlock_vmnt(vmpres); - *(resolve->l_vmp) = NULL; - return(r); /* i.e., an error occured */ - } - - /* While the response is related to mount control set the - * new requests respectively */ - while (r == EENTERMOUNT || r == ELEAVEMOUNT || r == ESYMLINK) { - /* Update user_fullpath to reflect what's left to be parsed. */ - path_off = res.char_processed; - path_left_len = strlen(&resolve->l_path[path_off]); - memmove(resolve->l_path, &resolve->l_path[path_off], path_left_len); - resolve->l_path[path_left_len] = '\0'; /* terminate string */ - - /* Update the current value of the symloop counter */ - symloop += res.symloop; - if (symloop > SYMLOOP_MAX) { - if (vmpres) unlock_vmnt(vmpres); - *(resolve->l_vmp) = NULL; - return(ELOOP); - } - - /* Symlink encountered with absolute path */ - if (r == ESYMLINK) { - dir_vp = rfp->fp_rd; - vmp = NULL; - } else if (r == EENTERMOUNT) { - /* Entering a new partition */ - dir_vp = NULL; - /* Start node is now the mounted partition's root node */ - for (vmp = &vmnt[0]; vmp != &vmnt[NR_MNTS]; ++vmp) { - if (vmp->m_dev != NO_DEV && vmp->m_mounted_on) { - if (vmp->m_mounted_on->v_inode_nr == res.inode_nr && - vmp->m_mounted_on->v_fs_e == res.fs_e) { - dir_vp = vmp->m_root_node; - break; - } - } - } - if (dir_vp == NULL) { - printf("VFS: path lookup error; root node not found\n"); - if (vmpres) unlock_vmnt(vmpres); - *(resolve->l_vmp) = NULL; - return(EIO); - } - } else { - /* Climbing up mount */ - /* Find the vmnt that represents the partition on - * which we "climb up". */ - if ((vmp = find_vmnt(res.fs_e)) == NULL) { - panic("VFS lookup: can't find parent vmnt"); - } - - /* Make sure that the child FS does not feed a bogus path - * to the parent FS. That is, when we climb up the tree, we - * must've encountered ".." in the path, and that is exactly - * what we're going to feed to the parent */ - if(strncmp(resolve->l_path, "..", 2) != 0 || - (resolve->l_path[2] != '\0' && resolve->l_path[2] != '/')) { - printf("VFS: bogus path: %s\n", resolve->l_path); - if (vmpres) unlock_vmnt(vmpres); - *(resolve->l_vmp) = NULL; - return(ENOENT); - } - - /* Start node is the vnode on which the partition is - * mounted */ - dir_vp = vmp->m_mounted_on; - } - - /* Set the starting directories inode number and FS endpoint */ - fs_e = dir_vp->v_fs_e; - dir_ino = dir_vp->v_inode_nr; - - /* Is the process' root directory on the same partition?, - * if so, set the chroot directory too. */ - if (dir_vp->v_dev == rfp->fp_rd->v_dev) - root_ino = rfp->fp_rd->v_inode_nr; - else - root_ino = 0; - - /* Unlock a previously locked vmnt if locked and lock new vmnt */ - if (vmpres) unlock_vmnt(vmpres); - vmpres = find_vmnt(fs_e); - if (vmpres == NULL) return(EIO); /* mount point vanished? */ - if ((r = lock_vmnt(vmpres, resolve->l_vmnt_lock)) != OK) { - if (r == EBUSY) - vmpres = NULL; /* Already locked */ - else - return(r); - } - *(resolve->l_vmp) = vmpres; - - r = req_lookup(fs_e, dir_ino, root_ino, uid, gid, resolve, &res, rfp); - - if (r != OK && r != EENTERMOUNT && r != ELEAVEMOUNT && r != ESYMLINK) { - if (vmpres) unlock_vmnt(vmpres); - *(resolve->l_vmp) = NULL; - return(r); - } - } - - /* Fill in response fields */ - result_node->inode_nr = res.inode_nr; - result_node->fmode = res.fmode; - result_node->fsize = res.fsize; - result_node->dev = res.dev; - result_node->fs_e = res.fs_e; - result_node->uid = res.uid; - result_node->gid = res.gid; - - return(r); -} - -/*===========================================================================* - * lookup_init * - *===========================================================================*/ -PUBLIC void lookup_init(resolve, path, flags, vmp, vp) -struct lookup *resolve; -char *path; -int flags; -struct vmnt **vmp; -struct vnode **vp; -{ - assert(vmp != NULL); - assert(vp != NULL); - - resolve->l_path = path; - resolve->l_flags = flags; - resolve->l_vmp = vmp; - resolve->l_vnode = vp; - resolve->l_vmnt_lock = TLL_NONE; - resolve->l_vnode_lock = TLL_NONE; - *vmp = NULL; /* Initialize lookup result to NULL */ - *vp = NULL; -} - -/*===========================================================================* - * get_name * - *===========================================================================*/ -PUBLIC int get_name(dirp, entry, ename) -struct vnode *dirp; -struct vnode *entry; -char ename[NAME_MAX + 1]; -{ - u64_t pos, new_pos; - int r, consumed, totalbytes; - char buf[(sizeof(struct dirent) + NAME_MAX) * 8]; - struct dirent *cur; - - pos = make64(0, 0); - - if ((dirp->v_mode & I_TYPE) != I_DIRECTORY) { - return(EBADF); - } - - do { - r = req_getdents(dirp->v_fs_e, dirp->v_inode_nr, pos, buf, sizeof(buf), - &new_pos, 1); - - if (r == 0) { - return(ENOENT); /* end of entries -- matching inode !found */ - } else if (r < 0) { - return(r); /* error */ - } - - consumed = 0; /* bytes consumed */ - totalbytes = r; /* number of bytes to consume */ - - do { - cur = (struct dirent *) (buf + consumed); - if (entry->v_inode_nr == cur->d_ino) { - /* found the entry we were looking for */ - strncpy(ename, cur->d_name, NAME_MAX); - ename[NAME_MAX] = '\0'; - return(OK); - } - - /* not a match -- move on to the next dirent */ - consumed += cur->d_reclen; - } while (consumed < totalbytes); - - pos = new_pos; - } while (1); -} - -/*===========================================================================* - * canonical_path * - *===========================================================================*/ -PUBLIC int canonical_path(orig_path, rfp) -char orig_path[PATH_MAX]; -struct fproc *rfp; -{ -/* Find canonical path of a given path */ - int len = 0; - int r, symloop = 0; - struct vnode *dir_vp, *parent_dir; - struct vmnt *dir_vmp, *parent_vmp; - char component[NAME_MAX+1]; /* NAME_MAX does /not/ include '\0' */ - char temp_path[PATH_MAX]; - struct lookup resolve; - - dir_vp = NULL; - strncpy(temp_path, orig_path, PATH_MAX); - temp_path[PATH_MAX - 1] = '\0'; - - /* First resolve path to the last directory holding the file */ - do { - if (dir_vp) { - unlock_vnode(dir_vp); - unlock_vmnt(dir_vmp); - put_vnode(dir_vp); - } - - lookup_init(&resolve, temp_path, PATH_NOFLAGS, &dir_vmp, &dir_vp); - resolve.l_vmnt_lock = VMNT_READ; - resolve.l_vnode_lock = VNODE_READ; - if ((dir_vp = last_dir(&resolve, rfp)) == NULL) return(err_code); - - /* dir_vp points to dir and resolve path now contains only the - * filename. - */ - strncpy(orig_path, temp_path, NAME_MAX); /* Store file name */ - - /* check if the file is a symlink, if so resolve it */ - r = rdlink_direct(orig_path, temp_path, rfp); - - if (r <= 0) - break; - - /* encountered a symlink -- loop again */ - strncpy(orig_path, temp_path, PATH_MAX - 1); - symloop++; - } while (symloop < SYMLOOP_MAX); - - if (symloop >= SYMLOOP_MAX) { - if (dir_vp) { - unlock_vnode(dir_vp); - unlock_vmnt(dir_vmp); - put_vnode(dir_vp); - } - return(ELOOP); - } - - /* We've got the filename and the actual directory holding the file. From - * here we start building up the canonical path by climbing up the tree */ - while (dir_vp != rfp->fp_rd) { - - strcpy(temp_path, ".."); - - /* check if we're at the root node of the file system */ - if (dir_vp->v_vmnt->m_root_node == dir_vp) { - unlock_vnode(dir_vp); - unlock_vmnt(dir_vmp); - put_vnode(dir_vp); - dir_vp = dir_vp->v_vmnt->m_mounted_on; - dir_vmp = dir_vp->v_vmnt; - if (lock_vmnt(dir_vmp, VMNT_READ) != OK) - panic("failed to lock vmnt"); - if (lock_vnode(dir_vp, VNODE_READ) != OK) - panic("failed to lock vnode"); - dup_vnode(dir_vp); - } - - lookup_init(&resolve, temp_path, PATH_NOFLAGS, &parent_vmp, - &parent_dir); - resolve.l_vmnt_lock = VMNT_READ; - resolve.l_vnode_lock = VNODE_READ; - - if ((parent_dir = advance(dir_vp, &resolve, rfp)) == NULL) { - unlock_vnode(dir_vp); - unlock_vmnt(dir_vmp); - put_vnode(dir_vp); - return(err_code); - } - - /* now we have to retrieve the name of the parent directory */ - if (get_name(parent_dir, dir_vp, component) != OK) { - unlock_vnode(parent_dir); - unlock_vmnt(parent_vmp); - unlock_vnode(dir_vp); - unlock_vmnt(dir_vmp); - put_vnode(parent_dir); - put_vnode(dir_vp); - return(ENOENT); - } - - len += strlen(component) + 1; - if (len >= PATH_MAX) { - /* adding the component to orig_path would exceed PATH_MAX */ - unlock_vnode(parent_dir); - unlock_vmnt(parent_vmp); - unlock_vnode(dir_vp); - unlock_vmnt(dir_vmp); - put_vnode(parent_dir); - put_vnode(dir_vp); - return(ENOMEM); - } - - /* Store result of component in orig_path. First make space by moving - * the contents of orig_path to the right. Move strlen + 1 bytes to - * include the terminating '\0'. Move to strlen + 1 bytes to reserve - * space for the slash. - */ - memmove(orig_path+strlen(component)+1, orig_path, strlen(orig_path)+1); - /* Copy component into canon_path */ - memmove(orig_path, component, strlen(component)); - /* Put slash into place */ - orig_path[strlen(component)] = '/'; - - /* Store parent_dir result, and continue the loop once more */ - unlock_vnode(dir_vp); - unlock_vmnt(dir_vmp); - put_vnode(dir_vp); - dir_vp = parent_dir; - } - - unlock_vnode(dir_vp); - unlock_vmnt(parent_vmp); - - put_vnode(dir_vp); - - /* add the leading slash */ - if (strlen(orig_path) >= PATH_MAX) return(ENAMETOOLONG); - memmove(orig_path+1, orig_path, strlen(orig_path)); - orig_path[0] = '/'; - - return(OK); -} - -/*===========================================================================* - * check_perms * - *===========================================================================*/ -PRIVATE int check_perms(ep, io_gr, pathlen) -endpoint_t ep; -cp_grant_id_t io_gr; -size_t pathlen; -{ - int r, slot; - struct vnode *vp; - struct vmnt *vmp; - struct fproc *rfp; - char canon_path[PATH_MAX]; - struct lookup resolve; - - if (isokendpt(ep, &slot) != OK) return(EINVAL); - if (pathlen < UNIX_PATH_MAX || pathlen >= PATH_MAX) return(EINVAL); - - rfp = &(fproc[slot]); - r = sys_safecopyfrom(PFS_PROC_NR, io_gr, (vir_bytes) 0, - (vir_bytes) canon_path, pathlen, D); - if (r != OK) return(r); - canon_path[pathlen] = '\0'; - - /* Turn path into canonical path to the socket file */ - if ((r = canonical_path(canon_path, rfp)) != OK) - return(r); - - if (strlen(canon_path) >= pathlen) return(ENAMETOOLONG); - - /* copy canon_path back to PFS */ - r = sys_safecopyto(PFS_PROC_NR, (cp_grant_id_t) io_gr, (vir_bytes) 0, - (vir_bytes) canon_path, pathlen, D); - if (r != OK) return(r); - - /* Now do permissions checking */ - lookup_init(&resolve, canon_path, PATH_NOFLAGS, &vmp, &vp); - resolve.l_vmnt_lock = VMNT_READ; - resolve.l_vnode_lock = VNODE_READ; - if ((vp = eat_path(&resolve, rfp)) == NULL) return(err_code); - - /* check permissions */ - r = forbidden(rfp, vp, (R_BIT | W_BIT)); - - unlock_vnode(vp); - unlock_vmnt(vmp); - - put_vnode(vp); - return(r); -} - -/*===========================================================================* - * do_check_perms * - *===========================================================================*/ -PUBLIC int do_check_perms(void) -{ - return check_perms(m_in.USER_ENDPT, (cp_grant_id_t) m_in.IO_GRANT, - (size_t) m_in.COUNT); -} diff --git a/servers/avfs/pipe.c b/servers/avfs/pipe.c deleted file mode 100644 index 0a6d6f49d..000000000 --- a/servers/avfs/pipe.c +++ /dev/null @@ -1,645 +0,0 @@ -/* This file deals with the suspension and revival of processes. A process can - * be suspended because it wants to read or write from a pipe and can't, or - * because it wants to read or write from a special file and can't. When a - * process can't continue it is suspended, and revived later when it is able - * to continue. - * - * The entry points into this file are - * do_pipe: perform the PIPE system call - * pipe_check: check to see that a read or write on a pipe is feasible now - * suspend: suspend a process that cannot do a requested read or write - * release: check to see if a suspended process can be released and do - * it - * revive: mark a suspended process as able to run again - * unsuspend_by_endpt: revive all processes blocking on a given process - * do_unpause: a signal has been sent to a process; see if it suspended - */ - -#include "fs.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "file.h" -#include "fproc.h" -#include "scratchpad.h" -#include "dmap.h" -#include "param.h" -#include "select.h" -#include -#include "vnode.h" -#include "vmnt.h" - - -/*===========================================================================* - * do_pipe * - *===========================================================================*/ -PUBLIC int do_pipe() -{ -/* Perform the pipe(fil_des) system call. */ - - register struct fproc *rfp; - int r; - struct filp *fil_ptr0, *fil_ptr1; - int fil_des[2]; /* reply goes here */ - struct vnode *vp; - struct vmnt *vmp; - struct node_details res; - - /* Get a lock on PFS */ - if ((vmp = find_vmnt(PFS_PROC_NR)) == NULL) panic("PFS gone"); - if ((r = lock_vmnt(vmp, VMNT_WRITE)) != OK) return(r); - - /* See if a free vnode is available */ - if ((vp = get_free_vnode()) == NULL) return(err_code); - lock_vnode(vp, VNODE_OPCL); - - /* Acquire two file descriptors. */ - rfp = fp; - if ((r = get_fd(0, R_BIT, &fil_des[0], &fil_ptr0)) != OK) { - unlock_vnode(vp); - unlock_vmnt(vmp); - return(r); - } - rfp->fp_filp[fil_des[0]] = fil_ptr0; - FD_SET(fil_des[0], &rfp->fp_filp_inuse); - fil_ptr0->filp_count = 1; /* mark filp in use */ - if ((r = get_fd(0, W_BIT, &fil_des[1], &fil_ptr1)) != OK) { - rfp->fp_filp[fil_des[0]] = NULL; - FD_CLR(fil_des[0], &rfp->fp_filp_inuse); - fil_ptr0->filp_count = 0; /* mark filp free */ - unlock_filp(fil_ptr0); - unlock_vnode(vp); - unlock_vmnt(vmp); - return(r); - } - rfp->fp_filp[fil_des[1]] = fil_ptr1; - FD_SET(fil_des[1], &rfp->fp_filp_inuse); - fil_ptr1->filp_count = 1; - - /* Create a named pipe inode on PipeFS */ - r = req_newnode(PFS_PROC_NR, fp->fp_effuid, fp->fp_effgid, I_NAMED_PIPE, - NO_DEV, &res); - - if (r != OK) { - rfp->fp_filp[fil_des[0]] = NULL; - FD_CLR(fil_des[0], &rfp->fp_filp_inuse); - fil_ptr0->filp_count = 0; - rfp->fp_filp[fil_des[1]] = NULL; - FD_CLR(fil_des[1], &rfp->fp_filp_inuse); - fil_ptr1->filp_count = 0; - unlock_filp(fil_ptr1); - unlock_filp(fil_ptr0); - unlock_vnode(vp); - unlock_vmnt(vmp); - return(r); - } - - /* Fill in vnode */ - vp->v_fs_e = res.fs_e; - vp->v_mapfs_e = res.fs_e; - vp->v_inode_nr = res.inode_nr; - vp->v_mapinode_nr = res.inode_nr; - vp->v_mode = res.fmode; - vp->v_pipe = I_PIPE; - vp->v_pipe_rd_pos= 0; - vp->v_pipe_wr_pos= 0; - vp->v_fs_count = 1; - vp->v_mapfs_count = 1; - vp->v_ref_count = 1; - vp->v_size = 0; - vp->v_vmnt = NULL; - vp->v_dev = NO_DEV; - - /* Fill in filp objects */ - fil_ptr0->filp_vno = vp; - dup_vnode(vp); - fil_ptr1->filp_vno = vp; - fil_ptr0->filp_flags = O_RDONLY; - fil_ptr1->filp_flags = O_WRONLY; - - m_out.reply_i1 = fil_des[0]; - m_out.reply_i2 = fil_des[1]; - - unlock_filps(fil_ptr0, fil_ptr1); - unlock_vmnt(vmp); - - return(OK); -} - - -/*===========================================================================* - * map_vnode * - *===========================================================================*/ -PUBLIC int map_vnode(vp, map_to_fs_e) -struct vnode *vp; -endpoint_t map_to_fs_e; -{ - int r; - struct vmnt *vmp; - struct node_details res; - - if(vp->v_mapfs_e != NONE) return(OK); /* Already mapped; nothing to do. */ - - if ((vmp = find_vmnt(map_to_fs_e)) == NULL) - panic("Can't map to unknown endpoint"); - if ((r = lock_vmnt(vmp, VMNT_WRITE)) != OK) { - if (r == EBUSY) - vmp = NULL; /* Already locked, do not unlock */ - else - return(r); - - } - - /* Create a temporary mapping of this inode to another FS. Read and write - * operations on data will be handled by that FS. The rest by the 'original' - * FS that holds the inode. */ - if ((r = req_newnode(map_to_fs_e, fp->fp_effuid, fp->fp_effgid, I_NAMED_PIPE, - vp->v_dev, &res)) == OK) { - vp->v_mapfs_e = res.fs_e; - vp->v_mapinode_nr = res.inode_nr; - vp->v_mapfs_count = 1; - } - - if (vmp) unlock_vmnt(vmp); - - return(r); -} - -/*===========================================================================* - * pipe_check * - *===========================================================================*/ -PUBLIC int pipe_check(vp, rw_flag, oflags, bytes, position, notouch) -register struct vnode *vp; /* the inode of the pipe */ -int rw_flag; /* READING or WRITING */ -int oflags; /* flags set by open or fcntl */ -register int bytes; /* bytes to be read or written (all chunks) */ -u64_t position; /* current file position */ -int notouch; /* check only */ -{ -/* Pipes are a little different. If a process reads from an empty pipe for - * which a writer still exists, suspend the reader. If the pipe is empty - * and there is no writer, return 0 bytes. If a process is writing to a - * pipe and no one is reading from it, give a broken pipe error. - */ - off_t pos; - int r = OK; - - if (ex64hi(position) != 0) - panic("pipe_check: position too large in pipe"); - pos = ex64lo(position); - - /* If reading, check for empty pipe. */ - if (rw_flag == READING) { - if (pos >= vp->v_size) { - /* Process is reading from an empty pipe. */ - if (find_filp(vp, W_BIT) != NULL) { - /* Writer exists */ - if (oflags & O_NONBLOCK) - r = EAGAIN; - else - r = SUSPEND; - - /* If need be, activate sleeping writers. */ - if (susp_count > 0) - release(vp, WRITE, susp_count); - } - return(r); - } - return(bytes); - } - - /* Process is writing to a pipe. */ - if (find_filp(vp, R_BIT) == NULL) { - /* Process is writing, but there is no reader. Tell kernel to generate - * a SIGPIPE signal. */ - if (!notouch) sys_kill(fp->fp_endpoint, SIGPIPE); - - return(EPIPE); - } - - /* Calculate how many bytes can be written. */ - if (pos + bytes > PIPE_BUF) { - if (oflags & O_NONBLOCK) { - if (bytes <= PIPE_BUF) { - /* Write has to be atomic */ - return(EAGAIN); - } - - /* Compute available space */ - bytes = PIPE_BUF - pos; - - if (bytes > 0) { - /* Do a partial write. Need to wakeup reader */ - if (!notouch) - release(vp, READ, susp_count); - return(bytes); - } else { - /* Pipe is full */ - return(EAGAIN); - } - } - - if (bytes > PIPE_BUF) { - /* Compute available space */ - bytes = PIPE_BUF - pos; - - if (bytes > 0) { - /* Do a partial write. Need to wakeup reader - * since we'll suspend ourself in read_write() - */ - if (!notouch) - release(vp, READ, susp_count); - return(bytes); - } - } - - /* Pipe is full */ - return(SUSPEND); - } - - /* Writing to an empty pipe. Search for suspended reader. */ - if (pos == 0 && !notouch) - release(vp, READ, susp_count); - - /* Requested amount fits */ - return(bytes); -} - - -/*===========================================================================* - * suspend * - *===========================================================================*/ -PUBLIC void suspend(int why) -{ -/* Take measures to suspend the processing of the present system call. - * Store the parameters to be used upon resuming in the process table. - * (Actually they are not used when a process is waiting for an I/O device, - * but they are needed for pipes, and it is not worth making the distinction.) - * The SUSPEND pseudo error should be returned after calling suspend(). - */ - -#if DO_SANITYCHECKS - if(fp_is_blocked(fp)) - panic("suspend: called for suspended process"); - - if(why == FP_BLOCKED_ON_NONE) - panic("suspend: called for FP_BLOCKED_ON_NONE"); -#endif - - if (why == FP_BLOCKED_ON_POPEN || why == FP_BLOCKED_ON_PIPE) - /* #procs susp'ed on pipe*/ - susp_count++; - - fp->fp_blocked_on = why; - assert(fp->fp_grant == GRANT_INVALID || !GRANT_VALID(fp->fp_grant)); - fp->fp_block_callnr = call_nr; - fp->fp_flags &= ~FP_SUSP_REOPEN; /* Clear this flag. The caller - * can set it when needed. - */ -} - -/*===========================================================================* - * wait_for * - *===========================================================================*/ -PUBLIC void wait_for(endpoint_t who) -{ - if(who == NONE || who == ANY) - panic("suspend on NONE or ANY"); - suspend(FP_BLOCKED_ON_OTHER); - fp->fp_task = who; -} - - -/*===========================================================================* - * pipe_suspend * - *===========================================================================*/ -PUBLIC void pipe_suspend(filp, buf, size) -struct filp *filp; -char *buf; -size_t size; -{ -/* Take measures to suspend the processing of the present system call. - * Store the parameters to be used upon resuming in the process table. - */ -#if DO_SANITYCHECKS - if(fp_is_blocked(fp)) - panic("pipe_suspend: called for suspended process"); -#endif - - scratch(fp).file.filp = filp; - scratch(fp).io.io_buffer = buf; - scratch(fp).io.io_nbytes = size; - suspend(FP_BLOCKED_ON_PIPE); -} - - -/*===========================================================================* - * unsuspend_by_endpt * - *===========================================================================*/ -PUBLIC void unsuspend_by_endpt(endpoint_t proc_e) -{ -/* Revive processes waiting for drivers (SUSPENDed) that have disappeared with - * return code EAGAIN. - */ - struct fproc *rp; - - for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) { - if (rp->fp_pid == PID_FREE) continue; - if (rp->fp_blocked_on == FP_BLOCKED_ON_OTHER && rp->fp_task == proc_e) - revive(rp->fp_endpoint, EAGAIN); - } - - /* Revive processes waiting in drivers on select()s with EAGAIN too */ - select_unsuspend_by_endpt(proc_e); - - return; -} - - -/*===========================================================================* - * release * - *===========================================================================*/ -PUBLIC void release(vp, op, count) -register struct vnode *vp; /* inode of pipe */ -int op; /* READ, WRITE, OPEN or CREAT */ -int count; /* max number of processes to release */ -{ -/* Check to see if any process is hanging on vnode 'vp'. If one is, and it - * was trying to perform the call indicated by 'call_nr', release it. - */ - - register struct fproc *rp; - struct filp *f; - int selop; - - /* Trying to perform the call also includes SELECTing on it with that - * operation. - */ - if (op == READ || op == WRITE) { - if (op == READ) - selop = SEL_RD; - else - selop = SEL_WR; - - for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { - if (f->filp_count < 1 || !(f->filp_pipe_select_ops & selop) || - f->filp_vno != vp) - continue; - select_callback(f, selop); - f->filp_pipe_select_ops &= ~selop; - } - } - - /* Search the proc table. */ - for (rp = &fproc[0]; rp < &fproc[NR_PROCS] && count > 0; rp++) { - if (rp->fp_pid != PID_FREE && fp_is_blocked(rp) && - !(rp->fp_flags & FP_REVIVED) && rp->fp_block_callnr == op) { - /* Find the vnode. Depending on the reason the process was - * suspended, there are different ways of finding it. - */ - - if (rp->fp_blocked_on == FP_BLOCKED_ON_POPEN || - rp->fp_blocked_on == FP_BLOCKED_ON_DOPEN || - rp->fp_blocked_on == FP_BLOCKED_ON_LOCK || - rp->fp_blocked_on == FP_BLOCKED_ON_OTHER) { - if (!FD_ISSET(scratch(rp).file.fd_nr, - &rp->fp_filp_inuse)) - continue; - if (rp->fp_filp[scratch(rp).file.fd_nr]->filp_vno != vp) - continue; - } else if (rp->fp_blocked_on == FP_BLOCKED_ON_PIPE) { - if (scratch(rp).file.filp == NULL) - continue; - if (scratch(rp).file.filp->filp_vno != vp) - continue; - } else - continue; - - /* We found the vnode. Revive process. */ - revive(rp->fp_endpoint, 0); - susp_count--; /* keep track of who is suspended */ - if(susp_count < 0) - panic("susp_count now negative: %d", susp_count); - if (--count == 0) return; - } - } -} - - -/*===========================================================================* - * revive * - *===========================================================================*/ -PUBLIC void revive(proc_nr_e, returned) -int proc_nr_e; /* process to revive */ -int returned; /* if hanging on task, how many bytes read */ -{ -/* Revive a previously blocked process. When a process hangs on tty, this - * is the way it is eventually released. - */ - register struct fproc *rfp; - int blocked_on; - int fd_nr, slot; - struct filp *fil_ptr; - - if (proc_nr_e == NONE || isokendpt(proc_nr_e, &slot) != OK) return; - - rfp = &fproc[slot]; - if (!fp_is_blocked(rfp) || (rfp->fp_flags & FP_REVIVED)) return; - - /* The 'reviving' flag only applies to pipes. Processes waiting for TTY get - * a message right away. The revival process is different for TTY and pipes. - * For select and TTY revival, the work is already done, for pipes it is not: - * the proc must be restarted so it can try again. - */ - blocked_on = rfp->fp_blocked_on; - fd_nr = scratch(rfp).file.fd_nr; - if (blocked_on == FP_BLOCKED_ON_PIPE || blocked_on == FP_BLOCKED_ON_LOCK) { - /* Revive a process suspended on a pipe or lock. */ - rfp->fp_flags |= FP_REVIVED; - reviving++; /* process was waiting on pipe or lock */ - } else if (blocked_on == FP_BLOCKED_ON_DOPEN) { - rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; - scratch(rfp).file.fd_nr = 0; - if (returned < 0) { - fil_ptr = rfp->fp_filp[fd_nr]; - lock_filp(fil_ptr, VNODE_OPCL); - rfp->fp_filp[fd_nr] = NULL; - FD_CLR(fd_nr, &rfp->fp_filp_inuse); - if (fil_ptr->filp_count != 1) { - panic("VFS: revive: bad count in filp: %d", - fil_ptr->filp_count); - } - fil_ptr->filp_count = 0; - unlock_filp(fil_ptr); - put_vnode(fil_ptr->filp_vno); - fil_ptr->filp_vno = NULL; - reply(proc_nr_e, returned); - } else { - reply(proc_nr_e, fd_nr); - } - } else { - rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; - scratch(rfp).file.fd_nr = 0; - if (blocked_on == FP_BLOCKED_ON_POPEN) { - /* process blocked in open or create */ - reply(proc_nr_e, fd_nr); - } else if (blocked_on == FP_BLOCKED_ON_SELECT) { - reply(proc_nr_e, returned); - } else { - /* Revive a process suspended on TTY or other device. - * Pretend it wants only what there is. - */ - scratch(rfp).io.io_nbytes = returned; - /* If a grant has been issued by FS for this I/O, revoke - * it again now that I/O is done. - */ - if (GRANT_VALID(rfp->fp_grant)) { - if(cpf_revoke(rfp->fp_grant)) { - panic("VFS: revoke failed for grant: %d", - rfp->fp_grant); - } - rfp->fp_grant = GRANT_INVALID; - } - reply(proc_nr_e, returned); /* unblock the process */ - } - } -} - - -/*===========================================================================* - * unpause * - *===========================================================================*/ -PUBLIC void unpause(endpoint_t proc_e) -{ -/* A signal has been sent to a user who is paused on the file system. - * Abort the system call with the EINTR error message. - */ - - register struct fproc *rfp, *org_fp; - int slot, blocked_on, fild, status = EINTR, major_dev, minor_dev; - struct filp *f; - dev_t dev; - message mess; - int wasreviving = 0; - - if (isokendpt(proc_e, &slot) != OK) { - printf("VFS: ignoring unpause for bogus endpoint %d\n", proc_e); - return; - } - - rfp = &fproc[slot]; - if (!fp_is_blocked(rfp)) return; - blocked_on = rfp->fp_blocked_on; - - if (rfp->fp_flags & FP_REVIVED) { - rfp->fp_flags &= ~FP_REVIVED; - reviving--; - wasreviving = 1; - } - - switch (blocked_on) { - case FP_BLOCKED_ON_PIPE:/* process trying to read or write a pipe */ - break; - - case FP_BLOCKED_ON_LOCK:/* process trying to set a lock with FCNTL */ - break; - - case FP_BLOCKED_ON_SELECT:/* process blocking on select() */ - select_forget(proc_e); - break; - - case FP_BLOCKED_ON_POPEN: /* process trying to open a fifo */ - break; - - case FP_BLOCKED_ON_DOPEN:/* process trying to open a device */ - /* Don't cancel OPEN. Just wait until the open completes. */ - return; - - case FP_BLOCKED_ON_OTHER:/* process trying to do device I/O (e.g. tty)*/ - if (rfp->fp_flags & FP_SUSP_REOPEN) { - /* Process is suspended while waiting for a reopen. - * Just reply EINTR. - */ - rfp->fp_flags &= ~FP_SUSP_REOPEN; - status = EINTR; - break; - } - - fild = scratch(rfp).file.fd_nr; - if (fild < 0 || fild >= OPEN_MAX) - panic("file descriptor out-of-range"); - f = rfp->fp_filp[fild]; - dev = (dev_t) f->filp_vno->v_sdev; /* device hung on */ - major_dev = major(dev); - minor_dev = minor(dev); - mess.TTY_LINE = minor_dev; - mess.USER_ENDPT = rfp->fp_ioproc; - mess.IO_GRANT = (char *) rfp->fp_grant; - - /* Tell kernel R or W. Mode is from current call, not open. */ - mess.COUNT = rfp->fp_block_callnr == READ ? R_BIT : W_BIT; - mess.m_type = CANCEL; - - org_fp = fp; - fp = rfp; /* hack - ctty_io uses fp */ - (*dmap[major_dev].dmap_io)(rfp->fp_task, &mess); - fp = org_fp; - status = mess.REP_STATUS; - if (status == SUSPEND) - return; /* Process will be revived at a - * later time. - */ - - if (status == EAGAIN) status = EINTR; - if (GRANT_VALID(rfp->fp_grant)) { - (void) cpf_revoke(rfp->fp_grant); - rfp->fp_grant = GRANT_INVALID; - } - break; - default : - panic("VFS: unknown block reason: %d", blocked_on); - } - - rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; - - if ((blocked_on == FP_BLOCKED_ON_PIPE || blocked_on == FP_BLOCKED_ON_POPEN)&& - !wasreviving) { - susp_count--; - } - - reply(proc_e, status); /* signal interrupted call */ -} - -#if DO_SANITYCHECKS -/*===========================================================================* - * check_pipe * - *===========================================================================*/ -PUBLIC int check_pipe(void) -{ -/* Integrity check; verify that susp_count equals what the fproc table thinks - * is suspended on a pipe */ - struct fproc *rfp; - int count = 0; - for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - if (rfp->fp_pid == PID_FREE) continue; - if ( !(rfp->fp_flags & FP_REVIVED) && - (rfp->fp_blocked_on == FP_BLOCKED_ON_PIPE || - rfp->fp_blocked_on == FP_BLOCKED_ON_POPEN)) { - count++; - } - } - - if (count != susp_count) { - printf("check_pipe: count %d susp_count %d\n", count, susp_count); - return(0); - } - - return(l); -} -#endif diff --git a/servers/avfs/protect.c b/servers/avfs/protect.c deleted file mode 100644 index 04325c614..000000000 --- a/servers/avfs/protect.c +++ /dev/null @@ -1,276 +0,0 @@ -/* This file deals with protection in the file system. It contains the code - * for four system calls that relate to protection. - * - * The entry points into this file are - * do_chmod: perform the CHMOD and FCHMOD system calls - * do_chown: perform the CHOWN and FCHOWN system calls - * do_umask: perform the UMASK system call - * do_access: perform the ACCESS system call - */ - -#include "fs.h" -#include -#include -#include "file.h" -#include "fproc.h" -#include "path.h" -#include "param.h" -#include -#include "vnode.h" -#include "vmnt.h" - -/*===========================================================================* - * do_chmod * - *===========================================================================*/ -PUBLIC int do_chmod() -{ -/* Perform the chmod(name, mode) and fchmod(fd, mode) system calls. */ - - struct filp *flp; - struct vnode *vp; - struct vmnt *vmp; - int r; - mode_t new_mode; - char fullpath[PATH_MAX]; - struct lookup resolve; - - flp = NULL; - - lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); - resolve.l_vmnt_lock = VMNT_WRITE; - resolve.l_vnode_lock = VNODE_WRITE; - - if (call_nr == CHMOD) { - /* Temporarily open the file */ - if (fetch_name(m_in.name, m_in.name_length, M3, fullpath) != OK) - return(err_code); - if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); - } else { /* call_nr == FCHMOD */ - /* File is already opened; get a pointer to vnode from filp. */ - if ((flp = get_filp(m_in.fd, VNODE_WRITE)) == NULL) - return(err_code); - vp = flp->filp_vno; - dup_vnode(vp); - } - - /* Only the owner or the super_user may change the mode of a file. - * No one may change the mode of a file on a read-only file system. - */ - if (vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID) - r = EPERM; - else - r = read_only(vp); - - if (r == OK) { - /* Now make the change. Clear setgid bit if file is not in caller's - * group */ - if (fp->fp_effuid != SU_UID && vp->v_gid != fp->fp_effgid) - m_in.mode &= ~I_SET_GID_BIT; - - r = req_chmod(vp->v_fs_e, vp->v_inode_nr, m_in.mode, &new_mode); - if (r == OK) - vp->v_mode = new_mode; - } - - if (call_nr == CHMOD) { - unlock_vnode(vp); - unlock_vmnt(vmp); - } else { /* FCHMOD */ - unlock_filp(flp); - } - - put_vnode(vp); - return(r); -} - - -/*===========================================================================* - * do_chown * - *===========================================================================*/ -PUBLIC int do_chown() -{ -/* Perform the chown(path, owner, group) and fchmod(fd, owner, group) system - * calls. */ - struct filp *flp; - struct vnode *vp; - struct vmnt *vmp; - int r; - uid_t uid; - gid_t gid; - mode_t new_mode; - char fullpath[PATH_MAX]; - struct lookup resolve; - - flp = NULL; - - lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); - resolve.l_vmnt_lock = VMNT_WRITE; - resolve.l_vnode_lock = VNODE_WRITE; - - if (call_nr == CHOWN) { - /* Temporarily open the file. */ - if (fetch_name(m_in.name1, m_in.name1_length, M1, fullpath) != OK) - return(err_code); - if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); - } else { /* call_nr == FCHOWN */ - /* File is already opened; get a pointer to the vnode from filp. */ - if ((flp = get_filp(m_in.fd, VNODE_WRITE)) == NULL) - return(err_code); - vp = flp->filp_vno; - dup_vnode(vp); - } - - r = read_only(vp); - if (r == OK) { - /* FS is R/W. Whether call is allowed depends on ownership, etc. */ - /* The super user can do anything, so check permissions only if we're - a regular user. */ - if (fp->fp_effuid != SU_UID) { - /* Regular users can only change groups of their own files. */ - if (vp->v_uid != fp->fp_effuid) r = EPERM; - if (vp->v_uid != m_in.owner) r = EPERM; /* no giving away */ - if (fp->fp_effgid != m_in.group) r = EPERM; - } - } - - if (r == OK) { - /* Do not change uid/gid if new uid/gid is -1. */ - uid = (m_in.owner == (uid_t)-1 ? vp->v_uid : m_in.owner); - gid = (m_in.group == (gid_t)-1 ? vp->v_gid : m_in.group); - - if (uid > UID_MAX || gid > GID_MAX) - r = EINVAL; - else if ((r = req_chown(vp->v_fs_e, vp->v_inode_nr, uid, gid, - &new_mode)) == OK) { - vp->v_uid = uid; - vp->v_gid = gid; - vp->v_mode = new_mode; - } - } - - if (call_nr == CHOWN) { - unlock_vnode(vp); - unlock_vmnt(vmp); - } else { /* FCHOWN */ - unlock_filp(flp); - } - - put_vnode(vp); - return(r); -} - -/*===========================================================================* - * do_umask * - *===========================================================================*/ -PUBLIC int do_umask() -{ -/* Perform the umask(co_mode) system call. */ - register mode_t r; - - r = ~fp->fp_umask; /* set 'r' to complement of old mask */ - fp->fp_umask = ~(m_in.co_mode & RWX_MODES); - return(r); /* return complement of old mask */ -} - - -/*===========================================================================* - * do_access * - *===========================================================================*/ -PUBLIC int do_access() -{ -/* Perform the access(name, mode) system call. */ - int r; - struct vnode *vp; - struct vmnt *vmp; - char fullpath[PATH_MAX]; - struct lookup resolve; - - lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); - resolve.l_vmnt_lock = VMNT_READ; - resolve.l_vnode_lock = VNODE_READ; - - /* First check to see if the mode is correct. */ - if ( (m_in.mode & ~(R_OK | W_OK | X_OK)) != 0 && m_in.mode != F_OK) - return(EINVAL); - - /* Temporarily open the file. */ - if (fetch_name(m_in.name, m_in.name_length, M3, fullpath) != OK) - return(err_code); - if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); - - r = forbidden(fp, vp, m_in.mode); - - unlock_vnode(vp); - unlock_vmnt(vmp); - - put_vnode(vp); - return(r); -} - - -/*===========================================================================* - * forbidden * - *===========================================================================*/ -PUBLIC int forbidden(struct fproc *rfp, struct vnode *vp, mode_t access_desired) -{ -/* Given a pointer to an vnode, 'vp', and the access desired, determine - * if the access is allowed, and if not why not. The routine looks up the - * caller's uid in the 'fproc' table. If access is allowed, OK is returned - * if it is forbidden, EACCES is returned. - */ - - register mode_t bits, perm_bits; - uid_t uid; - gid_t gid; - int r, shift; - - if (vp->v_uid == (uid_t) -1 || vp->v_gid == (gid_t) -1) return(EACCES); - - /* Isolate the relevant rwx bits from the mode. */ - bits = vp->v_mode; - uid = (call_nr == ACCESS ? rfp->fp_realuid : rfp->fp_effuid); - gid = (call_nr == ACCESS ? rfp->fp_realgid : rfp->fp_effgid); - - if (uid == SU_UID) { - /* Grant read and write permission. Grant search permission for - * directories. Grant execute permission (for non-directories) if - * and only if one of the 'X' bits is set. - */ - if ( (bits & I_TYPE) == I_DIRECTORY || - bits & ((X_BIT << 6) | (X_BIT << 3) | X_BIT)) - perm_bits = R_BIT | W_BIT | X_BIT; - else - perm_bits = R_BIT | W_BIT; - } else { - if (uid == vp->v_uid) shift = 6; /* owner */ - else if (gid == vp->v_gid) shift = 3; /* group */ - else if (in_group(fp, vp->v_gid) == OK) shift = 3; /* suppl. groups */ - else shift = 0; /* other */ - perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT); - } - - /* If access desired is not a subset of what is allowed, it is refused. */ - r = OK; - if ((perm_bits | access_desired) != perm_bits) r = EACCES; - - /* Check to see if someone is trying to write on a file system that is - * mounted read-only. - */ - if (r == OK) - if (access_desired & W_BIT) - r = read_only(vp); - - return(r); -} - -/*===========================================================================* - * read_only * - *===========================================================================*/ -PUBLIC int read_only(vp) -struct vnode *vp; /* ptr to inode whose file sys is to be cked */ -{ -/* Check to see if the file system on which the inode 'ip' resides is mounted - * read only. If so, return EROFS, else return OK. - */ - return((vp->v_vmnt->m_flags & VMNT_READONLY) ? EROFS : OK); -} diff --git a/servers/avfs/proto.h b/servers/avfs/proto.h deleted file mode 100644 index 432ef3a52..000000000 --- a/servers/avfs/proto.h +++ /dev/null @@ -1,390 +0,0 @@ -#ifndef __VFS_PROTO_H__ -#define __VFS_PROTO_H__ - -/* Function prototypes. */ - -#include "timers.h" -#include "request.h" -#include "tll.h" -#include "threads.h" -#include - -/* Structs used in prototypes must be declared as such first. */ -struct filp; -struct fproc; -struct vmnt; -struct vnode; -struct lookup; -struct worker_thread; -struct job; - -typedef struct filp * filp_id_t; - -/* comm.c */ -_PROTOTYPE(void fs_cancel, (struct vmnt *vmp) ); -_PROTOTYPE(int fs_sendrec, (endpoint_t fs_e, message *reqm) ); -_PROTOTYPE(void fs_sendmore, (struct vmnt *vmp) ); -_PROTOTYPE(void send_work, (void) ); - -/* device.c */ -_PROTOTYPE( int dev_open, (dev_t dev, endpoint_t proc_e, int flags) ); -_PROTOTYPE( int dev_reopen, (dev_t dev, int filp_no, int flags) ); -_PROTOTYPE( int dev_close, (dev_t dev, int filp_no) ); -_PROTOTYPE( int bdev_open, (dev_t dev, int access) ); -_PROTOTYPE( int bdev_close, (dev_t dev) ); -_PROTOTYPE( int dev_io, (int op, dev_t dev, endpoint_t proc_e, void *buf, - u64_t pos, size_t bytes, int flags, int suspend_reopen) ); -_PROTOTYPE( int gen_opcl, (int op, dev_t dev, endpoint_t task_nr, int flags)); -_PROTOTYPE( int gen_io, (endpoint_t driver_e, message *mess_ptr) ); -_PROTOTYPE( int asyn_io, (int task_nr, message *mess_ptr) ); -_PROTOTYPE( int no_dev, (int op, dev_t dev, int proc, int flags) ); -_PROTOTYPE( int no_dev_io, (int, message *) ); -_PROTOTYPE( int tty_opcl, (int op, dev_t dev, endpoint_t proc, int flags)); -_PROTOTYPE( int ctty_opcl, (int op, dev_t dev, endpoint_t proc, int flags)); -_PROTOTYPE( int clone_opcl, (int op, dev_t dev, int proc, int flags) ); -_PROTOTYPE( int ctty_io, (int task_nr, message *mess_ptr) ); -_PROTOTYPE( int do_ioctl, (void) ); -_PROTOTYPE( void pm_setsid, (int proc_e) ); -_PROTOTYPE( void dev_status, (message *) ); -_PROTOTYPE( void bdev_up, (int major) ); -_PROTOTYPE( void cdev_up, (int major) ); -_PROTOTYPE( endpoint_t find_suspended_ep, (endpoint_t driver, - cp_grant_id_t g) ); -_PROTOTYPE( void reopen_reply, (void) ); -_PROTOTYPE( void open_reply, (void) ); - -/* dmap.c */ -_PROTOTYPE( int do_mapdriver, (void) ); -_PROTOTYPE( void init_dmap, (void) ); -_PROTOTYPE( int dmap_driver_match, (endpoint_t proc, int major) ); -_PROTOTYPE( void dmap_endpt_up, (int proc_nr, int is_blk) ); -_PROTOTYPE( void dmap_unmap_by_endpt, (int proc_nr) ); -_PROTOTYPE( struct dmap *get_dmap, (endpoint_t proc_e) ); -_PROTOTYPE( int do_mapdriver, (void) ); -_PROTOTYPE( int map_service, (struct rprocpub *rpub) ); -_PROTOTYPE( void dmap_unmap_by_endpt, (int proc_nr) ); -_PROTOTYPE( struct dmap *get_dmap, (endpoint_t proc_e) ); -_PROTOTYPE( int map_driver, (const char *label, int major, endpoint_t proc_nr, - int dev_style, int flags) ); -_PROTOTYPE( int map_service, (struct rprocpub *rpub) ); - -/* elf_core_dump.c */ -_PROTOTYPE( void write_elf_core_file, (struct filp *f, int csig, - char *exe_name) ); - -/* exec.c */ -_PROTOTYPE( int pm_exec, (int proc_e, char *path, vir_bytes path_len, - char *frame, vir_bytes frame_len, vir_bytes *pc)); -#define check_bsf_lock() do { \ - assert(mutex_trylock(&bsf_lock) == 0); \ - unlock_bsf(); \ - } while(0) - -/* filedes.c */ -_PROTOTYPE( void check_filp_locks, (void) ); -_PROTOTYPE( void check_filp_locks_by_me, (void) ); -_PROTOTYPE( void init_filps, (void) ); -_PROTOTYPE( struct filp *find_filp, (struct vnode *vp, mode_t bits) ); -_PROTOTYPE( int get_fd, (int start, mode_t bits, int *k, - struct filp **fpt) ); -_PROTOTYPE( struct filp *get_filp, (int fild, tll_access_t locktype) ); -_PROTOTYPE( struct filp *get_filp2, (struct fproc *rfp, int fild, - tll_access_t locktype) ); -_PROTOTYPE( void lock_filp, (struct filp *filp, tll_access_t locktype) ); -_PROTOTYPE( void unlock_filp, (struct filp *filp) ); -_PROTOTYPE( void unlock_filps, (struct filp *filp1, struct filp *filp2) ); -_PROTOTYPE( int invalidate_filp, (struct filp *) ); -_PROTOTYPE( void invalidate_filp_by_endpt, (endpoint_t proc_e) ); -_PROTOTYPE( int do_verify_fd, (void) ); -_PROTOTYPE( int set_filp, (filp_id_t sfilp) ); -_PROTOTYPE( int do_set_filp, (void) ); -_PROTOTYPE( int copy_filp, (endpoint_t to_ep, filp_id_t cfilp) ); -_PROTOTYPE( int do_copy_filp, (void) ); -_PROTOTYPE( int put_filp, (filp_id_t pfilp) ); -_PROTOTYPE( int do_put_filp, (void) ); -_PROTOTYPE( int cancel_fd, (endpoint_t ep, int fd) ); -_PROTOTYPE( int do_cancel_fd, (void) ); -_PROTOTYPE( void close_filp, (struct filp *fp) ); - -/* fscall.c */ -_PROTOTYPE( void nested_fs_call, (message *m) ); - -/* link.c */ -_PROTOTYPE( int do_link, (void) ); -_PROTOTYPE( int do_unlink, (void) ); -_PROTOTYPE( int do_rename, (void) ); -_PROTOTYPE( int do_truncate, (void) ); -_PROTOTYPE( int do_ftruncate, (void) ); -_PROTOTYPE( int truncate_vnode, (struct vnode *vp, off_t newsize) ); -_PROTOTYPE( int rdlink_direct, (char *orig_path, char *link_path, - struct fproc *rfp) ); - -/* lock.c */ -_PROTOTYPE( int lock_op, (struct filp *f, int req) ); -_PROTOTYPE( void lock_revive, (void) ); - -/* main.c */ -_PROTOTYPE( int main, (void) ); -_PROTOTYPE( void reply, (int whom, int result) ); -_PROTOTYPE( void lock_proc, (struct fproc *rfp, int force_lock) ); -_PROTOTYPE( void unlock_proc, (struct fproc *rfp) ); -_PROTOTYPE( void *do_dummy, (void *arg) ); - -/* misc.c */ -_PROTOTYPE( int do_dup, (void) ); -_PROTOTYPE( void pm_exit, (int proc) ); -_PROTOTYPE( int do_fcntl, (void) ); -_PROTOTYPE( void pm_fork, (int pproc, int cproc, int cpid) ); -_PROTOTYPE( void pm_setgid, (int proc_e, int egid, int rgid) ); -_PROTOTYPE( void pm_setuid, (int proc_e, int euid, int ruid) ); -_PROTOTYPE( void pm_setgroups, (int proc_e, int ngroups, gid_t *addr) ); -_PROTOTYPE( int do_sync, (void) ); -_PROTOTYPE( int do_fsync, (void) ); -_PROTOTYPE( void pm_reboot, (void) ); -_PROTOTYPE( int do_svrctl, (void) ); -_PROTOTYPE( int do_getsysinfo, (void) ); -_PROTOTYPE( int pm_dumpcore, (endpoint_t proc_e, int sig, - vir_bytes exe_name) ); -_PROTOTYPE( void ds_event, (void) ); - -/* mount.c */ -_PROTOTYPE( int do_fsready, (void) ); -_PROTOTYPE( int do_mount, (void) ); -_PROTOTYPE( int do_umount, (void) ); -_PROTOTYPE( int is_nonedev, (dev_t dev) ); -_PROTOTYPE( void mount_pfs, (void) ); -_PROTOTYPE( int mount_fs, (dev_t dev, char fullpath[PATH_MAX+1], - endpoint_t fs_e, int rdonly, - char mount_label[LABEL_MAX]) ); -_PROTOTYPE( int unmount, (dev_t dev, char *label) ); -_PROTOTYPE( void unmount_all, (void) ); - -/* open.c */ -_PROTOTYPE( int do_close, (void) ); -_PROTOTYPE( int close_fd, (struct fproc *rfp, int fd_nr) ); -_PROTOTYPE( void close_reply, (void) ); -_PROTOTYPE( int common_open, (char path[PATH_MAX], int oflags, - mode_t omode) ); -_PROTOTYPE( int do_creat, (void) ); -_PROTOTYPE( int do_lseek, (void) ); -_PROTOTYPE( int do_llseek, (void) ); -_PROTOTYPE( int do_mknod, (void) ); -_PROTOTYPE( int do_mkdir, (void) ); -_PROTOTYPE( int do_open, (void) ); -_PROTOTYPE( int do_slink, (void) ); -_PROTOTYPE( int do_vm_open, (void) ); -_PROTOTYPE( int do_vm_close, (void) ); - -/* path.c */ -_PROTOTYPE( struct vnode *advance, (struct vnode *dirp, struct lookup *resolve, - struct fproc *rfp) ); -_PROTOTYPE( struct vnode *eat_path, (struct lookup *resolve, - struct fproc *rfp) ); -_PROTOTYPE( struct vnode *last_dir, (struct lookup *resolve, - struct fproc *rfp) ); -_PROTOTYPE( void lookup_init, (struct lookup *resolve, char *path, int flags, - struct vmnt **vmp, struct vnode **vp) ); -_PROTOTYPE( int get_name, (struct vnode *dirp, struct vnode *entry, - char *_name) ); -_PROTOTYPE( int canonical_path, (char *orig_path, struct fproc *rfp) ); -_PROTOTYPE( int do_check_perms, (void) ); - -/* pipe.c */ -_PROTOTYPE( int do_pipe, (void) ); -_PROTOTYPE( int map_vnode, (struct vnode *vp, endpoint_t fs_e) ); -_PROTOTYPE( void unpause, (int proc_nr_e) ); -_PROTOTYPE( int pipe_check, (struct vnode *vp, int rw_flag, - int oflags, int bytes, u64_t position, int notouch) ); -_PROTOTYPE( void release, (struct vnode *vp, int call_nr, int count) ); -_PROTOTYPE( void revive, (int proc_nr, int bytes) ); -_PROTOTYPE( void suspend, (int task) ); -_PROTOTYPE( void pipe_suspend, (struct filp *rfilp, char *buf, size_t size)); -_PROTOTYPE( void unsuspend_by_endpt, (endpoint_t) ); -_PROTOTYPE( void wait_for, (endpoint_t) ); -#if DO_SANITYCHECKS -_PROTOTYPE( int check_pipe, (void) ); -#endif - -/* protect.c */ -_PROTOTYPE( int do_access, (void) ); -_PROTOTYPE( int do_chmod, (void) ); -_PROTOTYPE( int do_chown, (void) ); -_PROTOTYPE( int do_umask, (void) ); -_PROTOTYPE( int forbidden, (struct fproc *rfp, struct vnode *vp, - mode_t access_desired) ); -_PROTOTYPE( int read_only, (struct vnode *vp) ); - -/* read.c */ -_PROTOTYPE( int do_read, (void) ); -_PROTOTYPE( int do_getdents, (void) ); -_PROTOTYPE( void lock_bsf, (void) ); -_PROTOTYPE( void unlock_bsf, (void) ); -_PROTOTYPE( int do_read_write, (int rw_flag) ); -_PROTOTYPE( int read_write, (int rw_flag, struct filp *f, char *buffer, - size_t nbytes, endpoint_t for_e) ); -_PROTOTYPE( int rw_pipe, (int rw_flag, endpoint_t usr, struct filp *f, - char *buf, size_t req_size) ); - -/* request.c */ -_PROTOTYPE( int req_breadwrite, (endpoint_t fs_e, endpoint_t user_e, - dev_t dev, u64_t pos, unsigned int num_of_bytes, - char *user_addr, int rw_flag, - u64_t *new_posp, unsigned int *cum_iop) ); -_PROTOTYPE( int req_chmod, (int fs_e, ino_t inode_nr, mode_t rmode, - mode_t *new_modep) ); -_PROTOTYPE( int req_chown, (endpoint_t fs_e, ino_t inode_nr, - uid_t newuid, gid_t newgid, mode_t *new_modep) ); -_PROTOTYPE( int req_create, (int fs_e, ino_t inode_nr, int omode, - uid_t uid, gid_t gid, char *path, node_details_t *res) ); -_PROTOTYPE( int req_flush, (endpoint_t fs_e, dev_t dev) ); -_PROTOTYPE( int req_fstatfs, (int fs_e, int who_e, char *buf) ); -_PROTOTYPE( int req_statvfs, (int fs_e, int who_e, char *buf) ); -_PROTOTYPE( int req_ftrunc, (endpoint_t fs_e, ino_t inode_nr, - off_t start, off_t end) ); -_PROTOTYPE( int req_getdents, (endpoint_t fs_e, ino_t inode_nr, - u64_t pos, char *buf, size_t size, - u64_t *new_pos, int direct) ); -_PROTOTYPE( int req_inhibread, (endpoint_t fs_e, ino_t inode_nr) ); -_PROTOTYPE( int req_link, (endpoint_t fs_e, ino_t link_parent, - char *lastc, ino_t linked_file) ); -_PROTOTYPE( int req_lookup, (endpoint_t fs_e, ino_t dir_ino, ino_t root_ino, - uid_t uid, gid_t gid, struct lookup *resolve, - lookup_res_t *res, struct fproc *rfp) ); -_PROTOTYPE( int req_mkdir, (endpoint_t fs_e, ino_t inode_nr, - char *lastc, uid_t uid, gid_t gid, mode_t dmode) ); -_PROTOTYPE( int req_mknod, (endpoint_t fs_e, ino_t inode_nr, - char *lastc, uid_t uid, gid_t gid, - mode_t dmode, dev_t dev) ); -_PROTOTYPE( int req_mountpoint, (endpoint_t fs_e, ino_t inode_nr) ); -_PROTOTYPE( int req_newnode, (endpoint_t fs_e, uid_t uid, - gid_t gid, mode_t dmode, - dev_t dev, struct node_details *res) ); -_PROTOTYPE( int req_putnode, (int fs_e, ino_t inode_nr, int count) ); -_PROTOTYPE( int req_rdlink, (endpoint_t fs_e, ino_t inode_nr, - endpoint_t who_e, char *buf, size_t len, - int direct) ); -_PROTOTYPE( int req_readsuper, (endpoint_t fs_e, char *driver_name, - dev_t dev, int readonly, int isroot, - struct node_details *res_nodep, - int *con_reqs) ); -_PROTOTYPE( int req_readwrite, (endpoint_t fs_e, ino_t inode_nr, - u64_t pos, int rw_flag, - endpoint_t user_e, char *user_addr, - unsigned int num_of_bytes, u64_t *new_posp, - unsigned int *cum_iop) ); -_PROTOTYPE( int req_rename, (endpoint_t fs_e, ino_t old_dir, - char *old_name, ino_t new_dir, char *new_name) ); -_PROTOTYPE( int req_rmdir, (endpoint_t fs_e, ino_t inode_nr, - char *lastc) ); -_PROTOTYPE(int req_slink, (endpoint_t fs_e, ino_t inode_nr, char *lastc, - endpoint_t who_e, char *path_addr, - unsigned short path_length, uid_t uid, gid_t gid) ); -_PROTOTYPE( int req_stat, (int fs_e, ino_t inode_nr, int who_e, - char *buf, int pos, int stat_version) ); -_PROTOTYPE( int req_sync, (endpoint_t fs_e) ); -_PROTOTYPE( int req_unlink, (endpoint_t fs_e, ino_t inode_nr, - char *lastc) ); -_PROTOTYPE( int req_unmount, (endpoint_t fs_e) ); -_PROTOTYPE( int req_utime, (endpoint_t fs_e, ino_t inode_nr, - time_t actime, time_t modtime) ); -_PROTOTYPE( int req_newdriver, (endpoint_t fs_e, dev_t dev, - char *label) ); - -/* stadir.c */ -_PROTOTYPE( int do_chdir, (void) ); -_PROTOTYPE( int do_fchdir, (void) ); -_PROTOTYPE( int do_chroot, (void) ); -_PROTOTYPE( int do_fstat, (void) ); -_PROTOTYPE( int do_stat, (void) ); -_PROTOTYPE( int do_fstatfs, (void) ); -_PROTOTYPE( int do_statvfs, (void) ); -_PROTOTYPE( int do_fstatvfs, (void) ); -_PROTOTYPE( int do_rdlink, (void) ); -_PROTOTYPE( int do_lstat, (void) ); - -/* time.c */ -_PROTOTYPE( int do_utime, (void) ); - -/* tll.c */ -_PROTOTYPE( void tll_downgrade, (tll_t *tllp) ); -_PROTOTYPE( int tll_haspendinglock, (tll_t *tllp) ); -_PROTOTYPE( void tll_init, (tll_t *tllp) ); -_PROTOTYPE( int tll_islocked, (tll_t *tllp) ); -_PROTOTYPE( int tll_lock, (tll_t *tllp, tll_access_t locktype) ); -_PROTOTYPE( int tll_locked_by_me, (tll_t *tllp) ); -_PROTOTYPE( void tll_lockstat, (tll_t *tllp) ); -_PROTOTYPE( int tll_unlock, (tll_t *tllp) ); -_PROTOTYPE( void tll_upgrade, (tll_t *tllp) ); - -/* utility.c */ -_PROTOTYPE( time_t clock_time, (void) ); -_PROTOTYPE( unsigned conv2, (int norm, int w) ); -_PROTOTYPE( long conv4, (int norm, long x) ); -_PROTOTYPE( int fetch_name, (char *path, int len, int flag, char *dest) ); -_PROTOTYPE( int no_sys, (void) ); -_PROTOTYPE( int isokendpt_f, (char *f, int l, endpoint_t e, int *p, int ft)); -_PROTOTYPE( int in_group, (struct fproc *rfp, gid_t grp) ); - -#define okendpt(e, p) isokendpt_f(__FILE__, __LINE__, (e), (p), 1) -#define isokendpt(e, p) isokendpt_f(__FILE__, __LINE__, (e), (p), 0) - -/* vmnt.c */ -_PROTOTYPE( void check_vmnt_locks, (void) ); -_PROTOTYPE( void check_vmnt_locks_by_me, (struct fproc *rfp) ); -_PROTOTYPE( struct vmnt *get_free_vmnt, (void) ); -_PROTOTYPE( struct vmnt *find_vmnt, (endpoint_t fs_e) ); -_PROTOTYPE( struct vmnt *get_locked_vmnt, (struct fproc *rfp) ); -_PROTOTYPE( void init_vmnts, (void) ); -_PROTOTYPE( int lock_vmnt, (struct vmnt *vp, tll_access_t locktype) ); -_PROTOTYPE( void unlock_vmnt, (struct vmnt *vp) ); -_PROTOTYPE( void vmnt_unmap_by_endpt, (endpoint_t proc_e) ); - -/* vnode.c */ -_PROTOTYPE( void check_vnode_locks, (void) ); -_PROTOTYPE( void check_vnode_locks_by_me, (struct fproc *rfp) ); -_PROTOTYPE( struct vnode *get_free_vnode, (void) ); -_PROTOTYPE( struct vnode *find_vnode, (int fs_e, int numb) ); -_PROTOTYPE( void init_vnodes, (void) ); -_PROTOTYPE( int is_vnode_locked, (struct vnode *vp) ); -_PROTOTYPE( int lock_vnode, (struct vnode *vp, tll_access_t locktype) ); -_PROTOTYPE( void unlock_vnode, (struct vnode *vp) ); -_PROTOTYPE( void dup_vnode, (struct vnode *vp) ); -_PROTOTYPE( void put_vnode, (struct vnode *vp) ); -_PROTOTYPE( void vnode_clean_refs, (struct vnode *vp) ); -#if DO_SANITYCHECKS -_PROTOTYPE( int check_vrefs, (void) ); -#endif - -/* write.c */ -_PROTOTYPE( int do_write, (void) ); - -/* gcov.c */ -_PROTOTYPE( int do_gcov_flush, (void) ); -#if ! USE_COVERAGE -#define do_gcov_flush no_sys -#endif - -/* select.c */ -_PROTOTYPE( int do_select, (void) ); -_PROTOTYPE( void init_select, (void) ); -_PROTOTYPE( void select_callback, (struct filp *, int ops) ); -_PROTOTYPE( void select_forget, (endpoint_t proc_e) ); -_PROTOTYPE( void select_reply1, (endpoint_t driver_e, int minor, int status)); -_PROTOTYPE( void select_reply2, (endpoint_t driver_e, int minor, int status)); -_PROTOTYPE( void select_timeout_check, (timer_t *) ); -_PROTOTYPE( void select_unsuspend_by_endpt, (endpoint_t proc) ); - -/* worker.c */ -_PROTOTYPE( int worker_available, (void) ); -_PROTOTYPE( struct worker_thread *worker_get, (thread_t worker_tid) ); -_PROTOTYPE( struct job *worker_getjob, (thread_t worker_tid) ); -_PROTOTYPE( void worker_init, (struct worker_thread *worker) ); -_PROTOTYPE( struct worker_thread *worker_self, (void) ); -_PROTOTYPE( void worker_signal, (struct worker_thread *worker) ); -_PROTOTYPE( void worker_start, (void *(*func)(void *arg)) ); -_PROTOTYPE( void worker_stop, (struct worker_thread *worker) ); -_PROTOTYPE( void worker_stop_by_endpt, (endpoint_t proc_e) ); -_PROTOTYPE( void worker_wait, (void) ); -_PROTOTYPE( void sys_worker_start, (void *(*func)(void *arg)) ); -_PROTOTYPE( void dl_worker_start, (void *(*func)(void *arg)) ); -#endif diff --git a/servers/avfs/read.c b/servers/avfs/read.c deleted file mode 100644 index 13df38ae0..000000000 --- a/servers/avfs/read.c +++ /dev/null @@ -1,347 +0,0 @@ -/* This file contains the heart of the mechanism used to read (and write) - * files. Read and write requests are split up into chunks that do not cross - * block boundaries. Each chunk is then processed in turn. Reads on special - * files are also detected and handled. - * - * The entry points into this file are - * do_read: perform the READ system call by calling read_write - * do_getdents: read entries from a directory (GETDENTS) - * read_write: actually do the work of READ and WRITE - * - */ - -#include "fs.h" -#include -#include -#include -#include -#include "file.h" -#include "fproc.h" -#include "scratchpad.h" -#include "param.h" -#include -#include -#include -#include "vnode.h" -#include "vmnt.h" - - -/*===========================================================================* - * do_read * - *===========================================================================*/ -PUBLIC int do_read() -{ - return(do_read_write(READING)); -} - - -/*===========================================================================* - * lock_bsf * - *===========================================================================*/ -PUBLIC void lock_bsf(void) -{ - message org_m_in; - struct fproc *org_fp; - struct worker_thread *org_self; - - if (mutex_trylock(&bsf_lock) == 0) - return; - - org_m_in = m_in; - org_fp = fp; - org_self = self; - - if (mutex_lock(&bsf_lock) != 0) - panic("unable to lock block special file lock"); - - m_in = org_m_in; - fp = org_fp; - self = org_self; -} - -/*===========================================================================* - * unlock_bsf * - *===========================================================================*/ -PUBLIC void unlock_bsf(void) -{ - if (mutex_unlock(&bsf_lock) != 0) - panic("failed to unlock block special file lock"); -} - -/*===========================================================================* - * do_read_write * - *===========================================================================*/ -PUBLIC int do_read_write(rw_flag) -int rw_flag; /* READING or WRITING */ -{ -/* Perform read(fd, buffer, nbytes) or write(fd, buffer, nbytes) call. */ - struct filp *f; - tll_access_t locktype; - int r; - - scratch(fp).file.fd_nr = m_in.fd; - scratch(fp).io.io_buffer = m_in.buffer; - scratch(fp).io.io_nbytes = (size_t) m_in.nbytes; - - locktype = (rw_flag == READING) ? VNODE_READ : VNODE_WRITE; - if ((f = get_filp(scratch(fp).file.fd_nr, locktype)) == NULL) - return(err_code); - if (((f->filp_mode) & (rw_flag == READING ? R_BIT : W_BIT)) == 0) { - unlock_filp(f); - return(f->filp_mode == FILP_CLOSED ? EIO : EBADF); - } - if (scratch(fp).io.io_nbytes == 0) { - unlock_filp(f); - return(0); /* so char special files need not check for 0*/ - } - - r = read_write(rw_flag, f, scratch(fp).io.io_buffer, scratch(fp).io.io_nbytes, - who_e); - - unlock_filp(f); - return(r); -} - -/*===========================================================================* - * read_write * - *===========================================================================*/ -PUBLIC int read_write(int rw_flag, struct filp *f, char *buf, size_t size, - endpoint_t for_e) -{ - register struct vnode *vp; - u64_t position, res_pos, new_pos; - unsigned int cum_io, cum_io_incr, res_cum_io; - int op, oflags, r, block_spec, char_spec, regular; - mode_t mode_word; - - position = f->filp_pos; - oflags = f->filp_flags; - vp = f->filp_vno; - r = OK; - cum_io = 0; - - if (size > SSIZE_MAX) return(EINVAL); - - if (vp->v_pipe == I_PIPE) { - if (fp->fp_cum_io_partial != 0) { - panic("VFS: read_write: fp_cum_io_partial not clear"); - } - r = rw_pipe(rw_flag, for_e, f, buf, size); - return(r); - } - - op = (rw_flag == READING ? VFS_DEV_READ : VFS_DEV_WRITE); - mode_word = vp->v_mode & I_TYPE; - regular = mode_word == I_REGULAR; - - if ((char_spec = (mode_word == I_CHAR_SPECIAL ? 1 : 0))) { - if (vp->v_sdev == NO_DEV) - panic("VFS: read_write tries to access char dev NO_DEV"); - } - - if ((block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 : 0))) { - if (vp->v_sdev == NO_DEV) - panic("VFS: read_write tries to access block dev NO_DEV"); - } - - if (char_spec) { /* Character special files. */ - dev_t dev; - int suspend_reopen; - - suspend_reopen = (f->filp_state != FS_NORMAL); - dev = (dev_t) vp->v_sdev; - - r = dev_io(op, dev, for_e, buf, position, size, oflags, - suspend_reopen); - if (r >= 0) { - cum_io = r; - position = add64ul(position, r); - r = OK; - } - } else if (block_spec) { /* Block special files. */ - lock_bsf(); - - r = req_breadwrite(vp->v_bfs_e, for_e, vp->v_sdev, position, size, - buf, rw_flag, &res_pos, &res_cum_io); - if (r == OK) { - position = res_pos; - cum_io += res_cum_io; - } - - unlock_bsf(); - } else { /* Regular files */ - if (rw_flag == WRITING && block_spec == 0) { - /* Check for O_APPEND flag. */ - if (oflags & O_APPEND) position = cvul64(vp->v_size); - } - - /* Issue request */ - r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, position, rw_flag, for_e, - buf, size, &new_pos, &cum_io_incr); - - if (r >= 0) { - if (ex64hi(new_pos)) - panic("read_write: bad new pos"); - - position = new_pos; - cum_io += cum_io_incr; - } - } - - /* On write, update file size and access time. */ - if (rw_flag == WRITING) { - if (regular || mode_word == I_DIRECTORY) { - if (cmp64ul(position, vp->v_size) > 0) { - if (ex64hi(position) != 0) { - panic("read_write: file size too big "); - } - vp->v_size = ex64lo(position); - } - } - } - - f->filp_pos = position; - - if (r == OK) return(cum_io); - return(r); -} - -/*===========================================================================* - * do_getdents * - *===========================================================================*/ -PUBLIC int do_getdents() -{ -/* Perform the getdents(fd, buf, size) system call. */ - int r = OK; - u64_t new_pos; - register struct filp *rfilp; - - /* Is the file descriptor valid? */ - if ( (rfilp = get_filp(m_in.fd, VNODE_READ)) == NULL) return(err_code); - - if (!(rfilp->filp_mode & R_BIT)) - r = EBADF; - else if ((rfilp->filp_vno->v_mode & I_TYPE) != I_DIRECTORY) - r = EBADF; - - if (r == OK) { - if (ex64hi(rfilp->filp_pos) != 0) - panic("do_getdents: can't handle large offsets"); - - r = req_getdents(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr, - rfilp->filp_pos, m_in.buffer, m_in.nbytes,&new_pos,0); - - if (r > 0) rfilp->filp_pos = new_pos; - } - - unlock_filp(rfilp); - return(r); -} - - -/*===========================================================================* - * rw_pipe * - *===========================================================================*/ -PUBLIC int rw_pipe(rw_flag, usr_e, f, buf, req_size) -int rw_flag; /* READING or WRITING */ -endpoint_t usr_e; -struct filp *f; -char *buf; -size_t req_size; -{ - int r, oflags, partial_pipe = 0; - size_t size, cum_io, cum_io_incr; - struct vnode *vp; - u64_t position, new_pos; - - /* Must make sure we're operating on locked filp and vnode */ - assert(tll_islocked(&f->filp_vno->v_lock)); - assert(mutex_trylock(&f->filp_lock) == -EDEADLK); - - oflags = f->filp_flags; - vp = f->filp_vno; - position = cvu64((rw_flag == READING) ? vp->v_pipe_rd_pos : - vp->v_pipe_wr_pos); - /* fp->fp_cum_io_partial is only nonzero when doing partial writes */ - cum_io = fp->fp_cum_io_partial; - - r = pipe_check(vp, rw_flag, oflags, req_size, position, 0); - if (r <= 0) { - if (r == SUSPEND) pipe_suspend(f, buf, req_size); - return(r); - } - - size = r; - if (size < req_size) partial_pipe = 1; - - /* Truncate read request at size. */ - if((rw_flag == READING) && - cmp64ul(add64ul(position, size), vp->v_size) > 0) { - /* Position always should fit in an off_t (LONG_MAX). */ - off_t pos32; - - assert(cmp64ul(position, LONG_MAX) <= 0); - pos32 = cv64ul(position); - assert(pos32 >= 0); - assert(pos32 <= LONG_MAX); - size = vp->v_size - pos32; - } - - if (vp->v_mapfs_e == 0) - panic("unmapped pipe"); - - r = req_readwrite(vp->v_mapfs_e, vp->v_mapinode_nr, position, rw_flag, usr_e, - buf, size, &new_pos, &cum_io_incr); - - if (r >= 0) { - if (ex64hi(new_pos)) - panic("rw_pipe: bad new pos"); - - position = new_pos; - cum_io += cum_io_incr; - buf += cum_io_incr; - req_size -= cum_io_incr; - } - - /* On write, update file size and access time. */ - if (rw_flag == WRITING) { - if (cmp64ul(position, vp->v_size) > 0) { - if (ex64hi(position) != 0) { - panic("read_write: file size too big for v_size"); - } - vp->v_size = ex64lo(position); - } - } else { - if (cmp64ul(position, vp->v_size) >= 0) { - /* Reset pipe pointers */ - vp->v_size = 0; - vp->v_pipe_rd_pos= 0; - vp->v_pipe_wr_pos= 0; - position = cvu64(0); - } - } - - if (rw_flag == READING) - vp->v_pipe_rd_pos= cv64ul(position); - else - vp->v_pipe_wr_pos= cv64ul(position); - - if (r == OK) { - if (partial_pipe) { - /* partial write on pipe with */ - /* O_NONBLOCK, return write count */ - if (!(oflags & O_NONBLOCK)) { - /* partial write on pipe with req_size > PIPE_SIZE, - * non-atomic - */ - fp->fp_cum_io_partial = cum_io; - pipe_suspend(f, buf, req_size); - return(SUSPEND); - } - } - fp->fp_cum_io_partial = 0; - return(cum_io); - } - - return(r); -} diff --git a/servers/avfs/request.c b/servers/avfs/request.c deleted file mode 100644 index be230da77..000000000 --- a/servers/avfs/request.c +++ /dev/null @@ -1,1093 +0,0 @@ -/* This file contains the wrapper functions for issuing a request - * and receiving response from FS processes. - * Each function builds a request message according to the request - * parameter, calls the most low-level fs_sendrec, and copies - * back the response. - */ - -#include "fs.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "fproc.h" -#include "vmnt.h" -#include "vnode.h" -#include "path.h" -#include "param.h" - - -/*===========================================================================* - * req_breadwrite * - *===========================================================================*/ -PUBLIC int req_breadwrite( - endpoint_t fs_e, - endpoint_t user_e, - dev_t dev, - u64_t pos, - unsigned int num_of_bytes, - char *user_addr, - int rw_flag, - u64_t *new_posp, - unsigned int *cum_iop -) -{ - int r; - cp_grant_id_t grant_id; - message m; - - grant_id = cpf_grant_magic(fs_e, user_e, (vir_bytes) user_addr, num_of_bytes, - (rw_flag == READING ? CPF_WRITE : CPF_READ)); - if(grant_id == -1) - panic("req_breadwrite: cpf_grant_magic failed"); - - /* Fill in request message */ - m.m_type = rw_flag == READING ? REQ_BREAD : REQ_BWRITE; - m.REQ_DEV2 = dev; - m.REQ_GRANT = grant_id; - m.REQ_SEEK_POS_LO = ex64lo(pos); - m.REQ_SEEK_POS_HI = ex64hi(pos); - m.REQ_NBYTES = num_of_bytes; - - /* Send/rec request */ - r = fs_sendrec(fs_e, &m); - cpf_revoke(grant_id); - if (r != OK) return(r); - - /* Fill in response structure */ - *new_posp = make64(m.RES_SEEK_POS_LO, m.RES_SEEK_POS_HI); - *cum_iop = m.RES_NBYTES; - - return(OK); -} - - -/*===========================================================================* - * req_chmod * - *===========================================================================*/ -PUBLIC int req_chmod( - int fs_e, - ino_t inode_nr, - mode_t rmode, - mode_t *new_modep -) -{ - message m; - int r; - - /* Fill in request message */ - m.m_type = REQ_CHMOD; - m.REQ_INODE_NR = inode_nr; - m.REQ_MODE = rmode; - - /* Send/rec request */ - r = fs_sendrec(fs_e, &m); - - /* Copy back actual mode. */ - *new_modep = m.RES_MODE; - - return(r); -} - - -/*===========================================================================* - * req_chown * - *===========================================================================*/ -PUBLIC int req_chown( - endpoint_t fs_e, - ino_t inode_nr, - uid_t newuid, - gid_t newgid, - mode_t *new_modep -) -{ - message m; - int r; - - /* Fill in request message */ - m.m_type = REQ_CHOWN; - m.REQ_INODE_NR = inode_nr; - m.REQ_UID = newuid; - m.REQ_GID = newgid; - - /* Send/rec request */ - r = fs_sendrec(fs_e, &m); - - /* Return new mode to caller. */ - *new_modep = m.RES_MODE; - - return(r); -} - - -/*===========================================================================* - * req_create * - *===========================================================================*/ -PUBLIC int req_create( - int fs_e, - ino_t inode_nr, - int omode, - uid_t uid, - gid_t gid, - char *path, - node_details_t *res -) -{ - int r; - cp_grant_id_t grant_id; - size_t len; - message m; - - if (path[0] == '/') - panic("req_create: filename starts with '/'"); - - len = strlen(path) + 1; - grant_id = cpf_grant_direct(fs_e, (vir_bytes) path, len, CPF_READ); - if (grant_id == -1) - panic("req_create: cpf_grant_direct failed"); - - /* Fill in request message */ - m.m_type = REQ_CREATE; - m.REQ_INODE_NR = inode_nr; - m.REQ_MODE = omode; - m.REQ_UID = uid; - m.REQ_GID = gid; - m.REQ_GRANT = grant_id; - m.REQ_PATH_LEN = len; - - /* Send/rec request */ - r = fs_sendrec(fs_e, &m); - cpf_revoke(grant_id); - if (r != OK) return(r); - - /* Fill in response structure */ - res->fs_e = m.m_source; - res->inode_nr = m.RES_INODE_NR; - res->fmode = m.RES_MODE; - res->fsize = m.RES_FILE_SIZE_LO; - res->uid = m.RES_UID; - res->gid = m.RES_GID; - res->dev = m.RES_DEV; - - return(OK); -} - - -/*===========================================================================* - * req_flush * - *===========================================================================*/ -PUBLIC int req_flush(endpoint_t fs_e, dev_t dev) -{ - message m; - - /* Fill in request message */ - m.m_type = REQ_FLUSH; - m.REQ_DEV = dev; - - /* Send/rec request */ - return fs_sendrec(fs_e, &m); -} - - -/*===========================================================================* - * req_fstatfs * - *===========================================================================*/ -PUBLIC int req_fstatfs(int fs_e, int proc_e, char *buf) -{ - int r; - cp_grant_id_t grant_id; - message m; - - grant_id = cpf_grant_magic(fs_e, proc_e, (vir_bytes) buf, sizeof(struct statfs), - CPF_WRITE); - if(grant_id == -1) - panic("req_fstatfs: cpf_grant_magic failed"); - - /* Fill in request message */ - m.m_type = REQ_FSTATFS; - m.REQ_GRANT = grant_id; - - /* Send/rec request */ - r = fs_sendrec(fs_e, &m); - cpf_revoke(grant_id); - - return(r); -} - - -/*===========================================================================* - * req_statvfs * - *===========================================================================*/ -PUBLIC int req_statvfs(int fs_e, int proc_e, char *buf) -{ - int r; - cp_grant_id_t grant_id; - message m; - - grant_id = cpf_grant_magic(fs_e, proc_e, (vir_bytes) buf, sizeof(struct statvfs), - CPF_WRITE); - if(grant_id == -1) - panic("req_statvfs: cpf_grant_magic failed"); - - /* Fill in request message */ - m.m_type = REQ_STATVFS; - m.REQ_GRANT = grant_id; - - /* Send/rec request */ - r = fs_sendrec(fs_e, &m); - cpf_revoke(grant_id); - - return(r); -} - - -/*===========================================================================* - * req_ftrunc * - *===========================================================================*/ -PUBLIC int req_ftrunc(endpoint_t fs_e, ino_t inode_nr, off_t start, off_t end) -{ - message m; - - /* Fill in request message */ - m.m_type = REQ_FTRUNC; - m.REQ_INODE_NR = inode_nr; - m.REQ_TRC_START_LO = start; - m.REQ_TRC_START_HI = 0; /* Not used for now, so clear it. */ - m.REQ_TRC_END_LO = end; - m.REQ_TRC_END_HI = 0; /* Not used for now, so clear it. */ - - /* Send/rec request */ - return fs_sendrec(fs_e, &m); -} - - -/*===========================================================================* - * req_getdents * - *===========================================================================*/ -PUBLIC int req_getdents( - endpoint_t fs_e, - ino_t inode_nr, - u64_t pos, - char *buf, - size_t size, - u64_t *new_pos, - int direct -) -{ - int r; - message m; - cp_grant_id_t grant_id; - - if (direct) { - grant_id = cpf_grant_direct(fs_e, (vir_bytes) buf, size, - CPF_WRITE); - } else { - grant_id = cpf_grant_magic(fs_e, who_e, (vir_bytes) buf, size, - CPF_WRITE); - } - - if (grant_id < 0) - panic("req_getdents: cpf_grant_direct/cpf_grant_magic failed: %d", - grant_id); - - m.m_type = REQ_GETDENTS; - m.REQ_INODE_NR = inode_nr; - m.REQ_GRANT = grant_id; - m.REQ_MEM_SIZE = size; - m.REQ_SEEK_POS_LO = ex64lo(pos); - m.REQ_SEEK_POS_HI = 0; /* Not used for now, so clear it. */ - - r = fs_sendrec(fs_e, &m); - cpf_revoke(grant_id); - - if (r == OK) { - *new_pos = cvul64(m.RES_SEEK_POS_LO); - r = m.RES_NBYTES; - } - - return(r); -} - -/*===========================================================================* - * req_inhibread * - *===========================================================================*/ -PUBLIC int req_inhibread(endpoint_t fs_e, ino_t inode_nr) -{ - message m; - - /* Fill in request message */ - m.m_type = REQ_INHIBREAD; - m.REQ_INODE_NR = inode_nr; - - /* Send/rec request */ - return fs_sendrec(fs_e, &m); -} - - -/*===========================================================================* - * req_link * - *===========================================================================*/ -PUBLIC int req_link( - endpoint_t fs_e, - ino_t link_parent, - char *lastc, - ino_t linked_file -) -{ - int r; - cp_grant_id_t grant_id; - const size_t len = strlen(lastc) + 1; - message m; - - grant_id = cpf_grant_direct(fs_e, (vir_bytes)lastc, len, CPF_READ); - if(grant_id == -1) - panic("req_link: cpf_grant_direct failed"); - - /* Fill in request message */ - m.m_type = REQ_LINK; - m.REQ_INODE_NR = linked_file; - m.REQ_DIR_INO = link_parent; - m.REQ_GRANT = grant_id; - m.REQ_PATH_LEN = len; - - /* Send/rec request */ - r = fs_sendrec(fs_e, &m); - cpf_revoke(grant_id); - - return(r); -} - - -/*===========================================================================* - * req_lookup * - *===========================================================================*/ -PUBLIC int req_lookup( - endpoint_t fs_e, - ino_t dir_ino, - ino_t root_ino, - uid_t uid, - gid_t gid, - struct lookup *resolve, - lookup_res_t *res, - struct fproc *rfp -) -{ - int r; - size_t len; - cp_grant_id_t grant_id=0, grant_id2=0; - message m; - vfs_ucred_t credentials; - int flags; - - grant_id = cpf_grant_direct(fs_e, (vir_bytes) resolve->l_path, PATH_MAX, - CPF_READ | CPF_WRITE); - if(grant_id == -1) - panic("req_lookup: cpf_grant_direct failed"); - - flags = resolve->l_flags; - len = strlen(resolve->l_path) + 1; - - m.m_type = REQ_LOOKUP; - m.REQ_GRANT = grant_id; - m.REQ_PATH_LEN = len; - m.REQ_PATH_SIZE = PATH_MAX + 1; - m.REQ_DIR_INO = dir_ino; - m.REQ_ROOT_INO = root_ino; - - if(rfp->fp_ngroups > 0) { /* Is the process member of multiple groups? */ - /* In that case the FS has to copy the uid/gid credentials */ - int i; - - /* Set credentials */ - credentials.vu_uid = rfp->fp_effuid; - credentials.vu_gid = rfp->fp_effgid; - credentials.vu_ngroups = rfp->fp_ngroups; - for (i = 0; i < rfp->fp_ngroups; i++) - credentials.vu_sgroups[i] = rfp->fp_sgroups[i]; - - grant_id2 = cpf_grant_direct(fs_e, (vir_bytes) &credentials, - sizeof(credentials), CPF_READ); - if(grant_id2 == -1) - panic("req_lookup: cpf_grant_direct failed"); - - m.REQ_GRANT2 = grant_id2; - m.REQ_UCRED_SIZE= sizeof(credentials); - flags |= PATH_GET_UCRED; - } else { - /* When there's only one gid, we can send it directly */ - m.REQ_UID = uid; - m.REQ_GID = gid; - flags &= ~PATH_GET_UCRED; - } - - m.REQ_FLAGS = flags; - - /* Send/rec request */ - r = fs_sendrec(fs_e, &m); - cpf_revoke(grant_id); - if(rfp->fp_ngroups > 0) cpf_revoke(grant_id2); - - /* Fill in response according to the return value */ - res->fs_e = m.m_source; - - switch (r) { - case OK: - res->inode_nr = m.RES_INODE_NR; - res->fmode = m.RES_MODE; - res->fsize = m.RES_FILE_SIZE_LO; - res->dev = m.RES_DEV; - res->uid= m.RES_UID; - res->gid= m.RES_GID; - break; - case EENTERMOUNT: - res->inode_nr = m.RES_INODE_NR; - res->char_processed = m.RES_OFFSET; - res->symloop = m.RES_SYMLOOP; - break; - case ELEAVEMOUNT: - res->char_processed = m.RES_OFFSET; - res->symloop = m.RES_SYMLOOP; - break; - case ESYMLINK: - res->char_processed = m.RES_OFFSET; - res->symloop = m.RES_SYMLOOP; - break; - default: - break; - } - - return(r); -} - - -/*===========================================================================* - * req_mkdir * - *===========================================================================*/ -PUBLIC int req_mkdir( - endpoint_t fs_e, - ino_t inode_nr, - char *lastc, - uid_t uid, - gid_t gid, - mode_t dmode -) -{ - int r; - cp_grant_id_t grant_id; - size_t len; - message m; - - len = strlen(lastc) + 1; - grant_id = cpf_grant_direct(fs_e, (vir_bytes)lastc, len, CPF_READ); - if(grant_id == -1) - panic("req_mkdir: cpf_grant_direct failed"); - - /* Fill in request message */ - m.m_type = REQ_MKDIR; - m.REQ_INODE_NR = inode_nr; - m.REQ_MODE = dmode; - m.REQ_UID = uid; - m.REQ_GID = gid; - m.REQ_GRANT = grant_id; - m.REQ_PATH_LEN = len; - - /* Send/rec request */ - r = fs_sendrec(fs_e, &m); - cpf_revoke(grant_id); - - return(r); -} - - -/*===========================================================================* - * req_mknod * - *===========================================================================*/ -PUBLIC int req_mknod( - endpoint_t fs_e, - ino_t inode_nr, - char *lastc, - uid_t uid, - gid_t gid, - mode_t dmode, - dev_t dev -) -{ - int r; - size_t len; - cp_grant_id_t grant_id; - message m; - - len = strlen(lastc) + 1; - grant_id = cpf_grant_direct(fs_e, (vir_bytes)lastc, len, CPF_READ); - if(grant_id == -1) - panic("req_mknod: cpf_grant_direct failed"); - - /* Fill in request message */ - m.m_type = REQ_MKNOD; - m.REQ_INODE_NR = inode_nr; - m.REQ_MODE = dmode; - m.REQ_DEV = dev; - m.REQ_UID = uid; - m.REQ_GID = gid; - m.REQ_GRANT = grant_id; - m.REQ_PATH_LEN = len; - - /* Send/rec request */ - r = fs_sendrec(fs_e, &m); - cpf_revoke(grant_id); - - return(r); -} - - -/*===========================================================================* - * req_mountpoint * - *===========================================================================*/ -PUBLIC int req_mountpoint(endpoint_t fs_e, ino_t inode_nr) -{ - message m; - - /* Fill in request message */ - m.m_type = REQ_MOUNTPOINT; - m.REQ_INODE_NR = inode_nr; - - /* Send/rec request */ - return fs_sendrec(fs_e, &m); -} - - -/*===========================================================================* - * req_newnode * - *===========================================================================*/ -PUBLIC int req_newnode( - endpoint_t fs_e, - uid_t uid, - gid_t gid, - mode_t dmode, - dev_t dev, - struct node_details *res -) -{ - int r; - message m; - - /* Fill in request message */ - m.m_type = REQ_NEWNODE; - m.REQ_MODE = dmode; - m.REQ_DEV = dev; - m.REQ_UID = uid; - m.REQ_GID = gid; - - /* Send/rec request */ - r = fs_sendrec(fs_e, &m); - - res->fs_e = m.m_source; - res->inode_nr = m.RES_INODE_NR; - res->fmode = m.RES_MODE; - res->fsize = m.RES_FILE_SIZE_LO; - res->dev = m.RES_DEV; - res->uid = m.RES_UID; - res->gid = m.RES_GID; - - return(r); -} - - -/*===========================================================================* - * req_newdriver * - *===========================================================================*/ -PUBLIC int req_newdriver( - endpoint_t fs_e, - dev_t dev, - char *label -) -{ - cp_grant_id_t grant_id; - size_t len; - message m; - int r; - - /* Grant access to label */ - len = strlen(label) + 1; - grant_id = cpf_grant_direct(fs_e, (vir_bytes) label, len, CPF_READ); - if (grant_id == -1) - panic("req_newdriver: cpf_grant_direct failed"); - - /* Fill in request message */ - m.m_type = REQ_NEW_DRIVER; - m.REQ_DEV = dev; - m.REQ_GRANT = grant_id; - m.REQ_PATH_LEN = len; - - /* Issue request */ - r = fs_sendrec(fs_e, &m); - - cpf_revoke(grant_id); - - return(r); -} - - -/*===========================================================================* - * req_putnode * - *===========================================================================*/ -PUBLIC int req_putnode(fs_e, inode_nr, count) -int fs_e; -ino_t inode_nr; -int count; -{ - message m; - - /* Fill in request message */ - m.m_type = REQ_PUTNODE; - m.REQ_INODE_NR = inode_nr; - m.REQ_COUNT = count; - - /* Send/rec request */ - return fs_sendrec(fs_e, &m); -} - - -/*===========================================================================* - * req_rdlink * - *===========================================================================*/ -PUBLIC int req_rdlink(fs_e, inode_nr, proc_e, buf, len, direct) -endpoint_t fs_e; -ino_t inode_nr; -endpoint_t proc_e; -char *buf; -size_t len; -int direct; /* set to 1 to use direct grants instead of magic grants */ -{ - message m; - int r; - cp_grant_id_t grant_id; - - if (direct) { - grant_id = cpf_grant_direct(fs_e, (vir_bytes) buf, len, CPF_WRITE); - } else { - grant_id = cpf_grant_magic(fs_e, proc_e, (vir_bytes) buf, len, - CPF_WRITE); - } - if(grant_id == -1) - panic("req_rdlink: cpf_grant_magic failed"); - - /* Fill in request message */ - m.m_type = REQ_RDLINK; - m.REQ_INODE_NR = inode_nr; - m.REQ_GRANT = grant_id; - m.REQ_MEM_SIZE = len; - - /* Send/rec request */ - r = fs_sendrec(fs_e, &m); - cpf_revoke(grant_id); - - if(r == OK) r = m.RES_NBYTES; - - return(r); -} - - -/*===========================================================================* - * req_readsuper * - *===========================================================================*/ -PUBLIC int req_readsuper( - endpoint_t fs_e, - char *label, - dev_t dev, - int readonly, - int isroot, - struct node_details *res_nodep, - int *con_reqs -) -{ - int r; - cp_grant_id_t grant_id; - size_t len; - message m; - - len = strlen(label)+1; - grant_id = cpf_grant_direct(fs_e, (vir_bytes) label, len, CPF_READ); - if (grant_id == -1) - panic("req_readsuper: cpf_grant_direct failed"); - - /* Fill in request message */ - m.m_type = REQ_READSUPER; - m.REQ_FLAGS = 0; - if(readonly) m.REQ_FLAGS |= REQ_RDONLY; - if(isroot) m.REQ_FLAGS |= REQ_ISROOT; - m.REQ_GRANT = grant_id; - m.REQ_DEV = dev; - m.REQ_PATH_LEN = len; - - /* Send/rec request */ - r = fs_sendrec(fs_e, &m); - cpf_revoke(grant_id); - - if(r == OK) { - /* Fill in response structure */ - res_nodep->fs_e = m.m_source; - res_nodep->inode_nr = m.RES_INODE_NR; - res_nodep->fmode = m.RES_MODE; - res_nodep->fsize = m.RES_FILE_SIZE_LO; - res_nodep->uid = m.RES_UID; - res_nodep->gid = m.RES_GID; - *con_reqs = m.RES_CONREQS; - } - - return(r); -} - - -/*===========================================================================* - * req_readwrite * - *===========================================================================*/ -PUBLIC int req_readwrite(fs_e, inode_nr, pos, rw_flag, user_e, - user_addr, num_of_bytes, new_posp, cum_iop) -endpoint_t fs_e; -ino_t inode_nr; -u64_t pos; -int rw_flag; -endpoint_t user_e; -char *user_addr; -unsigned int num_of_bytes; -u64_t *new_posp; -unsigned int *cum_iop; -{ - int r; - cp_grant_id_t grant_id; - message m; - - if (ex64hi(pos) != 0) - panic("req_readwrite: pos too large"); - - grant_id = cpf_grant_magic(fs_e, user_e, (vir_bytes) user_addr, num_of_bytes, - (rw_flag==READING ? CPF_WRITE:CPF_READ)); - if (grant_id == -1) - panic("req_readwrite: cpf_grant_magic failed"); - - /* Fill in request message */ - m.m_type = rw_flag == READING ? REQ_READ : REQ_WRITE; - m.REQ_INODE_NR = inode_nr; - m.REQ_GRANT = grant_id; - m.REQ_SEEK_POS_LO = ex64lo(pos); - m.REQ_SEEK_POS_HI = 0; /* Not used for now, so clear it. */ - m.REQ_NBYTES = num_of_bytes; - - /* Send/rec request */ - r = fs_sendrec(fs_e, &m); - cpf_revoke(grant_id); - - if (r == OK) { - /* Fill in response structure */ - *new_posp = cvul64(m.RES_SEEK_POS_LO); - *cum_iop = m.RES_NBYTES; - } - - return(r); -} - - -/*===========================================================================* - * req_rename * - *===========================================================================*/ -PUBLIC int req_rename(fs_e, old_dir, old_name, new_dir, new_name) -endpoint_t fs_e; -ino_t old_dir; -char *old_name; -ino_t new_dir; -char *new_name; -{ - int r; - cp_grant_id_t gid_old, gid_new; - size_t len_old, len_new; - message m; - - len_old = strlen(old_name) + 1; - gid_old = cpf_grant_direct(fs_e, (vir_bytes) old_name, len_old, CPF_READ); - if(gid_old == -1) - panic("req_rename: cpf_grant_direct failed"); - - len_new = strlen(new_name) + 1; - gid_new = cpf_grant_direct(fs_e, (vir_bytes) new_name, len_new, CPF_READ); - if(gid_new == -1) - panic("req_rename: cpf_grant_direct failed"); - - /* Fill in request message */ - m.m_type = REQ_RENAME; - m.REQ_REN_OLD_DIR = old_dir; - m.REQ_REN_NEW_DIR = new_dir; - m.REQ_REN_GRANT_OLD = gid_old; - m.REQ_REN_LEN_OLD = len_old; - m.REQ_REN_GRANT_NEW = gid_new; - m.REQ_REN_LEN_NEW = len_new; - - /* Send/rec request */ - r = fs_sendrec(fs_e, &m); - cpf_revoke(gid_old); - cpf_revoke(gid_new); - - return(r); -} - - -/*===========================================================================* - * req_rmdir * - *===========================================================================*/ -PUBLIC int req_rmdir(fs_e, inode_nr, lastc) -endpoint_t fs_e; -ino_t inode_nr; -char *lastc; -{ - int r; - cp_grant_id_t grant_id; - size_t len; - message m; - - len = strlen(lastc) + 1; - grant_id = cpf_grant_direct(fs_e, (vir_bytes) lastc, len, CPF_READ); - if(grant_id == -1) - panic("req_rmdir: cpf_grant_direct failed"); - - /* Fill in request message */ - m.m_type = REQ_RMDIR; - m.REQ_INODE_NR = inode_nr; - m.REQ_GRANT = grant_id; - m.REQ_PATH_LEN = len; - - /* Send/rec request */ - r = fs_sendrec(fs_e, &m); - cpf_revoke(grant_id); - - return(r); -} - - -/*===========================================================================* - * req_slink * - *===========================================================================*/ -PUBLIC int req_slink( - endpoint_t fs_e, - ino_t inode_nr, - char *lastc, - endpoint_t proc_e, - char *path_addr, - unsigned short path_length, - uid_t uid, - gid_t gid -) -{ - int r; - size_t len; - cp_grant_id_t gid_name, gid_buf; - message m; - - len = strlen(lastc) + 1; - gid_name = cpf_grant_direct(fs_e, (vir_bytes) lastc, len, CPF_READ); - if(gid_name == -1) - panic("req_slink: cpf_grant_direct failed"); - - gid_buf = cpf_grant_magic(fs_e, proc_e, (vir_bytes) path_addr, path_length, - CPF_READ); - if(gid_buf == -1) { - cpf_revoke(gid_name); - panic("req_slink: cpf_grant_magic failed"); - } - - /* Fill in request message */ - m.m_type = REQ_SLINK; - m.REQ_INODE_NR = inode_nr; - m.REQ_UID = uid; - m.REQ_GID = gid; - m.REQ_GRANT = gid_name; - m.REQ_PATH_LEN = len; - m.REQ_GRANT3 = gid_buf; - m.REQ_MEM_SIZE = path_length; - - /* Send/rec request */ - r = fs_sendrec(fs_e, &m); - cpf_revoke(gid_name); - cpf_revoke(gid_buf); - - return(r); -} - - -/*===========================================================================* - * req_stat * - *===========================================================================*/ -PUBLIC int req_stat(fs_e, inode_nr, proc_e, buf, pos, stat_version) -int fs_e; -ino_t inode_nr; -int proc_e; -char *buf; -int pos; -int stat_version; -{ - cp_grant_id_t grant_id; - int r; - message m; - struct stat sb; - struct minix_prev_stat old_sb; /* for backward compatibility */ - - if (pos != 0 || stat_version != 0) - grant_id = cpf_grant_direct(fs_e, (vir_bytes) &sb, - sizeof(struct stat), CPF_WRITE); - else - grant_id = cpf_grant_magic(fs_e, proc_e, (vir_bytes) buf, - sizeof(struct stat), CPF_WRITE); - - if (grant_id < 0) - panic("req_stat: cpf_grant_* failed"); - - /* Fill in request message */ - m.m_type = REQ_STAT; - m.REQ_INODE_NR = inode_nr; - m.REQ_GRANT = grant_id; - - /* Send/rec request */ - r = fs_sendrec(fs_e, &m); - cpf_revoke(grant_id); - - if (r != OK || (pos == 0 && stat_version == 0)) - return(r); - - if (pos != 0) - sb.st_size -= pos; - if (stat_version == 0) { - r = sys_vircopy(SELF, D, (vir_bytes) &sb, proc_e, D, (vir_bytes) buf, - sizeof(struct stat)); - return(r); - } - - /* User needs old struct stat. - * Just 1 prev version at this moment */ - assert(stat_version == 1); - -/* XXX until that st_Xtime macroses used, we have to undefine them, - * because of minix_prev_stat - */ -#undef st_atime -#undef st_ctime -#undef st_mtime - -/* Copy field by field because of st_gid type mismath and - * difference in order after atime. - */ - old_sb.st_dev = sb.st_dev; - old_sb.st_ino = sb.st_ino; - old_sb.st_mode = sb.st_mode; - old_sb.st_nlink = sb.st_nlink; - old_sb.st_uid = sb.st_uid; - old_sb.st_gid = sb.st_gid; - old_sb.st_rdev = sb.st_rdev; - old_sb.st_size = sb.st_size; -#if defined(_NETBSD_SOURCE) - old_sb.st_atime = sb.st_atimespec.tv_sec; - old_sb.st_mtime = sb.st_mtimespec.tv_sec; - old_sb.st_ctime = sb.st_ctimespec.tv_sec; -#else - old_sb.st_atime = sb.st_atime; - old_sb.st_mtime = sb.st_mtime; - old_sb.st_ctime = sb.st_ctime; -#endif - - r = sys_vircopy(SELF, D, (vir_bytes) &old_sb, proc_e, D, (vir_bytes) buf, - sizeof(struct minix_prev_stat)); - - return(r); -} - - -/*===========================================================================* - * req_sync * - *===========================================================================*/ -PUBLIC int req_sync(fs_e) -endpoint_t fs_e; -{ - message m; - - /* Fill in request message */ - m.m_type = REQ_SYNC; - - /* Send/rec request */ - return fs_sendrec(fs_e, &m); -} - - -/*===========================================================================* - * req_unlink * - *===========================================================================*/ -PUBLIC int req_unlink(fs_e, inode_nr, lastc) -endpoint_t fs_e; -ino_t inode_nr; -char *lastc; -{ - cp_grant_id_t grant_id; - size_t len; - int r; - message m; - - len = strlen(lastc) + 1; - grant_id = cpf_grant_direct(fs_e, (vir_bytes) lastc, len, CPF_READ); - if(grant_id == -1) - panic("req_unlink: cpf_grant_direct failed"); - - /* Fill in request message */ - m.m_type = REQ_UNLINK; - m.REQ_INODE_NR = inode_nr; - m.REQ_GRANT = grant_id; - m.REQ_PATH_LEN = len; - - /* Send/rec request */ - r = fs_sendrec(fs_e, &m); - cpf_revoke(grant_id); - - return(r); -} - - -/*===========================================================================* - * req_unmount * - *===========================================================================*/ -PUBLIC int req_unmount(fs_e) -endpoint_t fs_e; -{ - message m; - - /* Fill in request message */ - m.m_type = REQ_UNMOUNT; - - /* Send/rec request */ - return fs_sendrec(fs_e, &m); -} - - -/*===========================================================================* - * req_utime * - *===========================================================================*/ -PUBLIC int req_utime(fs_e, inode_nr, actime, modtime) -endpoint_t fs_e; -ino_t inode_nr; -time_t actime; -time_t modtime; -{ - message m; - - /* Fill in request message */ - m.m_type = REQ_UTIME; - m.REQ_INODE_NR = inode_nr; - m.REQ_ACTIME = actime; - m.REQ_MODTIME = modtime; - - /* Send/rec request */ - return fs_sendrec(fs_e, &m); -} diff --git a/servers/avfs/request.h b/servers/avfs/request.h deleted file mode 100644 index 74f612bf9..000000000 --- a/servers/avfs/request.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef __VFS_REQUEST_H__ -#define __VFS_REQUEST_H__ - -/* Low level request messages are built and sent by wrapper functions. - * This file contains the request and response structures for accessing - * those wrappers functions. - */ - -#include - -/* Structure for response that contains inode details */ -typedef struct node_details { - endpoint_t fs_e; - ino_t inode_nr; - mode_t fmode; - off_t fsize; - uid_t uid; - gid_t gid; - - /* For char/block special files */ - dev_t dev; -} node_details_t; - -/* Structure for a lookup response */ -typedef struct lookup_res { - endpoint_t fs_e; - ino_t inode_nr; - mode_t fmode; - off_t fsize; - uid_t uid; - gid_t gid; - /* For char/block special files */ - dev_t dev; - - /* Fields used for handling mount point and symbolic links */ - int char_processed; - unsigned char symloop; -} lookup_res_t; - - -#endif diff --git a/servers/avfs/select.c b/servers/avfs/select.c deleted file mode 100644 index 90e23ab06..000000000 --- a/servers/avfs/select.c +++ /dev/null @@ -1,1071 +0,0 @@ -/* Implement entry point to select system call. - * - * The entry points into this file are - * do_select: perform the SELECT system call - * select_callback: notify select system of possible fd operation - * select_unsuspend_by_endpt: cancel a blocking select on exiting driver - */ - -#include "fs.h" -#include -#include -#include -#include -#include -#include - -#include "select.h" -#include "file.h" -#include "fproc.h" -#include "dmap.h" -#include "vnode.h" - -/* max. number of simultaneously pending select() calls */ -#define MAXSELECTS 25 -#define FROM_PROC 0 -#define TO_PROC 1 - -PRIVATE struct selectentry { - struct fproc *requestor; /* slot is free iff this is NULL */ - endpoint_t req_endpt; - fd_set readfds, writefds, errorfds; - fd_set ready_readfds, ready_writefds, ready_errorfds; - fd_set *vir_readfds, *vir_writefds, *vir_errorfds; - struct filp *filps[OPEN_MAX]; - int type[OPEN_MAX]; - int nfds, nreadyfds; - int error; - char block; - clock_t expiry; - timer_t timer; /* if expiry > 0 */ -} selecttab[MAXSELECTS]; - -FORWARD _PROTOTYPE(int copy_fdsets, (struct selectentry *se, int nfds, - int direction) ); -FORWARD _PROTOTYPE(int do_select_request, (struct selectentry *se, int fd, - int *ops) ); -FORWARD _PROTOTYPE(void filp_status, (struct filp *fp, int status) ); -FORWARD _PROTOTYPE(int is_deferred, (struct selectentry *se) ); -FORWARD _PROTOTYPE(void restart_proc, (struct selectentry *se) ); -FORWARD _PROTOTYPE(void ops2tab, (int ops, int fd, struct selectentry *e)); -FORWARD _PROTOTYPE(int is_regular_file, (struct filp *f) ); -FORWARD _PROTOTYPE(int is_pipe, (struct filp *f) ); -FORWARD _PROTOTYPE(int is_supported_major, (struct filp *f) ); -FORWARD _PROTOTYPE(void select_lock_filp, (struct filp *f, int ops) ); -FORWARD _PROTOTYPE(int select_request_async, (struct filp *f, int *ops, - int block) ); -FORWARD _PROTOTYPE(int select_request_file, (struct filp *f, int *ops, - int block) ); -FORWARD _PROTOTYPE(int select_request_major, (struct filp *f, int *ops, - int block) ); -FORWARD _PROTOTYPE(int select_request_pipe, (struct filp *f, int *ops, - int block) ); -FORWARD _PROTOTYPE(int select_request_sync, (struct filp *f, int *ops, - int block) ); -FORWARD _PROTOTYPE(void select_cancel_all, (struct selectentry *e) ); -FORWARD _PROTOTYPE(void select_cancel_filp, (struct filp *f) ); -FORWARD _PROTOTYPE(void select_return, (struct selectentry *) ); -FORWARD _PROTOTYPE(void select_restart_filps, (void) ); -FORWARD _PROTOTYPE(int tab2ops, (int fd, struct selectentry *e) ); -FORWARD _PROTOTYPE(void wipe_select, (struct selectentry *s) ); - -PRIVATE struct fdtype { - int (*select_request)(struct filp *, int *ops, int block); - int (*type_match)(struct filp *f); -} fdtypes[] = { - { select_request_major, is_supported_major }, - { select_request_file, is_regular_file }, - { select_request_pipe, is_pipe }, -}; -#define SEL_FDS (sizeof(fdtypes) / sizeof(fdtypes[0])) -PRIVATE int select_majors[] = { /* List of majors that support selecting on */ - TTY_MAJOR, - INET_MAJOR, - UDS_MAJOR, - LOG_MAJOR, -}; -#define SEL_MAJORS (sizeof(select_majors) / sizeof(select_majors[0])) - -/*===========================================================================* - * do_select * - *===========================================================================*/ -PUBLIC int do_select(void) -{ -/* Implement the select(nfds, readfds, writefds, errorfds, timeout) system - * call. First we copy the arguments and verify their sanity. Then we check - * whether there are file descriptors that satisfy the select call right of the - * bat. If so, or if there are no ready file descriptors but the process - * requested to return immediately, we return the result. Otherwise we set a - * timeout and wait for either the file descriptors to become ready or the - * timer to go off. If no timeout value was provided, we wait indefinitely. */ - - int r, nfds, do_timeout = 0, fd, s; - struct timeval timeout; - struct selectentry *se; - - nfds = m_in.SEL_NFDS; - - /* Sane amount of file descriptors? */ - if (nfds < 0 || nfds > OPEN_MAX) return(EINVAL); - - /* Find a slot to store this select request */ - for (s = 0; s < MAXSELECTS; s++) - if (selecttab[s].requestor == NULL) /* Unused slot */ - break; - if (s >= MAXSELECTS) return(ENOSPC); - - se = &selecttab[s]; - wipe_select(se); /* Clear results of previous usage */ - se->req_endpt = who_e; - se->vir_readfds = (fd_set *) m_in.SEL_READFDS; - se->vir_writefds = (fd_set *) m_in.SEL_WRITEFDS; - se->vir_errorfds = (fd_set *) m_in.SEL_ERRORFDS; - - /* Copy fdsets from the process */ - if ((r = copy_fdsets(se, nfds, FROM_PROC)) != OK) return(r); - - /* Did the process set a timeout value? If so, retrieve it. */ - if (m_in.SEL_TIMEOUT != NULL) { - do_timeout = 1; - r = sys_vircopy(who_e, D, (vir_bytes) m_in.SEL_TIMEOUT, SELF, D, - (vir_bytes) &timeout, sizeof(timeout)); - if (r != OK) return(r); - } - - /* No nonsense in the timeval */ - if (do_timeout && (timeout.tv_sec < 0 || timeout.tv_usec < 0)) - return(EINVAL); - - /* If there is no timeout, we block forever. Otherwise, we block up to the - * specified time interval. - */ - if (!do_timeout) /* No timeout value set */ - se->block = 1; - else if (do_timeout && (timeout.tv_sec > 0 || timeout.tv_usec > 0)) - se->block = 1; - else /* timeout set as (0,0) - this effects a poll */ - se->block = 0; - se->expiry = 0; /* no timer set (yet) */ - - /* Verify that file descriptors are okay to select on */ - for (fd = 0; fd < nfds; fd++) { - struct filp *f; - int type, ops; - - /* Because the select() interface implicitly includes file descriptors - * you might not want to select on, we have to figure out whether we're - * interested in them. Typically, these file descriptors include fd's - * inherited from the parent proc and file descriptors that have been - * close()d, but had a lower fd than one in the current set. - */ - if (!(ops = tab2ops(fd, se))) - continue; /* No operations set; nothing to do for this fd */ - - /* Get filp belonging to this fd */ - f = se->filps[fd] = get_filp(fd, VNODE_READ); - if (f == NULL) { - if (err_code == EBADF) - r = err_code; - else /* File descriptor is 'ready' to return EIO */ - r = EINTR; - - return(r); - } - - /* Check file types. According to POSIX 2008: - * "The pselect() and select() functions shall support regular files, - * terminal and pseudo-terminal devices, FIFOs, pipes, and sockets. The - * behavior of pselect() and select() on file descriptors that refer to - * other types of file is unspecified." - * - * In our case, terminal and pseudo-terminal devices are handled by the - * TTY major and sockets by either INET major (socket type AF_INET) or - * PFS major (socket type AF_UNIX). PFS acts as an FS when it handles - * pipes and as a driver when it handles sockets. Additionally, we - * support select on the LOG major to handle kernel logging, which is - * beyond the POSIX spec. */ - - se->type[fd] = -1; - for (type = 0; type < SEL_FDS; type++) { - if (fdtypes[type].type_match(f)) { - se->type[fd] = type; - se->nfds = fd+1; - se->filps[fd]->filp_selectors++; - break; - } - } - unlock_filp(f); - if (se->type[fd] == -1) /* Type not found */ - return(EBADF); - } - - /* Check all file descriptors in the set whether one is 'ready' now */ - for (fd = 0; fd < nfds; fd++) { - int ops, r; - struct filp *f; - - /* Again, check for involuntarily selected fd's */ - if (!(ops = tab2ops(fd, se))) - continue; /* No operations set; nothing to do for this fd */ - - /* Test filp for select operations if not already done so. e.g., - * processes sharing a filp and both doing a select on that filp. */ - f = se->filps[fd]; - select_lock_filp(f, f->filp_select_ops | ops); - if ((f->filp_select_ops & ops) != ops) { - int wantops; - - wantops = (f->filp_select_ops |= ops); - r = do_select_request(se, fd, &wantops); - unlock_filp(f); - if (r != SEL_OK) { - if (r == SEL_DEFERRED) continue; - else break; /* Error or bogus return code; abort */ - } - - /* The select request above might have turned on/off some - * operations because they were 'ready' or not meaningful. - * Either way, we might have a result and we need to store them - * in the select table entry. */ - if (wantops & ops) ops2tab(wantops, fd, se); - } else { - unlock_filp(f); - } - } - - if ((se->nreadyfds > 0 || !se->block) && !is_deferred(se)) { - /* fd's were found that were ready to go right away, and/or - * we were instructed not to block at all. Must return - * immediately. - */ - r = copy_fdsets(se, se->nfds, TO_PROC); - select_cancel_all(se); - - if (r != OK) - return(r); - else if (se->error != OK) - return(se->error); - - return(se->nreadyfds); - } - - /* Convert timeval to ticks and set the timer. If it fails, undo - * all, return error. - */ - if (do_timeout) { - int ticks; - /* Open Group: - * "If the requested timeout interval requires a finer - * granularity than the implementation supports, the - * actual timeout interval shall be rounded up to the next - * supported value." - */ -#define USECPERSEC 1000000 - while(timeout.tv_usec >= USECPERSEC) { - /* this is to avoid overflow with *system_hz below */ - timeout.tv_usec -= USECPERSEC; - timeout.tv_sec++; - } - ticks = timeout.tv_sec * system_hz + - (timeout.tv_usec * system_hz + USECPERSEC-1) / USECPERSEC; - se->expiry = ticks; - set_timer(&se->timer, ticks, select_timeout_check, s); - } - - /* If we're blocking, the table entry is now valid */ - se->requestor = fp; - - /* process now blocked */ - suspend(FP_BLOCKED_ON_SELECT); - return(SUSPEND); -} - -/*===========================================================================* - * is_deferred * - *===========================================================================*/ -PRIVATE int is_deferred(struct selectentry *se) -{ -/* Find out whether this select has pending initial replies */ - - int fd; - struct filp *f; - - for (fd = 0; fd < se->nfds; fd++) { - if ((f = se->filps[fd]) == NULL) continue; - if (f->filp_select_flags & (FSF_UPDATE|FSF_BUSY)) return(TRUE); - } - - return(FALSE); -} - - -/*===========================================================================* - * is_regular_file * - *===========================================================================*/ -PRIVATE int is_regular_file(struct filp *f) -{ - return(f && f->filp_vno && (f->filp_vno->v_mode & I_TYPE) == I_REGULAR); -} - -/*===========================================================================* - * is_pipe * - *===========================================================================*/ -PRIVATE int is_pipe(struct filp *f) -{ -/* Recognize either anonymous pipe or named pipe (FIFO) */ - return(f && f->filp_vno && (f->filp_vno->v_mode & I_TYPE) == I_NAMED_PIPE); -} - -/*===========================================================================* - * is_supported_major * - *===========================================================================*/ -PRIVATE int is_supported_major(struct filp *f) -{ -/* See if this filp is a handle on a device on which we support select() */ - int m; - - if (!(f && f->filp_vno)) return(FALSE); - if ((f->filp_vno->v_mode & I_TYPE) != I_CHAR_SPECIAL) return(FALSE); - - for (m = 0; m < SEL_MAJORS; m++) - if (major(f->filp_vno->v_sdev) == select_majors[m]) - return(TRUE); - - return(FALSE); -} - -/*===========================================================================* - * select_request_async * - *===========================================================================*/ -PRIVATE int select_request_async(struct filp *f, int *ops, int block) -{ - int r, rops, major; - struct dmap *dp; - - rops = *ops; - - if (!block && (f->filp_select_flags & FSF_BLOCKED)) { - /* This filp is blocked waiting for a reply, but we don't want to - * block ourselves. Unless we're awaiting the initial reply, these - * operations won't be ready */ - if (!(f->filp_select_flags & FSF_BUSY)) { - if ((rops & SEL_RD) && (f->filp_select_flags & FSF_RD_BLOCK)) - rops &= ~SEL_RD; - if ((rops & SEL_WR) && (f->filp_select_flags & FSF_WR_BLOCK)) - rops &= ~SEL_WR; - if ((rops & SEL_ERR) && (f->filp_select_flags & FSF_ERR_BLOCK)) - rops &= ~SEL_ERR; - if (!(rops & (SEL_RD|SEL_WR|SEL_ERR))) { - /* Nothing left to do */ - *ops = 0; - return(SEL_OK); - } - } - } - - f->filp_select_flags |= FSF_UPDATE; - if (block) { - rops |= SEL_NOTIFY; - if (rops & SEL_RD) f->filp_select_flags |= FSF_RD_BLOCK; - if (rops & SEL_WR) f->filp_select_flags |= FSF_WR_BLOCK; - if (rops & SEL_ERR) f->filp_select_flags |= FSF_ERR_BLOCK; - } - - if (f->filp_select_flags & FSF_BUSY) - return(SEL_DEFERRED); - - major = major(f->filp_vno->v_sdev); - if (major < 0 || major >= NR_DEVICES) return(SEL_ERROR); - dp = &dmap[major]; - if (dp->dmap_sel_filp) - return(SEL_DEFERRED); - - f->filp_select_flags &= ~FSF_UPDATE; - r = dev_io(VFS_DEV_SELECT, f->filp_vno->v_sdev, rops, NULL, - cvu64(0), 0, 0, FALSE); - if (r < 0 && r != SUSPEND) - return(SEL_ERROR); - - if (r != SUSPEND) - panic("select_request_asynch: expected SUSPEND got: %d", r); - - dp->dmap_sel_filp = f; - f->filp_select_flags |= FSF_BUSY; - - return(SEL_DEFERRED); -} - -/*===========================================================================* - * select_request_file * - *===========================================================================*/ -PRIVATE int select_request_file(struct filp *UNUSED(f), int *UNUSED(ops), - int UNUSED(block)) -{ - /* Files are always ready, so output *ops is input *ops */ - return(SEL_OK); -} - -/*===========================================================================* - * select_request_major * - *===========================================================================*/ -PRIVATE int select_request_major(struct filp *f, int *ops, int block) -{ - int major, r; - - major = major(f->filp_vno->v_sdev); - if (major < 0 || major >= NR_DEVICES) return(SEL_ERROR); - - if (dmap[major].dmap_style == STYLE_DEVA || - dmap[major].dmap_style == STYLE_CLONE_A) - r = select_request_async(f, ops, block); - else - r = select_request_sync(f, ops, block); - - return(r); -} - -/*===========================================================================* - * select_request_sync * - *===========================================================================*/ -PRIVATE int select_request_sync(struct filp *f, int *ops, int block) -{ - int rops; - - rops = *ops; - if (block) rops |= SEL_NOTIFY; - *ops = dev_io(VFS_DEV_SELECT, f->filp_vno->v_sdev, rops, NULL, - cvu64(0), 0, 0, FALSE); - if (*ops < 0) - return(SEL_ERROR); - - return(SEL_OK); -} - -/*===========================================================================* - * select_request_pipe * - *===========================================================================*/ -PRIVATE int select_request_pipe(struct filp *f, int *ops, int block) -{ - int orig_ops, r = 0, err; - - orig_ops = *ops; - - if ((*ops & (SEL_RD|SEL_ERR))) { - err = pipe_check(f->filp_vno, READING, 0, 1, f->filp_pos, 1); - - if (err != SUSPEND) - r |= SEL_RD; - if (err < 0 && err != SUSPEND) - r |= SEL_ERR; - if (err == SUSPEND && !(f->filp_mode & R_BIT)) { - /* A "meaningless" read select, therefore ready - * for reading and no error set. */ - r |= SEL_RD; - r &= ~SEL_ERR; - } - } - - if ((*ops & (SEL_WR|SEL_ERR))) { - err = pipe_check(f->filp_vno, WRITING, 0, 1, f->filp_pos, 1); - - if (err != SUSPEND) - r |= SEL_WR; - if (err < 0 && err != SUSPEND) - r |= SEL_ERR; - if (err == SUSPEND && !(f->filp_mode & W_BIT)) { - /* A "meaningless" write select, therefore ready - for writing and no error set. */ - r |= SEL_WR; - r &= ~SEL_ERR; - } - } - - /* Some options we collected might not be requested. */ - *ops = r & orig_ops; - - if (!*ops && block) - f->filp_pipe_select_ops |= orig_ops; - - return(SEL_OK); -} - -/*===========================================================================* - * tab2ops * - *===========================================================================*/ -PRIVATE int tab2ops(int fd, struct selectentry *e) -{ - int ops = 0; - if (FD_ISSET(fd, &e->readfds)) ops |= SEL_RD; - if (FD_ISSET(fd, &e->writefds)) ops |= SEL_WR; - if (FD_ISSET(fd, &e->errorfds)) ops |= SEL_ERR; - - return(ops); -} - - -/*===========================================================================* - * ops2tab * - *===========================================================================*/ -PRIVATE void ops2tab(int ops, int fd, struct selectentry *e) -{ - if ((ops & SEL_RD) && e->vir_readfds && FD_ISSET(fd, &e->readfds) && - !FD_ISSET(fd, &e->ready_readfds)) { - FD_SET(fd, &e->ready_readfds); - e->nreadyfds++; - } - - if ((ops & SEL_WR) && e->vir_writefds && FD_ISSET(fd, &e->writefds) && - !FD_ISSET(fd, &e->ready_writefds)) { - FD_SET(fd, &e->ready_writefds); - e->nreadyfds++; - } - - if ((ops & SEL_ERR) && e->vir_errorfds && FD_ISSET(fd, &e->errorfds) && - !FD_ISSET(fd, &e->ready_errorfds)) { - FD_SET(fd, &e->ready_errorfds); - e->nreadyfds++; - } -} - - -/*===========================================================================* - * copy_fdsets * - *===========================================================================*/ -PRIVATE int copy_fdsets(struct selectentry *se, int nfds, int direction) -{ - int r; - size_t fd_setsize; - endpoint_t src_e, dst_e; - fd_set *src_fds, *dst_fds; - - if (nfds < 0 || nfds > OPEN_MAX) - panic("select copy_fdsets: nfds wrong: %d", nfds); - - /* Only copy back as many bits as the user expects. */ -#ifdef __NBSD_LIBC - fd_setsize = (size_t) (howmany(nfds, __NFDBITS) * sizeof(__fd_mask)); -#else - fd_setsize = (size_t) (_FDSETWORDS(nfds) * _FDSETBITSPERWORD/8); -#endif - - /* Set source and destination endpoints */ - src_e = (direction == FROM_PROC) ? se->req_endpt : SELF; - dst_e = (direction == FROM_PROC) ? SELF : se->req_endpt; - - /* read set */ - src_fds = (direction == FROM_PROC) ? se->vir_readfds : &se->ready_readfds; - dst_fds = (direction == FROM_PROC) ? &se->readfds : se->vir_readfds; - if (se->vir_readfds) { - r = sys_vircopy(src_e, D, (vir_bytes) src_fds, dst_e, D, - (vir_bytes) dst_fds, fd_setsize); - if (r != OK) return(r); - } - - /* write set */ - src_fds = (direction == FROM_PROC) ? se->vir_writefds : &se->ready_writefds; - dst_fds = (direction == FROM_PROC) ? &se->writefds : se->vir_writefds; - if (se->vir_writefds) { - r = sys_vircopy(src_e, D, (vir_bytes) src_fds, dst_e, D, - (vir_bytes) dst_fds, fd_setsize); - if (r != OK) return(r); - } - - /* error set */ - src_fds = (direction == FROM_PROC) ? se->vir_errorfds : &se->ready_errorfds; - dst_fds = (direction == FROM_PROC) ? &se->errorfds : se->vir_errorfds; - if (se->vir_errorfds) { - r = sys_vircopy(src_e, D, (vir_bytes) src_fds, dst_e, D, - (vir_bytes) dst_fds, fd_setsize); - if (r != OK) return(r); - } - - return(OK); -} - - -/*===========================================================================* - * select_cancel_all * - *===========================================================================*/ -PRIVATE void select_cancel_all(struct selectentry *se) -{ -/* Cancel select. Decrease select usage and cancel timer */ - - int fd; - struct filp *f; - - for (fd = 0; fd < se->nfds; fd++) { - if ((f = se->filps[fd]) == NULL) continue; - se->filps[fd] = NULL; - select_cancel_filp(f); - } - - if (se->expiry > 0) { - cancel_timer(&se->timer); - se->expiry = 0; - } - - se->requestor = NULL; -} - -/*===========================================================================* - * select_cancel_filp * - *===========================================================================*/ -PRIVATE void select_cancel_filp(struct filp *f) -{ -/* Reduce number of select users of this filp */ - - assert(f); - assert(f->filp_selectors >= 0); - if (f->filp_selectors == 0) return; - if (f->filp_count == 0) return; - - select_lock_filp(f, f->filp_select_ops); - - f->filp_selectors--; - if (f->filp_selectors == 0) { - /* No one selecting on this filp anymore, forget about select state */ - f->filp_select_ops = 0; - f->filp_select_flags = 0; - f->filp_pipe_select_ops = 0; - } - - unlock_filp(f); -} - -/*===========================================================================* - * select_return * - *===========================================================================*/ -PRIVATE void select_return(struct selectentry *se) -{ - int r, r1; - - assert(!is_deferred(se)); /* Not done yet, first wait for async reply */ - - select_cancel_all(se); - - r1 = copy_fdsets(se, se->nfds, TO_PROC); - if (r1 != OK) - r = r1; - else if (se->error != OK) - r = se->error; - else - r = se->nreadyfds; - - revive(se->req_endpt, r); -} - - -/*===========================================================================* - * select_callback * - *===========================================================================*/ -PUBLIC void select_callback(struct filp *f, int status) -{ - filp_status(f, status); -} - -/*===========================================================================* - * init_select * - *===========================================================================*/ -PUBLIC void init_select(void) -{ - int s; - - for (s = 0; s < MAXSELECTS; s++) - init_timer(&selecttab[s].timer); -} - - -/*===========================================================================* - * select_forget * - *===========================================================================*/ -PUBLIC void select_forget(endpoint_t proc_e) -{ -/* Something has happened (e.g. signal delivered that interrupts select()). - * Totally forget about the select(). */ - - int slot; - struct selectentry *se; - - for (slot = 0; slot < MAXSELECTS; slot++) { - se = &selecttab[slot]; - if (se->requestor != NULL && se->req_endpt == proc_e) - break; - } - - if (slot >= MAXSELECTS) return; /* Entry not found */ - se->error = EINTR; - if (is_deferred(se)) return; /* Still awaiting initial reply */ - - select_cancel_all(se); -} - - -/*===========================================================================* - * select_timeout_check * - *===========================================================================*/ -PUBLIC void select_timeout_check(timer_t *timer) -{ - int s; - struct selectentry *se; - - s = tmr_arg(timer)->ta_int; - if (s < 0 || s >= MAXSELECTS) return; /* Entry does not exist */ - - se = &selecttab[s]; - if (se->requestor == NULL) return; - fp = se->requestor; - if (se->expiry <= 0) return; /* Strange, did we even ask for a timeout? */ - se->expiry = 0; - if (is_deferred(se)) return; /* Wait for initial replies to DEV_SELECT */ - select_return(se); -} - - -/*===========================================================================* - * select_unsuspend_by_endpt * - *===========================================================================*/ -PUBLIC void select_unsuspend_by_endpt(endpoint_t proc_e) -{ -/* Revive blocked processes when a driver has disappeared */ - - int fd, s, major; - struct selectentry *se; - struct filp *f; - - for (s = 0; s < MAXSELECTS; s++) { - int wakehim = 0; - se = &selecttab[s]; - if (se->requestor == NULL) continue; - if (se->requestor->fp_endpoint == proc_e) { - assert(se->requestor->fp_flags & FP_EXITING); - select_cancel_all(se); - continue; - } - - for (fd = 0; fd < se->nfds; fd++) { - if ((f = se->filps[fd]) == NULL || f->filp_vno == NULL) - continue; - - major = major(f->filp_vno->v_sdev); - if (dmap_driver_match(proc_e, major)) { - se->filps[fd] = NULL; - se->error = EINTR; - select_cancel_filp(f); - wakehim = 1; - } - } - - if (wakehim && !is_deferred(se)) - select_return(se); - } -} - -/*===========================================================================* - * select_reply1 * - *===========================================================================*/ -PUBLIC void select_reply1(driver_e, minor, status) -endpoint_t driver_e; -int minor; -int status; -{ -/* Handle reply to DEV_SELECT request */ - - int major; - dev_t dev; - struct filp *f; - struct dmap *dp; - struct vnode *vp; - - /* Figure out which device is replying */ - if ((dp = get_dmap(driver_e)) == NULL) return; - - major = dp-dmap; - dev = makedev(major, minor); - - /* Get filp belonging to character special file */ - if ((f = dp->dmap_sel_filp) == NULL) { - printf("VFS (%s:%d): major %d was not expecting a DEV_SELECT reply\n", - __FILE__, __LINE__, major); - return; - } - - /* Is the filp still in use and busy waiting for a reply? The owner might - * have vanished before the driver was able to reply. */ - if (f->filp_count >= 1 && (f->filp_select_flags & FSF_BUSY)) { - /* Find vnode and check we got a reply from the device we expected */ - vp = f->filp_vno; - assert(vp != NULL); - assert((vp->v_mode & I_TYPE) == I_CHAR_SPECIAL); /* Must be char. special */ - if (vp->v_sdev != dev) { - printf("VFS (%s:%d): expected reply from dev %d not %d\n", - __FILE__, __LINE__, vp->v_sdev, dev); - return; - } - } - - /* No longer waiting for a reply from this device */ - dp->dmap_sel_filp = NULL; - - /* Process select result only if requestor is still around. That is, the - * corresponding filp is still in use. - */ - if (f->filp_count >= 1) { - select_lock_filp(f, f->filp_select_ops); - f->filp_select_flags &= ~FSF_BUSY; - - /* The select call is done now, except when - * - another process started a select on the same filp with possibly a - * different set of operations. - * - a process does a select on the same filp but using different file - * descriptors. - * - the select has a timeout. Upon receiving this reply the operations - * might not be ready yet, so we want to wait for that to ultimately - * happen. - * Therefore we need to keep remembering what the operations are. - */ - if (!(f->filp_select_flags & (FSF_UPDATE|FSF_BLOCKED))) - f->filp_select_ops = 0; /* done selecting */ - else if (!(f->filp_select_flags & FSF_UPDATE)) - /* there may be operations pending */ - f->filp_select_ops &= ~status; - - /* Tell filp owners about result unless we need to wait longer */ - if (!(status == 0 && (f->filp_select_flags & FSF_BLOCKED))) { - if (status > 0) { /* operations ready */ - if (status & SEL_RD) - f->filp_select_flags &= ~FSF_RD_BLOCK; - if (status & SEL_WR) - f->filp_select_flags &= ~FSF_WR_BLOCK; - if (status & SEL_ERR) - f->filp_select_flags &= ~FSF_ERR_BLOCK; - } else if (status < 0) { /* error */ - /* Always unblock upon error */ - f->filp_select_flags &= ~FSF_BLOCKED; - } - - unlock_filp(f); - filp_status(f, status); /* Tell filp owners about the results */ - } else { - unlock_filp(f); - } - } - - select_restart_filps(); -} - - -/*===========================================================================* - * select_reply2 * - *===========================================================================*/ -PUBLIC void select_reply2(driver_e, minor, status) -endpoint_t driver_e; -int minor; -int status; -{ -/* Handle secondary reply to DEV_SELECT request. A secondary reply occurs when - * the select request is 'blocking' until an operation becomes ready. */ - int major, slot, fd; - dev_t dev; - struct filp *f; - struct dmap *dp; - struct vnode *vp; - struct selectentry *se; - - if (status == 0) { - printf("VFS (%s:%d): weird status (%d) to report\n", - __FILE__, __LINE__, status); - return; - } - - /* Figure out which device is replying */ - if ((dp = get_dmap(driver_e)) == NULL) { - printf("VFS (%s:%d): endpoint %d is not a known driver endpoint\n", - __FILE__, __LINE__, driver_e); - return; - } - major = dp-dmap; - dev = makedev(major, minor); - - /* Find all file descriptors selecting for this device */ - for (slot = 0; slot < MAXSELECTS; slot++) { - se = &selecttab[slot]; - if (se->requestor == NULL) continue; /* empty slot */ - - for (fd = 0; fd < se->nfds; fd++) { - if ((f = se->filps[fd]) == NULL) continue; - if ((vp = f->filp_vno) == NULL) continue; - if ((vp->v_mode & I_TYPE) != I_CHAR_SPECIAL) continue; - if (vp->v_sdev != dev) continue; - - select_lock_filp(f, f->filp_select_ops); - if (status > 0) { /* Operations ready */ - /* Clear the replied bits from the request - * mask unless FSF_UPDATE is set. - */ - if (!(f->filp_select_flags & FSF_UPDATE)) - f->filp_select_ops &= ~status; - if (status & SEL_RD) - f->filp_select_flags &= ~FSF_RD_BLOCK; - if (status & SEL_WR) - f->filp_select_flags &= ~FSF_WR_BLOCK; - if (status & SEL_ERR) - f->filp_select_flags &= ~FSF_ERR_BLOCK; - - ops2tab(status, fd, se); - } else { - f->filp_select_flags &= ~FSF_BLOCKED; - ops2tab(SEL_RD|SEL_WR|SEL_ERR, fd, se); - } - unlock_filp(f); - if (se->nreadyfds > 0) restart_proc(se); - } - } - - select_restart_filps(); -} - -/*===========================================================================* - * select_restart_filps * - *===========================================================================*/ -PRIVATE void select_restart_filps() -{ - int fd, slot; - struct filp *f; - struct vnode *vp; - struct selectentry *se; - - /* Locate filps that can be restarted */ - for (slot = 0; slot < MAXSELECTS; slot++) { - se = &selecttab[slot]; - if (se->requestor == NULL) continue; /* empty slot */ - - /* Only 'deferred' processes are eligible to restart */ - if (!is_deferred(se)) continue; - - /* Find filps that are not waiting for a reply, but have an updated - * status (i.e., another select on the same filp with possibly a - * different set of operations is to be done), and thus requires the - * select request to be sent again). - */ - for (fd = 0; fd < se->nfds; fd++) { - int r, wantops, ops; - if ((f = se->filps[fd]) == NULL) continue; - if (f->filp_select_flags & FSF_BUSY) /* Still waiting for */ - continue; /* initial reply */ - if (!(f->filp_select_flags & FSF_UPDATE)) /* Must be in */ - continue; /* 'update' state */ - - wantops = ops = f->filp_select_ops; - select_lock_filp(f, ops); - vp = f->filp_vno; - assert((vp->v_mode & I_TYPE) == I_CHAR_SPECIAL); - r = do_select_request(se, fd, &wantops); - unlock_filp(f); - if (r != SEL_OK) { - if (r == SEL_DEFERRED) continue; - else break; /* Error or bogus return code; abort */ - } - if (wantops & ops) ops2tab(wantops, fd, se); - } - } -} - -/*===========================================================================* - * do_select_request * - *===========================================================================*/ -PRIVATE int do_select_request(se, fd, ops) -struct selectentry *se; -int fd; -int *ops; -{ -/* Perform actual select request for file descriptor fd */ - - int r, type; - struct filp *f; - - type = se->type[fd]; - f = se->filps[fd]; - r = fdtypes[type].select_request(f, ops, se->block); - if (r != SEL_OK && r != SEL_DEFERRED) { - se->error = EINTR; - se->block = 0; /* Stop blocking to return asap */ - if (!is_deferred(se)) select_cancel_all(se); - } - - return(r); -} - -/*===========================================================================* - * filp_status * - *===========================================================================*/ -PRIVATE void filp_status(f, status) -struct filp *f; -int status; -{ -/* Tell processes that need to know about the status of this filp */ - int fd, slot; - struct selectentry *se; - - for (slot = 0; slot < MAXSELECTS; slot++) { - se = &selecttab[slot]; - if (se->requestor == NULL) continue; /* empty slot */ - - for (fd = 0; fd < se->nfds; fd++) { - if (se->filps[fd] != f) continue; - if (status < 0) - ops2tab(SEL_RD|SEL_WR|SEL_ERR, fd, se); - else - ops2tab(status, fd, se); - restart_proc(se); - } - } -} - -/*===========================================================================* - * restart_proc * - *===========================================================================*/ -PRIVATE void restart_proc(se) -struct selectentry *se; -{ -/* Tell process about select results (if any) unless there are still results - * pending. */ - - if ((se->nreadyfds > 0 || !se->block) && !is_deferred(se)) - select_return(se); -} - -/*===========================================================================* - * wipe_select * - *===========================================================================*/ -PRIVATE void wipe_select(struct selectentry *se) -{ - se->nfds = 0; - se->nreadyfds = 0; - se->error = OK; - se->block = 0; - memset(se->filps, 0, sizeof(se->filps)); - - FD_ZERO(&se->readfds); - FD_ZERO(&se->writefds); - FD_ZERO(&se->errorfds); - FD_ZERO(&se->ready_readfds); - FD_ZERO(&se->ready_writefds); - FD_ZERO(&se->ready_errorfds); -} - -/*===========================================================================* - * select_lock_filp * - *===========================================================================*/ -PRIVATE void select_lock_filp(struct filp *f, int ops) -{ -/* Lock a filp and vnode based on which operations are requested */ - tll_access_t locktype;; - - locktype = VNODE_READ; /* By default */ - - if (ops & (SEL_WR|SEL_ERR)) - /* Selecting for error or writing requires exclusive access */ - locktype = VNODE_WRITE; - - lock_filp(f, locktype); -} diff --git a/servers/avfs/select.h b/servers/avfs/select.h deleted file mode 100644 index 5215b1a90..000000000 --- a/servers/avfs/select.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __VFS_SELECT_H__ -#define __VFS_SELECT_H__ - -/* return codes for select_request_* and select_cancel_* */ -#define SEL_OK 0 /* ready */ -#define SEL_ERROR 1 /* failed */ -#define SEL_DEFERRED 2 /* request is sent to driver */ - -#endif diff --git a/servers/avfs/stadir.c b/servers/avfs/stadir.c deleted file mode 100644 index bc49bf9c4..000000000 --- a/servers/avfs/stadir.c +++ /dev/null @@ -1,287 +0,0 @@ -/* This file contains the code for performing four system calls relating to - * status and directories. - * - * The entry points into this file are - * do_chdir: perform the CHDIR system call - * do_chroot: perform the CHROOT system call - * do_lstat: perform the LSTAT system call - * do_stat: perform the STAT system call - * do_fstat: perform the FSTAT system call - * do_fstatfs: perform the FSTATFS system call - * do_statvfs: perform the STATVFS system call - * do_fstatvfs: perform the FSTATVFS system call - */ - -#include "fs.h" -#include -#include -#include -#include -#include -#include "file.h" -#include "fproc.h" -#include "path.h" -#include "param.h" -#include -#include -#include "vnode.h" -#include "vmnt.h" - -FORWARD _PROTOTYPE( int change, (struct vnode **iip, char *name_ptr, int len)); -FORWARD _PROTOTYPE( int change_into, (struct vnode **iip, struct vnode *vp)); - -/*===========================================================================* - * do_fchdir * - *===========================================================================*/ -PUBLIC int do_fchdir() -{ - /* Change directory on already-opened fd. */ - struct filp *rfilp; - int r; - - /* Is the file descriptor valid? */ - if ((rfilp = get_filp(m_in.fd, VNODE_READ)) == NULL) return(err_code); - r = change_into(&fp->fp_wd, rfilp->filp_vno); - unlock_filp(rfilp); - return(r); -} - -/*===========================================================================* - * do_chdir * - *===========================================================================*/ -PUBLIC int do_chdir() -{ -/* Perform the chdir(name) system call. */ - - return change(&fp->fp_wd, m_in.name, m_in.name_length); -} - -/*===========================================================================* - * do_chroot * - *===========================================================================*/ -PUBLIC int do_chroot() -{ -/* Perform the chroot(name) system call. */ - - if (!super_user) return(EPERM); /* only su may chroot() */ - return change(&fp->fp_rd, m_in.name, m_in.name_length); -} - -/*===========================================================================* - * change * - *===========================================================================*/ -PRIVATE int change(iip, name_ptr, len) -struct vnode **iip; /* pointer to the inode pointer for the dir */ -char *name_ptr; /* pointer to the directory name to change to */ -int len; /* length of the directory name string */ -{ -/* Do the actual work for chdir() and chroot(). */ - struct vnode *vp; - struct vmnt *vmp; - char fullpath[PATH_MAX]; - struct lookup resolve; - int r; - - lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); - resolve.l_vmnt_lock = VMNT_READ; - resolve.l_vnode_lock = VNODE_READ; - - /* Try to open the directory */ - if (fetch_name(name_ptr, len, M3, fullpath) != OK) return(err_code); - if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); - r = change_into(iip, vp); - unlock_vnode(vp); - unlock_vmnt(vmp); - put_vnode(vp); - return(r); -} - -/*===========================================================================* - * change_into * - *===========================================================================*/ -PRIVATE int change_into(iip, vp) -struct vnode **iip; /* pointer to the inode pointer for the dir */ -struct vnode *vp; /* this is what the inode has to become */ -{ - int r; - - if (*iip == vp) return(OK); /* Nothing to do */ - - /* It must be a directory and also be searchable */ - if ((vp->v_mode & I_TYPE) != I_DIRECTORY) - r = ENOTDIR; - else - r = forbidden(fp, vp, X_BIT); /* Check if dir is searchable*/ - if (r != OK) return(r); - - /* Everything is OK. Make the change. */ - put_vnode(*iip); /* release the old directory */ - dup_vnode(vp); - *iip = vp; /* acquire the new one */ - return(OK); -} - -/*===========================================================================* - * do_stat * - *===========================================================================*/ -PUBLIC int do_stat() -{ -/* Perform the stat(name, buf) system call. */ - int r; - struct vnode *vp; - struct vmnt *vmp; - char fullpath[PATH_MAX]; - struct lookup resolve; - int old_stat = 0; - - lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); - resolve.l_vmnt_lock = VMNT_READ; - resolve.l_vnode_lock = VNODE_READ; - - if (call_nr == PREV_STAT) - old_stat = 1; - - if (fetch_name(m_in.name1, m_in.name1_length, M1, fullpath) != OK) - return(err_code); - if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); - r = req_stat(vp->v_fs_e, vp->v_inode_nr, who_e, m_in.name2, 0, old_stat); - - unlock_vnode(vp); - unlock_vmnt(vmp); - - put_vnode(vp); - return r; -} - -/*===========================================================================* - * do_fstat * - *===========================================================================*/ -PUBLIC int do_fstat() -{ -/* Perform the fstat(fd, buf) system call. */ - register struct filp *rfilp; - int r; - int pipe_pos = 0; - int old_stat = 0; - - if (call_nr == PREV_FSTAT) - old_stat = 1; - - /* Is the file descriptor valid? */ - if ((rfilp = get_filp(m_in.fd, VNODE_READ)) == NULL) return(err_code); - - /* If we read from a pipe, send position too */ - if (rfilp->filp_vno->v_pipe == I_PIPE) { - if (rfilp->filp_mode & R_BIT) - if (ex64hi(rfilp->filp_pos) != 0) { - panic("do_fstat: bad position in pipe"); - } - pipe_pos = ex64lo(rfilp->filp_pos); - } - - r = req_stat(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr, - who_e, m_in.buffer, pipe_pos, old_stat); - - unlock_filp(rfilp); - - return(r); -} - -/*===========================================================================* - * do_fstatfs * - *===========================================================================*/ -PUBLIC int do_fstatfs() -{ -/* Perform the fstatfs(fd, buf) system call. */ - struct filp *rfilp; - int r; - - /* Is the file descriptor valid? */ - if( (rfilp = get_filp(m_in.fd, VNODE_READ)) == NULL) return(err_code); - - r = req_fstatfs(rfilp->filp_vno->v_fs_e, who_e, m_in.buffer); - - unlock_filp(rfilp); - - return(r); -} - -/*===========================================================================* - * do_statvfs * - *===========================================================================*/ -PUBLIC int do_statvfs() -{ -/* Perform the stat(name, buf) system call. */ - int r; - struct vnode *vp; - struct vmnt *vmp; - char fullpath[PATH_MAX]; - struct lookup resolve; - - lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); - resolve.l_vmnt_lock = VMNT_READ; - resolve.l_vnode_lock = VNODE_READ; - - if (fetch_name(m_in.STATVFS_NAME, m_in.STATVFS_LEN, M1, fullpath) != OK) - return(err_code); - if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); - r = req_statvfs(vp->v_fs_e, who_e, m_in.STATVFS_BUF); - - unlock_vnode(vp); - unlock_vmnt(vmp); - - put_vnode(vp); - return r; -} - -/*===========================================================================* - * do_fstatvfs * - *===========================================================================*/ -PUBLIC int do_fstatvfs() -{ -/* Perform the fstat(fd, buf) system call. */ - register struct filp *rfilp; - int r; - - /* Is the file descriptor valid? */ - if ((rfilp = get_filp(m_in.FSTATVFS_FD, VNODE_READ)) == NULL) - return(err_code); - - r = req_statvfs(rfilp->filp_vno->v_fs_e, who_e, m_in.FSTATVFS_BUF); - - unlock_filp(rfilp); - - return(r); -} - -/*===========================================================================* - * do_lstat * - *===========================================================================*/ -PUBLIC int do_lstat() -{ -/* Perform the lstat(name, buf) system call. */ - struct vnode *vp; - struct vmnt *vmp; - int r; - char fullpath[PATH_MAX]; - struct lookup resolve; - int old_stat = 0; - - lookup_init(&resolve, fullpath, PATH_RET_SYMLINK, &vmp, &vp); - resolve.l_vmnt_lock = VMNT_READ; - resolve.l_vnode_lock = VNODE_READ; - - if (call_nr == PREV_LSTAT) - old_stat = 1; - if (fetch_name(m_in.name1, m_in.name1_length, M1, fullpath) != OK) - return(err_code); - - if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); - r = req_stat(vp->v_fs_e, vp->v_inode_nr, who_e, m_in.name2, 0, old_stat); - - unlock_vnode(vp); - unlock_vmnt(vmp); - - put_vnode(vp); - return(r); -} diff --git a/servers/avfs/table.c b/servers/avfs/table.c deleted file mode 100644 index 4429e3192..000000000 --- a/servers/avfs/table.c +++ /dev/null @@ -1,145 +0,0 @@ -/* This file contains the table used to map system call numbers onto the - * routines that perform them. - */ - -#define _TABLE - -#include "fs.h" -#include -#include -#include "file.h" -#include "fproc.h" -#include "lock.h" -#include "scratchpad.h" -#include "vnode.h" -#include "vmnt.h" - -PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = { - no_sys, /* 0 = unused */ - no_sys, /* 1 = (exit) */ - no_sys, /* 2 = (fork) */ - do_read, /* 3 = read */ - do_write, /* 4 = write */ - do_open, /* 5 = open */ - do_close, /* 6 = close */ - no_sys, /* 7 = wait */ - do_creat, /* 8 = creat */ - do_link, /* 9 = link */ - do_unlink, /* 10 = unlink */ - no_sys, /* 11 = waitpid */ - do_chdir, /* 12 = chdir */ - no_sys, /* 13 = time */ - do_mknod, /* 14 = mknod */ - do_chmod, /* 15 = chmod */ - do_chown, /* 16 = chown */ - no_sys, /* 17 = break */ - do_stat, /* 18 = stat (prev)*/ - do_lseek, /* 19 = lseek */ - no_sys, /* 20 = getpid */ - do_mount, /* 21 = mount */ - do_umount, /* 22 = umount */ - no_sys, /* 23 = (setuid) */ - no_sys, /* 24 = getuid */ - no_sys, /* 25 = (stime) */ - no_sys, /* 26 = ptrace */ - no_sys, /* 27 = alarm */ - do_fstat, /* 28 = fstat (prev)*/ - no_sys, /* 29 = pause */ - do_utime, /* 30 = utime */ - no_sys, /* 31 = (stty) */ - no_sys, /* 32 = (gtty) */ - do_access, /* 33 = access */ - no_sys, /* 34 = (nice) */ - no_sys, /* 35 = (ftime) */ - do_sync, /* 36 = sync */ - no_sys, /* 37 = kill */ - do_rename, /* 38 = rename */ - do_mkdir, /* 39 = mkdir */ - do_unlink, /* 40 = rmdir */ - do_dup, /* 41 = dup */ - do_pipe, /* 42 = pipe */ - no_sys, /* 43 = times */ - no_sys, /* 44 = (prof) */ - do_slink, /* 45 = symlink */ - no_sys, /* 46 = (setgid)*/ - no_sys, /* 47 = getgid */ - no_sys, /* 48 = (signal)*/ - do_rdlink, /* 49 = readlink*/ - do_lstat, /* 50 = lstat (prev)*/ - do_stat, /* 51 = stat */ - do_fstat, /* 52 = fstat */ - do_lstat, /* 53 = lstat */ - do_ioctl, /* 54 = ioctl */ - do_fcntl, /* 55 = fcntl */ - no_sys, /* 56 = (mpx) */ - do_fsready, /* 57 = FS proc ready */ - no_sys, /* 58 = unused */ - no_sys, /* 59 = (execve)*/ - do_umask, /* 60 = umask */ - do_chroot, /* 61 = chroot */ - no_sys, /* 62 = (setsid)*/ - no_sys, /* 63 = (getpgrp)*/ - no_sys, /* 64 = (itimer)*/ - do_stat, /* 65 = stat - badly numbered, being phased out */ - do_fstat, /* 66 = fstat - badly numbered, being phased out */ - do_lstat, /* 67 = lstat - badly numbered, being phased out */ - no_sys, /* 68 = unused */ - no_sys, /* 69 = unused */ - no_sys, /* 70 = unused */ - no_sys, /* 71 = (sigaction) */ - no_sys, /* 72 = (sigsuspend) */ - no_sys, /* 73 = (sigpending) */ - no_sys, /* 74 = (sigprocmask) */ - no_sys, /* 75 = (sigreturn) */ - no_sys, /* 76 = (reboot) */ - do_svrctl, /* 77 = svrctl */ - no_sys, /* 78 = (sysuname) */ - no_sys, /* 79 = unused */ - do_getdents, /* 80 = getdents */ - do_llseek, /* 81 = llseek */ - do_fstatfs, /* 82 = fstatfs */ - do_statvfs, /* 83 = fstatvfs */ - do_fstatvfs, /* 84 = statvfs */ - do_select, /* 85 = select */ - do_fchdir, /* 86 = fchdir */ - do_fsync, /* 87 = fsync */ - no_sys, /* 88 = (getpriority) */ - no_sys, /* 89 = (setpriority) */ - no_sys, /* 90 = (gettimeofday) */ - no_sys, /* 91 = (seteuid) */ - no_sys, /* 92 = (setegid) */ - do_truncate, /* 93 = truncate */ - do_ftruncate, /* 94 = truncate */ - do_chmod, /* 95 = fchmod */ - do_chown, /* 96 = fchown */ - no_sys, /* 97 = unused */ - no_sys, /* 98 = (sprofile) */ - no_sys, /* 99 = (cprofile) */ - no_sys, /* 100 = (exec_newmem) */ - no_sys, /* 101 = (srv_fork) */ - no_sys, /* 102 = (exec_restart) */ - no_sys, /* 103 = unused */ - no_sys, /* 104 = (getprocnr) */ - no_sys, /* 105 = unused */ - no_sys, /* 106 = unused */ - no_sys, /* 107 = (getepinfo) */ - no_sys, /* 108 = unused */ - no_sys, /* 109 = unused */ - no_sys, /* 110 = unused */ - no_sys, /* 111 = (srv_kill) */ - do_gcov_flush, /* 112 = gcov_flush */ - no_sys, /* 113 = (getsid) */ -}; -/* This should not fail with "array size is negative": */ -extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1]; - -PUBLIC _PROTOTYPE (int (*pfs_call_vec[]), (void) ) = { - - no_sys, /* 0 */ - do_check_perms, /* 1 */ - do_verify_fd, /* 2 */ - do_set_filp, /* 3 */ - do_copy_filp, /* 4 */ - do_put_filp, /* 5 */ - do_cancel_fd /* 6 */ -}; diff --git a/servers/avfs/time.c b/servers/avfs/time.c deleted file mode 100644 index 29b84e320..000000000 --- a/servers/avfs/time.c +++ /dev/null @@ -1,66 +0,0 @@ -/* This file takes care of those system calls that deal with time. - * - * The entry points into this file are - * do_utime: perform the UTIME system call - */ - -#include "fs.h" -#include -#include -#include "file.h" -#include "fproc.h" -#include "path.h" -#include "param.h" -#include "vnode.h" -#include -#include "vmnt.h" - -/*===========================================================================* - * do_utime * - *===========================================================================*/ -PUBLIC int do_utime() -{ -/* Perform the utime(name, timep) system call. */ - register int len; - int r; - time_t actime, modtime; - struct vnode *vp; - struct vmnt *vmp; - char fullpath[PATH_MAX]; - struct lookup resolve; - - lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); - resolve.l_vmnt_lock = VMNT_WRITE; - resolve.l_vnode_lock = VNODE_READ; - - /* Adjust for case of 'timep' being NULL; - * utime_strlen then holds the actual size: strlen(name)+1 */ - len = m_in.utime_length; - if (len == 0) len = m_in.utime_strlen; - - /* Temporarily open the file */ - if (fetch_name(m_in.utime_file, len, M1, fullpath) != OK) return(err_code); - if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); - - /* Only the owner of a file or the super user can change its name. */ - r = OK; - if (vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID) r = EPERM; - if (m_in.utime_length == 0 && r != OK) r = forbidden(fp, vp, W_BIT); - if (read_only(vp) != OK) r = EROFS; /* Not even su can touch if R/O */ - if (r == OK) { - /* Issue request */ - if(m_in.utime_length == 0) { - actime = modtime = clock_time(); - } else { - actime = m_in.utime_actime; - modtime = m_in.utime_modtime; - } - r = req_utime(vp->v_fs_e, vp->v_inode_nr, actime, modtime); - } - - unlock_vnode(vp); - unlock_vmnt(vmp); - - put_vnode(vp); - return(r); -} diff --git a/servers/avfs/utility.c b/servers/avfs/utility.c deleted file mode 100644 index 71922d84a..000000000 --- a/servers/avfs/utility.c +++ /dev/null @@ -1,153 +0,0 @@ -/* This file contains a few general purpose utility routines. - * - * The entry points into this file are - * clock_time: ask the clock task for the real time - * copy: copy a block of data - * fetch_name: go get a path name from user space - * no_sys: reject a system call that FS does not handle - * panic: something awful has occurred; MINIX cannot continue - * conv2: do byte swapping on a 16-bit int - * conv4: do byte swapping on a 32-bit long - * in_group: determines if group 'grp' is in rfp->fp_sgroups[] - */ - -#include "fs.h" -#include -#include -#include -#include -#include -#include "file.h" -#include "fproc.h" -#include "param.h" -#include "vmnt.h" - -/*===========================================================================* - * fetch_name * - *===========================================================================*/ -PUBLIC int fetch_name(path, len, flag, dest) -char *path; /* pointer to the path in user space */ -int len; /* path length, including 0 byte */ -int flag; /* M3 means path may be in message */ -char *dest; /* pointer to where path is to be stored */ -{ -/* Go get path and put it in 'user_fullpath'. - * If 'flag' = M3 and 'len' <= M3_STRING, the path is present in 'message'. - * If it is not, go copy it from user space. - */ - register char *rpu, *rpm; - int r, count; - - if (len > PATH_MAX) { /* 'len' includes terminating-nul */ - err_code = ENAMETOOLONG; - return(EGENERIC); - } - - /* Check name length for validity. */ - if (len <= 0) { - err_code = EINVAL; - return(EGENERIC); - } - - if (flag == M3 && len <= M3_STRING) { - /* Just copy the path from the message to 'user_fullpath'. */ - rpu = &dest[0]; - rpm = m_in.pathname; /* contained in input message */ - count = len; - do { *rpu++ = *rpm++; } while (--count); - r = OK; - } else { - /* String is not contained in the message. Get it from user space. */ - r = sys_datacopy(who_e, (vir_bytes) path, - VFS_PROC_NR, (vir_bytes) dest, (phys_bytes) len); - } - - if (dest[len - 1] != '\0') { - err_code = ENAMETOOLONG; - return(EGENERIC); - } - - return(r); -} - - -/*===========================================================================* - * no_sys * - *===========================================================================*/ -PUBLIC int no_sys() -{ -/* Somebody has used an illegal system call number */ - return(ENOSYS); -} - - -/*===========================================================================* - * isokendpt_f * - *===========================================================================*/ -PUBLIC int isokendpt_f(char *file, int line, endpoint_t endpoint, int *proc, int fatal) -{ - int failed = 0; - endpoint_t ke; - *proc = _ENDPOINT_P(endpoint); - if (endpoint == NONE) { - printf("VFS %s:%d: endpoint is NONE\n", file, line); - failed = 1; - } else if (*proc < 0 || *proc >= NR_PROCS) { - printf("VFS %s:%d: proc (%d) from endpoint (%d) out of range\n", - file, line, *proc, endpoint); - failed = 1; - } else if ((ke = fproc[*proc].fp_endpoint) != endpoint) { - if(ke == NONE) { - printf("VFS %s:%d: endpoint (%d) points to NONE slot (%d)\n", - file, line, endpoint, *proc); - assert(fproc[*proc].fp_pid == PID_FREE); - } else { - printf("VFS %s:%d: proc (%d) from endpoint (%d) doesn't match " - "known endpoint (%d)\n", file, line, *proc, endpoint, - fproc[*proc].fp_endpoint); - assert(fproc[*proc].fp_pid != PID_FREE); - } - failed = 1; - } - - if(failed && fatal) - panic("isokendpt_f failed"); - - return(failed ? EDEADEPT : OK); -} - - -/*===========================================================================* - * clock_time * - *===========================================================================*/ -PUBLIC time_t clock_time() -{ -/* This routine returns the time in seconds since 1.1.1970. MINIX is an - * astrophysically naive system that assumes the earth rotates at a constant - * rate and that such things as leap seconds do not exist. - */ - - register int r; - clock_t uptime; - time_t boottime; - - r = getuptime2(&uptime, &boottime); - if (r != OK) - panic("clock_time err: %d", r); - - return( (time_t) (boottime + (uptime/system_hz))); -} - -/*===========================================================================* - * in_group * - *===========================================================================*/ -PUBLIC int in_group(struct fproc *rfp, gid_t grp) -{ - int i; - - for (i = 0; i < rfp->fp_ngroups; i++) - if (rfp->fp_sgroups[i] == grp) - return(OK); - - return(EINVAL); -} diff --git a/servers/avfs/vmnt.c b/servers/avfs/vmnt.c deleted file mode 100644 index bb3dc0746..000000000 --- a/servers/avfs/vmnt.c +++ /dev/null @@ -1,201 +0,0 @@ -/* Virtual mount table related routines. - * - */ - -#include "fs.h" -#include "threads.h" -#include "vmnt.h" -#include -#include "fproc.h" - -FORWARD _PROTOTYPE( int is_vmnt_locked, (struct vmnt *vmp) ); -FORWARD _PROTOTYPE( void clear_vmnt, (struct vmnt *vmp) ); - -/* Is vmp pointer reasonable? */ -#define SANEVMP(v) ((((v) >= &vmnt[0] && (v) < &vmnt[NR_MNTS]))) -#define BADVMP(v, f, l) printf("%s:%d: bad vmp %p\n", f, l, v) -/* vp check that panics */ -#define ASSERTVMP(v) if(!SANEVMP(v)) { \ - BADVMP(v, __FILE__, __LINE__); panic("bad vmp"); } - -#if LOCK_DEBUG -/*===========================================================================* - * check_vmnt_locks_by_me * - *===========================================================================*/ -PUBLIC void check_vmnt_locks_by_me(struct fproc *rfp) -{ -/* Check whether this thread still has locks held on vmnts */ - struct vmnt *vmp; - - for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) { - if (tll_locked_by_me(&vmp->m_lock)) - panic("Thread %d still holds vmnt lock on vmp %p call_nr=%d\n", - mthread_self(), vmp, call_nr); - } - - if (rfp->fp_vmnt_rdlocks != 0) - panic("Thread %d still holds read locks on a vmnt (%d) call_nr=%d\n", - mthread_self(), rfp->fp_vmnt_rdlocks, call_nr); -} -#endif - -/*===========================================================================* - * check_vmnt_locks * - *===========================================================================*/ -PUBLIC void check_vmnt_locks() -{ - struct vmnt *vmp; - int count = 0; - - for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) - if (is_vmnt_locked(vmp)) { - count++; - printf("vmnt %p is %s, fs_e=%d dev=%d\n", vmp, (tll_islocked(&vmp->m_lock) ? "locked":"pending locked"), vmp->m_fs_e, vmp->m_dev); - } - - if (count) panic("%d locked vmnts\n", count); -#if 0 - printf("check_vmnt_locks OK\n"); -#endif -} - -/*===========================================================================* - * clear_vmnt * - *===========================================================================*/ -PRIVATE void clear_vmnt(struct vmnt *vmp) -{ -/* Reset vmp to initial parameters */ - ASSERTVMP(vmp); - - vmp->m_fs_e = NONE; - vmp->m_dev = NO_DEV; - vmp->m_flags = 0; - vmp->m_mounted_on = NULL; - vmp->m_root_node = NULL; - vmp->m_label[0] = '\0'; - vmp->m_comm.c_max_reqs = 1; - vmp->m_comm.c_cur_reqs = 0; - vmp->m_comm.c_req_queue = NULL; -} - -/*===========================================================================* - * get_free_vmnt * - *===========================================================================*/ -PUBLIC struct vmnt *get_free_vmnt(void) -{ - struct vmnt *vp; - - for (vp = &vmnt[0]; vp < &vmnt[NR_MNTS]; ++vp) - if (vp->m_dev == NO_DEV) return(vp); - - return(NULL); -} - -/*===========================================================================* - * find_vmnt * - *===========================================================================*/ -PUBLIC struct vmnt *find_vmnt(endpoint_t fs_e) -{ -/* Find the vmnt belonging to an FS with endpoint 'fs_e' iff it's in use */ - struct vmnt *vp; - - for (vp = &vmnt[0]; vp < &vmnt[NR_MNTS]; ++vp) - if (vp->m_fs_e == fs_e && vp->m_dev != NO_DEV) - return(vp); - - return(NULL); -} - -/*===========================================================================* - * init_vmnts * - *===========================================================================*/ -PUBLIC void init_vmnts(void) -{ -/* Initialize vmnt table */ - struct vmnt *vmp; - - for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) { - clear_vmnt(vmp); - tll_init(&vmp->m_lock); - } -} - -/*===========================================================================* - * is_vmnt_locked * - *===========================================================================*/ -PRIVATE int is_vmnt_locked(struct vmnt *vmp) -{ - ASSERTVMP(vmp); - return(tll_islocked(&vmp->m_lock) || tll_haspendinglock(&vmp->m_lock)); -} - -/*===========================================================================* - * lock_vmnt * - *===========================================================================*/ -PUBLIC int lock_vmnt(struct vmnt *vmp, tll_access_t locktype) -{ - int r; - tll_access_t initial_locktype; - - ASSERTVMP(vmp); - - initial_locktype = (locktype == VMNT_EXCL) ? VMNT_WRITE : locktype; - - if (vmp->m_fs_e == who_e) return(EDEADLK); - - r = tll_lock(&vmp->m_lock, initial_locktype); - - if (r == EBUSY) return(r); - - if (initial_locktype != locktype) { - tll_upgrade(&vmp->m_lock); - } - -#if LOCK_DEBUG - if (locktype == VMNT_READ) - fp->fp_vmnt_rdlocks++; -#endif - - return(OK); -} - -/*===========================================================================* - * vmnt_unmap_by_endpoint * - *===========================================================================*/ -PUBLIC void vmnt_unmap_by_endpt(endpoint_t proc_e) -{ - struct vmnt *vmp; - - if ((vmp = find_vmnt(proc_e)) != NULL) { - fs_cancel(vmp); - invalidate_filp_by_endpt(proc_e); - if (vmp->m_mounted_on) { - /* Only put mount point when it was actually used as mount - * point. That is, the mount was succesful. */ - put_vnode(vmp->m_mounted_on); - } - clear_vmnt(vmp); - } -} - -/*===========================================================================* - * unlock_vmnt * - *===========================================================================*/ -PUBLIC void unlock_vmnt(struct vmnt *vmp) -{ - ASSERTVMP(vmp); - -#if LOCK_DEBUG - /* Decrease read-only lock counter when not locked as VMNT_WRITE or - * VMNT_EXCL */ - if (!tll_locked_by_me(&vmp->m_lock)) - fp->fp_vmnt_rdlocks--; -#endif - - tll_unlock(&vmp->m_lock); - -#if LOCK_DEBUG - assert(!tll_locked_by_me(&vmp->m_lock)); -#endif - -} diff --git a/servers/avfs/vmnt.h b/servers/avfs/vmnt.h deleted file mode 100644 index 14d00b3ab..000000000 --- a/servers/avfs/vmnt.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef __VFS_VMNT_H__ -#define __VFS_VMNT_H__ - -EXTERN struct vmnt { - int m_fs_e; /* FS process' kernel endpoint */ - tll_t m_lock; - comm_t m_comm; - dev_t m_dev; /* device number */ - unsigned int m_flags; /* mount flags */ - struct vnode *m_mounted_on; /* vnode on which the partition is mounted */ - struct vnode *m_root_node; /* root vnode */ - char m_label[LABEL_MAX]; /* label of the file system process */ -} vmnt[NR_MNTS]; - -/* vmnt flags */ -#define VMNT_READONLY 01 /* Device mounted readonly */ -#define VMNT_CALLBACK 02 /* FS did back call */ -#define VMNT_MOUNTING 04 /* Device is being mounted */ -#define VMNT_FORCEROOTBSF 010 /* Force usage of none-device */ - -/* vmnt lock types mapping */ -#define VMNT_READ TLL_READ -#define VMNT_WRITE TLL_READSER -#define VMNT_EXCL TLL_WRITE - -#endif diff --git a/servers/avfs/vnode.c b/servers/avfs/vnode.c deleted file mode 100644 index ad854f732..000000000 --- a/servers/avfs/vnode.c +++ /dev/null @@ -1,389 +0,0 @@ -/* This file contains the routines related to vnodes. - * The entry points are: - * - * get_vnode - increase counter and get details of an inode - * get_free_vnode - get a pointer to a free vnode obj - * find_vnode - find a vnode according to the FS endpoint and the inode num. - * dup_vnode - duplicate vnode (i.e. increase counter) - * put_vnode - drop vnode (i.e. decrease counter) - */ - -#include "fs.h" -#include "threads.h" -#include "vnode.h" -#include "vmnt.h" -#include "fproc.h" -#include "file.h" -#include -#include - -/* Is vnode pointer reasonable? */ -#if NDEBUG -#define SANEVP(v) -#define CHECKVN(v) -#define ASSERTVP(v) -#else -#define SANEVP(v) ((((v) >= &vnode[0] && (v) < &vnode[NR_VNODES]))) - -#define BADVP(v, f, l) printf("%s:%d: bad vp %p\n", f, l, v) - -/* vp check that returns 0 for use in check_vrefs() */ -#define CHECKVN(v) if(!SANEVP(v)) { \ - BADVP(v, __FILE__, __LINE__); \ - return 0; \ -} - -/* vp check that panics */ -#define ASSERTVP(v) if(!SANEVP(v)) { \ - BADVP(v, __FILE__, __LINE__); panic("bad vp"); } -#endif - -#if LOCK_DEBUG -/*===========================================================================* - * check_vnode_locks_by_me * - *===========================================================================*/ -PUBLIC void check_vnode_locks_by_me(struct fproc *rfp) -{ -/* Check whether this thread still has locks held on vnodes */ - struct vnode *vp; - - for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; vp++) { - if (tll_locked_by_me(&vp->v_lock)) { - panic("Thread %d still holds vnode lock on vp %x call_nr=%d\n", - mthread_self(), vp, call_nr); - } - } - - if (rfp->fp_vp_rdlocks != 0) - panic("Thread %d still holds read locks on a vnode (%d) call_nr=%d\n", - mthread_self(), rfp->fp_vp_rdlocks, call_nr); -} -#endif - -/*===========================================================================* - * check_vnode_locks * - *===========================================================================*/ -PUBLIC void check_vnode_locks() -{ - struct vnode *vp; - int count = 0; - - for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; vp++) - if (is_vnode_locked(vp)) { - count++; - } - - if (count) panic("%d locked vnodes\n", count); -#if 0 - printf("check_vnode_locks OK\n"); -#endif -} - -/*===========================================================================* - * get_free_vnode * - *===========================================================================*/ -PUBLIC struct vnode *get_free_vnode() -{ -/* Find a free vnode slot in the vnode table (it's not actually allocated) */ - struct vnode *vp; - - for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; ++vp) { - if (vp->v_ref_count == 0 && !is_vnode_locked(vp)) { - vp->v_pipe = NO_PIPE; - vp->v_uid = -1; - vp->v_gid = -1; - vp->v_sdev = NO_DEV; - vp->v_mapfs_e = NONE; - vp->v_mapfs_count = 0; - vp->v_mapinode_nr = 0; - return(vp); - } - } - - err_code = ENFILE; - return(NULL); -} - - -/*===========================================================================* - * find_vnode * - *===========================================================================*/ -PUBLIC struct vnode *find_vnode(int fs_e, int ino) -{ -/* Find a specified (FS endpoint and inode number) vnode in the - * vnode table */ - struct vnode *vp; - - for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; ++vp) - if (vp->v_ref_count > 0 && vp->v_inode_nr == ino && vp->v_fs_e == fs_e) - return(vp); - - return(NULL); -} - -/*===========================================================================* - * is_vnode_locked * - *===========================================================================*/ -PUBLIC int is_vnode_locked(struct vnode *vp) -{ -/* Find out whether a thread holds a lock on this vnode or is trying to obtain - * a lock. */ - ASSERTVP(vp); - - return(tll_islocked(&vp->v_lock) || tll_haspendinglock(&vp->v_lock)); -} - -/*===========================================================================* - * init_vnodes * - *===========================================================================*/ -PUBLIC void init_vnodes(void) -{ - struct vnode *vp; - - for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; ++vp) { - vp->v_fs_e = NONE; - vp->v_mapfs_e = NONE; - vp->v_inode_nr = 0; - vp->v_ref_count = 0; - vp->v_fs_count = 0; - vp->v_mapfs_count = 0; - tll_init(&vp->v_lock); - } -} - -/*===========================================================================* - * lock_vnode * - *===========================================================================*/ -PUBLIC int lock_vnode(struct vnode *vp, tll_access_t locktype) -{ - int r; - - ASSERTVP(vp); - - r = tll_lock(&vp->v_lock, locktype); - -#if LOCK_DEBUG - if (locktype == VNODE_READ) { - fp->fp_vp_rdlocks++; - } -#endif - - if (r == EBUSY) return(r); - return(OK); -} - -/*===========================================================================* - * unlock_vnode * - *===========================================================================*/ -PUBLIC void unlock_vnode(struct vnode *vp) -{ -#if LOCK_DEBUG - int i; - register struct vnode *rvp; - struct worker_thread *w; -#endif - ASSERTVP(vp); - -#if LOCK_DEBUG - /* Decrease read-only lock counter when not locked as VNODE_OPCL or - * VNODE_WRITE */ - if (!tll_locked_by_me(&vp->v_lock)) { - fp->fp_vp_rdlocks--; - } - - for (i = 0; i < NR_VNODES; i++) { - rvp = &vnode[i]; - - w = rvp->v_lock.t_write; - assert(w != self); - while (w && w->w_next != NULL) { - w = w->w_next; - assert(w != self); - } - - w = rvp->v_lock.t_serial; - assert(w != self); - while (w && w->w_next != NULL) { - w = w->w_next; - assert(w != self); - } - } -#endif - - tll_unlock(&vp->v_lock); -} - -/*===========================================================================* - * dup_vnode * - *===========================================================================*/ -PUBLIC void dup_vnode(struct vnode *vp) -{ -/* dup_vnode() is called to increment the vnode and therefore the - * referred inode's counter. - */ - ASSERTVP(vp); - vp->v_ref_count++; -} - - -/*===========================================================================* - * put_vnode * - *===========================================================================*/ -PUBLIC void put_vnode(struct vnode *vp) -{ -/* Decrease vnode's usage counter and decrease inode's usage counter in the - * corresponding FS process. Decreasing the fs_count each time we decrease the - * ref count would lead to poor performance. Instead, only decrease fs_count - * when the ref count hits zero. However, this could lead to fs_count to wrap. - * To prevent this, we drop the counter to 1 when the counter hits 256. - * We maintain fs_count as a sanity check to make sure VFS and the FS are in - * sync. - */ - int r, lock_vp; - - ASSERTVP(vp); - - /* Lock vnode. It's quite possible this thread already has a lock on this - * vnode. That's no problem, because the reference counter will not decrease - * to zero in that case. However, if the counter does decrease to zero *and* - * is already locked, we have a consistency problem somewhere. */ - lock_vp = lock_vnode(vp, VNODE_OPCL); - - if (vp->v_ref_count > 1) { - /* Decrease counter */ - vp->v_ref_count--; - if (vp->v_fs_count > 256) - vnode_clean_refs(vp); - if (lock_vp != EBUSY) unlock_vnode(vp); - return; - } - - /* If we already had a lock, there is a consistency problem */ - assert(lock_vp != EBUSY); - tll_upgrade(&vp->v_lock); /* Make sure nobody else accesses this vnode */ - - /* A vnode that's not in use can't be put back. */ - if (vp->v_ref_count <= 0) - panic("put_vnode failed: bad v_ref_count %d\n", vp->v_ref_count); - - /* fs_count should indicate that the file is in use. */ - if (vp->v_fs_count <= 0) - panic("put_vnode failed: bad v_fs_count %d\n", vp->v_fs_count); - - /* Tell FS we don't need this inode to be open anymore. */ - r = req_putnode(vp->v_fs_e, vp->v_inode_nr, vp->v_fs_count); - - if (r != OK) { - printf("VFS: putnode failed: %d\n", r); - util_stacktrace(); - } - - /* This inode could've been mapped. If so, tell mapped FS to close it as - * well. If mapped onto same FS, this putnode is not needed. */ - if (vp->v_mapfs_e != NONE && vp->v_mapfs_e != vp->v_fs_e) - req_putnode(vp->v_mapfs_e, vp->v_mapinode_nr, vp->v_mapfs_count); - - vp->v_fs_count = 0; - vp->v_ref_count = 0; - vp->v_mapfs_count = 0; - - unlock_vnode(vp); -} - - -/*===========================================================================* - * vnode_clean_refs * - *===========================================================================*/ -PUBLIC void vnode_clean_refs(struct vnode *vp) -{ -/* Tell the underlying FS to drop all reference but one. */ - - if (vp == NULL) return; - if (vp->v_fs_count <= 1) return; /* Nothing to do */ - - /* Drop all references except one */ - req_putnode(vp->v_fs_e, vp->v_inode_nr, vp->v_fs_count - 1); - vp->v_fs_count = 1; -} - - -#define REFVP(v) { vp = (v); CHECKVN(v); vp->v_ref_check++; } - -#if DO_SANITYCHECKS -/*===========================================================================* - * check_vrefs * - *===========================================================================*/ -PUBLIC int check_vrefs() -{ - int i, bad; - int ispipe_flag, ispipe_mode; - struct vnode *vp; - struct vmnt *vmp; - struct fproc *rfp; - struct filp *f; - - /* Clear v_ref_check */ - for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; ++vp) - vp->v_ref_check= 0; - - /* Count reference for processes */ - for (rfp=&fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - if (rfp->fp_pid == PID_FREE) - continue; - if(rfp->fp_rd) REFVP(rfp->fp_rd); - if(rfp->fp_wd) REFVP(rfp->fp_wd); - } - - /* Count references from filedescriptors */ - for (f = &filp[0]; f < &filp[NR_FILPS]; f++) - { - if (f->filp_count == 0) - continue; - REFVP(f->filp_vno); - } - - /* Count references to mount points */ - for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) - { - if (vmp->m_dev == NO_DEV) - continue; - REFVP(vmp->m_root_node); - if(vmp->m_mounted_on) - REFVP(vmp->m_mounted_on); - } - - /* Check references */ - bad= 0; - for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; ++vp) - { - if (vp->v_ref_count != vp->v_ref_check) - { - printf( -"Bad reference count for inode %d on device 0x%x: found %d, listed %d\n", - vp->v_inode_nr, vp->v_dev, vp->v_ref_check, - vp->v_ref_count); - printf("last marked at %s, %d\n", - vp->v_file, vp->v_line); - bad= 1; - } - - /* Also check v_pipe */ - if (vp->v_ref_count != 0) - { - ispipe_flag= (vp->v_pipe == I_PIPE); - ispipe_mode= ((vp->v_mode & I_TYPE) == I_NAMED_PIPE); - if (ispipe_flag != ispipe_mode) - { - printf( -"Bad v_pipe for inode %d on device 0x%x: found %d, mode 0%o\n", - vp->v_inode_nr, vp->v_dev, vp->v_pipe, - vp->v_mode); - printf("last marked at %s, %d\n", - vp->v_file, vp->v_line); - bad= 1; - } - } - } - return !bad; -} -#endif diff --git a/servers/avfs/vnode.h b/servers/avfs/vnode.h deleted file mode 100644 index babb6aab4..000000000 --- a/servers/avfs/vnode.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef __VFS_VNODE_H__ -#define __VFS_VNODE_H__ - -EXTERN struct vnode { - endpoint_t v_fs_e; /* FS process' endpoint number */ - endpoint_t v_mapfs_e; /* mapped FS process' endpoint number */ - ino_t v_inode_nr; /* inode number on its (minor) device */ - ino_t v_mapinode_nr; /* mapped inode number of mapped FS. */ - mode_t v_mode; /* file type, protection, etc. */ - uid_t v_uid; /* uid of inode. */ - gid_t v_gid; /* gid of inode. */ - off_t v_size; /* current file size in bytes */ - int v_ref_count; /* # times vnode used; 0 means slot is free */ - int v_fs_count; /* # reference at the underlying FS */ - int v_mapfs_count; /* # reference at the underlying mapped FS */ -#if 0 - int v_ref_check; /* for consistency checks */ -#endif - char v_pipe; /* set to I_PIPE if pipe */ - off_t v_pipe_rd_pos; - off_t v_pipe_wr_pos; - endpoint_t v_bfs_e; /* endpoint number for the FS proces in case - of a block special file */ - dev_t v_dev; /* device number on which the corresponding - inode resides */ - dev_t v_sdev; /* device number for special files */ - struct vmnt *v_vmnt; /* vmnt object of the partition */ - tll_t v_lock; /* three-level-lock */ -} vnode[NR_VNODES]; - - -/* Field values. */ -#define NO_PIPE 0 /* i_pipe is NO_PIPE if inode is not a pipe */ -#define I_PIPE 1 /* i_pipe is I_PIPE if inode is a pipe */ - -/* vnode lock types mapping */ -#define VNODE_READ TLL_READ -#define VNODE_OPCL TLL_READSER -#define VNODE_WRITE TLL_WRITE -#endif diff --git a/servers/avfs/write.c b/servers/avfs/write.c deleted file mode 100644 index a3e9d636e..000000000 --- a/servers/avfs/write.c +++ /dev/null @@ -1,19 +0,0 @@ -/* This file is the counterpart of "read.c". It contains the code for writing - * insofar as this is not contained in read_write(). - * - * The entry points into this file are - * do_write: call read_write to perform the WRITE system call - */ - -#include "fs.h" -#include "file.h" - - -/*===========================================================================* - * do_write * - *===========================================================================*/ -PUBLIC int do_write() -{ -/* Perform the write(fd, buffer, nbytes) system call. */ - return(do_read_write(WRITING)); -} diff --git a/servers/is/Makefile b/servers/is/Makefile index 92c22e21f..727ffca95 100644 --- a/servers/is/Makefile +++ b/servers/is/Makefile @@ -17,12 +17,6 @@ CPPFLAGS.dmp_kernel.c+= -I${MINIXSRCDIR} CPPFLAGS.dmp_rs.c+= -I${MINIXSRCDIR} CPPFLAGS.dmp_vm.c+= -I${MINIXSRCDIR} -.if ${BUILDAVFS} == "yes" -CFLAGS+= -D_USEAVFS -.else -CFLAGS+= -D_USEVFS -.endif - # This setting must match the kernel's, as it affects the IRQ hooks table size. .if ${USE_APIC} != "no" CFLAGS+= -DUSE_APIC diff --git a/servers/is/dmp_fs.c b/servers/is/dmp_fs.c index 92b7cd7a9..a8c2d8f49 100644 --- a/servers/is/dmp_fs.c +++ b/servers/is/dmp_fs.c @@ -10,15 +10,9 @@ #include "inc.h" #include "../mfs/const.h" -#if defined(_USEAVFS) -# include "../avfs/const.h" -# include "../avfs/fproc.h" -# include "../avfs/dmap.h" -#else -# include "../vfs/const.h" -# include "../vfs/fproc.h" -# include "../vfs/dmap.h" -#endif +#include "../vfs/const.h" +#include "../vfs/fproc.h" +#include "../vfs/dmap.h" #include PUBLIC struct fproc fproc[NR_PROCS]; @@ -44,16 +38,6 @@ PUBLIC void fproc_dmp() fp = &fproc[i]; if (fp->fp_pid <= 0) continue; if (++n > 22) break; -#if !defined(_USEAVFS) - printf("%3d %4d %2d/%d 0x%05x %2d (%2d) %2d (%2d) %3d %3d %3d ", - i, fp->fp_pid, - ((fp->fp_tty>>MAJOR)&BYTE), ((fp->fp_tty>>MINOR)&BYTE), - fp->fp_umask, - fp->fp_realuid, fp->fp_effuid, fp->fp_realgid, fp->fp_effgid, - fp->fp_sesldr, - fp->fp_blocked_on, !!fp->fp_revived - ); -#else printf("%3d %4d %2d/%d 0x%05x %2d (%2d) %2d (%2d) %3d %3d %3d ", i, fp->fp_pid, major(fp->fp_tty), minor(fp->fp_tty), @@ -62,7 +46,6 @@ PUBLIC void fproc_dmp() !!(fp->fp_flags & FP_SESLDR), fp->fp_blocked_on, !!(fp->fp_flags & FP_REVIVED) ); -#endif if (fp->fp_blocked_on == FP_BLOCKED_ON_OTHER) printf("%4d\n", fp->fp_task); else diff --git a/servers/pfs/Makefile b/servers/pfs/Makefile index ff1a9fad7..18f5305f5 100644 --- a/servers/pfs/Makefile +++ b/servers/pfs/Makefile @@ -1,15 +1,18 @@ # Makefile for Pipe File System (PFS) PROG= pfs SRCS= open.c table.c inode.c main.c super.c link.c \ - buffer.c read.c misc.c utility.c stadir.c \ + buffer.c read.c misc.c mount.c utility.c stadir.c \ uds.c dev_uds.c DPADD+= ${LIBSYS} LDADD+= -lsys +.if ${COMPILER_TYPE} == "gnu" +LDADD+= -lc +.endif + MAN= BINDIR?= /usr/sbin -INSTALLFLAGS+= -S 128k .include diff --git a/servers/pfs/buf.h b/servers/pfs/buf.h index 8e847bac7..cd31f7e84 100644 --- a/servers/pfs/buf.h +++ b/servers/pfs/buf.h @@ -1,7 +1,7 @@ #ifndef __PFS_BUF_H__ #define __PFS_BUF_H__ -/* Buffer (block) cache. +/* Buffer (block) cache. */ struct buf { diff --git a/servers/pfs/buffer.c b/servers/pfs/buffer.c index e745e419e..a5c77b4a6 100644 --- a/servers/pfs/buffer.c +++ b/servers/pfs/buffer.c @@ -28,11 +28,11 @@ PUBLIC struct buf *get_block(dev_t dev, ino_t inum) struct buf *bp = front; while(bp != NULL) { - if (bp->b_dev == dev && bp->b_num == inum) { - bp->b_count++; - return(bp); - } - bp = bp->b_next; + if (bp->b_dev == dev && bp->b_num == inum) { + bp->b_count++; + return(bp); + } + bp = bp->b_next; } /* Buffer was not found. Try to allocate a new one */ @@ -48,24 +48,24 @@ PRIVATE struct buf *new_block(dev_t dev, ino_t inum) /* Allocate a new buffer and add it to the double linked buffer list */ struct buf *bp; - bp = malloc(sizeof(struct buf)); + bp = malloc(sizeof(struct buf)); if (bp == NULL) { err_code = ENOSPC; - return(NULL); + return(NULL); } bp->b_num = inum; bp->b_dev = dev; bp->b_bytes = 0; bp->b_count = 1; memset(bp->b_data, 0 , PIPE_BUF); - + /* Add at the end of the buffer */ if (front == NULL) { /* Empty list? */ - front = bp; - bp->b_prev = NULL; + front = bp; + bp->b_prev = NULL; } else { - rear->b_next = bp; - bp->b_prev = rear; + rear->b_next = bp; + bp->b_prev = rear; } bp->b_next = NULL; rear = bp; @@ -84,22 +84,20 @@ PUBLIC void put_block(dev_t dev, ino_t inum) bp = get_block(dev, inum); if (bp == NULL) return; /* We didn't find the block. Nothing to put. */ - bp->b_count--; /* Compensate for above 'get_block'. */ + bp->b_count--; /* Compensate for above 'get_block'. */ if (--bp->b_count > 0) return; /* Cut bp out of the loop */ if (bp->b_prev == NULL) - front = bp->b_next; + front = bp->b_next; else - bp->b_prev->b_next = bp->b_next; + bp->b_prev->b_next = bp->b_next; if (bp->b_next == NULL) - rear = bp->b_prev; + rear = bp->b_prev; else - bp->b_next->b_prev = bp->b_prev; + bp->b_next->b_prev = bp->b_prev; /* Buffer administration is done. Now it's safe to free up bp. */ free(bp); } - - diff --git a/servers/pfs/const.h b/servers/pfs/const.h index 443c61f40..f89a239be 100644 --- a/servers/pfs/const.h +++ b/servers/pfs/const.h @@ -3,7 +3,7 @@ #define NR_INODES 256 /* # slots in "in core" inode table */ -/* Size of descriptor table for unix domain sockets. This should be +/* Size of descriptor table for unix domain sockets. This should be * equal to the maximum number of minor devices (currently 256). */ #define NR_FDS 256 @@ -40,4 +40,3 @@ #define DEV_CALL_VEC_SIZE 25 #endif - diff --git a/servers/pfs/dev_uds.c b/servers/pfs/dev_uds.c index 015e5cfd5..7250f071e 100644 --- a/servers/pfs/dev_uds.c +++ b/servers/pfs/dev_uds.c @@ -71,8 +71,8 @@ PUBLIC int uds_open(message *dev_m_in, message *dev_m_out) if (minor == -1) { /* descriptor table full */ - uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, ENFILE); + uds_set_reply(dev_m_out, DEV_OPEN_REPL, dev_m_in->USER_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, ENFILE); return ENFILE; } @@ -123,7 +123,7 @@ PUBLIC int uds_open(message *dev_m_in, message *dev_m_out) uds_fd_table[minor].backlog[i] = -1; } - memset(&uds_fd_table[minor].ancillary_data, '\0', sizeof(struct + memset(&uds_fd_table[minor].ancillary_data, '\0', sizeof(struct ancillary)); for (i = 0; i < OPEN_MAX; i++) { uds_fd_table[minor].ancillary_data.fds[i] = -1; @@ -168,8 +168,8 @@ PUBLIC int uds_open(message *dev_m_in, message *dev_m_out) memset(&(uds_fd_table[minor]), '\0', sizeof(uds_fd_t)); /* likely error: invalid endpoint / proc doesn't exist */ - uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, errno); + uds_set_reply(dev_m_out, DEV_OPEN_REPL, dev_m_in->USER_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, errno); return errno; } @@ -189,7 +189,7 @@ PUBLIC int uds_open(message *dev_m_in, message *dev_m_out) memset(&(uds_fd_table[minor]), '\0', sizeof(uds_fd_t)); /* likely error: get_block() failed */ - uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->USER_ENDPT, + uds_set_reply(dev_m_out, DEV_OPEN_REPL, dev_m_in->USER_ENDPT, (cp_grant_id_t) dev_m_in->IO_GRANT, rc); return rc; } @@ -201,8 +201,8 @@ PUBLIC int uds_open(message *dev_m_in, message *dev_m_out) /* prepare the reply */ uds_fd_table[minor].syscall_done = 1; - uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, minor); + uds_set_reply(dev_m_out, DEV_OPEN_REPL, dev_m_in->USER_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, minor); return minor; } @@ -222,11 +222,11 @@ PUBLIC int uds_close(message *dev_m_in, message *dev_m_out) minor = uds_minor(dev_m_in); if (uds_fd_table[minor].state != UDS_INUSE) { - /* attempted to close a socket that hasn't been opened -- + /* attempted to close a socket that hasn't been opened -- * something is very wrong :( */ - uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); + uds_set_reply(dev_m_out, DEV_CLOSE_REPL, dev_m_in->USER_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); return EINVAL; } @@ -246,11 +246,10 @@ PUBLIC int uds_close(message *dev_m_in, message *dev_m_out) /* if peer was blocked on I/O revive peer */ if (uds_fd_table[uds_fd_table[minor].peer].suspended) { - int peer = uds_fd_table[minor].peer; uds_fd_table[peer].ready_to_revive = 1; - notify(dev_m_in->m_source); + uds_unsuspend(dev_m_in->m_source, peer); } } @@ -276,8 +275,8 @@ PUBLIC int uds_close(message *dev_m_in, message *dev_m_out) return rc; } - uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, OK); + uds_set_reply(dev_m_out, DEV_CLOSE_REPL, dev_m_in->USER_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, OK); return OK; } @@ -297,12 +296,11 @@ PUBLIC int uds_select(message *dev_m_in, message *dev_m_out) if (uds_fd_table[minor].state != UDS_INUSE) { - /* attempted to close a socket that hasn't been opened -- + /* attempted to close a socket that hasn't been opened -- * something is very wrong :( */ - uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); + uds_sel_reply(dev_m_out, DEV_SEL_REPL1, minor, EINVAL); return EINVAL; } @@ -345,10 +343,8 @@ PUBLIC int uds_select(message *dev_m_in, message *dev_m_out) } uds_fd_table[minor].syscall_done = 1; - - uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, - uds_fd_table[minor].sel_ops_out); + uds_sel_reply(dev_m_out, DEV_SEL_REPL1, minor, + uds_fd_table[minor].sel_ops_out); return uds_fd_table[minor].sel_ops_out; } @@ -384,23 +380,22 @@ PRIVATE int uds_perform_read(int minor, endpoint_t m_source, return SUSPEND; } - /* maybe a process is blocked waiting to write? if + /* maybe a process is blocked waiting to write? if * needed revive the writer */ if (uds_fd_table[minor].peer != -1 && uds_fd_table[uds_fd_table[minor].peer].suspended) { - int peer = uds_fd_table[minor].peer; uds_fd_table[peer].ready_to_revive = 1; - notify(m_source); + uds_unsuspend(m_source, peer); } #if DEBUG == 1 printf("(uds) [%d] suspending read request\n", minor); #endif - /* Process is reading from an empty pipe, + /* Process is reading from an empty pipe, * suspend it so some bytes can be written */ uds_fd_table[minor].suspended = UDS_SUSPENDED_READ; @@ -435,7 +430,7 @@ PRIVATE int uds_perform_read(int minor, endpoint_t m_source, printf("(uds) [%d] read complete\n", minor); #endif - /* move the position of the data pointer up to data we haven't + /* move the position of the data pointer up to data we haven't * read yet */ uds_fd_table[minor].pos += fs_m_out.RES_NBYTES; @@ -443,29 +438,30 @@ PRIVATE int uds_perform_read(int minor, endpoint_t m_source, /* decrease the number of unread bytes */ uds_fd_table[minor].size -= fs_m_out.RES_NBYTES; - /* if we have 0 unread bytes, move the data pointer back to the + /* if we have 0 unread bytes, move the data pointer back to the * start of the buffer */ if (uds_fd_table[minor].size == 0) { uds_fd_table[minor].pos = 0; } - /* maybe a big write was waiting for us to read some data, if + /* maybe a big write was waiting for us to read some data, if * needed revive the writer */ - if (uds_fd_table[minor].peer != -1 && + if (uds_fd_table[minor].peer != -1 && uds_fd_table[uds_fd_table[minor].peer].suspended) { + int peer = uds_fd_table[minor].peer; - uds_fd_table[uds_fd_table[minor].peer].ready_to_revive = 1; - notify(m_source); + uds_fd_table[peer].ready_to_revive = 1; + uds_unsuspend(m_source, peer); } - /* see if peer is blocked on select() and a write is possible + /* see if peer is blocked on select() and a write is possible * (from peer to minor) */ - if (uds_fd_table[minor].peer != -1 && + if (uds_fd_table[minor].peer != -1 && uds_fd_table[uds_fd_table[minor].peer].selecting == 1 && - (uds_fd_table[minor].size + uds_fd_table[minor].pos + 1 + (uds_fd_table[minor].size + uds_fd_table[minor].pos + 1 < PIPE_BUF)) { int peer = uds_fd_table[minor].peer; @@ -479,7 +475,7 @@ PRIVATE int uds_perform_read(int minor, endpoint_t m_source, /* a write on peer is possible now */ uds_fd_table[peer].sel_ops_out |= SEL_WR; uds_fd_table[peer].status_updated = 1; - notify(uds_fd_table[peer].select_proc); + uds_unsuspend(m_source, peer); } } @@ -520,7 +516,7 @@ PRIVATE int uds_perform_write(int minor, endpoint_t m_source, if (uds_fd_table[minor].type == SOCK_STREAM || uds_fd_table[minor].type == SOCK_SEQPACKET) { - /* if we're writing with a connection oriented socket, + /* if we're writing with a connection oriented socket, * then it needs a peer to write to */ if (uds_fd_table[minor].peer == -1) { @@ -543,7 +539,7 @@ PRIVATE int uds_perform_write(int minor, endpoint_t m_source, /* locate the "peer" we want to write to */ for (i = 0; i < NR_FDS; i++) { - /* look for a SOCK_DGRAM socket that is bound on + /* look for a SOCK_DGRAM socket that is bound on * the target address */ if (uds_fd_table[i].type == SOCK_DGRAM && @@ -561,14 +557,14 @@ PRIVATE int uds_perform_write(int minor, endpoint_t m_source, } } - /* check if write would overrun buffer. check if message - * boundry preserving types (SEQPACKET and DGRAM) wouldn't write - * to an empty buffer. check if connectionless sockets have a + /* check if write would overrun buffer. check if message + * boundry preserving types (SEQPACKET and DGRAM) wouldn't write + * to an empty buffer. check if connectionless sockets have a * target to write to. */ if ((uds_fd_table[peer].pos+uds_fd_table[peer].size+size > PIPE_BUF) || ((uds_fd_table[minor].type == SOCK_SEQPACKET || - uds_fd_table[minor].type == SOCK_DGRAM) && + uds_fd_table[minor].type == SOCK_DGRAM) && uds_fd_table[peer].size > 0) || (peer == -1)) { if (pretend) { @@ -577,16 +573,15 @@ PRIVATE int uds_perform_write(int minor, endpoint_t m_source, /* if needed revive the reader */ if (uds_fd_table[peer].suspended) { - uds_fd_table[peer].ready_to_revive = 1; - notify(m_source); + uds_unsuspend(m_source, peer); } #if DEBUG == 1 printf("(uds) [%d] suspending write request\n", minor); #endif - /* Process is reading from an empty pipe, + /* Process is reading from an empty pipe, * suspend it so some bytes can be written */ uds_fd_table[minor].suspended = UDS_SUSPENDED_WRITE; @@ -629,9 +624,8 @@ PRIVATE int uds_perform_write(int minor, endpoint_t m_source, /* revive peer that was waiting for us to write */ if (uds_fd_table[peer].suspended) { - uds_fd_table[peer].ready_to_revive = 1; - notify(m_source); + uds_unsuspend(m_source, peer); } /* see if peer is blocked on select()*/ @@ -647,7 +641,7 @@ PRIVATE int uds_perform_write(int minor, endpoint_t m_source, /* a read on peer is possible now */ uds_fd_table[peer].sel_ops_out |= SEL_RD; uds_fd_table[peer].status_updated = 1; - notify(uds_fd_table[peer].select_proc); + uds_unsuspend(m_source, peer); } } @@ -674,8 +668,8 @@ PUBLIC int uds_read(message *dev_m_in, message *dev_m_out) /* attempted to close a socket that hasn't been opened -- * something is very wrong :( */ - uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); + uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); return EINVAL; } @@ -698,10 +692,8 @@ PUBLIC int uds_read(message *dev_m_in, message *dev_m_out) bytes = uds_perform_read(minor, dev_m_in->m_source, uds_fd_table[minor].io_gr_size, 0); - uds_set_reply(dev_m_out, TASK_REPLY, - uds_fd_table[minor].endpoint, - uds_fd_table[minor].io_gr, - bytes); + uds_set_reply(dev_m_out, DEV_REVIVE, uds_fd_table[minor].endpoint, + uds_fd_table[minor].io_gr, bytes); return bytes; } @@ -715,7 +707,7 @@ PUBLIC int uds_write(message *dev_m_in, message *dev_m_out) static int call_count = 0; printf("(uds) [%d] uds_write() call_count=%d\n", uds_minor(dev_m_in), ++call_count); - printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT, + printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT, dev_m_in->POSITION); #endif @@ -723,11 +715,11 @@ PUBLIC int uds_write(message *dev_m_in, message *dev_m_out) if (uds_fd_table[minor].state != UDS_INUSE) { - /* attempted to close a socket that hasn't been opened -- + /* attempted to close a socket that hasn't been opened -- * something is very wrong :( */ - uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); + uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); return EINVAL; } @@ -750,10 +742,8 @@ PUBLIC int uds_write(message *dev_m_in, message *dev_m_out) bytes = uds_perform_write(minor, dev_m_in->m_source, uds_fd_table[minor].io_gr_size, 0); - uds_set_reply(dev_m_out, TASK_REPLY, - uds_fd_table[minor].endpoint, - uds_fd_table[minor].io_gr, - bytes); + uds_set_reply(dev_m_out, DEV_REVIVE, uds_fd_table[minor].endpoint, + uds_fd_table[minor].io_gr, bytes); return bytes; } @@ -766,7 +756,7 @@ PUBLIC int uds_ioctl(message *dev_m_in, message *dev_m_out) static int call_count = 0; printf("(uds) [%d] uds_ioctl() call_count=%d\n", uds_minor(dev_m_in), ++call_count); - printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT, + printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT, dev_m_in->POSITION); #endif @@ -777,8 +767,8 @@ PUBLIC int uds_ioctl(message *dev_m_in, message *dev_m_out) /* attempted to close a socket that hasn't been opened -- * something is very wrong :( */ - uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); + uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); return EINVAL; } @@ -821,7 +811,7 @@ PUBLIC int uds_ioctl(message *dev_m_in, message *dev_m_out) case NWIOSUDSTYPE: - /* set the type for this socket (i.e. + /* set the type for this socket (i.e. * SOCK_STREAM, SOCK_DGRAM, etc) -- socket() */ rc = do_socket(dev_m_in, dev_m_out); @@ -851,7 +841,7 @@ PUBLIC int uds_ioctl(message *dev_m_in, message *dev_m_out) case NWIOSUDSSHUT: - /* shutdown a socket for reading, writing, or + /* shutdown a socket for reading, writing, or * both -- shutdown() */ rc = do_shutdown(dev_m_in, dev_m_out); @@ -952,8 +942,8 @@ PUBLIC int uds_ioctl(message *dev_m_in, message *dev_m_out) default: /* the IOCTL command is not valid for /dev/uds -- - * this happens a lot and is normal. a lot of - * libc functions determine the socket type with + * this happens a lot and is normal. a lot of + * libc functions determine the socket type with * IOCTLs. Any not for us simply get a EBADIOCTL * response. */ @@ -964,137 +954,101 @@ PUBLIC int uds_ioctl(message *dev_m_in, message *dev_m_out) if (rc != SUSPEND) uds_fd_table[minor].syscall_done = 1; - uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, rc); + uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, rc); return rc; } -PUBLIC int uds_status(message *dev_m_in, message *dev_m_out) +PUBLIC int uds_unsuspend(endpoint_t m_source, int minor) { - int i, bytes; + int r = OK, bytes; + message m_out; + uds_fd_t *fdp; -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] uds_status() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); - printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT, dev_m_in->POSITION); -#endif + fdp = &uds_fd_table[minor]; - for (i = 0; i < NR_FDS; i++) { + if (fdp->status_updated == 1) { - if (uds_fd_table[i].status_updated == 1) { + /* clear the status_updated flag */ + fdp->status_updated = 0; + fdp->selecting = 0; - /* clear the status_updated flag */ - uds_fd_table[i].status_updated = 0; - uds_fd_table[i].selecting = 0; + /* prepare the response */ + uds_sel_reply(&m_out, DEV_SEL_REPL2, minor, fdp->sel_ops_out); + } else if (fdp->ready_to_revive == 1) { - /* prepare the response */ - dev_m_out->m_type = DEV_IO_READY; - dev_m_out->DEV_MINOR = i; - dev_m_out->DEV_SEL_OPS = uds_fd_table[i].sel_ops_out; + /* clear the ready to revive flag */ + fdp->ready_to_revive = 0; - return uds_fd_table[i].sel_ops_out; + switch (fdp->suspended) { + + case UDS_SUSPENDED_READ: + + bytes = uds_perform_read(minor, m_source, + fdp->io_gr_size, 0); + + if (bytes == SUSPEND) { + r = SUSPEND; + break; + } + + fdp->suspended = UDS_NOT_SUSPENDED; + + uds_set_reply(&m_out, DEV_REVIVE, fdp->endpoint, + fdp->io_gr, bytes); + + break; + + case UDS_SUSPENDED_WRITE: + + bytes = uds_perform_write(minor, m_source, + fdp->io_gr_size, 0); + + if (bytes == SUSPEND) { + r = SUSPEND; + break; + } + + fdp->suspended = UDS_NOT_SUSPENDED; + + uds_set_reply(&m_out, DEV_REVIVE, fdp->endpoint, + fdp->io_gr, bytes); + + break; + + case UDS_SUSPENDED_CONNECT: + case UDS_SUSPENDED_ACCEPT: + + /* In both cases, the process + * that send the notify() + * already performed the connection. + * The only thing to do here is + * unblock. + */ + + fdp->suspended = UDS_NOT_SUSPENDED; + + uds_set_reply(&m_out, DEV_REVIVE, fdp->endpoint, + fdp->io_gr, OK); + + break; + + default: + return(OK); } - if (uds_fd_table[i].ready_to_revive == 1) { - - /* clear the ready to revive flag */ - uds_fd_table[i].ready_to_revive = 0; - - switch (uds_fd_table[i].suspended) { - - case UDS_SUSPENDED_READ: - - bytes = uds_perform_read(i, - dev_m_in->m_source, - uds_fd_table[i].io_gr_size, - 0); - - if (bytes == SUSPEND) { - - dev_m_out->m_type = - DEV_NO_STATUS; - - return OK; - - } - - uds_fd_table[i].suspended = - UDS_NOT_SUSPENDED; - - uds_set_reply(dev_m_out, - DEV_REVIVE, - uds_fd_table[i].endpoint, - uds_fd_table[i].io_gr, - bytes); - - return bytes; - - case UDS_SUSPENDED_WRITE: - - bytes = uds_perform_write(i, - dev_m_in->m_source, - uds_fd_table[i].io_gr_size, - 0); - - if (bytes == SUSPEND) { - - dev_m_out->m_type = - DEV_NO_STATUS; - - return OK; - - } - - uds_fd_table[i].suspended = - UDS_NOT_SUSPENDED; - - uds_set_reply(dev_m_out, - DEV_REVIVE, - uds_fd_table[i].endpoint, - uds_fd_table[i].io_gr, - bytes); - - return bytes; - - case UDS_SUSPENDED_CONNECT: - case UDS_SUSPENDED_ACCEPT: - - /* In both cases, the process - * that send the notify() - * already performed the connection. - * The only thing to do here is - * unblock. - */ - - uds_fd_table[i].suspended = - UDS_NOT_SUSPENDED; - - uds_set_reply(dev_m_out, - DEV_REVIVE, - uds_fd_table[i].endpoint, - uds_fd_table[i].io_gr, - OK); - - return OK; - - default: - continue; - } - - } } - dev_m_out->m_type = DEV_NO_STATUS; - return OK; + if (r == OK) reply(m_source, &m_out); + return(r); } PUBLIC int uds_cancel(message *dev_m_in, message *dev_m_out) { int i, j; int minor; - + /* XXX: should become a noop? */ #if DEBUG == 1 static int call_count = 0; printf("(uds) [%d] uds_cancel() call_count=%d\n", uds_minor(dev_m_in), @@ -1109,8 +1063,8 @@ PUBLIC int uds_cancel(message *dev_m_in, message *dev_m_out) /* attempted to close a socket that hasn't been opened -- * something is very wrong :( */ - uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); + uds_set_reply(dev_m_out, DEV_NO_STATUS, dev_m_in->USER_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); return EINVAL; } @@ -1136,14 +1090,14 @@ PUBLIC int uds_cancel(message *dev_m_in, message *dev_m_out) case NWIOSUDSACCEPT: /* accept() */ - /* partial accept() only changes + /* partial accept() only changes * uds_fd_table[minorparent].child */ for (i = 0; i < NR_FDS; i++) { if (uds_fd_table[i].child == minor) { - + uds_fd_table[i].child = -1; } @@ -1153,7 +1107,7 @@ PUBLIC int uds_cancel(message *dev_m_in, message *dev_m_out) case NWIOSUDSCONN: /* connect() */ - /* partial connect() sets addr + /* partial connect() sets addr * and adds minor to server backlog */ @@ -1166,7 +1120,7 @@ PUBLIC int uds_cancel(message *dev_m_in, message *dev_m_out) UDS_INUSE) { /* see if minor is in - * the backlog + * the backlog */ for (j = 0; j < uds_fd_table[i].backlog_size; j++) { @@ -1206,9 +1160,9 @@ PUBLIC int uds_cancel(message *dev_m_in, message *dev_m_out) } - /* DEV_READ_S or DEV_WRITE_S don't need to do anything - * when cancelled. DEV_OPEN, DEV_REOPEN, DEV_SELECT, - * DEV_CLOSE are atomic, never suspend, and can't + /* DEV_READ_S or DEV_WRITE_S don't need to do anything + * when cancelled. DEV_OPEN, DEV_REOPEN, DEV_SELECT, + * DEV_CLOSE are atomic, never suspend, and can't * be cancelled once called. */ @@ -1216,9 +1170,8 @@ PUBLIC int uds_cancel(message *dev_m_in, message *dev_m_out) } - uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->USER_ENDPT, + uds_set_reply(dev_m_out, DEV_NO_STATUS, dev_m_in->USER_ENDPT, (cp_grant_id_t) dev_m_in->IO_GRANT, EINTR); return EINTR; } - diff --git a/servers/pfs/glo.h b/servers/pfs/glo.h index 76338599b..175b4fc8e 100644 --- a/servers/pfs/glo.h +++ b/servers/pfs/glo.h @@ -21,8 +21,9 @@ EXTERN int req_nr; EXTERN int SELF_E; EXTERN int exitsignaled; EXTERN int busy; +EXTERN int unmountdone; /* Inode map. */ -EXTERN bitchunk_t inodemap[FS_BITMAP_CHUNKS(NR_INODES)]; +EXTERN bitchunk_t inodemap[FS_BITMAP_CHUNKS(NR_INODES)]; #endif diff --git a/servers/pfs/inc.h b/servers/pfs/inc.h index f8a0eb915..4484e8038 100644 --- a/servers/pfs/inc.h +++ b/servers/pfs/inc.h @@ -39,4 +39,3 @@ #include #include "proto.h" - diff --git a/servers/pfs/inode.c b/servers/pfs/inode.c index a2b42e8b6..98be69203 100644 --- a/servers/pfs/inode.c +++ b/servers/pfs/inode.c @@ -19,7 +19,7 @@ #include "inode.h" #include -FORWARD _PROTOTYPE( void addhash_inode, (struct inode * const node) ); +FORWARD _PROTOTYPE( void addhash_inode, (struct inode * const node) ); FORWARD _PROTOTYPE( void unhash_inode, (struct inode * const node) ); @@ -34,7 +34,7 @@ PUBLIC int fs_putnode(message *fs_m_in, message *fs_m_out) int count; dev_t dev; ino_t inum; - + rip = find_inode( (ino_t) fs_m_in->REQ_INODE_NR); if(!rip) { @@ -55,7 +55,7 @@ PUBLIC int fs_putnode(message *fs_m_in, message *fs_m_out) } /* Decrease reference counter, but keep one reference; it will be consumed by - * put_inode(). */ + * put_inode(). */ rip->i_count -= count - 1; dev = rip->i_dev; inum = rip->i_num; @@ -75,9 +75,9 @@ PUBLIC void init_inode_cache() /* init free/unused list */ TAILQ_INIT(&unused_inodes); - + /* init hash lists */ - for (rlp = &hash_inodes[0]; rlp < &hash_inodes[INODE_HASH_SIZE]; ++rlp) + for (rlp = &hash_inodes[0]; rlp < &hash_inodes[INODE_HASH_SIZE]; ++rlp) LIST_INIT(rlp); /* add free inodes to unused/free list */ @@ -95,10 +95,10 @@ PUBLIC void init_inode_cache() /*===========================================================================* * addhash_inode * *===========================================================================*/ -PRIVATE void addhash_inode(struct inode * const node) +PRIVATE void addhash_inode(struct inode * const node) { int hashi = (int) (node->i_num & INODE_HASH_MASK); - + /* insert into hash table */ LIST_INSERT_HEAD(&hash_inodes[hashi], node, i_hash); } @@ -107,7 +107,7 @@ PRIVATE void addhash_inode(struct inode * const node) /*===========================================================================* * unhash_inode * *===========================================================================*/ -PRIVATE void unhash_inode(struct inode * const node) +PRIVATE void unhash_inode(struct inode * const node) { /* remove from hash table */ LIST_REMOVE(node, i_hash); @@ -123,7 +123,7 @@ PUBLIC struct inode *get_inode( ) { /* Find the inode in the hash table. If it is not there, get a free inode - * load it from the disk if it's necessary and put on the hash list + * load it from the disk if it's necessary and put on the hash list */ register struct inode *rip; int hashi; @@ -152,7 +152,7 @@ PUBLIC struct inode *get_inode( /* If not free unhash it */ if (rip->i_num != NO_ENTRY) unhash_inode(rip); - + /* Inode is not unused any more */ TAILQ_REMOVE(&unused_inodes, rip, i_unused); @@ -165,7 +165,7 @@ PUBLIC struct inode *get_inode( /* Add to hash */ addhash_inode(rip); - + return(rip); } @@ -189,7 +189,7 @@ ino_t numb; /* inode number */ return(rip); } } - + return(NULL); } @@ -245,15 +245,19 @@ PUBLIC struct inode *alloc_inode(dev_t dev, mode_t bits) register struct inode *rip; bit_t b; ino_t i_num; + int print_oos_msg = 1; b = alloc_bit(); if (b == NO_BIT) { - err_code = ENOSPC; - printf("PipeFS is out of inodes\n"); - return(NULL); + err_code = ENOSPC; + if (print_oos_msg) + printf("PipeFS is out of inodes\n"); + print_oos_msg = 0; /* Don't repeat message */ + return(NULL); } i_num = (ino_t) b; - + print_oos_msg = 1; + /* Try to acquire a slot in the inode table. */ if ((rip = get_inode(dev, i_num)) == NULL) { @@ -320,7 +324,7 @@ struct inode *rip; /* pointer to inode to be read/written */ /* Various system calls are required by the standard to update atime, ctime, * or mtime. Since updating a time requires sending a message to the clock * task--an expensive business--the times are marked for update by setting - * bits in i_update. When a stat, fstat, or sync is done, or an inode is + * bits in i_update. When a stat, fstat, or sync is done, or an inode is * released, update_times() may be called to actually fill in the times. */ @@ -332,4 +336,3 @@ struct inode *rip; /* pointer to inode to be read/written */ if (rip->i_update & MTIME) rip->i_mtime = cur_time; rip->i_update = 0; /* they are all up-to-date now */ } - diff --git a/servers/pfs/inode.h b/servers/pfs/inode.h index 8614aa0f7..19e582593 100644 --- a/servers/pfs/inode.h +++ b/servers/pfs/inode.h @@ -1,7 +1,7 @@ #ifndef __PFS_INODE_H__ #define __PFS_INODE_H__ -/* Inode table. This table holds inodes that are currently in use. +/* Inode table. This table holds inodes that are currently in use. */ #include @@ -15,7 +15,7 @@ EXTERN struct inode { time_t i_atime; /* time of last access (V2 only) */ time_t i_mtime; /* when was file data last changed */ time_t i_ctime; /* when was inode itself changed (V2 only)*/ - + /* The following items are not present on the disk. */ dev_t i_dev; /* which device is the inode on */ dev_t i_rdev; /* which special device is the inode on */ @@ -26,10 +26,10 @@ EXTERN struct inode { LIST_ENTRY(inode) i_hash; /* hash list */ TAILQ_ENTRY(inode) i_unused; /* free and unused list */ - + } inode[NR_INODES]; -/* list of unused/free inodes */ +/* list of unused/free inodes */ EXTERN TAILQ_HEAD(unused_inodes_t, inode) unused_inodes; /* inode hashtable */ diff --git a/servers/pfs/link.c b/servers/pfs/link.c index 4a5e901cb..4ec064ef9 100644 --- a/servers/pfs/link.c +++ b/servers/pfs/link.c @@ -11,7 +11,7 @@ PUBLIC int fs_ftrunc(message *fs_m_in, message *fs_m_out) struct inode *rip; off_t start, end; ino_t inumb; - + inumb = (ino_t) fs_m_in->REQ_INODE_NR; if( (rip = find_inode(inumb)) == NULL) return(EINVAL); @@ -21,7 +21,7 @@ PUBLIC int fs_ftrunc(message *fs_m_in, message *fs_m_out) return truncate_inode(rip, start); } - + /*===========================================================================* * truncate_inode * @@ -35,17 +35,16 @@ off_t newsize; /* inode must become this size */ * extra space is a hole that reads as zeroes. * * Nothing special has to happen to file pointers if inode is opened in - * O_APPEND mode, as this is different per fd and is checked when + * O_APPEND mode, as this is different per fd and is checked when * writing is done. */ /* Pipes can shrink, so adjust size to make sure all zones are removed. */ if(newsize != 0) return(EINVAL); /* Only truncate pipes to 0. */ rip->i_size = newsize; - + /* Next correct the inode size. */ wipe_inode(rip); /* Pipes can only be truncated to 0. */ return(OK); } - diff --git a/servers/pfs/main.c b/servers/pfs/main.c index b449e1239..f4f20f8dd 100644 --- a/servers/pfs/main.c +++ b/servers/pfs/main.c @@ -4,7 +4,10 @@ #include #include #include +#include #include +#include +#include #include "buf.h" #include "inode.h" #include "uds.h" @@ -21,11 +24,11 @@ FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) ); *===========================================================================*/ PUBLIC int main(int argc, char *argv[]) { -/* This is the main routine of this service. The main loop consists of +/* This is the main routine of this service. The main loop consists of * three major activities: getting new work, processing the work, and * sending the reply. The loop never terminates, unless a panic occurs. */ - int ind, transid; + int ind, do_reply, transid; message pfs_m_in; message pfs_m_out; @@ -33,9 +36,10 @@ PUBLIC int main(int argc, char *argv[]) env_setargs(argc, argv); sef_local_startup(); - while(!exitsignaled || busy) { + while(!unmountdone || !exitsignaled) { endpoint_t src; + do_reply = 1; /* Wait for request message. */ get_work(&pfs_m_in); @@ -59,7 +63,13 @@ PUBLIC int main(int argc, char *argv[]) printf("pfs: bad DEV request %d\n", req_nr); pfs_m_out.m_type = EINVAL; } else { - (*dev_call_vec[ind])(&pfs_m_in, &pfs_m_out); + int result; + result = (*dev_call_vec[ind])(&pfs_m_in, &pfs_m_out); + if (pfs_m_out.REP_STATUS == SUSPEND || + result == SUSPEND) { + /* Nothing to tell, so not replying */ + do_reply = 0; + } } } else if (IS_VFS_RQ(req_nr)) { ind = req_nr - VFS_BASE; @@ -75,10 +85,13 @@ PUBLIC int main(int argc, char *argv[]) pfs_m_out.m_type = EINVAL; } - if (IS_VFS_RQ(req_nr) && IS_VFS_FS_TRANSID(transid)) { - pfs_m_out.m_type = TRNS_ADD_ID(pfs_m_out.m_type, transid); + if (do_reply) { + if (IS_VFS_RQ(req_nr) && IS_VFS_FS_TRANSID(transid)) { + pfs_m_out.m_type = TRNS_ADD_ID(pfs_m_out.m_type, + transid); + } + reply(src, &pfs_m_out); } - reply(src, &pfs_m_out); } return(OK); } @@ -108,6 +121,7 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) { /* Initialize the pipe file server. */ int i; + struct passwd *pw; /* Initialize main loop parameters. */ exitsignaled = 0; /* No exit request seen yet. */ @@ -117,12 +131,21 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) for (i = 0; i < NR_INODES; ++i) { inode[i].i_count = 0; } - + init_inode_cache(); uds_init(); + buf_pool(); + + + /* Drop root privileges */ + if ((pw = getpwnam(SERVICE_LOGIN)) == NULL) { + printf("PFS: unable to retrieve uid of SERVICE_LOGIN, " + "still running as root"); + } else if (setuid(pw->pw_uid) != 0) { + panic("unable to drop privileges"); + } SELF_E = getprocnr(); - buf_pool(); return(OK); } @@ -135,6 +158,7 @@ PRIVATE void sef_cb_signal_handler(int signo) /* Only check for termination signal, ignore anything else. */ if (signo != SIGTERM) return; + exitsignaled = 1; } @@ -148,7 +172,7 @@ message *m_in; /* pointer to message */ endpoint_t src; do { - /* wait for a message */ + /* wait for a message */ if ((r = sef_receive_status(ANY, m_in, &status)) != OK) panic("sef_receive_status failed: %d", r); src = m_in->m_source; @@ -165,7 +189,7 @@ message *m_in; /* pointer to message */ * reply * *===========================================================================*/ PUBLIC void reply(who, m_out) -endpoint_t who; +endpoint_t who; message *m_out; /* report result */ { if (OK != send(who, m_out)) /* send the message */ diff --git a/servers/pfs/misc.c b/servers/pfs/misc.c index dc8da9e6e..2f8e3010d 100644 --- a/servers/pfs/misc.c +++ b/servers/pfs/misc.c @@ -10,5 +10,3 @@ PUBLIC int fs_sync(message *fs_m_in, message *fs_m_out) return(OK); /* sync() can't fail */ } - - diff --git a/servers/apfs/mount.c b/servers/pfs/mount.c similarity index 100% rename from servers/apfs/mount.c rename to servers/pfs/mount.c diff --git a/servers/pfs/open.c b/servers/pfs/open.c index 4abf5b1cf..a7e275757 100644 --- a/servers/pfs/open.c +++ b/servers/pfs/open.c @@ -24,8 +24,8 @@ PUBLIC int fs_newnode(message *fs_m_in, message *fs_m_out) if( (rip = alloc_inode(dev, bits) ) == NULL) return(err_code); switch (bits & S_IFMT) { - case S_IFBLK: - case S_IFCHR: + case S_IFBLK: + case S_IFCHR: rip->i_rdev = dev; /* Major/minor dev numbers */ break; case S_IFIFO: @@ -50,4 +50,3 @@ PUBLIC int fs_newnode(message *fs_m_in, message *fs_m_out) return(r); } - diff --git a/servers/pfs/proto.h b/servers/pfs/proto.h index d6465e0ac..210e9d1d4 100644 --- a/servers/pfs/proto.h +++ b/servers/pfs/proto.h @@ -39,6 +39,9 @@ _PROTOTYPE( void reply, (endpoint_t who, message *m_out) ); /* misc.c */ _PROTOTYPE( int fs_sync, (message *fs_m_in, message *fs_m_out) ); +/* mount.c */ +_PROTOTYPE( int fs_unmount, (message *fs_m_in, message *fs_m_out) ); + /* open.c */ _PROTOTYPE( int fs_newnode, (message *fs_m_in, message *fs_m_out) ); @@ -63,7 +66,7 @@ _PROTOTYPE( int uds_read, (message *dev_m_in, message *dev_m_out) ); _PROTOTYPE( int uds_write, (message *dev_m_in, message *dev_m_out) ); _PROTOTYPE( int uds_ioctl, (message *dev_m_in, message *dev_m_out) ); _PROTOTYPE( int uds_select, (message *dev_m_in, message *dev_m_out) ); -_PROTOTYPE( int uds_status, (message *dev_m_in, message *dev_m_out) ); +_PROTOTYPE( int uds_unsuspend, (endpoint_t m_source, int minor) ); _PROTOTYPE( int uds_cancel, (message *dev_m_in, message *dev_m_out) ); /* uds.c */ @@ -97,8 +100,8 @@ _PROTOTYPE( int do_recvfrom, (message *dev_m_in, message *dev_m_out) ); _PROTOTYPE( int do_sendmsg, (message *dev_m_in, message *dev_m_out) ); _PROTOTYPE( int do_recvmsg, (message *dev_m_in, message *dev_m_out) ); _PROTOTYPE( int perform_connection, - (message *dev_m_in, message *dev_m_out, - struct sockaddr_un *addr, int minorx, + (message *dev_m_in, message *dev_m_out, + struct sockaddr_un *addr, int minorx, int minory) ); _PROTOTYPE( int clear_fds, (int minor, struct ancillary *data) ); #endif diff --git a/servers/pfs/read.c b/servers/pfs/read.c index 3a6579f0a..b4f06b846 100644 --- a/servers/pfs/read.c +++ b/servers/pfs/read.c @@ -28,8 +28,8 @@ PUBLIC int fs_readwrite(message *fs_m_in, message *fs_m_out) mode_word = rip->i_mode & I_TYPE; if (mode_word != I_NAMED_PIPE) return(EIO); f_size = rip->i_size; - - /* Get the values from the request message */ + + /* Get the values from the request message */ rw_flag = (fs_m_in->m_type == REQ_READ ? READING : WRITING); gid = (cp_grant_id_t) fs_m_in->REQ_GRANT; position = fs_m_in->REQ_SEEK_POS_LO; @@ -37,7 +37,7 @@ PUBLIC int fs_readwrite(message *fs_m_in, message *fs_m_out) /* We can't read beyond the max file position */ if (nrbytes > MAX_FILE_POS) return(EFBIG); - + if (rw_flag == WRITING) { /* Check in advance to see if file will grow too big. */ /* Casting nrbytes to signed is safe, because it's guaranteed not to @@ -66,7 +66,7 @@ PUBLIC int fs_readwrite(message *fs_m_in, message *fs_m_out) fs_m_out->RES_SEEK_POS_LO = position; /* It might change later and the VFS has to know this value */ - + /* On write, update file size and access time. */ if (rw_flag == WRITING) { if (position > f_size) rip->i_size = position; @@ -87,4 +87,3 @@ PUBLIC int fs_readwrite(message *fs_m_in, message *fs_m_out) return(r); } - diff --git a/servers/pfs/stadir.c b/servers/pfs/stadir.c index 345d24ec9..7a49caff5 100644 --- a/servers/pfs/stadir.c +++ b/servers/pfs/stadir.c @@ -48,8 +48,8 @@ PRIVATE int stat_inode( /* Copy the struct to user space. */ r = sys_safecopyto(who_e, gid, (vir_bytes) 0, (vir_bytes) &statbuf, - (size_t) sizeof(statbuf), D); - + (size_t) sizeof(statbuf), D); + return(r); } @@ -63,9 +63,8 @@ PUBLIC int fs_stat(message *fs_m_in, message *fs_m_out) register struct inode *rip; /* target inode */ if( (rip = find_inode(fs_m_in->REQ_INODE_NR)) == NULL) return(EINVAL); - get_inode(rip->i_dev, rip->i_num); /* mark inode in use */ + get_inode(rip->i_dev, rip->i_num); /* mark inode in use */ r = stat_inode(rip, fs_m_in->m_source, (cp_grant_id_t) fs_m_in->REQ_GRANT); put_inode(rip); /* release the inode */ return(r); } - diff --git a/servers/pfs/super.c b/servers/pfs/super.c index 84559cc1c..50f4e0ba5 100644 --- a/servers/pfs/super.c +++ b/servers/pfs/super.c @@ -20,7 +20,7 @@ PUBLIC bit_t alloc_bit(void) { /* Allocate a bit from a bit map and return its bit number. */ - bitchunk_t *wptr, *wlim; + bitchunk_t *wptr, *wlim; bit_t b; unsigned int i, bcount; @@ -28,24 +28,24 @@ PUBLIC bit_t alloc_bit(void) wlim = &inodemap[bcount]; /* Point to last chunk in inodemap. */ for (wptr = &inodemap[0]; wptr < wlim; wptr++) { - /* Does this word contain a free bit? */ - if (*wptr == (bitchunk_t) ~0) continue; /* No. Go to next word */ + /* Does this word contain a free bit? */ + if (*wptr == (bitchunk_t) ~0) continue; /* No. Go to next word */ - /* Find and allocate the free bit. */ - for (i = 0; (*wptr & (1 << i)) != 0; ++i) {} + /* Find and allocate the free bit. */ + for (i = 0; (*wptr & (1 << i)) != 0; ++i) {} /* Get inode number */ - b = (bit_t) ((wptr - &inodemap[0]) * FS_BITCHUNK_BITS + i); - - /* Don't allocate bits beyond end of map. */ - if (b >= NR_INODES) break; + b = (bit_t) ((wptr - &inodemap[0]) * FS_BITCHUNK_BITS + i); - /* Allocate and return bit number. */ - *wptr |= 1 << i; + /* Don't allocate bits beyond end of map. */ + if (b >= NR_INODES) break; + + /* Allocate and return bit number. */ + *wptr |= 1 << i; /* Mark server 'busy' */ busy++; - return(b); + return(b); } return(NO_BIT); /* no bit could be allocated */ @@ -73,5 +73,3 @@ bit_t bit_returned; /* number of bit to insert into the inode map*/ busy--; /* One inode less in use. */ } - - diff --git a/servers/pfs/table.c b/servers/pfs/table.c index 95e5c5a40..760e5b21e 100644 --- a/servers/pfs/table.c +++ b/servers/pfs/table.c @@ -29,7 +29,7 @@ PUBLIC _PROTOTYPE (int (*fs_call_vec[]), no_sys, /* 12 */ no_sys, /* 13 */ no_sys, /* 14 */ - no_sys, /* 15 */ + fs_unmount, /* 15 */ fs_sync, /* 16 */ no_sys, /* 17 */ no_sys, /* 18 */ @@ -53,30 +53,30 @@ PUBLIC _PROTOTYPE (int (*fs_call_vec[]), PUBLIC _PROTOTYPE (int (*dev_call_vec[]), (message *dev_m_in, message *dev_m_out) ) = { - uds_cancel, /* 0 */ + uds_cancel, /* 0 CANCEL */ no_sys, /* 1 */ no_sys, /* 2 */ no_sys, /* 3 */ no_sys, /* 4 */ no_sys, /* 5 */ - uds_open, /* 6 */ - uds_close, /* 7 */ + uds_open, /* 6 DEV_OPEN */ + uds_close, /* 7 DEV_CLOSE */ no_sys, /* 8 */ no_sys, /* 9 */ - no_sys, /* 10 */ - no_sys, /* 11 */ - uds_select, /* 12 */ - uds_status, /* 13 */ - uds_open, /* 14 */ + no_sys, /* 10 TTY_SETPGRP */ + no_sys, /* 11 TTY_EXIT */ + uds_select, /* 12 DEV_SELECT */ + no_sys, /* 13 DEV_STATUS */ + uds_open, /* 14 DEV_REOPEN */ no_sys, /* 15 */ no_sys, /* 16 */ no_sys, /* 17 */ no_sys, /* 18 */ no_sys, /* 19 */ - uds_read, /* 20 */ - uds_write, /* 21 */ - no_sys, /* 22 */ - no_sys, /* 23 */ - uds_ioctl, /* 24 */ - no_sys, /* 25 */ + uds_read, /* 20 DEV_READ_S */ + uds_write, /* 21 DEV_WRITE_S */ + no_sys, /* 22 DEV_SCATTER_S */ + no_sys, /* 23 DEV_GATHER_S */ + uds_ioctl, /* 24 DEV_IOCTL_S */ + no_sys, /* 25 DEV_MMAP_S */ }; diff --git a/servers/pfs/uds.c b/servers/pfs/uds.c index 7a1309cf4..18c70e103 100644 --- a/servers/pfs/uds.c +++ b/servers/pfs/uds.c @@ -47,7 +47,7 @@ uds_fd_t uds_fd_table[NR_FDS]; PUBLIC void uds_init(void) { /* - * Setting everything to NULL implicitly sets the + * Setting everything to NULL implicitly sets the * state to UDS_FREE. */ memset(uds_fd_table, '\0', sizeof(uds_fd_t) * NR_FDS); @@ -74,7 +74,7 @@ PRIVATE int check_perms(int minor, struct sockaddr_un *addr) rc = sendrec(VFS_PROC_NR, &vfs_m); cpf_revoke(grant_id); if (OK != rc) { - printf("(uds) sendrec error... req_nr: %d err: %d\n", + printf("(uds) sendrec error... req_nr: %d err: %d\n", vfs_m.m_type, rc); return EIO; @@ -95,7 +95,7 @@ PRIVATE filp_id_t verify_fd(endpoint_t ep, int fd) #if DEBUG == 1 static int call_count = 0; - printf("(uds) verify_fd(%d,%d) call_count=%d\n", ep, fd, + printf("(uds) verify_fd(%d,%d) call_count=%d\n", ep, fd, ++call_count); #endif @@ -107,7 +107,7 @@ PRIVATE filp_id_t verify_fd(endpoint_t ep, int fd) rc = sendrec(VFS_PROC_NR, &vfs_m); if (OK != rc) { - printf("(uds) sendrec error... req_nr: %d err: %d\n", + printf("(uds) sendrec error... req_nr: %d err: %d\n", vfs_m.m_type, rc); return NULL; } @@ -136,7 +136,7 @@ PRIVATE int set_filp(filp_id_t sfilp) rc = sendrec(VFS_PROC_NR, &vfs_m); if (OK != rc) { - printf("(uds) sendrec error... req_nr: %d err: %d\n", + printf("(uds) sendrec error... req_nr: %d err: %d\n", vfs_m.m_type, rc); return EIO; } @@ -154,7 +154,7 @@ PRIVATE int copy_filp(endpoint_t to_ep, filp_id_t cfilp) #if DEBUG == 1 static int call_count = 0; - printf("(uds) copy_filp(%d, 0x%x) call_count=%d\n",to_ep, cfilp, + printf("(uds) copy_filp(%d, 0x%x) call_count=%d\n",to_ep, cfilp, ++call_count); #endif @@ -166,7 +166,7 @@ PRIVATE int copy_filp(endpoint_t to_ep, filp_id_t cfilp) rc = sendrec(VFS_PROC_NR, &vfs_m); if (OK != rc) { - printf("(uds) sendrec error... req_nr: %d err: %d\n", + printf("(uds) sendrec error... req_nr: %d err: %d\n", vfs_m.m_type, rc); return EIO; } @@ -194,7 +194,7 @@ PRIVATE int put_filp(filp_id_t pfilp) rc = sendrec(VFS_PROC_NR, &vfs_m); if (OK != rc) { - printf("(uds) sendrec error... req_nr: %d err: %d\n", + printf("(uds) sendrec error... req_nr: %d err: %d\n", vfs_m.m_type, rc); return EIO; } @@ -223,7 +223,7 @@ PRIVATE int cancel_fd(endpoint_t ep, int fd) rc = sendrec(VFS_PROC_NR, &vfs_m); if (OK != rc) { - printf("(uds) sendrec error... req_nr: %d err: %d\n", + printf("(uds) sendrec error... req_nr: %d err: %d\n", vfs_m.m_type, rc); return EIO; } @@ -234,7 +234,7 @@ PRIVATE int cancel_fd(endpoint_t ep, int fd) return vfs_m.m_type; /* return reply code OK, ELOOP, etc. */ } -PUBLIC int perform_connection(message *dev_m_in, message *dev_m_out, +PUBLIC int perform_connection(message *dev_m_in, message *dev_m_out, struct sockaddr_un *addr, int minorx, int minory) { /* there are several places were a connection is established. */ @@ -244,14 +244,14 @@ PUBLIC int perform_connection(message *dev_m_in, message *dev_m_out, #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] perform_connection() call_count=%d\n", + printf("(uds) [%d] perform_connection() call_count=%d\n", uds_minor(dev_m_in), ++call_count); #endif - /* only connection oriented types are acceptable and only like + /* only connection oriented types are acceptable and only like * types can connect to each other */ - if ((uds_fd_table[minorx].type != SOCK_SEQPACKET && + if ((uds_fd_table[minorx].type != SOCK_SEQPACKET && uds_fd_table[minorx].type != SOCK_STREAM) || uds_fd_table[minorx].type != uds_fd_table[minory].type) { @@ -281,16 +281,16 @@ PUBLIC int do_accept(message *dev_m_in, message *dev_m_out) #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] do_accept() call_count=%d\n", + printf("(uds) [%d] do_accept() call_count=%d\n", uds_minor(dev_m_in), ++call_count); #endif - /* Somewhat weird logic is used in this function, so here's an - * overview... The minor number is the server's client socket - * (the socket to be returned by accept()). The data waiting - * for us in the IO Grant is the address that the server is - * listening on. This function uses the address to find the - * server's descriptor. From there we can perform the + /* Somewhat weird logic is used in this function, so here's an + * overview... The minor number is the server's client socket + * (the socket to be returned by accept()). The data waiting + * for us in the IO Grant is the address that the server is + * listening on. This function uses the address to find the + * server's descriptor. From there we can perform the * connection or suspend and wait for a connect(). */ @@ -316,7 +316,7 @@ PUBLIC int do_accept(message *dev_m_in, message *dev_m_out) for (i = 0; i < NR_FDS; i++) { if (uds_fd_table[i].addr.sun_family == AF_UNIX && - !strncmp(addr.sun_path, + !strncmp(addr.sun_path, uds_fd_table[i].addr.sun_path, UNIX_PATH_MAX) && uds_fd_table[i].listening == 1) { @@ -327,7 +327,7 @@ PUBLIC int do_accept(message *dev_m_in, message *dev_m_out) } if (rc == -1) { - /* there is no server listening on addr. Maybe someone + /* there is no server listening on addr. Maybe someone * screwed up the ioctl()? */ return EINVAL; @@ -338,7 +338,7 @@ PUBLIC int do_accept(message *dev_m_in, message *dev_m_out) /* we are the parent's child */ uds_fd_table[minorparent].child = minor; - /* the peer has the same type as the parent. we need to be that + /* the peer has the same type as the parent. we need to be that * type too. */ uds_fd_table[minor].type = uds_fd_table[minorparent].type; @@ -360,7 +360,7 @@ PUBLIC int do_accept(message *dev_m_in, message *dev_m_out) printf("(uds) [%d] {do_accept} suspend\n", minor); #endif - /* there are no peers in the backlog, suspend and wait + /* there are no peers in the backlog, suspend and wait * for some to show up */ uds_fd_table[minor].suspended = UDS_SUSPENDED_ACCEPT; @@ -369,7 +369,7 @@ PUBLIC int do_accept(message *dev_m_in, message *dev_m_out) } #if DEBUG == 1 - printf("(uds) [%d] connecting to %d -- parent is %d\n", minor, + printf("(uds) [%d] connecting to %d -- parent is %d\n", minor, minorpeer, minorparent); #endif @@ -387,11 +387,11 @@ PUBLIC int do_accept(message *dev_m_in, message *dev_m_out) /* if peer is blocked on connect() revive peer */ if (uds_fd_table[minorpeer].suspended) { #if DEBUG == 1 - printf("(uds) [%d] {do_accept} revive %d\n", minor, + printf("(uds) [%d] {do_accept} revive %d\n", minor, minorpeer); #endif uds_fd_table[minorpeer].ready_to_revive = 1; - notify(dev_m_in->m_source); + uds_unsuspend(dev_m_in->m_source, minorpeer); } return OK; @@ -423,7 +423,7 @@ PUBLIC int do_connect(message *dev_m_in, message *dev_m_out) } rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &addr, + (vir_bytes) 0, (vir_bytes) &addr, sizeof(struct sockaddr_un), D); if (rc != OK) { @@ -436,7 +436,7 @@ PUBLIC int do_connect(message *dev_m_in, message *dev_m_out) return rc; } - /* look for a socket of the same type that is listening on the + /* look for a socket of the same type that is listening on the * address we want to connect to */ for (i = 0; i < NR_FDS; i++) { @@ -466,7 +466,7 @@ PUBLIC int do_connect(message *dev_m_in, message *dev_m_out) /* wake the parent (server) */ uds_fd_table[i].ready_to_revive = 1; - notify(dev_m_in->m_source); + uds_unsuspend(dev_m_in->m_source, i); } return rc; @@ -504,26 +504,24 @@ PUBLIC int do_connect(message *dev_m_in, message *dev_m_out) /* see if the server is blocked on select() */ if (uds_fd_table[i].selecting == 1) { - /* if the server wants to know - * about data ready to read and - * it doesn't know about it + /* if the server wants to know + * about data ready to read and + * it doesn't know about it * already, then let the server * know we have data for it. */ - if ((uds_fd_table[i].sel_ops_in & - SEL_RD) && + if ((uds_fd_table[i].sel_ops_in & + SEL_RD) && !(uds_fd_table[i].sel_ops_out & SEL_RD)) { uds_fd_table[i].sel_ops_out |= SEL_RD; - uds_fd_table[i].status_updated = 1; - notify( - uds_fd_table[i].select_proc - ); + uds_unsuspend( + dev_m_in->m_source, i); } } @@ -540,7 +538,7 @@ PUBLIC int do_connect(message *dev_m_in, message *dev_m_out) } if (uds_fd_table[minor].peer == -1) { - /* could not find another open socket listening on the + /* could not find another open socket listening on the * specified address with room in the backlog */ return ECONNREFUSED; @@ -580,7 +578,7 @@ PUBLIC int do_listen(message *dev_m_in, message *dev_m_out) return EINVAL; } - /* the two supported types for listen(2) are SOCK_STREAM and + /* the two supported types for listen(2) are SOCK_STREAM and * SOCK_SEQPACKET */ if (uds_fd_table[minor].type != SOCK_STREAM && @@ -590,9 +588,9 @@ PUBLIC int do_listen(message *dev_m_in, message *dev_m_out) return EOPNOTSUPP; } - /* The POSIX standard doesn't say what to do if listen() has - * already been called. Well, there isn't an errno. we silently - * let it happen, but if listen() has already been called, we + /* The POSIX standard doesn't say what to do if listen() has + * already been called. Well, there isn't an errno. we silently + * let it happen, but if listen() has already been called, we * don't allow the backlog to shrink */ rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, @@ -612,7 +610,7 @@ PUBLIC int do_listen(message *dev_m_in, message *dev_m_out) } else { - /* the user gave an invalid size, use + /* the user gave an invalid size, use * UDS_SOMAXCONN instead */ uds_fd_table[minor].backlog_size = UDS_SOMAXCONN; @@ -627,7 +625,7 @@ PUBLIC int do_listen(message *dev_m_in, message *dev_m_out) uds_fd_table[minor].backlog_size = backlog_size; } - /* Don't let the user shrink the backlog_size (we might + /* Don't let the user shrink the backlog_size (we might * have clients waiting in those slots */ } @@ -679,7 +677,7 @@ PUBLIC int do_socket(message *dev_m_in, message *dev_m_out) default: - /* if the type isn't one of the 3 valid socket + /* if the type isn't one of the 3 valid socket * types, then it must be invalid. */ @@ -715,7 +713,7 @@ PUBLIC int do_bind(message *dev_m_in, message *dev_m_out) } rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &addr, sizeof(struct sockaddr_un), + (vir_bytes) 0, (vir_bytes) &addr, sizeof(struct sockaddr_un), D); if (rc != OK) { @@ -744,7 +742,7 @@ PUBLIC int do_bind(message *dev_m_in, message *dev_m_out) /* make sure the address isn't already in use by another socket. */ for (i = 0; i < NR_FDS; i++) { if ((uds_fd_table[i].addr.sun_family == AF_UNIX) && - !strncmp(addr.sun_path, + !strncmp(addr.sun_path, uds_fd_table[i].addr.sun_path, UNIX_PATH_MAX)) { /* another socket is bound to this sun_path */ @@ -772,13 +770,13 @@ PUBLIC int do_getsockname(message *dev_m_in, message *dev_m_out) minor = uds_minor(dev_m_in); /* Unconditionally send the address we have assigned to this socket. - * The POSIX standard doesn't say what to do if the address - * hasn't been set. If the address isn't currently set, then - * the user will get NULL bytes. Note: libc depends on this + * The POSIX standard doesn't say what to do if the address + * hasn't been set. If the address isn't currently set, then + * the user will get NULL bytes. Note: libc depends on this * behavior. */ rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].addr), + (vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].addr), sizeof(struct sockaddr_un), D); return rc ? EIO : OK; @@ -867,7 +865,7 @@ PUBLIC int do_shutdown(message *dev_m_in, message *dev_m_out) case SHUT_WR: /* take away write permission */ - uds_fd_table[minor].mode = + uds_fd_table[minor].mode = uds_fd_table[minor].mode ^ S_IWUSR; break; @@ -1000,7 +998,7 @@ PUBLIC int do_getsockopt_sotype(message *dev_m_in, message *dev_m_out) } rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].type), + (vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].type), sizeof(int), D); return rc ? EIO : OK; @@ -1095,7 +1093,7 @@ PUBLIC int do_getsockopt_peercred_old(message *dev_m_in, message *dev_m_out) return rc ? EIO : OK; } -int do_getsockopt_sndbuf(message *dev_m_in, message *dev_m_out) +int do_getsockopt_sndbuf(message *dev_m_in, message *dev_m_out) { int minor; int rc; @@ -1110,13 +1108,13 @@ int do_getsockopt_sndbuf(message *dev_m_in, message *dev_m_out) minor = uds_minor(dev_m_in); rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &(sndbuf), + (vir_bytes) 0, (vir_bytes) &(sndbuf), sizeof(size_t), D); return rc ? EIO : OK; } -int do_setsockopt_sndbuf(message *dev_m_in, message *dev_m_out) +int do_setsockopt_sndbuf(message *dev_m_in, message *dev_m_out) { int minor; int rc; @@ -1132,7 +1130,7 @@ int do_setsockopt_sndbuf(message *dev_m_in, message *dev_m_out) rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &sndbuf, + (vir_bytes) 0, (vir_bytes) &sndbuf, sizeof(size_t), D); if (rc != OK) { @@ -1150,7 +1148,7 @@ int do_setsockopt_sndbuf(message *dev_m_in, message *dev_m_out) return OK; } -int do_getsockopt_rcvbuf(message *dev_m_in, message *dev_m_out) +int do_getsockopt_rcvbuf(message *dev_m_in, message *dev_m_out) { int minor; int rc; @@ -1165,7 +1163,7 @@ int do_getsockopt_rcvbuf(message *dev_m_in, message *dev_m_out) minor = uds_minor(dev_m_in); rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &(rcvbuf), + (vir_bytes) 0, (vir_bytes) &(rcvbuf), sizeof(size_t), D); return rc ? EIO : OK; @@ -1187,7 +1185,7 @@ int do_setsockopt_rcvbuf(message *dev_m_in, message *dev_m_out) rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &rcvbuf, + (vir_bytes) 0, (vir_bytes) &rcvbuf, sizeof(size_t), D); if (rc != OK) { @@ -1264,7 +1262,7 @@ PUBLIC int do_recvfrom(message *dev_m_in, message *dev_m_out) minor = uds_minor(dev_m_in); rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].source), + (vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].source), sizeof(struct sockaddr_un), D); return rc ? EIO : OK; @@ -1279,7 +1277,7 @@ int msg_control_read(struct msg_control *msg_ctrl, struct ancillary *data, #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] msg_control_read() call_count=%d\n", minor, + printf("(uds) [%d] msg_control_read() call_count=%d\n", minor, ++call_count); #endif @@ -1366,8 +1364,8 @@ PRIVATE int send_fds(int minor, struct ancillary *data) PUBLIC int clear_fds(int minor, struct ancillary *data) { /* This function calls put_filp() for all of the FDs in data. - * This is used when a Unix Domain Socket is closed and there - * exists references to file descriptors that haven't been received + * This is used when a Unix Domain Socket is closed and there + * exists references to file descriptors that haven't been received * with recvmsg(). */ int i; @@ -1536,12 +1534,12 @@ PUBLIC int do_sendmsg(message *dev_m_in, message *dev_m_out) #if DEBUG == 1 printf("(uds) [%d] sendmsg() -- peer=%d\n", minor, peer); #endif - /* note: it's possible that there is already some file + /* note: it's possible that there is already some file * descriptors in ancillary_data if the peer didn't call * recvmsg() yet. That's okay. The receiver will * get the current file descriptors plus the new ones. */ - rc = msg_control_read(&msg_ctrl, &uds_fd_table[peer].ancillary_data, + rc = msg_control_read(&msg_ctrl, &uds_fd_table[peer].ancillary_data, minor); if (rc != OK) { return rc; @@ -1591,7 +1589,7 @@ PUBLIC int do_recvmsg(message *dev_m_in, message *dev_m_out) controllen_avail = MIN(msg_ctrl.msg_controllen, MSG_CONTROL_MAX); if (uds_fd_table[minor].ancillary_data.nfiledes > 0) { - controllen_needed = CMSG_LEN(sizeof(int) * + controllen_needed = CMSG_LEN(sizeof(int) * (uds_fd_table[minor].ancillary_data.nfiledes)); } @@ -1618,7 +1616,7 @@ PUBLIC int do_recvmsg(message *dev_m_in, message *dev_m_out) /* send the user the control data */ rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &msg_ctrl, + (vir_bytes) 0, (vir_bytes) &msg_ctrl, sizeof(struct msg_control), D); return rc ? EIO : OK; diff --git a/servers/pfs/uds.h b/servers/pfs/uds.h index facfdbc33..efcb9c1da 100644 --- a/servers/pfs/uds.h +++ b/servers/pfs/uds.h @@ -43,8 +43,8 @@ struct uds_fd { /* OR it is UDS_INUSE and can't be allocated. */ UDS_INUSE = 1 - /* state is set to UDS_INUSE in uds_open(). state is Set to - * UDS_FREE in uds_init() and uds_close(). state should be + /* state is set to UDS_INUSE in uds_open(). state is Set to + * UDS_FREE in uds_init() and uds_close(). state should be * checked prior to all operations. */ } state; @@ -103,7 +103,7 @@ struct uds_fd { unsigned char backlog_size; /* index of peer in uds_fd_table for connected sockets. - * -1 is used to mean no peer. Assumptions: peer != -1 means + * -1 is used to mean no peer. Assumptions: peer != -1 means * connected. */ int peer; @@ -131,7 +131,7 @@ struct uds_fd { */ int listening; - /* stores file pointers and credentials being sent between + /* stores file pointers and credentials being sent between * processes with sendmsg(2) and recvmsg(2). */ struct ancillary ancillary_data; @@ -144,7 +144,7 @@ struct uds_fd { /* Suspend/Revive Housekeeping */ - + /* SUSPEND State Flags */ enum UDS_SUSPENDED { @@ -232,11 +232,20 @@ EXTERN uds_fd_t uds_fd_table[NR_FDS]; */ #define uds_set_reply(msg,type,endpoint,io_gr,status) \ do { \ - msg->m_type = type; \ - msg->REP_ENDPT = endpoint; \ - msg->REP_IO_GRANT = io_gr; \ - msg->REP_STATUS = status; \ + (msg)->m_type = type; \ + (msg)->REP_ENDPT = endpoint; \ + (msg)->REP_IO_GRANT = io_gr; \ + (msg)->REP_STATUS = status; \ + } while (0) + +#define uds_sel_reply(msg,type,minor,ops) \ + do { \ + (msg)->m_type = type; \ + (msg)->DEV_MINOR = minor; \ + (msg)->DEV_SEL_OPS = ops; \ } while (0) + + #endif diff --git a/servers/pfs/utility.c b/servers/pfs/utility.c index b4bd955f1..fac9ec625 100644 --- a/servers/pfs/utility.c +++ b/servers/pfs/utility.c @@ -28,7 +28,6 @@ PUBLIC time_t clock_time() if ((r = getuptime2(&uptime, &boottime)) != OK) panic("clock_time: getuptme2 failed: %d", r); - + return( (time_t) (boottime + (uptime/sys_hz()))); } - diff --git a/servers/procfs/Makefile b/servers/procfs/Makefile index 5836e8dab..6c233fd6b 100644 --- a/servers/procfs/Makefile +++ b/servers/procfs/Makefile @@ -8,10 +8,6 @@ SRCS= buf.c main.c pid.c root.c tree.c util.c cpuinfo.c CPPFLAGS+= -I${MINIXSRCDIR} -I${MINIXSRCDIR}/servers -.if ${BUILDAVFS} == "yes" -CFLAGS+= -D_USEAVFS -.endif - DPADD+= ${LIBVTREEFS} ${LIBSYS} LDADD+= -lvtreefs -lsys diff --git a/servers/procfs/inc.h b/servers/procfs/inc.h index f1c0b8851..7a10ab571 100644 --- a/servers/procfs/inc.h +++ b/servers/procfs/inc.h @@ -50,15 +50,9 @@ #include "kernel/type.h" #include "kernel/proc.h" #include "pm/mproc.h" -#if defined(_USEAVFS) -# include "avfs/const.h" -# include "avfs/fproc.h" -# include "avfs/dmap.h" -#else -# include "vfs/const.h" -# include "vfs/fproc.h" -# include "vfs/dmap.h" -#endif +#include "vfs/const.h" +#include "vfs/fproc.h" +#include "vfs/dmap.h" #include #include diff --git a/servers/vfs/Makefile b/servers/vfs/Makefile index 1dc905723..ec0553f98 100644 --- a/servers/vfs/Makefile +++ b/servers/vfs/Makefile @@ -6,15 +6,20 @@ SRCS= main.c open.c read.c write.c pipe.c dmap.c \ path.c device.c mount.c link.c exec.c \ filedes.c stadir.c protect.c time.c \ lock.c misc.c utility.c select.c table.c \ - vnode.c vmnt.c request.c fscall.c elf_core_dump.c + vnode.c vmnt.c request.c fscall.c \ + tll.c comm.c worker.c coredump.c .if ${MKCOVERAGE} != "no" -SRCS+= gcov.c +SRCS+= gcov.c CPPFLAGS+= -DUSE_COVERAGE .endif DPADD+= ${LIBSYS} ${LIBTIMERS} ${LIBEXEC} -LDADD+= -lsys -ltimers -lexec +LDADD+= -lsys -ltimers -lexec -lmthread + +.if ${COMPILER_TYPE} == "gnu" +LDADD+= -lc +.endif MAN= diff --git a/servers/avfs/comm.c b/servers/vfs/comm.c similarity index 100% rename from servers/avfs/comm.c rename to servers/vfs/comm.c diff --git a/servers/avfs/comm.h b/servers/vfs/comm.h similarity index 100% rename from servers/avfs/comm.h rename to servers/vfs/comm.h diff --git a/servers/vfs/const.h b/servers/vfs/const.h index 0c4de2dd6..44a339d7c 100644 --- a/servers/vfs/const.h +++ b/servers/vfs/const.h @@ -1,8 +1,12 @@ +#ifndef __VFS_CONST_H__ +#define __VFS_CONST_H__ + /* Tables sizes */ #define NR_FILPS 512 /* # slots in filp table */ #define NR_LOCKS 8 /* # slots in the file locking table */ -#define NR_MNTS 16 /* # slots in mount table */ -#define NR_VNODES 512 /* # slots in vnode table */ +#define NR_MNTS 16 /* # slots in mount table */ +#define NR_VNODES 512 /* # slots in vnode table */ +#define NR_WTHREADS 8 /* # slots in worker thread table */ #define NR_NONEDEVS NR_MNTS /* # slots in nonedev bitmap */ @@ -17,7 +21,7 @@ #define FP_BLOCKED_ON_POPEN 3 /* susp'd on pipe open */ #define FP_BLOCKED_ON_SELECT 4 /* susp'd on select */ #define FP_BLOCKED_ON_DOPEN 5 /* susp'd on device open */ -#define FP_BLOCKED_ON_OTHER 6 /* blocked on other process, check +#define FP_BLOCKED_ON_OTHER 6 /* blocked on other process, check fp_task to find out */ /* test if the process is blocked on something */ @@ -28,7 +32,7 @@ #define LOOK_UP 0 /* tells search_dir to lookup string */ #define ENTER 1 /* tells search_dir to make dir entry */ #define DELETE 2 /* tells search_dir to delete entry */ -#define IS_EMPTY 3 /* tells search_dir to ret. OK or ENOTEMPTY */ +#define IS_EMPTY 3 /* tells search_dir to ret. OK or ENOTEMPTY */ #define SYMLOOP 16 @@ -40,7 +44,7 @@ /* Args to dev_io */ #define VFS_DEV_READ 2001 #define VFS_DEV_WRITE 2002 -#define VFS_DEV_SCATTER 2003 -#define VFS_DEV_GATHER 2004 #define VFS_DEV_IOCTL 2005 #define VFS_DEV_SELECT 2006 + +#endif diff --git a/servers/avfs/coredump.c b/servers/vfs/coredump.c similarity index 100% rename from servers/avfs/coredump.c rename to servers/vfs/coredump.c diff --git a/servers/vfs/device.c b/servers/vfs/device.c index 14f7370d1..926cf322a 100644 --- a/servers/vfs/device.c +++ b/servers/vfs/device.c @@ -16,8 +16,8 @@ * tty_opcl: perform tty-specific processing for open/close * ctty_opcl: perform controlling-tty-specific processing for open/close * ctty_io: perform controlling-tty-specific processing for I/O + * pm_setsid: perform VFS's side of setsid system call * do_ioctl: perform the IOCTL system call - * do_setsid: perform the SETSID system call (FS side) */ #include "fs.h" @@ -32,22 +32,19 @@ #include #include "file.h" #include "fproc.h" +#include "scratchpad.h" +#include "dmap.h" #include #include "vnode.h" #include "vmnt.h" #include "param.h" -#define ELEMENTS(a) (sizeof(a)/sizeof((a)[0])) - +FORWARD _PROTOTYPE( void restart_reopen, (int major) ); FORWARD _PROTOTYPE( int safe_io_conversion, (endpoint_t, cp_grant_id_t *, - int *, cp_grant_id_t *, int, - endpoint_t *, void **, int *, - vir_bytes, u32_t *) ); -FORWARD _PROTOTYPE( void safe_io_cleanup, (cp_grant_id_t, cp_grant_id_t *, - int) ); -FORWARD _PROTOTYPE( void restart_reopen, (int maj) ); + int *, + endpoint_t *, void **, + size_t, u32_t *) ); -extern int dmap_size; PRIVATE int dummyproc; @@ -56,23 +53,21 @@ PRIVATE int dummyproc; *===========================================================================*/ PUBLIC int dev_open( dev_t dev, /* device to open */ - int proc, /* process to open for */ + endpoint_t proc_e, /* process to open for */ int flags /* mode bits and flags */ ) { /* Open a character device. */ int major, r; - struct dmap *dp; /* Determine the major device number so as to call the device class specific * open/close routine. (This is the only routine that must check the * device number for being in range. All others can trust this check.) */ - major = (dev >> MAJOR) & BYTE; - if (major >= NR_DEVICES) major = 0; - dp = &dmap[major]; - if (dp->dmap_driver == NONE) return(ENXIO); - r = (*dp->dmap_opcl)(DEV_OPEN, dev, proc, flags); + major = major(dev); + if (major < 0 || major >= NR_DEVICES) major = 0; + if (dmap[major].dmap_driver == NONE) return(ENXIO); + r = (*dmap[major].dmap_opcl)(DEV_OPEN, dev, proc_e, flags); return(r); } @@ -87,19 +82,20 @@ PUBLIC int dev_reopen( ) { /* Reopen a character device after a failing device driver. */ + int major, r; struct dmap *dp; - /* Determine the major device number call the device class specific - * open/close routine. (This is the only routine that must check the - * device number for being in range. All others can trust this check.) + /* Determine the major device number and call the device class specific + * open/close routine. (This is the only routine that must check the device + * number for being in range. All others can trust this check.) */ - major = (dev >> MAJOR) & BYTE; - if (major >= NR_DEVICES) major = 0; + + major = major(dev); + if (major < 0 || major >= NR_DEVICES) major = 0; dp = &dmap[major]; if (dp->dmap_driver == NONE) return(ENXIO); r = (*dp->dmap_opcl)(DEV_REOPEN, dev, filp_no, flags); - if (r == OK) panic("OK on reopen from: %d", dp->dmap_driver); if (r == SUSPEND) r = OK; return(r); } @@ -114,17 +110,19 @@ PUBLIC int dev_close( ) { /* Close a character device. */ - int r; + int r, major; /* See if driver is roughly valid. */ - if (dmap[(dev >> MAJOR)].dmap_driver == NONE) return(ENXIO); - r = (*dmap[(dev >> MAJOR) & BYTE].dmap_opcl)(DEV_CLOSE, dev, filp_no, 0); + major = major(dev); + if (major < 0 || major >= NR_DEVICES) return(ENXIO); + if (dmap[major].dmap_driver == NONE) return(ENXIO); + r = (*dmap[major].dmap_opcl)(DEV_CLOSE, dev, filp_no, 0); return(r); } /*===========================================================================* - * bdev_open * + * dev_open * *===========================================================================*/ PUBLIC int bdev_open(dev_t dev, int access) { @@ -165,7 +163,7 @@ PRIVATE int bdev_ioctl(dev_t dev, endpoint_t proc_e, int req, void *buf) u32_t dummy; cp_grant_id_t gid; message dev_mess; - int op, safe, major_dev, minor_dev, vec_grants; + int op, major_dev, minor_dev; major_dev = major(dev); minor_dev = minor(dev); @@ -179,8 +177,8 @@ PRIVATE int bdev_ioctl(dev_t dev, endpoint_t proc_e, int req, void *buf) /* Set up a grant if necessary. */ op = VFS_DEV_IOCTL; - safe = safe_io_conversion(dp->dmap_driver, &gid, &op, NULL, 0, &proc_e, &buf, - &vec_grants, 0, &dummy); + (void) safe_io_conversion(dp->dmap_driver, &gid, &op, &proc_e, &buf, 0, + &dummy); /* Set up the message passed to the task. */ memset(&dev_mess, 0, sizeof(dev_mess)); @@ -195,7 +193,7 @@ PRIVATE int bdev_ioctl(dev_t dev, endpoint_t proc_e, int req, void *buf) (*dp->dmap_io)(dp->dmap_driver, &dev_mess); /* Clean up. */ - if (safe) safe_io_cleanup(gid, NULL, vec_grants); + if (GRANT_VALID(gid)) cpf_revoke(gid); if (dp->dmap_driver == NONE) { printf("VFS: block driver gone!?\n"); @@ -203,27 +201,29 @@ PRIVATE int bdev_ioctl(dev_t dev, endpoint_t proc_e, int req, void *buf) } /* Return the result. */ - return dev_mess.BDEV_STATUS; + return(dev_mess.BDEV_STATUS); } /*===========================================================================* - * suspended_ep * + * find_suspended_ep * *===========================================================================*/ -endpoint_t suspended_ep(endpoint_t driver, cp_grant_id_t g) +endpoint_t find_suspended_ep(endpoint_t driver, cp_grant_id_t g) { -/* A process is suspended on a driver for which FS issued - * a grant. Find out which process it was. +/* A process is suspended on a driver for which VFS issued a grant. Find out + * which process it was. */ struct fproc *rfp; for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - if(rfp->fp_pid == PID_FREE) continue; - if(rfp->fp_blocked_on == FP_BLOCKED_ON_OTHER && - rfp->fp_task == driver && rfp->fp_grant == g) - return rfp->fp_endpoint; - } + if(rfp->fp_pid == PID_FREE) + continue; - return(NONE); + if(rfp->fp_blocked_on == FP_BLOCKED_ON_OTHER && + rfp->fp_task == driver && rfp->fp_grant == g) + return(rfp->fp_endpoint); + } + + return(NONE); } @@ -232,191 +232,136 @@ endpoint_t suspended_ep(endpoint_t driver, cp_grant_id_t g) *===========================================================================*/ PUBLIC void dev_status(message *m) { +/* A device sent us a notification it has something for us. Retrieve it. */ + message st; - int d, get_more = 1; + int major, get_more = 1; endpoint_t endpt; - for(d = 0; d < NR_DEVICES; d++) - if (dmap[d].dmap_driver != NONE && dmap[d].dmap_driver == m->m_source) - break; + for (major = 0; major < NR_DEVICES; major++) + if (dmap_driver_match(m->m_source, major)) + break; /* 'major' is the device that sent the message */ - if (d >= NR_DEVICES) return; - if (dmap[d].dmap_style == STYLE_DEVA) { - printf("dev_status: not doing dev_status for async driver %d\n", - m->m_source); - return; + if (major >= NR_DEVICES) /* Device endpoint not found; nothing to do */ + return; + + if (dmap[major].dmap_style == STYLE_DEVA || + dmap[major].dmap_style == STYLE_CLONE_A) { + printf("VFS: not doing dev_status for async driver %d\n", m->m_source); + return; + } + + /* Continuously send DEV_STATUS messages until the device has nothing to + * say to us anymore. */ + do { + int r; + st.m_type = DEV_STATUS; + r = sendrec(m->m_source, &st); + if (r == OK && st.REP_STATUS == ERESTART) r = EDEADEPT; + if (r != OK) { + printf("VFS: DEV_STATUS failed to %d: %d\n", m->m_source, r); + if (r == EDEADSRCDST || r == EDEADEPT) return; + panic("VFS: couldn't sendrec for DEV_STATUS: %d", r); } - do { - int r; - st.m_type = DEV_STATUS; - r = sendrec(m->m_source, &st); - if(r == OK && st.REP_STATUS == ERESTART) r = EDEADEPT; - if (r != OK) { - printf("DEV_STATUS failed to %d: %d\n", m->m_source, r); - if (r == EDEADSRCDST || r == EDEADEPT) return; - panic("couldn't sendrec for DEV_STATUS: %d", r); + switch(st.m_type) { + case DEV_REVIVE: + /* We've got results for a read/write/ioctl call to a + * synchronous character driver */ + endpt = st.REP_ENDPT; + if (endpt == VFS_PROC_NR) { + endpt = find_suspended_ep(m->m_source,st.REP_IO_GRANT); + if(endpt == NONE) { + printf("VFS: proc with grant %d from %d not found\n", + st.REP_IO_GRANT, st.m_source); + continue; + } } - - switch(st.m_type) { - case DEV_REVIVE: - endpt = st.REP_ENDPT; - if(endpt == VFS_PROC_NR) { - endpt = suspended_ep(m->m_source, - st.REP_IO_GRANT); - if(endpt == NONE) { - printf("FS: proc with grant %d" - " from %d not found (revive)\n", - st.REP_IO_GRANT, st.m_source); - continue; - } - } - revive(endpt, st.REP_STATUS); - break; - case DEV_IO_READY: - select_reply2(st.m_source, st.DEV_MINOR, - st.DEV_SEL_OPS); - break; - default: - printf("FS: unrecognized reply %d to " - "DEV_STATUS\n", st.m_type); - /* Fall through. */ - case DEV_NO_STATUS: - get_more = 0; - break; - } - } while(get_more); - - return; + revive(endpt, st.REP_STATUS); + break; + case DEV_IO_READY: + /* Reply to a select request: driver is ready for I/O */ + select_reply2(st.m_source, st.DEV_MINOR, st.DEV_SEL_OPS); + break; + default: + printf("VFS: unrecognized reply %d to DEV_STATUS\n",st.m_type); + /* Fall through. */ + case DEV_NO_STATUS: + get_more = 0; + break; + } + } while(get_more); } - /*===========================================================================* * safe_io_conversion * *===========================================================================*/ -PRIVATE int safe_io_conversion(driver, gid, op, gids, gids_size, - io_ept, buf, vec_grants, bytes, pos_lo) +PRIVATE int safe_io_conversion(driver, gid, op, io_ept, buf, bytes, pos_lo) endpoint_t driver; cp_grant_id_t *gid; int *op; -cp_grant_id_t *gids; -int gids_size; endpoint_t *io_ept; void **buf; -int *vec_grants; -vir_bytes bytes; +size_t bytes; u32_t *pos_lo; { - int access = 0, size, j; - iovec_t *v; - static iovec_t new_iovec[NR_IOREQS]; +/* Convert operation to the 'safe' variant (i.e., grant based) if applicable. + * If no copying of data is involved, there is also no need to convert. */ - /* Number of grants allocated in vector I/O. */ - *vec_grants = 0; + int access = 0; + size_t size; - /* Driver can handle it - change request to a safe one. */ - *gid = GRANT_INVALID; + *gid = GRANT_INVALID; /* Grant to buffer */ switch(*op) { - case VFS_DEV_READ: - case VFS_DEV_WRITE: - /* Change to safe op. */ - *op = *op == VFS_DEV_READ ? DEV_READ_S : DEV_WRITE_S; - - *gid = cpf_grant_magic(driver, *io_ept, (vir_bytes) *buf, bytes, - *op == DEV_READ_S ? CPF_WRITE : CPF_READ); - if (*gid < 0) - panic("cpf_grant_magic of buffer failed"); - break; - case VFS_DEV_GATHER: - case VFS_DEV_SCATTER: - /* Change to safe op. */ - *op = *op == VFS_DEV_GATHER ? DEV_GATHER_S : DEV_SCATTER_S; - - /* Grant access to my new i/o vector. */ - *gid = cpf_grant_direct(driver, (vir_bytes) new_iovec, - bytes * sizeof(iovec_t), CPF_READ|CPF_WRITE); - if (*gid < 0) - panic("cpf_grant_direct of vector failed"); - - v = (iovec_t *) *buf; - /* Grant access to i/o buffers. */ - for(j = 0; j < bytes; j++) { - if(j >= NR_IOREQS) panic("vec too big: %d", bytes); - - new_iovec[j].iov_addr = - gids[j] = - cpf_grant_direct(driver, (vir_bytes) v[j].iov_addr, v[j].iov_size, - *op == DEV_GATHER_S ? CPF_WRITE : CPF_READ); - - if(!GRANT_VALID(gids[j])) - panic("grant to iovec buf failed"); - - new_iovec[j].iov_size = v[j].iov_size; - (*vec_grants)++; - } - - /* Set user's vector to the new one. */ - *buf = new_iovec; - break; - case VFS_DEV_IOCTL: - *pos_lo = *io_ept; /* Old endpoint in POSITION field. */ - *op = DEV_IOCTL_S; - if(_MINIX_IOCTL_IOR(m_in.REQUEST)) access |= CPF_WRITE; - if(_MINIX_IOCTL_IOW(m_in.REQUEST)) access |= CPF_READ; - if(_MINIX_IOCTL_BIG(m_in.REQUEST)) + case VFS_DEV_READ: + case VFS_DEV_WRITE: + /* Change to safe op. */ + *op = (*op == VFS_DEV_READ) ? DEV_READ_S : DEV_WRITE_S; + *gid = cpf_grant_magic(driver, *io_ept, (vir_bytes) *buf, bytes, + *op == DEV_READ_S ? CPF_WRITE : CPF_READ); + if (*gid < 0) + panic("VFS: cpf_grant_magic of READ/WRITE buffer failed"); + break; + case VFS_DEV_IOCTL: + *pos_lo = *io_ept; /* Old endpoint in POSITION field. */ + *op = DEV_IOCTL_S; + if(_MINIX_IOCTL_IOR(m_in.REQUEST)) access |= CPF_WRITE; + if(_MINIX_IOCTL_IOW(m_in.REQUEST)) access |= CPF_READ; + if(_MINIX_IOCTL_BIG(m_in.REQUEST)) size = _MINIX_IOCTL_SIZE_BIG(m_in.REQUEST); - else + else size = _MINIX_IOCTL_SIZE(m_in.REQUEST); + /* Grant access to the buffer even if no I/O happens with the ioctl, in + * order to disambiguate requests with DEV_IOCTL_S. + */ + *gid = cpf_grant_magic(driver, *io_ept, (vir_bytes) *buf, size, access); + if (*gid < 0) + panic("VFS: cpf_grant_magic IOCTL buffer failed"); - /* Do this even if no I/O happens with the ioctl, in - * order to disambiguate requests with DEV_IOCTL_S. - */ - *gid = cpf_grant_magic(driver, *io_ept, (vir_bytes) *buf, size, - access); - if (*gid < 0) - panic("cpf_grant_magic failed (ioctl)"); - - break; - case VFS_DEV_SELECT: - *op = DEV_SELECT; - break; - default: - panic("safe_io_conversion: unknown operation: %d", *op); + break; + case VFS_DEV_SELECT: + *op = DEV_SELECT; + break; + default: + panic("VFS: unknown operation %d for safe I/O conversion", *op); } - /* If we have converted to a safe operation, I/O - * endpoint becomes FS if it wasn't already. + /* If we have converted to a safe operation, I/O endpoint becomes VFS if it + * wasn't already. */ if(GRANT_VALID(*gid)) { *io_ept = VFS_PROC_NR; - return 1; - } + return(1); + } - /* Not converted to a safe operation (because there is no - * copying involved in this operation). - */ - return 0; + /* Not converted to a safe operation (because there is no copying involved in + * this operation). + */ + return(0); } -/*===========================================================================* - * safe_io_cleanup * - *===========================================================================*/ -PRIVATE void safe_io_cleanup(gid, gids, gids_size) -cp_grant_id_t gid; -cp_grant_id_t *gids; -int gids_size; -{ -/* Free resources (specifically, grants) allocated by safe_io_conversion(). */ - int j; - - cpf_revoke(gid); - for(j = 0; j < gids_size; j++) - cpf_revoke(gids[j]); -} - - /*===========================================================================* * dev_io * *===========================================================================*/ @@ -426,30 +371,31 @@ PUBLIC int dev_io( int proc_e, /* in whose address space is buf? */ void *buf, /* virtual address of the buffer */ u64_t pos, /* byte position */ - int bytes, /* how many bytes to transfer */ + size_t bytes, /* how many bytes to transfer */ int flags, /* special flags, like O_NONBLOCK */ int suspend_reopen /* Just suspend the process */ ) { -/* Read or write from a device. The parameter 'dev' tells which one. */ +/* Read from or write to a device. The parameter 'dev' tells which one. */ struct dmap *dp; u32_t pos_lo, pos_high; message dev_mess; cp_grant_id_t gid = GRANT_INVALID; - static cp_grant_id_t gids[NR_IOREQS]; - int vec_grants = 0, safe; + int safe, minor_dev, major_dev; void *buf_used; endpoint_t ioproc; - pos_lo= ex64lo(pos); - pos_high= ex64hi(pos); + pos_lo = ex64lo(pos); + pos_high = ex64hi(pos); + major_dev = major(dev); + minor_dev = minor(dev); /* Determine task dmap. */ - dp = &dmap[(dev >> MAJOR) & BYTE]; + dp = &dmap[major_dev]; /* See if driver is roughly valid. */ if (dp->dmap_driver == NONE) { - printf("FS: dev_io: no driver for dev %x\n", dev); + printf("VFS: dev_io: no driver for major %d\n", major_dev); return(ENXIO); } @@ -458,12 +404,13 @@ PUBLIC int dev_io( fp->fp_grant = GRANT_INVALID; fp->fp_ioproc = NONE; wait_for(dp->dmap_driver); - fp->fp_flags |= SUSP_REOPEN; + fp->fp_flags |= FP_SUSP_REOPEN; return(SUSPEND); } if(isokendpt(dp->dmap_driver, &dummyproc) != OK) { - printf("FS: dev_io: old driver for dev %x (%d)\n",dev,dp->dmap_driver); + printf("VFS: dev_io: old driver for major %x (%d)\n", major_dev, + dp->dmap_driver); return(ENXIO); } @@ -473,21 +420,18 @@ PUBLIC int dev_io( /* Convert DEV_* to DEV_*_S variants. */ buf_used = buf; - safe = safe_io_conversion(dp->dmap_driver, &gid, &op, gids, NR_IOREQS, - (endpoint_t*) &dev_mess.USER_ENDPT, &buf_used, - &vec_grants, bytes, &pos_lo); + safe = safe_io_conversion(dp->dmap_driver, &gid, &op, + (endpoint_t *) &dev_mess.USER_ENDPT, &buf_used, + bytes, &pos_lo); - if(buf != buf_used) - panic("dev_io: safe_io_conversion changed buffer"); - - /* If the safe conversion was done, set the ADDRESS to + /* If the safe conversion was done, set the IO_GRANT to * the grant id. */ if(safe) dev_mess.IO_GRANT = (char *) gid; /* Set up the rest of the message passed to task. */ dev_mess.m_type = op; - dev_mess.DEVICE = (dev >> MINOR) & BYTE; + dev_mess.DEVICE = minor_dev; dev_mess.POSITION = pos_lo; dev_mess.COUNT = bytes; dev_mess.HIGHPOS = pos_high; @@ -499,20 +443,16 @@ PUBLIC int dev_io( (*dp->dmap_io)(dp->dmap_driver, &dev_mess); if(dp->dmap_driver == NONE) { - /* Driver has vanished. */ - printf("Driver gone?\n"); - if(safe) safe_io_cleanup(gid, gids, vec_grants); + /* Driver has vanished. */ + printf("VFS: driver gone?!\n"); + if(safe) cpf_revoke(gid); return(EIO); } /* Task has completed. See if call completed. */ if (dev_mess.REP_STATUS == SUSPEND) { - if(vec_grants > 0) panic("SUSPEND on vectored i/o"); - - /* fp is uninitialized at init time. */ - if(!fp) panic("SUSPEND on NULL fp"); - - if ((flags & O_NONBLOCK) && !(dp->dmap_style == STYLE_DEVA)) { + if ((flags & O_NONBLOCK) && !(dp->dmap_style == STYLE_DEVA || + dp->dmap_style == STYLE_CLONE_A)) { /* Not supposed to block. */ dev_mess.m_type = CANCEL; dev_mess.USER_ENDPT = ioproc; @@ -524,7 +464,7 @@ PUBLIC int dev_io( dev_mess.COUNT = 0; if (call_nr == READ) dev_mess.COUNT = R_BIT; else if (call_nr == WRITE) dev_mess.COUNT = W_BIT; - dev_mess.DEVICE = (dev >> MINOR) & BYTE; + dev_mess.DEVICE = minor_dev; (*dp->dmap_io)(dp->dmap_driver, &dev_mess); if (dev_mess.REP_STATUS == EINTR) dev_mess.REP_STATUS = EAGAIN; } else { @@ -549,7 +489,7 @@ PUBLIC int dev_io( dev_mess.COUNT = 0; if(call_nr == READ) dev_mess.COUNT = R_BIT; else if(call_nr == WRITE) dev_mess.COUNT = W_BIT; - dev_mess.DEVICE = (dev >> MINOR) & BYTE; + dev_mess.DEVICE = minor_dev; (*dp->dmap_io)(dp->dmap_driver, &dev_mess); /* Should do something about EINTR -> EAGAIN mapping */ @@ -559,7 +499,7 @@ PUBLIC int dev_io( } /* No suspend, or cancelled suspend, so I/O is over and can be cleaned up. */ - if(safe) safe_io_cleanup(gid, gids, vec_grants); + if(safe) cpf_revoke(gid); return(dev_mess.REP_STATUS); } @@ -570,42 +510,46 @@ PUBLIC int dev_io( PUBLIC int gen_opcl( int op, /* operation, (B)DEV_OPEN or (B)DEV_CLOSE */ dev_t dev, /* device to open or close */ - int proc_e, /* process to open/close for */ + endpoint_t proc_e, /* process to open/close for */ int flags /* mode bits and flags */ ) { -/* Called from the dmap struct in table.c on opens & closes of special files.*/ - int r, is_bdev; +/* Called from the dmap struct on opens & closes of special files.*/ + int r, minor_dev, major_dev, is_bdev; struct dmap *dp; message dev_mess; /* Determine task dmap. */ - dp = &dmap[major(dev)]; + major_dev = major(dev); + minor_dev = minor(dev); + assert(major_dev >= 0 && major_dev < NR_DEVICES); + dp = &dmap[major_dev]; + assert(dp->dmap_driver != NONE); is_bdev = IS_BDEV_RQ(op); if (is_bdev) { memset(&dev_mess, 0, sizeof(dev_mess)); dev_mess.m_type = op; - dev_mess.BDEV_MINOR = minor(dev); + dev_mess.BDEV_MINOR = minor_dev; dev_mess.BDEV_ACCESS = flags; dev_mess.BDEV_ID = 0; } else { dev_mess.m_type = op; - dev_mess.DEVICE = minor(dev); + dev_mess.DEVICE = minor_dev; dev_mess.USER_ENDPT = proc_e; dev_mess.COUNT = flags; } - if (dp->dmap_driver == NONE) { - printf("FS: gen_opcl: no driver for dev %x\n", dev); - return(ENXIO); - } - /* Call the task. */ - r= (*dp->dmap_io)(dp->dmap_driver, &dev_mess); + r = (*dp->dmap_io)(dp->dmap_driver, &dev_mess); if (r != OK) return(r); + if (op == DEV_OPEN && dp->dmap_style == STYLE_DEVA) { + fp->fp_task = dp->dmap_driver; + worker_wait(); + } + if (is_bdev) return(dev_mess.BDEV_STATUS); else @@ -618,12 +562,12 @@ PUBLIC int gen_opcl( PUBLIC int tty_opcl( int op, /* operation, DEV_OPEN or DEV_CLOSE */ dev_t dev, /* device to open or close */ - int proc_e, /* process to open/close for */ + endpoint_t proc_e, /* process to open/close for */ int flags /* mode bits and flags */ ) { /* This procedure is called from the dmap struct on tty open/close. */ - + int r; register struct fproc *rfp; @@ -633,7 +577,7 @@ PUBLIC int tty_opcl( * if it already has a controlling tty, or if it is someone elses * controlling tty. */ - if (!fp->fp_sesldr || fp->fp_tty != 0) { + if (!(fp->fp_flags & FP_SESLDR) || fp->fp_tty != 0) { flags |= O_NOCTTY; } else { for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { @@ -649,6 +593,7 @@ PUBLIC int tty_opcl( fp->fp_tty = dev; r = OK; } + return(r); } @@ -658,15 +603,15 @@ PUBLIC int tty_opcl( *===========================================================================*/ PUBLIC int ctty_opcl( int op, /* operation, DEV_OPEN or DEV_CLOSE */ - dev_t dev, /* device to open or close */ - int proc_e, /* process to open/close for */ - int flags /* mode bits and flags */ + dev_t UNUSED(dev), /* device to open or close */ + endpoint_t UNUSED(proc_e), /* process to open/close for */ + int UNUSED(flags) /* mode bits and flags */ ) { -/* This procedure is called from the dmap struct in table.c on opening/closing +/* This procedure is called from the dmap struct on opening or closing * /dev/tty, the magic device that translates to the controlling tty. */ - + assert(!IS_BDEV_RQ(op)); return(fp->fp_tty == 0 ? ENXIO : OK); @@ -679,7 +624,7 @@ PUBLIC int ctty_opcl( PUBLIC void pm_setsid(proc_e) int proc_e; { -/* Perform the FS side of the SETSID call, i.e. get rid of the controlling +/* Perform the VFS side of the SETSID call, i.e. get rid of the controlling * terminal of a process, and make the process a session leader. */ register struct fproc *rfp; @@ -688,7 +633,7 @@ int proc_e; /* Make the process a session leader with no controlling tty. */ okendpt(proc_e, &slot); rfp = &fproc[slot]; - rfp->fp_sesldr = TRUE; + rfp->fp_flags |= FP_SESLDR; rfp->fp_tty = 0; } @@ -700,91 +645,82 @@ PUBLIC int do_ioctl() { /* Perform the ioctl(ls_fd, request, argx) system call (uses m2 fmt). */ - int suspend_reopen; + int r = OK, suspend_reopen; struct filp *f; register struct vnode *vp; dev_t dev; - if ((f = get_filp(m_in.ls_fd)) == NULL) return(err_code); + scratch(fp).file.fd_nr = m_in.ls_fd; + + if ((f = get_filp(scratch(fp).file.fd_nr, VNODE_READ)) == NULL) + return(err_code); vp = f->filp_vno; /* get vnode pointer */ if ((vp->v_mode & I_TYPE) != I_CHAR_SPECIAL && - (vp->v_mode & I_TYPE) != I_BLOCK_SPECIAL) return(ENOTTY); - suspend_reopen= (f->filp_state != FS_NORMAL); - dev = (dev_t) vp->v_sdev; + (vp->v_mode & I_TYPE) != I_BLOCK_SPECIAL) { + r = ENOTTY; + } - if ((vp->v_mode & I_TYPE) == I_BLOCK_SPECIAL) - return bdev_ioctl(dev, who_e, m_in.REQUEST, m_in.ADDRESS); + if (r == OK) { + suspend_reopen = (f->filp_state != FS_NORMAL); + dev = (dev_t) vp->v_sdev; - return dev_io(VFS_DEV_IOCTL, dev, who_e, m_in.ADDRESS, cvu64(0), - m_in.REQUEST, f->filp_flags, suspend_reopen); + if ((vp->v_mode & I_TYPE) == I_BLOCK_SPECIAL) + r = bdev_ioctl(dev, who_e, m_in.REQUEST, m_in.ADDRESS); + else + r = dev_io(VFS_DEV_IOCTL, dev, who_e, m_in.ADDRESS, cvu64(0), + m_in.REQUEST, f->filp_flags, suspend_reopen); + } + + unlock_filp(f); + + return(r); } /*===========================================================================* * gen_io * *===========================================================================*/ -PUBLIC int gen_io(task_nr, mess_ptr) -int task_nr; /* which task to call */ +PUBLIC int gen_io(driver_e, mess_ptr) +endpoint_t driver_e; /* which endpoint to call */ message *mess_ptr; /* pointer to message for task */ { /* All file system I/O ultimately comes down to I/O on major/minor device * pairs. These lead to calls on the following routines via the dmap table. */ - - int r, status, proc_e, is_bdev; - - if(task_nr == SYSTEM) { - printf("VFS: sending %d to SYSTEM\n", mess_ptr->m_type); - } + int r, status, proc_e = NONE, is_bdev; is_bdev = IS_BDEV_RQ(mess_ptr->m_type); if (!is_bdev) proc_e = mess_ptr->USER_ENDPT; - for (;;) { - - r = sendrec(task_nr, mess_ptr); - if(r == OK) { - if (is_bdev) - status = mess_ptr->BDEV_STATUS; - else - status = mess_ptr->REP_STATUS; - if (status == ERESTART) r = EDEADEPT; - } - if (r != OK) { - if (r == EDEADSRCDST || r == EDEADEPT) { - printf("fs: dead driver %d\n", task_nr); - dmap_unmap_by_endpt(task_nr); - return(r); - } - if (r == ELOCKED) { - printf("fs: ELOCKED talking to %d\n", task_nr); - return(r); - } - panic("call_task: can't send/receive: %d", r); + r = sendrec(driver_e, mess_ptr); + if (r == OK) { + if (is_bdev) + status = mess_ptr->BDEV_STATUS; + else + status = mess_ptr->REP_STATUS; + if (status == ERESTART) + r = EDEADEPT; + } + if (r != OK) { + if (r == EDEADSRCDST || r == EDEADEPT) { + printf("VFS: dead driver %d\n", driver_e); + dmap_unmap_by_endpt(driver_e); + return(r); + } else if (r == ELOCKED) { + printf("VFS: ELOCKED talking to %d\n", driver_e); + return(r); } + panic("call_task: can't send/receive: %d", r); + } - /* Did the process we did the sendrec() for get a result? */ - if (!is_bdev && - mess_ptr->REP_ENDPT != proc_e && VFS_PROC_NR != proc_e) { - - printf("fs: strange device reply from %d, type = %d, " - "proc = %d (not %d) (2) ignored\n", mess_ptr->m_source, + /* Did the process we did the sendrec() for get a result? */ + if (!is_bdev && mess_ptr->REP_ENDPT != proc_e) { + printf("VFS: strange device reply from %d, type = %d, " + "proc = %d (not %d) (2) ignored\n", mess_ptr->m_source, mess_ptr->m_type, proc_e, mess_ptr->REP_ENDPT); - return(EIO); - } - - if (mess_ptr->m_type == TASK_REPLY || - IS_DEV_RS(mess_ptr->m_type) || - IS_BDEV_RS(mess_ptr->m_type) || - mess_ptr->m_type <= 0) { - - break; /* reply */ - } else { - - nested_dev_call(mess_ptr); - } + return(EIO); } return(OK); @@ -799,15 +735,17 @@ int task_nr; /* which task to call */ message *mess_ptr; /* pointer to message for task */ { /* All file system I/O ultimately comes down to I/O on major/minor device - * pairs. These lead to calls on the following routines via the dmap table. + * pairs. These lead to calls on the following routines via the dmap table. */ int r; assert(!IS_BDEV_RQ(mess_ptr->m_type)); - r = asynsend(task_nr, mess_ptr); - if (r != OK) panic("asyn_io: asynsend failed: %d", r); + fp->fp_sendrec = mess_ptr; /* Remember where result should be stored */ + r = asynsend3(task_nr, mess_ptr, AMF_NOREPLY); + + if (r != OK) panic("VFS: asynsend in asyn_io failed: %d", r); /* Fake a SUSPEND */ mess_ptr->REP_STATUS = SUSPEND; @@ -818,9 +756,10 @@ message *mess_ptr; /* pointer to message for task */ /*===========================================================================* * ctty_io * *===========================================================================*/ -PUBLIC int ctty_io(task_nr, mess_ptr) -int task_nr; /* not used - for compatibility with dmap_t */ -message *mess_ptr; /* pointer to message for task */ +PUBLIC int ctty_io( + endpoint_t UNUSED(task_nr), /* not used - for compatibility with dmap_t */ + message *mess_ptr /* pointer to message for task */ +) { /* This routine is only called for one device, namely /dev/tty. Its job * is to change the message to use the controlling terminal, instead of the @@ -834,21 +773,22 @@ message *mess_ptr; /* pointer to message for task */ mess_ptr->REP_STATUS = EIO; } else { /* Substitute the controlling terminal device. */ - dp = &dmap[(fp->fp_tty >> MAJOR) & BYTE]; - mess_ptr->DEVICE = (fp->fp_tty >> MINOR) & BYTE; + dp = &dmap[major(fp->fp_tty)]; + mess_ptr->DEVICE = minor(fp->fp_tty); if (dp->dmap_driver == NONE) { printf("FS: ctty_io: no driver for dev\n"); return(EIO); } - if(isokendpt(dp->dmap_driver, &dummyproc) != OK) { - printf("FS: ctty_io: old driver %d\n", dp->dmap_driver); + if (isokendpt(dp->dmap_driver, &dummyproc) != OK) { + printf("VFS: ctty_io: old driver %d\n", dp->dmap_driver); return(EIO); } (*dp->dmap_io)(dp->dmap_driver, mess_ptr); } + return(OK); } @@ -870,7 +810,7 @@ PUBLIC int no_dev( /*===========================================================================* * no_dev_io * *===========================================================================*/ -PUBLIC int no_dev_io(int proc, message *m) +PUBLIC int no_dev_io(endpoint_t UNUSED(proc), message *UNUSED(m)) { /* Called when doing i/o on a nonexistent device. */ printf("VFS: I/O on unmapped device number\n"); @@ -894,45 +834,48 @@ PUBLIC int clone_opcl( * as a new network connection) that has been allocated within a task. */ struct dmap *dp; - int r, minor; + int r, minor_dev, major_dev; message dev_mess; assert(!IS_BDEV_RQ(op)); /* Determine task dmap. */ - dp = &dmap[(dev >> MAJOR) & BYTE]; - minor = (dev >> MINOR) & BYTE; + minor_dev = minor(dev); + major_dev = major(dev); + assert(major_dev >= 0 && major_dev < NR_DEVICES); + dp = &dmap[major_dev]; + assert(dp->dmap_driver != NONE); dev_mess.m_type = op; - dev_mess.DEVICE = minor; + dev_mess.DEVICE = minor_dev; dev_mess.USER_ENDPT = proc_e; dev_mess.COUNT = flags; - - if (dp->dmap_driver == NONE) { - printf("VFS clone_opcl: no driver for dev %x\n", dev); - return(ENXIO); - } - if(isokendpt(dp->dmap_driver, &dummyproc) != OK) { - printf("VFS clone_opcl: bad driver endpoint for dev %x (%d)\n", dev, - dp->dmap_driver); - return(ENXIO); + printf("VFS clone_opcl: bad driver endpoint for major %d (%d)\n", + major_dev, dp->dmap_driver); + return(ENXIO); } /* Call the task. */ r = (*dp->dmap_io)(dp->dmap_driver, &dev_mess); if (r != OK) return(r); + if (op == DEV_OPEN && dp->dmap_style == STYLE_CLONE_A) { + /* Wait for reply when driver is asynchronous */ + fp->fp_task = dp->dmap_driver; + worker_wait(); + } + if (op == DEV_OPEN && dev_mess.REP_STATUS >= 0) { - if (dev_mess.REP_STATUS != minor) { + if (dev_mess.REP_STATUS != minor_dev) { struct vnode *vp; struct node_details res; /* A new minor device number has been returned. - * Request PFS to create a temporary device file to hold it. + * Request PFS to create a temporary device file to hold it. */ - + /* Device number of the new device. */ dev = (dev & ~(BYTE << MINOR)) | (dev_mess.REP_STATUS << MINOR); @@ -940,27 +883,31 @@ PUBLIC int clone_opcl( r = req_newnode(PFS_PROC_NR, fp->fp_effuid, fp->fp_effgid, ALL_MODES | I_CHAR_SPECIAL, dev, &res); if (r != OK) { - (void) clone_opcl(DEV_CLOSE, dev, proc_e, 0); - return r; + (void) clone_opcl(DEV_CLOSE, dev, proc_e, 0); + return r; } /* Drop old node and use the new values */ - vp = fp->fp_filp[m_in.fd]->filp_vno; - + assert(FD_ISSET(scratch(fp).file.fd_nr, &fp->fp_filp_inuse)); + vp = fp->fp_filp[scratch(fp).file.fd_nr]->filp_vno; + + unlock_vnode(vp); put_vnode(vp); - if ((vp = get_free_vnode()) == NULL) - vp = fp->fp_filp[m_in.fd]->filp_vno; - + if ((vp = get_free_vnode()) == NULL) + return(err_code); + + lock_vnode(vp, VNODE_OPCL); + vp->v_fs_e = res.fs_e; vp->v_vmnt = NULL; - vp->v_dev = NO_DEV; + vp->v_dev = NO_DEV; vp->v_fs_e = res.fs_e; vp->v_inode_nr = res.inode_nr; - vp->v_mode = res.fmode; + vp->v_mode = res.fmode; vp->v_sdev = dev; vp->v_fs_count = 1; vp->v_ref_count = 1; - fp->fp_filp[m_in.fd]->filp_vno = vp; + fp->fp_filp[scratch(fp).file.fd_nr]->filp_vno = vp; } dev_mess.REP_STATUS = OK; } @@ -977,14 +924,15 @@ PUBLIC void bdev_up(int maj) * file systems and open block-special files. */ int r, found, bits; - struct filp *fp; + struct filp *rfilp; struct vmnt *vmp; struct vnode *vp; char *label; + if (maj < 0 || maj >= NR_DEVICES) panic("VFS: out-of-bound major"); label = dmap[maj].dmap_label; - /* Tell each affected mounted file system about the new driver. This code + /* Tell each affected mounted file system about the new endpoint. This code * is currently useless, as driver endpoints do not change across restarts. */ for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) { @@ -992,7 +940,7 @@ PUBLIC void bdev_up(int maj) /* Send the driver label to the mounted file system. */ if (OK != req_newdriver(vmp->m_fs_e, vmp->m_dev, label)) - printf("VFSdev_up: error sending new driver label to %d\n", + printf("VFS dev_up: error sending new driver label to %d\n", vmp->m_fs_e); } @@ -1000,13 +948,13 @@ PUBLIC void bdev_up(int maj) * device, we need to reopen it on the new driver. */ found = 0; - for (fp = filp; fp < &filp[NR_FILPS]; fp++) { - if(fp->filp_count < 1 || !(vp = fp->filp_vno)) continue; - if(major(vp->v_sdev) != maj) continue; - if(!S_ISBLK(vp->v_mode)) continue; + for (rfilp = filp; rfilp < &filp[NR_FILPS]; rfilp++) { + if (rfilp->filp_count < 1 || !(vp = rfilp->filp_vno)) continue; + if (major(vp->v_sdev) != maj) continue; + if (!S_ISBLK(vp->v_mode)) continue; /* Reopen the device on the driver, once per filp. */ - bits = mode_map[fp->filp_mode & O_ACCMODE]; + bits = mode_map[rfilp->filp_mode & O_ACCMODE]; if ((r = bdev_open(vp->v_sdev, bits)) != OK) printf("VFS: mounted dev %d/%d re-open failed: %d.\n", maj, minor(vp->v_sdev), r); @@ -1015,14 +963,14 @@ PUBLIC void bdev_up(int maj) } /* If any block-special file was open for this major at all, also inform the - * root file system about the endpoint update of the driver. We do this even - * if the block-special file is linked to another mounted file system, merely + * root file system about the new driver. We do this even if the + * block-special file is linked to another mounted file system, merely * because it is more work to check for that case. */ if (found) { if (OK != req_newdriver(ROOT_FS_E, makedev(maj, 0), label)) printf("VFSdev_up: error sending new driver label to %d\n", - ROOT_FS_E); + ROOT_FS_E); } } @@ -1033,38 +981,38 @@ PUBLIC void bdev_up(int maj) PUBLIC void cdev_up(int maj) { /* A new character device driver has been mapped in. - */ + */ int needs_reopen, fd_nr; - struct filp *fp; + struct filp *rfilp; struct fproc *rfp; struct vnode *vp; - /* Look for processes that are suspened in an OPEN call. Set SUSP_REOPEN + /* Look for processes that are suspened in an OPEN call. Set FP_SUSP_REOPEN * to indicate that this process was suspended before the call to dev_up. */ for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { if(rfp->fp_pid == PID_FREE) continue; if(rfp->fp_blocked_on != FP_BLOCKED_ON_DOPEN) continue; - printf("dev_up: found process in FP_BLOCKED_ON_DOPEN, fd %d\n", - rfp->fp_block_fd); - fd_nr = rfp->fp_block_fd; - fp = rfp->fp_filp[fd_nr]; - vp = fp->filp_vno; - if (!vp) panic("restart_reopen: no vp"); + fd_nr = scratch(rfp).file.fd_nr; + printf("VFS: dev_up: found process in FP_BLOCKED_ON_DOPEN, fd %d\n", + fd_nr); + rfilp = rfp->fp_filp[fd_nr]; + vp = rfilp->filp_vno; + if (!vp) panic("VFS: cdev_up: no vp"); if ((vp->v_mode & I_TYPE) != I_CHAR_SPECIAL) continue; - if (((vp->v_sdev >> MAJOR) & BYTE) != maj) continue; + if (major(vp->v_sdev) != maj) continue; - rfp->fp_flags |= SUSP_REOPEN; + rfp->fp_flags |= FP_SUSP_REOPEN; } needs_reopen= FALSE; - for (fp = filp; fp < &filp[NR_FILPS]; fp++) { - if(fp->filp_count < 1 || !(vp = fp->filp_vno)) continue; - if(((vp->v_sdev >> MAJOR) & BYTE) != maj) continue; - if(!S_ISCHR(vp->v_mode)) continue; + for (rfilp = filp; rfilp < &filp[NR_FILPS]; rfilp++) { + if (rfilp->filp_count < 1 || !(vp = rfilp->filp_vno)) continue; + if (major(vp->v_sdev) != maj) continue; + if (!S_ISCHR(vp->v_mode)) continue; - fp->filp_state = FS_NEEDS_REOPEN; + rfilp->filp_state = FS_NEEDS_REOPEN; needs_reopen = TRUE; } @@ -1072,6 +1020,21 @@ PUBLIC void cdev_up(int maj) restart_reopen(maj); } +/*===========================================================================* + * open_reply * + *===========================================================================*/ +PUBLIC void open_reply(void) +{ + struct fproc *rfp; + endpoint_t proc_e; + int slot; + + proc_e = m_in.REP_ENDPT; + if (isokendpt(proc_e, &slot) != OK) return; + rfp = &fproc[slot]; + *rfp->fp_sendrec = m_in; + worker_signal(worker_get(rfp->fp_wtid)); /* Continue open */ +} /*===========================================================================* * restart_reopen * @@ -1079,52 +1042,55 @@ PUBLIC void cdev_up(int maj) PRIVATE void restart_reopen(maj) int maj; { - int n, r, minor, fd_nr; + int n, r, minor_dev, major_dev, fd_nr; endpoint_t driver_e; struct vnode *vp; - struct filp *fp; + struct filp *rfilp; struct fproc *rfp; - for (fp = filp; fp < &filp[NR_FILPS]; fp++) { - if (fp->filp_count < 1 || !(vp = fp->filp_vno)) continue; - if (fp->filp_state != FS_NEEDS_REOPEN) continue; - if (((vp->v_sdev >> MAJOR) & BYTE) != maj) continue; + if (maj < 0 || maj >= NR_DEVICES) panic("VFS: out-of-bound major"); + for (rfilp = filp; rfilp < &filp[NR_FILPS]; rfilp++) { + if (rfilp->filp_count < 1 || !(vp = rfilp->filp_vno)) continue; + if (rfilp->filp_state != FS_NEEDS_REOPEN) continue; if ((vp->v_mode & I_TYPE) != I_CHAR_SPECIAL) continue; - minor = ((vp->v_sdev >> MINOR) & BYTE); - - if (!(fp->filp_flags & O_REOPEN)) { + + major_dev = major(vp->v_sdev); + minor_dev = minor(vp->v_sdev); + if (major_dev != maj) continue; + + if (!(rfilp->filp_flags & O_REOPEN)) { /* File descriptor is to be closed when driver restarts. */ - n = invalidate(fp); - if (n != fp->filp_count) { + n = invalidate_filp(rfilp); + if (n != rfilp->filp_count) { printf("VFS: warning: invalidate/count " - "discrepancy (%d, %d)\n", n, fp->filp_count); + "discrepancy (%d, %d)\n", n, rfilp->filp_count); } - fp->filp_count = 0; + rfilp->filp_count = 0; continue; } - r = dev_reopen(vp->v_sdev, fp-filp, vp->v_mode & (R_BIT|W_BIT)); + r = dev_reopen(vp->v_sdev, rfilp-filp, vp->v_mode & (R_BIT|W_BIT)); if (r == OK) return; /* Device could not be reopened. Invalidate all filps on that device.*/ - n = invalidate(fp); - if (n != fp->filp_count) { + n = invalidate_filp(rfilp); + if (n != rfilp->filp_count) { printf("VFS: warning: invalidate/count " - "discrepancy (%d, %d)\n", n, fp->filp_count); + "discrepancy (%d, %d)\n", n, rfilp->filp_count); } - fp->filp_count = 0; + rfilp->filp_count = 0; printf("VFS: file on dev %d/%d re-open failed: %d; " - "invalidated %d fd's.\n", maj, minor, r, n); + "invalidated %d fd's.\n", major_dev, minor_dev, r, n); } /* Nothing more to re-open. Restart suspended processes */ - driver_e= dmap[maj].dmap_driver; + driver_e = dmap[maj].dmap_driver; for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { if(rfp->fp_pid == PID_FREE) continue; if(rfp->fp_blocked_on == FP_BLOCKED_ON_OTHER && - rfp->fp_task == driver_e && (rfp->fp_flags & SUSP_REOPEN)) { - rfp->fp_flags &= ~SUSP_REOPEN; + rfp->fp_task == driver_e && (rfp->fp_flags & FP_SUSP_REOPEN)) { + rfp->fp_flags &= ~FP_SUSP_REOPEN; rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; reply(rfp->fp_endpoint, ERESTART); } @@ -1134,14 +1100,14 @@ int maj; for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { if (rfp->fp_pid == PID_FREE) continue; if (rfp->fp_blocked_on == FP_BLOCKED_ON_DOPEN || - !(rfp->fp_flags & SUSP_REOPEN)) continue; + !(rfp->fp_flags & FP_SUSP_REOPEN)) continue; - printf("restart_reopen: found process in FP_BLOCKED_ON_DOPEN, fd %d\n", - rfp->fp_block_fd); - fd_nr = rfp->fp_block_fd; - fp = rfp->fp_filp[fd_nr]; + fd_nr = scratch(rfp).file.fd_nr; + printf("VFS: restart_reopen: process in FP_BLOCKED_ON_DOPEN fd=%d\n", + fd_nr); + rfilp = rfp->fp_filp[fd_nr]; - if (!fp) { + if (!rfilp) { /* Open failed, and automatic reopen was not requested */ rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; FD_CLR(fd_nr, &rfp->fp_filp_inuse); @@ -1149,10 +1115,10 @@ int maj; continue; } - vp = fp->filp_vno; - if (!vp) panic("restart_reopen: no vp"); + vp = rfilp->filp_vno; + if (!vp) panic("VFS: restart_reopen: no vp"); if ((vp->v_mode & I_TYPE) != I_CHAR_SPECIAL) continue; - if (((vp->v_sdev >> MAJOR) & BYTE) != maj) continue; + if (major(vp->v_sdev) != maj) continue; rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; reply(rfp->fp_endpoint, fd_nr); @@ -1167,7 +1133,7 @@ PUBLIC void reopen_reply() { endpoint_t driver_e; int filp_no, status, maj; - struct filp *fp; + struct filp *rfilp; struct vnode *vp; struct dmap *dp; @@ -1176,50 +1142,50 @@ PUBLIC void reopen_reply() status = m_in.REP_STATUS; if (filp_no < 0 || filp_no >= NR_FILPS) { - printf("reopen_reply: bad filp number %d from driver %d\n", filp_no, - driver_e); - return; - } - - fp = &filp[filp_no]; - if (fp->filp_count < 1) { - printf("reopen_reply: filp number %d not inuse (from driver %d)\n", - filp_no, driver_e); - return; - } - - vp = fp->filp_vno; - if (!vp) { - printf("reopen_reply: no vnode for filp number %d (from driver %d)\n", + printf("VFS: reopen_reply: bad filp number %d from driver %d\n", filp_no, driver_e); return; } - if (fp->filp_state != FS_NEEDS_REOPEN) { - printf("reopen_reply: bad state %d for filp number %d" - " (from driver %d)\n", fp->filp_state, filp_no, driver_e); + rfilp = &filp[filp_no]; + if (rfilp->filp_count < 1) { + printf("VFS: reopen_reply: filp number %d not inuse (from driver %d)\n", + filp_no, driver_e); + return; + } + + vp = rfilp->filp_vno; + if (!vp) { + printf("VFS: reopen_reply: no vnode for filp number %d (from driver " + "%d)\n", filp_no, driver_e); + return; + } + + if (rfilp->filp_state != FS_NEEDS_REOPEN) { + printf("VFS: reopen_reply: bad state %d for filp number %d" + " (from driver %d)\n", rfilp->filp_state, filp_no, driver_e); return; } if ((vp->v_mode & I_TYPE) != I_CHAR_SPECIAL) { - printf("reopen_reply: bad mode 0%o for filp number %d" + printf("VFS: reopen_reply: bad mode 0%o for filp number %d" " (from driver %d)\n", vp->v_mode, filp_no, driver_e); return; } - maj = ((vp->v_sdev >> MAJOR) & BYTE); + maj = major(vp->v_sdev); dp = &dmap[maj]; if (dp->dmap_driver != driver_e) { - printf("reopen_reply: bad major %d for filp number %d " + printf("VFS: reopen_reply: bad major %d for filp number %d " "(from driver %d, current driver is %d)\n", maj, filp_no, driver_e, dp->dmap_driver); return; } if (status == OK) { - fp->filp_state= FS_NORMAL; + rfilp->filp_state= FS_NORMAL; } else { - printf("reopen_reply: should handle error status\n"); + printf("VFS: reopen_reply: should handle error status\n"); return; } diff --git a/servers/vfs/dmap.c b/servers/vfs/dmap.c index fddb2fb79..eb5d13b1b 100644 --- a/servers/vfs/dmap.c +++ b/servers/vfs/dmap.c @@ -1,24 +1,23 @@ /* This file contains the table with device <-> driver mappings. It also * contains some routines to dynamically add and/ or remove device drivers - * or change mappings. + * or change mappings. */ #include "fs.h" -#include "fproc.h" #include #include #include #include #include #include +#include "fproc.h" +#include "dmap.h" #include "param.h" -#define NC(x) (NR_CTRLRS >= (x)) - /* The order of the entries in the table determines the mapping between major * device numbers and device drivers. Character and block devices * can be intermixed at random. The ordering determines the device numbers in - * /dev. Note that the major device numbers used in /dev are NOT the same as + * /dev. Note that the major device numbers used in /dev are NOT the same as * the process numbers of the device drivers. See for mappings. */ @@ -31,53 +30,47 @@ struct dmap dmap[NR_DEVICES]; *===========================================================================*/ PUBLIC int do_mapdriver() { - int r, flags, major; - endpoint_t endpoint; - vir_bytes label_vir; - size_t label_len; - char label[LABEL_MAX]; +/* Create a device->driver mapping. RS will tell us which major is driven by + * this driver, what type of device it is (regular, TTY, asynchronous, clone, + * etc), and its label. This label is registered with DS, and allows us to + * retrieve the driver's endpoint. + */ + int r, flags, major; + endpoint_t endpoint; + vir_bytes label_vir; + size_t label_len; + char label[LABEL_MAX]; - /* Only RS can map drivers. */ - if (who_e != RS_PROC_NR) - { - printf("vfs: unauthorized call of do_mapdriver by proc %d\n", - who_e); - return(EPERM); - } + /* Only RS can map drivers. */ + if (who_e != RS_PROC_NR) return(EPERM); - /* Get the label */ - label_vir= (vir_bytes)m_in.md_label; - label_len= m_in.md_label_len; + /* Get the label */ + label_vir = (vir_bytes) m_in.md_label; + label_len = (size_t) m_in.md_label_len; - if (label_len+1 > sizeof(label)) - { - printf("vfs:do_mapdriver: label too long\n"); - return EINVAL; - } + if (label_len+1 > sizeof(label)) { /* Can we store this label? */ + printf("VFS: do_mapdriver: label too long\n"); + return(EINVAL); + } + r = sys_vircopy(who_e, D, label_vir, SELF, D, (vir_bytes) label, label_len); + if (r != OK) { + printf("VFS: do_mapdriver: sys_vircopy failed: %d\n", r); + return(EINVAL); + } + label[label_len] = '\0'; /* Terminate label */ - r= sys_vircopy(who_e, D, label_vir, SELF, D, (vir_bytes)label, - label_len); - if (r != OK) - { - printf("vfs:do_mapdriver: sys_vircopy failed: %d\n", r); - return EINVAL; - } + /* Now we know how the driver is called, fetch its endpoint */ + r = ds_retrieve_label_endpt(label, &endpoint); + if (r != OK) { + printf("VFS: do_mapdriver: label '%s' unknown\n", label); + return(EINVAL); + } - label[label_len]= '\0'; + /* Try to update device mapping. */ + major = m_in.md_major; + flags = m_in.md_flags; - r= ds_retrieve_label_endpt(label, &endpoint); - if (r != OK) - { - printf("vfs:do_mapdriver: ds doesn't know '%s'\n", label); - return EINVAL; - } - - /* Try to update device mapping. */ - major= m_in.md_major; - flags= m_in.md_flags; - r= map_driver(label, major, endpoint, m_in.md_style, flags); - - return(r); + return map_driver(label, major, endpoint, m_in.md_style, flags); } /*===========================================================================* @@ -90,19 +83,20 @@ endpoint_t proc_nr_e; /* process number of the driver */ int style; /* style of the device */ int flags; /* device flags */ { -/* Set a new device driver mapping in the dmap table. - * If the proc_nr is set to NONE, we're supposed to unmap it. +/* Add a new device driver mapping in the dmap table. If the proc_nr is set to + * NONE, we're supposed to unmap it. */ - int proc_nr_n; + + int slot; size_t len; struct dmap *dp; /* Get pointer to device entry in the dmap table. */ if (major < 0 || major >= NR_DEVICES) return(ENODEV); - dp = &dmap[major]; + dp = &dmap[major]; /* Check if we're supposed to unmap it. */ - if(proc_nr_e == NONE) { + if (proc_nr_e == NONE) { dp->dmap_opcl = no_dev; dp->dmap_io = no_dev_io; dp->dmap_driver = NONE; @@ -110,66 +104,78 @@ int flags; /* device flags */ return(OK); } - /* Check process number of new driver if requested. */ - if (! (flags & DRV_FORCED)) - { - if (isokendpt(proc_nr_e, &proc_nr_n) != OK) + /* Check process number of new driver if it was alive before mapping */ + if (! (flags & DRV_FORCED)) { + struct fproc *rfp; + + if (isokendpt(proc_nr_e, &slot) != OK) return(EINVAL); + + rfp = &fproc[slot]; + rfp->fp_flags |= FP_SYS_PROC; /* Process is a driver */ } if (label != NULL) { - len= strlen(label); + len = strlen(label); if (len+1 > sizeof(dp->dmap_label)) - panic("map_driver: label too long: %d", len); + panic("VFS: map_driver: label too long: %d", len); strcpy(dp->dmap_label, label); } - /* Try to update the entry. */ + /* Store driver I/O routines based on type of device */ switch (style) { - case STYLE_DEV: + case STYLE_DEV: dp->dmap_opcl = gen_opcl; dp->dmap_io = gen_io; break; - case STYLE_DEVA: + case STYLE_DEVA: dp->dmap_opcl = gen_opcl; dp->dmap_io = asyn_io; break; - case STYLE_TTY: + case STYLE_TTY: dp->dmap_opcl = tty_opcl; dp->dmap_io = gen_io; break; - case STYLE_CTTY: + case STYLE_CTTY: dp->dmap_opcl = ctty_opcl; dp->dmap_io = ctty_io; break; - case STYLE_CLONE: - case STYLE_CLONE_A: + case STYLE_CLONE: dp->dmap_opcl = clone_opcl; dp->dmap_io = gen_io; break; - default: + case STYLE_CLONE_A: + dp->dmap_opcl = clone_opcl; + dp->dmap_io = asyn_io; + break; + default: return(EINVAL); } + dp->dmap_driver = proc_nr_e; dp->dmap_flags = flags; dp->dmap_style = style; - return(OK); + return(OK); } /*===========================================================================* * dmap_unmap_by_endpt * *===========================================================================*/ -PUBLIC void dmap_unmap_by_endpt(int proc_nr_e) +PUBLIC void dmap_unmap_by_endpt(endpoint_t proc_e) { - int i, r; - for (i=0; idev_nr) { - return OK; - } + if(rpub->dev_nr == NO_DEV) return(OK); /* Map driver. */ - r = map_driver(rpub->label, rpub->dev_nr, rpub->endpoint, - rpub->dev_style, rpub->dev_flags); - if(r != OK) { - return r; - } + r = map_driver(rpub->label, rpub->dev_nr, rpub->endpoint, rpub->dev_style, + rpub->dev_flags); + if(r != OK) return(r); /* If driver has two major numbers associated, also map the other one. */ if(rpub->dev_style2 != STYLE_NDEV) { r = map_driver(rpub->label, rpub->dev_nr+1, rpub->endpoint, - rpub->dev_style2, rpub->dev_flags); - if(r != OK) { - return r; - } + rpub->dev_style2, rpub->dev_flags); + if(r != OK) return(r); } - return OK; + return(OK); } /*===========================================================================* - * build_dmap * + * init_dmap * *===========================================================================*/ -PUBLIC void build_dmap() +PUBLIC void init_dmap() { /* Initialize the table with empty device <-> driver mappings. */ int i; struct dmap dmap_default = DT_EMPTY; - for (i=0; i= NR_DEVICES) return(0); - if(dmap[major].dmap_driver != NONE && dmap[major].dmap_driver == proc) - return 1; - return 0; + if (major < 0 || major >= NR_DEVICES) return(0); + if (dmap[major].dmap_driver != NONE && dmap[major].dmap_driver == proc) + return(1); + + return(0); } /*===========================================================================* * dmap_endpt_up * - *===========================================================================*/ -PUBLIC void dmap_endpt_up(int proc_e, int is_blk) + *===========================================================================*/ +PUBLIC void dmap_endpt_up(endpoint_t proc_e, int is_blk) { - int i; - for (i=0; i -#include -#include "fproc.h" -#include -#include -#include -#include "param.h" - -/* Include ELF headers */ -#include - -FORWARD _PROTOTYPE( void fill_elf_header, (Elf32_Ehdr *elf_header, - int phnum) ); -FORWARD _PROTOTYPE( void fill_prog_header, (Elf32_Phdr *prog_header, - Elf32_Word p_type, Elf32_Off p_offset, Elf32_Addr p_vaddr, - Elf32_Word p_flags, Elf32_Word p_filesz, Elf32_Word p_memsz) ); -FORWARD _PROTOTYPE( int get_memory_regions, (Elf32_Phdr phdrs[]) ); -FORWARD _PROTOTYPE( void fill_note_segment_and_entries_hdrs, - (Elf32_Phdr phdrs[], Elf32_Nhdr nhdrs[]) ); -FORWARD _PROTOTYPE( void adjust_offsets, (Elf32_Phdr phdrs[], int phnum) ); -FORWARD _PROTOTYPE( void dump_elf_header, (Elf32_Ehdr elf_header) ); -FORWARD _PROTOTYPE( void dump_notes, (Elf32_Nhdr nhdrs[], int csig, - char *exe_name) ); -FORWARD _PROTOTYPE( void dump_program_headers, (Elf_Phdr phdrs[], - int phnum) ); -FORWARD _PROTOTYPE( void dump_segments, (Elf32_Phdr phdrs[], int phnum) ); - -/*===========================================================================* - * write_elf_core_file * - *===========================================================================*/ -/* First, fill in all the required headers, second, adjust the offsets, - * third, dump everything into the core file - */ -PUBLIC void write_elf_core_file(int csig, char *exe_name) -{ -#define MAX_REGIONS 20 -#define NR_NOTE_ENTRIES 2 - Elf_Ehdr elf_header; - Elf_Phdr phdrs[MAX_REGIONS + 1]; - Elf_Nhdr nhdrs[NR_NOTE_ENTRIES]; - int phnum; - - /* Fill in the NOTE Program Header - at phdrs[0] - and - * note entries' headers - */ - fill_note_segment_and_entries_hdrs(phdrs, nhdrs); - - /* Get the memory segments and fill in the Program headers */ - phnum = get_memory_regions(phdrs) + 1; - - /* Fill in the ELF header */ - fill_elf_header(&elf_header, phnum); - - /* Adjust offsets in program headers - The layout in the ELF core file - * is the following: the ELF Header, the Note Program Header, - * the rest of Program Headers (memory segments), Note contents, - * the program segments' contents - */ - adjust_offsets(phdrs, phnum); - - /* Write ELF header */ - dump_elf_header(elf_header); - - /* Write Program headers (Including the NOTE) */ - dump_program_headers(phdrs, phnum); - - /* Write NOTE contents */ - dump_notes(nhdrs, csig, exe_name); - - /* Write segments' contents */ - dump_segments(phdrs, phnum); -} - -/*===========================================================================* - * fill_elf_header * - *===========================================================================*/ -PRIVATE void fill_elf_header (Elf_Ehdr *elf_header, int phnum) -{ - memset((void *) elf_header, 0, sizeof(Elf_Ehdr)); - - elf_header->e_ident[EI_MAG0] = ELFMAG0; - elf_header->e_ident[EI_MAG1] = ELFMAG1; - elf_header->e_ident[EI_MAG2] = ELFMAG2; - elf_header->e_ident[EI_MAG3] = ELFMAG3; - elf_header->e_ident[EI_CLASS] = ELF_TARG_CLASS; - elf_header->e_ident[EI_DATA] = ELF_TARG_DATA; - elf_header->e_ident[EI_VERSION] = EV_CURRENT; - elf_header->e_ident[EI_OSABI] = ELFOSABI_FREEBSD; - elf_header->e_type = ET_CORE; - elf_header->e_machine = ELF_TARG_MACH; - elf_header->e_version = EV_CURRENT; - elf_header->e_ehsize = sizeof(Elf_Ehdr); - elf_header->e_phoff = sizeof(Elf_Ehdr); - elf_header->e_phentsize = sizeof(Elf_Phdr); - elf_header->e_phnum = phnum; -} - -/*===========================================================================* - * fill_prog_header * - *===========================================================================*/ -PRIVATE void fill_prog_header (Elf_Phdr *prog_header, Elf_Word p_type, - Elf_Off p_offset, Elf_Addr p_vaddr, Elf_Word p_flags, - Elf_Word p_filesz, Elf_Word p_memsz) -{ - - memset((void *) prog_header, 0, sizeof(Elf_Phdr)); - - prog_header->p_type = p_type; - prog_header->p_offset = p_offset; - prog_header->p_vaddr = p_vaddr; - prog_header->p_flags = p_flags; - prog_header->p_filesz = p_filesz; - prog_header->p_memsz = p_memsz; - -} - -#define PADBYTES 4 -#define PAD_LEN(x) ((x + (PADBYTES - 1)) & ~(PADBYTES - 1)) - -/*===========================================================================* - * fill_note_segment_and_entries_hdrs * - *===========================================================================*/ -PRIVATE void fill_note_segment_and_entries_hdrs(Elf_Phdr phdrs[], - Elf_Nhdr nhdrs[]) -{ - int filesize; - const char *note_name = ELF_NOTE_MINIX_ELFCORE_NAME "\0"; - int name_len, mei_len, gregs_len; - - /* Size of notes in the core file is rather fixed: - * sizeof(minix_elfcore_info_t) + - * 2 * sizeof(Elf_Nhdr) + the size of the padded name of the note - * - i.e. "MINIX-CORE\0" padded to 4-byte alignment => 2 * 8 bytes - */ - - name_len = strlen(note_name) + 1; - mei_len = sizeof(minix_elfcore_info_t); - gregs_len = sizeof(gregset_t); - - /* Make sure to also count the padding bytes */ - filesize = PAD_LEN(mei_len) + PAD_LEN(gregs_len) + - 2 * sizeof(Elf_Nhdr) + 2 * PAD_LEN(name_len); - fill_prog_header(&phdrs[0], PT_NOTE, 0, 0, PF_R, filesize, 0); - - /* First note entry header */ - nhdrs[0].n_namesz = name_len; - nhdrs[0].n_descsz = sizeof(minix_elfcore_info_t); - nhdrs[0].n_type = NT_MINIX_ELFCORE_INFO; - - /* Second note entry header */ - nhdrs[1].n_namesz = name_len; - nhdrs[1].n_descsz = sizeof(gregset_t); - nhdrs[1].n_type = NT_MINIX_ELFCORE_GREGS; -} - -/*===========================================================================* - * adjust_offset * - *===========================================================================*/ -PRIVATE void adjust_offsets(Elf_Phdr phdrs[], int phnum) -{ - int i; - long offset = sizeof(Elf_Ehdr) + phnum * sizeof(Elf_Phdr); - - for (i = 0; i < phnum; i++) { - phdrs[i].p_offset = offset; - offset += phdrs[i].p_filesz; - } -} - -/*===========================================================================* - * write_buf * - *===========================================================================*/ -PRIVATE void write_buf(char *buf, int size) -{ - m_in.buffer = buf; - m_in.nbytes = size; - read_write(WRITING); -} - -/*===========================================================================* - * get_memory_regions * - *===========================================================================*/ -/* The same as dump_regions from procfs/pid.c */ -PRIVATE int get_memory_regions(Elf_Phdr phdrs[]) -{ - /* Print the virtual memory regions of a process. */ - struct vm_region_info vri[MAX_VRI_COUNT]; - vir_bytes next; - int i, r, count; - Elf_Word pflags; - - count = 0; - next = 0; - - do { - r = vm_info_region(fp->fp_endpoint, vri, MAX_VRI_COUNT, - &next); - if (r < 0) return r; - if (r == 0) break; - - for (i = 0; i < r; i++) { - - pflags = (vri[i].vri_prot & PROT_READ ? PF_R : 0) - | (vri[i].vri_prot & PROT_WRITE ? PF_W : 0) - | (vri[i].vri_prot & PROT_EXEC ? PF_X : 0); - - fill_prog_header (&phdrs[count + 1], PT_LOAD, - 0, vri[i].vri_addr, pflags, - vri[i].vri_length, vri[i].vri_length); - count++; - - if (count >= MAX_REGIONS) { - printf("VFS: get_memory_regions Warning: " - "Program has too many regions\n"); - return count; - } - } - } while (r == MAX_VRI_COUNT); - - return count; -} - -/*===========================================================================* - * dump_notes * - *===========================================================================*/ -PRIVATE void dump_notes(Elf_Nhdr nhdrs[], int csig, char *exe_name) -{ - char *note_name = ELF_NOTE_MINIX_ELFCORE_NAME "\0"; - char pad[4]; - minix_elfcore_info_t mei; - int mei_len = sizeof(minix_elfcore_info_t); - int gregs_len = sizeof(gregset_t); - struct stackframe_s regs; - char proc_name[PROC_NAME_LEN]; - - /* Get process's name */ - if (sys_datacopy(PM_PROC_NR, (vir_bytes) exe_name, - VFS_PROC_NR, (vir_bytes) proc_name, PROC_NAME_LEN) != OK) - printf("VFS: Cannot get process's name\n"); - - /* Dump first note entry */ - mei.mei_version = MINIX_ELFCORE_VERSION; - mei.mei_meisize = mei_len; - mei.mei_signo = csig; - mei.mei_pid = fp->fp_pid; - memcpy(mei.mei_command, proc_name, sizeof(mei.mei_command)); - - write_buf((char *)&nhdrs[0], sizeof(Elf_Nhdr)); - write_buf(note_name, nhdrs[0].n_namesz); - write_buf(pad, PAD_LEN(nhdrs[0].n_namesz) - nhdrs[0].n_namesz); - write_buf((char *)&mei, mei_len); - write_buf(pad, PAD_LEN(mei_len) - mei_len); - - /* Get registers */ - if (sys_getregs(®s, fp->fp_endpoint) != OK) - printf("VFS: Could not read registers\n"); - - if (sizeof(regs) != gregs_len) - printf("VFS: Wrong core register structure size\n"); - - /* Dump second note entry - the general registers */ - write_buf((char *)&nhdrs[1], sizeof(Elf_Nhdr)); - write_buf(note_name, nhdrs[1].n_namesz); - write_buf(pad, PAD_LEN(nhdrs[1].n_namesz) - nhdrs[1].n_namesz); - write_buf((char *)®s, gregs_len); - write_buf(pad, PAD_LEN(gregs_len) - gregs_len); -} - -/*===========================================================================* - * dump_elf_header * - *===========================================================================*/ -PRIVATE void dump_elf_header(Elf_Ehdr elf_header) -{ - write_buf((char *)&elf_header, sizeof(Elf_Ehdr)); -} - -/*===========================================================================* - * dump_program_headers * - *===========================================================================*/ -PRIVATE void dump_program_headers(Elf_Phdr phdrs[], int phnum) -{ - int i; - - for (i = 0; i < phnum; i++) - write_buf((char *)&phdrs[i], sizeof(Elf_Phdr)); -} - -/*===========================================================================* - * dump_segments * - *===========================================================================*/ -PRIVATE void dump_segments(Elf_Phdr phdrs[], int phnum) -{ - int i; - vir_bytes len; - off_t off, seg_off; - int r; - static u8_t buf[CLICK_SIZE]; - - for (i = 1; i < phnum; i++) { - len = phdrs[i].p_memsz; - seg_off = phdrs[i].p_vaddr; - - for (off = 0; off < len; off += CLICK_SIZE) { - r = sys_vircopy(fp->fp_endpoint, D, - (vir_bytes) (seg_off + off), - SELF, D, (vir_bytes) buf, - (phys_bytes) CLICK_SIZE); - - write_buf((char *)buf, (off + CLICK_SIZE <= len) ? - CLICK_SIZE : (len - off)); - } - } -} diff --git a/servers/vfs/exec.c b/servers/vfs/exec.c index e91cb6cee..3f6e4a7e2 100644 --- a/servers/vfs/exec.c +++ b/servers/vfs/exec.c @@ -27,45 +27,87 @@ #include #include #include "fproc.h" +#include "path.h" #include "param.h" #include "vnode.h" -#include "vmnt.h" #include #include #include #include "exec.h" -static int exec_newmem(int proc_e, vir_bytes text_addr, vir_bytes text_bytes, +FORWARD _PROTOTYPE( void lock_exec, (void) ); +FORWARD _PROTOTYPE( void unlock_exec, (void) ); +FORWARD _PROTOTYPE( int exec_newmem, (int proc_e, vir_bytes text_addr, vir_bytes text_bytes, vir_bytes data_addr, vir_bytes data_bytes, vir_bytes tot_bytes, vir_bytes frame_len, int sep_id, int is_elf, dev_t st_dev, ino_t st_ino, time_t ctime, char *progname, int new_uid, int new_gid, vir_bytes *stack_topp, int *load_textp, - int *setugidp); -static int is_script(const char *exec_hdr, size_t exec_len); -static int patch_stack(struct vnode *vp, char stack[ARG_MAX], - vir_bytes *stk_bytes); -static int insert_arg(char stack[ARG_MAX], vir_bytes *stk_bytes, char *arg, - int replace); -static void patch_ptr(char stack[ARG_MAX], vir_bytes base); -static void clo_exec(struct fproc *rfp); -static int read_seg(struct vnode *vp, off_t off, int proc_e, int seg, - vir_bytes seg_addr, phys_bytes seg_bytes); -static int load_aout(struct exec_info *execi); -static int load_elf(struct exec_info *execi); -static int map_header(char **exec_hdr, const struct vnode *vp); + int *setugidp) ); +FORWARD _PROTOTYPE( int is_script, (const char *exec_hdr, size_t exec_len)); +FORWARD _PROTOTYPE( int patch_stack, (struct vnode *vp, char stack[ARG_MAX], + vir_bytes *stk_bytes, char path[PATH_MAX]) ); +FORWARD _PROTOTYPE( int insert_arg, (char stack[ARG_MAX], vir_bytes *stk_bytes, + char *arg, int replace) ); +FORWARD _PROTOTYPE( void patch_ptr, (char stack[ARG_MAX], vir_bytes base)); +FORWARD _PROTOTYPE( void clo_exec, (struct fproc *rfp) ); +FORWARD _PROTOTYPE( int read_seg, (struct vnode *vp, off_t off, int proc_e, + int seg, vir_bytes seg_addr, + phys_bytes seg_bytes) ); +FORWARD _PROTOTYPE( int load_aout, (struct exec_info *execi) ); +FORWARD _PROTOTYPE( int load_elf, (struct exec_info *execi) ); +FORWARD _PROTOTYPE( int map_header, (char **exec_hdr, + const struct vnode *vp) ); #define PTRSIZE sizeof(char *) /* Size of pointers in argv[] and envp[]. */ /* Array of loaders for different object file formats */ struct exec_loaders { int (*load_object)(struct exec_info *); -} static const exec_loaders[] = { +}; + +PRIVATE const struct exec_loaders exec_loaders[] = { { load_aout }, { load_elf }, { NULL } }; +PRIVATE char hdr[PAGE_SIZE]; /* Assume that header is not larger than a page */ + +/*===========================================================================* + * lock_exec * + *===========================================================================*/ +PRIVATE void lock_exec(void) +{ + message org_m_in; + struct fproc *org_fp; + struct worker_thread *org_self; + + /* First try to get it right off the bat */ + if (mutex_trylock(&exec_lock) == 0) + return; + + org_m_in = m_in; + org_fp = fp; + org_self = self; + + if (mutex_lock(&exec_lock) != 0) + panic("Could not obtain lock on exec"); + + m_in = org_m_in; + fp = org_fp; + self = org_self; +} + +/*===========================================================================* + * unlock_exec * + *===========================================================================*/ +PRIVATE void unlock_exec(void) +{ + if (mutex_unlock(&exec_lock) != 0) + panic("Could not release lock on exec"); +} + /*===========================================================================* * pm_exec * *===========================================================================*/ @@ -76,65 +118,73 @@ PUBLIC int pm_exec(int proc_e, char *path, vir_bytes path_len, char *frame, * complete stack image, including pointers, args, environ, etc. The stack * is copied to a buffer inside VFS, and then to the new core image. */ - int r, r1, round, proc_s; + int r, r1, round, slot; vir_bytes vsp; struct fproc *rfp; struct vnode *vp; + struct vmnt *vmp; char *cp; static char mbuf[ARG_MAX]; /* buffer for stack and zeroes */ struct exec_info execi; int i; + char fullpath[PATH_MAX]; + struct lookup resolve; - okendpt(proc_e, &proc_s); - rfp = fp = &fproc[proc_s]; - who_e = proc_e; - who_p = proc_s; - super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); /* su? */ + lock_exec(); + + okendpt(proc_e, &slot); + rfp = fp = &fproc[slot]; + vp = NULL; + + lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); + resolve.l_vmnt_lock = VMNT_READ; + resolve.l_vnode_lock = VNODE_READ; /* Get the exec file name. */ - if ((r = fetch_name(path, path_len, 0)) != OK) return(r); + if ((r = fetch_name(path, path_len, 0, fullpath)) != OK) + goto pm_execfinal; /* Fetch the stack from the user before destroying the old core image. */ if (frame_len > ARG_MAX) { - printf("VFS: pm_exec: stack too big\n"); - return(ENOMEM); /* stack too big */ - } + r = ENOMEM; /* stack too big */ + goto pm_execfinal; + } r = sys_datacopy(proc_e, (vir_bytes) frame, SELF, (vir_bytes) mbuf, - (phys_bytes) frame_len); + (phys_bytes) frame_len); if (r != OK) { /* can't fetch stack (e.g. bad virtual addr) */ - printf("pm_exec: sys_datacopy failed\n"); - return(r); + printf("VFS: pm_exec: sys_datacopy failed\n"); + goto pm_execfinal; } /* The default is to keep the original user and group IDs */ execi.new_uid = rfp->fp_effuid; execi.new_gid = rfp->fp_effgid; - for (round= 0; round < 2; round++) { + for (round = 0; round < 2; round++) { /* round = 0 (first attempt), or 1 (interpreted script) */ - /* Save the name of the program */ - (cp= strrchr(user_fullpath, '/')) ? cp++ : (cp= user_fullpath); + (cp = strrchr(fullpath, '/')) ? cp++ : (cp = fullpath); strncpy(execi.progname, cp, PROC_NAME_LEN-1); execi.progname[PROC_NAME_LEN-1] = '\0'; execi.setugid = 0; /* Open executable */ - if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); + if ((vp = eat_path(&resolve, fp)) == NULL) { + r = err_code; + goto pm_execfinal; + } execi.vp = vp; + unlock_vmnt(vmp); - if ((vp->v_mode & I_TYPE) != I_REGULAR) + if ((vp->v_mode & I_TYPE) != I_REGULAR) r = ENOEXEC; else if ((r1 = forbidden(fp, vp, X_BIT)) != OK) r = r1; else r = req_stat(vp->v_fs_e, vp->v_inode_nr, VFS_PROC_NR, (char *) &(execi.sb), 0, 0); - if (r != OK) { - put_vnode(vp); - return(r); - } + if (r != OK) goto pm_execfinal; if (round == 0) { /* Deal with setuid/setgid executables */ @@ -149,36 +199,35 @@ PUBLIC int pm_exec(int proc_e, char *path, vir_bytes path_len, char *frame, } r = map_header(&execi.hdr, execi.vp); - if (r != OK) { - put_vnode(vp); - return(r); - } + if (r != OK) goto pm_execfinal; if (!is_script(execi.hdr, execi.vp->v_size) || round != 0) break; /* Get fresh copy of the file name. */ - if ((r = fetch_name(path, path_len, 0)) != OK) + if ((r = fetch_name(path, path_len, 0, fullpath)) != OK) printf("VFS pm_exec: 2nd fetch_name failed\n"); - else if ((r = patch_stack(vp, mbuf, &frame_len)) != OK) - printf("VFS pm_exec: patch_stack failed\n"); + else + r = patch_stack(vp, mbuf, &frame_len, fullpath); + + unlock_vnode(vp); put_vnode(vp); - if (r != OK) return(r); + vp = NULL; + if (r != OK) goto pm_execfinal; } execi.proc_e = proc_e; execi.frame_len = frame_len; - for(i = 0; exec_loaders[i].load_object != NULL; i++) { + for (i = 0; exec_loaders[i].load_object != NULL; i++) { r = (*exec_loaders[i].load_object)(&execi); /* Loaded successfully, so no need to try other loaders */ if (r == OK) break; } - put_vnode(vp); - /* No exec loader could load the object */ - if (r != OK) { - return(ENOEXEC); + if (r != OK) { /* No exec loader could load the object */ + r = ENOEXEC; + goto pm_execfinal; } /* Save off PC */ @@ -191,26 +240,32 @@ PUBLIC int pm_exec(int proc_e, char *path, vir_bytes path_len, char *frame, if ((r = sys_datacopy(SELF, (vir_bytes) mbuf, proc_e, (vir_bytes) vsp, (phys_bytes)frame_len)) != OK) { printf("VFS: datacopy failed (%d) trying to copy to %lu\n", r, vsp); - return(r); + goto pm_execfinal; } - if (r != OK) return(r); + if (r != OK) goto pm_execfinal; clo_exec(rfp); if (execi.setugid) { /* If after loading the image we're still allowed to run with - * setuid or setgid, change the credentials now */ + * setuid or setgid, change credentials now */ rfp->fp_effuid = execi.new_uid; rfp->fp_effgid = execi.new_gid; } - /* This child has now exec()ced. */ - rfp->fp_execced = 1; - - return(OK); +pm_execfinal: + if (vp != NULL) { + unlock_vnode(vp); + put_vnode(vp); + } + unlock_exec(); + return(r); } -static int load_aout(struct exec_info *execi) +/*===========================================================================* + * load_aout * + *===========================================================================*/ +PRIVATE int load_aout(struct exec_info *execi) { int r; struct vnode *vp; @@ -249,14 +304,19 @@ static int load_aout(struct exec_info *execi) off = hdrlen; /* Read in text and data segments. */ - if (execi->load_text) r = read_seg(vp, off, proc_e, T, 0, text_bytes); + if (execi->load_text) + r = read_seg(vp, off, proc_e, T, 0, text_bytes); off += text_bytes; - if (r == OK) r = read_seg(vp, off, proc_e, D, 0, data_bytes); + if (r == OK) + r = read_seg(vp, off, proc_e, D, 0, data_bytes); - return (r); + return(r); } -static int load_elf(struct exec_info *execi) +/*===========================================================================* + * load_elf * + *===========================================================================*/ +PRIVATE int load_elf(struct exec_info *execi) { int r; struct vnode *vp; @@ -311,7 +371,7 @@ static int load_elf(struct exec_info *execi) /*===========================================================================* * exec_newmem * *===========================================================================*/ -static int exec_newmem( +PRIVATE int exec_newmem( int proc_e, vir_bytes text_addr, vir_bytes text_bytes, @@ -332,6 +392,7 @@ static int exec_newmem( int *setugidp ) { +/* Allocate a new memory map for a process that tries to exec */ int r; struct exec_newmem e; message m; @@ -367,25 +428,25 @@ static int exec_newmem( return(m.m_type); } -/* Is Interpreted script? */ -static int is_script(const char *exec_hdr, size_t exec_len) +/*===========================================================================* + * is_script * + *===========================================================================*/ +PRIVATE int is_script(const char *exec_hdr, size_t exec_len) { +/* Is Interpreted script? */ assert(exec_hdr != NULL); - if (exec_hdr[0] == '#' && exec_hdr[1] == '!' && exec_len >= 2) - return(TRUE); - else - return(FALSE); + return(exec_hdr[0] == '#' && exec_hdr[1] == '!' && exec_len >= 2); } /*===========================================================================* * patch_stack * *===========================================================================*/ -static int patch_stack( -struct vnode *vp, /* pointer for open script file */ -char stack[ARG_MAX], /* pointer to stack image within VFS */ -vir_bytes *stk_bytes /* size of initial stack */ -) +PRIVATE int patch_stack(vp, stack, stk_bytes, path) +struct vnode *vp; /* pointer for open script file */ +char stack[ARG_MAX]; /* pointer to stack image within VFS */ +vir_bytes *stk_bytes; /* size of initial stack */ +char path[PATH_MAX]; /* path to script file */ { /* Patch the argument vector to include the path name of the script to be * interpreted, and all strings on the #! line. Returns the path name of @@ -399,43 +460,40 @@ vir_bytes *stk_bytes /* size of initial stack */ unsigned int cum_io; char buf[_MAX_BLOCK_SIZE]; - /* Make user_fullpath the new argv[0]. */ - if (!insert_arg(stack, stk_bytes, user_fullpath, REPLACE)) { - printf("VFS: patch_stack: insert_arg for argv[0] failed\n"); - return(ENOMEM); - } + /* Make 'path' the new argv[0]. */ + if (!insert_arg(stack, stk_bytes, path, REPLACE)) return(ENOMEM); pos = 0; /* Read from the start of the file */ /* Issue request */ r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, cvul64(pos), READING, - VFS_PROC_NR, buf, _MAX_BLOCK_SIZE, &new_pos, &cum_io); + VFS_PROC_NR, buf, _MAX_BLOCK_SIZE, &new_pos, &cum_io); if (r != OK) return(r); - + n = vp->v_size; if (n > _MAX_BLOCK_SIZE) n = _MAX_BLOCK_SIZE; if (n < 2) return ENOEXEC; - + sp = &(buf[2]); /* just behind the #! */ n -= 2; if (n > PATH_MAX) n = PATH_MAX; - /* Use the user_fullpath variable for temporary storage */ - memcpy(user_fullpath, sp, n); + /* Use the 'path' variable for temporary storage */ + memcpy(path, sp, n); - if ((sp = memchr(user_fullpath, '\n', n)) == NULL) /* must be a proper line */ + if ((sp = memchr(path, '\n', n)) == NULL) /* must be a proper line */ return(ENOEXEC); /* Move sp backwards through script[], prepending each string to stack. */ for (;;) { /* skip spaces behind argument. */ - while (sp > user_fullpath && (*--sp == ' ' || *sp == '\t')) {} - if (sp == user_fullpath) break; + while (sp > path && (*--sp == ' ' || *sp == '\t')) {} + if (sp == path) break; sp[1] = 0; /* Move to the start of the argument. */ - while (sp > user_fullpath && sp[-1] != ' ' && sp[-1] != '\t') --sp; + while (sp > path && sp[-1] != ' ' && sp[-1] != '\t') --sp; interp = sp; if (!insert_arg(stack, stk_bytes, sp, INSERT)) { @@ -450,15 +508,15 @@ vir_bytes *stk_bytes /* size of initial stack */ /* Round *stk_bytes up to the size of a pointer for alignment contraints. */ *stk_bytes= ((*stk_bytes + PTRSIZE - 1) / PTRSIZE) * PTRSIZE; - if (interp != user_fullpath) - memmove(user_fullpath, interp, strlen(interp)+1); + if (interp != path) + memmove(path, interp, strlen(interp)+1); return(OK); } /*===========================================================================* * insert_arg * *===========================================================================*/ -static int insert_arg( +PRIVATE int insert_arg( char stack[ARG_MAX], /* pointer to stack image within PM */ vir_bytes *stk_bytes, /* size of initial stack */ char *arg, /* argument to prepend/replace as new argv[0] */ @@ -516,7 +574,7 @@ int replace /*===========================================================================* * patch_ptr * *===========================================================================*/ -static void patch_ptr( +PRIVATE void patch_ptr( char stack[ARG_MAX], /* pointer to stack image within PM */ vir_bytes base /* virtual address of stack base inside user */ ) @@ -549,7 +607,7 @@ vir_bytes base /* virtual address of stack base inside user */ /*===========================================================================* * read_seg * *===========================================================================*/ -static int read_seg( +PRIVATE int read_seg( struct vnode *vp, /* inode descriptor to read from */ off_t off, /* offset in file */ int proc_e, /* process number (endpoint) */ @@ -612,7 +670,7 @@ phys_bytes seg_bytes /* how much is to be transferred? */ printf("VFS: read_seg: req_readwrite failed (data)\n"); return(r); } - + if (r == OK && cum_io != seg_bytes) printf("VFS: read_seg segment has not been read properly by exec()\n"); @@ -626,9 +684,9 @@ phys_bytes seg_bytes /* how much is to be transferred? */ /*===========================================================================* * clo_exec * *===========================================================================*/ -static void clo_exec(struct fproc *rfp) +PRIVATE void clo_exec(struct fproc *rfp) { -/* Files can be marked with the FD_CLOEXEC bit (in fp->fp_cloexec). +/* Files can be marked with the FD_CLOEXEC bit (in fp->fp_cloexec). */ int i; @@ -638,13 +696,15 @@ static void clo_exec(struct fproc *rfp) (void) close_fd(rfp, i); } -static int map_header(char **exec_hdr, const struct vnode *vp) +/*===========================================================================* + * map_header * + *===========================================================================*/ +PRIVATE int map_header(char **exec_hdr, const struct vnode *vp) { int r; u64_t new_pos; unsigned int cum_io; off_t pos; - static char hdr[PAGE_SIZE]; /* Assume that header is not larger than a page */ pos = 0; /* Read from the start of the file */ diff --git a/servers/vfs/file.h b/servers/vfs/file.h index fe3b99971..52a5773c6 100644 --- a/servers/vfs/file.h +++ b/servers/vfs/file.h @@ -12,6 +12,10 @@ EXTERN struct filp { int filp_count; /* how many file descriptors share this slot?*/ struct vnode *filp_vno; /* vnode belonging to this file */ u64_t filp_pos; /* file position */ + mutex_t filp_lock; /* lock to gain exclusive access */ + struct fproc *filp_softlock; /* if not NULL; this filp didn't lock the + * vnode. Another filp already holds a lock + * for this thread */ /* the following fields are for select() and are owned by the generic * select() code (i.e., fd-type-specific select() code can't touch these). @@ -32,14 +36,13 @@ EXTERN struct filp { #define FSF_UPDATE 001 /* The driver should be informed about new * state. */ -#define FSF_BUSY 002 /* Select operation sent to driver but no +#define FSF_BUSY 002 /* Select operation sent to driver but no * reply yet. */ -#define FSF_RD_BLOCK 010 /* Read request is blocking, the driver should +#define FSF_RD_BLOCK 010 /* Read request is blocking, the driver should * keep state. */ #define FSF_WR_BLOCK 020 /* Write request is blocking */ #define FSF_ERR_BLOCK 040 /* Exception request is blocking */ #define FSF_BLOCKED 070 #endif - diff --git a/servers/vfs/filedes.c b/servers/vfs/filedes.c index a8e85dc1b..1d3cbc076 100644 --- a/servers/vfs/filedes.c +++ b/servers/vfs/filedes.c @@ -6,12 +6,12 @@ * find_filp: find a filp slot that points to a given vnode * inval_filp: invalidate a filp and associated fd's, only let close() * happen on it - * do_verify_fd: verify whether the given file descriptor is valid for + * do_verify_fd: verify whether the given file descriptor is valid for * the given endpoint. * do_set_filp: marks a filp as in-flight. * do_copy_filp: copies a filp to another endpoint. * do_put_filp: marks a filp as not in-flight anymore. - * do_cancel_fd: cancel the transaction when something goes wrong for + * do_cancel_fd: cancel the transaction when something goes wrong for * the receiver. */ @@ -24,6 +24,71 @@ #include "fproc.h" #include "vnode.h" + +FORWARD _PROTOTYPE( filp_id_t verify_fd, (endpoint_t ep, int fd) ); + +#if LOCK_DEBUG +/*===========================================================================* + * check_filp_locks * + *===========================================================================*/ +PUBLIC void check_filp_locks_by_me(void) +{ +/* Check whether this thread still has filp locks held */ + struct filp *f; + int r; + + for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { + r = mutex_trylock(&f->filp_lock); + if (r == -EDEADLK) + panic("Thread %d still holds filp lock on filp %p call_nr=%d\n", + mthread_self(), f, call_nr); + else if (r == 0) { + /* We just obtained the lock, release it */ + mutex_unlock(&f->filp_lock); + } + } +} +#endif + +/*===========================================================================* + * check_filp_locks * + *===========================================================================*/ +PUBLIC void check_filp_locks(void) +{ + struct filp *f; + int r, count = 0; + + for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { + r = mutex_trylock(&f->filp_lock); + if (r == -EBUSY) { + /* Mutex is still locked */ + count++; + } else if (r == 0) { + /* We just obtained a lock, don't want it */ + mutex_unlock(&f->filp_lock); + } else + panic("filp_lock weird state"); + } + if (count) panic("locked filps"); +#if 0 + else printf("check_filp_locks OK\n"); +#endif +} + +/*===========================================================================* + * init_filps * + *===========================================================================*/ +PUBLIC void init_filps(void) +{ +/* Initialize filps */ + struct filp *f; + + for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { + mutex_init(&f->filp_lock, NULL); + } + +} + /*===========================================================================* * get_fd * *===========================================================================*/ @@ -49,10 +114,13 @@ PUBLIC int get_fd(int start, mode_t bits, int *k, struct filp **fpt) /* Check to see if a file descriptor has been found. */ if (i >= OPEN_MAX) return(EMFILE); + /* If we don't care about a filp, return now */ + if (fpt == NULL) return(OK); + /* Now that a file descriptor has been found, look for a free filp slot. */ for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { assert(f->filp_count >= 0); - if (f->filp_count == 0) { + if (f->filp_count == 0 && mutex_trylock(&f->filp_lock) == 0) { f->filp_mode = bits; f->filp_pos = cvu64(0); f->filp_selectors = 0; @@ -61,6 +129,7 @@ PUBLIC int get_fd(int start, mode_t bits, int *k, struct filp **fpt) f->filp_flags = 0; f->filp_state = FS_NORMAL; f->filp_select_flags = 0; + f->filp_softlock = NULL; *fpt = f; return(OK); } @@ -74,38 +143,42 @@ PUBLIC int get_fd(int start, mode_t bits, int *k, struct filp **fpt) /*===========================================================================* * get_filp * *===========================================================================*/ -PUBLIC struct filp *get_filp(fild) +PUBLIC struct filp *get_filp(fild, locktype) int fild; /* file descriptor */ +tll_access_t locktype; { /* See if 'fild' refers to a valid file descr. If so, return its filp ptr. */ - return get_filp2(fp, fild); + return get_filp2(fp, fild, locktype); } /*===========================================================================* * get_filp2 * *===========================================================================*/ -PUBLIC struct filp *get_filp2(rfp, fild) +PUBLIC struct filp *get_filp2(rfp, fild, locktype) register struct fproc *rfp; int fild; /* file descriptor */ +tll_access_t locktype; { /* See if 'fild' refers to a valid file descr. If so, return its filp ptr. */ + struct filp *filp; err_code = EBADF; if (fild < 0 || fild >= OPEN_MAX ) return(NULL); - if (rfp->fp_filp[fild] == NULL && FD_ISSET(fild, &rfp->fp_filp_inuse)) + if (rfp->fp_filp[fild] == NULL && FD_ISSET(fild, &rfp->fp_filp_inuse)) err_code = EIO; /* The filedes is not there, but is not closed either. */ - - return(rfp->fp_filp[fild]); /* may also be NULL */ + if ((filp = rfp->fp_filp[fild]) != NULL) lock_filp(filp, locktype); + + return(filp); /* may also be NULL */ } /*===========================================================================* * find_filp * *===========================================================================*/ -PUBLIC struct filp *find_filp(register struct vnode *vp, mode_t bits) +PUBLIC struct filp *find_filp(struct vnode *vp, mode_t bits) { /* Find a filp slot that refers to the vnode 'vp' in a way as described * by the mode bit 'bits'. Used for determining whether somebody is still @@ -114,10 +187,10 @@ PUBLIC struct filp *find_filp(register struct vnode *vp, mode_t bits) * Like 'get_fd' it performs its job by linear search through the filp table. */ - register struct filp *f; + struct filp *f; for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { - if (f->filp_count != 0 && f->filp_vno == vp && (f->filp_mode & bits)){ + if (f->filp_count != 0 && f->filp_vno == vp && (f->filp_mode & bits)) { return(f); } } @@ -127,18 +200,18 @@ PUBLIC struct filp *find_filp(register struct vnode *vp, mode_t bits) } /*===========================================================================* - * invalidate * + * invalidate_filp * *===========================================================================*/ -PUBLIC int invalidate(struct filp *fp) +PUBLIC int invalidate_filp(struct filp *rfilp) { /* Invalidate filp. fp_filp_inuse is not cleared, so filp can't be reused until it is closed first. */ int f, fd, n = 0; - for(f = 0; f < NR_PROCS; f++) { - if(fproc[f].fp_pid == PID_FREE) continue; - for(fd = 0; fd < OPEN_MAX; fd++) { - if(fproc[f].fp_filp[fd] && fproc[f].fp_filp[fd] == fp) { + for (f = 0; f < NR_PROCS; f++) { + if (fproc[f].fp_pid == PID_FREE) continue; + for (fd = 0; fd < OPEN_MAX; fd++) { + if(fproc[f].fp_filp[fd] && fproc[f].fp_filp[fd] == rfilp) { fproc[f].fp_filp[fd] = NULL; n++; } @@ -149,24 +222,145 @@ PUBLIC int invalidate(struct filp *fp) } /*===========================================================================* - * verify_fd * + * invalidate_filp_by_endpt * *===========================================================================*/ -PUBLIC filp_id_t verify_fd(ep, fd) +PUBLIC void invalidate_filp_by_endpt(endpoint_t proc_e) +{ + struct filp *f; + + for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { + if (f->filp_count != 0 && f->filp_vno != NULL) { + if (f->filp_vno->v_fs_e == proc_e) + (void) invalidate_filp(f); + } + } +} + +/*===========================================================================* + * lock_filp * + *===========================================================================*/ +PUBLIC void lock_filp(filp, locktype) +struct filp *filp; +tll_access_t locktype; +{ + message org_m_in; + struct fproc *org_fp; + struct worker_thread *org_self; + struct vnode *vp; + + assert(filp->filp_count > 0); + vp = filp->filp_vno; + assert(vp != NULL); + + /* Lock vnode only if we haven't already locked it. If already locked by us, + * we're allowed to have one additional 'soft' lock. */ + if (tll_locked_by_me(&vp->v_lock)) { + assert(filp->filp_softlock == NULL); + filp->filp_softlock = fp; + } else { + lock_vnode(vp, locktype); + } + + assert(vp->v_ref_count > 0); /* vnode still in use? */ + assert(filp->filp_vno == vp); /* vnode still what we think it is? */ + assert(filp->filp_count > 0); /* filp still in use? */ + + /* First try to get filp lock right off the bat */ + if (mutex_trylock(&filp->filp_lock) != 0) { + + /* Already in use, let's wait for our turn */ + org_m_in = m_in; + org_fp = fp; + org_self = self; + + if (mutex_lock(&filp->filp_lock) != 0) + panic("unable to obtain lock on filp"); + + m_in = org_m_in; + fp = org_fp; + self = org_self; + } + + assert(filp->filp_count > 0); /* Yet again; filp still in use? */ +} + +/*===========================================================================* + * unlock_filp * + *===========================================================================*/ +PUBLIC void unlock_filp(filp) +struct filp *filp; +{ + /* If this filp holds a soft lock on the vnode, we must be the owner */ + if (filp->filp_softlock != NULL) + assert(filp->filp_softlock == fp); + + if (filp->filp_count > 0) { + /* Only unlock vnode if filp is still in use */ + + /* and if we don't hold a soft lock */ + if (filp->filp_softlock == NULL) { + assert(tll_islocked(&(filp->filp_vno->v_lock))); + unlock_vnode(filp->filp_vno); + } + } + + filp->filp_softlock = NULL; + if (mutex_unlock(&filp->filp_lock) != 0) + panic("unable to release lock on filp"); +} + +/*===========================================================================* + * unlock_filps * + *===========================================================================*/ +PUBLIC void unlock_filps(filp1, filp2) +struct filp *filp1; +struct filp *filp2; +{ +/* Unlock two filps that are tied to the same vnode. As a thread can lock a + * vnode only once, unlocking the vnode twice would result in an error. */ + + /* No NULL pointers and not equal */ + assert(filp1); + assert(filp2); + assert(filp1 != filp2); + + /* Must be tied to the same vnode and not NULL */ + assert(filp1->filp_vno == filp2->filp_vno); + assert(filp1->filp_vno != NULL); + + if (filp1->filp_count > 0 && filp2->filp_count > 0) { + /* Only unlock vnode if filps are still in use */ + unlock_vnode(filp1->filp_vno); + } + + filp1->filp_softlock = NULL; + filp2->filp_softlock = NULL; + if (mutex_unlock(&filp2->filp_lock) != 0) + panic("unable to release filp lock on filp2"); + if (mutex_unlock(&filp1->filp_lock) != 0) + panic("unable to release filp lock on filp1"); +} + +/*===========================================================================* + * verify_fd * + *===========================================================================*/ +PRIVATE filp_id_t verify_fd(ep, fd) endpoint_t ep; int fd; { - /* - * verify whether the given file descriptor 'fd' is valid for the - * endpoint 'ep'. When the file descriptor is valid verify_fd returns a - * pointer to that filp, else it returns NULL. - */ - int proc; +/* Verify whether the file descriptor 'fd' is valid for the endpoint 'ep'. When + * the file descriptor is valid, verify_fd returns a pointer to that filp, else + * it returns NULL. + */ + int slot; + struct filp *rfilp; - if (isokendpt(ep, &proc) != OK) { - return NULL; - } + if (isokendpt(ep, &slot) != OK) + return(NULL); - return get_filp2(&fproc[proc], fd); + rfilp = get_filp2(&fproc[slot], fd, VNODE_READ); + + return(rfilp); } /*===========================================================================* @@ -174,8 +368,11 @@ int fd; *===========================================================================*/ PUBLIC int do_verify_fd(void) { - m_out.ADDRESS = (void *) verify_fd(m_in.USER_ENDPT, m_in.COUNT); - return (m_out.ADDRESS != NULL) ? OK : EINVAL; + struct filp *rfilp; + rfilp = (struct filp *) verify_fd(m_in.USER_ENDPT, m_in.COUNT); + m_out.ADDRESS = (void *) rfilp; + if (rfilp != NULL) unlock_filp(rfilp); + return (rfilp != NULL) ? OK : EINVAL; } /*===========================================================================* @@ -184,12 +381,13 @@ PUBLIC int do_verify_fd(void) PUBLIC int set_filp(sfilp) filp_id_t sfilp; { - if (sfilp == NULL) { - return EINVAL; - } else { - sfilp->filp_count++; - return OK; - } + if (sfilp == NULL) return(EINVAL); + + lock_filp(sfilp, VNODE_READ); + sfilp->filp_count++; + unlock_filp(sfilp); + + return(OK); } /*===========================================================================* @@ -197,7 +395,7 @@ filp_id_t sfilp; *===========================================================================*/ PUBLIC int do_set_filp(void) { - return set_filp((filp_id_t) m_in.ADDRESS);; + return set_filp((filp_id_t) m_in.ADDRESS); } /*===========================================================================* @@ -207,28 +405,28 @@ PUBLIC int copy_filp(to_ep, cfilp) endpoint_t to_ep; filp_id_t cfilp; { - int j; - int proc; + int fd; + int slot; + struct fproc *rfp; - if (isokendpt(to_ep, &proc) != OK) { - return EINVAL; - } + if (isokendpt(to_ep, &slot) != OK) return(EINVAL); + rfp = &fproc[slot]; /* Find an open slot in fp_filp */ - for (j = 0; j < OPEN_MAX; j++) { - if (fproc[proc].fp_filp[j] == NULL && - !FD_ISSET(j, &fproc[proc].fp_filp_inuse)) { + for (fd = 0; fd < OPEN_MAX; fd++) { + if (rfp->fp_filp[fd] == NULL && + !FD_ISSET(fd, &rfp->fp_filp_inuse)) { /* Found a free slot, add descriptor */ - FD_SET(j, &fproc[proc].fp_filp_inuse); - fproc[proc].fp_filp[j] = cfilp; - fproc[proc].fp_filp[j]->filp_count++; - return j; + FD_SET(fd, &rfp->fp_filp_inuse); + rfp->fp_filp[fd] = cfilp; + rfp->fp_filp[fd]->filp_count++; + return(fd); } } - /* File Descriptor Table is Full */ - return EMFILE; + /* File descriptor table is full */ + return(EMFILE); } /*===========================================================================* @@ -248,8 +446,9 @@ filp_id_t pfilp; if (pfilp == NULL) { return EINVAL; } else { + lock_filp(pfilp, VNODE_OPCL); close_filp(pfilp); - return OK; + return(OK); } } @@ -262,31 +461,38 @@ PUBLIC int do_put_filp(void) } /*===========================================================================* - * cancel_fd * + * cancel_fd * *===========================================================================*/ PUBLIC int cancel_fd(ep, fd) endpoint_t ep; int fd; { - int proc; + int slot; + struct fproc *rfp; + struct filp *rfilp; - if (isokendpt(ep, &proc) != OK) { - return EINVAL; - } + if (isokendpt(ep, &slot) != OK) return(EINVAL); + rfp = &fproc[slot]; /* Check that the input 'fd' is valid */ - if (verify_fd(ep, fd) != NULL) { - + rfilp = (struct filp *) verify_fd(ep, fd); + if (rfilp != NULL) { /* Found a valid descriptor, remove it */ - FD_CLR(fd, &fproc[proc].fp_filp_inuse); - fproc[proc].fp_filp[fd]->filp_count--; - fproc[proc].fp_filp[fd] = NULL; - - return fd; + FD_CLR(fd, &rfp->fp_filp_inuse); + if (rfp->fp_filp[fd]->filp_count == 0) { + unlock_filp(rfilp); + printf("VFS: filp_count for slot %d fd %d already zero", slot, + fd); + return(EINVAL); + } + rfp->fp_filp[fd]->filp_count--; + rfp->fp_filp[fd] = NULL; + unlock_filp(rfilp); + return(fd); } /* File descriptor is not valid for the endpoint. */ - return EINVAL; + return(EINVAL); } /*===========================================================================* @@ -300,56 +506,73 @@ PUBLIC int do_cancel_fd(void) /*===========================================================================* * close_filp * *===========================================================================*/ -PUBLIC void close_filp(fp) -struct filp *fp; +PUBLIC void close_filp(f) +struct filp *f; { +/* Close a file. Will also unlock filp when done */ + int mode_word, rw; dev_t dev; struct vnode *vp; - vp = fp->filp_vno; - if (fp->filp_count - 1 == 0 && fp->filp_mode != FILP_CLOSED) { + /* Must be locked */ + assert(mutex_trylock(&f->filp_lock) == -EDEADLK); + assert(tll_islocked(&f->filp_vno->v_lock)); + + vp = f->filp_vno; + + if (f->filp_count - 1 == 0 && f->filp_mode != FILP_CLOSED) { /* Check to see if the file is special. */ mode_word = vp->v_mode & I_TYPE; if (mode_word == I_CHAR_SPECIAL || mode_word == I_BLOCK_SPECIAL) { dev = (dev_t) vp->v_sdev; if (mode_word == I_BLOCK_SPECIAL) { + lock_bsf(); if (vp->v_bfs_e == ROOT_FS_E) { /* Invalidate the cache unless the special is * mounted. Assume that the root filesystem's * is open only for fsck. - */ - req_flush(vp->v_bfs_e, dev); - } + */ + req_flush(vp->v_bfs_e, dev); + } + unlock_bsf(); } /* Do any special processing on device close. * Ignore any errors, even SUSPEND. - */ + */ if (mode_word == I_BLOCK_SPECIAL) (void) bdev_close(dev); else - (void) dev_close(dev, fp-filp); + (void) dev_close(dev, f-filp); - fp->filp_mode = FILP_CLOSED; + f->filp_mode = FILP_CLOSED; } } /* If the inode being closed is a pipe, release everyone hanging on it. */ if (vp->v_pipe == I_PIPE) { - rw = (fp->filp_mode & R_BIT ? WRITE : READ); + rw = (f->filp_mode & R_BIT ? WRITE : READ); release(vp, rw, NR_PROCS); } /* If a write has been done, the inode is already marked as DIRTY. */ - if (--fp->filp_count == 0) { + if (--f->filp_count == 0) { if (vp->v_pipe == I_PIPE) { /* Last reader or writer is going. Tell PFS about latest * pipe size. */ truncate_vnode(vp, vp->v_size); } - - put_vnode(fp->filp_vno); + + unlock_vnode(f->filp_vno); + put_vnode(f->filp_vno); + } else if (f->filp_count < 0) { + panic("VFS: invalid filp count: %d ino %d/%d", f->filp_count, + vp->v_dev, vp->v_inode_nr); + } else { + unlock_vnode(f->filp_vno); } + + mutex_unlock(&f->filp_lock); } diff --git a/servers/vfs/fproc.h b/servers/vfs/fproc.h index aab719e1f..79ede32f7 100644 --- a/servers/vfs/fproc.h +++ b/servers/vfs/fproc.h @@ -1,56 +1,69 @@ #ifndef __VFS_FPROC_H__ #define __VFS_FPROC_H__ +#include "threads.h" + #include #include /* This is the per-process information. A slot is reserved for each potential - * process. Thus NR_PROCS must be the same as in the kernel. It is not + * process. Thus NR_PROCS must be the same as in the kernel. It is not * possible or even necessary to tell when a slot is free here. */ +#define LOCK_DEBUG 0 EXTERN struct fproc { unsigned fp_flags; - mode_t fp_umask; /* mask set by umask system call */ - + pid_t fp_pid; /* process id */ + endpoint_t fp_endpoint; /* kernel endpoint number of this process */ + struct vnode *fp_wd; /* working directory; NULL during reboot */ struct vnode *fp_rd; /* root directory; NULL during reboot */ - - struct filp *fp_filp[OPEN_MAX];/* the file descriptor table */ + struct filp *fp_filp[OPEN_MAX];/* the file descriptor table */ fd_set fp_filp_inuse; /* which fd's are in use? */ + fd_set fp_cloexec_set; /* bit map for POSIX Table 6-2 FD_CLOEXEC */ + + dev_t fp_tty; /* major/minor of controlling tty */ + + int fp_blocked_on; /* what is it blocked on */ + int fp_block_callnr; /* blocked call if rd/wr can't finish */ + int fp_cum_io_partial; /* partial byte count if rd/wr can't finish */ + endpoint_t fp_task; /* which task is proc suspended on */ + endpoint_t fp_ioproc; /* proc no. in suspended-on i/o message */ + + cp_grant_id_t fp_grant; /* revoke this grant on unsuspend if > -1 */ + uid_t fp_realuid; /* real user id */ uid_t fp_effuid; /* effective user id */ gid_t fp_realgid; /* real group id */ gid_t fp_effgid; /* effective group id */ int fp_ngroups; /* number of supplemental groups */ gid_t fp_sgroups[NGROUPS_MAX];/* supplemental groups */ - dev_t fp_tty; /* major/minor of controlling tty */ - int fp_block_fd; /* place to save fd if rd/wr can't finish */ - int fp_block_callnr; /* blocked call if rd/wr can't finish */ - char *fp_buffer; /* place to save buffer if rd/wr can't finish*/ - int fp_nbytes; /* place to save bytes if rd/wr can't finish */ - int fp_cum_io_partial; /* partial byte count if rd/wr can't finish */ - int fp_revived; /* set to indicate process being revived */ - endpoint_t fp_task; /* which task is proc suspended on */ - int fp_blocked_on; /* what is it blocked on */ - - endpoint_t fp_ioproc; /* proc no. in suspended-on i/o message */ - cp_grant_id_t fp_grant; /* revoke this grant on unsuspend if > -1 */ - - char fp_sesldr; /* true if proc is a session leader */ - char fp_execced; /* true if proc has exec()ced after fork */ - pid_t fp_pid; /* process id */ - - fd_set fp_cloexec_set; /* bit map for POSIX Table 6-2 FD_CLOEXEC */ - endpoint_t fp_endpoint; /* kernel endpoint number of this process */ + mode_t fp_umask; /* mask set by umask system call */ + + message *fp_sendrec; /* request/reply to/from FS/driver */ + mutex_t fp_lock; /* mutex to lock fproc object */ + struct job fp_job; /* pending job */ + thread_t fp_wtid; /* Thread ID of worker */ +#if LOCK_DEBUG + int fp_vp_rdlocks; /* number of read-only locks on vnodes */ + int fp_vmnt_rdlocks; /* number of read-only locks on vmnts */ +#endif } fproc[NR_PROCS]; /* fp_flags */ -#define NO_FLAGS 0 -#define SUSP_REOPEN 1 /* Process is suspended until the reopens are +#define FP_NOFLAGS 00 +#define FP_SUSP_REOPEN 01 /* Process is suspended until the reopens are * completed (after the restart of a driver). */ +#define FP_REVIVED 0002 /* Indicates process is being revived */ +#define FP_SESLDR 0004 /* Set if process is session leader */ +#define FP_PENDING 0010 /* Set if process has pending work */ +#define FP_EXITING 0020 /* Set if process is exiting */ +#define FP_PM_PENDING 0040 /* Set if process has pending PM request */ +#define FP_SYS_PROC 0100 /* Set if process is a driver or FS */ +#define FP_DROP_WORK 0200 /* Set if process won't accept new work */ /* Field values. */ #define NOT_REVIVING 0xC0FFEEE /* process is not being revived */ diff --git a/servers/vfs/fs.h b/servers/vfs/fs.h index 216225de9..9531c2207 100644 --- a/servers/vfs/fs.h +++ b/servers/vfs/fs.h @@ -1,3 +1,6 @@ +#ifndef __VFS_FS_H__ +#define __VFS_FS_H__ + /* This is the master header for fs. It includes some other files * and defines the principal constants. */ @@ -40,4 +43,9 @@ #include "const.h" #include "dmap.h" #include "proto.h" +#include "threads.h" #include "glo.h" +#include "comm.h" +#include "vmnt.h" + +#endif diff --git a/servers/vfs/fscall.c b/servers/vfs/fscall.c index 214457afb..257afb32e 100644 --- a/servers/vfs/fscall.c +++ b/servers/vfs/fscall.c @@ -45,25 +45,16 @@ PRIVATE int push_globals() */ if (depth == MAX_DEPTH) - return EPERM; + return(EPERM); globals[depth].g_fp = fp; globals[depth].g_m_in = m_in; globals[depth].g_m_out = m_out; - globals[depth].g_who_e = who_e; - globals[depth].g_who_p = who_p; - globals[depth].g_call_nr = call_nr; globals[depth].g_super_user = super_user; - /* XXX is it safe to strcpy this? */ - assert(sizeof(globals[0].g_user_fullpath) == sizeof(user_fullpath)); - memcpy(globals[depth].g_user_fullpath, user_fullpath, sizeof(user_fullpath)); - /* err_code is not used across blocking calls */ - depth++; - - return OK; + return(OK); } /*===========================================================================* @@ -82,12 +73,7 @@ PRIVATE void pop_globals() fp = globals[depth].g_fp; m_in = globals[depth].g_m_in; m_out = globals[depth].g_m_out; - who_e = globals[depth].g_who_e; - who_p = globals[depth].g_who_p; - call_nr = globals[depth].g_call_nr; - super_user = globals[depth].g_super_user; - memcpy(user_fullpath, globals[depth].g_user_fullpath, sizeof(user_fullpath)); } /*===========================================================================* @@ -98,13 +84,13 @@ message *m; /* request message */ { /* Initialize global variables based on a request message. */ + int proc_p; m_in = *m; - who_e = m_in.m_source; - who_p = _ENDPOINT_P(who_e); - call_nr = m_in.m_type; - fp = &fproc[who_p]; - super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); + + proc_p = _ENDPOINT_P(m_in.m_source); + fp = &fproc[proc_p]; + /* the rest need not be initialized */ } @@ -144,51 +130,3 @@ message *m; /* request/reply message pointer */ m->m_type = r; } - -/*===========================================================================* - * nested_dev_call * - *===========================================================================*/ -PUBLIC void nested_dev_call(m) -message *m; /* request/reply message pointer */ -{ -/* Handle a nested call from a device driver server. - */ - int r; - - /* Save global variables of the current call */ - if ((r = push_globals()) != OK) { - printf("VFS: error saving globals in call %d from driver %d\n", - m->m_type, m->m_source); - } else { - /* Initialize global variables for the nested call */ - set_globals(m); - - if (call_nr >= PFS_BASE) { - call_nr -= PFS_BASE; - } - - /* Perform the nested call */ - if (call_nr < 0 || call_nr >= PFS_NREQS) { - - printf("VFS: invalid nested call %d from driver %d\n", - call_nr, who_e); - - r = ENOSYS; - } else if (who_e == PFS_PROC_NR) { - - r = (*pfs_call_vec[call_nr])(); - } else { - - printf("VFS: only the PFS device can make nested VFS calls\n"); - - r = ENOSYS; - } - - /* Store the result, and restore original global variables */ - *m = m_out; - - pop_globals(); - } - - m->m_type = r; -} diff --git a/servers/vfs/gcov.c b/servers/vfs/gcov.c index 374322f73..50bed6451 100644 --- a/servers/vfs/gcov.c +++ b/servers/vfs/gcov.c @@ -16,58 +16,51 @@ PUBLIC int do_gcov_flush() * makes the target copy its buffer to the caller (incl vfs * itself). */ - struct fproc *rfp; - ssize_t size; - cp_grant_id_t grantid; - int r; - int n; - pid_t target; + struct fproc *rfp; + ssize_t size; + cp_grant_id_t grantid; + int r, n; + pid_t target; + message m; - size = m_in.GCOV_BUFF_SZ; - target = m_in.GCOV_PID; + size = m_in.GCOV_BUFF_SZ; + target = m_in.GCOV_PID; - /* If the wrong process is sent to, the system hangs; - * so make this root-only. - */ + /* If the wrong process is sent to, the system hangs; so make this root-only. + */ - if (!super_user) return(EPERM); + if (!super_user) return(EPERM); - /* Find target gcov process. */ + /* Find target gcov process. */ + for(n = 0; n < NR_PROCS; n++) { + if(fproc[n].fp_endpoint != NONE && fproc[n].fp_pid == target) + break; + } + if(n >= NR_PROCS) { + printf("VFS: gcov process %d not found\n", target); + return(ESRCH); + } + rfp = &fproc[n]; - for(n = 0; n < NR_PROCS; n++) { - if(fproc[n].fp_endpoint != NONE && - fproc[n].fp_pid == target) - break; - } + /* Grant target process to requestor's buffer. */ + if ((grantid = cpf_grant_magic(rfp->fp_endpoint, who_e, + (vir_bytes) m_in.GCOV_BUFF_P, size, + CPF_WRITE)) < 0) { + printf("VFS: gcov_flush: grant failed\n"); + return(ENOMEM); + } - if(n >= NR_PROCS) { - printf("VFS: gcov proccess %d not found.\n", target); - return ESRCH; - } + if(rfp->fp_endpoint == VFS_PROC_NR) { + /* Request is for VFS itself. */ + r = gcov_flush(grantid, size); + } else { + /* Perform generic GCOV request. */ + m.GCOV_GRANT = grantid; + m.GCOV_BUFF_SZ = size; + r = _taskcall(rfp->fp_endpoint, COMMON_REQ_GCOV_DATA, &m); + } - rfp = &fproc[n]; + cpf_revoke(grantid); - /* Grant target process to requestor's buffer. */ - - if((grantid = cpf_grant_magic(rfp->fp_endpoint, - who_e, (vir_bytes) m_in.GCOV_BUFF_P, - size, CPF_WRITE)) < 0) { - printf("VFS: gcov_flush: grant failed\n"); - return ENOMEM; - } - - if(target == getpid()) { - /* Request is for VFS itself. */ - r = gcov_flush(grantid, size); - } else { - /* Perform generic GCOV request. */ - m_out.GCOV_GRANT = grantid; - m_out.GCOV_BUFF_SZ = size; - r = _taskcall(rfp->fp_endpoint, COMMON_REQ_GCOV_DATA, &m_out); - } - - cpf_revoke(grantid); - - return r; + return(r); } - diff --git a/servers/vfs/glo.h b/servers/vfs/glo.h index 6ecb0a4cd..c07220aa0 100644 --- a/servers/vfs/glo.h +++ b/servers/vfs/glo.h @@ -1,3 +1,6 @@ +#ifndef __VFS_GLO_H__ +#define __VFS_GLO_H__ + /* EXTERN should be extern except for the table file */ #ifdef _TABLE #undef EXTERN @@ -6,26 +9,41 @@ /* File System global variables */ EXTERN struct fproc *fp; /* pointer to caller's fproc struct */ -EXTERN int super_user; /* 1 if caller is super_user, else 0 */ EXTERN int susp_count; /* number of procs suspended on pipe */ EXTERN int nr_locks; /* number of locks currently in place */ EXTERN int reviving; /* number of pipe processes to be revived */ +EXTERN int pending; +EXTERN int sending; -EXTERN dev_t root_dev; /* device number of the root device */ +EXTERN dev_t ROOT_DEV; /* device number of the root device */ EXTERN int ROOT_FS_E; /* kernel endpoint of the root FS proc */ EXTERN u32_t system_hz; /* system clock frequency. */ /* The parameters of the call are kept here. */ EXTERN message m_in; /* the input message itself */ EXTERN message m_out; /* the output message used for reply */ -EXTERN int who_p, who_e; /* caller's proc number, endpoint */ -EXTERN int call_nr; /* system call number */ - -EXTERN message mount_m_in; /* the input message for a mount request */ +# define who_p ((int) (fp - fproc)) +# define isokslot(p) (p >= 0 && \ + p < (int)(sizeof(fproc) / sizeof(struct fproc))) +#if 0 +# define who_e (isokslot(who_p) ? fp->fp_endpoint : m_in.m_source) +#else +# define who_e (isokslot(who_p) && fp->fp_endpoint != NONE ? \ + fp->fp_endpoint : m_in.m_source) +#endif +# define call_nr (m_in.m_type) +# define super_user (fp->fp_effuid == SU_UID ? 1 : 0) +# define scratch(p) (scratchpad[((int) ((p) - fproc))]) +EXTERN struct worker_thread *self; +EXTERN int force_sync; /* toggle forced synchronous communication */ +EXTERN int deadlock_resolving; +EXTERN mutex_t exec_lock; +EXTERN mutex_t bsf_lock;/* Global lock for access to block special files */ +EXTERN struct worker_thread workers[NR_WTHREADS]; +EXTERN struct worker_thread sys_worker; +EXTERN struct worker_thread dl_worker; EXTERN char mount_label[LABEL_MAX]; /* label of file system to mount */ -EXTERN char user_fullpath[PATH_MAX]; /* storage for user path name */ - /* The following variables are used for returning results to the caller. */ EXTERN int err_code; /* temporary storage for error number */ @@ -35,3 +53,5 @@ extern _PROTOTYPE (int (*pfs_call_vec[]), (void) ); /* pfs callback table */ extern char dot1[2]; /* dot1 (&dot1[0]) and dot2 (&dot2[0]) have a special */ extern char dot2[3]; /* meaning to search_dir: no access permission check. */ extern char mode_map[]; /* mapping from O_ACCMODE mask to R_BIT/W_BIT flags */ + +#endif diff --git a/servers/avfs/job.h b/servers/vfs/job.h similarity index 100% rename from servers/avfs/job.h rename to servers/vfs/job.h diff --git a/servers/vfs/link.c b/servers/vfs/link.c index 5a1f81564..1c0b4af86 100644 --- a/servers/vfs/link.c +++ b/servers/vfs/link.c @@ -16,12 +16,14 @@ #include #include #include +#include #include +#include #include "file.h" #include "fproc.h" -#include "param.h" -#include +#include "path.h" #include "vnode.h" +#include "param.h" /*===========================================================================* * do_link * @@ -30,34 +32,52 @@ PUBLIC int do_link() { /* Perform the link(name1, name2) system call. */ int r = OK; - struct vnode *vp = NULL, *vp_d = NULL; + struct vnode *vp = NULL, *dirp = NULL; + struct vmnt *vmp1 = NULL, *vmp2 = NULL; + char fullpath[PATH_MAX]; + struct lookup resolve; - /* See if 'name1' (file to be linked to) exists. */ - if(fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); + lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp1, &vp); + resolve.l_vmnt_lock = VMNT_WRITE; + resolve.l_vnode_lock = VNODE_READ; + + /* See if 'name1' (file to be linked to) exists. */ + if (fetch_name(m_in.name1, m_in.name1_length, M1, fullpath) != OK) + return(err_code); + if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); /* Does the final directory of 'name2' exist? */ - if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) + lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp2, &dirp); + resolve.l_vmnt_lock = VMNT_READ; + resolve.l_vnode_lock = VNODE_READ; + if (fetch_name(m_in.name2, m_in.name2_length, M1, fullpath) != OK) r = err_code; - else if ((vp_d = last_dir(fp)) == NULL) - r = err_code; + else if ((dirp = last_dir(&resolve, fp)) == NULL) + r = err_code; + if (r != OK) { - put_vnode(vp); - return(r); + unlock_vnode(vp); + unlock_vmnt(vmp1); + put_vnode(vp); + return(r); } /* Check for links across devices. */ - if(vp->v_fs_e != vp_d->v_fs_e) - r = EXDEV; - else - r = forbidden(fp, vp_d, W_BIT | X_BIT); + if (vp->v_fs_e != dirp->v_fs_e) + r = EXDEV; + else + r = forbidden(fp, dirp, W_BIT | X_BIT); if (r == OK) - r = req_link(vp->v_fs_e, vp_d->v_inode_nr, user_fullpath, + r = req_link(vp->v_fs_e, dirp->v_inode_nr, fullpath, vp->v_inode_nr); + unlock_vnode(vp); + unlock_vnode(dirp); + if (vmp2 != NULL) unlock_vmnt(vmp2); + unlock_vmnt(vmp1); put_vnode(vp); - put_vnode(vp_d); + put_vnode(dirp); return(r); } @@ -71,52 +91,78 @@ PUBLIC int do_unlink() * is almost the same. They differ only in some condition testing. Unlink() * may be used by the superuser to do dangerous things; rmdir() may not. */ - struct vnode *vldirp, *vp; + struct vnode *dirp, *vp; + struct vmnt *vmp, *vmp2; int r; - + char fullpath[PATH_MAX]; + struct lookup resolve; + + lookup_init(&resolve, fullpath, PATH_RET_SYMLINK, &vmp, &dirp); + resolve.l_vmnt_lock = VMNT_WRITE; + resolve.l_vnode_lock = VNODE_READ; + /* Get the last directory in the path. */ - if(fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); - if ((vldirp = last_dir(fp)) == NULL) return(err_code); + if (fetch_name(m_in.name, m_in.name_length, M3, fullpath) != OK) + return(err_code); + + if ((dirp = last_dir(&resolve, fp)) == NULL) return(err_code); + assert(vmp != NULL); /* Make sure that the object is a directory */ - if((vldirp->v_mode & I_TYPE) != I_DIRECTORY) { - put_vnode(vldirp); - return(ENOTDIR); + if ((dirp->v_mode & I_TYPE) != I_DIRECTORY) { + unlock_vnode(dirp); + unlock_vmnt(vmp); + put_vnode(dirp); + return(ENOTDIR); } /* The caller must have both search and execute permission */ - if ((r = forbidden(fp, vldirp, X_BIT | W_BIT)) != OK) { - put_vnode(vldirp); + if ((r = forbidden(fp, dirp, X_BIT | W_BIT)) != OK) { + unlock_vnode(dirp); + unlock_vmnt(vmp); + put_vnode(dirp); return(r); } - + /* Also, if the sticky bit is set, only the owner of the file or a privileged user is allowed to unlink */ - if ((vldirp->v_mode & S_ISVTX) == S_ISVTX) { + if ((dirp->v_mode & S_ISVTX) == S_ISVTX) { /* Look up inode of file to unlink to retrieve owner */ - vp = advance(vldirp, PATH_RET_SYMLINK, fp); + resolve.l_flags = PATH_RET_SYMLINK; + resolve.l_vmp = &vmp2; /* Shouldn't actually get locked */ + resolve.l_vmnt_lock = VMNT_READ; + resolve.l_vnode = &vp; + resolve.l_vnode_lock = VNODE_READ; + vp = advance(dirp, &resolve, fp); + assert(vmp2 == NULL); if (vp != NULL) { - if(vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID) + if (vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID) r = EPERM; + unlock_vnode(vp); put_vnode(vp); } else r = err_code; if (r != OK) { - put_vnode(vldirp); + unlock_vnode(dirp); + unlock_vmnt(vmp); + put_vnode(dirp); return(r); } } - - if(call_nr == UNLINK) - r = req_unlink(vldirp->v_fs_e, vldirp->v_inode_nr, user_fullpath); - else - r = req_rmdir(vldirp->v_fs_e, vldirp->v_inode_nr, user_fullpath); - - put_vnode(vldirp); + + assert(vmp != NULL); + tll_upgrade(&vmp->m_lock); + + if (call_nr == UNLINK) + r = req_unlink(dirp->v_fs_e, dirp->v_inode_nr, fullpath); + else + r = req_rmdir(dirp->v_fs_e, dirp->v_inode_nr, fullpath); + unlock_vnode(dirp); + unlock_vmnt(vmp); + put_vnode(dirp); return(r); } - /*===========================================================================* * do_rename * *===========================================================================*/ @@ -125,61 +171,93 @@ PUBLIC int do_rename() /* Perform the rename(name1, name2) system call. */ int r = OK, r1; struct vnode *old_dirp, *new_dirp = NULL, *vp; + struct vmnt *oldvmp, *newvmp, *vmp2; char old_name[PATH_MAX]; - + char fullpath[PATH_MAX]; + struct lookup resolve; + + lookup_init(&resolve, fullpath, PATH_NOFLAGS, &oldvmp, &old_dirp); + /* Do not yet request exclusive lock on vmnt to prevent deadlocks later on */ + resolve.l_vmnt_lock = VMNT_WRITE; + resolve.l_vnode_lock = VNODE_READ; + /* See if 'name1' (existing file) exists. Get dir and file inodes. */ - if(fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((old_dirp = last_dir(fp)) == NULL) return(err_code); + if (fetch_name(m_in.name1, m_in.name1_length, M1, fullpath) != OK) + return(err_code); + if ((old_dirp = last_dir(&resolve, fp)) == NULL) + return(err_code); /* If the sticky bit is set, only the owner of the file or a privileged user is allowed to rename */ - if((old_dirp->v_mode & S_ISVTX) == S_ISVTX) { + if ((old_dirp->v_mode & S_ISVTX) == S_ISVTX) { /* Look up inode of file to unlink to retrieve owner */ - vp = advance(old_dirp, PATH_RET_SYMLINK, fp); + lookup_init(&resolve, resolve.l_path, PATH_RET_SYMLINK, &vmp2, &vp); + resolve.l_vmnt_lock = VMNT_READ; + resolve.l_vnode_lock = VNODE_READ; + vp = advance(old_dirp, &resolve, fp); + assert(vmp2 == NULL); if (vp != NULL) { - if(vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID) + if(vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID) r = EPERM; + unlock_vnode(vp); put_vnode(vp); } else r = err_code; - if (r != OK) { + if (r != OK) { + unlock_vnode(old_dirp); + unlock_vmnt(oldvmp); put_vnode(old_dirp); return(r); } } - + /* Save the last component of the old name */ - if(strlen(user_fullpath) >= sizeof(old_name)) { + if(strlen(fullpath) >= sizeof(old_name)) { + unlock_vnode(old_dirp); + unlock_vmnt(oldvmp); put_vnode(old_dirp); return(ENAMETOOLONG); } - strcpy(old_name, user_fullpath); - + strcpy(old_name, fullpath); + /* See if 'name2' (new name) exists. Get dir inode */ - if(fetch_name(m_in.name2, m_in.name2_length, M1) != OK) + lookup_init(&resolve, fullpath, PATH_NOFLAGS, &newvmp, &new_dirp); + resolve.l_vmnt_lock = VMNT_READ; + resolve.l_vnode_lock = VNODE_READ; + if (fetch_name(m_in.name2, m_in.name2_length, M1, fullpath) != OK) r = err_code; - else if ((new_dirp = last_dir(fp)) == NULL) - r = err_code; + else if ((new_dirp = last_dir(&resolve, fp)) == NULL) + r = err_code; + if (r != OK) { - put_vnode(old_dirp); - return r; + unlock_vnode(old_dirp); + unlock_vmnt(oldvmp); + put_vnode(old_dirp); + return(r); } /* Both parent directories must be on the same device. */ - if(old_dirp->v_fs_e != new_dirp->v_fs_e) r = EXDEV; + if (old_dirp->v_fs_e != new_dirp->v_fs_e) r = EXDEV; /* Parent dirs must be writable, searchable and on a writable device */ if ((r1 = forbidden(fp, old_dirp, W_BIT|X_BIT)) != OK || (r1 = forbidden(fp, new_dirp, W_BIT|X_BIT)) != OK) r = r1; - - if(r == OK) - r = req_rename(old_dirp->v_fs_e, old_dirp->v_inode_nr, old_name, - new_dirp->v_inode_nr, user_fullpath); + + if (r == OK) { + tll_upgrade(&oldvmp->m_lock); /* Upgrade to exclusive access */ + r = req_rename(old_dirp->v_fs_e, old_dirp->v_inode_nr, old_name, + new_dirp->v_inode_nr, fullpath); + } + unlock_vnode(old_dirp); + unlock_vnode(new_dirp); + unlock_vmnt(oldvmp); + if (newvmp) unlock_vmnt(newvmp); + put_vnode(old_dirp); put_vnode(new_dirp); + return(r); } - /*===========================================================================* * do_truncate * @@ -192,23 +270,31 @@ PUBLIC int do_truncate() * work. */ struct vnode *vp; + struct vmnt *vmp; int r; + char fullpath[PATH_MAX]; + struct lookup resolve; + + lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); + resolve.l_vmnt_lock = VMNT_EXCL; + resolve.l_vnode_lock = VNODE_WRITE; if ((off_t) m_in.flength < 0) return(EINVAL); /* Temporarily open file */ - if (fetch_name(m_in.m2_p1, m_in.m2_i1, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); - + if (fetch_name(m_in.m2_p1, m_in.m2_i1, M1, fullpath) != OK) return(err_code); + if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); + /* Ask FS to truncate the file */ if ((r = forbidden(fp, vp, W_BIT)) == OK) - r = truncate_vnode(vp, m_in.flength); - + r = truncate_vnode(vp, m_in.flength); + + unlock_vnode(vp); + unlock_vmnt(vmp); put_vnode(vp); return(r); } - /*===========================================================================* * do_ftruncate * *===========================================================================*/ @@ -216,13 +302,20 @@ PUBLIC int do_ftruncate() { /* As with do_truncate(), truncate_vnode() does the actual work. */ struct filp *rfilp; - + int r; + if ((off_t) m_in.flength < 0) return(EINVAL); /* File is already opened; get a vnode pointer from filp */ - if ((rfilp = get_filp(m_in.m2_i1)) == NULL) return(err_code); - if (!(rfilp->filp_mode & W_BIT)) return(EBADF); - return truncate_vnode(rfilp->filp_vno, m_in.flength); + if ((rfilp = get_filp(m_in.m2_i1, VNODE_WRITE)) == NULL) return(err_code); + + if (!(rfilp->filp_mode & W_BIT)) + r = EBADF; + else + r = truncate_vnode(rfilp->filp_vno, m_in.flength); + + unlock_filp(rfilp); + return(r); } @@ -233,14 +326,14 @@ PUBLIC int truncate_vnode(vp, newsize) struct vnode *vp; off_t newsize; { +/* Truncate a regular file or a pipe */ int r, file_type; + assert(tll_locked_by_me(&vp->v_lock)); file_type = vp->v_mode & I_TYPE; if (file_type != I_REGULAR && file_type != I_NAMED_PIPE) return(EINVAL); - if ((r = req_ftrunc(vp->v_fs_e, vp->v_inode_nr, newsize, 0)) == OK) vp->v_size = newsize; - return(r); } @@ -253,21 +346,33 @@ PUBLIC int do_slink() /* Perform the symlink(name1, name2) system call. */ int r; struct vnode *vp; + struct vmnt *vmp; + char fullpath[PATH_MAX]; + struct lookup resolve; + + lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); + resolve.l_vmnt_lock = VMNT_WRITE; + resolve.l_vnode_lock = VNODE_READ; + + if (m_in.name1_length <= 1) return(ENOENT); + if (m_in.name1_length >= SYMLINK_MAX) return(ENAMETOOLONG); - if(m_in.name1_length <= 1) return(ENOENT); - if(m_in.name1_length >= SYMLINK_MAX) return(ENAMETOOLONG); - /* Get dir inode of 'name2' */ - if(fetch_name(m_in.name2, m_in.name2_length, M1) != OK) return(err_code); - if ((vp = last_dir(fp)) == NULL) return(err_code); + if (fetch_name(m_in.name2, m_in.name2_length, M1, fullpath) != OK) + return(err_code); + + if ((vp = last_dir(&resolve, fp)) == NULL) return(err_code); if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) { - r = req_slink(vp->v_fs_e, vp->v_inode_nr, user_fullpath, who_e, + r = req_slink(vp->v_fs_e, vp->v_inode_nr, fullpath, who_e, m_in.name1, m_in.name1_length - 1, fp->fp_effuid, fp->fp_effgid); } + unlock_vnode(vp); + unlock_vmnt(vmp); put_vnode(vp); + return(r); } @@ -276,55 +381,75 @@ PUBLIC int do_slink() *===========================================================================*/ PUBLIC int rdlink_direct(orig_path, link_path, rfp) char *orig_path; -char *link_path; /* should have length PATH_MAX */ +char link_path[PATH_MAX]; /* should have length PATH_MAX */ struct fproc *rfp; { /* Perform a readlink()-like call from within the VFS */ int r; struct vnode *vp; + struct vmnt *vmp; + struct lookup resolve; - /* Temporarily open the file containing the symbolic link */ - orig_path[PATH_MAX - 1] = '\0'; - strncpy(user_fullpath, orig_path, PATH_MAX); - if ((vp = eat_path(PATH_RET_SYMLINK, rfp)) == NULL) return(err_code); + lookup_init(&resolve, link_path, PATH_RET_SYMLINK, &vmp, &vp); + resolve.l_vmnt_lock = VMNT_READ; + resolve.l_vnode_lock = VNODE_READ; + + /* Temporarily open the file containing the symbolic link. Use link_path + * for temporary storage to keep orig_path untouched. */ + strncpy(link_path, orig_path, PATH_MAX); /* PATH_MAX includes '\0' */ + link_path[PATH_MAX - 1] = '\0'; + if ((vp = eat_path(&resolve, rfp)) == NULL) return(err_code); /* Make sure this is a symbolic link */ - if((vp->v_mode & I_TYPE) != I_SYMBOLIC_LINK) + if ((vp->v_mode & I_TYPE) != I_SYMBOLIC_LINK) r = EINVAL; else - r = req_rdlink(vp->v_fs_e, vp->v_inode_nr, (endpoint_t) 0, - link_path, PATH_MAX - 1, 1); - if (r > 0) link_path[r] = '\0'; + r = req_rdlink(vp->v_fs_e, vp->v_inode_nr, NONE, link_path, + PATH_MAX - 1, 1); + if (r > 0) link_path[r] = '\0'; /* Terminate string when succesful */ + + unlock_vnode(vp); + unlock_vmnt(vmp); put_vnode(vp); + return r; } /*===========================================================================* - * do_rdlink * + * do_rdlink * *===========================================================================*/ PUBLIC int do_rdlink() { /* Perform the readlink(name, buf, bufsize) system call. */ int r, copylen; struct vnode *vp; - + struct vmnt *vmp; + char fullpath[PATH_MAX]; + struct lookup resolve; + + lookup_init(&resolve, fullpath, PATH_RET_SYMLINK, &vmp, &vp); + resolve.l_vmnt_lock = VMNT_READ; + resolve.l_vnode_lock = VNODE_READ; + copylen = m_in.nbytes; - if(copylen < 0) return(EINVAL); + if (copylen < 0) return(EINVAL); /* Temporarily open the file containing the symbolic link */ - if(fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_RET_SYMLINK, fp)) == NULL) return(err_code); + if (fetch_name(m_in.name1, m_in.name1_length, M1, fullpath) != OK) + return(err_code); + if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); /* Make sure this is a symbolic link */ - if((vp->v_mode & I_TYPE) != I_SYMBOLIC_LINK) + if ((vp->v_mode & I_TYPE) != I_SYMBOLIC_LINK) r = EINVAL; else r = req_rdlink(vp->v_fs_e, vp->v_inode_nr, who_e, m_in.name2, - copylen, 0); + copylen, 0); + unlock_vnode(vp); + unlock_vmnt(vmp); put_vnode(vp); + return(r); } - - diff --git a/servers/vfs/lock.c b/servers/vfs/lock.c index 340642f41..36ab59351 100644 --- a/servers/vfs/lock.c +++ b/servers/vfs/lock.c @@ -12,9 +12,10 @@ #include #include "file.h" #include "fproc.h" +#include "scratchpad.h" #include "lock.h" -#include "param.h" #include "vnode.h" +#include "param.h" /*===========================================================================* * lock_op * @@ -29,13 +30,11 @@ int req; /* either F_SETLK or F_SETLKW */ mode_t mo; off_t first, last; struct flock flock; - vir_bytes user_flock; struct file_lock *flp, *flp2, *empty; /* Fetch the flock structure from user space. */ - user_flock = (vir_bytes) m_in.name1; - r = sys_datacopy(who_e, (vir_bytes) user_flock, VFS_PROC_NR, - (vir_bytes) &flock, (phys_bytes) sizeof(flock)); + r = sys_datacopy(who_e, (vir_bytes) scratch(fp).io.io_buffer, VFS_PROC_NR, + (vir_bytes) &flock, sizeof(flock)); if (r != OK) return(EINVAL); /* Make some error checks. */ @@ -43,26 +42,27 @@ int req; /* either F_SETLK or F_SETLKW */ mo = f->filp_mode; if (ltype != F_UNLCK && ltype != F_RDLCK && ltype != F_WRLCK) return(EINVAL); if (req == F_GETLK && ltype == F_UNLCK) return(EINVAL); - if ( (f->filp_vno->v_mode & I_TYPE) != I_REGULAR) return(EINVAL); + if ( (f->filp_vno->v_mode & I_TYPE) != I_REGULAR && + (f->filp_vno->v_mode & I_TYPE) != I_BLOCK_SPECIAL) return(EINVAL); if (req != F_GETLK && ltype == F_RDLCK && (mo & R_BIT) == 0) return(EBADF); if (req != F_GETLK && ltype == F_WRLCK && (mo & W_BIT) == 0) return(EBADF); /* Compute the first and last bytes in the lock region. */ switch (flock.l_whence) { - case SEEK_SET: first = 0; break; - case SEEK_CUR: - if (ex64hi(f->filp_pos) != 0) + case SEEK_SET: first = 0; break; + case SEEK_CUR: + if (ex64hi(f->filp_pos) != 0) panic("lock_op: position in file too high"); - first = ex64lo(f->filp_pos); - break; - case SEEK_END: first = f->filp_vno->v_size; break; - default: return(EINVAL); + first = ex64lo(f->filp_pos); + break; + case SEEK_END: first = f->filp_vno->v_size; break; + default: return(EINVAL); } /* Check for overflow. */ - if (((long)flock.l_start > 0) && ((first + flock.l_start) < first)) + if (((long) flock.l_start > 0) && ((first + flock.l_start) < first)) return(EINVAL); - if (((long)flock.l_start < 0) && ((first + flock.l_start) > first)) + if (((long) flock.l_start < 0) && ((first + flock.l_start) > first)) return(EINVAL); first = first + flock.l_start; last = first + flock.l_len - 1; @@ -81,7 +81,7 @@ int req; /* either F_SETLK or F_SETLKW */ if (first > flp->lock_last) continue; /* new one is afterwards */ if (ltype == F_RDLCK && flp->lock_type == F_RDLCK) continue; if (ltype != F_UNLCK && flp->lock_pid == fp->fp_pid) continue; - + /* There might be a conflict. Process it. */ conflict = 1; if (req == F_GETLK) break; @@ -116,7 +116,7 @@ int req; /* either F_SETLK or F_SETLKW */ flp->lock_last = first - 1; continue; } - + /* Bad luck. A lock has been split in two by unlocking the middle. */ if (nr_locks == NR_LOCKS) return(ENOLCK); for (i = 0; i < NR_LOCKS; i++) @@ -148,7 +148,7 @@ int req; /* either F_SETLK or F_SETLKW */ /* Copy the flock structure back to the caller. */ r = sys_datacopy(VFS_PROC_NR, (vir_bytes) &flock, - who_e, (vir_bytes) user_flock, (phys_bytes) sizeof(flock)); + who_e, (vir_bytes) scratch(fp).io.io_buffer, sizeof(flock)); return(r); } @@ -171,22 +171,21 @@ int req; /* either F_SETLK or F_SETLKW */ *===========================================================================*/ PUBLIC void lock_revive() { -/* Go find all the processes that are waiting for any kind of lock and - * revive them all. The ones that are still blocked will block again when - * they run. The others will complete. This strategy is a space-time - * tradeoff. Figuring out exactly which ones to unblock now would take - * extra code, and the only thing it would win would be some performance in - * extremely rare circumstances (namely, that somebody actually used +/* Go find all the processes that are waiting for any kind of lock and + * revive them all. The ones that are still blocked will block again when + * they run. The others will complete. This strategy is a space-time + * tradeoff. Figuring out exactly which ones to unblock now would take + * extra code, and the only thing it would win would be some performance in + * extremely rare circumstances (namely, that somebody actually used * locking). */ struct fproc *fptr; for (fptr = &fproc[0]; fptr < &fproc[NR_PROCS]; fptr++){ - if(fptr->fp_pid == PID_FREE) continue; + if (fptr->fp_pid == PID_FREE) continue; if (fptr->fp_blocked_on == FP_BLOCKED_ON_LOCK) { revive(fptr->fp_endpoint, 0); } } } - diff --git a/servers/vfs/lock.h b/servers/vfs/lock.h index 95ab56c83..c2baa651e 100644 --- a/servers/vfs/lock.h +++ b/servers/vfs/lock.h @@ -1,3 +1,6 @@ +#ifndef __VFS_LOCK_H__ +#define __VFS_LOCK_H__ + /* This is the file locking table. Like the filp table, it points to the * inode table, however, in this case to achieve advisory locking. */ @@ -9,4 +12,4 @@ EXTERN struct file_lock { off_t lock_last; /* offset of last byte locked */ } file_lock[NR_LOCKS]; - +#endif diff --git a/servers/vfs/main.c b/servers/vfs/main.c index c9bd692e3..27d99bf07 100644 --- a/servers/vfs/main.c +++ b/servers/vfs/main.c @@ -6,8 +6,6 @@ * main: main program of the Virtual File System * reply: send a reply to a process after the requested work is done * - * Changes for VFS: - * Jul 2006 (Balazs Gerofi) */ #include "fs.h" @@ -27,25 +25,44 @@ #include #include #include -#include "file.h" -#include "fproc.h" -#include "param.h" - #include +#include "file.h" +#include "dmap.h" +#include "fproc.h" +#include "scratchpad.h" #include "vmnt.h" #include "vnode.h" +#include "job.h" +#include "param.h" #if ENABLE_SYSCALL_STATS EXTERN unsigned long calls_stats[NCALLS]; #endif +/* Thread related prototypes */ +FORWARD _PROTOTYPE( void thread_cleanup_f, (struct fproc *rfp, char *f, + int l) ); +#define thread_cleanup(x) thread_cleanup_f(x, __FILE__, __LINE__) +FORWARD _PROTOTYPE( void *do_async_dev_result, (void *arg) ); +FORWARD _PROTOTYPE( void *do_control_msgs, (void *arg) ); +FORWARD _PROTOTYPE( void *do_fs_reply, (struct job *job) ); +FORWARD _PROTOTYPE( void *do_work, (void *arg) ); +FORWARD _PROTOTYPE( void *do_pm, (void *arg) ); +FORWARD _PROTOTYPE( void *do_init_root, (void *arg) ); +FORWARD _PROTOTYPE( void handle_work, (void *(*func)(void *arg)) ); + FORWARD _PROTOTYPE( void get_work, (void) ); -FORWARD _PROTOTYPE( void init_root, (void) ); +FORWARD _PROTOTYPE( void lock_pm, (void) ); +FORWARD _PROTOTYPE( void unlock_pm, (void) ); FORWARD _PROTOTYPE( void service_pm, (void) ); +FORWARD _PROTOTYPE( void service_pm_postponed, (void) ); +FORWARD _PROTOTYPE( int unblock, (struct fproc *rfp) ); /* SEF functions and variables. */ FORWARD _PROTOTYPE( void sef_local_startup, (void) ); FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) ); +PRIVATE mutex_t pm_lock; +PRIVATE endpoint_t receive_from; /*===========================================================================* * main * @@ -56,146 +73,389 @@ PUBLIC int main(void) * three major activities: getting new work, processing the work, and sending * the reply. This loop never terminates as long as the file system runs. */ - int error; + int transid, req; + struct job *job; /* SEF local startup. */ sef_local_startup(); + printf("Started VFS: %d worker thread(s)\n", NR_WTHREADS); + /* This is the main loop that gets work, processes it, and sends replies. */ while (TRUE) { - SANITYCHECK; - get_work(); /* sets who and call_nr */ + yield_all(); /* let other threads run */ + send_work(); + get_work(); - if (call_nr == DEV_OPEN_REPL) /* XXX: hack to make DEV_OPEN_REPL */ - call_nr = DEV_REVIVE; /* work on synchronous VFS */ + transid = TRNS_GET_ID(m_in.m_type); + req = TRNS_DEL_ID(m_in.m_type); + job = worker_getjob( (thread_t) transid - VFS_TRANSID); - if (call_nr == DEV_REVIVE) - { - endpoint_t endpt; + /* Transaction encoding changes original m_type value; restore. */ + if (job == NULL) + m_in.m_type = transid; + else + m_in.m_type = req; - endpt = m_in.REP_ENDPT; - if(endpt == VFS_PROC_NR) { - endpt = suspended_ep(m_in.m_source, m_in.REP_IO_GRANT); - if(endpt == NONE) { - printf("FS: proc with " - "grant %d from %d not found (revive)\n", - m_in.REP_IO_GRANT, m_in.m_source); - continue; - } - } - revive(endpt, m_in.REP_STATUS); + if (job != NULL) { + do_fs_reply(job); continue; - } - if (call_nr == DEV_REOPEN_REPL) - { - reopen_reply(); + } else if (who_e == PM_PROC_NR) { /* Calls from PM */ + /* Special control messages from PM */ + sys_worker_start(do_pm); continue; - } - if (call_nr == DEV_CLOSE_REPL) - { - close_reply(); + } else if (is_notify(call_nr)) { + /* A task notify()ed us */ + sys_worker_start(do_control_msgs); continue; + } else if (who_p < 0) { /* i.e., message comes from a task */ + /* We're going to ignore this message. Tasks should + * send notify()s only. + */ + printf("VFS: ignoring message from %d (%d)\n", who_e, call_nr); + continue; } - if (call_nr == DEV_SEL_REPL1) - { - select_reply1(m_in.m_source, m_in.DEV_MINOR, m_in.DEV_SEL_OPS); + + /* At this point we either have results from an asynchronous device + * or a new system call. In both cases a new worker thread has to be + * started and there might not be one available from the pool. This is + * not a problem (requests/replies are simply queued), except when + * they're from an FS endpoint, because these can cause a deadlock. + * handle_work() takes care of the details. */ + if (IS_DEV_RS(call_nr)) { + /* We've got results for a device request */ + handle_work(do_async_dev_result); continue; + } else { + /* Normal syscall. */ + handle_work(do_work); } - if (call_nr == DEV_SEL_REPL2) - { - select_reply2(m_in.m_source, m_in.DEV_MINOR, m_in.DEV_SEL_OPS); - continue; - } - - /* Check for special control messages first. */ - if (is_notify(call_nr)) { - if (who_e == CLOCK) - { - /* Alarm timer expired. Used only for select(). - * Check it. - */ - expire_timers(m_in.NOTIFY_TIMESTAMP); - } - else if(who_e == DS_PROC_NR) - { - /* DS notifies us of an event. */ - ds_event(); - } - else - { - /* Device notifies us of an event. */ - dev_status(&m_in); - } - SANITYCHECK; - continue; - } - - /* We only expect notify()s from tasks. */ - if(who_p < 0) { - printf("FS: ignoring message from %d (%d)\n", - who_e, m_in.m_type); - continue; - } - - /* Now it's safe to set and check fp. */ - fp = &fproc[who_p]; /* pointer to proc table struct */ - super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); /* su? */ - -#if DO_SANITYCHECKS - if(fp_is_blocked(fp)) { - printf("VFS: requester %d call %d: suspended\n", - who_e, call_nr); - panic("requester suspended"); - } -#endif - - /* Calls from PM. */ - if (who_e == PM_PROC_NR) { - service_pm(); - - continue; - } - - SANITYCHECK; - - /* Other calls. */ - switch(call_nr) - { - case MAPDRIVER: - error= do_mapdriver(); - if (error != SUSPEND) reply(who_e, error); - break; - case COMMON_GETSYSINFO: - error= do_getsysinfo(); - if (error != SUSPEND) reply(who_e, error); - break; - default: - /* Call the internal function that does the work. */ - if (call_nr < 0 || call_nr >= NCALLS) { - error = ENOSYS; - /* Not supposed to happen. */ - } else if (fp->fp_pid == PID_FREE) { - error = ENOSYS; - printf( - "FS, bad process, who = %d, call_nr = %d, endpt1 = %d\n", - who_e, call_nr, m_in.endpt1); - } else { -#if ENABLE_SYSCALL_STATS - calls_stats[call_nr]++; -#endif - SANITYCHECK; - error = (*call_vec[call_nr])(); - SANITYCHECK; - } - - /* Copy the results back to the user and send reply. */ - if (error != SUSPEND) { reply(who_e, error); } - } - SANITYCHECK; } return(OK); /* shouldn't come here */ } +/*===========================================================================* + * handle_work * + *===========================================================================*/ +PRIVATE void handle_work(void *(*func)(void *arg)) +{ +/* Handle asynchronous device replies and new system calls. If the originating + * endpoint is an FS endpoint, take extra care not to get in deadlock. */ + struct vmnt *vmp = NULL; + + if ((vmp = find_vmnt(who_e)) != NULL) { + /* A call back or dev result from an FS endpoint */ + + /* Set call back flag. We assume that an FS does only one call back + * at a time */ + vmp->m_flags |= VMNT_CALLBACK; + + /* When an FS point has to make a call back in order to mount, force + * its device to a "none device" so block reads/writes will be handled + * by ROOT_FS_E. + */ + if (vmp->m_flags & VMNT_MOUNTING) + vmp->m_flags |= VMNT_FORCEROOTBSF; + + if (worker_available() == 0) { + /* No worker threads available to handle call */ + if (deadlock_resolving) { + /* Already trying to resolve a deadlock, can't + * handle more, sorry */ + vmp->m_flags &= ~VMNT_CALLBACK; + reply(who_e, EAGAIN); + return; + } + deadlock_resolving = 1; + dl_worker_start(func); + return; + } + } + + worker_start(func); +} + +/*===========================================================================* + * do_async_dev_result * + *===========================================================================*/ +PRIVATE void *do_async_dev_result(void *arg) +{ + endpoint_t endpt; + struct job my_job; + + my_job = *((struct job *) arg); + fp = my_job.j_fp; + m_in = my_job.j_m_in; + + /* An asynchronous character driver has results for us */ + if (call_nr == DEV_REVIVE) { + endpt = m_in.REP_ENDPT; + if (endpt == VFS_PROC_NR) + endpt = find_suspended_ep(m_in.m_source, m_in.REP_IO_GRANT); + + if (endpt == NONE) { + printf("VFS: proc with grant %d from %d not found\n", + m_in.REP_IO_GRANT, m_in.m_source); + } else if (m_in.REP_STATUS == SUSPEND) { + printf("VFS: got SUSPEND on DEV_REVIVE: not reviving proc\n"); + } else + revive(endpt, m_in.REP_STATUS); + } + else if (call_nr == DEV_OPEN_REPL) open_reply(); + else if (call_nr == DEV_REOPEN_REPL) reopen_reply(); + else if (call_nr == DEV_CLOSE_REPL) close_reply(); + else if (call_nr == DEV_SEL_REPL1) + select_reply1(m_in.m_source, m_in.DEV_MINOR, m_in.DEV_SEL_OPS); + else if (call_nr == DEV_SEL_REPL2) + select_reply2(m_in.m_source, m_in.DEV_MINOR, m_in.DEV_SEL_OPS); + + if (deadlock_resolving) { + if (fp != NULL && fp->fp_wtid == dl_worker.w_tid) + deadlock_resolving = 0; + } + + if (fp != NULL && (fp->fp_flags & FP_SYS_PROC)) { + struct vmnt *vmp; + + if ((vmp = find_vmnt(fp->fp_endpoint)) != NULL) + vmp->m_flags &= ~VMNT_CALLBACK; + } + + thread_cleanup(NULL); + return(NULL); +} + +/*===========================================================================* + * do_control_msgs * + *===========================================================================*/ +PRIVATE void *do_control_msgs(void *arg) +{ + struct job my_job; + + my_job = *((struct job *) arg); + fp = my_job.j_fp; + m_in = my_job.j_m_in; + + /* Check for special control messages. */ + if (who_e == CLOCK) { + /* Alarm timer expired. Used only for select(). Check it. */ + expire_timers(m_in.NOTIFY_TIMESTAMP); + } else if (who_e == DS_PROC_NR) { + /* DS notifies us of an event. */ + ds_event(); + } else { + /* Device notifies us of an event. */ + dev_status(&m_in); + } + + thread_cleanup(NULL); + return(NULL); +} + +/*===========================================================================* + * do_fs_reply * + *===========================================================================*/ +PRIVATE void *do_fs_reply(struct job *job) +{ + struct vmnt *vmp; + struct fproc *rfp; + + if ((vmp = find_vmnt(who_e)) == NULL) + panic("Couldn't find vmnt for endpoint %d", who_e); + + rfp = job->j_fp; + + if (rfp == NULL || rfp->fp_endpoint == NONE) { + printf("VFS: spurious reply from %d\n", who_e); + return(NULL); + } + + if (rfp->fp_task != who_e) + printf("VFS: expected %d to reply, not %d\n", rfp->fp_task, who_e); + *rfp->fp_sendrec = m_in; + rfp->fp_task = NONE; + vmp->m_comm.c_cur_reqs--; /* We've got our reply, make room for others */ + worker_signal(worker_get(rfp->fp_wtid));/* Continue this worker thread */ + return(NULL); +} + +/*===========================================================================* + * lock_pm * + *===========================================================================*/ +PRIVATE void lock_pm(void) +{ + message org_m_in; + struct fproc *org_fp; + struct worker_thread *org_self; + + /* First try to get it right off the bat */ + if (mutex_trylock(&pm_lock) == 0) + return; + + org_m_in = m_in; + org_fp = fp; + org_self = self; + + if (mutex_lock(&pm_lock) != 0) + panic("Could not obtain lock on pm\n"); + + m_in = org_m_in; + fp = org_fp; + self = org_self; +} + +/*===========================================================================* + * unlock_pm * + *===========================================================================*/ +PRIVATE void unlock_pm(void) +{ + if (mutex_unlock(&pm_lock) != 0) + panic("Could not release lock on pm"); +} + +/*===========================================================================* + * do_pm * + *===========================================================================*/ +PRIVATE void *do_pm(void *arg) +{ + struct job my_job; + struct fproc *rfp; + + my_job = *((struct job *) arg); + rfp = fp = my_job.j_fp; + m_in = my_job.j_m_in; + + lock_pm(); + service_pm(); + unlock_pm(); + + thread_cleanup(NULL); + return(NULL); +} + +/*===========================================================================* + * do_pending_pipe * + *===========================================================================*/ +PRIVATE void *do_pending_pipe(void *arg) +{ + int r, op; + struct job my_job; + struct filp *f; + tll_access_t locktype; + + my_job = *((struct job *) arg); + fp = my_job.j_fp; + m_in = my_job.j_m_in; + + lock_proc(fp, 1 /* force lock */); + + f = scratch(fp).file.filp; + assert(f != NULL); + scratch(fp).file.filp = NULL; + + locktype = (call_nr == READ) ? VNODE_READ : VNODE_WRITE; + op = (call_nr == READ) ? READING : WRITING; + lock_filp(f, locktype); + + r = rw_pipe(op, who_e, f, scratch(fp).io.io_buffer, scratch(fp).io.io_nbytes); + + if (r != SUSPEND) /* Do we have results to report? */ + reply(who_e, r); + + unlock_filp(f); + + thread_cleanup(fp); + return(NULL); +} + +/*===========================================================================* + * do_dummy * + *===========================================================================*/ +PUBLIC void *do_dummy(void *arg) +{ + struct job my_job; + int r; + + my_job = *((struct job *) arg); + fp = my_job.j_fp; + m_in = my_job.j_m_in; + + if ((r = mutex_trylock(&fp->fp_lock)) == 0) { + thread_cleanup(fp); + } else { + /* Proc is busy, let that worker thread carry out the work */ + thread_cleanup(NULL); + } + return(NULL); +} + +/*===========================================================================* + * do_work * + *===========================================================================*/ +PRIVATE void *do_work(void *arg) +{ + int error; + struct job my_job; + + my_job = *((struct job *) arg); + fp = my_job.j_fp; + m_in = my_job.j_m_in; + + lock_proc(fp, 0); /* This proc is busy */ + + if (call_nr == MAPDRIVER) { + error = do_mapdriver(); + } else if (call_nr == COMMON_GETSYSINFO) { + error = do_getsysinfo(); + } else if (IS_PFS_VFS_RQ(call_nr)) { + if (who_e != PFS_PROC_NR) { + printf("VFS: only PFS is allowed to make nested VFS calls\n"); + error = ENOSYS; + } else if (call_nr <= PFS_BASE || call_nr >= PFS_BASE + PFS_NREQS) { + error = ENOSYS; + } else { + call_nr -= PFS_BASE; + error = (*pfs_call_vec[call_nr])(); + } + } else { + /* We're dealing with a POSIX system call from a normal + * process. Call the internal function that does the work. + */ + if (call_nr < 0 || call_nr >= NCALLS) { + error = ENOSYS; + } else if (fp->fp_pid == PID_FREE) { + /* Process vanished before we were able to handle request. + * Replying has no use. Just drop it. */ + error = SUSPEND; + } else { +#if ENABLE_SYSCALL_STATS + calls_stats[call_nr]++; +#endif + error = (*call_vec[call_nr])(); + } + } + + /* Copy the results back to the user and send reply. */ + if (error != SUSPEND) { + + if ((fp->fp_flags & FP_SYS_PROC)) { + struct vmnt *vmp; + + if ((vmp = find_vmnt(fp->fp_endpoint)) != NULL) + vmp->m_flags &= ~VMNT_CALLBACK; + } + + if (deadlock_resolving) { + if (fp->fp_wtid == dl_worker.w_tid) + deadlock_resolving = 0; + } + reply(who_e, error); + } + + thread_cleanup(fp); + return(NULL); +} + /*===========================================================================* * sef_local_startup * *===========================================================================*/ @@ -214,198 +474,296 @@ PRIVATE void sef_local_startup() /*===========================================================================* * sef_cb_init_fresh * *===========================================================================*/ -PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) +PRIVATE int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info) { /* Initialize the virtual file server. */ int s, i; - register struct fproc *rfp; - struct vmnt *vmp; - struct vnode *root_vp; + struct fproc *rfp; message mess; struct rprocpub rprocpub[NR_BOOT_PROCS]; - /* Clear endpoint field */ - mount_m_in.m1_p3 = (char *) NONE; + force_sync = 0; + receive_from = ANY; - /* Initialize the process table with help of the process manager messages. - * Expect one message for each system process with its slot number and pid. - * When no more processes follow, the magic process number NONE is sent. + /* Initialize proc endpoints to NONE */ + for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { + rfp->fp_endpoint = NONE; + rfp->fp_pid = PID_FREE; + } + + /* Initialize the process table with help of the process manager messages. + * Expect one message for each system process with its slot number and pid. + * When no more processes follow, the magic process number NONE is sent. * Then, stop and synchronize with the PM. */ do { - if (OK != (s=sef_receive(PM_PROC_NR, &mess))) - panic("FS couldn't receive from PM: %d", s); + if ((s = sef_receive(PM_PROC_NR, &mess)) != OK) + panic("VFS: couldn't receive from PM: %d", s); if (mess.m_type != PM_INIT) panic("unexpected message from PM: %d", mess.m_type); - if (NONE == mess.PM_PROC) break; + if (NONE == mess.PM_PROC) break; rfp = &fproc[mess.PM_SLOT]; + rfp->fp_flags = FP_NOFLAGS; rfp->fp_pid = mess.PM_PID; rfp->fp_endpoint = mess.PM_PROC; + rfp->fp_grant = GRANT_INVALID; + rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; rfp->fp_realuid = (uid_t) SYS_UID; rfp->fp_effuid = (uid_t) SYS_UID; rfp->fp_realgid = (gid_t) SYS_GID; rfp->fp_effgid = (gid_t) SYS_GID; rfp->fp_umask = ~0; - rfp->fp_grant = GRANT_INVALID; - rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; - rfp->fp_revived = NOT_REVIVING; - } while (TRUE); /* continue until process NONE */ mess.m_type = OK; /* tell PM that we succeeded */ s = send(PM_PROC_NR, &mess); /* send synchronization message */ /* All process table entries have been set. Continue with initialization. */ - - /* The following initializations are needed to let dev_opcl succeed .*/ - fp = (struct fproc *) NULL; - who_e = who_p = VFS_PROC_NR; - - /* Initialize device table. */ - build_dmap(); + fp = &fproc[_ENDPOINT_P(VFS_PROC_NR)];/* During init all communication with + * FSes is on behalf of myself */ + init_dmap(); /* Initialize device table. */ + system_hz = sys_hz(); /* Map all the services in the boot image. */ - if((s = sys_safecopyfrom(RS_PROC_NR, info->rproctab_gid, 0, - (vir_bytes) rprocpub, sizeof(rprocpub), S)) != OK) { + if ((s = sys_safecopyfrom(RS_PROC_NR, info->rproctab_gid, 0, + (vir_bytes) rprocpub, sizeof(rprocpub), S)) != OK){ panic("sys_safecopyfrom failed: %d", s); } - for(i=0;i < NR_BOOT_PROCS;i++) { - if(rprocpub[i].in_use) { - if((s = map_service(&rprocpub[i])) != OK) { - panic("unable to map service: %d", s); + for (i = 0; i < NR_BOOT_PROCS; i++) { + if (rprocpub[i].in_use) { + if ((s = map_service(&rprocpub[i])) != OK) { + panic("VFS: unable to map service: %d", s); } } } - init_root(); /* init root device and load super block */ - init_select(); /* init select() structures */ - - - vmp = &vmnt[0]; /* Should be the root filesystem */ - if (vmp->m_dev == NO_DEV) - panic("vfs: no root filesystem"); - root_vp= vmp->m_root_node; - - /* The root device can now be accessed; set process directories. */ - for (rfp=&fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - FD_ZERO(&(rfp->fp_filp_inuse)); - if (rfp->fp_pid != PID_FREE) { - - dup_vnode(root_vp); - rfp->fp_rd = root_vp; - dup_vnode(root_vp); - rfp->fp_wd = root_vp; - - } else rfp->fp_endpoint = NONE; - } - - system_hz = sys_hz(); - /* Subscribe to block and character driver events. */ s = ds_subscribe("drv\\.[bc]..\\..*", DSF_INITIAL | DSF_OVERWRITE); - if(s != OK) { - panic("vfs: can't subscribe to driver events"); - } - - SANITYCHECK; + if (s != OK) panic("VFS: can't subscribe to driver events (%d)", s); #if DO_SANITYCHECKS FIXME("VFS: DO_SANITYCHECKS is on"); #endif + /* Initialize worker threads */ + for (i = 0; i < NR_WTHREADS; i++) { + worker_init(&workers[i]); + } + worker_init(&sys_worker); /* exclusive system worker thread */ + worker_init(&dl_worker); /* exclusive worker thread to resolve deadlocks */ + + /* Initialize global locks */ + if (mthread_mutex_init(&pm_lock, NULL) != 0) + panic("VFS: couldn't initialize pm lock mutex"); + if (mthread_mutex_init(&exec_lock, NULL) != 0) + panic("VFS: couldn't initialize exec lock"); + if (mthread_mutex_init(&bsf_lock, NULL) != 0) + panic("VFS: couldn't initialize block special file lock"); + + /* Initialize event resources for boot procs and locks for all procs */ + for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { + if (mutex_init(&rfp->fp_lock, NULL) != 0) + panic("unable to initialize fproc lock"); +#if LOCK_DEBUG + rfp->fp_vp_rdlocks = 0; + rfp->fp_vmnt_rdlocks = 0; +#endif + } + + init_vnodes(); /* init vnodes */ + init_vmnts(); /* init vmnt structures */ + init_select(); /* init select() structures */ + init_filps(); /* Init filp structures */ + mount_pfs(); /* mount Pipe File Server */ + worker_start(do_init_root); /* mount initial ramdisk as file system root */ + yield(); /* force do_init_root to start */ + return(OK); } +/*===========================================================================* + * do_init_root * + *===========================================================================*/ +PRIVATE void *do_init_root(void *arg) +{ + struct fproc *rfp; + struct job my_job; + int r; + char *mount_label = "fs_imgrd"; /* FIXME: obtain this from RS */ + + my_job = *((struct job *) arg); + fp = my_job.j_fp; + + lock_proc(fp, 1 /* force lock */); /* This proc is busy */ + lock_pm(); + + /* Initialize process directories. mount_fs will set them to the correct + * values */ + for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { + FD_ZERO(&(rfp->fp_filp_inuse)); + rfp->fp_rd = NULL; + rfp->fp_wd = NULL; + } + + receive_from = MFS_PROC_NR; + if ((r = mount_fs(DEV_IMGRD, "/", MFS_PROC_NR, 0, mount_label)) != OK) + panic("Failed to initialize root"); + receive_from = ANY; + + unlock_pm(); + thread_cleanup(fp); + return(NULL); +} + +/*===========================================================================* + * lock_proc * + *===========================================================================*/ +PUBLIC void lock_proc(struct fproc *rfp, int force_lock) +{ + int r; + message org_m_in; + struct fproc *org_fp; + struct worker_thread *org_self; + + r = mutex_trylock(&rfp->fp_lock); + + /* Were we supposed to obtain this lock immediately? */ + if (force_lock) { + assert(r == 0); + return; + } + + if (r == 0) return; + + org_m_in = m_in; + org_fp = fp; + org_self = self; + if ((r = mutex_lock(&rfp->fp_lock)) != 0) + panic("unable to lock fproc lock: %d", r); + m_in = org_m_in; + fp = org_fp; + self = org_self; +} + +/*===========================================================================* + * unlock_proc * + *===========================================================================*/ +PUBLIC void unlock_proc(struct fproc *rfp) +{ + int r; + + if ((r = mutex_unlock(&rfp->fp_lock)) != 0) + panic("Failed to unlock: %d", r); +} + +/*===========================================================================* + * thread_cleanup * + *===========================================================================*/ +PRIVATE void thread_cleanup_f(struct fproc *rfp, char *f, int l) +{ +/* Clean up worker thread. Skip parts if this thread is not associated + * with a particular process (i.e., rfp is NULL) */ + + assert(mthread_self() != -1); + +#if LOCK_DEBUG + if (rfp != NULL) { + check_filp_locks_by_me(); + check_vnode_locks_by_me(rfp); + check_vmnt_locks_by_me(rfp); + } +#endif + + if (rfp != NULL && rfp->fp_flags & FP_PM_PENDING) { /* Postponed PM call */ + m_in = rfp->fp_job.j_m_in; + rfp->fp_flags &= ~FP_PM_PENDING; + service_pm_postponed(); + } + +#if LOCK_DEBUG + if (rfp != NULL) { + check_filp_locks_by_me(); + check_vnode_locks_by_me(rfp); + check_vmnt_locks_by_me(rfp); + } +#endif + + if (rfp != NULL) { + rfp->fp_flags &= ~FP_DROP_WORK; + unlock_proc(rfp); + } + +#if 0 + mthread_exit(NULL); +#endif +} + /*===========================================================================* * get_work * *===========================================================================*/ PRIVATE void get_work() -{ +{ /* Normally wait for new input. However, if 'reviving' is * nonzero, a suspended process must be awakened. */ - int r, found_one, fd_nr; - struct filp *f; + int r, found_one, proc_p; register struct fproc *rp; while (reviving != 0) { - found_one= FALSE; + found_one = FALSE; - /* Revive a suspended process. */ - for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) - if (rp->fp_pid != PID_FREE && rp->fp_revived == REVIVING) { - int blocked_on = rp->fp_blocked_on; - found_one= TRUE; - who_p = (int)(rp - fproc); - who_e = rp->fp_endpoint; - call_nr = rp->fp_block_callnr; - - m_in.fd = rp->fp_block_fd; - m_in.buffer = rp->fp_buffer; - m_in.nbytes = rp->fp_nbytes; - /*no longer hanging*/ - rp->fp_blocked_on = FP_BLOCKED_ON_NONE; - rp->fp_revived = NOT_REVIVING; - reviving--; - /* This should be a pipe I/O, not a device I/O. - * If it is, it'll 'leak' grants. - */ - assert(!GRANT_VALID(rp->fp_grant)); - - if (blocked_on == FP_BLOCKED_ON_PIPE) - { - fp= rp; - fd_nr= rp->fp_block_fd; - f= get_filp(fd_nr); - assert(f != NULL); - r= rw_pipe((call_nr == READ) ? READING : - WRITING, who_e, fd_nr, f, - rp->fp_buffer, rp->fp_nbytes); - if (r != SUSPEND) - reply(who_e, r); - continue; - } - - return; + /* Find a suspended process. */ + for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) + if (rp->fp_pid != PID_FREE && (rp->fp_flags & FP_REVIVED)) { + found_one = TRUE; /* Found a suspended process */ + if (unblock(rp)) + return; /* So main loop can process job */ + send_work(); } - if (!found_one) - panic("get_work couldn't revive anyone"); + + if (!found_one) /* Consistency error */ + panic("VFS: get_work couldn't revive anyone"); } for(;;) { - int r; - /* Normal case. No one to revive. */ - if ((r=sef_receive(ANY, &m_in)) != OK) - panic("fs sef_receive error: %d", r); - who_e = m_in.m_source; - who_p = _ENDPOINT_P(who_e); - - /* - * negative who_p is never used to access the fproc array. Negative numbers - * (kernel tasks) are treated in a special way - */ - if(who_p >= (int)(sizeof(fproc) / sizeof(struct fproc))) - panic("receive process out of range: %d", who_p); - if(who_p >= 0 && fproc[who_p].fp_endpoint == NONE) { - printf("FS: ignoring request from %d, endpointless slot %d (%d)\n", - m_in.m_source, who_p, m_in.m_type); - continue; - } - if(who_p >= 0 && fproc[who_p].fp_endpoint != who_e) { - if(fproc[who_p].fp_endpoint == NONE) { - printf("slot unknown even\n"); + /* Normal case. No one to revive. Get a useful request. */ + if ((r = sef_receive(receive_from, &m_in)) != OK) { + panic("VFS: sef_receive error: %d", r); } - printf("FS: receive endpoint inconsistent (source %d, who_p %d, stored ep %d, who_e %d).\n", - m_in.m_source, who_p, fproc[who_p].fp_endpoint, who_e); -#if 0 - panic("FS: inconsistent endpoint "); -#endif - continue; - } - call_nr = m_in.m_type; - return; + + proc_p = _ENDPOINT_P(m_in.m_source); + if (proc_p < 0) fp = NULL; + else fp = &fproc[proc_p]; + + if (m_in.m_type == EDEADSRCDST) return; /* Failed 'sendrec' */ + + /* Negative who_p is never used to access the fproc array. Negative + * numbers (kernel tasks) are treated in a special way. + */ + if (who_p >= (int)(sizeof(fproc) / sizeof(struct fproc))) + panic("receive process out of range: %d", who_p); + if (who_p >= 0 && fproc[who_p].fp_endpoint == NONE) { + printf("VFS: ignoring request from %d, endpointless slot %d (%d)\n", + m_in.m_source, who_p, m_in.m_type); + continue; + } + + /* Internal consistency check; our mental image of process numbers and + * endpoints must match with how the rest of the system thinks of them. + */ + if (who_p >= 0 && fproc[who_p].fp_endpoint != who_e) { + if (fproc[who_p].fp_endpoint == NONE) + printf("slot unknown even\n"); + + printf("VFS: receive endpoint inconsistent (source %d, who_p " + "%d, stored ep %d, who_e %d).\n", m_in.m_source, who_p, + fproc[who_p].fp_endpoint, who_e); + panic("VFS: inconsistent endpoint "); + } + + return; } } @@ -418,123 +776,25 @@ int whom; /* process to reply to */ int result; /* result of the call (usually OK or error #) */ { /* Send a reply to a user process. If the send fails, just ignore it. */ - int s; - -#if 0 - if (call_nr == SYMLINK) - printf("vfs:reply: replying %d for call %d\n", result, call_nr); -#endif + int r; m_out.reply_type = result; - s = sendnb(whom, &m_out); - if (s != OK) printf("VFS: couldn't send reply %d to %d: %d\n", - result, whom, s); -} - -/*===========================================================================* - * init_root * - *===========================================================================*/ -PRIVATE void init_root() -{ - int r = OK; - struct vmnt *vmp; - struct vnode *root_node; - struct dmap *dp; - char *label; - struct node_details res; - - /* Open the root device. */ - root_dev = DEV_IMGRD; - ROOT_FS_E = MFS_PROC_NR; - - /* Initialize vmnt table */ - for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) - vmp->m_dev = NO_DEV; - - vmp = &vmnt[0]; - - /* We'll need a vnode for the root inode, check whether there is one */ - if ((root_node = get_free_vnode()) == NULL) - panic("Cannot get free vnode: %d", r); - - - /* Get driver process' endpoint */ - dp = &dmap[(root_dev >> MAJOR) & BYTE]; - if (dp->dmap_driver == NONE) { - panic("No driver for root device: %d", r); - } - - label= dp->dmap_label; - if (strlen(label) == 0) - { - panic("vfs:init_root: no label for major: %d", root_dev >> MAJOR); - } - - /* Issue request */ - r = req_readsuper(ROOT_FS_E, label, root_dev, 0 /*!readonly*/, - 1 /*isroot*/, &res); + r = sendnb(whom, &m_out); if (r != OK) { - panic("Cannot read superblock from root: %d", r); + printf("VFS: couldn't send reply %d to %d: %d\n", result, whom, r); } - - /* Fill in root node's fields */ - root_node->v_fs_e = res.fs_e; - root_node->v_inode_nr = res.inode_nr; - root_node->v_mode = res.fmode; - root_node->v_size = res.fsize; - root_node->v_sdev = NO_DEV; - root_node->v_fs_count = 1; - root_node->v_ref_count = 1; - - /* Fill in max file size and blocksize for the vmnt */ - vmp->m_fs_e = res.fs_e; - vmp->m_dev = root_dev; - vmp->m_flags = 0; - - /* Root node is indeed on the partition */ - root_node->v_vmnt = vmp; - root_node->v_dev = vmp->m_dev; - - /* Root directory is not mounted on a vnode. */ - vmp->m_mounted_on = NULL; - vmp->m_root_node = root_node; - strcpy(vmp->m_label, "fs_imgrd"); /* FIXME: obtain this from RS */ } /*===========================================================================* - * service_pm * + * service_pm_postponed * *===========================================================================*/ -PRIVATE void service_pm() +PRIVATE void service_pm_postponed(void) { int r; vir_bytes pc; - switch (call_nr) { - case PM_SETUID: - pm_setuid(m_in.PM_PROC, m_in.PM_EID, m_in.PM_RID); - - m_out.m_type = PM_SETUID_REPLY; - m_out.PM_PROC = m_in.PM_PROC; - - break; - - case PM_SETGID: - pm_setgid(m_in.PM_PROC, m_in.PM_EID, m_in.PM_RID); - - m_out.m_type = PM_SETGID_REPLY; - m_out.PM_PROC = m_in.PM_PROC; - - break; - - case PM_SETSID: - pm_setsid(m_in.PM_PROC); - - m_out.m_type = PM_SETSID_REPLY; - m_out.PM_PROC = m_in.PM_PROC; - - break; - - case PM_EXEC: + switch(call_nr) { + case PM_EXEC: r = pm_exec(m_in.PM_PROC, m_in.PM_PATH, m_in.PM_PATH_LEN, m_in.PM_FRAME, m_in.PM_FRAME_LEN, &pc); @@ -546,7 +806,7 @@ PRIVATE void service_pm() break; - case PM_EXIT: + case PM_EXIT: pm_exit(m_in.PM_PROC); /* Reply dummy status to PM for synchronization */ @@ -555,19 +815,95 @@ PRIVATE void service_pm() break; - case PM_DUMPCORE: - r = pm_dumpcore(m_in.PM_PROC, m_in.PM_TERM_SIG, m_in.PM_PATH); + case PM_DUMPCORE: + /* Copy parameters first. m_in gets overwritten when creating core + * file. + */ + + r = pm_dumpcore(m_in.PM_PROC, m_in.PM_TERM_SIG, + (vir_bytes) m_in.PM_PATH); /* Reply status to PM */ m_out.m_type = PM_CORE_REPLY; m_out.PM_PROC = m_in.PM_PROC; m_out.PM_TRACED_PROC = m_in.PM_TRACED_PROC; m_out.PM_STATUS = r; - + break; - case PM_FORK: - case PM_SRV_FORK: + default: + panic("Unhandled postponed PM call %d", m_in.m_type); + } + + r = send(PM_PROC_NR, &m_out); + if (r != OK) + panic("service_pm_postponed: send failed: %d", r); +} + +/*===========================================================================* + * service_pm * + *===========================================================================*/ +PRIVATE void service_pm() +{ + int r, slot; + + switch (call_nr) { + case PM_SETUID: + pm_setuid(m_in.PM_PROC, m_in.PM_EID, m_in.PM_RID); + + m_out.m_type = PM_SETUID_REPLY; + m_out.PM_PROC = m_in.PM_PROC; + + break; + + case PM_SETGID: + pm_setgid(m_in.PM_PROC, m_in.PM_EID, m_in.PM_RID); + + m_out.m_type = PM_SETGID_REPLY; + m_out.PM_PROC = m_in.PM_PROC; + + break; + + case PM_SETSID: + pm_setsid(m_in.PM_PROC); + + m_out.m_type = PM_SETSID_REPLY; + m_out.PM_PROC = m_in.PM_PROC; + + break; + + case PM_EXEC: + case PM_EXIT: + case PM_DUMPCORE: + okendpt(m_in.PM_PROC, &slot); + fp = &fproc[slot]; + + if (fp->fp_flags & FP_PENDING) { + /* This process has a request pending, but PM wants it gone. + * Forget about the pending request and satisfy PM's request + * instead. Note that a pending request AND an EXEC request + * are mutually exclusive. Also, PM should send only one + * request/process at a time. + */ + assert(fp->fp_job.j_m_in.m_source != PM_PROC_NR); + } + + /* PM requests on behalf of a proc are handled after the system call + * that might be in progress for that proc has finished. If the proc + * is not busy, we start a dummy call */ + if (!(fp->fp_flags & FP_PENDING) && mutex_trylock(&fp->fp_lock) == 0) { + mutex_unlock(&fp->fp_lock); + worker_start(do_dummy); + fp->fp_flags |= FP_DROP_WORK; + } + + fp->fp_job.j_m_in = m_in; + fp->fp_flags |= FP_PM_PENDING; + + return; + + case PM_FORK: + case PM_SRV_FORK: pm_fork(m_in.PM_PPROC, m_in.PM_PROC, m_in.PM_CPID); m_out.m_type = PM_FORK_REPLY; @@ -580,15 +916,16 @@ PRIVATE void service_pm() m_out.PM_PROC = m_in.PM_PROC; break; - case PM_SETGROUPS: - pm_setgroups(m_in.PM_PROC, m_in.PM_GROUP_NO, (gid_t *) m_in.PM_GROUP_ADDR); + case PM_SETGROUPS: + pm_setgroups(m_in.PM_PROC, m_in.PM_GROUP_NO, + (gid_t *) m_in.PM_GROUP_ADDR); m_out.m_type = PM_SETGROUPS_REPLY; m_out.PM_PROC = m_in.PM_PROC; break; - case PM_UNPAUSE: + case PM_UNPAUSE: unpause(m_in.PM_PROC); m_out.m_type = PM_UNPAUSE_REPLY; @@ -596,7 +933,7 @@ PRIVATE void service_pm() break; - case PM_REBOOT: + case PM_REBOOT: pm_reboot(); /* Reply dummy status to PM for synchronization */ @@ -604,8 +941,8 @@ PRIVATE void service_pm() break; - default: - printf("VFS: don't know how to handle PM request %x\n", call_nr); + default: + printf("VFS: don't know how to handle PM request %d\n", call_nr); return; } @@ -616,3 +953,38 @@ PRIVATE void service_pm() } + +/*===========================================================================* + * unblock * + *===========================================================================*/ +PRIVATE int unblock(rfp) +struct fproc *rfp; +{ + int blocked_on; + + fp = rfp; + blocked_on = rfp->fp_blocked_on; + m_in.m_type = rfp->fp_block_callnr; + m_in.fd = scratch(fp).file.fd_nr; + m_in.buffer = scratch(fp).io.io_buffer; + m_in.nbytes = scratch(fp).io.io_nbytes; + + rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; /* no longer blocked */ + rfp->fp_flags &= ~FP_REVIVED; + reviving--; + assert(reviving >= 0); + + /* This should be a pipe I/O, not a device I/O. If it is, it'll 'leak' + * grants. + */ + assert(!GRANT_VALID(rfp->fp_grant)); + + /* Pending pipe reads/writes can be handled directly */ + if (blocked_on == FP_BLOCKED_ON_PIPE) { + worker_start(do_pending_pipe); + yield(); /* Give thread a chance to run */ + return(0); /* Retrieve more work */ + } + + return(1); /* We've unblocked a process */ +} diff --git a/servers/vfs/misc.c b/servers/vfs/misc.c index 569b32202..5497bf76e 100644 --- a/servers/vfs/misc.c +++ b/servers/vfs/misc.c @@ -7,7 +7,7 @@ * do_fcntl: perform the FCNTL system call * do_sync: perform the SYNC system call * do_fsync: perform the FSYNC system call - * do_reboot: sync disks and prepare for shutdown + * pm_reboot: sync disks and prepare for shutdown * pm_fork: adjust the tables after PM has performed a FORK system call * do_exec: handle files with FD_CLOEXEC on after PM has done an EXEC * do_exit: a process has exited; note that in the tables @@ -33,10 +33,12 @@ #include #include "file.h" #include "fproc.h" -#include "param.h" +#include "scratchpad.h" +#include "dmap.h" #include #include "vnode.h" #include "vmnt.h" +#include "param.h" #define CORE_NAME "core" #define CORE_MODE 0777 /* mode to use on core image files */ @@ -46,7 +48,6 @@ PUBLIC unsigned long calls_stats[NCALLS]; #endif FORWARD _PROTOTYPE( void free_proc, (struct fproc *freed, int flags) ); -FORWARD _PROTOTYPE( void unmount_all, (void) ); /* FORWARD _PROTOTYPE( int dumpcore, (int proc_e, struct mem_map *seg_ptr) ); FORWARD _PROTOTYPE( int write_bytes, (struct inode *rip, off_t off, @@ -55,9 +56,6 @@ FORWARD _PROTOTYPE( int write_seg, (struct inode *rip, off_t off, int proc_e, int seg, off_t seg_off, phys_bytes seg_bytes) ); */ -#define FP_EXITING 1 - - /*===========================================================================* * do_getsysinfo * *===========================================================================*/ @@ -74,22 +72,22 @@ PUBLIC int do_getsysinfo() if (!super_user) return(EPERM); switch(m_in.SI_WHAT) { - case SI_PROC_TAB: - src_addr = (vir_bytes) fproc; - len = sizeof(struct fproc) * NR_PROCS; - break; - case SI_DMAP_TAB: - src_addr = (vir_bytes) dmap; - len = sizeof(struct dmap) * NR_DEVICES; - break; + case SI_PROC_TAB: + src_addr = (vir_bytes) fproc; + len = sizeof(struct fproc) * NR_PROCS; + break; + case SI_DMAP_TAB: + src_addr = (vir_bytes) dmap; + len = sizeof(struct dmap) * NR_DEVICES; + break; #if ENABLE_SYSCALL_STATS - case SI_CALL_STATS: - src_addr = (vir_bytes) calls_stats; - len = sizeof(calls_stats); - break; + case SI_CALL_STATS: + src_addr = (vir_bytes) calls_stats; + len = sizeof(calls_stats); + break; #endif - default: - return(EINVAL); + default: + return(EINVAL); } if (len != m_in.SI_SIZE) @@ -112,32 +110,42 @@ PUBLIC int do_dup() register int rfd; register struct filp *f; - struct filp *dummy; - int r; + int r = OK; /* Is the file descriptor valid? */ rfd = m_in.fd & ~DUP_MASK; /* kill off dup2 bit, if on */ - if ((f = get_filp(rfd)) == NULL) return(err_code); + if ((f = get_filp(rfd, VNODE_READ)) == NULL) return(err_code); /* Distinguish between dup and dup2. */ if (m_in.fd == rfd) { /* bit not on */ /* dup(fd) */ - if ((r = get_fd(0, 0, &m_in.fd2, &dummy)) != OK) return(r); + r = get_fd(0, 0, &m_in.fd2, NULL); } else { - /* dup2(fd, fd2) */ - if (m_in.fd2 < 0 || m_in.fd2 >= OPEN_MAX) return(EBADF); - if (rfd == m_in.fd2) return(m_in.fd2); /* ignore the call: dup2(x, x) */ - m_in.fd = m_in.fd2; /* prepare to close fd2 */ - (void) do_close(); /* cannot fail */ + /* dup2(old_fd, new_fd) */ + if (m_in.fd2 < 0 || m_in.fd2 >= OPEN_MAX) { + r = EBADF; + } else if (rfd == m_in.fd2) { /* ignore the call: dup2(x, x) */ + r = m_in.fd2; + } else { + /* All is fine, close new_fd if necessary */ + m_in.fd = m_in.fd2; /* prepare to close fd2 */ + unlock_filp(f); /* or it might deadlock on do_close */ + (void) do_close(); /* cannot fail */ + f = get_filp(rfd, VNODE_READ); /* lock old_fd again */ + } } - /* Success. Set up new file descriptors. */ - f->filp_count++; - fp->fp_filp[m_in.fd2] = f; - FD_SET(m_in.fd2, &fp->fp_filp_inuse); - return(m_in.fd2); -} + if (r == OK) { + /* Success. Set up new file descriptors. */ + f->filp_count++; + fp->fp_filp[m_in.fd2] = f; + FD_SET(m_in.fd2, &fp->fp_filp_inuse); + r = m_in.fd2; + } + unlock_filp(f); + return(r); +} /*===========================================================================* * do_fcntl * @@ -147,113 +155,131 @@ PUBLIC int do_fcntl() /* Perform the fcntl(fd, request, ...) system call. */ register struct filp *f; - int new_fd, r, fl; - struct filp *dummy; + int new_fd, fl, r = OK; + tll_access_t locktype; + + scratch(fp).file.fd_nr = m_in.fd; + scratch(fp).io.io_buffer = m_in.buffer; + scratch(fp).io.io_nbytes = m_in.nbytes; /* a.k.a. m_in.request */ /* Is the file descriptor valid? */ - if ((f = get_filp(m_in.fd)) == NULL) return(err_code); - + locktype = (m_in.request == F_FREESP) ? VNODE_WRITE : VNODE_READ; + if ((f = get_filp(scratch(fp).file.fd_nr, locktype)) == NULL) + return(err_code); + switch (m_in.request) { - case F_DUPFD: + case F_DUPFD: /* This replaces the old dup() system call. */ - if (m_in.addr < 0 || m_in.addr >= OPEN_MAX) return(EINVAL); - if ((r = get_fd(m_in.addr, 0, &new_fd, &dummy)) != OK) return(r); - f->filp_count++; - fp->fp_filp[new_fd] = f; - return(new_fd); + if (m_in.addr < 0 || m_in.addr >= OPEN_MAX) r = EINVAL; + else if ((r = get_fd(m_in.addr, 0, &new_fd, NULL)) == OK) { + f->filp_count++; + fp->fp_filp[new_fd] = f; + FD_SET(new_fd, &fp->fp_filp_inuse); + r = new_fd; + } + break; - case F_GETFD: + case F_GETFD: /* Get close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */ - return( FD_ISSET(m_in.fd, &fp->fp_cloexec_set) ? FD_CLOEXEC : 0); + r = 0; + if (FD_ISSET(scratch(fp).file.fd_nr, &fp->fp_cloexec_set)) + r = FD_CLOEXEC; + break; - case F_SETFD: + case F_SETFD: /* Set close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */ if(m_in.addr & FD_CLOEXEC) - FD_SET(m_in.fd, &fp->fp_cloexec_set); + FD_SET(scratch(fp).file.fd_nr, &fp->fp_cloexec_set); else - FD_CLR(m_in.fd, &fp->fp_cloexec_set); - return(OK); + FD_CLR(scratch(fp).file.fd_nr, &fp->fp_cloexec_set); + break; - case F_GETFL: + case F_GETFL: /* Get file status flags (O_NONBLOCK and O_APPEND). */ fl = f->filp_flags & (O_NONBLOCK | O_APPEND | O_ACCMODE); - return(fl); + r = fl; + break; - case F_SETFL: + case F_SETFL: /* Set file status flags (O_NONBLOCK and O_APPEND). */ fl = O_NONBLOCK | O_APPEND | O_REOPEN; f->filp_flags = (f->filp_flags & ~fl) | (m_in.addr & fl); - return(OK); + break; - case F_GETLK: - case F_SETLK: - case F_SETLKW: + case F_GETLK: + case F_SETLK: + case F_SETLKW: /* Set or clear a file lock. */ r = lock_op(f, m_in.request); - return(r); + break; - case F_FREESP: + case F_FREESP: { - /* Free a section of a file. Preparation is done here, actual freeing - * in freesp_inode(). - */ + /* Free a section of a file */ off_t start, end; struct flock flock_arg; signed long offset; /* Check if it's a regular file. */ - if((f->filp_vno->v_mode & I_TYPE) != I_REGULAR) return(EINVAL); - if (!(f->filp_mode & W_BIT)) return(EBADF); + if ((f->filp_vno->v_mode & I_TYPE) != I_REGULAR) r = EINVAL; + else if (!(f->filp_mode & W_BIT)) r = EBADF; + else + /* Copy flock data from userspace. */ + r = sys_datacopy(who_e, (vir_bytes) m_in.name1, SELF, + (vir_bytes) &flock_arg, + (phys_bytes) sizeof(flock_arg)); - /* Copy flock data from userspace. */ - if((r = sys_datacopy(who_e, (vir_bytes) m_in.name1, SELF, - (vir_bytes) &flock_arg, (phys_bytes) sizeof(flock_arg))) != OK) - return(r); + if (r != OK) break; /* Convert starting offset to signed. */ offset = (signed long) flock_arg.l_start; /* Figure out starting position base. */ switch(flock_arg.l_whence) { - case SEEK_SET: start = 0; break; - case SEEK_CUR: - if (ex64hi(f->filp_pos) != 0) + case SEEK_SET: start = 0; break; + case SEEK_CUR: + if (ex64hi(f->filp_pos) != 0) panic("do_fcntl: position in file too high"); - start = ex64lo(f->filp_pos); - break; - case SEEK_END: start = f->filp_vno->v_size; break; - default: return EINVAL; + start = ex64lo(f->filp_pos); + break; + case SEEK_END: start = f->filp_vno->v_size; break; + default: r = EINVAL; } + if (r != OK) break; /* Check for overflow or underflow. */ - if(offset > 0 && start + offset < start) return EINVAL; - if(offset < 0 && start + offset > start) return EINVAL; - start += offset; - if(start < 0) return EINVAL; + if (offset > 0 && start + offset < start) r = EINVAL; + else if (offset < 0 && start + offset > start) r = EINVAL; + else { + start += offset; + if (start < 0) r = EINVAL; + } + if (r != OK) break; - if(flock_arg.l_len != 0) { - if(start >= f->filp_vno->v_size) return EINVAL; - end = start + flock_arg.l_len; - if(end <= start) return EINVAL; - if(end > f->filp_vno->v_size) end = f->filp_vno->v_size; + if (flock_arg.l_len != 0) { + if (start >= f->filp_vno->v_size) r = EINVAL; + else if ((end = start + flock_arg.l_len) <= start) r = EINVAL; + else if (end > f->filp_vno->v_size) end = f->filp_vno->v_size; } else { end = 0; } + if (r != OK) break; - r = req_ftrunc(f->filp_vno->v_fs_e, f->filp_vno->v_inode_nr, start, - end); + r = req_ftrunc(f->filp_vno->v_fs_e, f->filp_vno->v_inode_nr,start,end); - if(r == OK && flock_arg.l_len == 0) + if (r == OK && flock_arg.l_len == 0) f->filp_vno->v_size = start; - return(r); + break; } - default: - return(EINVAL); + default: + r = EINVAL; } -} + unlock_filp(f); + return(r); +} /*===========================================================================* * do_sync * @@ -261,11 +287,19 @@ PUBLIC int do_fcntl() PUBLIC int do_sync() { struct vmnt *vmp; - for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) - if (vmp->m_dev != NO_DEV) - req_sync(vmp->m_fs_e); + int r = OK; - return(OK); + for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) { + if (vmp->m_dev != NO_DEV && vmp->m_fs_e != NONE && + vmp->m_root_node != NULL) { + if ((r = lock_vmnt(vmp, VMNT_EXCL)) != OK) + break; + req_sync(vmp->m_fs_e); + unlock_vmnt(vmp); + } + } + + return(r); } /*===========================================================================* @@ -273,31 +307,28 @@ PUBLIC int do_sync() *===========================================================================*/ PUBLIC int do_fsync() { -/* Perform the fsync() system call. For now, don't be unnecessarily smart. */ +/* Perform the fsync() system call. */ + struct filp *rfilp; + struct vmnt *vmp; + dev_t dev; + int r = OK; - do_sync(); - return(OK); -} + if ((rfilp = get_filp(m_in.m1_i1, VNODE_READ)) == NULL) return(err_code); + dev = rfilp->filp_vno->v_dev; + for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) { + if (vmp->m_dev != NO_DEV && vmp->m_dev == dev && + vmp->m_fs_e != NONE && vmp->m_root_node != NULL) { -/*===========================================================================* - * unmount_all * - *===========================================================================*/ -PRIVATE void unmount_all(void) -{ -/* Unmount all filesystems. File systems are mounted on other file systems, - * so you have to pull off the loose bits repeatedly to get it all undone. - */ - - int i; - for (i= 0; i < NR_MNTS; i++) { - struct vmnt *vmp; - - /* Unmount at least one. */ - for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) { - if (vmp->m_dev != NO_DEV) - unmount(vmp->m_dev, NULL); + if ((r = lock_vmnt(vmp, VMNT_EXCL)) != OK) + break; + req_sync(vmp->m_fs_e); + unlock_vmnt(vmp); } } + + unlock_filp(rfilp); + + return(r); } /*===========================================================================* @@ -305,32 +336,29 @@ PRIVATE void unmount_all(void) *===========================================================================*/ PUBLIC void pm_reboot() { - /* Perform the FS side of the reboot call. */ + /* Perform the VFS side of the reboot call. */ int i; + struct fproc *rfp; do_sync(); - SANITYCHECK; - /* Do exit processing for all leftover processes and servers, * but don't actually exit them (if they were really gone, PM * will tell us about it). */ - for (i = 0; i < NR_PROCS; i++) - if((m_in.endpt1 = fproc[i].fp_endpoint) != NONE) { - /* No FP_EXITING, just free the resources, otherwise - * consistency check for fp_endpoint (set to NONE) will - * fail if process wants to do something in the (short) - * future. - */ - free_proc(&fproc[i], 0); - } - SANITYCHECK; + for (i = 0; i < NR_PROCS; i++) { + rfp = &fproc[i]; + if (rfp->fp_endpoint == NONE) continue; + /* Don't just free the proc right away, but let it finish what it was + * doing first */ + lock_proc(rfp, 0); + free_proc(rfp, 0); + unlock_proc(rfp); + } + + do_sync(); unmount_all(); - - SANITYCHECK; - } /*===========================================================================* @@ -347,8 +375,9 @@ int cpid; /* Child process id */ * system uses the same slot numbers as the kernel. Only PM makes this call. */ - register struct fproc *cp; + register struct fproc *cp, *pp; int i, parentno, childno; + mutex_t c_fp_lock; /* Check up-to-dateness of fproc. */ okendpt(pproc, &parentno); @@ -358,17 +387,20 @@ int cpid; /* Child process id */ * number is correct in fproc, which it won't be. */ childno = _ENDPOINT_P(cproc); - if(childno < 0 || childno >= NR_PROCS) - panic("FS: bogus child for forking: %d", m_in.child_endpt); - if(fproc[childno].fp_pid != PID_FREE) - panic("FS: forking on top of in-use child: %d", childno); + if (childno < 0 || childno >= NR_PROCS) + panic("VFS: bogus child for forking: %d", m_in.child_endpt); + if (fproc[childno].fp_pid != PID_FREE) + panic("VFS: forking on top of in-use child: %d", childno); /* Copy the parent's fproc struct to the child. */ + /* However, the mutex variables belong to a slot and must stay the same. */ + c_fp_lock = fproc[childno].fp_lock; fproc[childno] = fproc[parentno]; + fproc[childno].fp_lock = c_fp_lock; /* Increase the counters in the 'filp' table. */ cp = &fproc[childno]; - fp = &fproc[parentno]; + pp = &fproc[parentno]; for (i = 0; i < OPEN_MAX; i++) if (cp->fp_filp[i] != NULL) cp->fp_filp[i]->filp_count++; @@ -377,27 +409,23 @@ int cpid; /* Child process id */ cp->fp_pid = cpid; cp->fp_endpoint = cproc; - /* A forking process never has an outstanding grant, - * as it isn't blocking on i/o. - */ - if(GRANT_VALID(fp->fp_grant)) { - printf("vfs: fork: fp (endpoint %d) has grant %d\n", fp->fp_endpoint, fp->fp_grant); - panic("fp contains valid grant"); + /* A forking process never has an outstanding grant, as it isn't blocking on + * I/O. */ + if(GRANT_VALID(pp->fp_grant)) { + panic("VFS: fork: pp (endpoint %d) has grant %d\n", pp->fp_endpoint, + pp->fp_grant); } if(GRANT_VALID(cp->fp_grant)) { - printf("vfs: fork: cp (endpoint %d) has grant %d\n", cp->fp_endpoint, cp->fp_grant); - panic("cp contains valid grant"); + panic("VFS: fork: cp (endpoint %d) has grant %d\n", cp->fp_endpoint, + cp->fp_grant); } - /* A child is not a process leader. */ - cp->fp_sesldr = 0; - - /* This child has not exec()ced yet. */ - cp->fp_execced = 0; + /* A child is not a process leader, not being revived, etc. */ + cp->fp_flags = FP_NOFLAGS; /* Record the fact that both root and working dir have another user. */ - if(cp->fp_rd) dup_vnode(cp->fp_rd); - if(cp->fp_wd) dup_vnode(cp->fp_wd); + if (cp->fp_rd) dup_vnode(cp->fp_rd); + if (cp->fp_wd) dup_vnode(cp->fp_wd); } /*===========================================================================* @@ -411,56 +439,46 @@ PRIVATE void free_proc(struct fproc *exiter, int flags) register struct vnode *vp; dev_t dev; - SANITYCHECK; - - fp = exiter; /* get_filp() needs 'fp' */ - - if(fp->fp_endpoint == NONE) { + if (exiter->fp_endpoint == NONE) panic("free_proc: already free"); - } - if (fp_is_blocked(fp)) { - SANITYCHECK; - unpause(fp->fp_endpoint); - SANITYCHECK; - } - - SANITYCHECK; + if (fp_is_blocked(exiter)) + unpause(exiter->fp_endpoint); /* Loop on file descriptors, closing any that are open. */ for (i = 0; i < OPEN_MAX; i++) { - (void) close_fd(fp, i); + (void) close_fd(exiter, i); } - + + /* Release root and working directories. */ + if (exiter->fp_rd) { put_vnode(exiter->fp_rd); exiter->fp_rd = NULL; } + if (exiter->fp_wd) { put_vnode(exiter->fp_wd); exiter->fp_wd = NULL; } + + /* The rest of these actions is only done when processes actually exit. */ + if (!(flags & FP_EXITING)) return; + + exiter->fp_flags |= FP_EXITING; + /* Check if any process is SUSPENDed on this driver. * If a driver exits, unmap its entries in the dmap table. * (unmapping has to be done after the first step, because the * dmap table is used in the first step.) */ - unsuspend_by_endpt(fp->fp_endpoint); + unsuspend_by_endpt(exiter->fp_endpoint); + dmap_unmap_by_endpt(exiter->fp_endpoint); - /* Release root and working directories. */ - if(fp->fp_rd) { put_vnode(fp->fp_rd); fp->fp_rd = NULL; } - if(fp->fp_wd) { put_vnode(fp->fp_wd); fp->fp_wd = NULL; } - - /* The rest of these actions is only done when processes actually - * exit. - */ - if(!(flags & FP_EXITING)) { - SANITYCHECK; - return; - } + worker_stop_by_endpt(exiter->fp_endpoint); /* Unblock waiting threads */ + vmnt_unmap_by_endpt(exiter->fp_endpoint); /* Invalidate open files if this + * was an active FS */ /* Invalidate endpoint number for error and sanity checks. */ - fp->fp_endpoint = NONE; + exiter->fp_endpoint = NONE; - /* If a session leader exits and it has a controlling tty, then revoke + /* If a session leader exits and it has a controlling tty, then revoke * access to its controlling tty from all other processes using it. */ - if (fp->fp_sesldr && fp->fp_tty != 0) { - - dev = fp->fp_tty; - + if ((exiter->fp_flags & FP_SESLDR) && exiter->fp_tty != 0) { + dev = exiter->fp_tty; for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { if(rfp->fp_pid == PID_FREE) continue; if (rfp->fp_tty == dev) rfp->fp_tty = 0; @@ -471,19 +489,21 @@ PRIVATE void free_proc(struct fproc *exiter, int flags) vp = rfilp->filp_vno; if ((vp->v_mode & I_TYPE) != I_CHAR_SPECIAL) continue; if ((dev_t) vp->v_sdev != dev) continue; - - (void) dev_close(dev, rfilp-filp); - /* Ignore any errors, even SUSPEND. */ + lock_filp(rfilp, VNODE_READ); + (void) dev_close(dev, rfilp-filp); /* Ignore any errors, even + * SUSPEND. */ rfilp->filp_mode = FILP_CLOSED; + unlock_filp(rfilp); } } } /* Exit done. Mark slot as free. */ - fp->fp_pid = PID_FREE; - - SANITYCHECK; + exiter->fp_pid = PID_FREE; + if (exiter->fp_flags & FP_PENDING) + pending--; /* No longer pending job, not going to do it */ + exiter->fp_flags = FP_NOFLAGS; } /*===========================================================================* @@ -492,12 +512,13 @@ PRIVATE void free_proc(struct fproc *exiter, int flags) PUBLIC void pm_exit(proc) int proc; { - int exitee_p; /* Perform the file system portion of the exit(status) system call. */ + int exitee_p; /* Nevertheless, pretend that the call came from the user. */ okendpt(proc, &exitee_p); - free_proc(&fproc[exitee_p], FP_EXITING); + fp = &fproc[exitee_p]; + free_proc(fp, FP_EXITING); } /*===========================================================================* @@ -533,12 +554,12 @@ gid_t *groups; okendpt(proc_e, &slot); rfp = &fproc[slot]; if (ngroups * sizeof(gid_t) > sizeof(rfp->fp_sgroups)) - panic("VFS: pm_setgroups: too much data to copy"); - if(sys_datacopy(who_e, (vir_bytes) groups, SELF, (vir_bytes) rfp->fp_sgroups, - ngroups * sizeof(gid_t)) == OK) { + panic("VFS: pm_setgroups: too much data to copy"); + if (sys_datacopy(who_e, (vir_bytes) groups, SELF, (vir_bytes) rfp->fp_sgroups, + ngroups * sizeof(gid_t)) == OK) { rfp->fp_ngroups = ngroups; } else - panic("VFS: pm_setgroups: datacopy failed"); + panic("VFS: pm_setgroups: datacopy failed"); } @@ -550,7 +571,7 @@ int proc_e; int euid; int ruid; { - register struct fproc *tfp; + struct fproc *tfp; int slot; okendpt(proc_e, &slot); @@ -567,7 +588,7 @@ PUBLIC int do_svrctl() { switch (m_in.svrctl_req) { /* No control request implemented yet. */ - default: + default: return(EINVAL); } } @@ -575,44 +596,34 @@ PUBLIC int do_svrctl() /*===========================================================================* * pm_dumpcore * *===========================================================================*/ -PUBLIC int pm_dumpcore(proc_e, csig, exe_name) -int proc_e; -int csig; -char *exe_name; +PUBLIC int pm_dumpcore(endpoint_t proc_e, int csig, vir_bytes exe_name) { - int proc_s, r, old_who_e; - int traced_proc_e = m_in.PM_TRACED_PROC; + int slot, r, core_fd; + struct filp *f; + char core_path[PATH_MAX]; + char proc_name[PROC_NAME_LEN]; - okendpt(traced_proc_e, &proc_s); - fp = &fproc[proc_s]; + okendpt(proc_e, &slot); + fp = &fproc[slot]; - /* Open the core file */ - sprintf(user_fullpath, "%s.%d", CORE_NAME, fproc[proc_s].fp_pid); - r = common_open(O_WRONLY | O_CREAT | O_TRUNC, CORE_MODE); - if (r < 0) { - printf("VFS: Cannot open file to dump core\n"); - return r; - } + /* open core file */ + snprintf(core_path, PATH_MAX, "%s.%d", CORE_NAME, fp->fp_pid); + core_fd = common_open(core_path, O_WRONLY | O_CREAT | O_TRUNC, CORE_MODE); + if (core_fd < 0) return(core_fd); - old_who_e = who_e; - who_e = VFS_PROC_NR; + /* get process' name */ + r = sys_datacopy(PM_PROC_NR, exe_name, VFS_PROC_NR, (vir_bytes) proc_name, + PROC_NAME_LEN); + if (r != OK) return(r); + proc_name[PROC_NAME_LEN - 1] = '\0'; - /* Write the core file in ELF format */ - write_elf_core_file(csig, exe_name); + if ((f = get_filp(core_fd, VNODE_WRITE)) == NULL) return(EBADF); + write_elf_core_file(f, csig, proc_name); + unlock_filp(f); + (void) close_fd(fp, core_fd); /* ignore failure, we're exiting anyway */ - /* Close file */ - close_fd(fp, r); - - /* Terminate the process */ - if (traced_proc_e == proc_e) - free_proc(&fproc[proc_s], FP_EXITING); - - /* Restore the important variables that have been overwritten */ - m_in.PM_PROC = proc_e; - m_in.PM_TRACED_PROC = traced_proc_e; - who_e = old_who_e; - - return OK; + free_proc(fp, FP_EXITING); + return(OK); } /*===========================================================================* @@ -620,39 +631,33 @@ char *exe_name; *===========================================================================*/ PUBLIC void ds_event(void) { - char key[DS_MAX_KEYLEN]; - char *blkdrv_prefix = "drv.blk."; - char *chrdrv_prefix = "drv.chr."; - u32_t value; - int type; - endpoint_t owner_endpoint; - int r, is_blk; - - /* Get the event and the owner from DS. */ - r = ds_check(key, &type, &owner_endpoint); - if(r != OK) { - if(r != ENOENT) - printf("vfs: ds_event: ds_check failed: %d\n", r); - return; - } + char key[DS_MAX_KEYLEN]; + char *blkdrv_prefix = "drv.blk."; + char *chrdrv_prefix = "drv.chr."; + u32_t value; + int type, r, is_blk; + endpoint_t owner_endpoint; + /* Get the event and the owner from DS. */ + while ((r = ds_check(key, &type, &owner_endpoint)) == OK) { /* Only check for block and character driver up events. */ if (!strncmp(key, blkdrv_prefix, strlen(blkdrv_prefix))) { is_blk = TRUE; } else if (!strncmp(key, chrdrv_prefix, strlen(chrdrv_prefix))) { is_blk = FALSE; } else { - return; /* neither block nor character driver */ + continue; } - r = ds_retrieve_u32(key, &value); - if(r != OK) { - printf("vfs: ds_event: ds_retrieve_u32 failed\n"); + if ((r = ds_retrieve_u32(key, &value)) != OK) { + printf("VFS: ds_event: ds_retrieve_u32 failed\n"); return; } - if (value != DS_DRIVER_UP) return; + if (value != DS_DRIVER_UP) continue; /* Perform up. */ dmap_endpt_up(owner_endpoint, is_blk); -} + } + if (r != ENOENT) printf("VFS: ds_event: ds_check failed: %d\n", r); +} diff --git a/servers/vfs/mount.c b/servers/vfs/mount.c index 118568ef9..4e4666d5a 100644 --- a/servers/vfs/mount.c +++ b/servers/vfs/mount.c @@ -1,7 +1,7 @@ /* This file performs the MOUNT and UMOUNT system calls. * * The entry points into this file are - * do_fslogin: perform the FSLOGIN system call + * do_fsready: perform the FS_READY system call * do_mount: perform the MOUNT system call * do_umount: perform the UMOUNT system call * unmount: unmount a file system @@ -22,15 +22,18 @@ #include #include #include +#include #include "file.h" #include "fproc.h" -#include "param.h" +#include "dmap.h" #include #include "vnode.h" #include "vmnt.h" +#include "path.h" +#include "param.h" /* Allow the root to be replaced before the first 'real' mount. */ -PRIVATE int allow_newroot = 1; +PRIVATE int have_root = 0; /* Bitmap of in-use "none" pseudo devices. */ PRIVATE bitchunk_t nonedev[BITMAP_CHUNKS(NR_NONEDEVS)] = { 0 }; @@ -38,49 +41,75 @@ PRIVATE bitchunk_t nonedev[BITMAP_CHUNKS(NR_NONEDEVS)] = { 0 }; #define alloc_nonedev(dev) SET_BIT(nonedev, minor(dev) - 1) #define free_nonedev(dev) UNSET_BIT(nonedev, minor(dev) - 1) -FORWARD _PROTOTYPE( dev_t name_to_dev, (int allow_mountpt) ); -FORWARD _PROTOTYPE( int mount_fs, (endpoint_t fs_e) ); -FORWARD _PROTOTYPE( int is_nonedev, (dev_t dev) ); +FORWARD _PROTOTYPE( dev_t name_to_dev, (int allow_mountpt, + char path[PATH_MAX]) ); FORWARD _PROTOTYPE( dev_t find_free_nonedev, (void) ); +FORWARD _PROTOTYPE( void update_bspec, (dev_t dev, endpoint_t fs_e, + int send_drv_e) ); /*===========================================================================* * update_bspec * *===========================================================================*/ -PRIVATE void update_bspec(dev_t dev, endpoint_t fs_e) +PRIVATE void update_bspec(dev_t dev, endpoint_t fs_e, int send_drv_e) { /* Update all block special files for a certain device, to use a new FS endpt * to route raw block I/O requests through. */ struct vnode *vp; + struct dmap *dp; + int r, major; for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; ++vp) - if (vp->v_ref_count > 0 && S_ISBLK(vp->v_mode) && vp->v_sdev == dev) + if (vp->v_ref_count > 0 && S_ISBLK(vp->v_mode) && vp->v_sdev == dev) { vp->v_bfs_e = fs_e; + if (send_drv_e) { + major = major(dev); + if (major < 0 || major >= NR_DEVICES) { + /* Can't update for out-of-range major */ + continue; + } + dp = &dmap[major(dev)]; + if (dp->dmap_driver == NONE) { + /* Can't update for vanished driver */ + printf("VFS: can't send new driver label\n"); + continue; + } + + if ((r = req_newdriver(fs_e, vp->v_sdev, + dp->dmap_label)) != OK) { + printf("VFS: Failed to send new driver label" + " for moved block special file to %d\n", + fs_e); + } + } + } } - /*===========================================================================* - * do_fslogin * + * do_fsready * *===========================================================================*/ -PUBLIC int do_fslogin() +PUBLIC int do_fsready() { /* deprecated */ return(SUSPEND); } - /*===========================================================================* * do_mount * *===========================================================================*/ PUBLIC int do_mount() { +/* Perform the mount(name, mfile, mount_flags) system call. */ endpoint_t fs_e; - int r, proc_nr; + int r, slot, rdonly, nodev; + char fullpath[PATH_MAX]; + char mount_label[LABEL_MAX]; + dev_t dev; /* Only the super-user may do MOUNT. */ if (!super_user) return(EPERM); - - /* FS process' endpoint number */ + + /* FS process' endpoint number */ if (m_in.mount_flags & MS_LABEL16) { /* Get the label from the caller, and ask DS for the endpoint. */ r = sys_datacopy(who_e, (vir_bytes) m_in.fs_label, SELF, @@ -91,8 +120,6 @@ PUBLIC int do_mount() r = ds_retrieve_label_endpt(mount_label, &fs_e); if (r != OK) return(r); - - if (isokendpt(fs_e, &proc_nr) != OK) return(EINVAL); } else { /* Legacy support: get the endpoint from the request itself. */ fs_e = (endpoint_t) m_in.fs_label; @@ -100,47 +127,18 @@ PUBLIC int do_mount() } /* Sanity check on process number. */ - if(fs_e <= 0) { - printf("VFS: warning: got process number %d for mount call.\n", fs_e); - return EINVAL; - } + if (isokendpt(fs_e, &slot) != OK) return(EINVAL); - /* Do the actual job */ - return mount_fs(fs_e); -} - - -/*===========================================================================* - * mount * - *===========================================================================*/ -PRIVATE int mount_fs(endpoint_t fs_e) -{ -/* Perform the mount(name, mfile, mount_flags) system call. */ - int rdir, mdir; /* TRUE iff {root|mount} file is dir */ - int i, r, found, rdonly, nodev, isroot, replace_root; - struct fproc *tfp; - struct dmap *dp; - dev_t dev; - struct vnode *root_node, *vp = NULL, *bspec; - struct vmnt *vmp; - char *label; - struct node_details res; - - /* Only the super-user may do MOUNT. */ - if (!super_user) return(EPERM); - - /* Clear endpoint field */ /* Should the file system be mounted read-only? */ rdonly = (m_in.mount_flags & MS_RDONLY); /* A null string for block special device means don't use a device at all. */ nodev = (m_in.name1_length == 0); - if (!nodev) { /* If 'name' is not for a block special file, return error. */ - if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) + if (fetch_name(m_in.name1, m_in.name1_length, M1, fullpath) != OK) return(err_code); - if ((dev = name_to_dev(FALSE /*allow_mountpt*/)) == NO_DEV) + if ((dev = name_to_dev(FALSE /*allow_mountpt*/, fullpath)) == NO_DEV) return(err_code); } else { /* Find a free pseudo-device as substitute for an actual device. */ @@ -148,124 +146,146 @@ PRIVATE int mount_fs(endpoint_t fs_e) return(err_code); } - /* Check whether there is a block special file open which uses the - * same device (partition) */ - for (bspec = &vnode[0]; bspec < &vnode[NR_VNODES]; ++bspec) { - if (bspec->v_ref_count > 0 && bspec->v_sdev == dev) { - /* Found, flush and invalidate any blocks for this device. */ - req_flush(bspec->v_fs_e, dev); - break; - } - } - - /* Scan vmnt table to see if dev already mounted. If not, find a free slot.*/ - found = FALSE; - vmp = NULL; - for (i = 0; i < NR_MNTS; ++i) { - if (vmnt[i].m_dev == dev) { - vmp = &vmnt[i]; - found = TRUE; - break; - } else if (!vmp && vmnt[i].m_dev == NO_DEV) { - vmp = &vmnt[i]; - } - } - - /* Partition was/is already mounted */ - if (found) { - /* It is possible that we have an old root lying around that - * needs to be remounted. This could for example be a boot - * ramdisk that has already been replaced by the real root. - */ - if(vmp->m_mounted_on || root_dev == vmp->m_dev) { - return(EBUSY); /* not a root or still mounted */ - } - - /* Now get the inode of the file to be mounted on. */ - if (fetch_name(m_in.name2, m_in.name2_length, M1)!=OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); - if (vp->v_ref_count != 1) { - put_vnode(vp); - return(EBUSY); - } - - /* Tell FS on which vnode it is mounted (glue into mount tree) */ - if ((r = req_mountpoint(vp->v_fs_e, vp->v_inode_nr)) == OK) { - root_node = vmp->m_root_node; - - /* File types of 'vp' and 'root_node' may not conflict. */ - mdir = ((vp->v_mode & I_TYPE) == I_DIRECTORY);/* TRUE iff dir*/ - rdir = ((root_node->v_mode & I_TYPE) == I_DIRECTORY); - if(!mdir && rdir) r = EISDIR; - } - - if (r != OK) { - put_vnode(vp); - return(r); - } - - /* Nothing else can go wrong. Perform the mount. */ - vmp->m_mounted_on = vp; - vmp->m_flags = rdonly; - strcpy(vmp->m_label, mount_label); - allow_newroot = 0; /* The root is now fixed */ - if (nodev) alloc_nonedev(dev); /* Make the allocation final */ - update_bspec(dev, fs_e); /* Update open block-special files */ - - return(OK); - } else if (vmp == NULL) { - /* No free slot available, bail out */ - return(ENOMEM); - } - /* Fetch the name of the mountpoint */ - if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) return(err_code); - isroot = (strcmp(user_fullpath, "/") == 0); - replace_root = (isroot && allow_newroot); + if (fetch_name(m_in.name2, m_in.name2_length, M1, fullpath) != OK) + return(err_code); - if(!replace_root) { - /* Get vnode of mountpoint */ - if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); + /* Do the actual job */ + return mount_fs(dev, fullpath, fs_e, rdonly, mount_label); +} - if (vp->v_ref_count != 1) { - put_vnode(vp); - return(EBUSY); - } - /* Tell FS on which vnode it is mounted (glue into mount tree) */ - if ((r = req_mountpoint(vp->v_fs_e, vp->v_inode_nr)) != OK) { - put_vnode(vp); - return r; - } - } - - /* We'll need a vnode for the root inode, check whether there is one */ - if ((root_node = get_free_vnode()) == NULL) { - if (vp != NULL) put_vnode(vp); - return(ENFILE); - } +/*===========================================================================* + * mount_fs * + *===========================================================================*/ +PUBLIC int mount_fs( +dev_t dev, +char mountpoint[PATH_MAX], +endpoint_t fs_e, +int rdonly, +char mount_label[LABEL_MAX] ) +{ + int rdir, mdir; /* TRUE iff {root|mount} file is dir */ + int i, r = OK, found, isroot, mount_root, con_reqs, slot; + struct fproc *tfp, *rfp; + struct dmap *dp; + struct vnode *root_node, *vp = NULL; + struct vmnt *new_vmp, *parent_vmp; + char *label; + struct node_details res; + struct lookup resolve; + /* Look up block device driver label when dev is not a pseudo-device */ label = ""; - if (!nodev) { + if (!is_nonedev(dev)) { /* Get driver process' endpoint */ - dp = &dmap[(dev >> MAJOR) & BYTE]; + dp = &dmap[major(dev)]; if (dp->dmap_driver == NONE) { - printf("VFS: no driver for dev %x\n", dev); - if (vp != NULL) put_vnode(vp); + printf("VFS: no driver for dev %d\n", dev); return(EINVAL); } label = dp->dmap_label; - if (strlen(label) == 0) - panic("VFS mount_fs: no label for major: 0x%x", dev >> MAJOR); + assert(strlen(label) > 0); } + /* Scan vmnt table to see if dev already mounted. If not, find a free slot.*/ + found = FALSE; + for (i = 0; i < NR_MNTS; ++i) { + if (vmnt[i].m_dev == dev) found = TRUE; + } + if (found) { + return(EBUSY); + } else if ((new_vmp = get_free_vmnt()) == NULL) { + return(ENOMEM); + } + + if ((r = lock_vmnt(new_vmp, VMNT_EXCL)) != OK) return(r); + + isroot = (strcmp(mountpoint, "/") == 0); + mount_root = (isroot && have_root < 2); /* Root can be mounted twice: + * 1: ramdisk + * 2: boot disk (e.g., harddisk) + */ + + if (!mount_root) { + /* Get vnode of mountpoint */ + lookup_init(&resolve, mountpoint, PATH_NOFLAGS, &parent_vmp, &vp); + resolve.l_vmnt_lock = VMNT_EXCL; + resolve.l_vnode_lock = VNODE_WRITE; + if ((vp = eat_path(&resolve, fp)) == NULL) + r = err_code; + else if (vp->v_ref_count == 1) { + /*Tell FS on which vnode it is mounted (glue into mount tree)*/ + r = req_mountpoint(vp->v_fs_e, vp->v_inode_nr); + } else + r = EBUSY; + + if (vp != NULL) { + /* Quickly unlock to allow back calls (from e.g. FUSE) to + * relock */ + unlock_vmnt(parent_vmp); + } + + if (r != OK) { + if (vp != NULL) { + unlock_vnode(vp); + put_vnode(vp); + } + unlock_vmnt(new_vmp); + return(r); + } + } + + /* We'll need a vnode for the root inode */ + if ((root_node = get_free_vnode()) == NULL) { + if (vp != NULL) { + unlock_vnode(vp); + put_vnode(vp); + } + unlock_vmnt(new_vmp); + return(err_code); + } + lock_vnode(root_node, VNODE_OPCL); + + /* Record process as a system process */ + if (isokendpt(fs_e, &slot) != OK) { + if (vp != NULL) { + unlock_vnode(vp); + put_vnode(vp); + } + unlock_vnode(root_node); + unlock_vmnt(new_vmp); + return(EINVAL); + } + rfp = &fproc[slot]; + rfp->fp_flags |= FP_SYS_PROC; /* Process is an FS */ + + /* Store some essential vmnt data first */ + new_vmp->m_fs_e = fs_e; + new_vmp->m_dev = dev; + if (rdonly) new_vmp->m_flags |= VMNT_READONLY; + else new_vmp->m_flags &= ~VMNT_READONLY; + /* Tell FS which device to mount */ - if ((r = req_readsuper(fs_e, label, dev, rdonly, isroot, &res)) != OK) { - if (vp != NULL) put_vnode(vp); + new_vmp->m_flags |= VMNT_MOUNTING; + r = req_readsuper(fs_e, label, dev, rdonly, isroot, &res, &con_reqs); + new_vmp->m_flags &= ~VMNT_MOUNTING; + + if (r != OK) { + new_vmp->m_fs_e = NONE; + new_vmp->m_dev = NO_DEV; + unlock_vnode(root_node); + if (vp != NULL) { + unlock_vnode(vp); + put_vnode(vp); + } + unlock_vmnt(new_vmp); return(r); } + lock_bsf(); + /* Fill in root node's fields */ root_node->v_fs_e = res.fs_e; root_node->v_inode_nr = res.inode_nr; @@ -276,46 +296,50 @@ PRIVATE int mount_fs(endpoint_t fs_e) root_node->v_sdev = NO_DEV; root_node->v_fs_count = 1; root_node->v_ref_count = 1; - - /* Fill in max file size and blocksize for the vmnt */ - vmp->m_fs_e = res.fs_e; - vmp->m_dev = dev; - vmp->m_flags = rdonly; - - /* Root node is indeed on the partition */ - root_node->v_vmnt = vmp; - root_node->v_dev = vmp->m_dev; - - if(replace_root) { - /* Superblock and root node already read. - * Nothing else can go wrong. Perform the mount. */ - vmp->m_root_node = root_node; - vmp->m_mounted_on = NULL; - strcpy(vmp->m_label, mount_label); - if (nodev) alloc_nonedev(dev); - update_bspec(dev, fs_e); - root_dev = dev; + /* Root node is indeed on the partition */ + root_node->v_vmnt = new_vmp; + root_node->v_dev = new_vmp->m_dev; + if (con_reqs == 0) + new_vmp->m_comm.c_max_reqs = 1; /* Default if FS doesn't tell us */ + else + new_vmp->m_comm.c_max_reqs = con_reqs; + new_vmp->m_comm.c_cur_reqs = 0; + + if (mount_root) { + /* Superblock and root node already read. + * Nothing else can go wrong. Perform the mount. */ + new_vmp->m_root_node = root_node; + new_vmp->m_mounted_on = NULL; + strcpy(new_vmp->m_label, mount_label); + if (is_nonedev(dev)) alloc_nonedev(dev); + update_bspec(dev, fs_e, 0 /* Don't send new driver endpoint */); + + ROOT_DEV = dev; ROOT_FS_E = fs_e; /* Replace all root and working directories */ - for (i= 0, tfp= fproc; ifp_pid == PID_FREE) continue; -#define MAKEROOT(what) { \ - put_vnode(what); \ - dup_vnode(root_node); \ - what = root_node; \ - } - - if(tfp->fp_rd) MAKEROOT(tfp->fp_rd); - if(tfp->fp_wd) MAKEROOT(tfp->fp_wd); +#define MAKEROOT(what) { \ + if (what) put_vnode(what); \ + dup_vnode(root_node); \ + what = root_node; \ + } + + MAKEROOT(tfp->fp_rd); + MAKEROOT(tfp->fp_wd); } + unlock_vnode(root_node); + unlock_vmnt(new_vmp); + have_root++; /* We have a (new) root */ + unlock_bsf(); return(OK); } - + /* File types may not conflict. */ mdir = ((vp->v_mode & I_TYPE) == I_DIRECTORY); /*TRUE iff dir*/ rdir = ((root_node->v_mode & I_TYPE) == I_DIRECTORY); @@ -323,30 +347,66 @@ PRIVATE int mount_fs(endpoint_t fs_e) /* If error, return the super block and both inodes; release the vmnt. */ if (r != OK) { + unlock_vnode(vp); + unlock_vnode(root_node); + unlock_vmnt(new_vmp); put_vnode(vp); put_vnode(root_node); - vmp->m_dev = NO_DEV; + new_vmp->m_dev = NO_DEV; + new_vmp->m_flags = 0; + unlock_bsf(); return(r); } /* Nothing else can go wrong. Perform the mount. */ - vmp->m_mounted_on = vp; - vmp->m_root_node = root_node; - strcpy(vmp->m_label, mount_label); - - /* The root is now fixed */ - allow_newroot = 0; + new_vmp->m_mounted_on = vp; + new_vmp->m_root_node = root_node; + strcpy(new_vmp->m_label, mount_label); /* Allocate the pseudo device that was found, if not using a real device. */ - if (nodev) alloc_nonedev(dev); + if (is_nonedev(dev)) alloc_nonedev(dev); /* The new FS will handle block I/O requests for its device now. */ - update_bspec(dev, fs_e); + if (!(new_vmp->m_flags & VMNT_FORCEROOTBSF)) + update_bspec(dev, fs_e, 0 /* Don't send new driver endpoint */); + + unlock_vnode(vp); + unlock_vnode(root_node); + unlock_vmnt(new_vmp); + unlock_bsf(); return(OK); } +/*===========================================================================* + * mount_pfs * + *===========================================================================*/ +PUBLIC void mount_pfs(void) +{ +/* Mount the Pipe File Server. It's not really mounted onto the file system, + but it's necessary it has a vmnt entry to make locking easier */ + + dev_t dev; + struct vmnt *vmp; + struct fproc *rfp; + + if ((dev = find_free_nonedev()) == NO_DEV) + panic("VFS: no nonedev to initialize PFS"); + + if ((vmp = get_free_vmnt()) == NULL) + panic("VFS: no vmnt to initialize PFS"); + + alloc_nonedev(dev); + + vmp->m_dev = dev; + vmp->m_fs_e = PFS_PROC_NR; + strcpy(vmp->m_label, "pfs"); + + rfp = &fproc[_ENDPOINT_P(PFS_PROC_NR)]; + rfp->fp_flags |= FP_SYS_PROC; /* PFS is a driver and an FS */ +} + /*===========================================================================* * do_umount * *===========================================================================*/ @@ -356,15 +416,18 @@ PUBLIC int do_umount(void) char label[LABEL_MAX]; dev_t dev; int r; - + char fullpath[PATH_MAX]; + /* Only the super-user may do umount. */ if (!super_user) return(EPERM); - - /* If 'name' is not for a block special file or mountpoint, return error. */ - if(fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); - if((dev = name_to_dev(TRUE /*allow_mountpt*/)) == NO_DEV) return(err_code); - if((r = unmount(dev, label)) != OK) return(r); + /* If 'name' is not for a block special file or mountpoint, return error. */ + if (fetch_name(m_in.name, m_in.name_length, M3, fullpath) != OK) + return(err_code); + if ((dev = name_to_dev(TRUE /*allow_mountpt*/, fullpath)) == NO_DEV) + return(err_code); + + if ((r = unmount(dev, label)) != OK) return(r); /* Return the label of the mounted file system, so that the caller * can shut down the corresponding server process. @@ -386,11 +449,10 @@ PUBLIC int unmount( { struct vnode *vp; struct vmnt *vmp_i = NULL, *vmp = NULL; - struct dmap *dp; - int count, r; - + int count, locks, r; + /* Find vmnt that is to be unmounted */ - for(vmp_i = &vmnt[0]; vmp_i < &vmnt[NR_MNTS]; ++vmp_i) { + for (vmp_i = &vmnt[0]; vmp_i < &vmnt[NR_MNTS]; ++vmp_i) { if (vmp_i->m_dev == dev) { if(vmp) panic("device mounted more than once: %d", dev); vmp = vmp_i; @@ -399,15 +461,23 @@ PUBLIC int unmount( /* Did we find the vmnt (i.e., was dev a mounted device)? */ if(!vmp) return(EINVAL); - + + if ((r = lock_vmnt(vmp, VMNT_EXCL)) != OK) return(r); + /* See if the mounted device is busy. Only 1 vnode using it should be * open -- the root vnode -- and that inode only 1 time. */ - count = 0; - for(vp = &vnode[0]; vp < &vnode[NR_VNODES]; vp++) - if(vp->v_ref_count > 0 && vp->v_dev == dev) count += vp->v_ref_count; + locks = count = 0; + for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; vp++) + if (vp->v_ref_count > 0 && vp->v_dev == dev) { + count += vp->v_ref_count; + if (is_vnode_locked(vp)) locks++; + } + + if (count > 1 || locks > 1 || tll_haspendinglock(&vmp->m_lock)) { + unlock_vmnt(vmp); + return(EBUSY); /* can't umount a busy file system */ + } - if(count > 1) return(EBUSY); /* can't umount a busy file system */ - /* Tell FS to drop all inode references for root inode except 1. */ vnode_clean_refs(vmp->m_root_node); @@ -416,59 +486,69 @@ PUBLIC int unmount( vmp->m_mounted_on = NULL; } + vmp->m_comm.c_max_reqs = 1; /* Force max concurrent reqs to just one, so + * we won't send any messages after the + * unmount request */ + /* Tell FS to unmount */ - if(vmp->m_fs_e <= 0 || vmp->m_fs_e == NONE) - panic("unmount: strange fs endpoint: %d", vmp->m_fs_e); - if ((r = req_unmount(vmp->m_fs_e)) != OK) /* Not recoverable. */ - printf("VFS: ignoring failed umount attempt (%d) fs pid: %d\n", r, - _ENDPOINT_P(vmp->m_fs_e)); + printf("VFS: ignoring failed umount attempt FS endpoint: %d (%d)\n", + vmp->m_fs_e, r); - if (is_nonedev(vmp->m_dev)) - free_nonedev(vmp->m_dev); + if (is_nonedev(vmp->m_dev)) free_nonedev(vmp->m_dev); - if (label != NULL) - strcpy(label, vmp->m_label); - - vmp->m_root_node->v_ref_count = 0; - vmp->m_root_node->v_fs_count = 0; - vmp->m_root_node->v_sdev = NO_DEV; - vmp->m_root_node = NULL; + if (label != NULL) strcpy(label, vmp->m_label); + + if (vmp->m_root_node) { /* PFS lacks a root node */ + vmp->m_root_node->v_ref_count = 0; + vmp->m_root_node->v_fs_count = 0; + vmp->m_root_node->v_sdev = NO_DEV; + vmp->m_root_node = NULL; + } vmp->m_dev = NO_DEV; vmp->m_fs_e = NONE; - - /* Is there a block special file that was handled by that partition? */ - for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; vp++) { - if(vp->v_ref_count > 0 && S_ISBLK(vp->v_mode) && - vp->v_bfs_e == vmp->m_fs_e) { - /* Get the driver endpoint of the block spec device */ - dp = &dmap[(dev >> MAJOR) & BYTE]; - if (dp->dmap_driver == NONE) { - printf("VFS: driver not found for device %d\n", dev); - continue; - } + unlock_vmnt(vmp); + + /* The root FS will handle block I/O requests for this device now. */ + lock_bsf(); + update_bspec(dev, ROOT_FS_E, 1 /* send new driver endpoint */); + unlock_bsf(); - printf("VFS: umount moving block spec %d to root FS\n", dev); - vp->v_bfs_e = ROOT_FS_E; - - /* Send the driver label */ - r = req_newdriver(vp->v_bfs_e, vp->v_sdev, dp->dmap_label); - if (r != OK) - printf("VFS: error sending driver label for" - " moved block spec to %d\n", vp->v_bfs_e); - - } - } - return(OK); } +/*===========================================================================* + * unmount_all * + *===========================================================================*/ +PUBLIC void unmount_all(void) +{ +/* Unmount all filesystems. File systems are mounted on other file systems, + * so you have to pull off the loose bits repeatedly to get it all undone. + */ + + int i; + struct vmnt *vmp; + + /* Now unmount the rest */ + for (i = 0; i < NR_MNTS; i++) { + /* Unmount at least one. */ + for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) { + if (vmp->m_dev != NO_DEV) + unmount(vmp->m_dev, NULL); + } + } + check_vnode_locks(); + check_vmnt_locks(); + check_filp_locks(); + check_bsf_lock(); +} + /*===========================================================================* * name_to_dev * *===========================================================================*/ -PRIVATE dev_t name_to_dev(int allow_mountpt) +PRIVATE dev_t name_to_dev(int allow_mountpt, char path[PATH_MAX]) { /* Convert the block special file in 'user_fullpath' to a device number. * If the given path is not a block special file, but 'allow_mountpt' is set @@ -477,21 +557,27 @@ PRIVATE dev_t name_to_dev(int allow_mountpt) */ dev_t dev; struct vnode *vp; - + struct vmnt *vmp; + struct lookup resolve; + + lookup_init(&resolve, path, PATH_NOFLAGS, &vmp, &vp); + resolve.l_vmnt_lock = VMNT_READ; + resolve.l_vnode_lock = VNODE_READ; + /* Request lookup */ - if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) { - return(NO_DEV); - } + if ((vp = eat_path(&resolve, fp)) == NULL) return(NO_DEV); if ((vp->v_mode & I_TYPE) == I_BLOCK_SPECIAL) { dev = vp->v_sdev; } else if (allow_mountpt && vp->v_vmnt->m_root_node == vp) { dev = vp->v_dev; } else { - err_code = ENOTBLK; + err_code = ENOTBLK; dev = NO_DEV; } + unlock_vnode(vp); + unlock_vmnt(vmp); put_vnode(vp); return(dev); } @@ -500,7 +586,7 @@ PRIVATE dev_t name_to_dev(int allow_mountpt) /*===========================================================================* * is_nonedev * *===========================================================================*/ -PRIVATE int is_nonedev(dev_t dev) +PUBLIC int is_nonedev(dev_t dev) { /* Return whether the given device is a "none" pseudo device. */ diff --git a/servers/vfs/open.c b/servers/vfs/open.c index ae47d048e..a3fd9dc24 100644 --- a/servers/vfs/open.c +++ b/servers/vfs/open.c @@ -8,6 +8,7 @@ * do_mkdir: perform the MKDIR system call * do_close: perform the CLOSE system call * do_lseek: perform the LSEEK system call + * do_llseek: perform the LLSEEK system call */ #include "fs.h" @@ -20,6 +21,8 @@ #include #include "file.h" #include "fproc.h" +#include "scratchpad.h" +#include "dmap.h" #include "lock.h" #include "param.h" #include @@ -27,11 +30,14 @@ #include #include "vnode.h" #include "vmnt.h" +#include "path.h" PUBLIC char mode_map[] = {R_BIT, W_BIT, R_BIT|W_BIT, 0}; -FORWARD _PROTOTYPE( struct vnode *new_node, (int oflags, mode_t bits) ); -FORWARD _PROTOTYPE( int pipe_open, (struct vnode *vp,mode_t bits,int oflags)); +FORWARD _PROTOTYPE( struct vnode *new_node, (struct lookup *resolve, + int oflags, mode_t bits) ); +FORWARD _PROTOTYPE( int pipe_open, (struct vnode *vp, mode_t bits, + int oflags) ); /*===========================================================================* @@ -41,9 +47,11 @@ PUBLIC int do_creat() { /* Perform the creat(name, mode) system call. */ int r; + char fullpath[PATH_MAX]; - if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); - r = common_open(O_WRONLY | O_CREAT | O_TRUNC, (mode_t) m_in.mode); + if (fetch_name(m_in.name, m_in.name_length, M3, fullpath) != OK) + return(err_code); + r = common_open(fullpath, O_WRONLY | O_CREAT | O_TRUNC, (mode_t) m_in.mode); return(r); } @@ -56,17 +64,18 @@ PUBLIC int do_open() /* Perform the open(name, flags,...) system call. */ int create_mode = 0; /* is really mode_t but this gives problems */ int r; + char fullpath[PATH_MAX]; /* If O_CREAT is set, open has three parameters, otherwise two. */ if (m_in.mode & O_CREAT) { - create_mode = m_in.c_mode; - r = fetch_name(m_in.c_name, m_in.name1_length, M1); + create_mode = m_in.c_mode; + r = fetch_name(m_in.c_name, m_in.name1_length, M1, fullpath); } else { - r = fetch_name(m_in.name, m_in.name_length, M3); + r = fetch_name(m_in.name, m_in.name_length, M3, fullpath); } if (r != OK) return(err_code); /* name was bad */ - r = common_open(m_in.mode, create_mode); + r = common_open(fullpath, m_in.mode, create_mode); return(r); } @@ -74,101 +83,143 @@ PUBLIC int do_open() /*===========================================================================* * common_open * *===========================================================================*/ -PUBLIC int common_open(register int oflags, mode_t omode) +PUBLIC int common_open(char path[PATH_MAX], int oflags, mode_t omode) { /* Common code from do_creat and do_open. */ - int b, r, exist = TRUE; + int b, r, exist = TRUE, major_dev; dev_t dev; mode_t bits; - struct filp *fil_ptr, *filp2; + struct filp *filp, *filp2; struct vnode *vp; struct vmnt *vmp; struct dmap *dp; + struct lookup resolve; /* Remap the bottom two bits of oflags. */ bits = (mode_t) mode_map[oflags & O_ACCMODE]; if (!bits) return(EINVAL); /* See if file descriptor and filp slots are available. */ - if ((r = get_fd(0, bits, &m_in.fd, &fil_ptr)) != OK) return(r); + if ((r = get_fd(0, bits, &(scratch(fp).file.fd_nr), &filp)) != OK) return(r); + + lookup_init(&resolve, path, PATH_NOFLAGS, &vmp, &vp); /* If O_CREATE is set, try to make the file. */ if (oflags & O_CREAT) { omode = I_REGULAR | (omode & ALL_MODES & fp->fp_umask); - vp = new_node(oflags, omode); + vp = new_node(&resolve, oflags, omode); r = err_code; - if (r == OK) exist = FALSE; /* We just created the file */ - else if (r != EEXIST) return(r); /* other error */ - else exist = !(oflags & O_EXCL); /* file exists, if the O_EXCL - flag is set this is an error */ + if (r == OK) exist = FALSE; /* We just created the file */ + else if (r != EEXIST) { /* other error */ + if (vp) unlock_vnode(vp); + unlock_filp(filp); + return(r); + } + else exist = !(oflags & O_EXCL);/* file exists, if the O_EXCL + flag is set this is an error */ } else { /* Scan path name */ - if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); + resolve.l_vmnt_lock = VMNT_READ; + resolve.l_vnode_lock = VNODE_OPCL; + if ((vp = eat_path(&resolve, fp)) == NULL) { + unlock_filp(filp); + return(err_code); + } + + if (vmp != NULL) unlock_vmnt(vmp); } /* Claim the file descriptor and filp slot and fill them in. */ - fp->fp_filp[m_in.fd] = fil_ptr; - FD_SET(m_in.fd, &fp->fp_filp_inuse); - fil_ptr->filp_count = 1; - fil_ptr->filp_vno = vp; - fil_ptr->filp_flags = oflags; + fp->fp_filp[scratch(fp).file.fd_nr] = filp; + FD_SET(scratch(fp).file.fd_nr, &fp->fp_filp_inuse); + filp->filp_count = 1; + filp->filp_vno = vp; + filp->filp_flags = oflags; /* Only do the normal open code if we didn't just create the file. */ - if(exist) { + if (exist) { /* Check protections. */ if ((r = forbidden(fp, vp, bits)) == OK) { /* Opening reg. files, directories, and special files differ */ switch (vp->v_mode & I_TYPE) { case I_REGULAR: - /* Truncate regular file if O_TRUNC. */ - if (oflags & O_TRUNC) { - if ((r = forbidden(fp, vp, W_BIT)) != OK) - break; - truncate_vnode(vp, 0); - } - break; + /* Truncate regular file if O_TRUNC. */ + if (oflags & O_TRUNC) { + if ((r = forbidden(fp, vp, W_BIT)) != OK) + break; + truncate_vnode(vp, 0); + } + break; case I_DIRECTORY: - /* Directories may be read but not written. */ - r = (bits & W_BIT ? EISDIR : OK); - break; + /* Directories may be read but not written. */ + r = (bits & W_BIT ? EISDIR : OK); + break; case I_CHAR_SPECIAL: /* Invoke the driver for special processing. */ dev = (dev_t) vp->v_sdev; /* TTY needs to know about the O_NOCTTY flag. */ r = dev_open(dev, who_e, bits | (oflags & O_NOCTTY)); - if (r == SUSPEND) suspend(FP_BLOCKED_ON_DOPEN); - break; + if (r == SUSPEND) suspend(FP_BLOCKED_ON_DOPEN); + else vp = filp->filp_vno; /* Might be updated by + * dev_open/clone_opcl */ + break; case I_BLOCK_SPECIAL: + + lock_bsf(); + /* Invoke the driver for special processing. */ dev = (dev_t) vp->v_sdev; r = bdev_open(dev, bits); - if (r != OK) break; + if (r != OK) { + unlock_bsf(); + break; + } + + major_dev = major(vp->v_sdev); + dp = &dmap[major_dev]; + if (dp->dmap_driver == NONE) { + printf("VFS: block driver disappeared!\n"); + unlock_bsf(); + r = ENXIO; + break; + } /* Check whether the device is mounted or not. If so, * then that FS is responsible for this device. * Otherwise we default to ROOT_FS. */ vp->v_bfs_e = ROOT_FS_E; /* By default */ - for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) - if (vmp->m_dev == vp->v_sdev) + for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) + if (vmp->m_dev == vp->v_sdev && + !(vmp->m_flags & VMNT_FORCEROOTBSF)) { vp->v_bfs_e = vmp->m_fs_e; + } - /* Send the driver label to the file system (even when - * known already). + /* Send the driver label to the file system that will + * handle the block I/O requests (even when its label + * and endpoint are known already), but only when it is + * the root file system. Other file systems will + * already have it anyway. */ - dp = &dmap[major(vp->v_sdev)]; - if ((r = req_newdriver(vp->v_bfs_e, vp->v_sdev, - dp->dmap_label)) != OK) { + if (vp->v_bfs_e != ROOT_FS_E) { + unlock_bsf(); + break; + } + + if (req_newdriver(vp->v_bfs_e, vp->v_sdev, + dp->dmap_label) != OK) { printf("VFS: error sending driver label\n"); bdev_close(dev); r = ENXIO; } + unlock_bsf(); break; case I_NAMED_PIPE: /* Create a mapped inode on PFS which handles reads and writes to this named pipe. */ - r = map_vnode(vp); + tll_upgrade(&vp->v_lock); + r = map_vnode(vp, PFS_PROC_NR); if (r == OK) { vp->v_pipe = I_PIPE; if (vp->v_ref_count == 1) { @@ -178,7 +229,7 @@ PUBLIC int common_open(register int oflags, mode_t omode) r = truncate_vnode(vp, 0); } oflags |= O_APPEND; /* force append mode */ - fil_ptr->filp_flags = oflags; + filp->filp_flags = oflags; } if (r == OK) { r = pipe_open(vp, bits, oflags); @@ -189,10 +240,10 @@ PUBLIC int common_open(register int oflags, mode_t omode) * file position will be automatically shared. */ b = (bits & R_BIT ? R_BIT : W_BIT); - fil_ptr->filp_count = 0; /* don't find self */ + filp->filp_count = 0; /* don't find self */ if ((filp2 = find_filp(vp, b)) != NULL) { /* Co-reader or writer found. Use it.*/ - fp->fp_filp[m_in.fd] = filp2; + fp->fp_filp[scratch(fp).file.fd_nr] = filp2; filp2->filp_count++; filp2->filp_vno = vp; filp2->filp_flags = oflags; @@ -204,71 +255,105 @@ PUBLIC int common_open(register int oflags, mode_t omode) * existing filp entry. Correct this * error. */ + unlock_vnode(vp); put_vnode(vp); } else { /* Nobody else found. Restore filp. */ - fil_ptr->filp_count = 1; + filp->filp_count = 1; } - } + } break; } } } + unlock_filp(filp); + /* If error, release inode. */ if (r != OK) { - if (r == SUSPEND) return(r); /* Oops, just suspended */ - fp->fp_filp[m_in.fd] = NULL; - FD_CLR(m_in.fd, &fp->fp_filp_inuse); - fil_ptr->filp_count= 0; - put_vnode(vp); - fil_ptr->filp_vno = NULL; - return(r); + if (r != SUSPEND) { + fp->fp_filp[scratch(fp).file.fd_nr] = NULL; + FD_CLR(scratch(fp).file.fd_nr, &fp->fp_filp_inuse); + filp->filp_count = 0; + filp->filp_vno = NULL; + put_vnode(vp); + } + } else { + r = scratch(fp).file.fd_nr; } - - return(m_in.fd); + + return(r); } /*===========================================================================* * new_node * *===========================================================================*/ -PRIVATE struct vnode *new_node(int oflags, mode_t bits) +PRIVATE struct vnode *new_node(struct lookup *resolve, int oflags, mode_t bits) { /* Try to create a new inode and return a pointer to it. If the inode already exists, return a pointer to it as well, but set err_code accordingly. NULL is returned if the path cannot be resolved up to the last directory, or when the inode cannot be created due to permissions or - otherwise. */ + otherwise. */ struct vnode *dirp, *vp; - int r, flags; + struct vmnt *dir_vmp, *vp_vmp; + int r; struct node_details res; + struct lookup findnode; + char *path; + + path = resolve->l_path; /* For easy access */ + + lookup_init(&findnode, path, resolve->l_flags, &dir_vmp, &dirp); + findnode.l_vmnt_lock = VMNT_WRITE; + findnode.l_vnode_lock = VNODE_WRITE; /* dir node */ /* When O_CREAT and O_EXCL flags are set, the path may not be named by a * symbolic link. */ - flags = PATH_NOFLAGS; - if (oflags & O_EXCL) flags |= PATH_RET_SYMLINK; + if (oflags & O_EXCL) findnode.l_flags |= PATH_RET_SYMLINK; /* See if the path can be opened down to the last directory. */ - if ((dirp = last_dir(fp)) == NULL) return(NULL); + if ((dirp = last_dir(&findnode, fp)) == NULL) return(NULL); /* The final directory is accessible. Get final component of the path. */ - vp = advance(dirp, flags, fp); + lookup_init(&findnode, findnode.l_path, findnode.l_flags, &vp_vmp, &vp); + findnode.l_vmnt_lock = VMNT_WRITE; + findnode.l_vnode_lock = (oflags & O_TRUNC) ? VNODE_WRITE : VNODE_OPCL; + vp = advance(dirp, &findnode, fp); + assert(vp_vmp == NULL); /* Lookup to last dir should have yielded lock + * on vmp or final component does not exist. + * Either way, vp_vmp ought to be not set. + */ /* The combination of a symlink with absolute path followed by a danglink * symlink results in a new path that needs to be re-resolved entirely. */ - if (user_fullpath[0] == '/') return new_node(oflags, bits); + if (path[0] == '/') { + unlock_vnode(dirp); + unlock_vmnt(dir_vmp); + put_vnode(dirp); + if (vp != NULL) { + unlock_vnode(vp); + put_vnode(vp); + } + return new_node(resolve, oflags, bits); + } if (vp == NULL && err_code == ENOENT) { /* Last path component does not exist. Make a new directory entry. */ if ((vp = get_free_vnode()) == NULL) { - /* Can't create new vnode: out of vnodes. */ - put_vnode(dirp); + /* Can't create new entry: out of vnodes. */ + unlock_vnode(dirp); + unlock_vmnt(dir_vmp); + put_vnode(dirp); return(NULL); } + + lock_vnode(vp, VNODE_OPCL); + if ((r = forbidden(fp, dirp, W_BIT|X_BIT)) != OK || (r = req_create(dirp->v_fs_e, dirp->v_inode_nr,bits, fp->fp_effuid, - fp->fp_effgid, user_fullpath, &res)) != OK ) { + fp->fp_effgid, path, &res)) != OK ) { /* Can't create inode either due to permissions or some other * problem. In case r is EEXIST, we might be dealing with a * dangling symlink.*/ @@ -276,58 +361,74 @@ PRIVATE struct vnode *new_node(int oflags, mode_t bits) struct vnode *slp, *old_wd; /* Resolve path up to symlink */ - slp = advance(dirp, PATH_RET_SYMLINK, fp); + findnode.l_flags = PATH_RET_SYMLINK; + findnode.l_vnode_lock = VNODE_READ; + findnode.l_vnode = &slp; + slp = advance(dirp, &findnode, fp); if (slp != NULL) { if (S_ISLNK(slp->v_mode)) { /* Get contents of link */ - int max_linklen; - max_linklen = sizeof(user_fullpath)-1; r = req_rdlink(slp->v_fs_e, slp->v_inode_nr, - VFS_PROC_NR, - user_fullpath, - max_linklen, 0); + VFS_PROC_NR, + path, + PATH_MAX - 1, 0); if (r < 0) { /* Failed to read link */ + unlock_vnode(slp); + unlock_vnode(dirp); + unlock_vmnt(dir_vmp); put_vnode(slp); put_vnode(dirp); err_code = r; return(NULL); } - user_fullpath[r] = '\0';/* Term. path*/ - } + path[r] = '\0'; /* Terminate path */ + } + unlock_vnode(slp); put_vnode(slp); } /* Try to create the inode the dangling symlink was * pointing to. We have to use dirp as starting point * as there might be multiple successive symlinks - * crossing multiple mountpoints. */ + * crossing multiple mountpoints. + * Unlock vnodes and vmnts as we're going to recurse. + */ + unlock_vnode(dirp); + unlock_vnode(vp); + unlock_vmnt(dir_vmp); + old_wd = fp->fp_wd; /* Save orig. working dirp */ fp->fp_wd = dirp; - vp = new_node(oflags, bits); + vp = new_node(resolve, oflags, bits); fp->fp_wd = old_wd; /* Restore */ if (vp != NULL) { put_vnode(dirp); + *(resolve->l_vnode) = vp; return(vp); } r = err_code; - } + } - if (r == EEXIST) + if (r == EEXIST) err_code = EIO; /* Impossible, we have verified that * the last component doesn't exist and * is not a dangling symlink. */ else err_code = r; + unlock_vnode(dirp); + unlock_vnode(vp); + unlock_vmnt(dir_vmp); put_vnode(dirp); return(NULL); } - + /* Store results and mark vnode in use */ + vp->v_fs_e = res.fs_e; vp->v_inode_nr = res.inode_nr; vp->v_mode = res.fmode; @@ -340,16 +441,25 @@ PRIVATE struct vnode *new_node(int oflags, mode_t bits) vp->v_fs_count = 1; vp->v_ref_count = 1; } else { - /* Either last component exists, or there is some other problem. */ - if (vp != NULL) - r = EEXIST; /* File exists or a symlink names a file while - * O_EXCL is set. */ - else + /* Either last component exists, or there is some other problem. */ + if (vp != NULL) { + r = EEXIST; /* File exists or a symlink names a file while + * O_EXCL is set. */ + } else r = err_code; /* Other problem. */ } err_code = r; + /* When dirp equals vp, we shouldn't release the lock as a vp is locked only + * once. Releasing the lock would cause the resulting vp not be locked and + * cause mayhem later on. */ + if (dirp != vp) { + unlock_vnode(dirp); + } + unlock_vmnt(dir_vmp); put_vnode(dirp); + + *(resolve->l_vnode) = vp; return(vp); } @@ -357,8 +467,7 @@ PRIVATE struct vnode *new_node(int oflags, mode_t bits) /*===========================================================================* * pipe_open * *===========================================================================*/ -PRIVATE int pipe_open(register struct vnode *vp, register mode_t bits, - register int oflags) +PRIVATE int pipe_open(struct vnode *vp, mode_t bits, int oflags) { /* This function is called from common_open. It checks if * there is at least one reader/writer pair for the pipe, if not @@ -366,15 +475,18 @@ PRIVATE int pipe_open(register struct vnode *vp, register mode_t bits, * processes hanging on the pipe. */ - vp->v_pipe = I_PIPE; + vp->v_pipe = I_PIPE; - if((bits & (R_BIT|W_BIT)) == (R_BIT|W_BIT)) return(ENXIO); + if ((bits & (R_BIT|W_BIT)) == (R_BIT|W_BIT)) return(ENXIO); - if (find_filp(vp, bits & W_BIT ? R_BIT : W_BIT) == NULL) { + /* Find the reader/writer at the other end of the pipe */ + if (find_filp(vp, bits & W_BIT ? R_BIT : W_BIT) == NULL) { + /* Not found */ if (oflags & O_NONBLOCK) { if (bits & W_BIT) return(ENXIO); } else { - suspend(FP_BLOCKED_ON_POPEN); /* suspend caller */ + /* Let's wait for the other side to show up */ + suspend(FP_BLOCKED_ON_POPEN); return(SUSPEND); } } else if (susp_count > 0) { /* revive blocked processes */ @@ -394,32 +506,41 @@ PUBLIC int do_mknod() register mode_t bits, mode_bits; int r; struct vnode *vp; - + struct vmnt *vmp; + char fullpath[PATH_MAX]; + struct lookup resolve; + + lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); + resolve.l_vmnt_lock = VMNT_WRITE; + resolve.l_vnode_lock = VNODE_READ; + /* Only the super_user may make nodes other than fifos. */ mode_bits = (mode_t) m_in.mk_mode; /* mode of the inode */ - if(!super_user && (((mode_bits & I_TYPE) != I_NAMED_PIPE) && ((mode_bits & I_TYPE) != I_UNIX_SOCKET))) return(EPERM); + if (!super_user && (((mode_bits & I_TYPE) != I_NAMED_PIPE) && + ((mode_bits & I_TYPE) != I_UNIX_SOCKET))) { + return(EPERM); + } bits = (mode_bits & I_TYPE) | (mode_bits & ALL_MODES & fp->fp_umask); /* Open directory that's going to hold the new node. */ - if(fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if((vp = last_dir(fp)) == NULL) return(err_code); + if (fetch_name(m_in.name1, m_in.name1_length, M1, fullpath) != OK) + return(err_code); + if ((vp = last_dir(&resolve, fp)) == NULL) return(err_code); /* Make sure that the object is a directory */ - if((vp->v_mode & I_TYPE) != I_DIRECTORY) { - put_vnode(vp); - return(ENOTDIR); - } - - if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) { - r = req_mknod(vp->v_fs_e, vp->v_inode_nr, user_fullpath, fp->fp_effuid, + if ((vp->v_mode & I_TYPE) != I_DIRECTORY) { + r = ENOTDIR; + } else if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) { + r = req_mknod(vp->v_fs_e, vp->v_inode_nr, fullpath, fp->fp_effuid, fp->fp_effgid, bits, m_in.mk_z0); } + unlock_vnode(vp); + unlock_vmnt(vmp); put_vnode(vp); return(r); } - /*===========================================================================* * do_mkdir * *===========================================================================*/ @@ -429,30 +550,33 @@ PUBLIC int do_mkdir() mode_t bits; /* mode bits for the new inode */ int r; struct vnode *vp; + struct vmnt *vmp; + char fullpath[PATH_MAX]; + struct lookup resolve; - if(fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); + lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); + resolve.l_vmnt_lock = VMNT_WRITE; + resolve.l_vnode_lock = VNODE_READ; + if (fetch_name(m_in.name1, m_in.name1_length, M1, fullpath) != OK) + return(err_code); bits = I_DIRECTORY | (m_in.mode & RWX_MODES & fp->fp_umask); - - /* Request lookup */ - if((vp = last_dir(fp)) == NULL) return(err_code); + if ((vp = last_dir(&resolve, fp)) == NULL) return(err_code); /* Make sure that the object is a directory */ if ((vp->v_mode & I_TYPE) != I_DIRECTORY) { - put_vnode(vp); - return(ENOTDIR); - } - - if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) { - r = req_mkdir(vp->v_fs_e, vp->v_inode_nr, user_fullpath, fp->fp_effuid, + r = ENOTDIR; + } else if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) { + r = req_mkdir(vp->v_fs_e, vp->v_inode_nr, fullpath, fp->fp_effuid, fp->fp_effgid, bits); } + unlock_vnode(vp); + unlock_vmnt(vmp); put_vnode(vp); return(r); } - /*===========================================================================* * do_lseek * *===========================================================================*/ @@ -460,48 +584,55 @@ PUBLIC int do_lseek() { /* Perform the lseek(ls_fd, offset, whence) system call. */ register struct filp *rfilp; - int r; + int r = OK; long offset; u64_t pos, newpos; /* Check to see if the file descriptor is valid. */ - if ( (rfilp = get_filp(m_in.ls_fd)) == NULL) return(err_code); + if ( (rfilp = get_filp(m_in.ls_fd, VNODE_READ)) == NULL) return(err_code); /* No lseek on pipes. */ - if (rfilp->filp_vno->v_pipe == I_PIPE) return(ESPIPE); + if (rfilp->filp_vno->v_pipe == I_PIPE) { + unlock_filp(rfilp); + return(ESPIPE); + } /* The value of 'whence' determines the start position to use. */ switch(m_in.whence) { - case SEEK_SET: pos = cvu64(0); break; - case SEEK_CUR: pos = rfilp->filp_pos; break; - case SEEK_END: pos = cvul64(rfilp->filp_vno->v_size); break; - default: return(EINVAL); + case SEEK_SET: pos = cvu64(0); break; + case SEEK_CUR: pos = rfilp->filp_pos; break; + case SEEK_END: pos = cvul64(rfilp->filp_vno->v_size); break; + default: unlock_filp(rfilp); return(EINVAL); } offset = m_in.offset_lo; if (offset >= 0) - newpos= add64ul(pos, offset); + newpos = add64ul(pos, offset); else - newpos= sub64ul(pos, -offset); + newpos = sub64ul(pos, -offset); /* Check for overflow. */ - if (ex64hi(newpos) != 0) - return(EINVAL); + if (ex64hi(newpos) != 0) { + r = EOVERFLOW; + } else if ((off_t) ex64lo(newpos) < 0) { /* no negative file size */ + r = EOVERFLOW; + } else { + rfilp->filp_pos = newpos; - if (cmp64(newpos, rfilp->filp_pos) != 0) { /* Inhibit read ahead request */ - r = req_inhibread(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr); - if (r != OK) return(r); + /* insert the new position into the output message */ + m_out.reply_l1 = ex64lo(newpos); + + if (cmp64(newpos, rfilp->filp_pos) != 0) { + /* Inhibit read ahead request */ + r = req_inhibread(rfilp->filp_vno->v_fs_e, + rfilp->filp_vno->v_inode_nr); + } } - rfilp->filp_pos = newpos; - - /* insert the new position into the output message */ - m_out.reply_l1 = ex64lo(newpos); - - return(OK); + unlock_filp(rfilp); + return(r); } - /*===========================================================================* * do_llseek * *===========================================================================*/ @@ -510,48 +641,57 @@ PUBLIC int do_llseek() /* Perform the llseek(ls_fd, offset, whence) system call. */ register struct filp *rfilp; u64_t pos, newpos; - int r; + int r = OK; /* Check to see if the file descriptor is valid. */ - if ( (rfilp = get_filp(m_in.ls_fd)) == NULL) return(err_code); + if ( (rfilp = get_filp(m_in.ls_fd, VNODE_READ)) == NULL) return(err_code); /* No lseek on pipes. */ - if (rfilp->filp_vno->v_pipe == I_PIPE) return(ESPIPE); + if (rfilp->filp_vno->v_pipe == I_PIPE) { + unlock_filp(rfilp); + return(ESPIPE); + } /* The value of 'whence' determines the start position to use. */ switch(m_in.whence) { - case SEEK_SET: pos = cvu64(0); break; - case SEEK_CUR: pos = rfilp->filp_pos; break; - case SEEK_END: pos = cvul64(rfilp->filp_vno->v_size); break; - default: return(EINVAL); + case SEEK_SET: pos = cvu64(0); break; + case SEEK_CUR: pos = rfilp->filp_pos; break; + case SEEK_END: pos = cvul64(rfilp->filp_vno->v_size); break; + default: unlock_filp(rfilp); return(EINVAL); } newpos = add64(pos, make64(m_in.offset_lo, m_in.offset_high)); /* Check for overflow. */ - if (((long)m_in.offset_high > 0) && cmp64(newpos, pos) < 0) - return(EINVAL); - if (((long)m_in.offset_high < 0) && cmp64(newpos, pos) > 0) - return(EINVAL); + if (( (long) m_in.offset_high > 0) && cmp64(newpos, pos) < 0) + r = EINVAL; + else if (( (long) m_in.offset_high < 0) && cmp64(newpos, pos) > 0) + r = EINVAL; + else { + rfilp->filp_pos = newpos; - if (cmp64(newpos, rfilp->filp_pos) != 0) { /* Inhibit read ahead request */ - r = req_inhibread(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr); - if (r != OK) return(r); + /* insert the new position into the output message */ + m_out.reply_l1 = ex64lo(newpos); + m_out.reply_l2 = ex64hi(newpos); + + if (cmp64(newpos, rfilp->filp_pos) != 0) { + /* Inhibit read ahead request */ + r = req_inhibread(rfilp->filp_vno->v_fs_e, + rfilp->filp_vno->v_inode_nr); + } } - rfilp->filp_pos = newpos; - m_out.reply_l1 = ex64lo(newpos); - m_out.reply_l2 = ex64hi(newpos); - return(OK); + unlock_filp(rfilp); + return(r); } - /*===========================================================================* * do_close * *===========================================================================*/ PUBLIC int do_close() { /* Perform the close(fd) system call. */ + return close_fd(fp, m_in.fd); } @@ -570,25 +710,28 @@ int fd_nr; int lock_count; /* First locate the vnode that belongs to the file descriptor. */ - if ( (rfilp = get_filp2(rfp, fd_nr)) == NULL) return(err_code); + if ( (rfilp = get_filp2(rfp, fd_nr, VNODE_OPCL)) == NULL) return(err_code); vp = rfilp->filp_vno; - close_filp(rfilp); - FD_CLR(fd_nr, &rfp->fp_cloexec_set); + close_filp(rfilp); rfp->fp_filp[fd_nr] = NULL; + FD_CLR(fd_nr, &rfp->fp_cloexec_set); FD_CLR(fd_nr, &rfp->fp_filp_inuse); /* Check to see if the file is locked. If so, release all locks. */ - if (nr_locks == 0) return(OK); - lock_count = nr_locks; /* save count of locks */ - for (flp = &file_lock[0]; flp < &file_lock[NR_LOCKS]; flp++) { - if (flp->lock_type == 0) continue; /* slot not in use */ - if (flp->lock_vnode == vp && flp->lock_pid == rfp->fp_pid) { - flp->lock_type = 0; - nr_locks--; + if (nr_locks > 0) { + lock_count = nr_locks; /* save count of locks */ + for (flp = &file_lock[0]; flp < &file_lock[NR_LOCKS]; flp++) { + if (flp->lock_type == 0) continue; /* slot not in use */ + if (flp->lock_vnode == vp && flp->lock_pid == rfp->fp_pid) { + flp->lock_type = 0; + nr_locks--; + } } + if (nr_locks < lock_count) + lock_revive(); /* one or more locks released */ } - if (nr_locks < lock_count) lock_revive(); /* lock released */ + return(OK); } @@ -599,4 +742,3 @@ PUBLIC void close_reply() { /* No need to do anything */ } - diff --git a/servers/vfs/param.h b/servers/vfs/param.h index 77a27f830..ea05621bb 100644 --- a/servers/vfs/param.h +++ b/servers/vfs/param.h @@ -1,3 +1,6 @@ +#ifndef __VFS_PARAM_H__ +#define __VFS_PARAM_H__ + /* The following names are synonyms for the variables in the input message. */ #define addr m1_i3 #define buffer m1_p1 @@ -54,3 +57,5 @@ #define reply_l2 m2_l2 #define reply_i1 m1_i1 #define reply_i2 m1_i2 + +#endif diff --git a/servers/vfs/path.c b/servers/vfs/path.c index 834ba6b2b..a6945458f 100644 --- a/servers/vfs/path.c +++ b/servers/vfs/path.c @@ -1,4 +1,4 @@ -/* lookup() is the main routine that controls the path name lookup. It +/* lookup() is the main routine that controls the path name lookup. It * handles mountpoints and symbolic links. The actual lookup requests * are sent through the req_lookup wrapper function. */ @@ -16,9 +16,11 @@ #include #include #include -#include "fproc.h" +#include "threads.h" #include "vmnt.h" #include "vnode.h" +#include "path.h" +#include "fproc.h" #include "param.h" /* Set to following define to 1 if you really want to use the POSIX definition @@ -31,157 +33,337 @@ */ #define DO_POSIX_PATHNAME_RES 0 -FORWARD _PROTOTYPE( int lookup, (struct vnode *dirp, int flags, +FORWARD _PROTOTYPE( int lookup, (struct vnode *dirp, struct lookup *resolve, node_details_t *node, struct fproc *rfp)); +FORWARD _PROTOTYPE( int check_perms, (endpoint_t ep, cp_grant_id_t io_gr, + size_t pathlen) ); /*===========================================================================* * advance * *===========================================================================*/ -PUBLIC struct vnode *advance(dirp, flags, rfp) +PUBLIC struct vnode *advance(dirp, resolve, rfp) struct vnode *dirp; -int flags; +struct lookup *resolve; struct fproc *rfp; { -/* Resolve a pathname (in user_fullpath) starting at dirp to a vnode. */ +/* Resolve a path name starting at dirp to a vnode. */ int r; + int do_downgrade = 1; struct vnode *new_vp, *vp; struct vmnt *vmp; struct node_details res = {0,0,0,0,0,0,0}; + tll_access_t initial_locktype; assert(dirp); + assert(resolve->l_vnode_lock != TLL_NONE); + assert(resolve->l_vmnt_lock != TLL_NONE); + + if (resolve->l_vnode_lock == VNODE_READ) + initial_locktype = VNODE_OPCL; + else + initial_locktype = resolve->l_vnode_lock; + + /* Get a free vnode and lock it */ + if ((new_vp = get_free_vnode()) == NULL) return(NULL); + lock_vnode(new_vp, initial_locktype); - /* Get a free vnode */ - if((new_vp = get_free_vnode()) == NULL) return(NULL); - /* Lookup vnode belonging to the file. */ - if ((r = lookup(dirp, flags, &res, rfp)) != OK) { + if ((r = lookup(dirp, resolve, &res, rfp)) != OK) { err_code = r; + unlock_vnode(new_vp); return(NULL); } - - /* Check whether vnode is already in use or not */ + + /* Check whether we already have a vnode for that file */ if ((vp = find_vnode(res.fs_e, res.inode_nr)) != NULL) { - dup_vnode(vp); - vp->v_fs_count++; /* We got a reference from the FS */ - return(vp); + unlock_vnode(new_vp); /* Don't need this anymore */ + do_downgrade = (lock_vnode(vp, initial_locktype) != EBUSY); + + /* Unfortunately, by the time we get the lock, another thread might've + * rid of the vnode (e.g., find_vnode found the vnode while a + * req_putnode was being processed). */ + if (vp->v_ref_count == 0) { /* vnode vanished! */ + /* As the lookup before increased the usage counters in the FS, + * we can simply set the usage counters to 1 and proceed as + * normal, because the putnode resulted in a use count of 1 in + * the FS. Other data is still valid, because the vnode was + * marked as pending lock, so get_free_vnode hasn't + * reinitialized the vnode yet. */ + vp->v_fs_count = 1; + if (vp->v_mapfs_e != NONE) vp->v_mapfs_count = 1; + } else { + vp->v_fs_count++; /* We got a reference from the FS */ + } + + } else { + /* Vnode not found, fill in the free vnode's fields */ + + new_vp->v_fs_e = res.fs_e; + new_vp->v_inode_nr = res.inode_nr; + new_vp->v_mode = res.fmode; + new_vp->v_size = res.fsize; + new_vp->v_uid = res.uid; + new_vp->v_gid = res.gid; + new_vp->v_sdev = res.dev; + + if( (vmp = find_vmnt(new_vp->v_fs_e)) == NULL) + panic("advance: vmnt not found"); + + new_vp->v_vmnt = vmp; + new_vp->v_dev = vmp->m_dev; + new_vp->v_fs_count = 1; + + vp = new_vp; } - /* Fill in the free vnode's fields */ - new_vp->v_fs_e = res.fs_e; - new_vp->v_inode_nr = res.inode_nr; - new_vp->v_mode = res.fmode; - new_vp->v_size = res.fsize; - new_vp->v_uid = res.uid; - new_vp->v_gid = res.gid; - new_vp->v_sdev = res.dev; - - if( (vmp = find_vmnt(new_vp->v_fs_e)) == NULL) - panic("VFS advance: vmnt not found"); + dup_vnode(vp); + if (do_downgrade) { + /* Only downgrade a lock if we managed to lock it in the first place */ + *(resolve->l_vnode) = vp; - new_vp->v_vmnt = vmp; - new_vp->v_dev = vmp->m_dev; - new_vp->v_fs_count = 1; - new_vp->v_ref_count = 1; - - return(new_vp); + if (initial_locktype != resolve->l_vnode_lock) + tll_downgrade(&vp->v_lock); + +#if LOCK_DEBUG + if (resolve->l_vnode_lock == VNODE_READ) + fp->fp_vp_rdlocks++; +#endif + } + + return(vp); } - /*===========================================================================* * eat_path * *===========================================================================*/ -PUBLIC struct vnode *eat_path(flags, rfp) -int flags; +PUBLIC struct vnode *eat_path(resolve, rfp) +struct lookup *resolve; struct fproc *rfp; { -/* Resolve 'user_fullpath' to a vnode. advance does the actual work. */ - struct vnode *vp; +/* Resolve path to a vnode. advance does the actual work. */ + struct vnode *start_dir; - vp = (user_fullpath[0] == '/' ? rfp->fp_rd : rfp->fp_wd); - return advance(vp, flags, rfp); + start_dir = (resolve->l_path[0] == '/' ? rfp->fp_rd : rfp->fp_wd); + return advance(start_dir, resolve, rfp); } - /*===========================================================================* * last_dir * *===========================================================================*/ -PUBLIC struct vnode *last_dir(rfp) +PUBLIC struct vnode *last_dir(resolve, rfp) +struct lookup *resolve; struct fproc *rfp; { -/* Parse a path, 'user_fullpath', as far as the last directory, fetch the vnode +/* Parse a path, as far as the last directory, fetch the vnode * for the last directory into the vnode table, and return a pointer to the * vnode. In addition, return the final component of the path in 'string'. If * the last directory can't be opened, return NULL and the reason for * failure in 'err_code'. We can't parse component by component as that would * be too expensive. Alternatively, we cut off the last component of the path, * and parse the path up to the penultimate component. - */ + */ size_t len; char *cp; char dir_entry[NAME_MAX+1]; - struct vnode *vp, *res; - - /* Is the path absolute or relative? Initialize 'vp' accordingly. */ - vp = (user_fullpath[0] == '/' ? rfp->fp_rd : rfp->fp_wd); + struct vnode *start_dir, *res_vp, *sym_vp, *loop_start; + struct vmnt *sym_vmp = NULL; + int r, symloop = 0, ret_on_symlink = 0; + struct lookup symlink; - len = strlen(user_fullpath); + *resolve->l_vnode = NULL; + *resolve->l_vmp = NULL; + loop_start = NULL; + sym_vp = NULL; - /* If path is empty, return ENOENT. */ - if (len == 0) { - err_code = ENOENT; - return(NULL); - } + ret_on_symlink = !!(resolve->l_flags & PATH_RET_SYMLINK); + + do { + /* Is the path absolute or relative? Initialize 'start_dir' + * accordingly. Use loop_start in case we're looping. + */ + if (loop_start != NULL) + start_dir = loop_start; + else + start_dir = (resolve->l_path[0] == '/' ? rfp->fp_rd:rfp->fp_wd); + + len = strlen(resolve->l_path); + + /* If path is empty, return ENOENT. */ + if (len == 0) { + err_code = ENOENT; + res_vp = NULL; + break; + } #if !DO_POSIX_PATHNAME_RES - /* Remove trailing slashes */ - while (len > 1 && user_fullpath[len-1] == '/') { - len--; - user_fullpath[len]= '\0'; - } + /* Remove trailing slashes */ + while (len > 1 && resolve->l_path[len-1] == '/') { + len--; + resolve->l_path[len]= '\0'; + } #endif - cp = strrchr(user_fullpath, '/'); - if (cp == NULL) { - /* Just one entry in the current working directory */ - dup_vnode(vp); - return(vp); - } else if (cp[1] == '\0') { - /* Path ends in a slash. The directory entry is '.' */ - strcpy(dir_entry, "."); - } else { - /* A path name for the directory and a directory entry */ - strncpy(dir_entry, cp+1, NAME_MAX); - cp[1]= '\0'; - dir_entry[NAME_MAX] = '\0'; + cp = strrchr(resolve->l_path, '/'); + if (cp == NULL) { + /* Just an entry in the current working directory */ + struct vmnt *vmp; + + vmp = find_vmnt(start_dir->v_fs_e); + if (vmp == NULL) { + r = EIO; + res_vp = NULL; + break; + } + r = lock_vmnt(vmp, resolve->l_vmnt_lock); + if (r == EDEADLK) { + res_vp = NULL; + break; + } else if (r == OK) + *resolve->l_vmp = vmp; + + lock_vnode(start_dir, resolve->l_vnode_lock); + *resolve->l_vnode = start_dir; + dup_vnode(start_dir); + if (loop_start != NULL) { + unlock_vnode(loop_start); + put_vnode(loop_start); + } + return(start_dir); + } else if (cp[1] == '\0') { + /* Path ends in a slash. The directory entry is '.' */ + strcpy(dir_entry, "."); + } else { + /* A path name for the directory and a directory entry */ + strncpy(dir_entry, cp+1, NAME_MAX); + cp[1] = '\0'; + dir_entry[NAME_MAX] = '\0'; + } + + /* Remove trailing slashes */ + while (cp > resolve->l_path && cp[0] == '/') { + cp[0]= '\0'; + cp--; + } + + /* Resolve up to and including the last directory of the path. Turn off + * PATH_RET_SYMLINK, because we do want to follow the symlink in this + * case. That is, the flag is meant for the actual filename of the path, + * not the last directory. + */ + resolve->l_flags &= ~PATH_RET_SYMLINK; + if ((res_vp = advance(start_dir, resolve, rfp)) == NULL) { + break; + } + + /* If the directory entry is not a symlink we're done now. If it is a + * symlink, then we're not at the last directory, yet. */ + + /* Copy the directory entry back to user_fullpath */ + strncpy(resolve->l_path, dir_entry, NAME_MAX + 1); + + /* Look up the directory entry, but do not follow the symlink when it + * is one. + */ + lookup_init(&symlink, resolve->l_path, + resolve->l_flags|PATH_RET_SYMLINK, &sym_vmp, &sym_vp); + symlink.l_vnode_lock = VNODE_READ; + symlink.l_vmnt_lock = VMNT_READ; + sym_vp = advance(res_vp, &symlink, rfp); + + /* Advance caused us to either switch to a different vmnt or we're + * still at the same vmnt. The former might've yielded a new vmnt lock, + * the latter should not have. Verify. */ + if (sym_vmp != NULL) { + /* We got a vmnt lock, so the endpoints of the vnodes must + * differ. + */ + assert(sym_vp->v_fs_e != res_vp->v_fs_e); + } + + if (sym_vp != NULL && S_ISLNK(sym_vp->v_mode)) { + /* Last component is a symlink, but if we've been asked to not + * resolve it, return now. + */ + if (ret_on_symlink) { + break; + } + + r = req_rdlink(sym_vp->v_fs_e, sym_vp->v_inode_nr, NONE, + resolve->l_path, PATH_MAX - 1, 1); + + if (r < 0) { + /* Failed to read link */ + err_code = r; + unlock_vnode(res_vp); + unlock_vmnt(*resolve->l_vmp); + put_vnode(res_vp); + *resolve->l_vmp = NULL; + *resolve->l_vnode = NULL; + res_vp = NULL; + break; + } + resolve->l_path[r] = '\0'; + + if (strrchr(resolve->l_path, '/') != NULL) { + unlock_vnode(sym_vp); + unlock_vmnt(*resolve->l_vmp); + if (sym_vmp != NULL) + unlock_vmnt(sym_vmp); + *resolve->l_vmp = NULL; + put_vnode(sym_vp); + sym_vp = NULL; + + symloop++; + + /* Relative symlinks are relative to res_vp, not cwd */ + if (resolve->l_path[0] != '/') { + loop_start = res_vp; + } else { + /* Absolute symlink, forget about res_vp */ + unlock_vnode(res_vp); + put_vnode(res_vp); + } + + continue; + } + } + break; + } while (symloop < SYMLOOP_MAX); + + if (symloop >= SYMLOOP_MAX) { + err_code = ELOOP; + res_vp = NULL; } - /* Remove trailing slashes */ - while(cp > user_fullpath && cp[0] == '/') { - cp[0]= '\0'; - cp--; + if (sym_vp != NULL) { + unlock_vnode(sym_vp); + if (sym_vmp != NULL) { + unlock_vmnt(sym_vmp); + } + put_vnode(sym_vp); } - res = advance(vp, PATH_NOFLAGS, rfp); - if (res == NULL) return(NULL); + if (loop_start != NULL) { + unlock_vnode(loop_start); + put_vnode(loop_start); + } /* Copy the directory entry back to user_fullpath */ - strncpy(user_fullpath, dir_entry, NAME_MAX); - - return(res); + strncpy(resolve->l_path, dir_entry, NAME_MAX + 1); + return(res_vp); } - /*===========================================================================* * lookup * *===========================================================================*/ -PRIVATE int lookup(start_node, flags, node, rfp) +PRIVATE int lookup(start_node, resolve, result_node, rfp) struct vnode *start_node; -int flags; -node_details_t *node; +struct lookup *resolve; +node_details_t *result_node; struct fproc *rfp; { -/* Resolve a pathname (in user_fullpath) relative to start_node. */ +/* Resolve a path name relative to start_node. */ int r, symloop; endpoint_t fs_e; @@ -190,62 +372,86 @@ struct fproc *rfp; uid_t uid; gid_t gid; struct vnode *dir_vp; - struct vmnt *vmp; + struct vmnt *vmp, *vmpres; struct lookup_res res; + assert(resolve->l_vmp); + assert(resolve->l_vnode); + + *(resolve->l_vmp) = vmpres = NULL; /* No vmnt found nor locked yet */ + /* Empty (start) path? */ - if (user_fullpath[0] == '\0') { - node->inode_nr = 0; + if (resolve->l_path[0] == '\0') { + result_node->inode_nr = 0; return(ENOENT); } - if(!rfp->fp_rd || !rfp->fp_wd) { - printf("VFS: lookup_rel %d: no rd/wd\n", rfp->fp_endpoint); + if (!rfp->fp_rd || !rfp->fp_wd) { + printf("VFS: lookup %d: no rd/wd\n", rfp->fp_endpoint); return(ENOENT); } fs_e = start_node->v_fs_e; dir_ino = start_node->v_inode_nr; - + vmpres = find_vmnt(fs_e); + + if (vmpres == NULL) return(EIO); /* mountpoint vanished? */ + /* Is the process' root directory on the same partition?, * if so, set the chroot directory too. */ if (rfp->fp_rd->v_dev == rfp->fp_wd->v_dev) - root_ino = rfp->fp_rd->v_inode_nr; + root_ino = rfp->fp_rd->v_inode_nr; else root_ino = 0; /* Set user and group ids according to the system call */ - uid = (call_nr == ACCESS ? rfp->fp_realuid : rfp->fp_effuid); - gid = (call_nr == ACCESS ? rfp->fp_realgid : rfp->fp_effgid); + uid = (call_nr == ACCESS ? rfp->fp_realuid : rfp->fp_effuid); + gid = (call_nr == ACCESS ? rfp->fp_realgid : rfp->fp_effgid); symloop = 0; /* Number of symlinks seen so far */ + /* Lock vmnt */ + if ((r = lock_vmnt(vmpres, resolve->l_vmnt_lock)) != OK) { + if (r == EBUSY) /* vmnt already locked */ + vmpres = NULL; + else + return(r); + } + *(resolve->l_vmp) = vmpres; + /* Issue the request */ - r = req_lookup(fs_e, dir_ino, root_ino, uid, gid, flags, &res, rfp); + r = req_lookup(fs_e, dir_ino, root_ino, uid, gid, resolve, &res, rfp); - if (r != OK && r != EENTERMOUNT && r != ELEAVEMOUNT && r != ESYMLINK) + if (r != OK && r != EENTERMOUNT && r != ELEAVEMOUNT && r != ESYMLINK) { + if (vmpres) unlock_vmnt(vmpres); + *(resolve->l_vmp) = NULL; return(r); /* i.e., an error occured */ + } - /* While the response is related to mount control set the + /* While the response is related to mount control set the * new requests respectively */ - while(r == EENTERMOUNT || r == ELEAVEMOUNT || r == ESYMLINK) { + while (r == EENTERMOUNT || r == ELEAVEMOUNT || r == ESYMLINK) { /* Update user_fullpath to reflect what's left to be parsed. */ path_off = res.char_processed; - path_left_len = strlen(&user_fullpath[path_off]); - memmove(user_fullpath, &user_fullpath[path_off], path_left_len); - user_fullpath[path_left_len] = '\0'; /* terminate string */ + path_left_len = strlen(&resolve->l_path[path_off]); + memmove(resolve->l_path, &resolve->l_path[path_off], path_left_len); + resolve->l_path[path_left_len] = '\0'; /* terminate string */ /* Update the current value of the symloop counter */ symloop += res.symloop; - if (symloop > SYMLOOP_MAX) + if (symloop > SYMLOOP_MAX) { + if (vmpres) unlock_vmnt(vmpres); + *(resolve->l_vmp) = NULL; return(ELOOP); + } /* Symlink encountered with absolute path */ if (r == ESYMLINK) { dir_vp = rfp->fp_rd; + vmp = NULL; } else if (r == EENTERMOUNT) { /* Entering a new partition */ - dir_vp = 0; + dir_vp = NULL; /* Start node is now the mounted partition's root node */ for (vmp = &vmnt[0]; vmp != &vmnt[NR_MNTS]; ++vmp) { if (vmp->m_dev != NO_DEV && vmp->m_mounted_on) { @@ -256,22 +462,29 @@ struct fproc *rfp; } } } - assert(dir_vp); + if (dir_vp == NULL) { + printf("VFS: path lookup error; root node not found\n"); + if (vmpres) unlock_vmnt(vmpres); + *(resolve->l_vmp) = NULL; + return(EIO); + } } else { /* Climbing up mount */ /* Find the vmnt that represents the partition on * which we "climb up". */ if ((vmp = find_vmnt(res.fs_e)) == NULL) { panic("VFS lookup: can't find parent vmnt"); - } + } /* Make sure that the child FS does not feed a bogus path * to the parent FS. That is, when we climb up the tree, we * must've encountered ".." in the path, and that is exactly * what we're going to feed to the parent */ - if(strncmp(user_fullpath, "..", 2) != 0 || - (user_fullpath[2] != '\0' && user_fullpath[2] != '/')) { - printf("VFS: bogus path: %s\n", user_fullpath); + if(strncmp(resolve->l_path, "..", 2) != 0 || + (resolve->l_path[2] != '\0' && resolve->l_path[2] != '/')) { + printf("VFS: bogus path: %s\n", resolve->l_path); + if (vmpres) unlock_vmnt(vmpres); + *(resolve->l_vmp) = NULL; return(ENOENT); } @@ -286,29 +499,67 @@ struct fproc *rfp; /* Is the process' root directory on the same partition?, * if so, set the chroot directory too. */ - if(dir_vp->v_dev == rfp->fp_rd->v_dev) - root_ino = rfp->fp_rd->v_inode_nr; + if (dir_vp->v_dev == rfp->fp_rd->v_dev) + root_ino = rfp->fp_rd->v_inode_nr; else root_ino = 0; - r = req_lookup(fs_e, dir_ino, root_ino, uid, gid, flags, &res, rfp); + /* Unlock a previously locked vmnt if locked and lock new vmnt */ + if (vmpres) unlock_vmnt(vmpres); + vmpres = find_vmnt(fs_e); + if (vmpres == NULL) return(EIO); /* mount point vanished? */ + if ((r = lock_vmnt(vmpres, resolve->l_vmnt_lock)) != OK) { + if (r == EBUSY) + vmpres = NULL; /* Already locked */ + else + return(r); + } + *(resolve->l_vmp) = vmpres; - if(r != OK && r != EENTERMOUNT && r != ELEAVEMOUNT && r != ESYMLINK) + r = req_lookup(fs_e, dir_ino, root_ino, uid, gid, resolve, &res, rfp); + + if (r != OK && r != EENTERMOUNT && r != ELEAVEMOUNT && r != ESYMLINK) { + if (vmpres) unlock_vmnt(vmpres); + *(resolve->l_vmp) = NULL; return(r); + } } /* Fill in response fields */ - node->inode_nr = res.inode_nr; - node->fmode = res.fmode; - node->fsize = res.fsize; - node->dev = res.dev; - node->fs_e = res.fs_e; - node->uid = res.uid; - node->gid = res.gid; - + result_node->inode_nr = res.inode_nr; + result_node->fmode = res.fmode; + result_node->fsize = res.fsize; + result_node->dev = res.dev; + result_node->fs_e = res.fs_e; + result_node->uid = res.uid; + result_node->gid = res.gid; + return(r); } +/*===========================================================================* + * lookup_init * + *===========================================================================*/ +PUBLIC void lookup_init(resolve, path, flags, vmp, vp) +struct lookup *resolve; +char *path; +int flags; +struct vmnt **vmp; +struct vnode **vp; +{ + assert(vmp != NULL); + assert(vp != NULL); + + resolve->l_path = path; + resolve->l_flags = flags; + resolve->l_vmp = vmp; + resolve->l_vnode = vp; + resolve->l_vmnt_lock = TLL_NONE; + resolve->l_vnode_lock = TLL_NONE; + *vmp = NULL; /* Initialize lookup result to NULL */ + *vp = NULL; +} + /*===========================================================================* * get_name * *===========================================================================*/ @@ -329,8 +580,8 @@ char ename[NAME_MAX + 1]; } do { - r = req_getdents(dirp->v_fs_e, dirp->v_inode_nr, pos, - buf, sizeof(buf), &new_pos, 1); + r = req_getdents(dirp->v_fs_e, dirp->v_inode_nr, pos, buf, sizeof(buf), + &new_pos, 1); if (r == 0) { return(ENOENT); /* end of entries -- matching inode !found */ @@ -361,108 +612,143 @@ char ename[NAME_MAX + 1]; /*===========================================================================* * canonical_path * *===========================================================================*/ -PUBLIC int canonical_path(orig_path, canon_path, rfp) -char *orig_path; -char *canon_path; /* should have length PATH_MAX */ +PUBLIC int canonical_path(orig_path, rfp) +char orig_path[PATH_MAX]; struct fproc *rfp; { +/* Find canonical path of a given path */ int len = 0; int r, symloop = 0; struct vnode *dir_vp, *parent_dir; - char component[NAME_MAX+1]; - char link_path[PATH_MAX]; + struct vmnt *dir_vmp, *parent_vmp; + char component[NAME_MAX+1]; /* NAME_MAX does /not/ include '\0' */ + char temp_path[PATH_MAX]; + struct lookup resolve; dir_vp = NULL; - orig_path[PATH_MAX - 1] = '\0'; - strncpy(user_fullpath, orig_path, PATH_MAX); + strncpy(temp_path, orig_path, PATH_MAX); + temp_path[PATH_MAX - 1] = '\0'; + /* First resolve path to the last directory holding the file */ do { - if (dir_vp) put_vnode(dir_vp); - - /* Resolve to the last directory holding the socket file */ - if ((dir_vp = last_dir(rfp)) == NULL) { - return(err_code); + if (dir_vp) { + unlock_vnode(dir_vp); + unlock_vmnt(dir_vmp); + put_vnode(dir_vp); } - /* dir_vp points to dir and user_fullpath now contains only the + lookup_init(&resolve, temp_path, PATH_NOFLAGS, &dir_vmp, &dir_vp); + resolve.l_vmnt_lock = VMNT_READ; + resolve.l_vnode_lock = VNODE_READ; + if ((dir_vp = last_dir(&resolve, rfp)) == NULL) return(err_code); + + /* dir_vp points to dir and resolve path now contains only the * filename. */ - strcpy(canon_path, user_fullpath); /* Store file name */ + strncpy(orig_path, temp_path, NAME_MAX); /* Store file name */ /* check if the file is a symlink, if so resolve it */ - r = rdlink_direct(canon_path, link_path, rfp); - if (r <= 0) { - strcpy(user_fullpath, canon_path); + r = rdlink_direct(orig_path, temp_path, rfp); + + if (r <= 0) break; - } /* encountered a symlink -- loop again */ - strcpy(user_fullpath, link_path); - + strncpy(orig_path, temp_path, PATH_MAX - 1); symloop++; } while (symloop < SYMLOOP_MAX); if (symloop >= SYMLOOP_MAX) { - if (dir_vp) put_vnode(dir_vp); - return ELOOP; + if (dir_vp) { + unlock_vnode(dir_vp); + unlock_vmnt(dir_vmp); + put_vnode(dir_vp); + } + return(ELOOP); } - while(dir_vp != rfp->fp_rd) { + /* We've got the filename and the actual directory holding the file. From + * here we start building up the canonical path by climbing up the tree */ + while (dir_vp != rfp->fp_rd) { - strcpy(user_fullpath, ".."); + strcpy(temp_path, ".."); /* check if we're at the root node of the file system */ if (dir_vp->v_vmnt->m_root_node == dir_vp) { + unlock_vnode(dir_vp); + unlock_vmnt(dir_vmp); put_vnode(dir_vp); dir_vp = dir_vp->v_vmnt->m_mounted_on; + dir_vmp = dir_vp->v_vmnt; + if (lock_vmnt(dir_vmp, VMNT_READ) != OK) + panic("failed to lock vmnt"); + if (lock_vnode(dir_vp, VNODE_READ) != OK) + panic("failed to lock vnode"); dup_vnode(dir_vp); } - if ((parent_dir = advance(dir_vp, PATH_NOFLAGS, rfp)) == NULL) { + lookup_init(&resolve, temp_path, PATH_NOFLAGS, &parent_vmp, + &parent_dir); + resolve.l_vmnt_lock = VMNT_READ; + resolve.l_vnode_lock = VNODE_READ; + + if ((parent_dir = advance(dir_vp, &resolve, rfp)) == NULL) { + unlock_vnode(dir_vp); + unlock_vmnt(dir_vmp); put_vnode(dir_vp); return(err_code); } /* now we have to retrieve the name of the parent directory */ if (get_name(parent_dir, dir_vp, component) != OK) { - put_vnode(dir_vp); + unlock_vnode(parent_dir); + unlock_vmnt(parent_vmp); + unlock_vnode(dir_vp); + unlock_vmnt(dir_vmp); put_vnode(parent_dir); + put_vnode(dir_vp); return(ENOENT); } len += strlen(component) + 1; if (len >= PATH_MAX) { - /* adding the component to canon_path would exceed PATH_MAX */ - put_vnode(dir_vp); + /* adding the component to orig_path would exceed PATH_MAX */ + unlock_vnode(parent_dir); + unlock_vmnt(parent_vmp); + unlock_vnode(dir_vp); + unlock_vmnt(dir_vmp); put_vnode(parent_dir); + put_vnode(dir_vp); return(ENOMEM); } - /* store result of component in canon_path */ - - /* first make space by moving the contents of canon_path to - * the right. Move strlen + 1 bytes to include the terminating '\0'. + /* Store result of component in orig_path. First make space by moving + * the contents of orig_path to the right. Move strlen + 1 bytes to + * include the terminating '\0'. Move to strlen + 1 bytes to reserve + * space for the slash. */ - memmove(canon_path+strlen(component)+1, canon_path, - strlen(canon_path) + 1); - + memmove(orig_path+strlen(component)+1, orig_path, strlen(orig_path)+1); /* Copy component into canon_path */ - memmove(canon_path, component, strlen(component)); - + memmove(orig_path, component, strlen(component)); /* Put slash into place */ - canon_path[strlen(component)] = '/'; + orig_path[strlen(component)] = '/'; /* Store parent_dir result, and continue the loop once more */ + unlock_vnode(dir_vp); + unlock_vmnt(dir_vmp); put_vnode(dir_vp); dir_vp = parent_dir; } + unlock_vnode(dir_vp); + unlock_vmnt(parent_vmp); + put_vnode(dir_vp); /* add the leading slash */ - if (strlen(canon_path) >= PATH_MAX) return(ENAMETOOLONG); - memmove(canon_path+1, canon_path, strlen(canon_path)); - canon_path[0] = '/'; + if (strlen(orig_path) >= PATH_MAX) return(ENAMETOOLONG); + memmove(orig_path+1, orig_path, strlen(orig_path)); + orig_path[0] = '/'; return(OK); } @@ -470,62 +756,50 @@ struct fproc *rfp; /*===========================================================================* * check_perms * *===========================================================================*/ -PUBLIC int check_perms(ep, io_gr, pathlen) +PRIVATE int check_perms(ep, io_gr, pathlen) endpoint_t ep; cp_grant_id_t io_gr; -int pathlen; +size_t pathlen; { - int r, i; + int r, slot; struct vnode *vp; + struct vmnt *vmp; struct fproc *rfp; - char orig_path[PATH_MAX]; char canon_path[PATH_MAX]; + struct lookup resolve; - i = _ENDPOINT_P(ep); - if (pathlen < UNIX_PATH_MAX || pathlen >= PATH_MAX || i < 0 || i >= NR_PROCS) - return EINVAL; - - rfp = &(fproc[i]); - - memset(canon_path, '\0', PATH_MAX); + if (isokendpt(ep, &slot) != OK) return(EINVAL); + if (pathlen < UNIX_PATH_MAX || pathlen >= PATH_MAX) return(EINVAL); + rfp = &(fproc[slot]); r = sys_safecopyfrom(PFS_PROC_NR, io_gr, (vir_bytes) 0, - (vir_bytes) &user_fullpath, pathlen, D); - if (r != OK) { - return r; - } - user_fullpath[pathlen] = '\0'; + (vir_bytes) canon_path, pathlen, D); + if (r != OK) return(r); + canon_path[pathlen] = '\0'; - /* save path from pfs before permissions checking modifies it */ - memcpy(orig_path, user_fullpath, PATH_MAX); + /* Turn path into canonical path to the socket file */ + if ((r = canonical_path(canon_path, rfp)) != OK) + return(r); - /* get the canonical path to the socket file */ - r = canonical_path(orig_path, canon_path, rfp); - if (r != OK) { - return r; - } - - if (strlen(canon_path) >= pathlen) { - return ENAMETOOLONG; - } + if (strlen(canon_path) >= pathlen) return(ENAMETOOLONG); /* copy canon_path back to PFS */ - r = sys_safecopyto(PFS_PROC_NR, (cp_grant_id_t) io_gr, (vir_bytes) 0, - (vir_bytes) canon_path, strlen(canon_path)+1, - D); - if (r != OK) { - return r; - } + r = sys_safecopyto(PFS_PROC_NR, (cp_grant_id_t) io_gr, (vir_bytes) 0, + (vir_bytes) canon_path, pathlen, D); + if (r != OK) return(r); - /* reload user_fullpath for permissions checking */ - memcpy(user_fullpath, orig_path, PATH_MAX); - if ((vp = eat_path(PATH_NOFLAGS, rfp)) == NULL) { - return(err_code); - } + /* Now do permissions checking */ + lookup_init(&resolve, canon_path, PATH_NOFLAGS, &vmp, &vp); + resolve.l_vmnt_lock = VMNT_READ; + resolve.l_vnode_lock = VNODE_READ; + if ((vp = eat_path(&resolve, rfp)) == NULL) return(err_code); /* check permissions */ r = forbidden(rfp, vp, (R_BIT | W_BIT)); + unlock_vnode(vp); + unlock_vmnt(vmp); + put_vnode(vp); return(r); } @@ -536,5 +810,5 @@ int pathlen; PUBLIC int do_check_perms(void) { return check_perms(m_in.USER_ENDPT, (cp_grant_id_t) m_in.IO_GRANT, - m_in.COUNT); + (size_t) m_in.COUNT); } diff --git a/servers/avfs/path.h b/servers/vfs/path.h similarity index 100% rename from servers/avfs/path.h rename to servers/vfs/path.h diff --git a/servers/vfs/pipe.c b/servers/vfs/pipe.c index c5183b337..0a6d6f49d 100644 --- a/servers/vfs/pipe.c +++ b/servers/vfs/pipe.c @@ -27,6 +27,8 @@ #include #include "file.h" #include "fproc.h" +#include "scratchpad.h" +#include "dmap.h" #include "param.h" #include "select.h" #include @@ -46,21 +48,34 @@ PUBLIC int do_pipe() struct filp *fil_ptr0, *fil_ptr1; int fil_des[2]; /* reply goes here */ struct vnode *vp; + struct vmnt *vmp; struct node_details res; + /* Get a lock on PFS */ + if ((vmp = find_vmnt(PFS_PROC_NR)) == NULL) panic("PFS gone"); + if ((r = lock_vmnt(vmp, VMNT_WRITE)) != OK) return(r); + /* See if a free vnode is available */ - if ( (vp = get_free_vnode()) == NULL) return(err_code); + if ((vp = get_free_vnode()) == NULL) return(err_code); + lock_vnode(vp, VNODE_OPCL); /* Acquire two file descriptors. */ rfp = fp; - if ((r = get_fd(0, R_BIT, &fil_des[0], &fil_ptr0)) != OK) return(r); + if ((r = get_fd(0, R_BIT, &fil_des[0], &fil_ptr0)) != OK) { + unlock_vnode(vp); + unlock_vmnt(vmp); + return(r); + } rfp->fp_filp[fil_des[0]] = fil_ptr0; FD_SET(fil_des[0], &rfp->fp_filp_inuse); - fil_ptr0->filp_count = 1; + fil_ptr0->filp_count = 1; /* mark filp in use */ if ((r = get_fd(0, W_BIT, &fil_des[1], &fil_ptr1)) != OK) { rfp->fp_filp[fil_des[0]] = NULL; FD_CLR(fil_des[0], &rfp->fp_filp_inuse); - fil_ptr0->filp_count = 0; + fil_ptr0->filp_count = 0; /* mark filp free */ + unlock_filp(fil_ptr0); + unlock_vnode(vp); + unlock_vmnt(vmp); return(r); } rfp->fp_filp[fil_des[1]] = fil_ptr1; @@ -78,14 +93,18 @@ PUBLIC int do_pipe() rfp->fp_filp[fil_des[1]] = NULL; FD_CLR(fil_des[1], &rfp->fp_filp_inuse); fil_ptr1->filp_count = 0; + unlock_filp(fil_ptr1); + unlock_filp(fil_ptr0); + unlock_vnode(vp); + unlock_vmnt(vmp); return(r); } /* Fill in vnode */ vp->v_fs_e = res.fs_e; vp->v_mapfs_e = res.fs_e; - vp->v_inode_nr = res.inode_nr; - vp->v_mapinode_nr = res.inode_nr; + vp->v_inode_nr = res.inode_nr; + vp->v_mapinode_nr = res.inode_nr; vp->v_mode = res.fmode; vp->v_pipe = I_PIPE; vp->v_pipe_rd_pos= 0; @@ -94,7 +113,7 @@ PUBLIC int do_pipe() vp->v_mapfs_count = 1; vp->v_ref_count = 1; vp->v_size = 0; - vp->v_vmnt = NULL; + vp->v_vmnt = NULL; vp->v_dev = NO_DEV; /* Fill in filp objects */ @@ -107,6 +126,9 @@ PUBLIC int do_pipe() m_out.reply_i1 = fil_des[0]; m_out.reply_i2 = fil_des[1]; + unlock_filps(fil_ptr0, fil_ptr1); + unlock_vmnt(vmp); + return(OK); } @@ -114,28 +136,41 @@ PUBLIC int do_pipe() /*===========================================================================* * map_vnode * *===========================================================================*/ -PUBLIC int map_vnode(vp) +PUBLIC int map_vnode(vp, map_to_fs_e) struct vnode *vp; +endpoint_t map_to_fs_e; { int r; + struct vmnt *vmp; struct node_details res; - if(vp->v_mapfs_e != 0) return(OK); /* Already mapped; nothing to do. */ + if(vp->v_mapfs_e != NONE) return(OK); /* Already mapped; nothing to do. */ - /* Create a temporary mapping of this inode to PipeFS. Read and write - * operations on data will be handled by PipeFS. The rest by the 'original' + if ((vmp = find_vmnt(map_to_fs_e)) == NULL) + panic("Can't map to unknown endpoint"); + if ((r = lock_vmnt(vmp, VMNT_WRITE)) != OK) { + if (r == EBUSY) + vmp = NULL; /* Already locked, do not unlock */ + else + return(r); + + } + + /* Create a temporary mapping of this inode to another FS. Read and write + * operations on data will be handled by that FS. The rest by the 'original' * FS that holds the inode. */ - if ((r = req_newnode(PFS_PROC_NR, fp->fp_effuid, fp->fp_effgid, I_NAMED_PIPE, + if ((r = req_newnode(map_to_fs_e, fp->fp_effuid, fp->fp_effgid, I_NAMED_PIPE, vp->v_dev, &res)) == OK) { vp->v_mapfs_e = res.fs_e; - vp->v_mapinode_nr = res.inode_nr; + vp->v_mapinode_nr = res.inode_nr; vp->v_mapfs_count = 1; } + if (vmp) unlock_vmnt(vmp); + return(r); } - /*===========================================================================* * pipe_check * *===========================================================================*/ @@ -165,11 +200,11 @@ int notouch; /* check only */ /* Process is reading from an empty pipe. */ if (find_filp(vp, W_BIT) != NULL) { /* Writer exists */ - if (oflags & O_NONBLOCK) + if (oflags & O_NONBLOCK) r = EAGAIN; - else + else r = SUSPEND; - + /* If need be, activate sleeping writers. */ if (susp_count > 0) release(vp, WRITE, susp_count); @@ -250,37 +285,25 @@ PUBLIC void suspend(int why) */ #if DO_SANITYCHECKS - if (why == FP_BLOCKED_ON_PIPE) - panic("suspend: called for FP_BLOCKED_ON_PIPE"); - if(fp_is_blocked(fp)) panic("suspend: called for suspended process"); - + if(why == FP_BLOCKED_ON_NONE) panic("suspend: called for FP_BLOCKED_ON_NONE"); #endif - if (why == FP_BLOCKED_ON_POPEN) - /* #procs susp'ed on pipe*/ - susp_count++; + if (why == FP_BLOCKED_ON_POPEN || why == FP_BLOCKED_ON_PIPE) + /* #procs susp'ed on pipe*/ + susp_count++; fp->fp_blocked_on = why; assert(fp->fp_grant == GRANT_INVALID || !GRANT_VALID(fp->fp_grant)); - fp->fp_block_fd = m_in.fd; fp->fp_block_callnr = call_nr; - fp->fp_flags &= ~SUSP_REOPEN; /* Clear this flag. The caller + fp->fp_flags &= ~FP_SUSP_REOPEN; /* Clear this flag. The caller * can set it when needed. */ - if (why == FP_BLOCKED_ON_LOCK) { - fp->fp_buffer = (char *) m_in.name1; /* third arg to fcntl() */ - fp->fp_nbytes = m_in.request; /* second arg to fcntl() */ - } else { - fp->fp_buffer = m_in.buffer; /* for reads and writes */ - fp->fp_nbytes = m_in.nbytes; - } } - /*===========================================================================* * wait_for * *===========================================================================*/ @@ -296,30 +319,23 @@ PUBLIC void wait_for(endpoint_t who) /*===========================================================================* * pipe_suspend * *===========================================================================*/ -PUBLIC void pipe_suspend(rw_flag, fd_nr, buf, size) -int rw_flag; -int fd_nr; +PUBLIC void pipe_suspend(filp, buf, size) +struct filp *filp; char *buf; size_t size; { /* Take measures to suspend the processing of the present system call. * Store the parameters to be used upon resuming in the process table. - * (Actually they are not used when a process is waiting for an I/O device, - * but they are needed for pipes, and it is not worth making the distinction.) - * The SUSPEND pseudo error should be returned after calling suspend(). */ #if DO_SANITYCHECKS if(fp_is_blocked(fp)) panic("pipe_suspend: called for suspended process"); #endif - susp_count++; /* #procs susp'ed on pipe*/ - fp->fp_blocked_on = FP_BLOCKED_ON_PIPE; - assert(!GRANT_VALID(fp->fp_grant)); - fp->fp_block_fd = fd_nr; - fp->fp_block_callnr = ((rw_flag == READING) ? READ : WRITE); - fp->fp_buffer = buf; - fp->fp_nbytes = size; + scratch(fp).file.filp = filp; + scratch(fp).io.io_buffer = buf; + scratch(fp).io.io_nbytes = size; + suspend(FP_BLOCKED_ON_PIPE); } @@ -334,8 +350,8 @@ PUBLIC void unsuspend_by_endpt(endpoint_t proc_e) struct fproc *rp; for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) { - if (rp->fp_pid == PID_FREE) continue; - if (rp->fp_blocked_on == FP_BLOCKED_ON_OTHER && rp->fp_task == proc_e) + if (rp->fp_pid == PID_FREE) continue; + if (rp->fp_blocked_on == FP_BLOCKED_ON_OTHER && rp->fp_task == proc_e) revive(rp->fp_endpoint, EAGAIN); } @@ -349,42 +365,63 @@ PUBLIC void unsuspend_by_endpt(endpoint_t proc_e) /*===========================================================================* * release * *===========================================================================*/ -PUBLIC void release(vp, call_nr, count) +PUBLIC void release(vp, op, count) register struct vnode *vp; /* inode of pipe */ -int call_nr; /* READ, WRITE, OPEN or CREAT */ +int op; /* READ, WRITE, OPEN or CREAT */ int count; /* max number of processes to release */ { -/* Check to see if any process is hanging on the pipe whose inode is in 'ip'. - * If one is, and it was trying to perform the call indicated by 'call_nr', - * release it. +/* Check to see if any process is hanging on vnode 'vp'. If one is, and it + * was trying to perform the call indicated by 'call_nr', release it. */ register struct fproc *rp; struct filp *f; + int selop; /* Trying to perform the call also includes SELECTing on it with that * operation. */ - if (call_nr == READ || call_nr == WRITE) { - int op; - if (call_nr == READ) - op = SEL_RD; - else - op = SEL_WR; - for(f = &filp[0]; f < &filp[NR_FILPS]; f++) { - if (f->filp_count < 1 || !(f->filp_pipe_select_ops & op) || - f->filp_vno != vp) - continue; - select_callback(f, op); - f->filp_pipe_select_ops &= ~op; - } + if (op == READ || op == WRITE) { + if (op == READ) + selop = SEL_RD; + else + selop = SEL_WR; + + for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { + if (f->filp_count < 1 || !(f->filp_pipe_select_ops & selop) || + f->filp_vno != vp) + continue; + select_callback(f, selop); + f->filp_pipe_select_ops &= ~selop; + } } /* Search the proc table. */ for (rp = &fproc[0]; rp < &fproc[NR_PROCS] && count > 0; rp++) { if (rp->fp_pid != PID_FREE && fp_is_blocked(rp) && - rp->fp_revived == NOT_REVIVING && rp->fp_block_callnr == call_nr && - rp->fp_filp[rp->fp_block_fd]->filp_vno == vp) { + !(rp->fp_flags & FP_REVIVED) && rp->fp_block_callnr == op) { + /* Find the vnode. Depending on the reason the process was + * suspended, there are different ways of finding it. + */ + + if (rp->fp_blocked_on == FP_BLOCKED_ON_POPEN || + rp->fp_blocked_on == FP_BLOCKED_ON_DOPEN || + rp->fp_blocked_on == FP_BLOCKED_ON_LOCK || + rp->fp_blocked_on == FP_BLOCKED_ON_OTHER) { + if (!FD_ISSET(scratch(rp).file.fd_nr, + &rp->fp_filp_inuse)) + continue; + if (rp->fp_filp[scratch(rp).file.fd_nr]->filp_vno != vp) + continue; + } else if (rp->fp_blocked_on == FP_BLOCKED_ON_PIPE) { + if (scratch(rp).file.filp == NULL) + continue; + if (scratch(rp).file.filp->filp_vno != vp) + continue; + } else + continue; + + /* We found the vnode. Revive process. */ revive(rp->fp_endpoint, 0); susp_count--; /* keep track of who is suspended */ if(susp_count < 0) @@ -407,61 +444,66 @@ int returned; /* if hanging on task, how many bytes read */ */ register struct fproc *rfp; int blocked_on; - int fd_nr, proc_nr; + int fd_nr, slot; struct filp *fil_ptr; - if(isokendpt(proc_nr_e, &proc_nr) != OK) return; + if (proc_nr_e == NONE || isokendpt(proc_nr_e, &slot) != OK) return; - rfp = &fproc[proc_nr]; - if (!fp_is_blocked(rfp) || rfp->fp_revived == REVIVING) return; + rfp = &fproc[slot]; + if (!fp_is_blocked(rfp) || (rfp->fp_flags & FP_REVIVED)) return; /* The 'reviving' flag only applies to pipes. Processes waiting for TTY get * a message right away. The revival process is different for TTY and pipes. * For select and TTY revival, the work is already done, for pipes it is not: - * the proc must be restarted so it can try again. + * the proc must be restarted so it can try again. */ blocked_on = rfp->fp_blocked_on; + fd_nr = scratch(rfp).file.fd_nr; if (blocked_on == FP_BLOCKED_ON_PIPE || blocked_on == FP_BLOCKED_ON_LOCK) { /* Revive a process suspended on a pipe or lock. */ - rfp->fp_revived = REVIVING; + rfp->fp_flags |= FP_REVIVED; reviving++; /* process was waiting on pipe or lock */ } else if (blocked_on == FP_BLOCKED_ON_DOPEN) { rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; - fd_nr = rfp->fp_block_fd; + scratch(rfp).file.fd_nr = 0; if (returned < 0) { fil_ptr = rfp->fp_filp[fd_nr]; + lock_filp(fil_ptr, VNODE_OPCL); rfp->fp_filp[fd_nr] = NULL; FD_CLR(fd_nr, &rfp->fp_filp_inuse); if (fil_ptr->filp_count != 1) { - panic("revive: bad count in filp: %d", + panic("VFS: revive: bad count in filp: %d", fil_ptr->filp_count); } fil_ptr->filp_count = 0; - put_vnode(fil_ptr->filp_vno); + unlock_filp(fil_ptr); + put_vnode(fil_ptr->filp_vno); fil_ptr->filp_vno = NULL; reply(proc_nr_e, returned); - } else + } else { reply(proc_nr_e, fd_nr); + } } else { rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; + scratch(rfp).file.fd_nr = 0; if (blocked_on == FP_BLOCKED_ON_POPEN) { /* process blocked in open or create */ - reply(proc_nr_e, rfp->fp_block_fd); + reply(proc_nr_e, fd_nr); } else if (blocked_on == FP_BLOCKED_ON_SELECT) { reply(proc_nr_e, returned); } else { - /* Revive a process suspended on TTY or other device. + /* Revive a process suspended on TTY or other device. * Pretend it wants only what there is. */ - rfp->fp_nbytes = returned; + scratch(rfp).io.io_nbytes = returned; /* If a grant has been issued by FS for this I/O, revoke * it again now that I/O is done. */ - if(GRANT_VALID(rfp->fp_grant)) { + if (GRANT_VALID(rfp->fp_grant)) { if(cpf_revoke(rfp->fp_grant)) { - panic("FS: revoke failed for grant: %d", + panic("VFS: revoke failed for grant: %d", rfp->fp_grant); - } + } rfp->fp_grant = GRANT_INVALID; } reply(proc_nr_e, returned); /* unblock the process */ @@ -473,31 +515,30 @@ int returned; /* if hanging on task, how many bytes read */ /*===========================================================================* * unpause * *===========================================================================*/ -PUBLIC void unpause(proc_nr_e) -int proc_nr_e; +PUBLIC void unpause(endpoint_t proc_e) { /* A signal has been sent to a user who is paused on the file system. * Abort the system call with the EINTR error message. */ - register struct fproc *rfp; - int proc_nr_p, blocked_on, fild, status = EINTR; + register struct fproc *rfp, *org_fp; + int slot, blocked_on, fild, status = EINTR, major_dev, minor_dev; struct filp *f; dev_t dev; message mess; int wasreviving = 0; - if(isokendpt(proc_nr_e, &proc_nr_p) != OK) { - printf("VFS: ignoring unpause for bogus endpoint %d\n", proc_nr_e); + if (isokendpt(proc_e, &slot) != OK) { + printf("VFS: ignoring unpause for bogus endpoint %d\n", proc_e); return; } - rfp = &fproc[proc_nr_p]; + rfp = &fproc[slot]; if (!fp_is_blocked(rfp)) return; blocked_on = rfp->fp_blocked_on; - if (rfp->fp_revived == REVIVING) { - rfp->fp_revived = NOT_REVIVING; + if (rfp->fp_flags & FP_REVIVED) { + rfp->fp_flags &= ~FP_REVIVED; reviving--; wasreviving = 1; } @@ -510,126 +551,69 @@ int proc_nr_e; break; case FP_BLOCKED_ON_SELECT:/* process blocking on select() */ - select_forget(proc_nr_e); + select_forget(proc_e); break; - case FP_BLOCKED_ON_POPEN: /* process trying to open a fifo */ + case FP_BLOCKED_ON_POPEN: /* process trying to open a fifo */ break; case FP_BLOCKED_ON_DOPEN:/* process trying to open a device */ /* Don't cancel OPEN. Just wait until the open completes. */ - return; + return; - case FP_BLOCKED_ON_OTHER: /* process trying to do device I/O (e.g. tty)*/ - if (rfp->fp_flags & SUSP_REOPEN) { + case FP_BLOCKED_ON_OTHER:/* process trying to do device I/O (e.g. tty)*/ + if (rfp->fp_flags & FP_SUSP_REOPEN) { /* Process is suspended while waiting for a reopen. * Just reply EINTR. */ - rfp->fp_flags &= ~SUSP_REOPEN; + rfp->fp_flags &= ~FP_SUSP_REOPEN; status = EINTR; break; } - - fild = rfp->fp_block_fd; + + fild = scratch(rfp).file.fd_nr; if (fild < 0 || fild >= OPEN_MAX) - panic("unpause err 2"); + panic("file descriptor out-of-range"); f = rfp->fp_filp[fild]; dev = (dev_t) f->filp_vno->v_sdev; /* device hung on */ - mess.TTY_LINE = (dev >> MINOR) & BYTE; + major_dev = major(dev); + minor_dev = minor(dev); + mess.TTY_LINE = minor_dev; mess.USER_ENDPT = rfp->fp_ioproc; mess.IO_GRANT = (char *) rfp->fp_grant; /* Tell kernel R or W. Mode is from current call, not open. */ mess.COUNT = rfp->fp_block_callnr == READ ? R_BIT : W_BIT; mess.m_type = CANCEL; + + org_fp = fp; fp = rfp; /* hack - ctty_io uses fp */ - (*dmap[(dev >> MAJOR) & BYTE].dmap_io)(rfp->fp_task, &mess); + (*dmap[major_dev].dmap_io)(rfp->fp_task, &mess); + fp = org_fp; status = mess.REP_STATUS; if (status == SUSPEND) return; /* Process will be revived at a * later time. */ - if(status == EAGAIN) status = EINTR; - if(GRANT_VALID(rfp->fp_grant)) { - if(cpf_revoke(rfp->fp_grant)) { - panic("FS: revoke failed for grant (cancel): %d", - rfp->fp_grant); - } + if (status == EAGAIN) status = EINTR; + if (GRANT_VALID(rfp->fp_grant)) { + (void) cpf_revoke(rfp->fp_grant); rfp->fp_grant = GRANT_INVALID; } break; default : - panic("FS: unknown value: %d", blocked_on); + panic("VFS: unknown block reason: %d", blocked_on); } rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; - if ((blocked_on == FP_BLOCKED_ON_PIPE || - blocked_on == FP_BLOCKED_ON_POPEN) && - !wasreviving) { + if ((blocked_on == FP_BLOCKED_ON_PIPE || blocked_on == FP_BLOCKED_ON_POPEN)&& + !wasreviving) { susp_count--; } - reply(proc_nr_e, status); /* signal interrupted call */ -} - - -/*===========================================================================* - * select_request_pipe * - *===========================================================================*/ -PUBLIC int select_request_pipe(struct filp *f, int *ops, int block) -{ - int orig_ops, r = 0, err; - orig_ops = *ops; - if ((*ops & (SEL_RD|SEL_ERR))) { - if ((err = pipe_check(f->filp_vno, READING, 0, - 1, f->filp_pos, 1)) != SUSPEND) - r |= SEL_RD; - if (err < 0 && err != SUSPEND) - r |= SEL_ERR; - if(err == SUSPEND && f->filp_mode & W_BIT) { - /* A "meaningless" read select, therefore ready - for reading and no error set. */ - r |= SEL_RD; - r &= ~SEL_ERR; - } - } - - if ((*ops & (SEL_WR|SEL_ERR))) { - if ((err = pipe_check(f->filp_vno, WRITING, 0, - 1, f->filp_pos, 1)) != SUSPEND) - r |= SEL_WR; - if (err < 0 && err != SUSPEND) - r |= SEL_ERR; - if(err == SUSPEND && f->filp_mode & R_BIT) { - /* A "meaningless" write select, therefore ready - for reading and no error set. */ - r |= SEL_WR; - r &= ~SEL_ERR; - } - } - - /* Some options we collected might not be requested. */ - *ops = r & orig_ops; - - if (!*ops && block) { - f->filp_pipe_select_ops |= orig_ops; - } - - return(SEL_OK); -} - - -/*===========================================================================* - * select_match_pipe * - *===========================================================================*/ -PUBLIC int select_match_pipe(struct filp *f) -{ - /* recognize either pipe or named pipe (FIFO) */ - if (f && f->filp_vno && (f->filp_vno->v_mode & I_NAMED_PIPE)) - return 1; - return 0; + reply(proc_e, status); /* signal interrupted call */ } #if DO_SANITYCHECKS @@ -638,24 +622,24 @@ PUBLIC int select_match_pipe(struct filp *f) *===========================================================================*/ PUBLIC int check_pipe(void) { - struct fproc *rfp; - int mycount = 0; - for (rfp=&fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - if (rfp->fp_pid == PID_FREE) - continue; - if(rfp->fp_revived != REVIVING && - (rfp->fp_blocked_on == FP_BLOCKED_ON_PIPE || - rfp->fp_blocked_on == FP_BLOCKED_ON_POPEN)) { - mycount++; - } - } - - if(mycount != susp_count) { - printf("check_pipe: mycount %d susp_count %d\n", - mycount, susp_count); - return 0; +/* Integrity check; verify that susp_count equals what the fproc table thinks + * is suspended on a pipe */ + struct fproc *rfp; + int count = 0; + for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { + if (rfp->fp_pid == PID_FREE) continue; + if ( !(rfp->fp_flags & FP_REVIVED) && + (rfp->fp_blocked_on == FP_BLOCKED_ON_PIPE || + rfp->fp_blocked_on == FP_BLOCKED_ON_POPEN)) { + count++; } + } - return 1; + if (count != susp_count) { + printf("check_pipe: count %d susp_count %d\n", count, susp_count); + return(0); + } + + return(l); } #endif diff --git a/servers/vfs/protect.c b/servers/vfs/protect.c index 958cfe8ac..04325c614 100644 --- a/servers/vfs/protect.c +++ b/servers/vfs/protect.c @@ -13,6 +13,7 @@ #include #include "file.h" #include "fproc.h" +#include "path.h" #include "param.h" #include #include "vnode.h" @@ -27,19 +28,30 @@ PUBLIC int do_chmod() struct filp *flp; struct vnode *vp; + struct vmnt *vmp; int r; mode_t new_mode; - + char fullpath[PATH_MAX]; + struct lookup resolve; + + flp = NULL; + + lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); + resolve.l_vmnt_lock = VMNT_WRITE; + resolve.l_vnode_lock = VNODE_WRITE; + if (call_nr == CHMOD) { - /* Temporarily open the file */ - if(fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); + /* Temporarily open the file */ + if (fetch_name(m_in.name, m_in.name_length, M3, fullpath) != OK) + return(err_code); + if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); } else { /* call_nr == FCHMOD */ /* File is already opened; get a pointer to vnode from filp. */ - if (!(flp = get_filp(m_in.fd))) return(err_code); + if ((flp = get_filp(m_in.fd, VNODE_WRITE)) == NULL) + return(err_code); vp = flp->filp_vno; dup_vnode(vp); - } + } /* Only the owner or the super_user may change the mode of a file. * No one may change the mode of a file on a read-only file system. @@ -49,21 +61,26 @@ PUBLIC int do_chmod() else r = read_only(vp); - /* If error, return inode. */ - if (r != OK) { - put_vnode(vp); - return(r); + if (r == OK) { + /* Now make the change. Clear setgid bit if file is not in caller's + * group */ + if (fp->fp_effuid != SU_UID && vp->v_gid != fp->fp_effgid) + m_in.mode &= ~I_SET_GID_BIT; + + r = req_chmod(vp->v_fs_e, vp->v_inode_nr, m_in.mode, &new_mode); + if (r == OK) + vp->v_mode = new_mode; } - /* Now make the change. Clear setgid bit if file is not in caller's grp */ - if (fp->fp_effuid != SU_UID && vp->v_gid != fp->fp_effgid) - m_in.mode &= ~I_SET_GID_BIT; - - if ((r = req_chmod(vp->v_fs_e, vp->v_inode_nr, m_in.mode, &new_mode)) == OK) - vp->v_mode = new_mode; + if (call_nr == CHMOD) { + unlock_vnode(vp); + unlock_vmnt(vmp); + } else { /* FCHMOD */ + unlock_filp(flp); + } put_vnode(vp); - return(OK); + return(r); } @@ -72,23 +89,35 @@ PUBLIC int do_chmod() *===========================================================================*/ PUBLIC int do_chown() { -/* Perform the chmod(name, mode) and fchmod(fd, mode) system calls. */ +/* Perform the chown(path, owner, group) and fchmod(fd, owner, group) system + * calls. */ struct filp *flp; struct vnode *vp; + struct vmnt *vmp; int r; uid_t uid; gid_t gid; mode_t new_mode; - + char fullpath[PATH_MAX]; + struct lookup resolve; + + flp = NULL; + + lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); + resolve.l_vmnt_lock = VMNT_WRITE; + resolve.l_vnode_lock = VNODE_WRITE; + if (call_nr == CHOWN) { /* Temporarily open the file. */ - if(fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); + if (fetch_name(m_in.name1, m_in.name1_length, M1, fullpath) != OK) + return(err_code); + if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); } else { /* call_nr == FCHOWN */ - /* File is already opened; get a pointer to the vnode from filp. */ - if (!(flp = get_filp(m_in.fd))) return(err_code); - vp = flp->filp_vno; - dup_vnode(vp); + /* File is already opened; get a pointer to the vnode from filp. */ + if ((flp = get_filp(m_in.fd, VNODE_WRITE)) == NULL) + return(err_code); + vp = flp->filp_vno; + dup_vnode(vp); } r = read_only(vp); @@ -98,7 +127,7 @@ PUBLIC int do_chown() a regular user. */ if (fp->fp_effuid != SU_UID) { /* Regular users can only change groups of their own files. */ - if (vp->v_uid != fp->fp_effuid) r = EPERM; + if (vp->v_uid != fp->fp_effuid) r = EPERM; if (vp->v_uid != m_in.owner) r = EPERM; /* no giving away */ if (fp->fp_effgid != m_in.group) r = EPERM; } @@ -113,17 +142,23 @@ PUBLIC int do_chown() r = EINVAL; else if ((r = req_chown(vp->v_fs_e, vp->v_inode_nr, uid, gid, &new_mode)) == OK) { - vp->v_uid = uid; + vp->v_uid = uid; vp->v_gid = gid; vp->v_mode = new_mode; } } + if (call_nr == CHOWN) { + unlock_vnode(vp); + unlock_vmnt(vmp); + } else { /* FCHOWN */ + unlock_filp(flp); + } + put_vnode(vp); return(r); } - /*===========================================================================* * do_umask * *===========================================================================*/ @@ -146,16 +181,28 @@ PUBLIC int do_access() /* Perform the access(name, mode) system call. */ int r; struct vnode *vp; - + struct vmnt *vmp; + char fullpath[PATH_MAX]; + struct lookup resolve; + + lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); + resolve.l_vmnt_lock = VMNT_READ; + resolve.l_vnode_lock = VNODE_READ; + /* First check to see if the mode is correct. */ if ( (m_in.mode & ~(R_OK | W_OK | X_OK)) != 0 && m_in.mode != F_OK) return(EINVAL); /* Temporarily open the file. */ - if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); + if (fetch_name(m_in.name, m_in.name_length, M3, fullpath) != OK) + return(err_code); + if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); r = forbidden(fp, vp, m_in.mode); + + unlock_vnode(vp); + unlock_vmnt(vmp); + put_vnode(vp); return(r); } @@ -211,7 +258,7 @@ PUBLIC int forbidden(struct fproc *rfp, struct vnode *vp, mode_t access_desired) */ if (r == OK) if (access_desired & W_BIT) - r = read_only(vp); + r = read_only(vp); return(r); } @@ -225,10 +272,5 @@ struct vnode *vp; /* ptr to inode whose file sys is to be cked */ /* Check to see if the file system on which the inode 'ip' resides is mounted * read only. If so, return EROFS, else return OK. */ - register struct vmnt *mp; - - mp = vp->v_vmnt; - return(mp->m_flags ? EROFS : OK); + return((vp->v_vmnt->m_flags & VMNT_READONLY) ? EROFS : OK); } - - diff --git a/servers/vfs/proto.h b/servers/vfs/proto.h index 3c933df04..432ef3a52 100644 --- a/servers/vfs/proto.h +++ b/servers/vfs/proto.h @@ -1,32 +1,46 @@ +#ifndef __VFS_PROTO_H__ +#define __VFS_PROTO_H__ + /* Function prototypes. */ #include "timers.h" #include "request.h" +#include "tll.h" +#include "threads.h" #include /* Structs used in prototypes must be declared as such first. */ -struct filp; +struct filp; struct fproc; struct vmnt; struct vnode; +struct lookup; +struct worker_thread; +struct job; typedef struct filp * filp_id_t; +/* comm.c */ +_PROTOTYPE(void fs_cancel, (struct vmnt *vmp) ); +_PROTOTYPE(int fs_sendrec, (endpoint_t fs_e, message *reqm) ); +_PROTOTYPE(void fs_sendmore, (struct vmnt *vmp) ); +_PROTOTYPE(void send_work, (void) ); + /* device.c */ -_PROTOTYPE( int dev_open, (dev_t dev, int proc, int flags) ); +_PROTOTYPE( int dev_open, (dev_t dev, endpoint_t proc_e, int flags) ); _PROTOTYPE( int dev_reopen, (dev_t dev, int filp_no, int flags) ); _PROTOTYPE( int dev_close, (dev_t dev, int filp_no) ); -_PROTOTYPE( int bdev_open, (dev_t dev, int flags) ); +_PROTOTYPE( int bdev_open, (dev_t dev, int access) ); _PROTOTYPE( int bdev_close, (dev_t dev) ); -_PROTOTYPE( int dev_io, (int op, dev_t dev, int proc, void *buf, - u64_t pos, int bytes, int flags, int suspend_reopen) ); -_PROTOTYPE( int gen_opcl, (int op, dev_t dev, int proc, int flags) ); -_PROTOTYPE( int gen_io, (int task_nr, message *mess_ptr) ); +_PROTOTYPE( int dev_io, (int op, dev_t dev, endpoint_t proc_e, void *buf, + u64_t pos, size_t bytes, int flags, int suspend_reopen) ); +_PROTOTYPE( int gen_opcl, (int op, dev_t dev, endpoint_t task_nr, int flags)); +_PROTOTYPE( int gen_io, (endpoint_t driver_e, message *mess_ptr) ); _PROTOTYPE( int asyn_io, (int task_nr, message *mess_ptr) ); _PROTOTYPE( int no_dev, (int op, dev_t dev, int proc, int flags) ); _PROTOTYPE( int no_dev_io, (int, message *) ); -_PROTOTYPE( int tty_opcl, (int op, dev_t dev, int proc, int flags) ); -_PROTOTYPE( int ctty_opcl, (int op, dev_t dev, int proc, int flags) ); +_PROTOTYPE( int tty_opcl, (int op, dev_t dev, endpoint_t proc, int flags)); +_PROTOTYPE( int ctty_opcl, (int op, dev_t dev, endpoint_t proc, int flags)); _PROTOTYPE( int clone_opcl, (int op, dev_t dev, int proc, int flags) ); _PROTOTYPE( int ctty_io, (int task_nr, message *mess_ptr) ); _PROTOTYPE( int do_ioctl, (void) ); @@ -34,33 +48,53 @@ _PROTOTYPE( void pm_setsid, (int proc_e) ); _PROTOTYPE( void dev_status, (message *) ); _PROTOTYPE( void bdev_up, (int major) ); _PROTOTYPE( void cdev_up, (int major) ); -_PROTOTYPE( endpoint_t suspended_ep, (endpoint_t driver, - cp_grant_id_t g) ); +_PROTOTYPE( endpoint_t find_suspended_ep, (endpoint_t driver, + cp_grant_id_t g) ); _PROTOTYPE( void reopen_reply, (void) ); +_PROTOTYPE( void open_reply, (void) ); /* dmap.c */ -_PROTOTYPE( void build_dmap, (void) ); _PROTOTYPE( int do_mapdriver, (void) ); +_PROTOTYPE( void init_dmap, (void) ); _PROTOTYPE( int dmap_driver_match, (endpoint_t proc, int major) ); _PROTOTYPE( void dmap_endpt_up, (int proc_nr, int is_blk) ); _PROTOTYPE( void dmap_unmap_by_endpt, (int proc_nr) ); _PROTOTYPE( struct dmap *get_dmap, (endpoint_t proc_e) ); +_PROTOTYPE( int do_mapdriver, (void) ); +_PROTOTYPE( int map_service, (struct rprocpub *rpub) ); +_PROTOTYPE( void dmap_unmap_by_endpt, (int proc_nr) ); +_PROTOTYPE( struct dmap *get_dmap, (endpoint_t proc_e) ); _PROTOTYPE( int map_driver, (const char *label, int major, endpoint_t proc_nr, int dev_style, int flags) ); _PROTOTYPE( int map_service, (struct rprocpub *rpub) ); +/* elf_core_dump.c */ +_PROTOTYPE( void write_elf_core_file, (struct filp *f, int csig, + char *exe_name) ); + /* exec.c */ _PROTOTYPE( int pm_exec, (int proc_e, char *path, vir_bytes path_len, char *frame, vir_bytes frame_len, vir_bytes *pc)); +#define check_bsf_lock() do { \ + assert(mutex_trylock(&bsf_lock) == 0); \ + unlock_bsf(); \ + } while(0) /* filedes.c */ +_PROTOTYPE( void check_filp_locks, (void) ); +_PROTOTYPE( void check_filp_locks_by_me, (void) ); +_PROTOTYPE( void init_filps, (void) ); _PROTOTYPE( struct filp *find_filp, (struct vnode *vp, mode_t bits) ); -_PROTOTYPE( int get_fd, (int start, mode_t bits, int *k, +_PROTOTYPE( int get_fd, (int start, mode_t bits, int *k, struct filp **fpt) ); -_PROTOTYPE( struct filp *get_filp, (int fild) ); -_PROTOTYPE( struct filp *get_filp2, (struct fproc *rfp, int fild) ); -_PROTOTYPE( int invalidate, (struct filp *) ); -_PROTOTYPE( filp_id_t verify_fd, (endpoint_t ep, int fd) ); +_PROTOTYPE( struct filp *get_filp, (int fild, tll_access_t locktype) ); +_PROTOTYPE( struct filp *get_filp2, (struct fproc *rfp, int fild, + tll_access_t locktype) ); +_PROTOTYPE( void lock_filp, (struct filp *filp, tll_access_t locktype) ); +_PROTOTYPE( void unlock_filp, (struct filp *filp) ); +_PROTOTYPE( void unlock_filps, (struct filp *filp1, struct filp *filp2) ); +_PROTOTYPE( int invalidate_filp, (struct filp *) ); +_PROTOTYPE( void invalidate_filp_by_endpt, (endpoint_t proc_e) ); _PROTOTYPE( int do_verify_fd, (void) ); _PROTOTYPE( int set_filp, (filp_id_t sfilp) ); _PROTOTYPE( int do_set_filp, (void) ); @@ -74,7 +108,6 @@ _PROTOTYPE( void close_filp, (struct filp *fp) ); /* fscall.c */ _PROTOTYPE( void nested_fs_call, (message *m) ); -_PROTOTYPE( void nested_dev_call, (message *m) ); /* link.c */ _PROTOTYPE( int do_link, (void) ); @@ -93,6 +126,9 @@ _PROTOTYPE( void lock_revive, (void) ); /* main.c */ _PROTOTYPE( int main, (void) ); _PROTOTYPE( void reply, (int whom, int result) ); +_PROTOTYPE( void lock_proc, (struct fproc *rfp, int force_lock) ); +_PROTOTYPE( void unlock_proc, (struct fproc *rfp) ); +_PROTOTYPE( void *do_dummy, (void *arg) ); /* misc.c */ _PROTOTYPE( int do_dup, (void) ); @@ -107,54 +143,62 @@ _PROTOTYPE( int do_fsync, (void) ); _PROTOTYPE( void pm_reboot, (void) ); _PROTOTYPE( int do_svrctl, (void) ); _PROTOTYPE( int do_getsysinfo, (void) ); -_PROTOTYPE( int pm_dumpcore, (int proc_e, int sig, char *exe_name) ); +_PROTOTYPE( int pm_dumpcore, (endpoint_t proc_e, int sig, + vir_bytes exe_name) ); _PROTOTYPE( void ds_event, (void) ); /* mount.c */ -_PROTOTYPE( int do_fslogin, (void) ); +_PROTOTYPE( int do_fsready, (void) ); _PROTOTYPE( int do_mount, (void) ); _PROTOTYPE( int do_umount, (void) ); +_PROTOTYPE( int is_nonedev, (dev_t dev) ); +_PROTOTYPE( void mount_pfs, (void) ); +_PROTOTYPE( int mount_fs, (dev_t dev, char fullpath[PATH_MAX+1], + endpoint_t fs_e, int rdonly, + char mount_label[LABEL_MAX]) ); _PROTOTYPE( int unmount, (dev_t dev, char *label) ); +_PROTOTYPE( void unmount_all, (void) ); /* open.c */ _PROTOTYPE( int do_close, (void) ); _PROTOTYPE( int close_fd, (struct fproc *rfp, int fd_nr) ); _PROTOTYPE( void close_reply, (void) ); +_PROTOTYPE( int common_open, (char path[PATH_MAX], int oflags, + mode_t omode) ); _PROTOTYPE( int do_creat, (void) ); _PROTOTYPE( int do_lseek, (void) ); _PROTOTYPE( int do_llseek, (void) ); _PROTOTYPE( int do_mknod, (void) ); _PROTOTYPE( int do_mkdir, (void) ); _PROTOTYPE( int do_open, (void) ); -_PROTOTYPE( int common_open, (register int oflags, mode_t omode) ); _PROTOTYPE( int do_slink, (void) ); _PROTOTYPE( int do_vm_open, (void) ); _PROTOTYPE( int do_vm_close, (void) ); /* path.c */ -_PROTOTYPE( struct vnode *advance, (struct vnode *dirp, int flags, - struct fproc *rfp) ); -_PROTOTYPE( struct vnode *eat_path, (int flags, struct fproc *rfp) ); -_PROTOTYPE( struct vnode *last_dir, (struct fproc *rfp) ); +_PROTOTYPE( struct vnode *advance, (struct vnode *dirp, struct lookup *resolve, + struct fproc *rfp) ); +_PROTOTYPE( struct vnode *eat_path, (struct lookup *resolve, + struct fproc *rfp) ); +_PROTOTYPE( struct vnode *last_dir, (struct lookup *resolve, + struct fproc *rfp) ); +_PROTOTYPE( void lookup_init, (struct lookup *resolve, char *path, int flags, + struct vmnt **vmp, struct vnode **vp) ); _PROTOTYPE( int get_name, (struct vnode *dirp, struct vnode *entry, char *_name) ); -_PROTOTYPE( int canonical_path, (char *orig_path, char *canon_path, - struct fproc *rfp) ); -_PROTOTYPE( int check_perms, (endpoint_t ep, cp_grant_id_t gid, - int strlen) ); +_PROTOTYPE( int canonical_path, (char *orig_path, struct fproc *rfp) ); _PROTOTYPE( int do_check_perms, (void) ); /* pipe.c */ _PROTOTYPE( int do_pipe, (void) ); -_PROTOTYPE( int map_vnode, (struct vnode *vp) ); +_PROTOTYPE( int map_vnode, (struct vnode *vp, endpoint_t fs_e) ); _PROTOTYPE( void unpause, (int proc_nr_e) ); _PROTOTYPE( int pipe_check, (struct vnode *vp, int rw_flag, int oflags, int bytes, u64_t position, int notouch) ); _PROTOTYPE( void release, (struct vnode *vp, int call_nr, int count) ); _PROTOTYPE( void revive, (int proc_nr, int bytes) ); _PROTOTYPE( void suspend, (int task) ); -_PROTOTYPE( void pipe_suspend, (int rw_flag, int fd_nr, char *buf, - size_t size) ); +_PROTOTYPE( void pipe_suspend, (struct filp *rfilp, char *buf, size_t size)); _PROTOTYPE( void unsuspend_by_endpt, (endpoint_t) ); _PROTOTYPE( void wait_for, (endpoint_t) ); #if DO_SANITYCHECKS @@ -173,9 +217,13 @@ _PROTOTYPE( int read_only, (struct vnode *vp) ); /* read.c */ _PROTOTYPE( int do_read, (void) ); _PROTOTYPE( int do_getdents, (void) ); -_PROTOTYPE( int read_write, (int rw_flag) ); -_PROTOTYPE( int rw_pipe, (int rw_flag, endpoint_t usr, - int fd_nr, struct filp *f, char *buf, size_t req_size) ); +_PROTOTYPE( void lock_bsf, (void) ); +_PROTOTYPE( void unlock_bsf, (void) ); +_PROTOTYPE( int do_read_write, (int rw_flag) ); +_PROTOTYPE( int read_write, (int rw_flag, struct filp *f, char *buffer, + size_t nbytes, endpoint_t for_e) ); +_PROTOTYPE( int rw_pipe, (int rw_flag, endpoint_t usr, struct filp *f, + char *buf, size_t req_size) ); /* request.c */ _PROTOTYPE( int req_breadwrite, (endpoint_t fs_e, endpoint_t user_e, @@ -187,7 +235,7 @@ _PROTOTYPE( int req_chmod, (int fs_e, ino_t inode_nr, mode_t rmode, _PROTOTYPE( int req_chown, (endpoint_t fs_e, ino_t inode_nr, uid_t newuid, gid_t newgid, mode_t *new_modep) ); _PROTOTYPE( int req_create, (int fs_e, ino_t inode_nr, int omode, - uid_t uid, gid_t gid, char *path, node_details_t *res) ); + uid_t uid, gid_t gid, char *path, node_details_t *res) ); _PROTOTYPE( int req_flush, (endpoint_t fs_e, dev_t dev) ); _PROTOTYPE( int req_fstatfs, (int fs_e, int who_e, char *buf) ); _PROTOTYPE( int req_statvfs, (int fs_e, int who_e, char *buf) ); @@ -200,7 +248,7 @@ _PROTOTYPE( int req_inhibread, (endpoint_t fs_e, ino_t inode_nr) ); _PROTOTYPE( int req_link, (endpoint_t fs_e, ino_t link_parent, char *lastc, ino_t linked_file) ); _PROTOTYPE( int req_lookup, (endpoint_t fs_e, ino_t dir_ino, ino_t root_ino, - uid_t uid, gid_t gid, int flags, + uid_t uid, gid_t gid, struct lookup *resolve, lookup_res_t *res, struct fproc *rfp) ); _PROTOTYPE( int req_mkdir, (endpoint_t fs_e, ino_t inode_nr, char *lastc, uid_t uid, gid_t gid, mode_t dmode) ); @@ -213,16 +261,17 @@ _PROTOTYPE( int req_newnode, (endpoint_t fs_e, uid_t uid, dev_t dev, struct node_details *res) ); _PROTOTYPE( int req_putnode, (int fs_e, ino_t inode_nr, int count) ); _PROTOTYPE( int req_rdlink, (endpoint_t fs_e, ino_t inode_nr, - endpoint_t who_e, char *buf, size_t len, + endpoint_t who_e, char *buf, size_t len, int direct) ); _PROTOTYPE( int req_readsuper, (endpoint_t fs_e, char *driver_name, dev_t dev, int readonly, int isroot, - struct node_details *res_nodep) ); + struct node_details *res_nodep, + int *con_reqs) ); _PROTOTYPE( int req_readwrite, (endpoint_t fs_e, ino_t inode_nr, u64_t pos, int rw_flag, endpoint_t user_e, char *user_addr, unsigned int num_of_bytes, u64_t *new_posp, - unsigned int *cum_iop) ); + unsigned int *cum_iop) ); _PROTOTYPE( int req_rename, (endpoint_t fs_e, ino_t old_dir, char *old_name, ino_t new_dir, char *new_name) ); _PROTOTYPE( int req_rmdir, (endpoint_t fs_e, ino_t inode_nr, @@ -238,7 +287,7 @@ _PROTOTYPE( int req_unlink, (endpoint_t fs_e, ino_t inode_nr, _PROTOTYPE( int req_unmount, (endpoint_t fs_e) ); _PROTOTYPE( int req_utime, (endpoint_t fs_e, ino_t inode_nr, time_t actime, time_t modtime) ); -_PROTOTYPE( int req_newdriver, (endpoint_t fs_e, dev_t dev, +_PROTOTYPE( int req_newdriver, (endpoint_t fs_e, dev_t dev, char *label) ); /* stadir.c */ @@ -250,17 +299,28 @@ _PROTOTYPE( int do_stat, (void) ); _PROTOTYPE( int do_fstatfs, (void) ); _PROTOTYPE( int do_statvfs, (void) ); _PROTOTYPE( int do_fstatvfs, (void) ); -_PROTOTYPE( int do_rdlink, (void) ); -_PROTOTYPE( int do_lstat, (void) ); +_PROTOTYPE( int do_rdlink, (void) ); +_PROTOTYPE( int do_lstat, (void) ); /* time.c */ _PROTOTYPE( int do_utime, (void) ); +/* tll.c */ +_PROTOTYPE( void tll_downgrade, (tll_t *tllp) ); +_PROTOTYPE( int tll_haspendinglock, (tll_t *tllp) ); +_PROTOTYPE( void tll_init, (tll_t *tllp) ); +_PROTOTYPE( int tll_islocked, (tll_t *tllp) ); +_PROTOTYPE( int tll_lock, (tll_t *tllp, tll_access_t locktype) ); +_PROTOTYPE( int tll_locked_by_me, (tll_t *tllp) ); +_PROTOTYPE( void tll_lockstat, (tll_t *tllp) ); +_PROTOTYPE( int tll_unlock, (tll_t *tllp) ); +_PROTOTYPE( void tll_upgrade, (tll_t *tllp) ); + /* utility.c */ _PROTOTYPE( time_t clock_time, (void) ); _PROTOTYPE( unsigned conv2, (int norm, int w) ); _PROTOTYPE( long conv4, (int norm, long x) ); -_PROTOTYPE( int fetch_name, (char *path, int len, int flag) ); +_PROTOTYPE( int fetch_name, (char *path, int len, int flag, char *dest) ); _PROTOTYPE( int no_sys, (void) ); _PROTOTYPE( int isokendpt_f, (char *f, int l, endpoint_t e, int *p, int ft)); _PROTOTYPE( int in_group, (struct fproc *rfp, gid_t grp) ); @@ -269,14 +329,27 @@ _PROTOTYPE( int in_group, (struct fproc *rfp, gid_t grp) ); #define isokendpt(e, p) isokendpt_f(__FILE__, __LINE__, (e), (p), 0) /* vmnt.c */ -_PROTOTYPE( struct vmnt *get_free_vmnt, (short *index) ); -_PROTOTYPE( struct vmnt *find_vmnt, (int fs_e) ); +_PROTOTYPE( void check_vmnt_locks, (void) ); +_PROTOTYPE( void check_vmnt_locks_by_me, (struct fproc *rfp) ); +_PROTOTYPE( struct vmnt *get_free_vmnt, (void) ); +_PROTOTYPE( struct vmnt *find_vmnt, (endpoint_t fs_e) ); +_PROTOTYPE( struct vmnt *get_locked_vmnt, (struct fproc *rfp) ); +_PROTOTYPE( void init_vmnts, (void) ); +_PROTOTYPE( int lock_vmnt, (struct vmnt *vp, tll_access_t locktype) ); +_PROTOTYPE( void unlock_vmnt, (struct vmnt *vp) ); +_PROTOTYPE( void vmnt_unmap_by_endpt, (endpoint_t proc_e) ); /* vnode.c */ +_PROTOTYPE( void check_vnode_locks, (void) ); +_PROTOTYPE( void check_vnode_locks_by_me, (struct fproc *rfp) ); _PROTOTYPE( struct vnode *get_free_vnode, (void) ); _PROTOTYPE( struct vnode *find_vnode, (int fs_e, int numb) ); +_PROTOTYPE( void init_vnodes, (void) ); +_PROTOTYPE( int is_vnode_locked, (struct vnode *vp) ); +_PROTOTYPE( int lock_vnode, (struct vnode *vp, tll_access_t locktype) ); +_PROTOTYPE( void unlock_vnode, (struct vnode *vp) ); _PROTOTYPE( void dup_vnode, (struct vnode *vp) ); -_PROTOTYPE( void put_vnode, (struct vnode *vp) ); +_PROTOTYPE( void put_vnode, (struct vnode *vp) ); _PROTOTYPE( void vnode_clean_refs, (struct vnode *vp) ); #if DO_SANITYCHECKS _PROTOTYPE( int check_vrefs, (void) ); @@ -301,5 +374,17 @@ _PROTOTYPE( void select_reply2, (endpoint_t driver_e, int minor, int status)); _PROTOTYPE( void select_timeout_check, (timer_t *) ); _PROTOTYPE( void select_unsuspend_by_endpt, (endpoint_t proc) ); -/* elf_core_dump.c */ -_PROTOTYPE( void write_elf_core_file, (int csig, char *exe_name) ); +/* worker.c */ +_PROTOTYPE( int worker_available, (void) ); +_PROTOTYPE( struct worker_thread *worker_get, (thread_t worker_tid) ); +_PROTOTYPE( struct job *worker_getjob, (thread_t worker_tid) ); +_PROTOTYPE( void worker_init, (struct worker_thread *worker) ); +_PROTOTYPE( struct worker_thread *worker_self, (void) ); +_PROTOTYPE( void worker_signal, (struct worker_thread *worker) ); +_PROTOTYPE( void worker_start, (void *(*func)(void *arg)) ); +_PROTOTYPE( void worker_stop, (struct worker_thread *worker) ); +_PROTOTYPE( void worker_stop_by_endpt, (endpoint_t proc_e) ); +_PROTOTYPE( void worker_wait, (void) ); +_PROTOTYPE( void sys_worker_start, (void *(*func)(void *arg)) ); +_PROTOTYPE( void dl_worker_start, (void *(*func)(void *arg)) ); +#endif diff --git a/servers/vfs/read.c b/servers/vfs/read.c index 06bf6dcf2..13df38ae0 100644 --- a/servers/vfs/read.c +++ b/servers/vfs/read.c @@ -17,6 +17,7 @@ #include #include "file.h" #include "fproc.h" +#include "scratchpad.h" #include "param.h" #include #include @@ -30,45 +31,103 @@ *===========================================================================*/ PUBLIC int do_read() { - return(read_write(READING)); + return(do_read_write(READING)); } /*===========================================================================* - * read_write * + * lock_bsf * *===========================================================================*/ -PUBLIC int read_write(rw_flag) +PUBLIC void lock_bsf(void) +{ + message org_m_in; + struct fproc *org_fp; + struct worker_thread *org_self; + + if (mutex_trylock(&bsf_lock) == 0) + return; + + org_m_in = m_in; + org_fp = fp; + org_self = self; + + if (mutex_lock(&bsf_lock) != 0) + panic("unable to lock block special file lock"); + + m_in = org_m_in; + fp = org_fp; + self = org_self; +} + +/*===========================================================================* + * unlock_bsf * + *===========================================================================*/ +PUBLIC void unlock_bsf(void) +{ + if (mutex_unlock(&bsf_lock) != 0) + panic("failed to unlock block special file lock"); +} + +/*===========================================================================* + * do_read_write * + *===========================================================================*/ +PUBLIC int do_read_write(rw_flag) int rw_flag; /* READING or WRITING */ { /* Perform read(fd, buffer, nbytes) or write(fd, buffer, nbytes) call. */ - register struct filp *f; + struct filp *f; + tll_access_t locktype; + int r; + + scratch(fp).file.fd_nr = m_in.fd; + scratch(fp).io.io_buffer = m_in.buffer; + scratch(fp).io.io_nbytes = (size_t) m_in.nbytes; + + locktype = (rw_flag == READING) ? VNODE_READ : VNODE_WRITE; + if ((f = get_filp(scratch(fp).file.fd_nr, locktype)) == NULL) + return(err_code); + if (((f->filp_mode) & (rw_flag == READING ? R_BIT : W_BIT)) == 0) { + unlock_filp(f); + return(f->filp_mode == FILP_CLOSED ? EIO : EBADF); + } + if (scratch(fp).io.io_nbytes == 0) { + unlock_filp(f); + return(0); /* so char special files need not check for 0*/ + } + + r = read_write(rw_flag, f, scratch(fp).io.io_buffer, scratch(fp).io.io_nbytes, + who_e); + + unlock_filp(f); + return(r); +} + +/*===========================================================================* + * read_write * + *===========================================================================*/ +PUBLIC int read_write(int rw_flag, struct filp *f, char *buf, size_t size, + endpoint_t for_e) +{ register struct vnode *vp; u64_t position, res_pos, new_pos; unsigned int cum_io, cum_io_incr, res_cum_io; - int op, oflags, r, block_spec, char_spec; - int regular; + int op, oflags, r, block_spec, char_spec, regular; mode_t mode_word; - /* If the file descriptor is valid, get the vnode, size and mode. */ - if (m_in.nbytes < 0) return(EINVAL); - if ((f = get_filp(m_in.fd)) == NULL) return(err_code); - if (((f->filp_mode) & (rw_flag == READING ? R_BIT : W_BIT)) == 0) { - return(f->filp_mode == FILP_CLOSED ? EIO : EBADF); - } - if (m_in.nbytes == 0) - return(0); /* so char special files need not check for 0*/ - position = f->filp_pos; oflags = f->filp_flags; vp = f->filp_vno; r = OK; cum_io = 0; + if (size > SSIZE_MAX) return(EINVAL); + if (vp->v_pipe == I_PIPE) { if (fp->fp_cum_io_partial != 0) { - panic("read_write: fp_cum_io_partial not clear"); + panic("VFS: read_write: fp_cum_io_partial not clear"); } - return rw_pipe(rw_flag, who_e, m_in.fd, f, m_in.buffer, m_in.nbytes); + r = rw_pipe(rw_flag, for_e, f, buf, size); + return(r); } op = (rw_flag == READING ? VFS_DEV_READ : VFS_DEV_WRITE); @@ -77,12 +136,12 @@ int rw_flag; /* READING or WRITING */ if ((char_spec = (mode_word == I_CHAR_SPECIAL ? 1 : 0))) { if (vp->v_sdev == NO_DEV) - panic("read_write tries to read from character device NO_DEV"); + panic("VFS: read_write tries to access char dev NO_DEV"); } if ((block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 : 0))) { if (vp->v_sdev == NO_DEV) - panic("read_write tries to read from block device NO_DEV"); + panic("VFS: read_write tries to access block dev NO_DEV"); } if (char_spec) { /* Character special files. */ @@ -92,7 +151,7 @@ int rw_flag; /* READING or WRITING */ suspend_reopen = (f->filp_state != FS_NORMAL); dev = (dev_t) vp->v_sdev; - r = dev_io(op, dev, who_e, m_in.buffer, position, m_in.nbytes, oflags, + r = dev_io(op, dev, for_e, buf, position, size, oflags, suspend_reopen); if (r >= 0) { cum_io = r; @@ -100,12 +159,16 @@ int rw_flag; /* READING or WRITING */ r = OK; } } else if (block_spec) { /* Block special files. */ - r = req_breadwrite(vp->v_bfs_e, who_e, vp->v_sdev, position, - m_in.nbytes, m_in.buffer, rw_flag, &res_pos, &res_cum_io); + lock_bsf(); + + r = req_breadwrite(vp->v_bfs_e, for_e, vp->v_sdev, position, size, + buf, rw_flag, &res_pos, &res_cum_io); if (r == OK) { position = res_pos; cum_io += res_cum_io; } + + unlock_bsf(); } else { /* Regular files */ if (rw_flag == WRITING && block_spec == 0) { /* Check for O_APPEND flag. */ @@ -113,8 +176,8 @@ int rw_flag; /* READING or WRITING */ } /* Issue request */ - r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, position, rw_flag, who_e, - m_in.buffer, m_in.nbytes, &new_pos, &cum_io_incr); + r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, position, rw_flag, for_e, + buf, size, &new_pos, &cum_io_incr); if (r >= 0) { if (ex64hi(new_pos)) @@ -138,40 +201,40 @@ int rw_flag; /* READING or WRITING */ } f->filp_pos = position; + if (r == OK) return(cum_io); return(r); } - /*===========================================================================* * do_getdents * *===========================================================================*/ PUBLIC int do_getdents() { /* Perform the getdents(fd, buf, size) system call. */ - int r; + int r = OK; u64_t new_pos; register struct filp *rfilp; /* Is the file descriptor valid? */ - if ( (rfilp = get_filp(m_in.fd)) == NULL) { - return(err_code); - } - + if ( (rfilp = get_filp(m_in.fd, VNODE_READ)) == NULL) return(err_code); + if (!(rfilp->filp_mode & R_BIT)) - return(EBADF); + r = EBADF; + else if ((rfilp->filp_vno->v_mode & I_TYPE) != I_DIRECTORY) + r = EBADF; - if ((rfilp->filp_vno->v_mode & I_TYPE) != I_DIRECTORY) - return(EBADF); + if (r == OK) { + if (ex64hi(rfilp->filp_pos) != 0) + panic("do_getdents: can't handle large offsets"); - if (ex64hi(rfilp->filp_pos) != 0) - panic("do_getdents: should handle large offsets"); - - r = req_getdents(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr, - rfilp->filp_pos, m_in.buffer, m_in.nbytes, &new_pos, 0); + r = req_getdents(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr, + rfilp->filp_pos, m_in.buffer, m_in.nbytes,&new_pos,0); - if (r > 0) - rfilp->filp_pos = new_pos; + if (r > 0) rfilp->filp_pos = new_pos; + } + + unlock_filp(rfilp); return(r); } @@ -179,10 +242,9 @@ PUBLIC int do_getdents() /*===========================================================================* * rw_pipe * *===========================================================================*/ -PUBLIC int rw_pipe(rw_flag, usr_e, fd_nr, f, buf, req_size) +PUBLIC int rw_pipe(rw_flag, usr_e, f, buf, req_size) int rw_flag; /* READING or WRITING */ endpoint_t usr_e; -int fd_nr; struct filp *f; char *buf; size_t req_size; @@ -192,17 +254,21 @@ size_t req_size; struct vnode *vp; u64_t position, new_pos; + /* Must make sure we're operating on locked filp and vnode */ + assert(tll_islocked(&f->filp_vno->v_lock)); + assert(mutex_trylock(&f->filp_lock) == -EDEADLK); + oflags = f->filp_flags; vp = f->filp_vno; position = cvu64((rw_flag == READING) ? vp->v_pipe_rd_pos : - vp->v_pipe_wr_pos); + vp->v_pipe_wr_pos); /* fp->fp_cum_io_partial is only nonzero when doing partial writes */ - cum_io = fp->fp_cum_io_partial; + cum_io = fp->fp_cum_io_partial; r = pipe_check(vp, rw_flag, oflags, req_size, position, 0); if (r <= 0) { - if (r == SUSPEND) pipe_suspend(rw_flag, fd_nr, buf, req_size); - return(r); + if (r == SUSPEND) pipe_suspend(f, buf, req_size); + return(r); } size = r; @@ -210,7 +276,7 @@ size_t req_size; /* Truncate read request at size. */ if((rw_flag == READING) && - cmp64ul(add64ul(position, size), vp->v_size) > 0) { + cmp64ul(add64ul(position, size), vp->v_size) > 0) { /* Position always should fit in an off_t (LONG_MAX). */ off_t pos32; @@ -221,7 +287,7 @@ size_t req_size; size = vp->v_size - pos32; } - if (vp->v_mapfs_e == 0) + if (vp->v_mapfs_e == 0) panic("unmapped pipe"); r = req_readwrite(vp->v_mapfs_e, vp->v_mapinode_nr, position, rw_flag, usr_e, @@ -236,7 +302,7 @@ size_t req_size; buf += cum_io_incr; req_size -= cum_io_incr; } - + /* On write, update file size and access time. */ if (rw_flag == WRITING) { if (cmp64ul(position, vp->v_size) > 0) { @@ -269,7 +335,7 @@ size_t req_size; * non-atomic */ fp->fp_cum_io_partial = cum_io; - pipe_suspend(rw_flag, fd_nr, buf, req_size); + pipe_suspend(f, buf, req_size); return(SUSPEND); } } @@ -279,4 +345,3 @@ size_t req_size; return(r); } - diff --git a/servers/vfs/request.c b/servers/vfs/request.c index 137c338ef..be230da77 100644 --- a/servers/vfs/request.c +++ b/servers/vfs/request.c @@ -21,13 +21,9 @@ #include "fproc.h" #include "vmnt.h" #include "vnode.h" +#include "path.h" #include "param.h" -FORWARD _PROTOTYPE(int fs_sendrec_f, (char *file, int line, endpoint_t fs_e, - message *reqm) ); - -#define fs_sendrec(e, m) fs_sendrec_f(__FILE__, __LINE__, (e), (m)) - /*===========================================================================* * req_breadwrite * @@ -94,7 +90,7 @@ PUBLIC int req_chmod( /* Send/rec request */ r = fs_sendrec(fs_e, &m); - + /* Copy back actual mode. */ *new_modep = m.RES_MODE; @@ -151,7 +147,7 @@ PUBLIC int req_create( message m; if (path[0] == '/') - panic("req_create: filename starts with '/'"); + panic("req_create: filename starts with '/'"); len = strlen(path) + 1; grant_id = cpf_grant_direct(fs_e, (vir_bytes) path, len, CPF_READ); @@ -180,7 +176,7 @@ PUBLIC int req_create( res->uid = m.RES_UID; res->gid = m.RES_GID; res->dev = m.RES_DEV; - + return(OK); } @@ -195,7 +191,7 @@ PUBLIC int req_flush(endpoint_t fs_e, dev_t dev) /* Fill in request message */ m.m_type = REQ_FLUSH; m.REQ_DEV = dev; - + /* Send/rec request */ return fs_sendrec(fs_e, &m); } @@ -204,15 +200,15 @@ PUBLIC int req_flush(endpoint_t fs_e, dev_t dev) /*===========================================================================* * req_fstatfs * *===========================================================================*/ -PUBLIC int req_fstatfs(int fs_e, int who_e, char *buf) +PUBLIC int req_fstatfs(int fs_e, int proc_e, char *buf) { int r; cp_grant_id_t grant_id; message m; - grant_id = cpf_grant_magic(fs_e, who_e, (vir_bytes) buf, sizeof(struct statfs), + grant_id = cpf_grant_magic(fs_e, proc_e, (vir_bytes) buf, sizeof(struct statfs), CPF_WRITE); - if(grant_id == -1) + if(grant_id == -1) panic("req_fstatfs: cpf_grant_magic failed"); /* Fill in request message */ @@ -230,15 +226,15 @@ PUBLIC int req_fstatfs(int fs_e, int who_e, char *buf) /*===========================================================================* * req_statvfs * *===========================================================================*/ -PUBLIC int req_statvfs(int fs_e, int who_e, char *buf) +PUBLIC int req_statvfs(int fs_e, int proc_e, char *buf) { int r; cp_grant_id_t grant_id; message m; - grant_id = cpf_grant_magic(fs_e, who_e, (vir_bytes) buf, sizeof(struct statvfs), + grant_id = cpf_grant_magic(fs_e, proc_e, (vir_bytes) buf, sizeof(struct statvfs), CPF_WRITE); - if(grant_id == -1) + if(grant_id == -1) panic("req_statvfs: cpf_grant_magic failed"); /* Fill in request message */ @@ -267,7 +263,7 @@ PUBLIC int req_ftrunc(endpoint_t fs_e, ino_t inode_nr, off_t start, off_t end) m.REQ_TRC_START_HI = 0; /* Not used for now, so clear it. */ m.REQ_TRC_END_LO = end; m.REQ_TRC_END_HI = 0; /* Not used for now, so clear it. */ - + /* Send/rec request */ return fs_sendrec(fs_e, &m); } @@ -299,7 +295,7 @@ PUBLIC int req_getdents( } if (grant_id < 0) - panic("req_getdents: cpf_grant_direct/cpf_grant_magic failed: %d", + panic("req_getdents: cpf_grant_direct/cpf_grant_magic failed: %d", grant_id); m.m_type = REQ_GETDENTS; @@ -308,10 +304,10 @@ PUBLIC int req_getdents( m.REQ_MEM_SIZE = size; m.REQ_SEEK_POS_LO = ex64lo(pos); m.REQ_SEEK_POS_HI = 0; /* Not used for now, so clear it. */ - + r = fs_sendrec(fs_e, &m); cpf_revoke(grant_id); - + if (r == OK) { *new_pos = cvul64(m.RES_SEEK_POS_LO); r = m.RES_NBYTES; @@ -330,7 +326,7 @@ PUBLIC int req_inhibread(endpoint_t fs_e, ino_t inode_nr) /* Fill in request message */ m.m_type = REQ_INHIBREAD; m.REQ_INODE_NR = inode_nr; - + /* Send/rec request */ return fs_sendrec(fs_e, &m); } @@ -365,10 +361,10 @@ PUBLIC int req_link( /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(grant_id); - + return(r); } - + /*===========================================================================* * req_lookup * @@ -379,7 +375,7 @@ PUBLIC int req_lookup( ino_t root_ino, uid_t uid, gid_t gid, - int flags, + struct lookup *resolve, lookup_res_t *res, struct fproc *rfp ) @@ -389,31 +385,33 @@ PUBLIC int req_lookup( cp_grant_id_t grant_id=0, grant_id2=0; message m; vfs_ucred_t credentials; + int flags; - grant_id = cpf_grant_direct(fs_e, (vir_bytes) user_fullpath, - sizeof(user_fullpath), CPF_READ | CPF_WRITE); + grant_id = cpf_grant_direct(fs_e, (vir_bytes) resolve->l_path, PATH_MAX, + CPF_READ | CPF_WRITE); if(grant_id == -1) panic("req_lookup: cpf_grant_direct failed"); - len = strlen(user_fullpath) + 1; + flags = resolve->l_flags; + len = strlen(resolve->l_path) + 1; m.m_type = REQ_LOOKUP; m.REQ_GRANT = grant_id; m.REQ_PATH_LEN = len; - m.REQ_PATH_SIZE = sizeof(user_fullpath); + m.REQ_PATH_SIZE = PATH_MAX + 1; m.REQ_DIR_INO = dir_ino; m.REQ_ROOT_INO = root_ino; if(rfp->fp_ngroups > 0) { /* Is the process member of multiple groups? */ - /* In that case the FS has to copy the uid/gid credentials */ - int i; + /* In that case the FS has to copy the uid/gid credentials */ + int i; - /* Set credentials */ - credentials.vu_uid = rfp->fp_effuid; - credentials.vu_gid = rfp->fp_effgid; - credentials.vu_ngroups = rfp->fp_ngroups; - for (i = 0; i < rfp->fp_ngroups; i++) - credentials.vu_sgroups[i] = rfp->fp_sgroups[i]; + /* Set credentials */ + credentials.vu_uid = rfp->fp_effuid; + credentials.vu_gid = rfp->fp_effgid; + credentials.vu_ngroups = rfp->fp_ngroups; + for (i = 0; i < rfp->fp_ngroups; i++) + credentials.vu_sgroups[i] = rfp->fp_sgroups[i]; grant_id2 = cpf_grant_direct(fs_e, (vir_bytes) &credentials, sizeof(credentials), CPF_READ); @@ -422,9 +420,9 @@ PUBLIC int req_lookup( m.REQ_GRANT2 = grant_id2; m.REQ_UCRED_SIZE= sizeof(credentials); - flags |= PATH_GET_UCRED; + flags |= PATH_GET_UCRED; } else { - /* When there's only one gid, we can send it directly */ + /* When there's only one gid, we can send it directly */ m.REQ_UID = uid; m.REQ_GID = gid; flags &= ~PATH_GET_UCRED; @@ -435,7 +433,7 @@ PUBLIC int req_lookup( /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(grant_id); - if(rfp->fp_ngroups > 0) cpf_revoke(grant_id2); + if(rfp->fp_ngroups > 0) cpf_revoke(grant_id2); /* Fill in response according to the return value */ res->fs_e = m.m_source; @@ -465,7 +463,7 @@ PUBLIC int req_lookup( default: break; } - + return(r); } @@ -486,7 +484,7 @@ PUBLIC int req_mkdir( cp_grant_id_t grant_id; size_t len; message m; - + len = strlen(lastc) + 1; grant_id = cpf_grant_direct(fs_e, (vir_bytes)lastc, len, CPF_READ); if(grant_id == -1) @@ -526,7 +524,7 @@ PUBLIC int req_mknod( size_t len; cp_grant_id_t grant_id; message m; - + len = strlen(lastc) + 1; grant_id = cpf_grant_direct(fs_e, (vir_bytes)lastc, len, CPF_READ); if(grant_id == -1) @@ -541,11 +539,11 @@ PUBLIC int req_mknod( m.REQ_GID = gid; m.REQ_GRANT = grant_id; m.REQ_PATH_LEN = len; - + /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(grant_id); - + return(r); } @@ -661,10 +659,10 @@ int count; /*===========================================================================* * req_rdlink * *===========================================================================*/ -PUBLIC int req_rdlink(fs_e, inode_nr, who_e, buf, len, direct) +PUBLIC int req_rdlink(fs_e, inode_nr, proc_e, buf, len, direct) endpoint_t fs_e; ino_t inode_nr; -endpoint_t who_e; +endpoint_t proc_e; char *buf; size_t len; int direct; /* set to 1 to use direct grants instead of magic grants */ @@ -676,7 +674,7 @@ int direct; /* set to 1 to use direct grants instead of magic grants */ if (direct) { grant_id = cpf_grant_direct(fs_e, (vir_bytes) buf, len, CPF_WRITE); } else { - grant_id = cpf_grant_magic(fs_e, who_e, (vir_bytes) buf, len, + grant_id = cpf_grant_magic(fs_e, proc_e, (vir_bytes) buf, len, CPF_WRITE); } if(grant_id == -1) @@ -687,7 +685,7 @@ int direct; /* set to 1 to use direct grants instead of magic grants */ m.REQ_INODE_NR = inode_nr; m.REQ_GRANT = grant_id; m.REQ_MEM_SIZE = len; - + /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(grant_id); @@ -707,14 +705,15 @@ PUBLIC int req_readsuper( dev_t dev, int readonly, int isroot, - struct node_details *res_nodep + struct node_details *res_nodep, + int *con_reqs ) { int r; cp_grant_id_t grant_id; size_t len; message m; - + len = strlen(label)+1; grant_id = cpf_grant_direct(fs_e, (vir_bytes) label, len, CPF_READ); if (grant_id == -1) @@ -724,11 +723,11 @@ PUBLIC int req_readsuper( m.m_type = REQ_READSUPER; m.REQ_FLAGS = 0; if(readonly) m.REQ_FLAGS |= REQ_RDONLY; - if(isroot) m.REQ_FLAGS |= REQ_ISROOT; + if(isroot) m.REQ_FLAGS |= REQ_ISROOT; m.REQ_GRANT = grant_id; m.REQ_DEV = dev; m.REQ_PATH_LEN = len; - + /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(grant_id); @@ -741,6 +740,7 @@ PUBLIC int req_readsuper( res_nodep->fsize = m.RES_FILE_SIZE_LO; res_nodep->uid = m.RES_UID; res_nodep->gid = m.RES_GID; + *con_reqs = m.RES_CONREQS; } return(r); @@ -770,7 +770,7 @@ unsigned int *cum_iop; panic("req_readwrite: pos too large"); grant_id = cpf_grant_magic(fs_e, user_e, (vir_bytes) user_addr, num_of_bytes, - (rw_flag==READING ? CPF_WRITE:CPF_READ)); + (rw_flag==READING ? CPF_WRITE:CPF_READ)); if (grant_id == -1) panic("req_readwrite: cpf_grant_magic failed"); @@ -781,7 +781,7 @@ unsigned int *cum_iop; m.REQ_SEEK_POS_LO = ex64lo(pos); m.REQ_SEEK_POS_HI = 0; /* Not used for now, so clear it. */ m.REQ_NBYTES = num_of_bytes; - + /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(grant_id); @@ -791,7 +791,7 @@ unsigned int *cum_iop; *new_posp = cvul64(m.RES_SEEK_POS_LO); *cum_iop = m.RES_NBYTES; } - + return(r); } @@ -829,7 +829,7 @@ char *new_name; m.REQ_REN_LEN_OLD = len_old; m.REQ_REN_GRANT_NEW = gid_new; m.REQ_REN_LEN_NEW = len_new; - + /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(gid_old); @@ -851,7 +851,7 @@ char *lastc; cp_grant_id_t grant_id; size_t len; message m; - + len = strlen(lastc) + 1; grant_id = cpf_grant_direct(fs_e, (vir_bytes) lastc, len, CPF_READ); if(grant_id == -1) @@ -878,7 +878,7 @@ PUBLIC int req_slink( endpoint_t fs_e, ino_t inode_nr, char *lastc, - endpoint_t who_e, + endpoint_t proc_e, char *path_addr, unsigned short path_length, uid_t uid, @@ -895,7 +895,7 @@ PUBLIC int req_slink( if(gid_name == -1) panic("req_slink: cpf_grant_direct failed"); - gid_buf = cpf_grant_magic(fs_e, who_e, (vir_bytes) path_addr, path_length, + gid_buf = cpf_grant_magic(fs_e, proc_e, (vir_bytes) path_addr, path_length, CPF_READ); if(gid_buf == -1) { cpf_revoke(gid_name); @@ -924,10 +924,10 @@ PUBLIC int req_slink( /*===========================================================================* * req_stat * *===========================================================================*/ -PUBLIC int req_stat(fs_e, inode_nr, who_e, buf, pos, stat_version) +PUBLIC int req_stat(fs_e, inode_nr, proc_e, buf, pos, stat_version) int fs_e; ino_t inode_nr; -int who_e; +int proc_e; char *buf; int pos; int stat_version; @@ -940,9 +940,9 @@ int stat_version; if (pos != 0 || stat_version != 0) grant_id = cpf_grant_direct(fs_e, (vir_bytes) &sb, - sizeof(struct stat), CPF_WRITE); + sizeof(struct stat), CPF_WRITE); else - grant_id = cpf_grant_magic(fs_e, who_e, (vir_bytes) buf, + grant_id = cpf_grant_magic(fs_e, proc_e, (vir_bytes) buf, sizeof(struct stat), CPF_WRITE); if (grant_id < 0) @@ -963,7 +963,7 @@ int stat_version; if (pos != 0) sb.st_size -= pos; if (stat_version == 0) { - r = sys_vircopy(SELF, D, (vir_bytes) &sb, who_e, D, (vir_bytes) buf, + r = sys_vircopy(SELF, D, (vir_bytes) &sb, proc_e, D, (vir_bytes) buf, sizeof(struct stat)); return(r); } @@ -971,7 +971,7 @@ int stat_version; /* User needs old struct stat. * Just 1 prev version at this moment */ assert(stat_version == 1); - + /* XXX until that st_Xtime macroses used, we have to undefine them, * because of minix_prev_stat */ @@ -1000,9 +1000,9 @@ int stat_version; old_sb.st_ctime = sb.st_ctime; #endif - r = sys_vircopy(SELF, D, (vir_bytes) &old_sb, who_e, D, (vir_bytes) buf, + r = sys_vircopy(SELF, D, (vir_bytes) &old_sb, proc_e, D, (vir_bytes) buf, sizeof(struct minix_prev_stat)); - + return(r); } @@ -1011,13 +1011,13 @@ int stat_version; * req_sync * *===========================================================================*/ PUBLIC int req_sync(fs_e) -endpoint_t fs_e; +endpoint_t fs_e; { message m; /* Fill in request message */ m.m_type = REQ_SYNC; - + /* Send/rec request */ return fs_sendrec(fs_e, &m); } @@ -1035,7 +1035,7 @@ char *lastc; size_t len; int r; message m; - + len = strlen(lastc) + 1; grant_id = cpf_grant_direct(fs_e, (vir_bytes) lastc, len, CPF_READ); if(grant_id == -1) @@ -1050,7 +1050,7 @@ char *lastc; /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(grant_id); - + return(r); } @@ -1059,13 +1059,13 @@ char *lastc; * req_unmount * *===========================================================================*/ PUBLIC int req_unmount(fs_e) -endpoint_t fs_e; +endpoint_t fs_e; { message m; /* Fill in request message */ m.m_type = REQ_UNMOUNT; - + /* Send/rec request */ return fs_sendrec(fs_e, &m); } @@ -1087,62 +1087,7 @@ time_t modtime; m.REQ_INODE_NR = inode_nr; m.REQ_ACTIME = actime; m.REQ_MODTIME = modtime; - + /* Send/rec request */ return fs_sendrec(fs_e, &m); } - - -/*===========================================================================* - * fs_sendrec * - *===========================================================================*/ -PRIVATE int fs_sendrec_f(char *file, int line, endpoint_t fs_e, message *reqm) -{ -/* This is the low level function that sends requests to FS processes. - * It also handles driver recovery mechanism and reissuing the - * request which failed due to a dead driver. - */ - int r; - message origm; - - if(fs_e <= 0 || fs_e == NONE) - panic("talking to bogus endpoint: %d", fs_e); - - /* Make a copy of the request so that we can load it back in - * case of a dead driver */ - origm = *reqm; - - /* In response to the request we sent, some file systems may send back their - * own VFS request, instead of a reply. VFS currently offers limited support - * for this. As long as the FS keeps sending requests, we process them and - * send back a reply. We break out of the loop as soon as the FS sends a - * reply to the original request. - * - * There is no form of locking or whatever on global data structures, so it - * is quite easy to mess things up; hence, 'limited' support. A future async - * VFS will solve this problem for good. - */ - for (;;) { - /* Do the actual send, receive */ - if (OK != (r = sendrec(fs_e, reqm))) { - printf("VFS:fs_sendrec:%s:%d: error sending message. " - "FS_e: %d req_nr: %d err: %d\n", file, line, fs_e, - reqm->m_type, r); - util_stacktrace(); - return(r); - } - - /* If the type field is 0 (OK) or negative (E*), this is a reply. If it - * contains a positive nonzero value, this is a request. - */ - if (reqm->m_type <= 0) - break; /* Reply */ - - /* Request */ - nested_fs_call(reqm); - } - - /* Return message type */ - return(reqm->m_type); -} - diff --git a/servers/vfs/request.h b/servers/vfs/request.h index 0ec8aab30..74f612bf9 100644 --- a/servers/vfs/request.h +++ b/servers/vfs/request.h @@ -1,3 +1,5 @@ +#ifndef __VFS_REQUEST_H__ +#define __VFS_REQUEST_H__ /* Low level request messages are built and sent by wrapper functions. * This file contains the request and response structures for accessing @@ -8,32 +10,32 @@ /* Structure for response that contains inode details */ typedef struct node_details { - endpoint_t fs_e; - ino_t inode_nr; - mode_t fmode; - off_t fsize; - uid_t uid; - gid_t gid; + endpoint_t fs_e; + ino_t inode_nr; + mode_t fmode; + off_t fsize; + uid_t uid; + gid_t gid; - /* For char/block special files */ - dev_t dev; + /* For char/block special files */ + dev_t dev; } node_details_t; /* Structure for a lookup response */ typedef struct lookup_res { - endpoint_t fs_e; - ino_t inode_nr; - mode_t fmode; - off_t fsize; - uid_t uid; - gid_t gid; - /* For char/block special files */ - dev_t dev; - - /* Fields used for handling mount point and symbolic links */ - int char_processed; - unsigned char symloop; + endpoint_t fs_e; + ino_t inode_nr; + mode_t fmode; + off_t fsize; + uid_t uid; + gid_t gid; + /* For char/block special files */ + dev_t dev; + + /* Fields used for handling mount point and symbolic links */ + int char_processed; + unsigned char symloop; } lookup_res_t; -/* Structure for REQ_ request */ +#endif diff --git a/servers/avfs/scratchpad.h b/servers/vfs/scratchpad.h similarity index 100% rename from servers/avfs/scratchpad.h rename to servers/vfs/scratchpad.h diff --git a/servers/vfs/select.c b/servers/vfs/select.c index ae9a8ded0..90e23ab06 100644 --- a/servers/vfs/select.c +++ b/servers/vfs/select.c @@ -2,7 +2,7 @@ * * The entry points into this file are * do_select: perform the SELECT system call - * select_callback: notify select system of possible fd operation + * select_callback: notify select system of possible fd operation * select_unsuspend_by_endpt: cancel a blocking select on exiting driver */ @@ -51,6 +51,7 @@ FORWARD _PROTOTYPE(void ops2tab, (int ops, int fd, struct selectentry *e)); FORWARD _PROTOTYPE(int is_regular_file, (struct filp *f) ); FORWARD _PROTOTYPE(int is_pipe, (struct filp *f) ); FORWARD _PROTOTYPE(int is_supported_major, (struct filp *f) ); +FORWARD _PROTOTYPE(void select_lock_filp, (struct filp *f, int ops) ); FORWARD _PROTOTYPE(int select_request_async, (struct filp *f, int *ops, int block) ); FORWARD _PROTOTYPE(int select_request_file, (struct filp *f, int *ops, @@ -69,9 +70,9 @@ FORWARD _PROTOTYPE(int tab2ops, (int fd, struct selectentry *e) ); FORWARD _PROTOTYPE(void wipe_select, (struct selectentry *s) ); PRIVATE struct fdtype { - int (*select_request)(struct filp *, int *ops, int block); + int (*select_request)(struct filp *, int *ops, int block); int (*type_match)(struct filp *f); -} fdtypes[] = { +} fdtypes[] = { { select_request_major, is_supported_major }, { select_request_file, is_regular_file }, { select_request_pipe, is_pipe }, @@ -93,9 +94,9 @@ PUBLIC int do_select(void) /* Implement the select(nfds, readfds, writefds, errorfds, timeout) system * call. First we copy the arguments and verify their sanity. Then we check * whether there are file descriptors that satisfy the select call right of the - * bat. If so, or if there are no ready file descriptors but the process + * bat. If so, or if there are no ready file descriptors but the process * requested to return immediately, we return the result. Otherwise we set a - * timeout and wait for either the file descriptors to become ready or the + * timeout and wait for either the file descriptors to become ready or the * timer to go off. If no timeout value was provided, we wait indefinitely. */ int r, nfds, do_timeout = 0, fd, s; @@ -121,11 +122,11 @@ PUBLIC int do_select(void) se->vir_errorfds = (fd_set *) m_in.SEL_ERRORFDS; /* Copy fdsets from the process */ - if ((r = copy_fdsets(se, nfds, FROM_PROC)) != OK) return(r); + if ((r = copy_fdsets(se, nfds, FROM_PROC)) != OK) return(r); /* Did the process set a timeout value? If so, retrieve it. */ if (m_in.SEL_TIMEOUT != NULL) { - do_timeout = 1; + do_timeout = 1; r = sys_vircopy(who_e, D, (vir_bytes) m_in.SEL_TIMEOUT, SELF, D, (vir_bytes) &timeout, sizeof(timeout)); if (r != OK) return(r); @@ -136,20 +137,20 @@ PUBLIC int do_select(void) return(EINVAL); /* If there is no timeout, we block forever. Otherwise, we block up to the - * specified time interval. + * specified time interval. */ if (!do_timeout) /* No timeout value set */ se->block = 1; else if (do_timeout && (timeout.tv_sec > 0 || timeout.tv_usec > 0)) - se->block = 1; + se->block = 1; else /* timeout set as (0,0) - this effects a poll */ - se->block = 0; + se->block = 0; se->expiry = 0; /* no timer set (yet) */ /* Verify that file descriptors are okay to select on */ for (fd = 0; fd < nfds; fd++) { - struct filp *f; - int type, ops; + struct filp *f; + int type, ops; /* Because the select() interface implicitly includes file descriptors * you might not want to select on, we have to figure out whether we're @@ -157,20 +158,19 @@ PUBLIC int do_select(void) * inherited from the parent proc and file descriptors that have been * close()d, but had a lower fd than one in the current set. */ - if (!(ops = tab2ops(fd, se))) + if (!(ops = tab2ops(fd, se))) continue; /* No operations set; nothing to do for this fd */ /* Get filp belonging to this fd */ - f = se->filps[fd] = get_filp(fd); + f = se->filps[fd] = get_filp(fd, VNODE_READ); if (f == NULL) { - if (err_code == EBADF) + if (err_code == EBADF) r = err_code; else /* File descriptor is 'ready' to return EIO */ r = EINTR; return(r); - } else if (f->filp_vno == NULL) - return(EBADF); + } /* Check file types. According to POSIX 2008: * "The pselect() and select() functions shall support regular files, @@ -194,7 +194,8 @@ PUBLIC int do_select(void) break; } } - if (se->type[fd] == -1) /* Type not found */ + unlock_filp(f); + if (se->type[fd] == -1) /* Type not found */ return(EBADF); } @@ -202,30 +203,34 @@ PUBLIC int do_select(void) for (fd = 0; fd < nfds; fd++) { int ops, r; struct filp *f; - + /* Again, check for involuntarily selected fd's */ - if (!(ops = tab2ops(fd, se))) + if (!(ops = tab2ops(fd, se))) continue; /* No operations set; nothing to do for this fd */ - /* Test filp for select operations if not already done so. e.g., + /* Test filp for select operations if not already done so. e.g., * processes sharing a filp and both doing a select on that filp. */ f = se->filps[fd]; + select_lock_filp(f, f->filp_select_ops | ops); if ((f->filp_select_ops & ops) != ops) { int wantops; wantops = (f->filp_select_ops |= ops); r = do_select_request(se, fd, &wantops); + unlock_filp(f); if (r != SEL_OK) { if (r == SEL_DEFERRED) continue; else break; /* Error or bogus return code; abort */ } - + /* The select request above might have turned on/off some * operations because they were 'ready' or not meaningful. * Either way, we might have a result and we need to store them * in the select table entry. */ if (wantops & ops) ops2tab(wantops, fd, se); - } + } else { + unlock_filp(f); + } } if ((se->nreadyfds > 0 || !se->block) && !is_deferred(se)) { @@ -243,7 +248,7 @@ PUBLIC int do_select(void) return(se->nreadyfds); } - + /* Convert timeval to ticks and set the timer. If it fails, undo * all, return error. */ @@ -322,9 +327,9 @@ PRIVATE int is_supported_major(struct filp *f) if (!(f && f->filp_vno)) return(FALSE); if ((f->filp_vno->v_mode & I_TYPE) != I_CHAR_SPECIAL) return(FALSE); - for (m = 0; m < SEL_MAJORS; m++) - if (major(f->filp_vno->v_sdev) == select_majors[m]) - return(TRUE); + for (m = 0; m < SEL_MAJORS; m++) + if (major(f->filp_vno->v_sdev) == select_majors[m]) + return(TRUE); return(FALSE); } @@ -381,7 +386,7 @@ PRIVATE int select_request_async(struct filp *f, int *ops, int block) if (r < 0 && r != SUSPEND) return(SEL_ERROR); - if (r != SUSPEND) + if (r != SUSPEND) panic("select_request_asynch: expected SUSPEND got: %d", r); dp->dmap_sel_filp = f; @@ -393,7 +398,8 @@ PRIVATE int select_request_async(struct filp *f, int *ops, int block) /*===========================================================================* * select_request_file * *===========================================================================*/ -PRIVATE int select_request_file(struct filp *f, int *ops, int block) +PRIVATE int select_request_file(struct filp *UNUSED(f), int *UNUSED(ops), + int UNUSED(block)) { /* Files are always ready, so output *ops is input *ops */ return(SEL_OK); @@ -409,10 +415,11 @@ PRIVATE int select_request_major(struct filp *f, int *ops, int block) major = major(f->filp_vno->v_sdev); if (major < 0 || major >= NR_DEVICES) return(SEL_ERROR); - if (dmap[major].dmap_style == STYLE_DEVA) - r = select_request_async(f, ops, block); + if (dmap[major].dmap_style == STYLE_DEVA || + dmap[major].dmap_style == STYLE_CLONE_A) + r = select_request_async(f, ops, block); else - r = select_request_sync(f, ops, block); + r = select_request_sync(f, ops, block); return(r); } @@ -453,7 +460,7 @@ PRIVATE int select_request_pipe(struct filp *f, int *ops, int block) if (err == SUSPEND && !(f->filp_mode & R_BIT)) { /* A "meaningless" read select, therefore ready * for reading and no error set. */ - r |= SEL_RD; + r |= SEL_RD; r &= ~SEL_ERR; } } @@ -468,7 +475,7 @@ PRIVATE int select_request_pipe(struct filp *f, int *ops, int block) if (err == SUSPEND && !(f->filp_mode & W_BIT)) { /* A "meaningless" write select, therefore ready for writing and no error set. */ - r |= SEL_WR; + r |= SEL_WR; r &= ~SEL_ERR; } } @@ -491,8 +498,8 @@ PRIVATE int tab2ops(int fd, struct selectentry *e) if (FD_ISSET(fd, &e->readfds)) ops |= SEL_RD; if (FD_ISSET(fd, &e->writefds)) ops |= SEL_WR; if (FD_ISSET(fd, &e->errorfds)) ops |= SEL_ERR; - - return(ops); + + return(ops); } @@ -586,9 +593,6 @@ PRIVATE void select_cancel_all(struct selectentry *se) int fd; struct filp *f; - /* Always await results of asynchronous requests */ - assert(!is_deferred(se)); - for (fd = 0; fd < se->nfds; fd++) { if ((f = se->filps[fd]) == NULL) continue; se->filps[fd] = NULL; @@ -596,7 +600,7 @@ PRIVATE void select_cancel_all(struct selectentry *se) } if (se->expiry > 0) { - cancel_timer(&se->timer); + cancel_timer(&se->timer); se->expiry = 0; } @@ -613,14 +617,19 @@ PRIVATE void select_cancel_filp(struct filp *f) assert(f); assert(f->filp_selectors >= 0); if (f->filp_selectors == 0) return; + if (f->filp_count == 0) return; + + select_lock_filp(f, f->filp_select_ops); f->filp_selectors--; - if (f->filp_selectors == 0) { + if (f->filp_selectors == 0) { /* No one selecting on this filp anymore, forget about select state */ f->filp_select_ops = 0; f->filp_select_flags = 0; f->filp_pipe_select_ops = 0; } + + unlock_filp(f); } /*===========================================================================* @@ -633,13 +642,14 @@ PRIVATE void select_return(struct selectentry *se) assert(!is_deferred(se)); /* Not done yet, first wait for async reply */ select_cancel_all(se); - r1 = copy_fdsets(se, se->nfds, TO_PROC); + + r1 = copy_fdsets(se, se->nfds, TO_PROC); if (r1 != OK) - r = r1; + r = r1; else if (se->error != OK) - r = se->error; + r = se->error; else - r = se->nreadyfds; + r = se->nreadyfds; revive(se->req_endpt, r); } @@ -670,7 +680,7 @@ PUBLIC void init_select(void) *===========================================================================*/ PUBLIC void select_forget(endpoint_t proc_e) { -/* Something has happened (e.g. signal delivered that interrupts select()). +/* Something has happened (e.g. signal delivered that interrupts select()). * Totally forget about the select(). */ int slot; @@ -678,7 +688,7 @@ PUBLIC void select_forget(endpoint_t proc_e) for (slot = 0; slot < MAXSELECTS; slot++) { se = &selecttab[slot]; - if (se->requestor != NULL && se->req_endpt == proc_e) + if (se->requestor != NULL && se->req_endpt == proc_e) break; } @@ -700,9 +710,10 @@ PUBLIC void select_timeout_check(timer_t *timer) s = tmr_arg(timer)->ta_int; if (s < 0 || s >= MAXSELECTS) return; /* Entry does not exist */ - - se = &selecttab[s]; + + se = &selecttab[s]; if (se->requestor == NULL) return; + fp = se->requestor; if (se->expiry <= 0) return; /* Strange, did we even ask for a timeout? */ se->expiry = 0; if (is_deferred(se)) return; /* Wait for initial replies to DEV_SELECT */ @@ -722,12 +733,17 @@ PUBLIC void select_unsuspend_by_endpt(endpoint_t proc_e) struct filp *f; for (s = 0; s < MAXSELECTS; s++) { - int wakehim = 0; - se = &selecttab[s]; + int wakehim = 0; + se = &selecttab[s]; if (se->requestor == NULL) continue; - + if (se->requestor->fp_endpoint == proc_e) { + assert(se->requestor->fp_flags & FP_EXITING); + select_cancel_all(se); + continue; + } + for (fd = 0; fd < se->nfds; fd++) { - if ((f = se->filps[fd]) == NULL || f->filp_vno == NULL) + if ((f = se->filps[fd]) == NULL || f->filp_vno == NULL) continue; major = major(f->filp_vno->v_sdev); @@ -744,7 +760,6 @@ PUBLIC void select_unsuspend_by_endpt(endpoint_t proc_e) } } - /*===========================================================================* * select_reply1 * *===========================================================================*/ @@ -762,11 +777,8 @@ int status; struct vnode *vp; /* Figure out which device is replying */ - if ((dp = get_dmap(driver_e)) == NULL) { - printf("VFS (%s:%d): endpoint %d is not a known driver endpoint\n", - __FILE__, __LINE__, driver_e); - return; - } + if ((dp = get_dmap(driver_e)) == NULL) return; + major = dp-dmap; dev = makedev(major, minor); @@ -792,31 +804,50 @@ int status; } /* No longer waiting for a reply from this device */ - f->filp_select_flags &= ~FSF_BUSY; dp->dmap_sel_filp = NULL; - /* The select call is done now, except when - * - another process started a select on the same filp with possibly a - * different set of operations. - * - a process does a select on the same filp but using different file - * descriptors. - * - the select has a timeout. Upon receiving this reply the operations might - * not be ready yet, so we want to wait for that to ultimately happen. - * Therefore we need to keep remembering what the operations are. */ - if (!(f->filp_select_flags & (FSF_UPDATE|FSF_BLOCKED))) - f->filp_select_ops = 0; /* done selecting */ - else if (!(f->filp_select_flags & FSF_UPDATE)) - f->filp_select_ops &= ~status; /* there may be operations pending */ + /* Process select result only if requestor is still around. That is, the + * corresponding filp is still in use. + */ + if (f->filp_count >= 1) { + select_lock_filp(f, f->filp_select_ops); + f->filp_select_flags &= ~FSF_BUSY; - /* Tell filp owners about result unless we need to wait longer */ - if (!(status == 0 && (f->filp_select_flags & FSF_BLOCKED))) { - if (status > 0) { /* operations ready */ - if (status & SEL_RD) f->filp_select_flags &= ~FSF_RD_BLOCK; - if (status & SEL_WR) f->filp_select_flags &= ~FSF_WR_BLOCK; - if (status & SEL_ERR) f->filp_select_flags &= ~FSF_ERR_BLOCK; - } else if (status < 0) /* error */ - f->filp_select_flags &= ~FSF_BLOCKED; /* No longer blocking */ - filp_status(f, status); /* Tell filp owners about the results */ + /* The select call is done now, except when + * - another process started a select on the same filp with possibly a + * different set of operations. + * - a process does a select on the same filp but using different file + * descriptors. + * - the select has a timeout. Upon receiving this reply the operations + * might not be ready yet, so we want to wait for that to ultimately + * happen. + * Therefore we need to keep remembering what the operations are. + */ + if (!(f->filp_select_flags & (FSF_UPDATE|FSF_BLOCKED))) + f->filp_select_ops = 0; /* done selecting */ + else if (!(f->filp_select_flags & FSF_UPDATE)) + /* there may be operations pending */ + f->filp_select_ops &= ~status; + + /* Tell filp owners about result unless we need to wait longer */ + if (!(status == 0 && (f->filp_select_flags & FSF_BLOCKED))) { + if (status > 0) { /* operations ready */ + if (status & SEL_RD) + f->filp_select_flags &= ~FSF_RD_BLOCK; + if (status & SEL_WR) + f->filp_select_flags &= ~FSF_WR_BLOCK; + if (status & SEL_ERR) + f->filp_select_flags &= ~FSF_ERR_BLOCK; + } else if (status < 0) { /* error */ + /* Always unblock upon error */ + f->filp_select_flags &= ~FSF_BLOCKED; + } + + unlock_filp(f); + filp_status(f, status); /* Tell filp owners about the results */ + } else { + unlock_filp(f); + } } select_restart_filps(); @@ -841,9 +872,9 @@ int status; struct selectentry *se; if (status == 0) { - printf("VFS (%s:%d): weird status (%d) to report\n", - __FILE__, __LINE__, status); - return; + printf("VFS (%s:%d): weird status (%d) to report\n", + __FILE__, __LINE__, status); + return; } /* Figure out which device is replying */ @@ -857,19 +888,21 @@ int status; /* Find all file descriptors selecting for this device */ for (slot = 0; slot < MAXSELECTS; slot++) { - se = &selecttab[slot]; + se = &selecttab[slot]; if (se->requestor == NULL) continue; /* empty slot */ - + for (fd = 0; fd < se->nfds; fd++) { if ((f = se->filps[fd]) == NULL) continue; if ((vp = f->filp_vno) == NULL) continue; if ((vp->v_mode & I_TYPE) != I_CHAR_SPECIAL) continue; if (vp->v_sdev != dev) continue; + + select_lock_filp(f, f->filp_select_ops); if (status > 0) { /* Operations ready */ /* Clear the replied bits from the request * mask unless FSF_UPDATE is set. */ - if (!(f->filp_select_flags & FSF_UPDATE)) + if (!(f->filp_select_flags & FSF_UPDATE)) f->filp_select_ops &= ~status; if (status & SEL_RD) f->filp_select_flags &= ~FSF_RD_BLOCK; @@ -880,10 +913,10 @@ int status; ops2tab(status, fd, se); } else { - f->filp_select_flags &= ~FSF_BLOCKED; + f->filp_select_flags &= ~FSF_BLOCKED; ops2tab(SEL_RD|SEL_WR|SEL_ERR, fd, se); } - + unlock_filp(f); if (se->nreadyfds > 0) restart_proc(se); } } @@ -910,7 +943,7 @@ PRIVATE void select_restart_filps() if (!is_deferred(se)) continue; /* Find filps that are not waiting for a reply, but have an updated - * status (i.e., another select on the same filp with possibly a + * status (i.e., another select on the same filp with possibly a * different set of operations is to be done), and thus requires the * select request to be sent again). */ @@ -922,11 +955,12 @@ PRIVATE void select_restart_filps() if (!(f->filp_select_flags & FSF_UPDATE)) /* Must be in */ continue; /* 'update' state */ - vp = f->filp_vno; - assert(vp != NULL); - assert((vp->v_mode & I_TYPE) == I_CHAR_SPECIAL); wantops = ops = f->filp_select_ops; + select_lock_filp(f, ops); + vp = f->filp_vno; + assert((vp->v_mode & I_TYPE) == I_CHAR_SPECIAL); r = do_select_request(se, fd, &wantops); + unlock_filp(f); if (r != SEL_OK) { if (r == SEL_DEFERRED) continue; else break; /* Error or bogus return code; abort */ @@ -946,17 +980,16 @@ int *ops; { /* Perform actual select request for file descriptor fd */ - int r, type, block; + int r, type; struct filp *f; type = se->type[fd]; - block = se->block; f = se->filps[fd]; - r = fdtypes[type].select_request(f, ops, block); + r = fdtypes[type].select_request(f, ops, se->block); if (r != SEL_OK && r != SEL_DEFERRED) { se->error = EINTR; se->block = 0; /* Stop blocking to return asap */ - select_cancel_all(se); + if (!is_deferred(se)) select_cancel_all(se); } return(r); @@ -981,7 +1014,7 @@ int status; if (se->filps[fd] != f) continue; if (status < 0) ops2tab(SEL_RD|SEL_WR|SEL_ERR, fd, se); - else + else ops2tab(status, fd, se); restart_proc(se); } @@ -997,7 +1030,7 @@ struct selectentry *se; /* Tell process about select results (if any) unless there are still results * pending. */ - if ((se->nreadyfds > 0 || !se->block) && !is_deferred(se)) + if ((se->nreadyfds > 0 || !se->block) && !is_deferred(se)) select_return(se); } @@ -1009,7 +1042,8 @@ PRIVATE void wipe_select(struct selectentry *se) se->nfds = 0; se->nreadyfds = 0; se->error = OK; - memset(se->filps, 0, sizeof(se->filps)); + se->block = 0; + memset(se->filps, 0, sizeof(se->filps)); FD_ZERO(&se->readfds); FD_ZERO(&se->writefds); @@ -1019,3 +1053,19 @@ PRIVATE void wipe_select(struct selectentry *se) FD_ZERO(&se->ready_errorfds); } +/*===========================================================================* + * select_lock_filp * + *===========================================================================*/ +PRIVATE void select_lock_filp(struct filp *f, int ops) +{ +/* Lock a filp and vnode based on which operations are requested */ + tll_access_t locktype;; + + locktype = VNODE_READ; /* By default */ + + if (ops & (SEL_WR|SEL_ERR)) + /* Selecting for error or writing requires exclusive access */ + locktype = VNODE_WRITE; + + lock_filp(f, locktype); +} diff --git a/servers/vfs/select.h b/servers/vfs/select.h index 4f5d76019..5215b1a90 100644 --- a/servers/vfs/select.h +++ b/servers/vfs/select.h @@ -1,5 +1,5 @@ -#ifndef _FS_SELECT_H -#define _FS_SELECT_H 1 +#ifndef __VFS_SELECT_H__ +#define __VFS_SELECT_H__ /* return codes for select_request_* and select_cancel_* */ #define SEL_OK 0 /* ready */ @@ -7,4 +7,3 @@ #define SEL_DEFERRED 2 /* request is sent to driver */ #endif - diff --git a/servers/vfs/stadir.c b/servers/vfs/stadir.c index 8f8da3059..bc49bf9c4 100644 --- a/servers/vfs/stadir.c +++ b/servers/vfs/stadir.c @@ -20,6 +20,7 @@ #include #include "file.h" #include "fproc.h" +#include "path.h" #include "param.h" #include #include @@ -29,7 +30,6 @@ FORWARD _PROTOTYPE( int change, (struct vnode **iip, char *name_ptr, int len)); FORWARD _PROTOTYPE( int change_into, (struct vnode **iip, struct vnode *vp)); - /*===========================================================================* * do_fchdir * *===========================================================================*/ @@ -37,14 +37,15 @@ PUBLIC int do_fchdir() { /* Change directory on already-opened fd. */ struct filp *rfilp; + int r; /* Is the file descriptor valid? */ - if ((rfilp = get_filp(m_in.fd)) == NULL) return(err_code); - dup_vnode(rfilp->filp_vno); /* Change into expects a reference. */ - return change_into(&fp->fp_wd, rfilp->filp_vno); + if ((rfilp = get_filp(m_in.fd, VNODE_READ)) == NULL) return(err_code); + r = change_into(&fp->fp_wd, rfilp->filp_vno); + unlock_filp(rfilp); + return(r); } - /*===========================================================================* * do_chdir * *===========================================================================*/ @@ -55,7 +56,6 @@ PUBLIC int do_chdir() return change(&fp->fp_wd, m_in.name, m_in.name_length); } - /*===========================================================================* * do_chroot * *===========================================================================*/ @@ -67,7 +67,6 @@ PUBLIC int do_chroot() return change(&fp->fp_rd, m_in.name, m_in.name_length); } - /*===========================================================================* * change * *===========================================================================*/ @@ -78,14 +77,25 @@ int len; /* length of the directory name string */ { /* Do the actual work for chdir() and chroot(). */ struct vnode *vp; + struct vmnt *vmp; + char fullpath[PATH_MAX]; + struct lookup resolve; + int r; + + lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); + resolve.l_vmnt_lock = VMNT_READ; + resolve.l_vnode_lock = VNODE_READ; /* Try to open the directory */ - if (fetch_name(name_ptr, len, M3) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); - return change_into(iip, vp); + if (fetch_name(name_ptr, len, M3, fullpath) != OK) return(err_code); + if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); + r = change_into(iip, vp); + unlock_vnode(vp); + unlock_vmnt(vmp); + put_vnode(vp); + return(r); } - /*===========================================================================* * change_into * *===========================================================================*/ @@ -95,25 +105,22 @@ struct vnode *vp; /* this is what the inode has to become */ { int r; + if (*iip == vp) return(OK); /* Nothing to do */ + /* It must be a directory and also be searchable */ if ((vp->v_mode & I_TYPE) != I_DIRECTORY) - r = ENOTDIR; + r = ENOTDIR; else r = forbidden(fp, vp, X_BIT); /* Check if dir is searchable*/ - - /* If error, return vnode */ - if (r != OK) { - put_vnode(vp); - return(r); - } + if (r != OK) return(r); /* Everything is OK. Make the change. */ put_vnode(*iip); /* release the old directory */ + dup_vnode(vp); *iip = vp; /* acquire the new one */ return(OK); } - /*===========================================================================* * do_stat * *===========================================================================*/ @@ -122,20 +129,30 @@ PUBLIC int do_stat() /* Perform the stat(name, buf) system call. */ int r; struct vnode *vp; + struct vmnt *vmp; + char fullpath[PATH_MAX]; + struct lookup resolve; int old_stat = 0; + lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); + resolve.l_vmnt_lock = VMNT_READ; + resolve.l_vnode_lock = VNODE_READ; + if (call_nr == PREV_STAT) old_stat = 1; - if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); + if (fetch_name(m_in.name1, m_in.name1_length, M1, fullpath) != OK) + return(err_code); + if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); r = req_stat(vp->v_fs_e, vp->v_inode_nr, who_e, m_in.name2, 0, old_stat); + unlock_vnode(vp); + unlock_vmnt(vmp); + put_vnode(vp); return r; } - /*===========================================================================* * do_fstat * *===========================================================================*/ @@ -143,6 +160,7 @@ PUBLIC int do_fstat() { /* Perform the fstat(fd, buf) system call. */ register struct filp *rfilp; + int r; int pipe_pos = 0; int old_stat = 0; @@ -150,21 +168,24 @@ PUBLIC int do_fstat() old_stat = 1; /* Is the file descriptor valid? */ - if ((rfilp = get_filp(m_in.fd)) == NULL) return(err_code); - + if ((rfilp = get_filp(m_in.fd, VNODE_READ)) == NULL) return(err_code); + /* If we read from a pipe, send position too */ if (rfilp->filp_vno->v_pipe == I_PIPE) { - if (rfilp->filp_mode & R_BIT) + if (rfilp->filp_mode & R_BIT) if (ex64hi(rfilp->filp_pos) != 0) { panic("do_fstat: bad position in pipe"); } pipe_pos = ex64lo(rfilp->filp_pos); } - return req_stat(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr, - who_e, m_in.buffer, pipe_pos, old_stat); -} + r = req_stat(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr, + who_e, m_in.buffer, pipe_pos, old_stat); + unlock_filp(rfilp); + + return(r); +} /*===========================================================================* * do_fstatfs * @@ -173,11 +194,16 @@ PUBLIC int do_fstatfs() { /* Perform the fstatfs(fd, buf) system call. */ struct filp *rfilp; + int r; /* Is the file descriptor valid? */ - if( (rfilp = get_filp(m_in.fd)) == NULL) return(err_code); + if( (rfilp = get_filp(m_in.fd, VNODE_READ)) == NULL) return(err_code); - return req_fstatfs(rfilp->filp_vno->v_fs_e, who_e, m_in.buffer); + r = req_fstatfs(rfilp->filp_vno->v_fs_e, who_e, m_in.buffer); + + unlock_filp(rfilp); + + return(r); } /*===========================================================================* @@ -188,16 +214,26 @@ PUBLIC int do_statvfs() /* Perform the stat(name, buf) system call. */ int r; struct vnode *vp; + struct vmnt *vmp; + char fullpath[PATH_MAX]; + struct lookup resolve; - if (fetch_name(m_in.STATVFS_NAME, m_in.STATVFS_LEN, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); + lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); + resolve.l_vmnt_lock = VMNT_READ; + resolve.l_vnode_lock = VNODE_READ; + + if (fetch_name(m_in.STATVFS_NAME, m_in.STATVFS_LEN, M1, fullpath) != OK) + return(err_code); + if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); r = req_statvfs(vp->v_fs_e, who_e, m_in.STATVFS_BUF); + unlock_vnode(vp); + unlock_vmnt(vmp); + put_vnode(vp); return r; } - /*===========================================================================* * do_fstatvfs * *===========================================================================*/ @@ -205,13 +241,18 @@ PUBLIC int do_fstatvfs() { /* Perform the fstat(fd, buf) system call. */ register struct filp *rfilp; + int r; /* Is the file descriptor valid? */ - if ((rfilp = get_filp(m_in.FSTATVFS_FD)) == NULL) return(err_code); - - return req_statvfs(rfilp->filp_vno->v_fs_e, who_e, m_in.FSTATVFS_BUF); -} + if ((rfilp = get_filp(m_in.FSTATVFS_FD, VNODE_READ)) == NULL) + return(err_code); + r = req_statvfs(rfilp->filp_vno->v_fs_e, who_e, m_in.FSTATVFS_BUF); + + unlock_filp(rfilp); + + return(r); +} /*===========================================================================* * do_lstat * @@ -220,18 +261,27 @@ PUBLIC int do_lstat() { /* Perform the lstat(name, buf) system call. */ struct vnode *vp; + struct vmnt *vmp; int r; + char fullpath[PATH_MAX]; + struct lookup resolve; int old_stat = 0; + lookup_init(&resolve, fullpath, PATH_RET_SYMLINK, &vmp, &vp); + resolve.l_vmnt_lock = VMNT_READ; + resolve.l_vnode_lock = VNODE_READ; + if (call_nr == PREV_LSTAT) old_stat = 1; + if (fetch_name(m_in.name1, m_in.name1_length, M1, fullpath) != OK) + return(err_code); - if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_RET_SYMLINK, fp)) == NULL) return(err_code); + if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); r = req_stat(vp->v_fs_e, vp->v_inode_nr, who_e, m_in.name2, 0, old_stat); + unlock_vnode(vp); + unlock_vmnt(vmp); + put_vnode(vp); return(r); } - - diff --git a/servers/vfs/table.c b/servers/vfs/table.c index 5b59ca9b5..4429e3192 100644 --- a/servers/vfs/table.c +++ b/servers/vfs/table.c @@ -10,10 +10,10 @@ #include "file.h" #include "fproc.h" #include "lock.h" +#include "scratchpad.h" #include "vnode.h" #include "vmnt.h" - PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = { no_sys, /* 0 = unused */ no_sys, /* 1 = (exit) */ @@ -46,11 +46,11 @@ PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = { do_fstat, /* 28 = fstat (prev)*/ no_sys, /* 29 = pause */ do_utime, /* 30 = utime */ - no_sys, /* 31 = unused */ - no_sys, /* 32 = unused */ + no_sys, /* 31 = (stty) */ + no_sys, /* 32 = (gtty) */ do_access, /* 33 = access */ - no_sys, /* 34 = unused */ - no_sys, /* 35 = unused */ + no_sys, /* 34 = (nice) */ + no_sys, /* 35 = (ftime) */ do_sync, /* 36 = sync */ no_sys, /* 37 = kill */ do_rename, /* 38 = rename */ @@ -59,7 +59,7 @@ PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = { do_dup, /* 41 = dup */ do_pipe, /* 42 = pipe */ no_sys, /* 43 = times */ - no_sys, /* 44 = unused */ + no_sys, /* 44 = (prof) */ do_slink, /* 45 = symlink */ no_sys, /* 46 = (setgid)*/ no_sys, /* 47 = getgid */ @@ -71,8 +71,8 @@ PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = { do_lstat, /* 53 = lstat */ do_ioctl, /* 54 = ioctl */ do_fcntl, /* 55 = fcntl */ - no_sys, /* 56 = unused */ - do_fslogin, /* 57 = FS proc login */ + no_sys, /* 56 = (mpx) */ + do_fsready, /* 57 = FS proc ready */ no_sys, /* 58 = unused */ no_sys, /* 59 = (execve)*/ do_umask, /* 60 = umask */ @@ -137,7 +137,7 @@ PUBLIC _PROTOTYPE (int (*pfs_call_vec[]), (void) ) = { no_sys, /* 0 */ do_check_perms, /* 1 */ - do_verify_fd, /* 2 */ + do_verify_fd, /* 2 */ do_set_filp, /* 3 */ do_copy_filp, /* 4 */ do_put_filp, /* 5 */ diff --git a/servers/avfs/threads.h b/servers/vfs/threads.h similarity index 100% rename from servers/avfs/threads.h rename to servers/vfs/threads.h diff --git a/servers/vfs/time.c b/servers/vfs/time.c index 491adeb5d..29b84e320 100644 --- a/servers/vfs/time.c +++ b/servers/vfs/time.c @@ -9,6 +9,7 @@ #include #include "file.h" #include "fproc.h" +#include "path.h" #include "param.h" #include "vnode.h" #include @@ -24,21 +25,28 @@ PUBLIC int do_utime() int r; time_t actime, modtime; struct vnode *vp; - + struct vmnt *vmp; + char fullpath[PATH_MAX]; + struct lookup resolve; + + lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); + resolve.l_vmnt_lock = VMNT_WRITE; + resolve.l_vnode_lock = VNODE_READ; + /* Adjust for case of 'timep' being NULL; * utime_strlen then holds the actual size: strlen(name)+1 */ len = m_in.utime_length; - if(len == 0) len = m_in.utime_strlen; + if (len == 0) len = m_in.utime_strlen; /* Temporarily open the file */ - if (fetch_name(m_in.utime_file, len, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); + if (fetch_name(m_in.utime_file, len, M1, fullpath) != OK) return(err_code); + if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); - /* Only the owner of a file or the super user can change its name. */ + /* Only the owner of a file or the super user can change its name. */ r = OK; if (vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID) r = EPERM; if (m_in.utime_length == 0 && r != OK) r = forbidden(fp, vp, W_BIT); - if (read_only(vp) != OK) r = EROFS; /* Not even su can touch if R/O */ + if (read_only(vp) != OK) r = EROFS; /* Not even su can touch if R/O */ if (r == OK) { /* Issue request */ if(m_in.utime_length == 0) { @@ -50,7 +58,9 @@ PUBLIC int do_utime() r = req_utime(vp->v_fs_e, vp->v_inode_nr, actime, modtime); } + unlock_vnode(vp); + unlock_vmnt(vmp); + put_vnode(vp); return(r); } - diff --git a/servers/avfs/tll.c b/servers/vfs/tll.c similarity index 100% rename from servers/avfs/tll.c rename to servers/vfs/tll.c diff --git a/servers/avfs/tll.h b/servers/vfs/tll.h similarity index 100% rename from servers/avfs/tll.h rename to servers/vfs/tll.h diff --git a/servers/vfs/utility.c b/servers/vfs/utility.c index 79227fb52..71922d84a 100644 --- a/servers/vfs/utility.c +++ b/servers/vfs/utility.c @@ -25,10 +25,11 @@ /*===========================================================================* * fetch_name * *===========================================================================*/ -PUBLIC int fetch_name(path, len, flag) +PUBLIC int fetch_name(path, len, flag, dest) char *path; /* pointer to the path in user space */ int len; /* path length, including 0 byte */ int flag; /* M3 means path may be in message */ +char *dest; /* pointer to where path is to be stored */ { /* Go get path and put it in 'user_fullpath'. * If 'flag' = M3 and 'len' <= M3_STRING, the path is present in 'message'. @@ -42,9 +43,6 @@ int flag; /* M3 means path may be in message */ return(EGENERIC); } - if (len > sizeof(user_fullpath)) - panic("fetch_name: len too much for user_fullpath: %d", len); - /* Check name length for validity. */ if (len <= 0) { err_code = EINVAL; @@ -53,7 +51,7 @@ int flag; /* M3 means path may be in message */ if (flag == M3 && len <= M3_STRING) { /* Just copy the path from the message to 'user_fullpath'. */ - rpu = &user_fullpath[0]; + rpu = &dest[0]; rpm = m_in.pathname; /* contained in input message */ count = len; do { *rpu++ = *rpm++; } while (--count); @@ -61,12 +59,12 @@ int flag; /* M3 means path may be in message */ } else { /* String is not contained in the message. Get it from user space. */ r = sys_datacopy(who_e, (vir_bytes) path, - VFS_PROC_NR, (vir_bytes) user_fullpath, (phys_bytes) len); + VFS_PROC_NR, (vir_bytes) dest, (phys_bytes) len); } - if (user_fullpath[len - 1] != '\0') { - err_code = ENAMETOOLONG; - return(EGENERIC); + if (dest[len - 1] != '\0') { + err_code = ENAMETOOLONG; + return(EGENERIC); } return(r); @@ -91,20 +89,20 @@ PUBLIC int isokendpt_f(char *file, int line, endpoint_t endpoint, int *proc, int int failed = 0; endpoint_t ke; *proc = _ENDPOINT_P(endpoint); - if(endpoint == NONE) { - printf("vfs:%s:%d: endpoint is NONE\n", file, line); + if (endpoint == NONE) { + printf("VFS %s:%d: endpoint is NONE\n", file, line); failed = 1; - } else if(*proc < 0 || *proc >= NR_PROCS) { - printf("vfs:%s:%d: proc (%d) from endpoint (%d) out of range\n", + } else if (*proc < 0 || *proc >= NR_PROCS) { + printf("VFS %s:%d: proc (%d) from endpoint (%d) out of range\n", file, line, *proc, endpoint); failed = 1; - } else if((ke=fproc[*proc].fp_endpoint) != endpoint) { + } else if ((ke = fproc[*proc].fp_endpoint) != endpoint) { if(ke == NONE) { - printf("vfs:%s:%d: endpoint (%d) points to NONE slot (%d)\n", - file, line, endpoint, *proc); + printf("VFS %s:%d: endpoint (%d) points to NONE slot (%d)\n", + file, line, endpoint, *proc); assert(fproc[*proc].fp_pid == PID_FREE); - } else { - printf("vfs:%s:%d: proc (%d) from endpoint (%d) doesn't match " + } else { + printf("VFS %s:%d: proc (%d) from endpoint (%d) doesn't match " "known endpoint (%d)\n", file, line, *proc, endpoint, fproc[*proc].fp_endpoint); assert(fproc[*proc].fp_pid != PID_FREE); @@ -147,12 +145,9 @@ PUBLIC int in_group(struct fproc *rfp, gid_t grp) { int i; - for (i = 0; i < rfp->fp_ngroups; i++) { - if (rfp->fp_sgroups[i] == grp) { + for (i = 0; i < rfp->fp_ngroups; i++) + if (rfp->fp_sgroups[i] == grp) return(OK); - } - } return(EINVAL); } - diff --git a/servers/vfs/vmnt.c b/servers/vfs/vmnt.c index 842abc1cc..bb3dc0746 100644 --- a/servers/vfs/vmnt.c +++ b/servers/vfs/vmnt.c @@ -3,33 +3,199 @@ */ #include "fs.h" +#include "threads.h" #include "vmnt.h" +#include +#include "fproc.h" +FORWARD _PROTOTYPE( int is_vmnt_locked, (struct vmnt *vmp) ); +FORWARD _PROTOTYPE( void clear_vmnt, (struct vmnt *vmp) ); + +/* Is vmp pointer reasonable? */ +#define SANEVMP(v) ((((v) >= &vmnt[0] && (v) < &vmnt[NR_MNTS]))) +#define BADVMP(v, f, l) printf("%s:%d: bad vmp %p\n", f, l, v) +/* vp check that panics */ +#define ASSERTVMP(v) if(!SANEVMP(v)) { \ + BADVMP(v, __FILE__, __LINE__); panic("bad vmp"); } + +#if LOCK_DEBUG +/*===========================================================================* + * check_vmnt_locks_by_me * + *===========================================================================*/ +PUBLIC void check_vmnt_locks_by_me(struct fproc *rfp) +{ +/* Check whether this thread still has locks held on vmnts */ + struct vmnt *vmp; + + for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) { + if (tll_locked_by_me(&vmp->m_lock)) + panic("Thread %d still holds vmnt lock on vmp %p call_nr=%d\n", + mthread_self(), vmp, call_nr); + } + + if (rfp->fp_vmnt_rdlocks != 0) + panic("Thread %d still holds read locks on a vmnt (%d) call_nr=%d\n", + mthread_self(), rfp->fp_vmnt_rdlocks, call_nr); +} +#endif + +/*===========================================================================* + * check_vmnt_locks * + *===========================================================================*/ +PUBLIC void check_vmnt_locks() +{ + struct vmnt *vmp; + int count = 0; + + for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) + if (is_vmnt_locked(vmp)) { + count++; + printf("vmnt %p is %s, fs_e=%d dev=%d\n", vmp, (tll_islocked(&vmp->m_lock) ? "locked":"pending locked"), vmp->m_fs_e, vmp->m_dev); + } + + if (count) panic("%d locked vmnts\n", count); +#if 0 + printf("check_vmnt_locks OK\n"); +#endif +} + +/*===========================================================================* + * clear_vmnt * + *===========================================================================*/ +PRIVATE void clear_vmnt(struct vmnt *vmp) +{ +/* Reset vmp to initial parameters */ + ASSERTVMP(vmp); + + vmp->m_fs_e = NONE; + vmp->m_dev = NO_DEV; + vmp->m_flags = 0; + vmp->m_mounted_on = NULL; + vmp->m_root_node = NULL; + vmp->m_label[0] = '\0'; + vmp->m_comm.c_max_reqs = 1; + vmp->m_comm.c_cur_reqs = 0; + vmp->m_comm.c_req_queue = NULL; +} /*===========================================================================* * get_free_vmnt * *===========================================================================*/ -PUBLIC struct vmnt *get_free_vmnt(short *index) +PUBLIC struct vmnt *get_free_vmnt(void) { struct vmnt *vp; - *index = 0; - for (vp = &vmnt[0]; vp < &vmnt[NR_MNTS]; ++vp, ++(*index)) + + for (vp = &vmnt[0]; vp < &vmnt[NR_MNTS]; ++vp) if (vp->m_dev == NO_DEV) return(vp); return(NULL); } - /*===========================================================================* * find_vmnt * *===========================================================================*/ -PUBLIC struct vmnt *find_vmnt(int fs_e) +PUBLIC struct vmnt *find_vmnt(endpoint_t fs_e) { +/* Find the vmnt belonging to an FS with endpoint 'fs_e' iff it's in use */ struct vmnt *vp; - for (vp = &vmnt[0]; vp < &vmnt[NR_MNTS]; ++vp) - if (vp->m_fs_e == fs_e) return(vp); + + for (vp = &vmnt[0]; vp < &vmnt[NR_MNTS]; ++vp) + if (vp->m_fs_e == fs_e && vp->m_dev != NO_DEV) + return(vp); return(NULL); } +/*===========================================================================* + * init_vmnts * + *===========================================================================*/ +PUBLIC void init_vmnts(void) +{ +/* Initialize vmnt table */ + struct vmnt *vmp; + for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) { + clear_vmnt(vmp); + tll_init(&vmp->m_lock); + } +} + +/*===========================================================================* + * is_vmnt_locked * + *===========================================================================*/ +PRIVATE int is_vmnt_locked(struct vmnt *vmp) +{ + ASSERTVMP(vmp); + return(tll_islocked(&vmp->m_lock) || tll_haspendinglock(&vmp->m_lock)); +} + +/*===========================================================================* + * lock_vmnt * + *===========================================================================*/ +PUBLIC int lock_vmnt(struct vmnt *vmp, tll_access_t locktype) +{ + int r; + tll_access_t initial_locktype; + + ASSERTVMP(vmp); + + initial_locktype = (locktype == VMNT_EXCL) ? VMNT_WRITE : locktype; + + if (vmp->m_fs_e == who_e) return(EDEADLK); + + r = tll_lock(&vmp->m_lock, initial_locktype); + + if (r == EBUSY) return(r); + + if (initial_locktype != locktype) { + tll_upgrade(&vmp->m_lock); + } + +#if LOCK_DEBUG + if (locktype == VMNT_READ) + fp->fp_vmnt_rdlocks++; +#endif + + return(OK); +} + +/*===========================================================================* + * vmnt_unmap_by_endpoint * + *===========================================================================*/ +PUBLIC void vmnt_unmap_by_endpt(endpoint_t proc_e) +{ + struct vmnt *vmp; + + if ((vmp = find_vmnt(proc_e)) != NULL) { + fs_cancel(vmp); + invalidate_filp_by_endpt(proc_e); + if (vmp->m_mounted_on) { + /* Only put mount point when it was actually used as mount + * point. That is, the mount was succesful. */ + put_vnode(vmp->m_mounted_on); + } + clear_vmnt(vmp); + } +} + +/*===========================================================================* + * unlock_vmnt * + *===========================================================================*/ +PUBLIC void unlock_vmnt(struct vmnt *vmp) +{ + ASSERTVMP(vmp); + +#if LOCK_DEBUG + /* Decrease read-only lock counter when not locked as VMNT_WRITE or + * VMNT_EXCL */ + if (!tll_locked_by_me(&vmp->m_lock)) + fp->fp_vmnt_rdlocks--; +#endif + + tll_unlock(&vmp->m_lock); + +#if LOCK_DEBUG + assert(!tll_locked_by_me(&vmp->m_lock)); +#endif + +} diff --git a/servers/vfs/vmnt.h b/servers/vfs/vmnt.h index 390d93e67..14d00b3ab 100644 --- a/servers/vfs/vmnt.h +++ b/servers/vfs/vmnt.h @@ -1,11 +1,26 @@ - +#ifndef __VFS_VMNT_H__ +#define __VFS_VMNT_H__ EXTERN struct vmnt { - int m_fs_e; /* FS process' kernel endpoint */ - dev_t m_dev; /* device number */ - int m_flags; /* mount flags */ - struct vnode *m_mounted_on; /* vnode on which the partition is mounted */ - struct vnode *m_root_node; /* root vnode */ + int m_fs_e; /* FS process' kernel endpoint */ + tll_t m_lock; + comm_t m_comm; + dev_t m_dev; /* device number */ + unsigned int m_flags; /* mount flags */ + struct vnode *m_mounted_on; /* vnode on which the partition is mounted */ + struct vnode *m_root_node; /* root vnode */ char m_label[LABEL_MAX]; /* label of the file system process */ } vmnt[NR_MNTS]; +/* vmnt flags */ +#define VMNT_READONLY 01 /* Device mounted readonly */ +#define VMNT_CALLBACK 02 /* FS did back call */ +#define VMNT_MOUNTING 04 /* Device is being mounted */ +#define VMNT_FORCEROOTBSF 010 /* Force usage of none-device */ + +/* vmnt lock types mapping */ +#define VMNT_READ TLL_READ +#define VMNT_WRITE TLL_READSER +#define VMNT_EXCL TLL_WRITE + +#endif diff --git a/servers/vfs/vnode.c b/servers/vfs/vnode.c index 9e1a9e03a..ad854f732 100644 --- a/servers/vfs/vnode.c +++ b/servers/vfs/vnode.c @@ -1,19 +1,21 @@ /* This file contains the routines related to vnodes. * The entry points are: - * + * * get_vnode - increase counter and get details of an inode * get_free_vnode - get a pointer to a free vnode obj - * find_vnode - find a vnode according to the FS endpoint and the inode num. + * find_vnode - find a vnode according to the FS endpoint and the inode num. * dup_vnode - duplicate vnode (i.e. increase counter) - * put_vnode - drop vnode (i.e. decrease counter) + * put_vnode - drop vnode (i.e. decrease counter) */ #include "fs.h" +#include "threads.h" #include "vnode.h" #include "vmnt.h" #include "fproc.h" #include "file.h" #include +#include /* Is vnode pointer reasonable? */ #if NDEBUG @@ -36,6 +38,47 @@ BADVP(v, __FILE__, __LINE__); panic("bad vp"); } #endif +#if LOCK_DEBUG +/*===========================================================================* + * check_vnode_locks_by_me * + *===========================================================================*/ +PUBLIC void check_vnode_locks_by_me(struct fproc *rfp) +{ +/* Check whether this thread still has locks held on vnodes */ + struct vnode *vp; + + for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; vp++) { + if (tll_locked_by_me(&vp->v_lock)) { + panic("Thread %d still holds vnode lock on vp %x call_nr=%d\n", + mthread_self(), vp, call_nr); + } + } + + if (rfp->fp_vp_rdlocks != 0) + panic("Thread %d still holds read locks on a vnode (%d) call_nr=%d\n", + mthread_self(), rfp->fp_vp_rdlocks, call_nr); +} +#endif + +/*===========================================================================* + * check_vnode_locks * + *===========================================================================*/ +PUBLIC void check_vnode_locks() +{ + struct vnode *vp; + int count = 0; + + for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; vp++) + if (is_vnode_locked(vp)) { + count++; + } + + if (count) panic("%d locked vnodes\n", count); +#if 0 + printf("check_vnode_locks OK\n"); +#endif +} + /*===========================================================================* * get_free_vnode * *===========================================================================*/ @@ -45,16 +88,17 @@ PUBLIC struct vnode *get_free_vnode() struct vnode *vp; for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; ++vp) { - if (vp->v_ref_count == 0) { + if (vp->v_ref_count == 0 && !is_vnode_locked(vp)) { vp->v_pipe = NO_PIPE; vp->v_uid = -1; vp->v_gid = -1; vp->v_sdev = NO_DEV; - vp->v_mapfs_e = 0; + vp->v_mapfs_e = NONE; + vp->v_mapfs_count = 0; vp->v_mapinode_nr = 0; return(vp); } - } + } err_code = ENFILE; return(NULL); @@ -64,19 +108,110 @@ PUBLIC struct vnode *get_free_vnode() /*===========================================================================* * find_vnode * *===========================================================================*/ -PUBLIC struct vnode *find_vnode(int fs_e, int numb) +PUBLIC struct vnode *find_vnode(int fs_e, int ino) { /* Find a specified (FS endpoint and inode number) vnode in the * vnode table */ struct vnode *vp; for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; ++vp) - if (vp->v_ref_count > 0 && vp->v_inode_nr == numb && vp->v_fs_e == fs_e) + if (vp->v_ref_count > 0 && vp->v_inode_nr == ino && vp->v_fs_e == fs_e) return(vp); - + return(NULL); } +/*===========================================================================* + * is_vnode_locked * + *===========================================================================*/ +PUBLIC int is_vnode_locked(struct vnode *vp) +{ +/* Find out whether a thread holds a lock on this vnode or is trying to obtain + * a lock. */ + ASSERTVP(vp); + + return(tll_islocked(&vp->v_lock) || tll_haspendinglock(&vp->v_lock)); +} + +/*===========================================================================* + * init_vnodes * + *===========================================================================*/ +PUBLIC void init_vnodes(void) +{ + struct vnode *vp; + + for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; ++vp) { + vp->v_fs_e = NONE; + vp->v_mapfs_e = NONE; + vp->v_inode_nr = 0; + vp->v_ref_count = 0; + vp->v_fs_count = 0; + vp->v_mapfs_count = 0; + tll_init(&vp->v_lock); + } +} + +/*===========================================================================* + * lock_vnode * + *===========================================================================*/ +PUBLIC int lock_vnode(struct vnode *vp, tll_access_t locktype) +{ + int r; + + ASSERTVP(vp); + + r = tll_lock(&vp->v_lock, locktype); + +#if LOCK_DEBUG + if (locktype == VNODE_READ) { + fp->fp_vp_rdlocks++; + } +#endif + + if (r == EBUSY) return(r); + return(OK); +} + +/*===========================================================================* + * unlock_vnode * + *===========================================================================*/ +PUBLIC void unlock_vnode(struct vnode *vp) +{ +#if LOCK_DEBUG + int i; + register struct vnode *rvp; + struct worker_thread *w; +#endif + ASSERTVP(vp); + +#if LOCK_DEBUG + /* Decrease read-only lock counter when not locked as VNODE_OPCL or + * VNODE_WRITE */ + if (!tll_locked_by_me(&vp->v_lock)) { + fp->fp_vp_rdlocks--; + } + + for (i = 0; i < NR_VNODES; i++) { + rvp = &vnode[i]; + + w = rvp->v_lock.t_write; + assert(w != self); + while (w && w->w_next != NULL) { + w = w->w_next; + assert(w != self); + } + + w = rvp->v_lock.t_serial; + assert(w != self); + while (w && w->w_next != NULL) { + w = w->w_next; + assert(w != self); + } + } +#endif + + tll_unlock(&vp->v_lock); +} /*===========================================================================* * dup_vnode * @@ -96,7 +231,7 @@ PUBLIC void dup_vnode(struct vnode *vp) *===========================================================================*/ PUBLIC void put_vnode(struct vnode *vp) { -/* Decrease vnode's usage counter and decrease inode's usage counter in the +/* Decrease vnode's usage counter and decrease inode's usage counter in the * corresponding FS process. Decreasing the fs_count each time we decrease the * ref count would lead to poor performance. Instead, only decrease fs_count * when the ref count hits zero. However, this could lead to fs_count to wrap. @@ -104,45 +239,55 @@ PUBLIC void put_vnode(struct vnode *vp) * We maintain fs_count as a sanity check to make sure VFS and the FS are in * sync. */ + int r, lock_vp; + ASSERTVP(vp); + /* Lock vnode. It's quite possible this thread already has a lock on this + * vnode. That's no problem, because the reference counter will not decrease + * to zero in that case. However, if the counter does decrease to zero *and* + * is already locked, we have a consistency problem somewhere. */ + lock_vp = lock_vnode(vp, VNODE_OPCL); + if (vp->v_ref_count > 1) { /* Decrease counter */ vp->v_ref_count--; - if (vp->v_fs_count > 256) + if (vp->v_fs_count > 256) vnode_clean_refs(vp); - + if (lock_vp != EBUSY) unlock_vnode(vp); return; } - /* A vnode that's not in use can't be put. */ - if (vp->v_ref_count <= 0) { - printf("put_vnode: bad v_ref_count %d\n", vp->v_ref_count); - panic("put_vnode failed"); - } + /* If we already had a lock, there is a consistency problem */ + assert(lock_vp != EBUSY); + tll_upgrade(&vp->v_lock); /* Make sure nobody else accesses this vnode */ + + /* A vnode that's not in use can't be put back. */ + if (vp->v_ref_count <= 0) + panic("put_vnode failed: bad v_ref_count %d\n", vp->v_ref_count); /* fs_count should indicate that the file is in use. */ - if (vp->v_fs_count <= 0) { - printf("put_vnode: bad v_fs_count %d\n", vp->v_fs_count); - panic("put_vnode failed"); - } + if (vp->v_fs_count <= 0) + panic("put_vnode failed: bad v_fs_count %d\n", vp->v_fs_count); /* Tell FS we don't need this inode to be open anymore. */ - req_putnode(vp->v_fs_e, vp->v_inode_nr, vp->v_fs_count); + r = req_putnode(vp->v_fs_e, vp->v_inode_nr, vp->v_fs_count); - /* This inode could've been mapped. If so, tell PFS to close it as well. */ - if(vp->v_mapfs_e != 0 && vp->v_mapinode_nr != vp->v_inode_nr && - vp->v_mapfs_e != vp->v_fs_e) { - req_putnode(vp->v_mapfs_e, vp->v_mapinode_nr, vp->v_mapfs_count); + if (r != OK) { + printf("VFS: putnode failed: %d\n", r); + util_stacktrace(); } + /* This inode could've been mapped. If so, tell mapped FS to close it as + * well. If mapped onto same FS, this putnode is not needed. */ + if (vp->v_mapfs_e != NONE && vp->v_mapfs_e != vp->v_fs_e) + req_putnode(vp->v_mapfs_e, vp->v_mapinode_nr, vp->v_mapfs_count); + vp->v_fs_count = 0; vp->v_ref_count = 0; - vp->v_pipe = NO_PIPE; - vp->v_sdev = NO_DEV; - vp->v_mapfs_e = 0; - vp->v_mapinode_nr = 0; vp->v_mapfs_count = 0; + + unlock_vnode(vp); } @@ -187,7 +332,7 @@ PUBLIC int check_vrefs() continue; if(rfp->fp_rd) REFVP(rfp->fp_rd); if(rfp->fp_wd) REFVP(rfp->fp_wd); - } + } /* Count references from filedescriptors */ for (f = &filp[0]; f < &filp[NR_FILPS]; f++) diff --git a/servers/vfs/vnode.h b/servers/vfs/vnode.h index 9ce588d7e..babb6aab4 100644 --- a/servers/vfs/vnode.h +++ b/servers/vfs/vnode.h @@ -1,4 +1,5 @@ - +#ifndef __VFS_VNODE_H__ +#define __VFS_VNODE_H__ EXTERN struct vnode { endpoint_t v_fs_e; /* FS process' endpoint number */ @@ -20,10 +21,11 @@ EXTERN struct vnode { off_t v_pipe_wr_pos; endpoint_t v_bfs_e; /* endpoint number for the FS proces in case of a block special file */ - dev_t v_dev; /* device number on which the corresponding + dev_t v_dev; /* device number on which the corresponding inode resides */ dev_t v_sdev; /* device number for special files */ struct vmnt *v_vmnt; /* vmnt object of the partition */ + tll_t v_lock; /* three-level-lock */ } vnode[NR_VNODES]; @@ -31,3 +33,8 @@ EXTERN struct vnode { #define NO_PIPE 0 /* i_pipe is NO_PIPE if inode is not a pipe */ #define I_PIPE 1 /* i_pipe is I_PIPE if inode is a pipe */ +/* vnode lock types mapping */ +#define VNODE_READ TLL_READ +#define VNODE_OPCL TLL_READSER +#define VNODE_WRITE TLL_WRITE +#endif diff --git a/servers/avfs/worker.c b/servers/vfs/worker.c similarity index 100% rename from servers/avfs/worker.c rename to servers/vfs/worker.c diff --git a/servers/vfs/write.c b/servers/vfs/write.c index 6682ed2e7..a3e9d636e 100644 --- a/servers/vfs/write.c +++ b/servers/vfs/write.c @@ -7,7 +7,6 @@ #include "fs.h" #include "file.h" -#include "fproc.h" /*===========================================================================* @@ -16,6 +15,5 @@ PUBLIC int do_write() { /* Perform the write(fd, buffer, nbytes) system call. */ - return(read_write(WRITING)); + return(do_read_write(WRITING)); } - diff --git a/share/mk/bsd.own.mk b/share/mk/bsd.own.mk index fdcc62e38..8022426e6 100644 --- a/share/mk/bsd.own.mk +++ b/share/mk/bsd.own.mk @@ -12,8 +12,6 @@ SMP_FLAGS += -DCONFIG_MAX_CPUS=${CONFIG_MAX_CPUS} CPPFLAGS+= ${SMP_FLAGS} -BUILDAVFS?= "no" - MAKECONF?= /etc/make.conf .-include "${MAKECONF}" diff --git a/tools/Makefile b/tools/Makefile index 0e387adef..f2f6ad193 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -9,13 +9,6 @@ MDEC= /usr/mdec GEN_FILES= *.bak image kernel *.iso *.iso.gz cdfdimage rootimage src # Specify the programs that are part of the system image. -.if ${BUILDAVFS} == "yes" -VFS= avfs -PFS= apfs -.else -VFS= vfs -PFS= pfs -.endif KERNEL= kernel # PROGRAMS are in the order they should be loaded by boot PROGRAMS= \ @@ -23,13 +16,13 @@ PROGRAMS= \ ../servers/rs/rs \ ../servers/pm/pm \ ../servers/sched/sched \ - ../servers/${VFS}/vfs \ + ../servers/vfs/vfs \ ../drivers/memory/memory \ ../drivers/log/log \ ../drivers/tty/tty \ ../servers/mfs/mfs \ ../servers/vm/vm \ - ../servers/${PFS}/pfs \ + ../servers/pfs/pfs \ ../servers/init/init usage: