diff --git a/commands/bzip2-1.0.3/Makefile b/commands/bzip2-1.0.3/Makefile index a9790f293..54a54ef9a 100644 --- a/commands/bzip2-1.0.3/Makefile +++ b/commands/bzip2-1.0.3/Makefile @@ -12,7 +12,7 @@ BIGFILES=#-D_FILE_OFFSET_BITS=64 CFLAGS=-Wall -Winline -O -g $(BIGFILES) -Dlstat=stat -D_POSIX_SOURCE=1 # Where you want it installed when you do 'make install' -PREFIX=/usr/local +PREFIX=/usr PREFIX_BIN=$(PREFIX)/bin PREFIX_LIB=$(PREFIX)/lib PREFIX_MAN=$(PREFIX)/man diff --git a/commands/de/de.c b/commands/de/de.c index f5b5a1ecf..a8d93e379 100755 --- a/commands/de/de.c +++ b/commands/de/de.c @@ -27,9 +27,9 @@ #include #include -#include "../../servers/fs/const.h" -#include "../../servers/fs/type.h" -#include "../../servers/fs/inode.h" +#include "../../servers/mfs/const.h" +#include "../../servers/mfs/type.h" +#include "../../servers/mfs/inode.h" #include "de.h" diff --git a/commands/de/de_diskio.c b/commands/de/de_diskio.c index e4162782d..e14383bd9 100755 --- a/commands/de/de_diskio.c +++ b/commands/de/de_diskio.c @@ -18,10 +18,10 @@ #include #include -#include "../../servers/fs/const.h" -#include "../../servers/fs/type.h" -#include "../../servers/fs/super.h" -#include "../../servers/fs/inode.h" +#include "../../servers/mfs/const.h" +#include "../../servers/mfs/type.h" +#include "../../servers/mfs/super.h" +#include "../../servers/mfs/inode.h" #include #include "de.h" diff --git a/commands/de/de_recover.c b/commands/de/de_recover.c index add90cfc8..a26b4cc88 100755 --- a/commands/de/de_recover.c +++ b/commands/de/de_recover.c @@ -23,9 +23,9 @@ #include #include -#include "../../servers/fs/const.h" -#include "../../servers/fs/type.h" -#include "../../servers/fs/inode.h" +#include "../../servers/mfs/const.h" +#include "../../servers/mfs/type.h" +#include "../../servers/mfs/inode.h" #include #include "de.h" diff --git a/commands/de/de_stdin.c b/commands/de/de_stdin.c index 2bd2531eb..5f440d8d6 100755 --- a/commands/de/de_stdin.c +++ b/commands/de/de_stdin.c @@ -17,8 +17,8 @@ #include #include -#include "../../servers/fs/const.h" -#include "../../servers/fs/inode.h" +#include "../../servers/mfs/const.h" +#include "../../servers/mfs/inode.h" #include "de.h" diff --git a/commands/de/de_stdout.c b/commands/de/de_stdout.c index c95a1c2bc..e3f86fd04 100755 --- a/commands/de/de_stdout.c +++ b/commands/de/de_stdout.c @@ -25,9 +25,9 @@ #include #include -#include "../../servers/fs/const.h" -#include "../../servers/fs/type.h" -#include "../../servers/fs/inode.h" +#include "../../servers/mfs/const.h" +#include "../../servers/mfs/type.h" +#include "../../servers/mfs/inode.h" #include #include "de.h" diff --git a/commands/ps/Makefile b/commands/ps/Makefile index a20f0b025..77b29ce75 100644 --- a/commands/ps/Makefile +++ b/commands/ps/Makefile @@ -11,7 +11,7 @@ all: ps ps: ps.c /usr/include/minix/config.h /usr/include/minix/const.h \ ../../kernel/const.h ../../kernel/type.h \ ../../kernel/proc.h ../../servers/pm/mproc.h \ - ../../servers/fs/fproc.h ../../servers/fs/const.h + ../../servers/vfs/fproc.h ../../servers/mfs/const.h $(CC) -i $(CFLAGS) -o $@ ps.c install -S 32kw $@ install: /usr/bin/ps diff --git a/commands/ps/ps.c b/commands/ps/ps.c index 11641025f..ce73d79d8 100644 --- a/commands/ps/ps.c +++ b/commands/ps/ps.c @@ -81,8 +81,8 @@ #include "../../kernel/proc.h" #include "../../servers/pm/mproc.h" -#include "../../servers/fs/fproc.h" -#include "../../servers/fs/const.h" +#include "../../servers/vfs/fproc.h" +#include "../../servers/mfs/const.h" /*----- ps's local stuff below this line ------*/ diff --git a/commands/scripts/packman.sh b/commands/scripts/packman.sh index 8254552ea..d97eab591 100644 --- a/commands/scripts/packman.sh +++ b/commands/scripts/packman.sh @@ -13,6 +13,7 @@ TMPDIR=/usr/tmp/packages mkdir -p $TMPDIR URL1=http://www.minix3.org/packages/$PACKDIR SRCURL1=http://www.minix3.org/software +PATH=/bin:/sbin:/usr/bin:/usr/sbin # can we execute bunzip2? if bunzip2 --help 2>&1 | grep usage >/dev/null diff --git a/commands/simple/Makefile b/commands/simple/Makefile index 3b53b37f3..a3a25a32c 100755 --- a/commands/simple/Makefile +++ b/commands/simple/Makefile @@ -355,7 +355,7 @@ dhrystone: dhrystone.c diff: diff.c $(CCLD) -o $@ $? - @install -S 40kw $@ + @install -S 512kw $@ dirname: dirname.c $(CCLD) -o $@ $? diff --git a/commands/simple/badblocks.c b/commands/simple/badblocks.c index f1cc4c4f7..36682c377 100755 --- a/commands/simple/badblocks.c +++ b/commands/simple/badblocks.c @@ -28,15 +28,15 @@ #include #include -#include "../../servers/fs/const.h" /* must be included before stdio.h */ +#include "../../servers/mfs/const.h" /* must be included before stdio.h */ #undef printf /* so its define of printf can be undone */ -#include "../../servers/fs/type.h" +#include "../../servers/mfs/type.h" #include #include #define EXTERN extern -#include "../../servers/fs/super.h" +#include "../../servers/mfs/super.h" _PROTOTYPE(int main, (int argc, char **argv)); _PROTOTYPE(void rw_super, (int flag)); diff --git a/commands/simple/cdprobe.c b/commands/simple/cdprobe.c index 26e3f22e4..3512dcc68 100644 --- a/commands/simple/cdprobe.c +++ b/commands/simple/cdprobe.c @@ -22,7 +22,7 @@ #include #include -#include "../../servers/fs/const.h" +#include "../../servers/vfs/const.h" char pvd[CD_SECTOR]; diff --git a/commands/simple/df.c b/commands/simple/df.c index f1d69e031..ec921936f 100755 --- a/commands/simple/df.c +++ b/commands/simple/df.c @@ -30,9 +30,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #undef printf #if !__minix_vmd diff --git a/commands/simple/fsck.c b/commands/simple/fsck.c index f7e9a1c59..c23bbc21e 100755 --- a/commands/simple/fsck.c +++ b/commands/simple/fsck.c @@ -47,9 +47,9 @@ #include #include #include -#include "../../servers/fs/const.h" -#include "../../servers/fs/inode.h" -#include "../../servers/fs/type.h" +#include "../../servers/mfs/const.h" +#include "../../servers/mfs/inode.h" +#include "../../servers/mfs/type.h" #include #include #include @@ -87,7 +87,7 @@ unsigned int fs_version = 2, block_size = 0; #define ZONE_CT 360 /* default zones (when making file system) */ #define INODE_CT 95 /* default inodes (when making file system) */ -#include "../../servers/fs/super.h" +#include "../../servers/mfs/super.h" static struct super_block sb; #define STICKY_BIT 01000 /* not defined anywhere else */ diff --git a/commands/simple/fsck1.c b/commands/simple/fsck1.c index 92dd6a13e..b36dbb8c5 100755 --- a/commands/simple/fsck1.c +++ b/commands/simple/fsck1.c @@ -49,9 +49,9 @@ #include #include #include -#include "../../servers/fs/const.h" -#include "../../servers/fs/inode.h" -#include "../../servers/fs/type.h" +#include "../../servers/mfs/const.h" +#include "../../servers/mfs/inode.h" +#include "../../servers/mfs/type.h" #include #include #include @@ -71,7 +71,7 @@ #define ZONE_CT 360 /* default zones (when making file system) */ #define INODE_CT 95 /* default inodes (when making file system) */ -#include "../../servers/fs/super.h" +#include "../../servers/mfs/super.h" struct super_block sb; #define STICKY_BIT 01000 /* not defined anywhere else */ diff --git a/commands/simple/mkfs.c b/commands/simple/mkfs.c index 3f0d4d307..de7882489 100755 --- a/commands/simple/mkfs.c +++ b/commands/simple/mkfs.c @@ -23,7 +23,7 @@ #include #include #include -#include "../../servers/fs/const.h" +#include "../../servers/mfs/const.h" #if (MACHINE == IBM_PC) #include #include @@ -35,8 +35,8 @@ #undef EXTERN #define EXTERN /* get rid of EXTERN by making it null */ -#include "../../servers/fs/type.h" -#include "../../servers/fs/super.h" +#include "../../servers/mfs/type.h" +#include "../../servers/mfs/super.h" #include #ifndef max diff --git a/commands/simple/mkswap.c b/commands/simple/mkswap.c index 5211661f3..aaf66e579 100755 --- a/commands/simple/mkswap.c +++ b/commands/simple/mkswap.c @@ -19,9 +19,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include static void usage(void) { diff --git a/commands/simple/mount.c b/commands/simple/mount.c index cc7119854..603fcedd1 100755 --- a/commands/simple/mount.c +++ b/commands/simple/mount.c @@ -14,7 +14,7 @@ #include #include #include -#include "../../servers/fs/const.h" +#include "../../servers/vfs/const.h" _PROTOTYPE(int main, (int argc, char **argv)); _PROTOTYPE(void list, (void)); diff --git a/commands/simple/readfs.c b/commands/simple/readfs.c index 0d2667a46..77f4d8cd7 100755 --- a/commands/simple/readfs.c +++ b/commands/simple/readfs.c @@ -41,10 +41,10 @@ #include #include #include -#include "../../servers/fs/const.h" -#include "../../servers/fs/type.h" -#include "../../servers/fs/buf.h" -#include "../../servers/fs/super.h" +#include "../../servers/mfs/const.h" +#include "../../servers/mfs/type.h" +#include "../../servers/mfs/buf.h" +#include "../../servers/mfs/super.h" #undef printf /* Definition used only in the kernel */ #include diff --git a/drivers/at_wini/at_wini.c b/drivers/at_wini/at_wini.c index 8e79483bd..846580207 100644 --- a/drivers/at_wini/at_wini.c +++ b/drivers/at_wini/at_wini.c @@ -1923,7 +1923,7 @@ PRIVATE void w_intr_wait() /* Wait for an interrupt that sets w_status to "not busy". */ while (w_wn->w_status & (STATUS_ADMBSY|STATUS_BSY)) { int rr; - if((rr=receive(ANY, &m)) != OK) { /* expect HARD_INT message */ + if((rr=receive(HARDWARE, &m)) != OK) { /* expect HARD_INT message */ printf("w_intr_wait: receive from ANY failed (%d)\n", r); continue; /* try again */ diff --git a/drivers/memory/ramdisk/Makefile b/drivers/memory/ramdisk/Makefile index a45db86b1..dce479fea 100644 --- a/drivers/memory/ramdisk/Makefile +++ b/drivers/memory/ramdisk/Makefile @@ -1,7 +1,7 @@ # Makefile for ramdisk image PROGRAMS=at_wini bios_wini cdprobe dev2name floppy loadramdisk newroot \ - pci sh service sysenv + pci sh service sysenv mfs MAKEDEV=/usr/bin/MAKEDEV @@ -90,6 +90,12 @@ service: ../../../servers/rs/service ../../../servers/rs/service: cd ../../../servers/rs && make service +mfs: ../../../servers/mfs/mfs + install -s ../../../servers/mfs/$@ $@ + +../../../servers/mfs/mfs: + cd ../../../servers/mfs && make + depend: /usr/bin/mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend diff --git a/drivers/memory/ramdisk/proto b/drivers/memory/ramdisk/proto index 38b861269..38987d9bb 100644 --- a/drivers/memory/ramdisk/proto +++ b/drivers/memory/ramdisk/proto @@ -1,5 +1,5 @@ boot -200 250 +210 250 d--755 0 0 bin d--755 0 0 at_wini ---755 0 0 at_wini @@ -13,6 +13,7 @@ d--755 0 0 sh ---755 0 0 sh service ---755 0 0 service sysenv ---755 0 0 sysenv + mfs ---755 0 0 mfs $ dev d--755 0 0 @DEV@ diff --git a/drivers/memory/ramdisk/proto.sh b/drivers/memory/ramdisk/proto.sh index 00d593902..cab7fc841 100644 --- a/drivers/memory/ramdisk/proto.sh +++ b/drivers/memory/ramdisk/proto.sh @@ -1,4 +1,5 @@ #!/bin/sh +PATH=/bin:/sbin:/usr/bin:/usr/sbin sed -n '1,/@DEV/p' #include +#include extern pid_t _fork(void); extern pid_t _wait(int *); @@ -35,7 +36,7 @@ system(const char *str) if ((pid = _fork()) < 0) return str ? -1 : 0; if (pid == 0) { - for (i = 3; i <= 20; i++) + for (i = 3; i <= OPEN_MAX; i++) _close(i); if (!str) str = "cd ."; /* just testing for a shell */ exec_tab[2] = str; /* fill in command */ diff --git a/lib/other/fslib.c b/lib/other/fslib.c index 2b11a55b0..a24c886ce 100755 --- a/lib/other/fslib.c +++ b/lib/other/fslib.c @@ -7,10 +7,10 @@ #include #include #include /* for unshort :-( */ -#include "fs/const.h" /* depends of -I flag in Makefile */ -#include "fs/type.h" /* ditto */ -#include "fs/inode.h" /* ditto */ -#include "fs/super.h" +#include "mfs/const.h" /* depends of -I flag in Makefile */ +#include "mfs/type.h" /* ditto */ +#include "mfs/inode.h" /* ditto */ +#include "mfs/super.h" #include /* The next routine is copied from fsck.c and mkfs.c... (Re)define some diff --git a/lib/other/fsversion.c b/lib/other/fsversion.c index 6e74d0d4e..3a0faa59f 100755 --- a/lib/other/fsversion.c +++ b/lib/other/fsversion.c @@ -17,9 +17,9 @@ #include #include -#include "fs/const.h" -#include "fs/type.h" -#include "fs/super.h" +#include "mfs/const.h" +#include "mfs/type.h" +#include "mfs/super.h" static struct super_block super, *sp; diff --git a/lib/posix/_mount.c b/lib/posix/_mount.c index c32542ae9..7130d450d 100755 --- a/lib/posix/_mount.c +++ b/lib/posix/_mount.c @@ -1,14 +1,51 @@ + #include #define mount _mount #include #include +#include +#include +#include + +#define OK 0 PUBLIC int mount(special, name, rwflag) char *name, *special; int rwflag; { + struct stat stat_buf; message m; - + + m.RS_CMD_ADDR = "/sbin/mfs"; + if (stat(m.RS_CMD_ADDR, &stat_buf) == -1) { + printf("MOUNT: /sbin/mfs doesn't exist\n"); + m.RS_CMD_ADDR = 0; + } + + if (!m.RS_CMD_ADDR) { + m.RS_CMD_ADDR = "/bin/mfs"; + if (stat(m.RS_CMD_ADDR, &stat_buf) == -1) { + printf("MOUNT: /bin/mfs doesn't exist\n"); + m.RS_CMD_ADDR = 0; + } + } + + if (m.RS_CMD_ADDR) { + if (!(stat_buf.st_mode & S_IFREG)) { + printf("MOUNT: FS binary is not a regular file\n"); + } + m.RS_CMD_LEN = strlen(m.RS_CMD_ADDR); + m.RS_DEV_MAJOR = 0; + m.RS_PERIOD = 0; + if (OK != _taskcall(RS_PROC_NR, RS_UP, &m)) { + printf("MOUNT: error sending request to RS\n"); + } + else { + /* copy endpointnumber */ + m.m1_p3 = (char*)(unsigned long)m.RS_ENDPOINT; + } + } + m.m1_i1 = strlen(special) + 1; m.m1_i2 = strlen(name) + 1; m.m1_i3 = rwflag; diff --git a/servers/Makefile b/servers/Makefile index 938e75854..a534e5686 100644 --- a/servers/Makefile +++ b/servers/Makefile @@ -16,7 +16,8 @@ usage: build: all all install depend clean: cd ./pm && $(MAKE) $@ - cd ./fs && $(MAKE) $@ + cd ./vfs && $(MAKE) $@ + cd ./mfs && $(MAKE) $@ cd ./rs && $(MAKE) $@ cd ./ds && $(MAKE) $@ cd ./is && $(MAKE) $@ @@ -25,7 +26,8 @@ all install depend clean: image: cd ./pm && $(MAKE) EXTRA_OPTS=$(EXTRA_OPTS) build - cd ./fs && $(MAKE) EXTRA_OPTS=$(EXTRA_OPTS) build + cd ./vfs && $(MAKE) EXTRA_OPTS=$(EXTRA_OPTS) build + cd ./mfs && $(MAKE) EXTRA_OPTS=$(EXTRA_OPTS) build cd ./rs && $(MAKE) EXTRA_OPTS=$(EXTRA_OPTS) build cd ./ds && $(MAKE) EXTRA_OPTS=$(EXTRA_OPTS) build cd ./init && $(MAKE) EXTRA_OPTS=$(EXTRA_OPTS) build diff --git a/servers/fs/cache2.c b/servers/fs/cache2.c deleted file mode 100644 index 6ef2e31da..000000000 --- a/servers/fs/cache2.c +++ /dev/null @@ -1,126 +0,0 @@ -/* Second level block cache to supplement the file system cache. The block - * cache of a 16-bit Minix system is very small, too small to prevent trashing. - * A generic 32-bit system also doesn't have a very large cache to allow it - * to run on systems with little memory. On a system with lots of memory one - * can use the RAM disk as a read-only second level cache. Any blocks pushed - * out of the primary cache are cached on the RAM disk. This code manages the - * second level cache. The cache is a simple FIFO where old blocks are put - * into and drop out at the other end. Must be searched backwards. - * - * The entry points into this file are: - * init_cache2: initialize the second level cache - * get_block2: get a block from the 2nd level cache - * put_block2: store a block in the 2nd level cache - * invalidate2: remove all the cache blocks on some device - */ - -#include "fs.h" -#include -#include "buf.h" - -#if ENABLE_CACHE2 - -#define MAX_BUF2 (256 * sizeof(char *)) - -PRIVATE struct buf2 { /* 2nd level cache per block administration */ - block_t b2_blocknr; /* block number */ - dev_t b2_dev; /* device number */ - u16_t b2_count; /* count of in-cache block groups */ -} buf2[MAX_BUF2]; - -PRIVATE unsigned nr_buf2; /* actual cache size */ -PRIVATE unsigned buf2_idx; /* round-robin reuse index */ - -#define hash2(block) ((unsigned) ((block) & (MAX_BUF2 - 1))) - -/*===========================================================================* - * init_cache2 * - *===========================================================================*/ -PUBLIC void init_cache2(size) -unsigned long size; -{ -/* Initialize the second level disk buffer cache of 'size' blocks. */ - - nr_buf2 = size > MAX_BUF2 ? MAX_BUF2 : (unsigned) size; -} - -/*===========================================================================* - * get_block2 * - *===========================================================================*/ -PUBLIC int get_block2(bp, only_search) -struct buf *bp; /* buffer to get from the 2nd level cache */ -int only_search; /* if NO_READ, do nothing, else act normal */ -{ -/* Fill a buffer from the 2nd level cache. Return true iff block acquired. */ - unsigned b; - struct buf2 *bp2; - - /* If the block wanted is in the RAM disk then our game is over. */ - if (bp->b_dev == DEV_RAM) nr_buf2 = 0; - - /* Cache enabled? NO_READ? Any blocks with the same hash key? */ - if (nr_buf2 == 0 || only_search == NO_READ - || buf2[hash2(bp->b_blocknr)].b2_count == 0) return(0); - - /* Search backwards (there may be older versions). */ - b = buf2_idx; - for (;;) { - if (b == 0) b = nr_buf2; - bp2 = &buf2[--b]; - if (bp2->b2_blocknr == bp->b_blocknr && bp2->b2_dev == bp->b_dev) break; - if (b == buf2_idx) return(0); - } - - /* Block is in the cache, get it. */ - if (dev_io(DEV_READ, DEV_RAM, FS_PROC_NR, bp->b_data, - (off_t) b * BLOCK_SIZE, BLOCK_SIZE, 0) == BLOCK_SIZE) { - return(1); - } - return(0); -} - -/*===========================================================================* - * put_block2 * - *===========================================================================*/ -PUBLIC void put_block2(bp) -struct buf *bp; /* buffer to store in the 2nd level cache */ -{ -/* Store a buffer into the 2nd level cache. */ - unsigned b; - struct buf2 *bp2; - - if (nr_buf2 == 0) return; /* no 2nd level cache */ - - b = buf2_idx++; - if (buf2_idx == nr_buf2) buf2_idx = 0; - - bp2 = &buf2[b]; - - if (dev_io(DEV_WRITE, DEV_RAM, FS_PROC_NR, bp->b_data, - (off_t) b * BLOCK_SIZE, BLOCK_SIZE, 0) == BLOCK_SIZE) { - if (bp2->b2_dev != NO_DEV) buf2[hash2(bp2->b2_blocknr)].b2_count--; - bp2->b2_dev = bp->b_dev; - bp2->b2_blocknr = bp->b_blocknr; - buf2[hash2(bp2->b2_blocknr)].b2_count++; - } -} - -/*===========================================================================* - * invalidate2 * - *===========================================================================*/ -PUBLIC void invalidate2(device) -dev_t device; -{ -/* Invalidate all blocks from a given device in the 2nd level cache. */ - unsigned b; - struct buf2 *bp2; - - for (b = 0; b < nr_buf2; b++) { - bp2 = &buf2[b]; - if (bp2->b2_dev == device) { - bp2->b2_dev = NO_DEV; - buf2[hash2(bp2->b2_blocknr)].b2_count--; - } - } -} -#endif /* ENABLE_CACHE2 */ diff --git a/servers/fs/mount.c b/servers/fs/mount.c deleted file mode 100644 index d6a8d7173..000000000 --- a/servers/fs/mount.c +++ /dev/null @@ -1,353 +0,0 @@ -/* This file performs the MOUNT and UMOUNT system calls. - * - * The entry points into this file are - * do_mount: perform the MOUNT system call - * do_umount: perform the UMOUNT system call - */ - -#include "fs.h" -#include -#include -#include -#include -#include "buf.h" -#include "file.h" -#include "fproc.h" -#include "inode.h" -#include "param.h" -#include "super.h" - -/* Allow the root to be replaced before the first 'real' mount. */ -PRIVATE int allow_newroot= 1; - -FORWARD _PROTOTYPE( dev_t name_to_dev, (char *path) ); - -/*===========================================================================* - * do_mount * - *===========================================================================*/ -PUBLIC int do_mount() -{ -/* Perform the mount(name, mfile, rd_only) system call. */ - - register struct inode *rip, *root_ip; - struct super_block *xp, *sp; - dev_t dev; - mode_t bits; - int rdir, mdir; /* TRUE iff {root|mount} file is dir */ - int i, r, found; - struct fproc *tfp; - - /* Only the super-user may do MOUNT. */ - if (!super_user) return(EPERM); - - /* If 'name' is not for a block special file, return error. */ - if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ( (dev = name_to_dev(user_path)) == NO_DEV) return(err_code); - - /* Scan super block table to see if dev already mounted & find a free slot.*/ - sp = NIL_SUPER; - found = FALSE; - for (xp = &super_block[0]; xp < &super_block[NR_SUPERS]; xp++) { - if (xp->s_dev == dev) - { - /* is it mounted already? */ - found = TRUE; - sp= xp; - break; - } - if (xp->s_dev == NO_DEV) sp = xp; /* record free slot */ - } - if (found) - { - printf( -"do_mount: s_imount = 0x%x (%x, %d), s_isup = 0x%x (%x, %d), fp_rootdir = 0x%x\n", - xp->s_imount, xp->s_imount->i_dev, xp->s_imount->i_num, - xp->s_isup, xp->s_isup->i_dev, xp->s_isup->i_num, - fproc[FS_PROC_NR].fp_rootdir); - /* It is possible that we have an old root lying around that - * needs to be remounted. - */ - if (xp->s_imount != xp->s_isup || - xp->s_isup == fproc[FS_PROC_NR].fp_rootdir) - { - /* Normally, s_imount refers to the mount point. For a root - * filesystem, s_imount is equal to the root inode. We assume - * that the root of FS is always the real root. If the two - * inodes are different or if the root of FS is equal two the - * root of the filesystem we found, we found a filesystem that - * is in use. - */ - return(EBUSY); /* already mounted */ - } - - if (root_dev == xp->s_dev) - { - panic("fs", "inconsistency remounting old root", - NO_NUM); - } - - /* 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 ( (rip = eat_path(user_path)) == NIL_INODE) { - return(err_code); - } - - r = OK; - - /* It may not be special. */ - bits = rip->i_mode & I_TYPE; - if (bits == I_BLOCK_SPECIAL || bits == I_CHAR_SPECIAL) - r = ENOTDIR; - - /* Get the root inode of the mounted file system. */ - root_ip= sp->s_isup; - - /* File types of 'rip' and 'root_ip' may not conflict. */ - if (r == OK) { - mdir = ((rip->i_mode & I_TYPE) == I_DIRECTORY); - /* TRUE iff dir */ - rdir = ((root_ip->i_mode & I_TYPE) == I_DIRECTORY); - if (!mdir && rdir) r = EISDIR; - } - - /* If error, return the mount point. */ - if (r != OK) { - put_inode(rip); - return(r); - } - - /* Nothing else can go wrong. Perform the mount. */ - rip->i_mount = I_MOUNT; /* this bit says the inode is - * mounted on - */ - put_inode(sp->s_imount); - sp->s_imount = rip; - sp->s_rd_only = m_in.rd_only; - allow_newroot= 0; /* The root is now fixed */ - return(OK); - } - if (sp == NIL_SUPER) return(ENFILE); /* no super block available */ - - /* Open the device the file system lives on. */ - if (dev_open(dev, who_e, m_in.rd_only ? R_BIT : (R_BIT|W_BIT)) != OK) - return(EINVAL); - - /* Make the cache forget about blocks it has open on the filesystem */ - (void) do_sync(); - invalidate(dev); - - /* Fill in the super block. */ - sp->s_dev = dev; /* read_super() needs to know which dev */ - r = read_super(sp); - - /* Is it recognized as a Minix filesystem? */ - if (r != OK) { - dev_close(dev); - sp->s_dev = NO_DEV; - return(r); - } - - /* Now get the inode of the file to be mounted on. */ - if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) { - dev_close(dev); - sp->s_dev = NO_DEV; - return(err_code); - } - - if (strcmp(user_path, "/") == 0 && allow_newroot) - { - printf("Replacing root\n"); - - /* Get the root inode of the mounted file system. */ - if ( (root_ip = get_inode(dev, ROOT_INODE)) == NIL_INODE) r = err_code; - if (root_ip != NIL_INODE && root_ip->i_mode == 0) { - r = EINVAL; - } - - /* If error, return the super block and both inodes; release the - * maps. - */ - if (r != OK) { - put_inode(root_ip); - (void) do_sync(); - invalidate(dev); - dev_close(dev); - sp->s_dev = NO_DEV; - return(r); - } - - /* Nothing else can go wrong. Perform the mount. */ - sp->s_imount = root_ip; - dup_inode(root_ip); - sp->s_isup = root_ip; - sp->s_rd_only = m_in.rd_only; - root_dev= dev; - - /* Replace all root and working directories */ - for (i= 0, tfp= fproc; ifp_pid == PID_FREE) - continue; - if (tfp->fp_rootdir == NULL) - panic("fs", "do_mount: null rootdir", i); - put_inode(tfp->fp_rootdir); - dup_inode(root_ip); - tfp->fp_rootdir= root_ip; - - if (tfp->fp_workdir == NULL) - panic("fs", "do_mount: null workdir", i); - put_inode(tfp->fp_workdir); - dup_inode(root_ip); - tfp->fp_workdir= root_ip; - } - - /* Leave the old filesystem lying around. */ - return(OK); - } - - if ( (rip = eat_path(user_path)) == NIL_INODE) { - dev_close(dev); - sp->s_dev = NO_DEV; - return(err_code); - } - - /* It may not be busy. */ - r = OK; - if (rip->i_count > 1) r = EBUSY; - - /* It may not be special. */ - bits = rip->i_mode & I_TYPE; - if (bits == I_BLOCK_SPECIAL || bits == I_CHAR_SPECIAL) r = ENOTDIR; - - /* Get the root inode of the mounted file system. */ - root_ip = NIL_INODE; /* if 'r' not OK, make sure this is defined */ - if (r == OK) { - if ( (root_ip = get_inode(dev, ROOT_INODE)) == NIL_INODE) r = err_code; - } - if (root_ip != NIL_INODE && root_ip->i_mode == 0) { - r = EINVAL; - } - - /* File types of 'rip' and 'root_ip' may not conflict. */ - if (r == OK) { - mdir = ((rip->i_mode & I_TYPE) == I_DIRECTORY); /* TRUE iff dir */ - rdir = ((root_ip->i_mode & I_TYPE) == I_DIRECTORY); - if (!mdir && rdir) r = EISDIR; - } - - /* If error, return the super block and both inodes; release the maps. */ - if (r != OK) { - put_inode(rip); - put_inode(root_ip); - (void) do_sync(); - invalidate(dev); - dev_close(dev); - sp->s_dev = NO_DEV; - return(r); - } - - /* Nothing else can go wrong. Perform the mount. */ - rip->i_mount = I_MOUNT; /* this bit says the inode is mounted on */ - sp->s_imount = rip; - sp->s_isup = root_ip; - sp->s_rd_only = m_in.rd_only; - allow_newroot= 0; /* The root is now fixed */ - return(OK); -} - -/*===========================================================================* - * do_umount * - *===========================================================================*/ -PUBLIC int do_umount() -{ -/* Perform the umount(name) system call. */ - dev_t dev; - - /* Only the super-user may do UMOUNT. */ - if (!super_user) return(EPERM); - - /* If 'name' is not for a block special file, return error. */ - if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); - if ( (dev = name_to_dev(user_path)) == NO_DEV) return(err_code); - - return(unmount(dev)); -} - -/*===========================================================================* - * unmount * - *===========================================================================*/ -PUBLIC int unmount(dev) -Dev_t dev; -{ -/* Unmount a file system by device number. */ - register struct inode *rip; - struct super_block *sp, *sp1; - int count; - - /* See if the mounted device is busy. Only 1 inode using it should be - * open -- the root inode -- and that inode only 1 time. - */ - count = 0; - for (rip = &inode[0]; rip< &inode[NR_INODES]; rip++) - if (rip->i_count > 0 && rip->i_dev == dev) count += rip->i_count; - if (count > 1) return(EBUSY); /* can't umount a busy file system */ - - /* Find the super block. */ - sp = NIL_SUPER; - for (sp1 = &super_block[0]; sp1 < &super_block[NR_SUPERS]; sp1++) { - if (sp1->s_dev == dev) { - sp = sp1; - break; - } - } - - /* Sync the disk, and invalidate cache. */ - (void) do_sync(); /* force any cached blocks out of memory */ - invalidate(dev); /* invalidate cache entries for this dev */ - if (sp == NIL_SUPER) { - return(EINVAL); - } - - /* Close the device the file system lives on. */ - dev_close(dev); - - /* Finish off the unmount. */ - sp->s_imount->i_mount = NO_MOUNT; /* inode returns to normal */ - put_inode(sp->s_imount); /* release the inode mounted on */ - put_inode(sp->s_isup); /* release the root inode of the mounted fs */ - sp->s_imount = NIL_INODE; - sp->s_dev = NO_DEV; - return(OK); -} - -/*===========================================================================* - * name_to_dev * - *===========================================================================*/ -PRIVATE dev_t name_to_dev(path) -char *path; /* pointer to path name */ -{ -/* Convert the block special file 'path' to a device number. If 'path' - * is not a block special file, return error code in 'err_code'. - */ - - register struct inode *rip; - register dev_t dev; - - /* If 'path' can't be opened, give up immediately. */ - if ( (rip = eat_path(path)) == NIL_INODE) return(NO_DEV); - - /* If 'path' is not a block special file, return error. */ - if ( (rip->i_mode & I_TYPE) != I_BLOCK_SPECIAL) { - err_code = ENOTBLK; - put_inode(rip); - return(NO_DEV); - } - - /* Extract the device number. */ - dev = (dev_t) rip->i_zone[0]; - put_inode(rip); - return(dev); -} diff --git a/servers/fs/open.c b/servers/fs/open.c deleted file mode 100644 index 6657fd42f..000000000 --- a/servers/fs/open.c +++ /dev/null @@ -1,573 +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 - * new_node: create a new file, directory, etc. - */ - -#include "fs.h" -#include -#include -#include -#include -#include -#include -#include "buf.h" -#include "file.h" -#include "fproc.h" -#include "inode.h" -#include "lock.h" -#include "param.h" -#include "super.h" - -#define offset m2_l1 - -PRIVATE char mode_map[] = {R_BIT, W_BIT, R_BIT|W_BIT, 0}; - -FORWARD _PROTOTYPE( int common_open, (int oflags, mode_t omode) ); -FORWARD _PROTOTYPE( int pipe_open, (struct inode *rip,mode_t bits,int oflags)); - -/*===========================================================================* - * do_creat * - *===========================================================================*/ -PUBLIC int do_creat() -{ -/* Perform the creat(name, mode) system call. */ - int r; - - 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); - 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; - - /* 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); - } else { - r = fetch_name(m_in.name, m_in.name_length, M3); - } - - if (r != OK) return(err_code); /* name was bad */ - r = common_open(m_in.mode, create_mode); - return(r); -} - -/*===========================================================================* - * common_open * - *===========================================================================*/ -PRIVATE int common_open(register int oflags, mode_t omode) -{ -/* Common code from do_creat and do_open. */ - - struct inode *rip, *ldirp; - int r, b, exist = TRUE; - dev_t dev; - mode_t bits; - off_t pos; - struct filp *fil_ptr, *filp2; - - /* Remap the bottom two bits of oflags. */ - bits = (mode_t) mode_map[oflags & O_ACCMODE]; - - /* See if file descriptor and filp slots are available. */ - if ( (r = get_fd(0, bits, &m_in.fd, &fil_ptr)) != OK) return(r); - - /* If O_CREATE is set, try to make the file. */ - if (oflags & O_CREAT) { - /* Create a new inode by calling new_node(). */ - omode = I_REGULAR | (omode & ALL_MODES & fp->fp_umask); - rip = new_node(&ldirp, user_path, omode, NO_ZONE, oflags&O_EXCL, NULL); - r = err_code; - put_inode(ldirp); - 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 */ - } else { - /* Scan path name. */ - if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code); - } - - /* 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_ino = rip; - fil_ptr->filp_flags = oflags; - - /* Only do the normal open code if we didn't just create the file. */ - if (exist) { - /* Check protections. */ - if ((r = forbidden(rip, bits)) == OK) { - /* Opening reg. files directories and special files differ. */ - switch (rip->i_mode & I_TYPE) { - case I_REGULAR: - /* Truncate regular file if O_TRUNC. */ - if (oflags & O_TRUNC) { - if ((r = forbidden(rip, W_BIT)) !=OK) break; - truncate_inode(rip, 0); - wipe_inode(rip); - /* Send the inode from the inode cache to the - * block cache, so it gets written on the next - * cache flush. - */ - rw_inode(rip, WRITING); - } - break; - - case I_DIRECTORY: - /* Directories may be read but not written. */ - r = (bits & W_BIT ? EISDIR : OK); - break; - - case I_CHAR_SPECIAL: - case I_BLOCK_SPECIAL: - /* Invoke the driver for special processing. */ - dev = (dev_t) rip->i_zone[0]; - r = dev_open(dev, who_e, bits | (oflags & ~O_ACCMODE)); - break; - - case I_NAMED_PIPE: - oflags |= O_APPEND; /* force append mode */ - fil_ptr->filp_flags = oflags; - r = pipe_open(rip, 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); - fil_ptr->filp_count = 0; /* don't find self */ - if ((filp2 = find_filp(rip, b)) != NIL_FILP) { - /* Co-reader or writer found. Use it.*/ - fp->fp_filp[m_in.fd] = filp2; - filp2->filp_count++; - filp2->filp_ino = rip; - filp2->filp_flags = oflags; - - /* i_count was incremented incorrectly - * by eatpath above, not knowing that - * we were going to use an existing - * filp entry. Correct this error. - */ - rip->i_count--; - } else { - /* Nobody else found. Restore filp. */ - fil_ptr->filp_count = 1; - if (b == R_BIT) - pos = rip->i_zone[V2_NR_DZONES+0]; - else - pos = rip->i_zone[V2_NR_DZONES+1]; - fil_ptr->filp_pos = pos; - } - } - break; - } - } - } - - /* If error, release inode. */ - if (r != OK) { - if (r == SUSPEND) return(r); /* Oops, just suspended */ - fp->fp_filp[m_in.fd] = NIL_FILP; - FD_CLR(m_in.fd, &fp->fp_filp_inuse); - fil_ptr->filp_count= 0; - put_inode(rip); - return(r); - } - - return(m_in.fd); -} - -/*===========================================================================* - * new_node * - *===========================================================================*/ -PUBLIC struct inode *new_node(struct inode **ldirp, - char *path, mode_t bits, zone_t z0, int opaque, char *parsed) -{ -/* New_node() is called by common_open(), do_mknod(), and do_mkdir(). - * In all cases it allocates a new inode, makes a directory entry for it on - * the path 'path', and initializes it. It returns a pointer to the inode if - * it can do this; otherwise it returns NIL_INODE. It always sets 'err_code' - * to an appropriate value (OK or an error code). - * - * The parsed path rest is returned in 'parsed' if parsed is nonzero. It - * has to hold at least NAME_MAX bytes. - */ - - register struct inode *rip; - register int r; - char string[NAME_MAX]; - - *ldirp = parse_path(path, string, opaque ? LAST_DIR : LAST_DIR_EATSYM); - if (*ldirp == NIL_INODE) return(NIL_INODE); - - /* The final directory is accessible. Get final component of the path. */ - rip = advance(ldirp, string); - - if (S_ISDIR(bits) && - (*ldirp)->i_nlinks >= ((*ldirp)->i_sp->s_version == V1 ? - CHAR_MAX : SHRT_MAX)) { - /* New entry is a directory, alas we can't give it a ".." */ - put_inode(rip); - err_code = EMLINK; - return(NIL_INODE); - } - - if ( rip == NIL_INODE && err_code == ENOENT) { - /* Last path component does not exist. Make new directory entry. */ - if ( (rip = alloc_inode((*ldirp)->i_dev, bits)) == NIL_INODE) { - /* Can't creat new inode: out of inodes. */ - return(NIL_INODE); - } - - /* Force inode to the disk before making directory entry to make - * the system more robust in the face of a crash: an inode with - * no directory entry is much better than the opposite. - */ - rip->i_nlinks++; - rip->i_zone[0] = z0; /* major/minor device numbers */ - rw_inode(rip, WRITING); /* force inode to disk now */ - - /* New inode acquired. Try to make directory entry. */ - if ((r = search_dir(*ldirp, string, &rip->i_num,ENTER)) != OK) { - rip->i_nlinks--; /* pity, have to free disk inode */ - rip->i_dirt = DIRTY; /* dirty inodes are written out */ - put_inode(rip); /* this call frees the inode */ - err_code = r; - return(NIL_INODE); - } - - } else { - /* Either last component exists, or there is some problem. */ - if (rip != NIL_INODE) - r = EEXIST; - else - r = err_code; - } - - if(parsed) { /* Give the caller the parsed string if requested. */ - strncpy(parsed, string, NAME_MAX-1); - parsed[NAME_MAX-1] = '\0'; - } - - /* The caller has to return the directory inode (*ldirp). */ - err_code = r; - return(rip); -} - -/*===========================================================================* - * pipe_open * - *===========================================================================*/ -PRIVATE int pipe_open(register struct inode *rip, register mode_t bits, - register 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. - */ - - rip->i_pipe = I_PIPE; - - if((bits & (R_BIT|W_BIT)) == (R_BIT|W_BIT)) { - printf("pipe opened RW.\n"); - return ENXIO; - } - - if (find_filp(rip, bits & W_BIT ? R_BIT : W_BIT) == NIL_FILP) { - if (oflags & O_NONBLOCK) { - if (bits & W_BIT) return(ENXIO); - } else { - suspend(XPOPEN); /* suspend caller */ - return(SUSPEND); - } - } else if (susp_count > 0) {/* revive blocked processes */ - release(rip, OPEN, susp_count); - release(rip, 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; - struct inode *ip, *ldirp; - - /* 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)) return(EPERM); - if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - bits = (mode_bits & I_TYPE) | (mode_bits & ALL_MODES & fp->fp_umask); - ip = new_node(&ldirp, user_path, bits, (zone_t) m_in.mk_z0, TRUE, NULL); - put_inode(ip); - put_inode(ldirp); - return(err_code); -} - -/*===========================================================================* - * do_mkdir * - *===========================================================================*/ -PUBLIC int do_mkdir() -{ -/* Perform the mkdir(name, mode) system call. */ - - int r1, r2; /* status codes */ - ino_t dot, dotdot; /* inode numbers for . and .. */ - mode_t bits; /* mode bits for the new inode */ - char string[NAME_MAX]; /* last component of the new dir's path name */ - struct inode *rip, *ldirp; - - if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - - /* Next make the inode. If that fails, return error code. */ - bits = I_DIRECTORY | (m_in.mode & RWX_MODES & fp->fp_umask); - rip = new_node(&ldirp, user_path, bits, (zone_t) 0, TRUE, string); - if (rip == NIL_INODE || err_code == EEXIST) { - put_inode(rip); /* can't make dir: it already exists */ - put_inode(ldirp); - return(err_code); - } - - /* Get the inode numbers for . and .. to enter in the directory. */ - dotdot = ldirp->i_num; /* parent's inode number */ - dot = rip->i_num; /* inode number of the new dir itself */ - - /* Now make dir entries for . and .. unless the disk is completely full. */ - /* Use dot1 and dot2, so the mode of the directory isn't important. */ - rip->i_mode = bits; /* set mode */ - r1 = search_dir(rip, dot1, &dot, ENTER); /* enter . in the new dir */ - r2 = search_dir(rip, dot2, &dotdot, ENTER); /* enter .. in the new dir */ - - /* If both . and .. were successfully entered, increment the link counts. */ - if (r1 == OK && r2 == OK) { - /* Normal case. It was possible to enter . and .. in the new dir. */ - rip->i_nlinks++; /* this accounts for . */ - ldirp->i_nlinks++; /* this accounts for .. */ - ldirp->i_dirt = DIRTY; /* mark parent's inode as dirty */ - } else { - /* It was not possible to enter . or .. probably disk was full - - * links counts haven't been touched. - */ - if(search_dir(ldirp, string, (ino_t *) 0, DELETE) != OK) - panic(__FILE__, "Dir disappeared ", rip->i_num); - rip->i_nlinks--; /* undo the increment done in new_node() */ - } - rip->i_dirt = DIRTY; /* either way, i_nlinks has changed */ - - put_inode(ldirp); /* return the inode of the parent dir */ - put_inode(rip); /* return the inode of the newly made dir */ - return(err_code); /* new_node() always sets 'err_code' */ -} - -/*===========================================================================* - * 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; -{ -/* Close a filedescriptor for a process. */ - - register struct filp *rfilp; - register struct inode *rip; - struct file_lock *flp; - int rw, mode_word, lock_count; - dev_t dev; - - /* First locate the inode that belongs to the file descriptor. */ - if ( (rfilp = get_filp2(rfp, fd_nr)) == NIL_FILP) return(err_code); - rip = rfilp->filp_ino; /* 'rip' points to the inode */ - - if (rfilp->filp_count - 1 == 0 && rfilp->filp_mode != FILP_CLOSED) { - /* Check to see if the file is special. */ - mode_word = rip->i_mode & I_TYPE; - if (mode_word == I_CHAR_SPECIAL || mode_word == I_BLOCK_SPECIAL) { - dev = (dev_t) rip->i_zone[0]; - if (mode_word == I_BLOCK_SPECIAL) { - /* Invalidate cache entries unless special is mounted - * or ROOT - */ - if (!mounted(rip)) { - (void) do_sync(); /* purge cache */ - invalidate(dev); - } - } - /* Do any special processing on device close. */ - dev_close(dev); - } - } - - /* If the inode being closed is a pipe, release everyone hanging on it. */ - if (rip->i_pipe == I_PIPE) { - rw = (rfilp->filp_mode & R_BIT ? WRITE : READ); - release(rip, rw, NR_PROCS); - } - - /* If a write has been done, the inode is already marked as DIRTY. */ - if (--rfilp->filp_count == 0) { - if (rip->i_pipe == I_PIPE && rip->i_count > 1) { - /* Save the file position in the i-node in case needed later. - * The read and write positions are saved separately. The - * last 3 zones in the i-node are not used for (named) pipes. - */ - if (rfilp->filp_mode == R_BIT) - rip->i_zone[V2_NR_DZONES+0] = (zone_t) rfilp->filp_pos; - else - rip->i_zone[V2_NR_DZONES+1] = (zone_t) rfilp->filp_pos; - } - put_inode(rip); - } - - FD_CLR(fd_nr, &rfp->fp_cloexec_set); - rfp->fp_filp[fd_nr] = NIL_FILP; - 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_inode == rip && flp->lock_pid == rfp->fp_pid) { - flp->lock_type = 0; - nr_locks--; - } - } - if (nr_locks < lock_count) lock_revive(); /* lock released */ - return(OK); -} - -/*===========================================================================* - * do_lseek * - *===========================================================================*/ -PUBLIC int do_lseek() -{ -/* Perform the lseek(ls_fd, offset, whence) system call. */ - - register struct filp *rfilp; - register off_t pos; - - /* Check to see if the file descriptor is valid. */ - if ( (rfilp = get_filp(m_in.ls_fd)) == NIL_FILP) return(err_code); - - /* No lseek on pipes. */ - if (rfilp->filp_ino->i_pipe == I_PIPE) return(ESPIPE); - - /* The value of 'whence' determines the start position to use. */ - switch(m_in.whence) { - case SEEK_SET: pos = 0; break; - case SEEK_CUR: pos = rfilp->filp_pos; break; - case SEEK_END: pos = rfilp->filp_ino->i_size; break; - default: return(EINVAL); - } - - /* Check for overflow. */ - if (((long)m_in.offset > 0) && ((long)(pos + m_in.offset) < (long)pos)) - return(EINVAL); - if (((long)m_in.offset < 0) && ((long)(pos + m_in.offset) > (long)pos)) - return(EINVAL); - pos = pos + m_in.offset; - - if (pos != rfilp->filp_pos) - rfilp->filp_ino->i_seek = ISEEK; /* inhibit read ahead */ - rfilp->filp_pos = pos; - m_out.reply_l1 = pos; /* insert the long into the output message */ - return(OK); -} - -/*===========================================================================* - * do_slink * - *===========================================================================*/ -PUBLIC int do_slink() -{ -/* Perform the symlink(name1, name2) system call. */ - - register int r; /* error code */ - char string[NAME_MAX]; /* last component of the new dir's path name */ - struct inode *sip; /* inode containing symbolic link */ - struct buf *bp; /* disk buffer for link */ - struct inode *ldirp; /* directory containing link */ - - if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) - return(err_code); - - if (m_in.name1_length <= 1 || m_in.name1_length >= _MIN_BLOCK_SIZE) - return(ENAMETOOLONG); - - /* Create the inode for the symlink. */ - sip = new_node(&ldirp, user_path, (mode_t) (I_SYMBOLIC_LINK | RWX_MODES), - (zone_t) 0, TRUE, string); - - /* Allocate a disk block for the contents of the symlink. - * Copy contents of symlink (the name pointed to) into first disk block. - */ - if ((r = err_code) == OK) { - r = (bp = new_block(sip, (off_t) 0)) == NIL_BUF - ? err_code - : sys_vircopy(who_e, D, (vir_bytes) m_in.name1, - SELF, D, (vir_bytes) bp->b_data, - (vir_bytes) m_in.name1_length-1); - - if(r == OK) { - bp->b_data[_MIN_BLOCK_SIZE-1] = '\0'; - sip->i_size = strlen(bp->b_data); - if(sip->i_size != m_in.name1_length-1) { - /* This can happen if the user provides a buffer - * with a \0 in it. This can cause a lot of trouble - * when the symlink is used later. We could just use - * the strlen() value, but we want to let the user - * know he did something wrong. ENAMETOOLONG doesn't - * exactly describe the error, but there is no - * ENAMETOOWRONG. - */ - r = ENAMETOOLONG; - } - } - - put_block(bp, DIRECTORY_BLOCK); /* put_block() accepts NIL_BUF. */ - - if (r != OK) { - sip->i_nlinks = 0; - if (search_dir(ldirp, string, (ino_t *) 0, DELETE) != OK) - panic(__FILE__, "Symbolic link vanished", NO_NUM); - } - } - - /* put_inode() accepts NIL_INODE as a noop, so the below are safe. */ - put_inode(sip); - put_inode(ldirp); - - return(r); -} - diff --git a/servers/fs/stadir.c b/servers/fs/stadir.c deleted file mode 100644 index c84b5ec9e..000000000 --- a/servers/fs/stadir.c +++ /dev/null @@ -1,303 +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_stat: perform the STAT system call - * do_fstat: perform the FSTAT system call - * do_fstatfs: perform the FSTATFS system call - * do_lstat: perform the LSTAT system call - * do_rdlink: perform the RDLNK system call - */ - -#include "fs.h" -#include -#include -#include -#include -#include "buf.h" -#include "file.h" -#include "fproc.h" -#include "inode.h" -#include "param.h" -#include "super.h" - -FORWARD _PROTOTYPE( int change, (struct inode **iip, char *name_ptr, int len)); -FORWARD _PROTOTYPE( int change_into, (struct inode **iip, struct inode *ip)); -FORWARD _PROTOTYPE( int stat_inode, (struct inode *rip, struct filp *fil_ptr, - char *user_addr) ); - -/*===========================================================================* - * do_fchdir * - *===========================================================================*/ -PUBLIC int do_fchdir() -{ - /* Change directory on already-opened fd. */ - struct filp *rfilp; - - /* Is the file descriptor valid? */ - if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code); - dup_inode(rfilp->filp_ino); - return change_into(&fp->fp_workdir, rfilp->filp_ino); -} - -/*===========================================================================* - * do_chdir * - *===========================================================================*/ -PUBLIC int do_chdir() -{ -/* Change directory. This function is also called by MM to simulate a chdir - * in order to do EXEC, etc. It also changes the root directory, the uids and - * gids, and the umask. - */ - - int r; - register struct fproc *rfp; - - if (who_e == PM_PROC_NR) { - int slot; - if(isokendpt(m_in.endpt1, &slot) != OK) - return EINVAL; - rfp = &fproc[slot]; - put_inode(fp->fp_rootdir); - dup_inode(fp->fp_rootdir = rfp->fp_rootdir); - put_inode(fp->fp_workdir); - dup_inode(fp->fp_workdir = rfp->fp_workdir); - - /* MM uses access() to check permissions. To make this work, pretend - * that the user's real ids are the same as the user's effective ids. - * FS calls other than access() do not use the real ids, so are not - * affected. - */ - fp->fp_realuid = - fp->fp_effuid = rfp->fp_effuid; - fp->fp_realgid = - fp->fp_effgid = rfp->fp_effgid; - fp->fp_umask = rfp->fp_umask; - return(OK); - } - - /* Perform the chdir(name) system call. */ - r = change(&fp->fp_workdir, m_in.name, m_in.name_length); - return(r); -} - -/*===========================================================================* - * do_chroot * - *===========================================================================*/ -PUBLIC int do_chroot() -{ -/* Perform the chroot(name) system call. */ - - register int r; - - if (!super_user) return(EPERM); /* only su may chroot() */ - r = change(&fp->fp_rootdir, m_in.name, m_in.name_length); - return(r); -} - -/*===========================================================================* - * change * - *===========================================================================*/ -PRIVATE int change(iip, name_ptr, len) -struct inode **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 inode *rip; - - /* Try to open the new directory. */ - if (fetch_name(name_ptr, len, M3) != OK) return(err_code); - if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code); - return change_into(iip, rip); -} - -/*===========================================================================* - * change_into * - *===========================================================================*/ -PRIVATE int change_into(iip, rip) -struct inode **iip; /* pointer to the inode pointer for the dir */ -struct inode *rip; /* this is what the inode has to become */ -{ - register int r; - - /* It must be a directory and also be searchable. */ - if ( (rip->i_mode & I_TYPE) != I_DIRECTORY) - r = ENOTDIR; - else - r = forbidden(rip, X_BIT); /* check if dir is searchable */ - - /* If error, return inode. */ - if (r != OK) { - put_inode(rip); - return(r); - } - - /* Everything is OK. Make the change. */ - put_inode(*iip); /* release the old directory */ - *iip = rip; /* acquire the new one */ - return(OK); -} - -/*===========================================================================* - * do_stat * - *===========================================================================*/ -PUBLIC int do_stat() -{ -/* Perform the stat(name, buf) system call. */ - - register struct inode *rip; - register int r; - - /* Both stat() and fstat() use the same routine to do the real work. That - * routine expects an inode, so acquire it temporarily. - */ - if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code); - r = stat_inode(rip, NIL_FILP, m_in.name2); /* actually do the work.*/ - put_inode(rip); /* release the inode */ - return(r); -} - -/*===========================================================================* - * do_fstat * - *===========================================================================*/ -PUBLIC int do_fstat() -{ -/* Perform the fstat(fd, buf) system call. */ - - register struct filp *rfilp; - - /* Is the file descriptor valid? */ - if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code); - - return(stat_inode(rfilp->filp_ino, rfilp, m_in.buffer)); -} - -/*===========================================================================* - * stat_inode * - *===========================================================================*/ -PRIVATE int stat_inode(rip, fil_ptr, user_addr) -register struct inode *rip; /* pointer to inode to stat */ -struct filp *fil_ptr; /* filp pointer, supplied by 'fstat' */ -char *user_addr; /* user space address where stat buf goes */ -{ -/* Common code for stat and fstat system calls. */ - - struct stat statbuf; - mode_t mo; - int r, s; - - /* Update the atime, ctime, and mtime fields in the inode, if need be. */ - if (rip->i_update) update_times(rip); - - /* Fill in the statbuf struct. */ - mo = rip->i_mode & I_TYPE; - - /* true iff special */ - s = (mo == I_CHAR_SPECIAL || mo == I_BLOCK_SPECIAL); - - 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 = rip->i_gid; - statbuf.st_rdev = (dev_t) (s ? rip->i_zone[0] : NO_DEV); - statbuf.st_size = rip->i_size; - - if (rip->i_pipe == I_PIPE) { - statbuf.st_mode &= ~I_REGULAR; /* wipe out I_REGULAR bit for pipes */ - if (fil_ptr != NIL_FILP && fil_ptr->filp_mode & R_BIT) - statbuf.st_size -= fil_ptr->filp_pos; - } - - statbuf.st_atime = rip->i_atime; - statbuf.st_mtime = rip->i_mtime; - statbuf.st_ctime = rip->i_ctime; - - /* Copy the struct to user space. */ - r = sys_datacopy(FS_PROC_NR, (vir_bytes) &statbuf, - who_e, (vir_bytes) user_addr, (phys_bytes) sizeof(statbuf)); - return(r); -} - -/*===========================================================================* - * do_fstatfs * - *===========================================================================*/ -PUBLIC int do_fstatfs() -{ - /* Perform the fstatfs(fd, buf) system call. */ - struct statfs st; - register struct filp *rfilp; - int r; - - /* Is the file descriptor valid? */ - if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code); - - st.f_bsize = rfilp->filp_ino->i_sp->s_block_size; - - r = sys_datacopy(FS_PROC_NR, (vir_bytes) &st, - who_e, (vir_bytes) m_in.buffer, (phys_bytes) sizeof(st)); - - return(r); -} - -/*===========================================================================* - * do_lstat * - *===========================================================================*/ -PUBLIC int do_lstat() -{ -/* Perform the lstat(name, buf) system call. */ - - register int r; /* return value */ - register struct inode *rip; /* target inode */ - - if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((rip = parse_path(user_path, (char *) 0, EAT_PATH_OPAQUE)) == NIL_INODE) - return(err_code); - r = stat_inode(rip, NIL_FILP, m_in.name2); - put_inode(rip); - return(r); -} - -/*===========================================================================* - * do_rdlink * - *===========================================================================*/ -PUBLIC int do_rdlink() -{ -/* Perform the readlink(name, buf) system call. */ - - register int r; /* return value */ - block_t b; /* block containing link text */ - struct buf *bp; /* buffer containing link text */ - register struct inode *rip; /* target inode */ - int copylen; - copylen = m_in.m1_i2; - if(copylen < 0) return EINVAL; - - if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((rip = parse_path(user_path, (char *) 0, EAT_PATH_OPAQUE)) == NIL_INODE) - return(err_code); - - r = EACCES; - if (S_ISLNK(rip->i_mode) && (b = read_map(rip, (off_t) 0)) != NO_BLOCK) { - if (m_in.name2_length <= 0) r = EINVAL; - else if (m_in.name2_length < rip->i_size) r = ERANGE; - else { - if(rip->i_size < copylen) copylen = rip->i_size; - bp = get_block(rip->i_dev, b, NORMAL); - r = sys_vircopy(SELF, D, (vir_bytes) bp->b_data, - who_e, D, (vir_bytes) m_in.name2, (vir_bytes) copylen); - - if (r == OK) r = copylen; - put_block(bp, DIRECTORY_BLOCK); - } - } - - put_inode(rip); - return(r); -} - diff --git a/servers/is/dmp_fs.c b/servers/is/dmp_fs.c index d67fc67cb..0eeea9589 100644 --- a/servers/is/dmp_fs.c +++ b/servers/is/dmp_fs.c @@ -9,8 +9,8 @@ */ #include "inc.h" -#include "../fs/const.h" -#include "../fs/fproc.h" +#include "../mfs/const.h" +#include "../vfs/fproc.h" #include PUBLIC struct fproc fproc[NR_PROCS]; diff --git a/servers/mfs/Makefile b/servers/mfs/Makefile new file mode 100644 index 000000000..8ed054eb3 --- /dev/null +++ b/servers/mfs/Makefile @@ -0,0 +1,37 @@ +# Makefile for File System (FS) +SERVER = mfs + +# directories +u = /usr +i = $u/include +s = $i/sys +h = $i/minix + +# programs, flags, etc. +CC = exec cc +CFLAGS = -I$i $(EXTRA_OPTS) +LDFLAGS = -i +LIBS = -lsys -lsysutil -ltimers + +OBJ = cache.o device.o link.o \ + mount.o misc.o open.o pipe.o protect.o read.o \ + stadir.o table.o time.o utility.o \ + write.o inode.o main.o path.o super.o + +# build local binary +install all build: $(SERVER) +$(SERVER): $(OBJ) + $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS) + install -S 16k $@ /sbin + +# clean up local files +clean: + rm -f $(SERVER) *.o *.bak + +depend: + /usr/bin/mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend + +# Include generated dependencies. +include .depend + + diff --git a/servers/fs/buf.h b/servers/mfs/buf.h similarity index 100% rename from servers/fs/buf.h rename to servers/mfs/buf.h diff --git a/servers/fs/cache.c b/servers/mfs/cache.c similarity index 84% rename from servers/fs/cache.c rename to servers/mfs/cache.c index f5e7100b4..02e2a8c2c 100644 --- a/servers/fs/cache.c +++ b/servers/mfs/cache.c @@ -17,13 +17,13 @@ #include "fs.h" #include #include "buf.h" -#include "file.h" -#include "fproc.h" #include "super.h" FORWARD _PROTOTYPE( void rm_lru, (struct buf *bp) ); FORWARD _PROTOTYPE( int rw_block, (struct buf *, int) ); +#define ENABLE_CACHE2 0 + /*===========================================================================* * get_block * *===========================================================================*/ @@ -58,7 +58,6 @@ int only_search; /* if NO_READ, don't read, else act normal */ if (dev != NO_DEV) { b = (int) block & HASH_MASK; bp = buf_hash[b]; - while (bp != NIL_BUF) { if (bp->b_blocknr == block && bp->b_dev == dev) { /* Block needed has been found. */ @@ -70,7 +69,6 @@ int only_search; /* if NO_READ, don't read, else act normal */ /* This block is not the one sought. */ bp = bp->b_hash; /* move to next block on hash chain */ } - } } @@ -86,14 +84,12 @@ int only_search; /* if NO_READ, don't read, else act normal */ } else { /* The block just taken is not on the front of its hash chain. */ while (prev_ptr->b_hash != NIL_BUF) - { if (prev_ptr->b_hash == bp) { prev_ptr->b_hash = bp->b_hash; /* found it */ break; } else { prev_ptr = prev_ptr->b_hash; /* keep looking */ } - } } /* If the block taken is dirty, make it clean by writing it to the disk. @@ -167,7 +163,8 @@ int block_type; /* INODE_BLOCK, DIRECTORY_BLOCK, or whatever */ else front->b_prev = bp; front = bp; - } else { + } + else { /* Block probably will be needed quickly. Put it on rear of chain. * It will not be evicted from the cache for a long time. */ @@ -222,8 +219,7 @@ zone_t z; /* try to allocate new zone near this one */ err_code = ENOSPC; major = (int) (sp->s_dev >> MAJOR) & BYTE; minor = (int) (sp->s_dev >> MINOR) & BYTE; - printf("No space on %sdevice %d/%d\n", - sp->s_dev == root_dev ? "root " : "", major, minor); + printf("No space on device %d/%d\n", major, minor); return(NO_ZONE); } if (z == sp->s_firstdatazone) sp->s_zsearch = b; /* for next time */ @@ -262,7 +258,6 @@ int rw_flag; /* READING or WRITING */ * is not reported to the caller. If the error occurred while purging a block * from the cache, it is not clear what the caller could do about it anyway. */ - int r, op; off_t pos; dev_t dev; @@ -271,19 +266,21 @@ int rw_flag; /* READING or WRITING */ block_size = get_block_size(bp->b_dev); if ( (dev = bp->b_dev) != NO_DEV) { - pos = (off_t) bp->b_blocknr * block_size; - op = (rw_flag == READING ? DEV_READ : DEV_WRITE); - r = dev_bio(op, dev, FS_PROC_NR, bp->b_data, pos, block_size); - if (r != block_size) { - if (r >= 0) r = END_OF_FILE; - if (r != END_OF_FILE) - printf("Unrecoverable disk error on device %d/%d, block %ld\n", - (dev>>MAJOR)&BYTE, (dev>>MINOR)&BYTE, bp->b_blocknr); - bp->b_dev = NO_DEV; /* invalidate block */ + pos = (off_t) bp->b_blocknr * block_size; + op = (rw_flag == READING ? DEV_READ : DEV_WRITE); + r = block_dev_io(op, dev, SELF_E, bp->b_data, pos, block_size, 0); + if (r != block_size) { + if (r >= 0) r = END_OF_FILE; + if (r != END_OF_FILE) + printf("MFS(%d) I/O error on device %d/%d, block %ld\n", + SELF_E, (dev>>MAJOR)&BYTE, (dev>>MINOR)&BYTE, + bp->b_blocknr); + + bp->b_dev = NO_DEV; /* invalidate block */ - /* Report read errors to interested parties. */ - if (rw_flag == READING) rdwt_err = r; - } + /* Report read errors to interested parties. */ + if (rw_flag == READING) rdwt_err = r; + } } bp->b_dirt = CLEAN; @@ -375,9 +372,9 @@ int rw_flag; /* READING or WRITING */ iop->iov_addr = (vir_bytes) bp->b_data; iop->iov_size = block_size; } - r = dev_bio(rw_flag == WRITING ? DEV_SCATTER : DEV_GATHER, - dev, FS_PROC_NR, iovec, - (off_t) bufq[0]->b_blocknr * block_size, j); + r = block_dev_io(rw_flag == WRITING ? DEV_SCATTER : DEV_GATHER, + dev, SELF_E, iovec, + (off_t) bufq[0]->b_blocknr * block_size, j, 0); /* Harvest the results. Dev_io reports the first error it may have * encountered, but we only care if it's the first block that failed. @@ -437,123 +434,12 @@ struct buf *bp; next_ptr = bp->b_next; /* successor on LRU chain */ prev_ptr = bp->b_prev; /* predecessor on LRU chain */ if (prev_ptr != NIL_BUF) - { prev_ptr->b_next = next_ptr; - } else front = next_ptr; /* this block was at front of chain */ if (next_ptr != NIL_BUF) - { next_ptr->b_prev = prev_ptr; - } else rear = prev_ptr; /* this block was at rear of chain */ } - -#if 0 -PRIVATE void check_lru() -{ - int i; - struct buf *bp, *nbp; - - for (i= 0; ib_next; - if (nbp != NULL && (nbp < buf || nbp >= &buf[NR_BUFS])) - { - stacktrace(); - panic(__FILE__, "check_lru: bad next", nbp); - } - nbp= bp->b_prev; - if (nbp != NULL && (nbp < buf || nbp >= &buf[NR_BUFS])) - { - stacktrace(); - panic(__FILE__, "check_lru: bad next", nbp); - } - } -} - -PRIVATE void check_buf(bp) -struct buf *bp; -{ - struct buf *nbp; - - if (bp < buf || bp >= &buf[NR_BUFS]) - { - stacktrace(); - panic(__FILE__, "check_buf: bad buf", bp); - } - nbp= bp->b_next; - if (nbp != NULL && (nbp < buf || nbp >= &buf[NR_BUFS])) - { - stacktrace(); - panic(__FILE__, "check_buf: bad next", nbp); - } - nbp= bp->b_prev; - if (nbp != NULL && (nbp < buf || nbp >= &buf[NR_BUFS])) - { - stacktrace(); - panic(__FILE__, "check_buf: bad next", nbp); - } -} - -PRIVATE void check_hash_chains() -{ - int i; - struct buf *bp; - - for (i= 0; i= &buf[NR_BUFS]) - { - panic(__FILE__, "check_hash_chains: bad buf", - bp); - } - bp= bp->b_hash; - } - } -} - -PUBLIC void check_hash_chainsX(file, line) -char *file; -int line; -{ - int i; - struct buf *bp; - - for (i= 0; i= &buf[NR_BUFS]) - { - printf( - "check_hash_chainsX: called from %s, %d\n", - file, line); - panic(__FILE__, "check_hash_chainsX: bad buf", - bp); - } - bp= bp->b_hash; - } - } -} - -PRIVATE void check_hash_chain(bp) -struct buf *bp; -{ - while (bp) - { - if (bp < buf || bp >= &buf[NR_BUFS]) - { - panic(__FILE__, "check_hash_chain: bad buf", bp); - } - bp= bp->b_hash; - } -} -#endif diff --git a/servers/mfs/const.h b/servers/mfs/const.h new file mode 100644 index 000000000..e6b77e572 --- /dev/null +++ b/servers/mfs/const.h @@ -0,0 +1,108 @@ +/* Tables sizes */ +#define V1_NR_DZONES 7 /* # direct zone numbers in a V1 inode */ +#define V1_NR_TZONES 9 /* total # zone numbers in a V1 inode */ +#define V2_NR_DZONES 7 /* # direct zone numbers in a V2 inode */ +#define V2_NR_TZONES 10 /* total # zone numbers in a V2 inode */ + +#define NR_INODES 256 /* # slots in "in core" inode table */ +#define NR_SUPERS 1 /* # slots in super block table */ + +#define INODE_HASH_LOG2 7 /* 2 based logarithm of the inode hash size */ +#define INODE_HASH_SIZE ((unsigned long)1< +#include +#include +#include +#include +#include +#include +#include +#include "inode.h" +#include "super.h" +#include "const.h" +#include "drivers.h" + +#include + +PRIVATE int dummyproc; + +FORWARD _PROTOTYPE( int safe_io_conversion, (endpoint_t, + cp_grant_id_t *, int *, cp_grant_id_t *, int, endpoint_t *, + void **, int *, vir_bytes, off_t *)); +FORWARD _PROTOTYPE( void safe_io_cleanup, (cp_grant_id_t, cp_grant_id_t *, + int)); + +/*===========================================================================* + * fs_clone_opcl * + *===========================================================================*/ +PUBLIC int fs_clone_opcl(void) +{ + /* A new minor device number has been returned. + * Create a temporary device file to hold it. + */ + struct inode *ip; + dev_t dev; + + dev = fs_m_in.REQ_DEV; /* Device number */ + + ip = alloc_inode(fs_dev, ALL_MODES | I_CHAR_SPECIAL); + + if (ip == NIL_INODE) return err_code; + + ip->i_zone[0] = dev; + + fs_m_out.m_source = ip->i_dev; + fs_m_out.RES_INODE_NR = ip->i_num; + fs_m_out.RES_MODE = ip->i_mode; + return OK; +} + + +/*===========================================================================* + * fs_new_driver * + *===========================================================================*/ +PUBLIC int fs_new_driver(void) +{ + /* New driver endpoint for this device */ + driver_endpoints[(fs_m_in.REQ_DEV >> MAJOR) & BYTE].driver_e = + fs_m_in.REQ_DRIVER_E; + return OK; +} + + +/*===========================================================================* + * safe_io_conversion * + *===========================================================================*/ +PRIVATE int safe_io_conversion(driver, gid, op, gids, gids_size, + io_ept, buf, vec_grants, bytes, pos) +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; +off_t *pos; +{ + int access = 0, size; + int j; + iovec_t *v; + static iovec_t new_iovec[NR_IOREQS]; + + /* Number of grants allocated in vector I/O. */ + *vec_grants = 0; + + /* Driver can handle it - change request to a safe one. */ + + *gid = GRANT_INVALID; + + switch(*op) { + case DEV_READ: + case DEV_WRITE: + /* Change to safe op. */ + *op = *op == DEV_READ ? DEV_READ_S : DEV_WRITE_S; + + if((*gid=cpf_grant_direct(driver, (vir_bytes) *buf, + bytes, *op == DEV_READ_S ? CPF_WRITE : + CPF_READ)) < 0) { + panic(__FILE__, + "cpf_grant_magic of buffer failed\n", NO_NUM); + } + + break; + case DEV_GATHER: + case DEV_SCATTER: + /* Change to safe op. */ + *op = *op == DEV_GATHER ? DEV_GATHER_S : DEV_SCATTER_S; + + /* Grant access to my new i/o vector. */ + if((*gid = cpf_grant_direct(driver, + (vir_bytes) new_iovec, bytes * sizeof(iovec_t), + CPF_READ | CPF_WRITE)) < 0) { + panic(__FILE__, + "cpf_grant_direct of vector failed", NO_NUM); + } + v = (iovec_t *) *buf; + /* Grant access to i/o buffers. */ + for(j = 0; j < bytes; j++) { + if(j >= NR_IOREQS) + panic(__FILE__, "vec too big", 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(__FILE__, "grant to iovec buf failed", + NO_NUM); + } + new_iovec[j].iov_size = v[j].iov_size; + (*vec_grants)++; + } + + /* Set user's vector to the new one. */ + *buf = new_iovec; + break; + /* + case DEV_IOCTL: + *pos = *io_ept; + *op = DEV_IOCTL_S; + if(_MINIX_IOCTL_IOR(m_in.REQUEST)) access |= CPF_WRITE; + if(_MINIX_IOCTL_IOW(m_in.REQUEST)) access |= CPF_READ; + size = _MINIX_IOCTL_SIZE(m_in.REQUEST); + + if((*gid=cpf_grant_magic(driver, *io_ept, + (vir_bytes) *buf, size, access)) < 0) { + panic(__FILE__, + "cpf_grant_magic failed (ioctl)\n", + NO_NUM); + } + */ + } + + /* If we have converted to a safe operation, I/O + * endpoint becomes FS if it wasn't already. + */ + if(GRANT_VALID(*gid)) { + *io_ept = SELF_E; + return 1; + } + + /* 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]); + + return; +} + +/*===========================================================================* + * block_dev_io * + *===========================================================================*/ +PUBLIC int block_dev_io(op, dev, proc_e, buf, pos, bytes, flags) +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 */ +off_t pos; /* byte position */ +int bytes; /* how many bytes to transfer */ +int flags; /* special flags, like O_NONBLOCK */ +{ +/* Read or write from a device. The parameter 'dev' tells which one. */ + struct dmap *dp; + int r, safe; + message m; + iovec_t *v; + cp_grant_id_t gid = GRANT_INVALID; + int vec_grants; + int op_used; + void *buf_used; + static cp_grant_id_t gids[NR_IOREQS]; + endpoint_t driver_e; + + /* Determine driver endpoint for this device */ + driver_e = driver_endpoints[(dev >> MAJOR) & BYTE].driver_e; + + /* See if driver is roughly valid. */ + if (driver_e == NONE) { + printf("MFS(%d) block_dev_io: no driver for dev %x\n", SELF_E, dev); + return EDSTDIED; + } + + /* The io vector copying relies on this I/O being for FS itself. */ + if(proc_e != SELF_E) { + printf("MFS(%d) doing block_dev_io for non-self %d\n", SELF_E, proc_e); + panic(__FILE__, "doing block_dev_io for non-self", proc_e); + } + + /* By default, these are right. */ + m.IO_ENDPT = proc_e; + m.ADDRESS = buf; + buf_used = buf; + + /* Convert parameters to 'safe mode'. */ + op_used = op; + safe = safe_io_conversion(driver_e, &gid, + &op_used, gids, NR_IOREQS, &m.IO_ENDPT, &buf_used, + &vec_grants, bytes, &pos); + + /* Set up rest of the message. */ + if (safe) m.IO_GRANT = (char *) gid; + + m.m_type = op_used; + m.DEVICE = (dev >> MINOR) & BYTE; + m.POSITION = pos; + m.COUNT = bytes; + m.HIGHPOS = 0; + + /* Call the task. */ + r = sendrec(driver_e, &m); + + /* As block I/O never SUSPENDs, safe cleanup must be done whether + * the I/O succeeded or not. */ + if (safe) safe_io_cleanup(gid, gids, vec_grants); + + /* RECOVERY: + * - send back dead driver number + * - VFS unmaps it, waits for new driver + * - VFS sends the new dirver endp for the FS proc and the request again + */ + if (r != OK) { + if (r == EDEADSRCDST || r == EDSTDIED || r == ESRCDIED) { + printf("MFS(%d) dead driver %d\n", SELF_E, driver_e); + driver_endpoints[(dev >> MAJOR) & BYTE].driver_e = NONE; + return r; + /*dmap_unmap_by_endpt(task_nr); <- in the VFS proc... */ + } + else if (r == ELOCKED) { + printf("MFS(%d) ELOCKED talking to %d\n", SELF_E, driver_e); + return r; + } + else + panic(__FILE__,"call_task: can't send/receive", r); + } + else { + /* Did the process we did the sendrec() for get a result? */ + if (m.REP_ENDPT != proc_e) { + printf("MFS(%d) strange device reply from %d, type = %d, proc = %d (not %d) (2) ignored\n", SELF_E, m.m_source, m.m_type, proc_e, m.REP_ENDPT); + r = EIO; + } + } + + /* Task has completed. See if call completed. */ + if (m.REP_STATUS == SUSPEND) { + panic(__FILE__, "MFS block_dev_io: driver returned SUSPEND", NO_NUM); + } + + if(buf != buf_used && r == OK) { + memcpy(buf, buf_used, bytes * sizeof(iovec_t)); + } + + return(m.REP_STATUS); +} + + + + + + + + diff --git a/servers/mfs/drivers.h b/servers/mfs/drivers.h new file mode 100644 index 000000000..2f41fdd55 --- /dev/null +++ b/servers/mfs/drivers.h @@ -0,0 +1,9 @@ + +/* Driver endpoints for major devices. Only the block devices + * are mapped here, it's a subset of the mapping in the VFS */ + +EXTERN struct driver_endpoints { + endpoint_t driver_e; +} driver_endpoints[NR_DEVICES]; + + diff --git a/servers/fs/file.h b/servers/mfs/file.h similarity index 100% rename from servers/fs/file.h rename to servers/mfs/file.h diff --git a/servers/fs/fproc.h b/servers/mfs/fproc.h similarity index 100% rename from servers/fs/fproc.h rename to servers/mfs/fproc.h diff --git a/servers/fs/fs.h b/servers/mfs/fs.h similarity index 100% rename from servers/fs/fs.h rename to servers/mfs/fs.h diff --git a/servers/mfs/glo.h b/servers/mfs/glo.h new file mode 100644 index 000000000..36cd88329 --- /dev/null +++ b/servers/mfs/glo.h @@ -0,0 +1,43 @@ +/* EXTERN should be extern except for the table file */ +#ifdef _TABLE +#undef EXTERN +#define EXTERN +#endif + +EXTERN off_t rdahedpos; /* position to read ahead */ +EXTERN struct inode *rdahed_inode; /* pointer to inode to read ahead */ + +/* The following variables are used for returning results to the caller. */ +EXTERN int err_code; /* temporary storage for error number */ +EXTERN int rdwt_err; /* status of last disk i/o request */ + +EXTERN int cch[NR_INODES]; + +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 _PROTOTYPE (int (*fs_call_vec[]), (void) ); /* fs call table */ + +EXTERN message fs_m_in; +EXTERN message fs_m_out; +EXTERN int FS_STATE; + +EXTERN uid_t caller_uid; +EXTERN gid_t caller_gid; + +EXTERN time_t boottime; /* time in seconds at system boot */ +EXTERN int req_nr; + +EXTERN int SELF_E; + +EXTERN struct inode *chroot_dir; + +EXTERN short path_processed; /* number of characters processed */ +EXTERN char user_path[PATH_MAX]; /* pathname to be processed */ +EXTERN char *vfs_slink_storage; +EXTERN int symloop; + +EXTERN dev_t fs_dev; /* the device that is handled by this FS proc */ + + + diff --git a/servers/mfs/inc.h b/servers/mfs/inc.h new file mode 100644 index 000000000..9f22b60e9 --- /dev/null +++ b/servers/mfs/inc.h @@ -0,0 +1,31 @@ + +#define _SYSTEM 1 /* get OK and negative error codes */ +#define _MINIX 1 /* tell headers to include MINIX stuff */ + +#define VERBOSE 0 /* display diagnostics */ + +#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/fs/inode.c b/servers/mfs/inode.c similarity index 69% rename from servers/fs/inode.c rename to servers/mfs/inode.c index 519c8244b..a98fc9671 100644 --- a/servers/fs/inode.c +++ b/servers/mfs/inode.c @@ -18,16 +18,121 @@ #include "fs.h" #include "buf.h" -#include "file.h" -#include "fproc.h" #include "inode.h" #include "super.h" +#include + FORWARD _PROTOTYPE( void old_icopy, (struct inode *rip, d1_inode *dip, int direction, int norm)); FORWARD _PROTOTYPE( void new_icopy, (struct inode *rip, d2_inode *dip, int direction, int norm)); + +/*===========================================================================* + * fs_putnode * + *===========================================================================*/ +PUBLIC int fs_putnode() +{ +/* Find the inode specified by the request message and decrease its counter. + */ + struct inode *rip; + + /* Sanity check for the direct index */ + if (fs_m_in.REQ_INODE_INDEX >= 0 && + fs_m_in.REQ_INODE_INDEX < NR_INODES && + inode[fs_m_in.REQ_INODE_INDEX].i_num == fs_m_in.REQ_INODE_NR) { + rip = &inode[fs_m_in.REQ_INODE_INDEX]; + } + /* Otherwise find it */ + else { + rip = find_inode(fs_dev, fs_m_in.REQ_INODE_NR); + } + + if (!rip) + printf("FSput_inode: inode #%d dev: %d couldn't be put, req_nr: %d\n", + fs_m_in.REQ_INODE_NR, fs_dev, req_nr); + + put_inode(rip); + return OK; +} + + +/*===========================================================================* + * fs_getnode * + *===========================================================================*/ +PUBLIC int fs_getnode() +{ +/* Increase the inode's counter specified in the request message + */ + struct inode *rip; + /* Get the inode */ + rip = get_inode(fs_dev, fs_m_in.REQ_INODE_NR); + + if (!rip) { + printf("FS: inode #%d couldn't be found\n", fs_m_in.REQ_INODE_NR); + return EINVAL; + } + + /* Transfer back the inode's details */ + fs_m_out.m_source = rip->i_dev; + fs_m_out.RES_INODE_NR = rip->i_num; + fs_m_out.RES_MODE = rip->i_mode; + fs_m_out.RES_FILE_SIZE = rip->i_size; + fs_m_out.RES_DEV = (Dev_t) rip->i_zone[0]; + + return OK; +} + + +/*===========================================================================* + * init_inode_cache * + *===========================================================================*/ +PUBLIC void init_inode_cache() +{ + struct inode *rip; + struct inodelist *rlp; + + inode_cache_hit = 0; + inode_cache_miss = 0; + + /* 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 = 0; + TAILQ_INSERT_HEAD(&unused_inodes, rip, i_unused); + } +} + + +/*===========================================================================* + * addhash_inode * + *===========================================================================*/ +PRIVATE int addhash_inode(struct inode *node) +{ + int hashi = node->i_num & INODE_HASH_MASK; + + /* insert into hash table */ + LIST_INSERT_HEAD(&hash_inodes[hashi], node, i_hash); + return OK; +} + +/*===========================================================================* + * unhash_inode * + *===========================================================================*/ +PRIVATE int unhash_inode(struct inode *node) +{ + /* remove from hash table */ + LIST_REMOVE(node, i_hash); + return OK; +} + /*===========================================================================* * get_inode * *===========================================================================*/ @@ -35,42 +140,81 @@ PUBLIC struct inode *get_inode(dev, numb) dev_t dev; /* device on which inode resides */ int numb; /* inode number (ANSI: may not be unshort) */ { -/* Find a slot in the inode table, load the specified inode into it, and - * return a pointer to the slot. If 'dev' == NO_DEV, just return a free slot. +/* 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, *xp; + int hashi; - /* Search the inode table both for (dev, numb) and a free slot. */ - xp = NIL_INODE; - for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++) { - if (rip->i_count > 0) { /* only check used slots for (dev, numb) */ - if (rip->i_dev == dev && rip->i_num == numb) { - /* This is the inode that we are looking for. */ - rip->i_count++; - return(rip); /* (dev, numb) found */ - } - } else { - xp = rip; /* remember this free slot for later */ - } + hashi = 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) { + inode_cache_hit++; + TAILQ_REMOVE(&unused_inodes, rip, i_unused); + } + ++rip->i_count; + return rip; + } } - /* Inode we want is not currently in use. Did we find a free slot? */ - if (xp == NIL_INODE) { /* inode table completely full */ - err_code = ENFILE; - return(NIL_INODE); + inode_cache_miss++; + + /* Inode is not on the hash, get a free one */ + if (TAILQ_EMPTY(&unused_inodes)) { + err_code = ENFILE; + return NIL_INODE; } + rip = TAILQ_FIRST(&unused_inodes); - /* A free inode slot has been located. Load the inode into it. */ - xp->i_dev = dev; - xp->i_num = numb; - xp->i_count = 1; - if (dev != NO_DEV) rw_inode(xp, READING); /* get inode from disk */ - xp->i_update = 0; /* all the times are initially up-to-date */ + /* If not free unhash it */ + if (rip->i_num != 0) + unhash_inode(rip); + + /* Inode is not unused any more */ + TAILQ_REMOVE(&unused_inodes, rip, i_unused); - return(xp); + /* Load the inode. */ + rip->i_dev = dev; + rip->i_num = numb; + rip->i_count = 1; + if (dev != NO_DEV) rw_inode(rip, READING); /* get inode from disk */ + 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(dev, numb) +dev_t dev; /* device on which inode resides */ +int numb; /* inode number (ANSI: may not be unshort) */ +{ +/* Find the inode specified by the inode and device number. + */ + struct inode *rip; + int hashi; + + hashi = 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 && rip->i_dev == dev) { + return rip; + } + } + + return NIL_INODE; +} + + /*===========================================================================* * put_inode * *===========================================================================*/ @@ -83,6 +227,7 @@ register struct inode *rip; /* pointer to inode to be released */ */ if (rip == NIL_INODE) return; /* checking here is easier than in caller */ + if (--rip->i_count == 0) { /* i_count == 0 means no one is using it now */ if (rip->i_nlinks == 0) { /* i_nlinks == 0 means free the inode. */ @@ -90,14 +235,28 @@ register struct inode *rip; /* pointer to inode to be released */ rip->i_mode = I_NOT_ALLOC; /* clear I_TYPE field */ rip->i_dirt = DIRTY; free_inode(rip->i_dev, rip->i_num); - } else { + } + else { if (rip->i_pipe == I_PIPE) truncate_inode(rip, 0); } + rip->i_mount = NO_MOUNT; rip->i_pipe = NO_PIPE; /* should always be cleared */ if (rip->i_dirt == DIRTY) rw_inode(rip, WRITING); + + if (rip->i_nlinks == 0) { + /* free, put at the front of the LRU list */ + unhash_inode(rip); + rip->i_num = 0; + 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 * *===========================================================================*/ @@ -122,8 +281,7 @@ PUBLIC struct inode *alloc_inode(dev_t dev, mode_t bits) err_code = ENFILE; major = (int) (sp->s_dev >> MAJOR) & BYTE; minor = (int) (sp->s_dev >> MINOR) & BYTE; - printf("Out of i-nodes on %sdevice %d/%d\n", - sp->s_dev == root_dev ? "root " : "", major, minor); + printf("Out of i-nodes on device %d/%d\n", major, minor); return(NIL_INODE); } sp->s_isearch = b; /* next time start here */ @@ -137,8 +295,8 @@ PUBLIC struct inode *alloc_inode(dev_t dev, mode_t bits) /* An inode slot is available. Put the inode just allocated into it. */ rip->i_mode = bits; /* set up RWX bits */ rip->i_nlinks = 0; /* initial no links */ - rip->i_uid = fp->fp_effuid; /* file's uid is owner's */ - rip->i_gid = fp->fp_effgid; /* ditto group id */ + rip->i_uid = caller_uid; /* file's uid is owner's */ + rip->i_gid = caller_gid; /* ditto group id */ rip->i_dev = dev; /* mark which device it is on */ rip->i_ndzones = sp->s_ndzones; /* number of direct zones */ rip->i_nindirs = sp->s_nindirs; /* number of indirect zones per blk*/ diff --git a/servers/mfs/inode.h b/servers/mfs/inode.h new file mode 100644 index 000000000..77effb0b2 --- /dev/null +++ b/servers/mfs/inode.h @@ -0,0 +1,62 @@ +/* Inode table. This table holds inodes that are currently in use. In some + * cases they have been opened by an open() or creat() system call, in other + * cases the file system itself needs the inode for one reason or another, + * such as to search a directory for a path name. + * The first part of the struct holds fields that are present on the + * disk; the second part holds fields not present on the disk. + * The disk inode part is also declared in "type.h" as 'd1_inode' for V1 + * file systems and 'd2_inode' for V2 file systems. + */ + +#include "queue.h" + +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)*/ + zone_t i_zone[V2_NR_TZONES]; /* zone numbers for direct, ind, and dbl ind */ + + /* The following items are not present on the disk. */ + dev_t i_dev; /* which 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 */ + int i_ndzones; /* # direct zones (Vx_NR_DZONES) */ + int i_nindirs; /* # indirect zones per indirect block */ + struct super_block *i_sp; /* pointer to super block for inode's device */ + char i_dirt; /* CLEAN or DIRTY */ + char i_pipe; /* set to I_PIPE if pipe */ + + char i_mount; /* this bit is set if file mounted on */ + short i_vmnt_ind; /* index of the vmnt mounted on */ + + char i_seek; /* set on LSEEK, cleared on READ/WRITE */ + 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]; + +EXTERN unsigned int inode_cache_hit; +EXTERN unsigned int inode_cache_miss; + +#define NIL_INODE (struct inode *) 0 /* indicates absence of inode slot */ + +/* Field values. Note that CLEAN and DIRTY are defined in "const.h" */ +#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 */ +#define NO_MOUNT 0 /* i_mount is NO_MOUNT if file not mounted on*/ +#define I_MOUNT 1 /* i_mount is I_MOUNT if file mounted on */ +#define NO_SEEK 0 /* i_seek = NO_SEEK if last op was not SEEK */ +#define ISEEK 1 /* i_seek = ISEEK if last op was SEEK */ diff --git a/servers/fs/link.c b/servers/mfs/link.c similarity index 74% rename from servers/fs/link.c rename to servers/mfs/link.c index 8fef8f8e2..155421ee7 100644 --- a/servers/fs/link.c +++ b/servers/mfs/link.c @@ -1,29 +1,17 @@ -/* 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 - * truncate_inode: release the blocks associated with an inode up to a size - * freesp_inode: release a range of blocks without setting the size - */ + #include "fs.h" #include #include #include #include + #include "buf.h" -#include "file.h" -#include "fproc.h" #include "inode.h" -#include "param.h" #include "super.h" +#include + #define SAME 1000 FORWARD _PROTOTYPE( int remove_dir, (struct inode *rldirp, struct inode *rip, @@ -38,10 +26,11 @@ FORWARD _PROTOTYPE( void zeroblock_range, (struct inode *i, off_t p, off_t h)); #define FIRST_HALF 0 #define LAST_HALF 1 + /*===========================================================================* - * do_link * + * fs_link * *===========================================================================*/ -PUBLIC int do_link() +PUBLIC int fs_link() { /* Perform the link(name1, name2) system call. */ @@ -50,10 +39,20 @@ PUBLIC int do_link() char string[NAME_MAX]; struct inode *new_ip; - /* See if 'name' (file to be linked) exists. */ - if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code); - + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + /* Copy the link name's last component */ + r = sys_datacopy(FS_PROC_NR, (vir_bytes) fs_m_in.REQ_PATH, + SELF, (vir_bytes) string, + (phys_bytes) fs_m_in.REQ_PATH_LEN); + + /* Temporarily open the file. */ + if ( (rip = get_inode(fs_dev, fs_m_in.REQ_LINKED_FILE)) == NIL_INODE) { +printf("MFS(%d) get_inode by fs_link() failed\n", SELF_E); + return(EINVAL); + } + /* Check to see if the file has maximum number of links already. */ r = OK; if (rip->i_nlinks >= (rip->i_sp->s_version == V1 ? CHAR_MAX : SHRT_MAX)) @@ -61,7 +60,8 @@ PUBLIC int do_link() /* Only super_user may link to directories. */ if (r == OK) - if ( (rip->i_mode & I_TYPE) == I_DIRECTORY && !super_user) r = EPERM; + if ( (rip->i_mode & I_TYPE) == I_DIRECTORY && caller_uid != SU_UID) + r = EPERM; /* If error with 'name', return the inode. */ if (r != OK) { @@ -69,12 +69,11 @@ PUBLIC int do_link() return(r); } - /* Does the final directory of 'name2' exist? */ - if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) { - put_inode(rip); - return(err_code); + /* Temporarily open the last dir */ + if ( (ip = get_inode(fs_dev, fs_m_in.REQ_LINK_PARENT)) == NIL_INODE) { +printf("MFS(%d) get_inode by fs_link() failed\n", SELF_E); + return(EINVAL); } - if ( (ip = last_dir(user_path, string)) == NIL_INODE) r = err_code; /* If 'name2' exists in full (even if no space) set 'r' to error. */ if (r == OK) { @@ -87,10 +86,6 @@ PUBLIC int do_link() } } - /* Check for links across devices. */ - if (r == OK) - if (rip->i_dev != ip->i_dev) r = EXDEV; - /* Try to link. */ if (r == OK) r = search_dir(ip, string, &rip->i_num, ENTER); @@ -108,47 +103,54 @@ PUBLIC int do_link() return(r); } + /*===========================================================================* - * do_unlink * + * fs_unlink * *===========================================================================*/ -PUBLIC int do_unlink() +PUBLIC int fs_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. */ - register struct inode *rip; struct inode *rldirp; int r; char string[NAME_MAX]; + + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + /* Copy the last component */ + r = sys_datacopy(FS_PROC_NR, (vir_bytes) fs_m_in.REQ_PATH, + SELF, (vir_bytes) string, + (phys_bytes) fs_m_in.REQ_PATH_LEN); - /* Get the last directory in the path. */ - if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); - if ( (rldirp = last_dir(user_path, string)) == NIL_INODE) - return(err_code); - + if (r != OK) return r; + + /* Temporarily open the dir. */ + if ( (rldirp = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) { + return(EINVAL); + } + /* The last directory exists. Does the file also exist? */ r = OK; if ( (rip = advance(&rldirp, string)) == NIL_INODE) r = err_code; /* If error, return inode. */ if (r != OK) { + /* Mount point? */ + if (r == EENTERMOUNT || r == ELEAVEMOUNT) + r = EBUSY; put_inode(rldirp); return(r); } - /* Do not remove a mount point. */ - if (rip->i_num == ROOT_INODE) { - put_inode(rldirp); - put_inode(rip); - return(EBUSY); - } - /* Now test if the call is allowed, separately for unlink() and rmdir(). */ - if (call_nr == UNLINK) { + if (fs_m_in.m_type == REQ_UNLINK) { /* Only the su may unlink directories, but the su can unlink any dir.*/ - if ( (rip->i_mode & I_TYPE) == I_DIRECTORY && !super_user) r = EPERM; + if ( (rip->i_mode & I_TYPE) == I_DIRECTORY + && caller_uid != SU_UID) r = EPERM; /* Don't unlink a file if it is the root of a mounted file system. */ if (rip->i_num == ROOT_INODE) r = EBUSY; @@ -156,7 +158,8 @@ PUBLIC int do_unlink() /* Actually try to unlink the file; fails if parent is mode 0 etc. */ if (r == OK) r = unlink_file(rldirp, rip, string); - } else { + } + else { r = remove_dir(rldirp, rip, string); /* call is RMDIR */ } @@ -166,13 +169,126 @@ PUBLIC int do_unlink() return(r); } + + /*===========================================================================* - * do_rename * + * fs_rdlink * *===========================================================================*/ -PUBLIC int do_rename() +PUBLIC int fs_rdlink() +{ + block_t b; /* block containing link text */ + struct buf *bp; /* buffer containing link text */ + register struct inode *rip; /* target inode */ + register int r; /* return value */ + int copylen; + + copylen = fs_m_in.REQ_SLENGTH; + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + /* Temporarily open the file. */ + if ( (rip = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) { + return(EINVAL); + } + + r = EACCES; + if (S_ISLNK(rip->i_mode) && (b = read_map(rip, (off_t) 0)) != NO_BLOCK) { + if (copylen <= 0) r = EINVAL; + else if (copylen < rip->i_size) r = ERANGE; + else { + if(rip->i_size < copylen) copylen = rip->i_size; + bp = get_block(rip->i_dev, b, NORMAL); + r = sys_vircopy(SELF, D, (vir_bytes) bp->b_data, + fs_m_in.REQ_WHO_E, D, (vir_bytes) fs_m_in.REQ_USER_ADDR, + (vir_bytes) copylen); + + if (r == OK) r = copylen; + put_block(bp, DIRECTORY_BLOCK); + } + } + + put_inode(rip); + return(r); +} + + +/*===========================================================================* + * remove_dir * + *===========================================================================*/ +PRIVATE int remove_dir(rldirp, rip, dir_name) +struct inode *rldirp; /* parent directory */ +struct inode *rip; /* directory to be removed */ +char dir_name[NAME_MAX]; /* name of directory to be removed */ +{ + /* A directory file has to be removed. Five conditions have to met: + * - The file must be a directory + * - The directory must be empty (except for . and ..) + * - The final component of the path must not be . or .. + * - The directory must not be the root of a mounted file system (VFS) + * - The directory must not be anybody's root/working directory (VFS) + */ + int r; + + /* search_dir checks that rip is a directory too. */ + if ((r = search_dir(rip, "", (ino_t *) 0, IS_EMPTY)) != OK) return r; + + if (strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0)return(EINVAL); + if (rip->i_num == ROOT_INODE) return(EBUSY); /* can't remove 'root' */ + + /* Actually try to unlink the file; fails if parent is mode 0 etc. */ + if ((r = unlink_file(rldirp, rip, dir_name)) != OK) return r; + + /* Unlink . and .. from the dir. The super user can link and unlink any dir, + * so don't make too many assumptions about them. + */ + (void) unlink_file(rip, NIL_INODE, dot1); + (void) unlink_file(rip, NIL_INODE, dot2); + return(OK); +} + + +/*===========================================================================* + * unlink_file * + *===========================================================================*/ +PRIVATE int unlink_file(dirp, rip, file_name) +struct inode *dirp; /* parent directory of file */ +struct inode *rip; /* inode of file, may be NIL_INODE too. */ +char file_name[NAME_MAX]; /* name of file to be removed */ +{ +/* Unlink 'file_name'; rip must be the inode of 'file_name' or NIL_INODE. */ + + ino_t numb; /* inode number */ + int r; + + /* If rip is not NIL_INODE, it is used to get faster access to the inode. */ + if (rip == NIL_INODE) { + /* Search for file in directory and try to get its inode. */ + err_code = search_dir(dirp, file_name, &numb, LOOK_UP); + if (err_code == OK) rip = get_inode(dirp->i_dev, (int) numb); + if (err_code != OK || rip == NIL_INODE) return(err_code); + } else { + dup_inode(rip); /* inode will be returned with put_inode */ + } + + r = search_dir(dirp, file_name, (ino_t *) 0, DELETE); + + if (r == OK) { + rip->i_nlinks--; /* entry deleted from parent's dir */ + rip->i_update |= CTIME; + rip->i_dirt = DIRTY; + } + + put_inode(rip); + return(r); +} + + +/*===========================================================================* + * fs_rename * + *===========================================================================*/ +PUBLIC int fs_rename() { /* Perform the rename(name1, name2) system call. */ - struct inode *old_dirp, *old_ip; /* ptrs to old dir, file inodes */ struct inode *new_dirp, *new_ip; /* ptrs to new dir, file inodes */ struct inode *new_superdirp, *next_new_superdirp; @@ -183,15 +299,30 @@ PUBLIC int do_rename() ino_t numb; int r1; - /* 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(user_path, old_name))==NIL_INODE) return(err_code); + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + /* Copy the last component of the old name */ + r = sys_datacopy(FS_PROC_NR, (vir_bytes) fs_m_in.REQ_PATH, + SELF, (vir_bytes) old_name, + (phys_bytes) fs_m_in.REQ_PATH_LEN); + if (r != OK) return r; + + /* Copy the last component of the new name */ + r = sys_datacopy(FS_PROC_NR, (vir_bytes) fs_m_in.REQ_USER_ADDR, + SELF, (vir_bytes) new_name, + (phys_bytes) fs_m_in.REQ_SLENGTH); + if (r != OK) return r; + + /* Get old dir inode */ + if ( (old_dirp = get_inode(fs_dev, fs_m_in.REQ_OLD_DIR)) == NIL_INODE) + return(err_code); if ( (old_ip = advance(&old_dirp, old_name)) == NIL_INODE) r = err_code; - /* See if 'name2' (new name) exists. Get dir and file inodes. */ - if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) r = err_code; - if ( (new_dirp = last_dir(user_path, new_name)) == NIL_INODE) r = err_code; + /* Get new dir inode */ + if ( (new_dirp = get_inode(fs_dev, fs_m_in.REQ_NEW_DIR)) == NIL_INODE) + r = err_code; new_ip = advance(&new_dirp, new_name); /* not required to exist */ if (old_ip != NIL_INODE) @@ -206,13 +337,25 @@ PUBLIC int do_rename() dup_inode(new_superdirp = new_dirp); while (TRUE) { /* may hang in a file system loop */ if (new_superdirp == old_ip) { + put_inode(new_superdirp); r = EINVAL; break; } next_new_superdirp = advance(&new_superdirp, dot2); put_inode(new_superdirp); - if (next_new_superdirp == new_superdirp) - break; /* back at system root directory */ + /* + if (next_new_superdirp == new_superdirp) { + put_inode(new_superdirp); + break; + } + */ + if (err_code == ELEAVEMOUNT) { + /* imitate that we are back at the root, + * cross device checked already on VFS */ + /*next_new_superdirp = new_superdirp;*/ + err_code = OK; + break; + } new_superdirp = next_new_superdirp; if (new_superdirp == NIL_INODE) { /* Missing ".." entry. Assume the worst. */ @@ -220,36 +363,49 @@ PUBLIC int do_rename() break; } } - put_inode(new_superdirp); + /*put_inode(new_superdirp);*/ } /* The old or new name must not be . or .. */ if (strcmp(old_name, ".")==0 || strcmp(old_name, "..")==0 || - strcmp(new_name, ".")==0 || strcmp(new_name, "..")==0) r = EINVAL; - - /* Both parent directories must be on the same device. */ - if (old_dirp->i_dev != new_dirp->i_dev) r = EXDEV; + strcmp(new_name, ".")==0 || strcmp(new_name, "..")==0) { + r = EINVAL; + } + /* Both parent directories must be on the same device. + if (old_dirp->i_dev != new_dirp->i_dev) r = EXDEV; */ /* Parent dirs must be writable, searchable and on a writable device */ if ((r1 = forbidden(old_dirp, W_BIT | X_BIT)) != OK || - (r1 = forbidden(new_dirp, W_BIT | X_BIT)) != OK) r = r1; + (r1 = forbidden(new_dirp, W_BIT | X_BIT)) != OK) { + r = r1; + } /* Some tests apply only if the new path exists. */ if (new_ip == NIL_INODE) { - /* don't rename a file with a file system mounted on it. */ - if (old_ip->i_dev != old_dirp->i_dev) r = EXDEV; + /* don't rename a file with a file system mounted on it. + if (old_ip->i_dev != old_dirp->i_dev) r = EXDEV;*/ if (odir && new_dirp->i_nlinks >= (new_dirp->i_sp->s_version == V1 ? CHAR_MAX : SHRT_MAX) && - !same_pdir && r == OK) r = EMLINK; - } else { - if (old_ip == new_ip) r = SAME; /* old=new */ - - /* has the old file or new file a file system mounted on it? */ + !same_pdir && r == OK) { + r = EMLINK; + } + } + else { + if (old_ip == new_ip) { + r = SAME; /* old=new */ + } + + /* has the old file or new file a file system mounted on it? if (old_ip->i_dev != new_ip->i_dev) r = EXDEV; + */ ndir = ((new_ip->i_mode & I_TYPE) == I_DIRECTORY); /* dir ? */ - if (odir == TRUE && ndir == FALSE) r = ENOTDIR; - if (odir == FALSE && ndir == TRUE) r = EISDIR; + if (odir == TRUE && ndir == FALSE) { + r = ENOTDIR; + } + if (odir == FALSE && ndir == TRUE) { + r = EISDIR; + } } } @@ -320,46 +476,65 @@ PUBLIC int do_rename() return(r == SAME ? OK : r); } + /*===========================================================================* - * do_truncate * + * fs_trunc * *===========================================================================*/ -PUBLIC int do_truncate() +PUBLIC int fs_trunc() { -/* truncate_inode() 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. - */ - int r; - struct inode *rip; /* pointer to inode to be truncated */ + struct inode *rip; + int r = OK; + + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + /* Temporarily open the file. */ + if ( (rip = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) { +printf("MFS(%d) get_inode by fs_chmod() failed\n", SELF_E); + return(EINVAL); + } + + if ( (rip->i_mode & I_TYPE) != I_REGULAR) + r = EINVAL; + else + r = truncate_inode(rip, fs_m_in.REQ_LENGTH); + + put_inode(rip); - if (fetch_name(m_in.m2_p1, m_in.m2_i1, M1) != OK) - return err_code; - if( (rip = eat_path(user_path)) == NIL_INODE) - return err_code; - if ( (rip->i_mode & I_TYPE) != I_REGULAR) - r = EINVAL; - else - r = truncate_inode(rip, m_in.m2_l1); - put_inode(rip); - - return r; + return r; } /*===========================================================================* - * do_ftruncate * + * fs_ftrunc * *===========================================================================*/ -PUBLIC int do_ftruncate() +PUBLIC int fs_ftrunc(void) { -/* As with do_truncate(), truncate_inode() does the actual work. */ - struct filp *rfilp; - if ( (rfilp = get_filp(m_in.m2_i1)) == NIL_FILP) - return err_code; - if ( (rfilp->filp_ino->i_mode & I_TYPE) != I_REGULAR) - return EINVAL; - return truncate_inode(rfilp->filp_ino, m_in.m2_l1); + struct inode *rip; + off_t start, end; + int r; + + if ( (rip = find_inode(fs_dev, fs_m_in.REQ_FD_INODE_NR)) + == NIL_INODE) { + printf("FSfreesp: couldn't find inode %d\n", + fs_m_in.REQ_FD_INODE_NR); + return EINVAL; + } + + start = fs_m_in.REQ_FD_START; + end = fs_m_in.REQ_FD_END; + + if (end == 0) { + r = truncate_inode(rip, start); + } + else { + r = freesp_inode(rip, start, end); + } + + return r; } + + /*===========================================================================* * truncate_inode * *===========================================================================*/ @@ -539,78 +714,4 @@ off_t len; put_block(bp, FULL_DATA_BLOCK); } -/*===========================================================================* - * remove_dir * - *===========================================================================*/ -PRIVATE int remove_dir(rldirp, rip, dir_name) -struct inode *rldirp; /* parent directory */ -struct inode *rip; /* directory to be removed */ -char dir_name[NAME_MAX]; /* name of directory to be removed */ -{ - /* A directory file has to be removed. Five conditions have to met: - * - The file must be a directory - * - The directory must be empty (except for . and ..) - * - The final component of the path must not be . or .. - * - The directory must not be the root of a mounted file system - * - The directory must not be anybody's root/working directory - */ - int r; - register struct fproc *rfp; - - /* search_dir checks that rip is a directory too. */ - if ((r = search_dir(rip, "", (ino_t *) 0, IS_EMPTY)) != OK) return r; - - if (strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0)return(EINVAL); - if (rip->i_num == ROOT_INODE) return(EBUSY); /* can't remove 'root' */ - - for (rfp = &fproc[INIT_PROC_NR + 1]; rfp < &fproc[NR_PROCS]; rfp++) - if (rfp->fp_pid != PID_FREE && - (rfp->fp_workdir == rip || rfp->fp_rootdir == rip)) - return(EBUSY); /* can't remove anybody's working dir */ - - /* Actually try to unlink the file; fails if parent is mode 0 etc. */ - if ((r = unlink_file(rldirp, rip, dir_name)) != OK) return r; - - /* Unlink . and .. from the dir. The super user can link and unlink any dir, - * so don't make too many assumptions about them. - */ - (void) unlink_file(rip, NIL_INODE, dot1); - (void) unlink_file(rip, NIL_INODE, dot2); - return(OK); -} - -/*===========================================================================* - * unlink_file * - *===========================================================================*/ -PRIVATE int unlink_file(dirp, rip, file_name) -struct inode *dirp; /* parent directory of file */ -struct inode *rip; /* inode of file, may be NIL_INODE too. */ -char file_name[NAME_MAX]; /* name of file to be removed */ -{ -/* Unlink 'file_name'; rip must be the inode of 'file_name' or NIL_INODE. */ - - ino_t numb; /* inode number */ - int r; - - /* If rip is not NIL_INODE, it is used to get faster access to the inode. */ - if (rip == NIL_INODE) { - /* Search for file in directory and try to get its inode. */ - err_code = search_dir(dirp, file_name, &numb, LOOK_UP); - if (err_code == OK) rip = get_inode(dirp->i_dev, (int) numb); - if (err_code != OK || rip == NIL_INODE) return(err_code); - } else { - dup_inode(rip); /* inode will be returned with put_inode */ - } - - r = search_dir(dirp, file_name, (ino_t *) 0, DELETE); - - if (r == OK) { - rip->i_nlinks--; /* entry deleted from parent's dir */ - rip->i_update |= CTIME; - rip->i_dirt = DIRTY; - } - - put_inode(rip); - return(r); -} diff --git a/servers/fs/lock.h b/servers/mfs/lock.h similarity index 100% rename from servers/fs/lock.h rename to servers/mfs/lock.h diff --git a/servers/mfs/main.c b/servers/mfs/main.c new file mode 100644 index 000000000..5da82d7f0 --- /dev/null +++ b/servers/mfs/main.c @@ -0,0 +1,198 @@ + +#include "inc.h" +#include +#include + +#include +#include "fs.h" +#include "buf.h" +#include "inode.h" +#include "drivers.h" + + +/* Declare some local functions. */ +FORWARD _PROTOTYPE(void init_server, (void) ); +FORWARD _PROTOTYPE(void get_work, (message *m_in) ); + +FORWARD _PROTOTYPE(void cch_check, (void) ); + + +/*===========================================================================* + * main * + *===========================================================================*/ +PUBLIC int main(void) +{ +/* 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 who_e; /* caller */ + int error; + message m; + + /* Initialize the server, then go to work. */ + init_server(); + + printf("\nMFS(%d): STARTED: Logging in to VFS\n", SELF_E); + fs_m_in.m_type = FS_READY; + + if (sendrec(FS_PROC_NR, &fs_m_in) != OK) { + printf("MFS(%d): Error sending login to VFS\n", SELF_E); + return -1; + } + + if (fs_m_in.m_type != REQ_READSUPER) { + printf("MFS(%d): Invalid login reply\n", SELF_E); + return -1; + } + else { + fs_m_out.m_type = fs_readsuper(); + reply(FS_PROC_NR, &fs_m_out); + if (fs_m_out.m_type != OK) return -1; + } + printf("MFS(%d): Login + Readsuper OK\n", SELF_E); + + + for (;;) { + /* Wait for request message. */ + get_work(&fs_m_in); + error = OK; + + who_e = fs_m_in.m_source; + if (who_e != FS_PROC_NR) { + if (who_e == 0) { + /* + printf("MFS(%d): MSG from PM\n", SELF_E); + error = 1; + fs_m_out.m_type = error; + reply(who_e, &fs_m_out); + */ + } + continue; + } + + req_nr = fs_m_in.m_type; + + if (req_nr < 0 || req_nr >= NREQS) { + error = EINVAL; + } + else { + error = (*fs_call_vec[req_nr])(); + /*cch_check();*/ + } + + fs_m_out.m_type = error; + reply(who_e, &fs_m_out); + + + if (error == OK && rdahed_inode != NIL_INODE) { + read_ahead(); /* do block read ahead */ + } + + /* + * VFS asks RS to bring down the FS... */ + /* + if (req_nr == REQ_UNMOUNT || + (req_nr == REQ_READSUPER && error != OK)) { + printf("MFS(%d) exit() cachehit: %d cachemiss: %d\n", SELF_E, + inode_cache_hit, inode_cache_miss); + return 0; + } + */ + } +} + +/*===========================================================================* + * buf_pool * + *===========================================================================*/ +PRIVATE void buf_pool(void) +{ +/* Initialize the buffer pool. */ + register struct buf *bp; + + bufs_in_use = 0; + front = &buf[0]; + rear = &buf[NR_BUFS - 1]; + + for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) { + bp->b_blocknr = NO_BLOCK; + bp->b_dev = NO_DEV; + bp->b_next = bp + 1; + bp->b_prev = bp - 1; + } + buf[0].b_prev = NIL_BUF; + buf[NR_BUFS - 1].b_next = NIL_BUF; + + for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) bp->b_hash = bp->b_next; + buf_hash[0] = front; + +} + + +/*===========================================================================* + * init_server * + *===========================================================================*/ +PRIVATE void init_server(void) +{ + int i; + + /* Init inode table */ + for (i = 0; i < NR_INODES; ++i) { + inode[i].i_count = 0; + cch[i] = 0; + } + + init_inode_cache(); + + /* Init driver mapping */ + for (i = 0; i < NR_DEVICES; ++i) + driver_endpoints[i].driver_e = NONE; + + SELF_E = getprocnr(); + buf_pool(); +} + +/*===========================================================================* + * get_work * + *===========================================================================*/ +PRIVATE void get_work(m_in) +message *m_in; /* pointer to message */ +{ + int s; /* receive status */ + if (OK != (s = receive(ANY, m_in))) /* wait for message */ + panic("MFS","receive failed", s); +} + + +/*===========================================================================* + * reply * + *===========================================================================*/ +PUBLIC void reply(who, m_out) +int who; +message *m_out; /* report result */ +{ + if (OK != send(who, m_out)) /* send the message */ + printf("MFS(%d) was unable to send reply\n", SELF_E); +} + +PRIVATE void cch_check(void) +{ + int i; + + for (i = 0; i < NR_INODES; ++i) { + if (inode[i].i_count != cch[i] && + req_nr != REQ_OPEN && req_nr != REQ_GETNODE && + req_nr != REQ_PUTNODE && req_nr != REQ_GETDIR && + req_nr != REQ_CLONE_OPCL && req_nr != REQ_READSUPER && + req_nr != REQ_MOUNTPOINT && req_nr != REQ_UNMOUNT && + req_nr != REQ_PIPE && req_nr != REQ_SYNC && + req_nr != REQ_LOOKUP) +printf("MFS(%d) inode(%d) cc: %d req_nr: %d\n", + SELF_E, inode[i].i_num, inode[i].i_count - cch[i], req_nr); + + cch[i] = inode[i].i_count; + } +} + + + diff --git a/servers/mfs/misc.c b/servers/mfs/misc.c new file mode 100644 index 000000000..3613fc71f --- /dev/null +++ b/servers/mfs/misc.c @@ -0,0 +1,34 @@ + +#include "fs.h" +#include + +#include "buf.h" +#include "inode.h" + + +/*===========================================================================* + * fs_sync * + *===========================================================================*/ +PUBLIC int fs_sync() +{ +/* Perform the sync() system call. Flush all the tables. + * The order in which the various tables are flushed is critical. The + * blocks must be flushed last, since rw_inode() leaves its results in + * the block cache. + */ + register struct inode *rip; + register struct buf *bp; + + /* Write all the dirty inodes to the disk. */ + for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++) + if (rip->i_count > 0 && rip->i_dirt == DIRTY) rw_inode(rip, WRITING); + + /* Write all the dirty blocks to the disk, one drive at a time. */ + for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) + if (bp->b_dev != NO_DEV && bp->b_dirt == DIRTY) + flushall(bp->b_dev); + + return(OK); /* sync() can't fail */ +} + + diff --git a/servers/mfs/mount.c b/servers/mfs/mount.c new file mode 100644 index 000000000..ae19bf407 --- /dev/null +++ b/servers/mfs/mount.c @@ -0,0 +1,196 @@ + + +#include "fs.h" +#include +#include +#include +#include +#include "buf.h" +#include "inode.h" +#include "super.h" +#include "drivers.h" +#include + + + + + +/*===========================================================================* + * fs_readsuper * + *===========================================================================*/ +PUBLIC int fs_readsuper() +{ +/* This function reads the superblock of the partition, gets the root inode + * and sends back the details of them. Note, that the FS process does not + * know the index of the vmnt object which refers to it, whenever the pathname + * lookup leaves a partition an ELEAVEMOUNT error is transferred back + * so that the VFS knows that it has to find the vnode on which this FS + * process' partition is mounted on. + */ + struct super_block *xp, *sp; + struct inode *root_ip; + int r = OK; + + fs_dev = fs_m_in.REQ_DEV; + + /* Map the driver endpoint for this major */ + driver_endpoints[(fs_dev >> MAJOR) & BYTE].driver_e = fs_m_in.REQ_DRIVER_E; + boottime = fs_m_in.REQ_BOOTTIME; + vfs_slink_storage = fs_m_in.REQ_SLINK_STORAGE; + + sp = &super_block[0]; + + /* Fill in the super block. */ + sp->s_dev = fs_dev; /* read_super() needs to know which dev */ + r = read_super(sp); + + /* Is it recognized as a Minix filesystem? */ + if (r != OK) { +printf("MFS(%d)readsuper read_super() ERROR\n", SELF_E); + sp->s_dev = NO_DEV; + return(r); + } + + /* Get the root inode of the mounted file system. */ + root_ip = NIL_INODE; /* if 'r' not OK, make sure this is defined */ + if (r == OK) { + if ( (root_ip = get_inode(fs_dev, ROOT_INODE)) == NIL_INODE) + r = err_code; + } + + if (root_ip != NIL_INODE && root_ip->i_mode == 0) { + put_inode(root_ip); + r = EINVAL; + } + + if (r != OK) return r; + sp->s_rd_only = fs_m_in.REQ_READONLY; + sp->s_is_root = fs_m_in.REQ_ISROOT; + + /* Root inode properties */ + fs_m_out.RES_INODE_NR = root_ip->i_num; + fs_m_out.RES_MODE = root_ip->i_mode; + fs_m_out.RES_FILE_SIZE = root_ip->i_size; + + /* Partition properties */ + fs_m_out.RES_MAXSIZE = sp->s_max_size; + fs_m_out.RES_BLOCKSIZE = sp->s_block_size; + +if (r == OK) + printf("MFS(%d)readsuper DEV: %d driver_e: %d BOOTT: %d\n", + SELF_E, fs_dev, fs_m_in.REQ_DRIVER_E, boottime); + return r; +} + + +/*===========================================================================* + * fs_mountpoint * + *===========================================================================*/ +PUBLIC int fs_mountpoint() +{ +/* This function looks up the mount point, it checks the condition whether + * the partition can be mounted on the inode or not. If ok, it gets the + * mountpoint inode's details and stores the mounted vmnt's index (in the + * vmnt table) so that it can be transferred back when the pathname lookup + * encounters a mountpoint. + */ + register struct inode *rip; + int r = OK; + mode_t bits; + + /* Get inode */ + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + /* Temporarily open the file. */ + if ( (rip = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) { +printf("MFS(%d) get_inode by fs_mountpoint() failed\n", SELF_E); + return(EINVAL); + } + + /* It may not be busy. */ + if (rip->i_count > 1) r = EBUSY; + + /* It may not be special. */ + bits = rip->i_mode & I_TYPE; + if (bits == I_BLOCK_SPECIAL || bits == I_CHAR_SPECIAL) r = ENOTDIR; + + if ((rip->i_mode & I_TYPE) != I_DIRECTORY) r = ENOTDIR; + + if (r != OK) { + put_inode(rip); + return r; + } + + rip->i_mount = I_MOUNT; + rip->i_vmnt_ind = fs_m_in.REQ_VMNT_IND; + + fs_m_out.m_source = rip->i_dev;/* Filled with the FS endp by the system */ + fs_m_out.RES_INODE_NR = rip->i_num; + fs_m_out.RES_FILE_SIZE = rip->i_size; + fs_m_out.RES_MODE = rip->i_mode; + + return r; +} + + +/*===========================================================================* + * fs_unmount * + *===========================================================================*/ +PUBLIC int fs_unmount() +{ +/* Unmount a file system by device number. */ + struct super_block *sp, *sp1; + int count; + register struct inode *rip; + + /* !!!!!!!!!!!!! REMOVE THIS LATER !!!!!!!!!!!!!!!!!!!!!!! */ + /* Find the super block. */ + sp = NIL_SUPER; + for (sp1 = &super_block[0]; sp1 < &super_block[NR_SUPERS]; sp1++) { + if (sp1->s_dev == fs_dev) { + sp = sp1; + break; + } + } + if (sp == NIL_SUPER) { + return(EINVAL); + } + /* !!!!!!!!!!!!! REMOVE THIS LATER !!!!!!!!!!!!!!!!!!!!!!! */ + + /* See if the mounted device is busy. Only 1 inode using it should be + * open -- the root inode -- and that inode only 1 time. + */ + count = 0; + for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++) { + if (rip->i_count > 0 && rip->i_dev == fs_dev) { +/*printf("FSunmount DEV: %d inode: %d count: %d iaddr: %d\n", + rip->i_dev, rip->i_num, rip->i_count, rip);*/ + count += rip->i_count; + } + } + + if (count > 1) { + printf("MFS(%d) unmount: filesystem is busy %d\n", SELF_E, count); + return(EBUSY); /* can't umount a busy file system */ + } + + /* Put the root inode */ + rip = get_inode(fs_dev, ROOT_INODE); + put_inode(rip); + put_inode(rip); + + /* Sync the disk, and invalidate cache. */ + (void) fs_sync(); /* force any cached blocks out of memory */ + /*invalidate(fs_dev);*/ /* invalidate cache entries for this dev */ + + /* Finish off the unmount. */ + sp->s_dev = NO_DEV; + + +printf("MFS(%d) DEV %d unmounted\n", SELF_E, fs_dev); + return OK; +} + + + diff --git a/servers/mfs/open.c b/servers/mfs/open.c new file mode 100644 index 000000000..9e040c1ee --- /dev/null +++ b/servers/mfs/open.c @@ -0,0 +1,426 @@ + + +#include "fs.h" +#include +#include +#include +#include +#include +#include +#include "buf.h" +#include "inode.h" +#include "super.h" + +#include + +PRIVATE char mode_map[] = {R_BIT, W_BIT, R_BIT|W_BIT, 0}; +FORWARD _PROTOTYPE( struct inode *new_node, (struct inode *ldirp, + char *string, mode_t bits, zone_t z0, int opaque, char *parsed)); + + +/*===========================================================================* + * fs_open * + *===========================================================================*/ +PUBLIC int fs_open() +{ + int r, b, exist = TRUE; + struct inode *ldirp; + struct inode *rip; + int oflags; + mode_t omode; + mode_t bits; + char lastc[NAME_MAX]; + + /* Read request message */ + oflags = fs_m_in.REQ_FLAGS; + omode = fs_m_in.REQ_MODE; + + + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + /* Device number only for device special files */ + fs_m_out.RES_DEV = NO_DEV; + + /* Remap the bottom two bits of oflags. */ + bits = (mode_t) mode_map[oflags & O_ACCMODE]; + + + /* If O_CREATE is set, try to make the file. */ + if (oflags & O_CREAT) { + /* Copy the last component */ + err_code = sys_datacopy(FS_PROC_NR, (vir_bytes) fs_m_in.REQ_PATH, + SELF, (vir_bytes) lastc, (phys_bytes) fs_m_in.REQ_PATH_LEN); + + if (err_code != OK) return err_code; + + /* Get last directory inode */ + if ((ldirp = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) { +printf("MFS(%d) get_inode for parent dir by creat() failed\n", SELF_E); + return ENOENT; + } + + /* Create a new inode by calling new_node(). */ + rip = new_node(ldirp, lastc, omode, NO_ZONE, oflags&O_EXCL, NULL); + r = err_code; + if (r == OK) exist = FALSE; /* we just created the file */ + else if (r != EEXIST) { + put_inode(ldirp); + return(r); /* other error */ + } + else exist = !(oflags & O_EXCL); /* file exists, if the O_EXCL + flag is set this is an error */ + } + else { + /* Get file inode. */ + if ( (rip = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) { +printf("MFS(%d) get_inode by open() failed\n", SELF_E); + return ENOENT; + } + ldirp = NIL_INODE; + } + + /* Only do the normal open code if we didn't just create the file. */ + if (exist) { + /* Check protections. */ + if ((r = forbidden(rip, bits)) == OK) { + /* Opening reg. files directories and special files differ. */ + switch (rip->i_mode & I_TYPE) { + case I_REGULAR: + /* Truncate regular file if O_TRUNC. */ + if (oflags & O_TRUNC) { + if ((r = forbidden(rip, W_BIT)) !=OK) break; + truncate_inode(rip, 0); + wipe_inode(rip); + /* Send the inode from the inode cache to the + * block cache, so it gets written on the next + * cache flush. + */ + rw_inode(rip, WRITING); + } + break; + + case I_DIRECTORY: + /* Directories may be read but not written. */ + r = (bits & W_BIT ? EISDIR : OK); + break; + + case I_CHAR_SPECIAL: + case I_BLOCK_SPECIAL: + /* Send back the device number */ + fs_m_out.RES_DEV = (Dev_t) rip->i_zone[0]; + break; + + case I_NAMED_PIPE: + rip->i_pipe = I_PIPE; + b = (bits & R_BIT ? R_BIT : W_BIT); + if (b == R_BIT) + fs_m_out.RES_POS = rip->i_zone[V2_NR_DZONES+0]; + else + fs_m_out.RES_POS = rip->i_zone[V2_NR_DZONES+1]; + break; + } + } + } + + /* If error, release inode. */ + if (r != OK) { + put_inode(ldirp); + put_inode(rip); + return(r); + } + + /* Reply message */ + fs_m_out.m_source = rip->i_dev; /* filled with FS endpoint by the system */ + fs_m_out.RES_INODE_NR = rip->i_num; + fs_m_out.RES_MODE = rip->i_mode; + fs_m_out.RES_FILE_SIZE = rip->i_size; + fs_m_out.RES_INODE_INDEX = (rip - &inode[0]) / sizeof(struct inode); + + /* This values are needed for the execution */ + fs_m_out.RES_UID = rip->i_uid; + fs_m_out.RES_GID = rip->i_gid; + if ((rip->i_mode & I_TYPE) == I_REGULAR) fs_m_out.RES_CTIME = rip->i_ctime; + + /* Drop parent dir */ + put_inode(ldirp); + + return OK; +} + +/*===========================================================================* + * fs_mknod * + *===========================================================================*/ +PUBLIC int fs_mknod() +{ + struct inode *ip, *ldirp; + char lastc[NAME_MAX]; + + /* Copy the last component and set up caller's user and group id */ + err_code = sys_datacopy(FS_PROC_NR, (vir_bytes) fs_m_in.REQ_PATH, SELF, + (vir_bytes) lastc, (phys_bytes) fs_m_in.REQ_PATH_LEN); + + if (err_code != OK) return err_code; + + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + /* Get last directory inode */ + if ((ldirp = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) { +printf("MFS(%d) get_inode for parent dir by mknod() failed\n", SELF_E); + return ENOENT; + } + + /* Try to create the new node */ + ip = new_node(ldirp, lastc, fs_m_in.REQ_MODE, (zone_t) fs_m_in.REQ_DEV, + TRUE, NULL); + + put_inode(ip); + put_inode(ldirp); + return(err_code); +} + + +/*===========================================================================* + * fs_mkdir * + *===========================================================================*/ +PUBLIC int fs_mkdir() +{ + int r1, r2; /* status codes */ + ino_t dot, dotdot; /* inode numbers for . and .. */ + struct inode *rip, *ldirp; + char lastc[NAME_MAX]; /* last component */ + + /* Copy the last component and set up caller's user and group id */ + err_code = sys_datacopy(FS_PROC_NR, (vir_bytes) fs_m_in.REQ_PATH, SELF, + (vir_bytes) lastc, (phys_bytes) + MIN(fs_m_in.REQ_PATH_LEN, NAME_MAX)); + + if (err_code != OK) return err_code; + + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + /* Get last directory inode */ + if ((ldirp = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) { +printf("MFS(%d) get_inode for parent dir by mkdir() failed\n", SELF_E); + return ENOENT; + } + + /* Next make the inode. If that fails, return error code. */ + rip = new_node(ldirp, lastc, fs_m_in.REQ_MODE, (zone_t) 0, TRUE, NULL); + + if (rip == NIL_INODE || err_code == EEXIST) { + put_inode(rip); /* can't make dir: it already exists */ + put_inode(ldirp); + return(err_code); + } + + /* Get the inode numbers for . and .. to enter in the directory. */ + dotdot = ldirp->i_num; /* parent's inode number */ + dot = rip->i_num; /* inode number of the new dir itself */ + + /* Now make dir entries for . and .. unless the disk is completely full. */ + /* Use dot1 and dot2, so the mode of the directory isn't important. */ + rip->i_mode = fs_m_in.REQ_MODE; /* set mode */ + r1 = search_dir(rip, dot1, &dot, ENTER); /* enter . in the new dir */ + r2 = search_dir(rip, dot2, &dotdot, ENTER); /* enter .. in the new dir */ + + /* If both . and .. were successfully entered, increment the link counts. */ + if (r1 == OK && r2 == OK) { + /* Normal case. It was possible to enter . and .. in the new dir. */ + rip->i_nlinks++; /* this accounts for . */ + ldirp->i_nlinks++; /* this accounts for .. */ + ldirp->i_dirt = DIRTY; /* mark parent's inode as dirty */ + } else { + /* It was not possible to enter . or .. probably disk was full - + * links counts haven't been touched. + */ + if(search_dir(ldirp, lastc, (ino_t *) 0, DELETE) != OK) + panic(__FILE__, "Dir disappeared ", rip->i_num); + rip->i_nlinks--; /* undo the increment done in new_node() */ + } + rip->i_dirt = DIRTY; /* either way, i_nlinks has changed */ + + put_inode(ldirp); /* return the inode of the parent dir */ + put_inode(rip); /* return the inode of the newly made dir */ + return(err_code); /* new_node() always sets 'err_code' */ +} + +/*===========================================================================* + * fs_slink * + *===========================================================================*/ +PUBLIC int fs_slink() +{ + struct inode *sip; /* inode containing symbolic link */ + struct inode *ldirp; /* directory containing link */ + register int r; /* error code */ + char string[NAME_MAX]; /* last component of the new dir's path name */ + struct buf *bp; /* disk buffer for link */ + + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + /* Temporarily open the dir. */ + if ( (ldirp = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) { + return(EINVAL); + } + + /* Copy the link name's last component */ + r = sys_datacopy(FS_PROC_NR, (vir_bytes) fs_m_in.REQ_PATH, + SELF, (vir_bytes) string, + (phys_bytes) fs_m_in.REQ_PATH_LEN); + + if (r != OK) return r; + + /* Create the inode for the symlink. */ + sip = new_node(ldirp, string, (mode_t) (I_SYMBOLIC_LINK | RWX_MODES), + (zone_t) 0, TRUE, NULL); + + /* Allocate a disk block for the contents of the symlink. + * Copy contents of symlink (the name pointed to) into first disk block. + */ + if ((r = err_code) == OK) { + r = (bp = new_block(sip, (off_t) 0)) == NIL_BUF ? err_code : + sys_vircopy(fs_m_in.REQ_WHO_E, D, (vir_bytes) fs_m_in.REQ_USER_ADDR, + SELF, D, (vir_bytes) bp->b_data, + (vir_bytes) fs_m_in.REQ_SLENGTH); + + if(r == OK) { + bp->b_data[_MIN_BLOCK_SIZE-1] = '\0'; + sip->i_size = strlen(bp->b_data); + /*if(sip->i_size != m_in.name1_length-1) {*/ + if(sip->i_size != fs_m_in.REQ_SLENGTH) { + /* This can happen if the user provides a buffer + * with a \0 in it. This can cause a lot of trouble + * when the symlink is used later. We could just use + * the strlen() value, but we want to let the user + * know he did something wrong. ENAMETOOLONG doesn't + * exactly describe the error, but there is no + * ENAMETOOWRONG. + */ + r = ENAMETOOLONG; + } + } + + put_block(bp, DIRECTORY_BLOCK); /* put_block() accepts NIL_BUF. */ + + if (r != OK) { + sip->i_nlinks = 0; + if (search_dir(ldirp, string, (ino_t *) 0, DELETE) != OK) + panic(__FILE__, "Symbolic link vanished", NO_NUM); + } + } + + /* put_inode() accepts NIL_INODE as a noop, so the below are safe. */ + put_inode(sip); + put_inode(ldirp); + + return(r); +} + + + +/*===========================================================================* + * new_node * + *===========================================================================*/ +PRIVATE struct inode *new_node(struct inode *ldirp, + char *string, mode_t bits, zone_t z0, int opaque, char *parsed) +{ +/* New_node() is called by fs_open(), fs_mknod(), and fs_mkdir(). + * In all cases it allocates a new inode, makes a directory entry for it in + * the ldirp directory with string name, and initializes it. + * It returns a pointer to the inode if it can do this; + * otherwise it returns NIL_INODE. It always sets 'err_code' + * to an appropriate value (OK or an error code). + * + * The parsed path rest is returned in 'parsed' if parsed is nonzero. It + * has to hold at least NAME_MAX bytes. + */ + + register struct inode *rip; + register int r; + + /* + *ldirp = parse_path(path, string, opaque ? LAST_DIR : LAST_DIR_EATSYM); + if (*ldirp == NIL_INODE) return(NIL_INODE); + */ + + /* Get final component of the path. */ + rip = advance(&ldirp, string); + + if (S_ISDIR(bits) && + (ldirp)->i_nlinks >= ((ldirp)->i_sp->s_version == V1 ? + CHAR_MAX : SHRT_MAX)) { + /* New entry is a directory, alas we can't give it a ".." */ + put_inode(rip); + err_code = EMLINK; + return(NIL_INODE); + } + + if ( rip == NIL_INODE && err_code == ENOENT) { + /* Last path component does not exist. Make new directory entry. */ + if ( (rip = alloc_inode((ldirp)->i_dev, bits)) == NIL_INODE) { + /* Can't creat new inode: out of inodes. */ + return(NIL_INODE); + } + + /* Force inode to the disk before making directory entry to make + * the system more robust in the face of a crash: an inode with + * no directory entry is much better than the opposite. + */ + rip->i_nlinks++; + rip->i_zone[0] = z0; /* major/minor device numbers */ + rw_inode(rip, WRITING); /* force inode to disk now */ + + /* New inode acquired. Try to make directory entry. */ + if ((r = search_dir(ldirp, string, &rip->i_num, ENTER)) != OK) { + rip->i_nlinks--; /* pity, have to free disk inode */ + rip->i_dirt = DIRTY; /* dirty inodes are written out */ + put_inode(rip); /* this call frees the inode */ + err_code = r; + return(NIL_INODE); + } + + } else { + /* Either last component exists, or there is some problem. */ + if (rip != NIL_INODE || err_code == EENTERMOUNT || + err_code == ELEAVEMOUNT) + r = EEXIST; + else + r = err_code; + } + + if(parsed) { /* Give the caller the parsed string if requested. */ + strncpy(parsed, string, NAME_MAX-1); + parsed[NAME_MAX-1] = '\0'; + } + + /* The caller has to return the directory inode (*ldirp). */ + err_code = r; + return(rip); +} + + + + + + +/*===========================================================================* + * fs_inhibread * + *===========================================================================*/ +PUBLIC int fs_inhibread() +{ + struct inode *rip; + + if ((rip = find_inode(fs_dev, fs_m_in.REQ_INODE_NR))== NIL_INODE){ + printf("FSinhibread: couldn't find inode %d\n", fs_m_in.REQ_INODE_NR); + return EINVAL; + } + + /* inhibit read ahead */ + rip->i_seek = ISEEK; + + return OK; +} + diff --git a/servers/fs/param.h b/servers/mfs/param.h similarity index 100% rename from servers/fs/param.h rename to servers/mfs/param.h diff --git a/servers/fs/path.c b/servers/mfs/path.c similarity index 63% rename from servers/fs/path.c rename to servers/mfs/path.c index 18b1f9b21..ab0b80cef 100644 --- a/servers/fs/path.c +++ b/servers/mfs/path.c @@ -12,20 +12,74 @@ #include "fs.h" #include #include +#include #include #include "buf.h" -#include "file.h" -#include "fproc.h" #include "inode.h" #include "super.h" +#include + + PUBLIC char dot1[2] = "."; /* used for search_dir to bypass the access */ PUBLIC char dot2[3] = ".."; /* permissions for . and .. */ FORWARD _PROTOTYPE( char *get_name, (char *old_name, char string [NAME_MAX]) ); +FORWARD _PROTOTYPE( int ltraverse, (struct inode *rip, char *path, + char *suffix) ); + + +/*===========================================================================* + * lookup * + *===========================================================================*/ +PUBLIC int lookup() +{ + char string[NAME_MAX]; + struct inode *rip; + int s_error; + + string[0] = '\0'; + + /* Copy the pathname and set up caller's user and group id */ + err_code = sys_datacopy(FS_PROC_NR, (vir_bytes) fs_m_in.REQ_PATH, SELF, + (vir_bytes) user_path, (phys_bytes) fs_m_in.REQ_PATH_LEN); + + if (err_code != OK) return err_code; + + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + /* Lookup inode */ + rip = parse_path(user_path, string, fs_m_in.REQ_FLAGS); + + /* Copy back the last name if it is required */ + if ((fs_m_in.REQ_FLAGS & LAST_DIR || fs_m_in.REQ_FLAGS & LAST_DIR_EATSYM) + && err_code != ENAMETOOLONG) { + s_error = sys_datacopy(SELF_E, (vir_bytes) string, FS_PROC_NR, + (vir_bytes) fs_m_in.REQ_USER_ADDR, (phys_bytes) + MIN(strlen(string)+1, NAME_MAX)); + if (s_error != OK) return s_error; + } + + /* Error or mount point encountered */ + if (rip == NIL_INODE) + return err_code; + + fs_m_out.RES_INODE_NR = rip->i_num; + fs_m_out.RES_MODE = rip->i_mode; + fs_m_out.RES_FILE_SIZE = rip->i_size; + + /* If 'path' is a block special file, return dev number. */ + if ( (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL) { + fs_m_out.RES_DEV = (dev_t) rip->i_zone[0]; + } + + /* Drop inode (path parse increased the counter) */ + put_inode(rip); + + return OK; +} -FORWARD _PROTOTYPE( struct inode *ltraverse, (struct inode *rip, - char *path, char *suffix, struct inode *ldip) ); /*===========================================================================* * parse_path * @@ -44,22 +98,69 @@ int action; /* action on last part of path */ */ struct inode *rip, *dir_ip; + struct inode *ver_rip; char *new_name; - int symloop; char lstring[NAME_MAX]; + + /* Find starting inode inode according to the request message */ + if ((rip = find_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) { + printf("FS: couldn't find starting inode req_nr: %d %s\n", req_nr, + user_path); + err_code = ENOENT; + return NIL_INODE; + } - /* Is the path absolute or relative? Initialize 'rip' accordingly. */ - rip = (*path == '/' ? fp->fp_rootdir : fp->fp_workdir); + /* Find chroot inode according to the request message */ + if (fs_m_in.REQ_CHROOT_NR != 0) { + if ((chroot_dir = find_inode(fs_dev, fs_m_in.REQ_CHROOT_NR)) + == NIL_INODE) { + printf("FS: couldn't find chroot inode\n"); + err_code = ENOENT; + return NIL_INODE; + } + } + else chroot_dir = NIL_INODE; - /* If dir has been removed or path is empty, return ENOENT. */ - if (rip->i_nlinks == 0 || *path == '\0') { + /* Set user and group ID */ + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + /* No characters were processed yet */ + path_processed = 0; + + /* Current number of symlinks encountered */ + symloop = fs_m_in.REQ_SYMLOOP; + + /* If dir has been removed return ENOENT. */ + /* Note: empty (start) path is checked in the VFS process */ + if (rip->i_nlinks == 0/* || *path == '\0'*/) { err_code = ENOENT; return(NIL_INODE); } - dup_inode(rip); /* inode will be returned with put_inode */ + /* There is only one way how the starting directory of the lookup + * can be a mount point which is not a root directory, + * namely: climbing up on a mount (ELEAVEMOUNT). + * In this case the lookup is intrested in the parent dir of the mount + * point, but the last ".." component was processed in the 'previous' + * FS process. Let's do that first. + */ + if (rip->i_mount == I_MOUNT && rip->i_num != ROOT_INODE) { + dir_ip = rip; + rip = advance(&dir_ip, ".."); + if (rip == NIL_INODE) return rip; + put_inode(rip); /* advance() increased the counter */ + } + + dup_inode(rip); /* inode will be returned with put_inode */ + + /* Looking for the starting directory? + * Note: this happens after EENTERMOUNT or ELEAVEMOUNT + * without more path component */ + if (*path == '\0') { + return rip; + } - symloop = 0; /* symbolic link traversal count */ if (string == (char *) 0) string = lstring; /* Scan the path component by component. */ @@ -83,31 +184,64 @@ int action; /* action on last part of path */ /* There is more path. Keep parsing. */ dir_ip = rip; rip = advance(&dir_ip, string); + + /* Mount point encountered? */ + if (rip == NIL_INODE && (err_code == EENTERMOUNT || + err_code == ELEAVEMOUNT)) { + put_inode(dir_ip); + return NIL_INODE; + } - if (rip == NIL_INODE) { - if (*new_name == '\0' && (action & PATH_NONSYMBOLIC) != 0) - return(dir_ip); - else { - put_inode(dir_ip); - return(NIL_INODE); - } - } + if (rip == NIL_INODE) { + if (*new_name == '\0' && (action & PATH_NONSYMBOLIC) != 0) + return(dir_ip); + else { + put_inode(dir_ip); + return(NIL_INODE); + } + } /* The call to advance() succeeded. Fetch next component. */ if (S_ISLNK(rip->i_mode)) { - if (*new_name != '\0' || (action & PATH_OPAQUE) == 0) { + if (*new_name != '\0' || (action & PATH_OPAQUE) == 0) { + if (*new_name != '\0') new_name--; - rip = ltraverse(rip, path, new_name, dir_ip); - put_inode(dir_ip); - if (++symloop > SYMLOOP) { - err_code = ELOOP; - put_inode(rip); - rip = NIL_INODE; + + /* Extract path name from the symlink file */ + if (ltraverse(rip, user_path, new_name) != OK) { + put_inode(dir_ip); + err_code = ENOENT; + return NIL_INODE; + } + + /* Symloop limit reached? */ + if (++symloop > SYMLOOP) { + put_inode(dir_ip); + err_code = ELOOP; + return NIL_INODE; + } + + /* Start over counting */ + path_processed = 0; + + /* Check whether new path is relative or absolute */ + if (user_path[0] == '/') { + /* Go back to VFS */ + put_inode(dir_ip); + err_code = ESYMLINK; + fs_m_out.RES_OFFSET = path_processed; + fs_m_out.RES_SYMLOOP = symloop; + return NIL_INODE; + } + /* Path is relative */ + else { + rip = dir_ip; + path = user_path; + continue; } - if (rip == NIL_INODE) return(NIL_INODE); - continue; } - } else if (*new_name != '\0') { + } + else if (*new_name != '\0') { put_inode(dir_ip); path = new_name; continue; @@ -124,60 +258,27 @@ int action; /* action on last part of path */ } } -/*===========================================================================* - * eat_path * - *===========================================================================*/ -PUBLIC struct inode *eat_path(path) -char *path; /* the path name to be parsed */ -{ - /* Parse the path 'path' and put its inode in the inode table. If not possible, - * return NIL_INODE as function value and an error code in 'err_code'. - */ - - return parse_path(path, (char *) 0, EAT_PATH); -} - -/*===========================================================================* - * last_dir * - *===========================================================================*/ -PUBLIC struct inode *last_dir(path, string) -char *path; /* the path name to be parsed */ -char string[NAME_MAX]; /* the final component is returned here */ -{ -/* Given a path, 'path', located in the fs address space, parse it as - * far as the last directory, fetch the inode for the last directory into - * the inode table, and return a pointer to the inode. In - * addition, return the final component of the path in 'string'. - * If the last directory can't be opened, return NIL_INODE and - * the reason for failure in 'err_code'. - */ - - return parse_path(path, string, LAST_DIR); -} - /*===========================================================================* * ltraverse * *===========================================================================*/ -PRIVATE struct inode *ltraverse(rip, path, suffix, ldip) +PRIVATE int ltraverse(rip, path, suffix) register struct inode *rip; /* symbolic link */ char *path; /* path containing link */ char *suffix; /* suffix following link within path */ -register struct inode *ldip; /* directory containing link */ { /* Traverse a symbolic link. Copy the link text from the inode and insert - * the text into the path. Return the inode of base directory and the - * ammended path. The symbolic link inode is always freed. The inode - * returned is already duplicated. NIL_INODE is returned on error. + * the text into the path. Return error code or report success. Base + * directory has to be determined according to the first character of the + * new pathname. */ block_t b; /* block containing link text */ - struct inode *bip; /* inode of base directory */ struct buf *bp; /* buffer containing link text */ size_t sl; /* length of link */ size_t tl; /* length of suffix */ char *sp; /* start of link text */ + int r = OK; - bip = NIL_INODE; bp = NIL_BUF; if ((b = read_map(rip, (off_t) 0)) != NO_BLOCK) { @@ -188,62 +289,30 @@ register struct inode *ldip; /* directory containing link */ /* Insert symbolic text into path name. */ tl = strlen(suffix); if (sl > 0 && sl + tl <= PATH_MAX-1) { - memmove(path+sl, suffix, tl); - memmove(path, sp, sl); - path[sl+tl] = 0; - dup_inode(bip = path[0] == '/' ? fp->fp_rootdir : ldip); + memmove(path+sl, suffix, tl); + memmove(path, sp, sl); + path[sl+tl] = 0; + + /* Copy back to VFS layer THIS SHOULD BE IN parse_path */ + r = sys_datacopy(SELF_E, (vir_bytes) path, FS_PROC_NR, + (vir_bytes) vfs_slink_storage, (phys_bytes) sl+tl+1); + + /* + dup_inode(bip = path[0] == '/' ? chroot_dir : ldip); + */ } } + else { + r = ENOENT; + } put_block(bp, DIRECTORY_BLOCK); put_inode(rip); - if (bip == NIL_INODE) - { - err_code = ENOENT; - } - return (bip); + return r; } -/*===========================================================================* - * get_name * - *===========================================================================*/ -PRIVATE char *get_name(old_name, string) -char *old_name; /* path name to parse */ -char string[NAME_MAX]; /* component extracted from 'old_name' */ -{ -/* Given a pointer to a path name in fs space, 'old_name', copy the next - * component to 'string' and pad with zeros. A pointer to that part of - * the name as yet unparsed is returned. Roughly speaking, - * 'get_name' = 'old_name' - 'string'. - * - * This routine follows the standard convention that /usr/ast, /usr//ast, - * //usr///ast and /usr/ast/ are all equivalent. - */ - register int c; - register char *np, *rnp; - np = string; /* 'np' points to current position */ - rnp = old_name; /* 'rnp' points to unparsed string */ - while ( (c = *rnp) == '/') rnp++; /* skip leading slashes */ - - /* Copy the unparsed path, 'old_name', to the array, 'string'. */ - while ( rnp < &old_name[PATH_MAX] && c != '/' && c != '\0') { - if (np < &string[NAME_MAX]) *np++ = c; - c = *++rnp; /* advance to next character */ - } - - /* To make /usr/ast/ equivalent to /usr/ast, skip trailing slashes. */ - while (c == '/' && rnp < &old_name[PATH_MAX]) c = *++rnp; - - if (np < &string[NAME_MAX]) *np = '\0'; /* Terminate string */ - - if (rnp >= &old_name[PATH_MAX]) { - err_code = ENAMETOOLONG; - return((char *) 0); - } - return(rnp); -} /*===========================================================================* * advance * @@ -277,14 +346,18 @@ char string[NAME_MAX]; /* component name to look for */ return(NIL_INODE); } - /* Don't go beyond the current root directory, unless the string is dot2. */ - if (dirp == fp->fp_rootdir && strcmp(string, "..") == 0 && string != dot2) - return(get_inode(dirp->i_dev, (int) dirp->i_num)); + /* Don't go beyond the current root directory, unless the string is dot2. + * Note: it has to be checked only if this FS process owns the chroot + * directory of the process */ + if (chroot_dir != NIL_INODE) { + if (dirp == chroot_dir && strcmp(string, "..") == 0 && string != dot2) + return(get_inode(dirp->i_dev, (int) dirp->i_num)); + } /* The component has been found in the directory. Get inode. */ if ( (rip = get_inode(dirp->i_dev, (int) numb)) == NIL_INODE) { return(NIL_INODE); - } + } /* The following test is for "mountpoint/.." where mountpoint is a * mountpoint. ".." will refer to the root of the mounted filesystem, @@ -296,46 +369,97 @@ char string[NAME_MAX]; /* component name to look for */ * root inode, _and_ the name[1] being '.'. (This is a test for '..' * and excludes '.'.) */ - if (rip->i_num == ROOT_INODE) - if (dirp->i_num == ROOT_INODE) { - if (string[1] == '.') { - sp= rip->i_sp; - if (sp->s_imount != sp->s_isup) - { - /* Release the root inode. Replace by the - * inode mounted on. Update parent. - */ - put_inode(rip); - put_inode(dirp); - mnt_dev = sp->s_imount->i_dev; - inumb = (int) sp->s_imount->i_num; - dirp = *pdirp = get_inode(mnt_dev, inumb); - rip = advance(pdirp, string); - } - } - } + if (rip->i_num == ROOT_INODE) { + if (dirp->i_num == ROOT_INODE) { + if (string[1] == '.') { + sp = rip->i_sp; + if (!sp->s_is_root) { +/*printf("FSadvance: ELEAVEMOUNT callnr: %d, cp: %d, restp: %s\n", + call_nr, path_processed, user_path + path_processed);*/ + + /* Climbing up mountpoint */ + err_code = ELEAVEMOUNT; + /* This will be the FS process endoint */ + fs_m_out.m_source = rip->i_dev; + fs_m_out.RES_OFFSET = path_processed; + fs_m_out.RES_SYMLOOP = symloop; + put_inode(rip); + /*put_inode(dirp);*/ + rip = NIL_INODE; + } + } + } + } if (rip == NIL_INODE) return(NIL_INODE); /* See if the inode is mounted on. If so, switch to root directory of the * mounted file system. The super_block provides the linkage between the * inode mounted on and the root directory of the mounted file system. */ - while (rip != NIL_INODE && rip->i_mount == I_MOUNT) { - /* The inode is indeed mounted on. */ - for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) { - if (sp->s_imount == rip) { - /* Release the inode mounted on. Replace by the - * inode of the root inode of the mounted device. - */ - put_inode(rip); - rip = get_inode(sp->s_dev, ROOT_INODE); - break; - } - } + if (rip != NIL_INODE && rip->i_mount == I_MOUNT) { +/*printf("FSadvance: EENTERMOUNT callnr: %d, cp: %d, vmnti: %d, restp: %s\n", + call_nr, path_processed, rip->i_vmnt_ind, user_path + path_processed);*/ + + /* Mountpoint encountered, report it */ + err_code = EENTERMOUNT; + fs_m_out.RES_INODE_NR = rip->i_num; + fs_m_out.RES_OFFSET = path_processed; + fs_m_out.RES_SYMLOOP = symloop; + put_inode(rip); + rip = NIL_INODE; } return(rip); /* return pointer to inode's component */ } + +/*===========================================================================* + * get_name * + *===========================================================================*/ +PRIVATE char *get_name(old_name, string) +char *old_name; /* path name to parse */ +char string[NAME_MAX]; /* component extracted from 'old_name' */ +{ +/* Given a pointer to a path name in fs space, 'old_name', copy the next + * component to 'string' and pad with zeros. A pointer to that part of + * the name as yet unparsed is returned. Roughly speaking, + * 'get_name' = 'old_name' - 'string'. + * + * This routine follows the standard convention that /usr/ast, /usr//ast, + * //usr///ast and /usr/ast/ are all equivalent. + */ + + register int c; + register char *np, *rnp; + + np = string; /* 'np' points to current position */ + rnp = old_name; /* 'rnp' points to unparsed string */ + while ( (c = *rnp) == '/') { + rnp++; /* skip leading slashes */ + path_processed++; /* count characters */ + } + + /* Copy the unparsed path, 'old_name', to the array, 'string'. */ + while ( rnp < &old_name[PATH_MAX] && c != '/' && c != '\0') { + if (np < &string[NAME_MAX]) *np++ = c; + c = *++rnp; /* advance to next character */ + path_processed++; /* count characters */ + } + + /* To make /usr/ast/ equivalent to /usr/ast, skip trailing slashes. */ + while (c == '/' && rnp < &old_name[PATH_MAX]) { + c = *++rnp; + path_processed++; /* count characters */ + } + + if (np < &string[NAME_MAX]) *np = '\0'; /* Terminate string */ + + if (rnp >= &old_name[PATH_MAX]) { + err_code = ENAMETOOLONG; + return((char *) 0); + } + return(rnp); +} + /*===========================================================================* * search_dir * *===========================================================================*/ @@ -368,7 +492,7 @@ int flag; /* LOOK_UP, ENTER, DELETE or IS_EMPTY */ if ( (ldir_ptr->i_mode & I_TYPE) != I_DIRECTORY) { return(ENOTDIR); } - + r = OK; if (flag != IS_EMPTY) { @@ -413,7 +537,7 @@ int flag; /* LOOK_UP, ENTER, DELETE or IS_EMPTY */ if (strcmp(dp->d_name, "." ) != 0 && strcmp(dp->d_name, "..") != 0) match = 1; } else { - if (strncmp(dp->d_name, string, NAME_MAX) == 0) { + if (strncmp(dp->d_name, string, NAME_MAX) == 0){ match = 1; } } @@ -484,3 +608,35 @@ int flag; /* LOOK_UP, ENTER, DELETE or IS_EMPTY */ } return(OK); } + + +/*===========================================================================* + * eat_path * + *===========================================================================*/ +PUBLIC struct inode *eat_path(path) +char *path; /* the path name to be parsed */ +{ + /* Parse the path 'path' and put its inode in the inode table. If not possible, + * return NIL_INODE as function value and an error code in 'err_code'. + */ + + return parse_path(path, (char *) 0, EAT_PATH); +} + +/*===========================================================================* + * last_dir * + *===========================================================================*/ +PUBLIC struct inode *last_dir(path, string) +char *path; /* the path name to be parsed */ +char string[NAME_MAX]; /* the final component is returned here */ +{ +/* Given a path, 'path', located in the fs address space, parse it as + * far as the last directory, fetch the inode for the last directory into + * the inode table, and return a pointer to the inode. In + * addition, return the final component of the path in 'string'. + * If the last directory can't be opened, return NIL_INODE and + * the reason for failure in 'err_code'. + */ + + return parse_path(path, string, LAST_DIR); +} diff --git a/servers/mfs/pipe.c b/servers/mfs/pipe.c new file mode 100644 index 000000000..188cf27ed --- /dev/null +++ b/servers/mfs/pipe.c @@ -0,0 +1,57 @@ + +#include "fs.h" +#include +#include +#include +#include +#include +#include +#include +#include "inode.h" +#include "super.h" + +#include + + + +/*===========================================================================* + * fs_pipe * + *===========================================================================*/ +PUBLIC int fs_pipe(void) +{ + struct inode *rip; + + /* Get caller's user and group id from the request */ + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + /* Try to allocate the inode */ + if ( (rip = alloc_inode(fs_dev, I_REGULAR) ) == NIL_INODE) { + return err_code; + } + + /* !!! already checked in alloc_inode + if (read_only(rip) != OK) + panic(__FILE__,"pipe device is read only", NO_NUM); + */ + + /* Fill in the fields of the inode */ + rip->i_pipe = I_PIPE; + rip->i_mode &= ~I_REGULAR; + rip->i_mode |= I_NAMED_PIPE; /* pipes and FIFOs have this bit set */ + + /* We'll need it twice, nothing can go wrong here */ + dup_inode(rip); + rw_inode(rip, WRITING); /* mark inode as allocated */ + rip->i_update = ATIME | CTIME | MTIME; + + /* Fill in the fields of the response message */ + fs_m_out.m_source = fs_dev; /* filled with FS endpoint by the system */ + fs_m_out.RES_INODE_NR = rip->i_num; + fs_m_out.RES_MODE = rip->i_mode; + fs_m_out.RES_INODE_INDEX = (rip - &inode[0]) / sizeof(struct inode); + + return OK; +} + + diff --git a/servers/fs/protect.c b/servers/mfs/protect.c similarity index 53% rename from servers/fs/protect.c rename to servers/mfs/protect.c index 295b2dfb2..a2d1d609b 100644 --- a/servers/fs/protect.c +++ b/servers/mfs/protect.c @@ -1,146 +1,123 @@ -/* 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 - * forbidden: check to see if a given access is allowed on a given inode - */ + #include "fs.h" #include #include #include "buf.h" -#include "file.h" -#include "fproc.h" #include "inode.h" -#include "param.h" #include "super.h" +#include + + /*===========================================================================* - * do_chmod * + * fs_chmod * *===========================================================================*/ -PUBLIC int do_chmod() +PUBLIC int fs_chmod() { /* Perform the chmod(name, mode) system call. */ - register struct inode *rip = NULL; + register struct inode *rip; register int r; - - if(call_nr == CHMOD) { - /* Temporarily open the file. */ - if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); - if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code); - } else if(call_nr == FCHMOD) { - struct filp *filp; - if(!(filp = get_filp(m_in.m3_i1))) return(err_code); - rip = filp->filp_ino; - } else panic(__FILE__, "do_chmod called with strange call_nr", call_nr); + + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + /* Temporarily open the file. */ + if ( (rip = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) { +printf("MFS(%d) get_inode by fs_chmod() failed\n", SELF_E); + return(EINVAL); + } /* 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 (rip->i_uid != fp->fp_effuid && !super_user) + if (rip->i_uid != caller_uid && caller_uid != SU_UID) r = EPERM; else r = read_only(rip); /* If error, return inode. */ if (r != OK) { - if(call_nr == CHMOD) put_inode(rip); + put_inode(rip); return(r); } /* Now make the change. Clear setgid bit if file is not in caller's grp */ - rip->i_mode = (rip->i_mode & ~ALL_MODES) | (m_in.mode & ALL_MODES); - if (!super_user && rip->i_gid != fp->fp_effgid)rip->i_mode &= ~I_SET_GID_BIT; + rip->i_mode = (rip->i_mode & ~ALL_MODES) | (fs_m_in.REQ_MODE & ALL_MODES); + if (caller_uid != SU_UID && rip->i_gid != caller_gid) + rip->i_mode &= ~I_SET_GID_BIT; rip->i_update |= CTIME; rip->i_dirt = DIRTY; - if(call_nr == CHMOD) put_inode(rip); + put_inode(rip); return(OK); } + /*===========================================================================* - * do_chown * + * fs_chown * *===========================================================================*/ -PUBLIC int do_chown() +PUBLIC int fs_chown() { -/* Perform the chown(name, owner, group) system call. */ - - register struct inode *rip = NULL; + register struct inode *rip; register int r; - - if(call_nr == CHOWN) { - /* Temporarily open the file. */ - if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code); - } else if(call_nr == FCHOWN) { - struct filp *filp; - if(!(filp = get_filp(m_in.m1_i1))) return(err_code); - rip = filp->filp_ino; - } else panic(__FILE__, "do_chown called with strange call_nr", call_nr); + /* Temporarily open the file. */ + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + /* Temporarily open the file. */ + if ( (rip = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) { +printf("MFS(%d) get_inode by fs_chown() failed\n", SELF_E); + return(EINVAL); + } /* Not permitted to change the owner of a file on a read-only file sys. */ r = read_only(rip); if (r == OK) { /* FS is R/W. Whether call is allowed depends on ownership, etc. */ - if (super_user) { + if (caller_uid == SU_UID) { /* The super user can do anything. */ - rip->i_uid = m_in.owner; /* others later */ + rip->i_uid = fs_m_in.REQ_NEW_UID; /* others later */ } else { /* Regular users can only change groups of their own files. */ - if (rip->i_uid != fp->fp_effuid) r = EPERM; - if (rip->i_uid != m_in.owner) r = EPERM; /* no giving away */ - if (fp->fp_effgid != m_in.group) r = EPERM; + if (rip->i_uid != caller_uid) r = EPERM; + if (rip->i_uid != fs_m_in.REQ_NEW_UID) + r = EPERM; /* no giving away */ + if (caller_gid != fs_m_in.REQ_NEW_GID) r = EPERM; } } if (r == OK) { - rip->i_gid = m_in.group; + rip->i_gid = fs_m_in.REQ_NEW_GID; rip->i_mode &= ~(I_SET_UID_BIT | I_SET_GID_BIT); rip->i_update |= CTIME; rip->i_dirt = DIRTY; } - if(call_nr == CHOWN) put_inode(rip); + put_inode(rip); return(r); } /*===========================================================================* - * do_umask * + * fs_access * *===========================================================================*/ -PUBLIC int do_umask() +PUBLIC int fs_access() { -/* 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. */ - struct inode *rip; register int r; - - /* 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 whose access is to be checked. */ - if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); - if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code); + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + /* Temporarily open the file. */ + if ( (rip = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) { +printf("MFS(%d) get_inode by fs_access() failed\n", SELF_E); + return(EINVAL); + } /* Now check the permissions. */ - r = forbidden(rip, (mode_t) m_in.mode); + r = forbidden(rip, (mode_t) fs_m_in.REQ_MODE); put_inode(rip); return(r); } @@ -159,20 +136,20 @@ PUBLIC int forbidden(register struct inode *rip, mode_t access_desired) register struct inode *old_rip = rip; register struct super_block *sp; register mode_t bits, perm_bits; - int r, shift, test_uid, test_gid, type; + int r, shift, type; - if (rip->i_mount == I_MOUNT) /* The inode is mounted on. */ + /* + if (rip->i_mount == I_MOUNT) for (sp = &super_block[1]; sp < &super_block[NR_SUPERS]; sp++) if (sp->s_imount == rip) { rip = get_inode(sp->s_dev, ROOT_INODE); break; - } /* if */ + } + */ /* Isolate the relevant rwx bits from the mode. */ bits = rip->i_mode; - test_uid = (call_nr == ACCESS ? fp->fp_realuid : fp->fp_effuid); - test_gid = (call_nr == ACCESS ? fp->fp_realgid : fp->fp_effgid); - if (test_uid == SU_UID) { + if (caller_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. @@ -183,8 +160,8 @@ PUBLIC int forbidden(register struct inode *rip, mode_t access_desired) else perm_bits = R_BIT | W_BIT; } else { - if (test_uid == rip->i_uid) shift = 6; /* owner */ - else if (test_gid == rip->i_gid ) shift = 3; /* group */ + if (caller_uid == rip->i_uid) shift = 6; /* owner */ + else if (caller_gid == rip->i_gid ) shift = 3; /* group */ else shift = 0; /* other */ perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT); } @@ -203,6 +180,7 @@ PUBLIC int forbidden(register struct inode *rip, mode_t access_desired) if (rip != old_rip) put_inode(rip); +/*printf("FSforbidden: %s %s\n", user_path, (r == OK ? "OK" : "notOK")); */ return(r); } @@ -221,3 +199,6 @@ struct inode *ip; /* ptr to inode whose file sys is to be cked */ sp = ip->i_sp; return(sp->s_rd_only ? EROFS : OK); } + + + diff --git a/servers/fs/proto.h b/servers/mfs/proto.h similarity index 63% rename from servers/fs/proto.h rename to servers/mfs/proto.h index c37d66843..2ed4d75b9 100644 --- a/servers/fs/proto.h +++ b/servers/mfs/proto.h @@ -2,15 +2,53 @@ #include "timers.h" -#include - /* Structs used in prototypes must be declared as such first. */ struct buf; struct filp; -struct fproc; struct inode; struct super_block; + +int fs_open(void); +int fs_putnode(void); +int fs_getnode(void); +int fs_pipe(void); +int fs_readwrite(void); +int fs_clone_opcl(void); +int fs_new_driver(void); +int fs_ftrunc(void); +int fs_chown(void); +int fs_chmod(void); +int fs_access(void); +int fs_mknod(void); +int fs_mkdir(void); +int fs_inhibread(void); +int fs_stat(void); +int fs_fstat(void); +int fs_unlink(void); +int fs_utime(void); +int fs_fstatfs(void); +int fs_lstat(void); +int fs_getdir(void); +int fs_link(void); +int fs_lookup_rn_old(void); +int fs_lookup_rn_new(void); +int fs_rename(void); + +int fs_mountpoint(void); +int fs_readsuper(void); +int fs_unmount(void); +int fs_trunc(void); +int fs_sync(void); +int fs_stime(void); +int lookup(void); + +int fs_slink(void); +int fs_rdlink(void); +int fs_breadwrite(void); + +void init_inode_cache(void); + /* cache.c */ _PROTOTYPE( zone_t alloc_zone, (Dev_t dev, zone_t z) ); _PROTOTYPE( void flushall, (Dev_t dev) ); @@ -30,51 +68,13 @@ _PROTOTYPE( void invalidate2, (Dev_t device) ); #endif /* device.c */ -_PROTOTYPE( int dev_open, (Dev_t dev, int proc, int flags) ); -_PROTOTYPE( void dev_close, (Dev_t dev) ); -_PROTOTYPE( int dev_bio, (int op, Dev_t dev, int proc, void *buf, - off_t pos, int bytes) ); -_PROTOTYPE( int dev_io, (int op, Dev_t dev, int proc, void *buf, +_PROTOTYPE( int block_dev_io, (int op, Dev_t dev, int proc, void *buf, off_t pos, int bytes, int flags) ); -_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 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 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 dev_up, (int major) ); -/* dmp.c */ -_PROTOTYPE( int do_fkey_pressed, (void) ); - -/* dmap.c */ -_PROTOTYPE( int do_devctl, (void) ); -_PROTOTYPE( int fs_devctl, (int req, int dev, int proc_nr_e, int style, - int force) ); -_PROTOTYPE( void build_dmap, (void) ); -_PROTOTYPE( int map_driver, (int major, int proc_nr, int dev_style, - int force) ); -_PROTOTYPE( int dmap_driver_match, (int proc, int major) ); -_PROTOTYPE( void dmap_unmap_by_endpt, (int proc_nr) ); -_PROTOTYPE( void dmap_endpt_up, (int proc_nr) ); - -/* exec.c */ -_PROTOTYPE( int pm_exec, (int proc_e, char *path, vir_bytes path_len, - char *frame, vir_bytes frame_len) ); - -/* filedes.c */ -_PROTOTYPE( struct filp *find_filp, (struct inode *rip, mode_t bits) ); -_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 inval_filp, (struct filp *) ); /* inode.c */ +_PROTOTYPE( struct inode *find_inode, (Dev_t dev, int numb) ); + _PROTOTYPE( struct inode *alloc_inode, (dev_t dev, mode_t bits) ); _PROTOTYPE( void dup_inode, (struct inode *ip) ); _PROTOTYPE( void free_inode, (Dev_t dev, Ino_t numb) ); @@ -85,11 +85,6 @@ _PROTOTYPE( void rw_inode, (struct inode *rip, int rw_flag) ); _PROTOTYPE( void wipe_inode, (struct inode *rip) ); /* 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_inode, (struct inode *rip, off_t len) ); _PROTOTYPE( int freesp_inode, (struct inode *rip, off_t st, off_t end) ); @@ -99,21 +94,21 @@ _PROTOTYPE( void lock_revive, (void) ); /* main.c */ _PROTOTYPE( int main, (void) ); -_PROTOTYPE( void reply, (int whom, int result) ); +_PROTOTYPE( void reply, (int who, message *m_out) ); /* misc.c */ _PROTOTYPE( int do_dup, (void) ); -_PROTOTYPE( void pm_exit, (int proc) ); +_PROTOTYPE( int do_exit, (void) ); _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( int do_fork, (void) ); +_PROTOTYPE( int do_exec, (void) ); +_PROTOTYPE( int do_revive, (void) ); +_PROTOTYPE( int do_set, (void) ); _PROTOTYPE( int do_sync, (void) ); _PROTOTYPE( int do_fsync, (void) ); -_PROTOTYPE( void pm_reboot, (void) ); +_PROTOTYPE( int do_reboot, (void) ); _PROTOTYPE( int do_svrctl, (void) ); _PROTOTYPE( int do_getsysinfo, (void) ); -_PROTOTYPE( int pm_dumpcore, (int proc_e, struct mem_map *seg_ptr) ); /* mount.c */ _PROTOTYPE( int do_mount, (void) ); @@ -122,15 +117,12 @@ _PROTOTYPE( int unmount, (Dev_t dev) ); /* open.c */ _PROTOTYPE( int do_close, (void) ); -_PROTOTYPE( int close_fd, (struct fproc *rfp, int fd_nr) ); _PROTOTYPE( int do_creat, (void) ); _PROTOTYPE( int do_lseek, (void) ); _PROTOTYPE( int do_mknod, (void) ); _PROTOTYPE( int do_mkdir, (void) ); _PROTOTYPE( int do_open, (void) ); -_PROTOTYPE( int do_slink, (void) ); -_PROTOTYPE( struct inode *new_node, (struct inode **ldirp, - char *path, mode_t bits, zone_t z0, int opaque, char *string) ); +_PROTOTYPE( int do_slink, (void) ); /* path.c */ _PROTOTYPE( struct inode *advance,(struct inode **dirp, char string[NAME_MAX])); @@ -141,19 +133,6 @@ _PROTOTYPE( struct inode *last_dir, (char *path, char string [NAME_MAX])); _PROTOTYPE( struct inode *parse_path, (char *path, char string[NAME_MAX], int action) ); -/* pipe.c */ -_PROTOTYPE( int do_pipe, (void) ); -_PROTOTYPE( int do_unpause, (void) ); -_PROTOTYPE( int unpause, (int proc_nr_e) ); -_PROTOTYPE( int pipe_check, (struct inode *rip, int rw_flag, - int oflags, int bytes, off_t position, int *canwrite, int notouch)); -_PROTOTYPE( void release, (struct inode *ip, int call_nr, int count) ); -_PROTOTYPE( void revive, (int proc_nr, int bytes) ); -_PROTOTYPE( void suspend, (int task) ); -_PROTOTYPE( int select_request_pipe, (struct filp *f, int *ops, int bl) ); -_PROTOTYPE( int select_cancel_pipe, (struct filp *f) ); -_PROTOTYPE( int select_match_pipe, (struct filp *f) ); -_PROTOTYPE( void unsuspend_by_endpt, (int) ); /* protect.c */ _PROTOTYPE( int do_access, (void) ); @@ -228,3 +207,6 @@ _PROTOTYPE( void fs_set_timer, (timer_t *tp, int delta, tmr_func_t watchdog, int _PROTOTYPE( void fs_expire_timers, (clock_t now) ); _PROTOTYPE( void fs_cancel_timer, (timer_t *tp) ); _PROTOTYPE( void fs_init_timer, (timer_t *tp) ); + +/* cdprobe.c */ +_PROTOTYPE( int cdprobe, (void) ); diff --git a/servers/mfs/queue.h b/servers/mfs/queue.h new file mode 100644 index 000000000..b5aef4e52 --- /dev/null +++ b/servers/mfs/queue.h @@ -0,0 +1,215 @@ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +#define __offsetof(type, field) ((size_t)(&((type *)0)->field)) +#define __rangeof(type, start, end) \ + (__offsetof(type, end) - __offsetof(type, start)) + +#define QMD_TRACE_ELEM(elem) +#define QMD_TRACE_HEAD(head) +#define TRACEBUF +#define TRASHIT(x) + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ + TRACEBUF \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ +} + +/* + * Tail queue functions. + */ +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_HEAD(head2); \ + } \ +} while (0) + +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + } \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + QMD_TRACE_HEAD(head); \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ + TRASHIT((elm)->field.tqe_next); \ + TRASHIT((elm)->field.tqe_prev); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + + +#endif /* _SYS_QUEUE_H */ diff --git a/servers/fs/read.c b/servers/mfs/read.c similarity index 68% rename from servers/fs/read.c rename to servers/mfs/read.c index b049aef89..44b1724ec 100644 --- a/servers/fs/read.c +++ b/servers/mfs/read.c @@ -1,213 +1,135 @@ -/* 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 - * read_write: actually do the work of READ and WRITE - * read_map: given an inode and file position, look up its zone number - * rd_indir: read an entry in an indirect block - * read_ahead: manage the block read ahead business - */ + #include "fs.h" #include #include #include #include "buf.h" -#include "file.h" -#include "fproc.h" #include "inode.h" -#include "param.h" #include "super.h" +#include + + + FORWARD _PROTOTYPE( int rw_chunk, (struct inode *rip, off_t position, unsigned off, int chunk, unsigned left, int rw_flag, char *buff, int seg, int usr, int block_size, int *completed)); -/*===========================================================================* - * do_read * - *===========================================================================*/ -PUBLIC int do_read() -{ - return(read_write(READING)); -} /*===========================================================================* - * read_write * + * fs_readwrite * *===========================================================================*/ -PUBLIC int read_write(rw_flag) -int rw_flag; /* READING or WRITING */ +PUBLIC int fs_readwrite(void) { -/* Perform read(fd, buffer, nbytes) or write(fd, buffer, nbytes) call. */ - - register struct inode *rip; - register struct filp *f; - off_t bytes_left, f_size, position; + int r, usr, seg, rw_flag, chunk, block_size, block_spec; + int partial_cnt, regular, partial_pipe, nrbytes; + off_t position, f_size, bytes_left; unsigned int off, cum_io; - int op, oflags, r, chunk, usr, seg, block_spec, char_spec; - int regular, partial_pipe = 0, partial_cnt = 0; mode_t mode_word; - struct filp *wf; - int block_size = 0; int completed, r2 = OK; - phys_bytes p; - - /* PM loads segments by putting funny things in other bits of the - * message, indicated by a high bit in fd. - */ - if (who_e == PM_PROC_NR && (m_in.fd & _PM_SEG_FLAG)) { - seg = (int) m_in.m1_p2; - usr = (int) m_in.m1_p3; - m_in.fd &= ~(_PM_SEG_FLAG); /* get rid of flag bit */ - } else { - usr = who_e; /* normal case */ - seg = D; - } - - /* If the file descriptor is valid, get the inode, size and mode. */ - if (m_in.nbytes < 0) return(EINVAL); - if ((f = get_filp(m_in.fd)) == NIL_FILP) 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*/ - - /* check if user process has the memory it needs. - * if not, copying will fail later. - * do this after 0-check above because umap doesn't want to map 0 bytes. - */ - if ((r = sys_umap(usr, seg, (vir_bytes) m_in.buffer, m_in.nbytes, &p)) != OK) { - printf("FS: read_write: umap failed for process %d\n", usr); - return r; - } - position = f->filp_pos; - oflags = f->filp_flags; - rip = f->filp_ino; - f_size = rip->i_size; + char *user_addr; + struct inode *rip; + + partial_pipe = 0; r = OK; - if (rip->i_pipe == I_PIPE) { - /* fp->fp_cum_io_partial is only nonzero when doing partial writes */ - cum_io = fp->fp_cum_io_partial; - } else { - cum_io = 0; + + /* Try to get inode according to its index */ + if (fs_m_in.REQ_FD_INODE_INDEX >= 0 && + fs_m_in.REQ_FD_INODE_INDEX < NR_INODES && + inode[fs_m_in.REQ_FD_INODE_INDEX].i_num == fs_m_in.REQ_FD_INODE_NR) { + rip = &inode[fs_m_in.REQ_FD_INODE_INDEX]; } - op = (rw_flag == READING ? DEV_READ : DEV_WRITE); + else { + /* Find the inode referred */ + rip = find_inode(fs_dev, fs_m_in.REQ_FD_INODE_NR); + if (!rip) { + printf("FS: unavaliable inode by fs_readwrite(), nr: %d\n", + fs_m_in.REQ_FD_INODE_NR); + return EINVAL; + } + } + mode_word = rip->i_mode & I_TYPE; - regular = mode_word == I_REGULAR || mode_word == I_NAMED_PIPE; + regular = (mode_word == I_REGULAR || mode_word == I_NAMED_PIPE); + block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 : 0); + + /* Determine blocksize */ + block_size = (block_spec ? get_block_size(rip->i_zone[0]) + : rip->i_sp->s_block_size); - if ((char_spec = (mode_word == I_CHAR_SPECIAL ? 1 : 0))) { - if (rip->i_zone[0] == NO_DEV) - panic(__FILE__,"read_write tries to read from " - "character device NO_DEV", NO_NUM); - block_size = get_block_size(rip->i_zone[0]); - } - if ((block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 : 0))) { - f_size = ULONG_MAX; - if (rip->i_zone[0] == NO_DEV) - panic(__FILE__,"read_write tries to read from " - " block device NO_DEV", NO_NUM); - block_size = get_block_size(rip->i_zone[0]); - } - - if (!char_spec && !block_spec) - block_size = rip->i_sp->s_block_size; + f_size = (block_spec ? ULONG_MAX : rip->i_size); + + /* Get the values from the request message */ + rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING); + usr = fs_m_in.REQ_FD_WHO_E; + seg = fs_m_in.REQ_FD_SEG; + position = fs_m_in.REQ_FD_POS; + nrbytes = (unsigned) fs_m_in.REQ_FD_NBYTES; + /*partial_cnt = fs_m_in.REQ_FD_PARTIAL;*/ + user_addr = fs_m_in.REQ_FD_USER_ADDR; + /*if (partial_cnt > 0) partial_pipe = 1;*/ + rdwt_err = OK; /* set to EIO if disk error occurs */ + + if (rw_flag == WRITING && block_spec == 0) { + /* Clear the zone containing present EOF if hole about + * to be created. This is necessary because all unwritten + * blocks prior to the EOF must read as zeros. + */ + if (position > f_size) clear_zone(rip, f_size, 0); + } + + cum_io = 0; + /* Split the transfer into chunks that don't span two blocks. */ + while (nrbytes != 0) { + off = (unsigned int) (position % block_size);/* offset in blk*/ + + chunk = MIN(nrbytes, block_size - off); + if (chunk < 0) chunk = block_size - off; - /* Check for character special files. */ - if (char_spec) { - dev_t dev; - dev = (dev_t) rip->i_zone[0]; - r = dev_io(op, dev, usr, m_in.buffer, position, m_in.nbytes, oflags); - if (r >= 0) { - cum_io = r; - position += r; - r = OK; - } - } else { - if (rw_flag == WRITING && block_spec == 0) { - /* Check in advance to see if file will grow too big. */ - if (position > rip->i_sp->s_max_size - m_in.nbytes) - return(EFBIG); + if (rw_flag == READING) { + bytes_left = f_size - position; + if (position >= f_size) break; /* we are beyond EOF */ + if (chunk > bytes_left) chunk = (int) bytes_left; + } - /* Check for O_APPEND flag. */ - if (oflags & O_APPEND) position = f_size; + /* Read or write 'chunk' bytes. */ + r = rw_chunk(rip, position, off, chunk, (unsigned) nrbytes, + rw_flag, user_addr, seg, usr, block_size, &completed); - /* Clear the zone containing present EOF if hole about - * to be created. This is necessary because all unwritten - * blocks prior to the EOF must read as zeros. - */ - if (position > f_size) clear_zone(rip, f_size, 0); - } + if (r != OK) break; /* EOF reached */ + if (rdwt_err < 0) break; - /* Pipes are a little different. Check. */ - if (rip->i_pipe == I_PIPE) { - r = pipe_check(rip, rw_flag, oflags, - m_in.nbytes, position, &partial_cnt, 0); - if (r <= 0) return(r); - } - - if (partial_cnt > 0) partial_pipe = 1; - - /* Split the transfer into chunks that don't span two blocks. */ - while (m_in.nbytes != 0) { - - off = (unsigned int) (position % block_size);/* offset in blk*/ - if (partial_pipe) { /* pipes only */ - chunk = MIN(partial_cnt, block_size - off); - } else - chunk = MIN(m_in.nbytes, block_size - off); - if (chunk < 0) chunk = block_size - off; - - if (rw_flag == READING) { - bytes_left = f_size - position; - if (position >= f_size) break; /* we are beyond EOF */ - if (chunk > bytes_left) chunk = (int) bytes_left; - } - - /* Read or write 'chunk' bytes. */ - r = rw_chunk(rip, position, off, chunk, (unsigned) m_in.nbytes, - rw_flag, m_in.buffer, seg, usr, block_size, &completed); - - if (r != OK) break; /* EOF reached */ - if (rdwt_err < 0) break; - - /* Update counters and pointers. */ - m_in.buffer += chunk; /* user buffer address */ - m_in.nbytes -= chunk; /* bytes yet to be read */ - cum_io += chunk; /* bytes read so far */ - position += chunk; /* position within the file */ - - if (partial_pipe) { - partial_cnt -= chunk; - if (partial_cnt <= 0) break; - } - } + /* Update counters and pointers. */ + user_addr += chunk; /* user buffer address */ + nrbytes -= chunk; /* bytes yet to be read */ + cum_io += chunk; /* bytes read so far */ + position += chunk; /* position within the file */ } + fs_m_out.RES_FD_POS = 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 (regular || mode_word == I_DIRECTORY) { if (position > f_size) rip->i_size = position; } - } else { + } + else { if (rip->i_pipe == I_PIPE) { if ( position >= rip->i_size) { /* Reset pipe pointers. */ rip->i_size = 0; /* no data left */ position = 0; /* reset reader(s) */ - wf = find_filp(rip, W_BIT); - if (wf != NIL_FILP) wf->filp_pos = 0; } } } - f->filp_pos = position; /* Check to see if read-ahead is called for, and if so, set it up. */ - if (rw_flag == READING && rip->i_seek == NO_SEEK && position % block_size== 0 + if (rw_flag == READING && rip->i_seek == NO_SEEK && position % block_size == 0 && (regular || mode_word == I_DIRECTORY)) { rdahed_inode = rip; rdahedpos = position; @@ -221,26 +143,94 @@ int rw_flag; /* READING or WRITING */ if (r == OK && r2 != OK) { r = r2; } + if (r == OK) { if (rw_flag == READING) rip->i_update |= ATIME; if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME; rip->i_dirt = DIRTY; /* inode is thus now dirty */ - if (partial_pipe) { - partial_pipe = 0; - /* partial write on pipe with */ - /* O_NONBLOCK, return write count */ - if (!(oflags & O_NONBLOCK)) { - fp->fp_cum_io_partial = cum_io; - suspend(XPIPE); /* partial write on pipe with */ - return(SUSPEND); /* nbyte > PIPE_SIZE - non-atomic */ - } - } - fp->fp_cum_io_partial = 0; - return(cum_io); } + + fs_m_out.RES_FD_CUM_IO = cum_io; + fs_m_out.RES_FD_SIZE = rip->i_size; + return(r); } + +/*===========================================================================* + * fs_breadwrite * + *===========================================================================*/ +PUBLIC int fs_breadwrite(void) +{ + int r, usr, rw_flag, chunk, block_size; + int nrbytes; + off_t position, f_size, bytes_left; + unsigned int off, cum_io; + mode_t mode_word; + int completed, r2 = OK; + char *user_addr; + + /* Pseudo inode for rw_chunk */ + struct inode rip; + + r = OK; + f_size = ULONG_MAX; + + /* Get the values from the request message */ + rw_flag = (fs_m_in.m_type == REQ_BREAD ? READING : WRITING); + usr = fs_m_in.REQ_FD_WHO_E; + position = fs_m_in.REQ_FD_POS; + nrbytes = (unsigned) fs_m_in.REQ_FD_NBYTES; + user_addr = fs_m_in.REQ_FD_USER_ADDR; + + block_size = get_block_size(fs_m_in.REQ_FD_BDEV); + + rip.i_zone[0] = fs_m_in.REQ_FD_BDEV; + rip.i_mode = I_BLOCK_SPECIAL; + rip.i_size = f_size; + + rdwt_err = OK; /* set to EIO if disk error occurs */ + + cum_io = 0; + /* Split the transfer into chunks that don't span two blocks. */ + while (nrbytes != 0) { + off = (unsigned int) (position % block_size);/* offset in blk*/ + + chunk = MIN(nrbytes, block_size - off); + if (chunk < 0) chunk = block_size - off; + + if (rw_flag == READING) { + bytes_left = f_size - position; + if (position >= f_size) break; /* we are beyond EOF */ + if (chunk > bytes_left) chunk = (int) bytes_left; + } + + /* Read or write 'chunk' bytes. */ + r = rw_chunk(&rip, position, off, chunk, (unsigned) nrbytes, + rw_flag, user_addr, D, usr, block_size, &completed); + + if (r != OK) break; /* EOF reached */ + if (rdwt_err < 0) break; + + /* Update counters and pointers. */ + user_addr += chunk; /* user buffer address */ + nrbytes -= chunk; /* bytes yet to be read */ + cum_io += chunk; /* bytes read so far */ + position += chunk; /* position within the file */ + } + + fs_m_out.RES_FD_POS = position; + + if (rdwt_err != OK) r = rdwt_err; /* check for disk error */ + if (rdwt_err == END_OF_FILE) r = OK; + + fs_m_out.RES_FD_CUM_IO = cum_io; + fs_m_out.RES_FD_SIZE = rip.i_size; + + return(r); +} + + /*===========================================================================* * rw_chunk * *===========================================================================*/ @@ -269,10 +259,12 @@ int *completed; /* number of bytes copied */ *completed = 0; block_spec = (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL; + if (block_spec) { b = position/block_size; dev = (dev_t) rip->i_zone[0]; - } else { + } + else { b = read_map(rip, position); dev = rip->i_dev; } @@ -282,14 +274,17 @@ int *completed; /* number of bytes copied */ /* Reading from a nonexistent block. Must read as all zeros.*/ bp = get_block(NO_DEV, NO_BLOCK, NORMAL); /* get a buffer */ zero_block(bp); - } else { + } + else { /* Writing to a nonexistent block. Create and enter in inode.*/ if ((bp= new_block(rip, position)) == NIL_BUF)return(err_code); } - } else if (rw_flag == READING) { + } + else if (rw_flag == READING) { /* Read and read ahead if convenient. */ bp = rahead(rip, b, position, left); - } else { + } + else { /* Normally an existing block to be partially overwritten is first read * in. However, a full block need not be read in. If it is already in * the cache, acquire it, otherwise just acquire a free buffer. @@ -303,6 +298,7 @@ int *completed; /* number of bytes copied */ if (bp == NIL_BUF) { panic(__FILE__,"bp not valid in rw_chunk, this can't happen", NO_NUM); } + if (rw_flag == WRITING && chunk != block_size && !block_spec && position >= rip->i_size && off == 0) { zero_block(bp); @@ -310,13 +306,14 @@ int *completed; /* number of bytes copied */ if (rw_flag == READING) { /* Copy a chunk from the block buffer to user space. */ - r = sys_vircopy(FS_PROC_NR, D, (phys_bytes) (bp->b_data+off), + r = sys_vircopy(SELF_E, D, (phys_bytes) (bp->b_data+off), usr, seg, (phys_bytes) buff, (phys_bytes) chunk); - } else { + } + else { /* Copy a chunk from user space to the block buffer. */ r = sys_vircopy(usr, seg, (phys_bytes) buff, - FS_PROC_NR, D, (phys_bytes) (bp->b_data+off), + SELF_E, D, (phys_bytes) (bp->b_data+off), (phys_bytes) chunk); bp->b_dirt = DIRTY; } @@ -558,3 +555,4 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */ rw_scattered(dev, read_q, read_q_size, READING); return(get_block(dev, baseblock, NORMAL)); } + diff --git a/servers/fs/select.h b/servers/mfs/select.h similarity index 100% rename from servers/fs/select.h rename to servers/mfs/select.h diff --git a/servers/mfs/stadir.c b/servers/mfs/stadir.c new file mode 100644 index 000000000..6b7d7cb1a --- /dev/null +++ b/servers/mfs/stadir.c @@ -0,0 +1,209 @@ + + +#include "fs.h" +#include +#include +#include +#include +#include "buf.h" +#include "inode.h" +#include "super.h" + +#include + + +FORWARD _PROTOTYPE( int stat_inode, (struct inode *rip, int pipe_pos, + char *user_addr, int who_e) ); + + +/*===========================================================================* + * fs_getdir * + *===========================================================================*/ +PUBLIC int fs_getdir() +{ + register int r; + register struct inode *rip; + + struct inodelist *rlp; + + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + /* Try to open the new directory. */ + if ( (rip = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) { +printf("MFS(%d) get_inode by fs_getdir() failed\n", SELF_E); + return(EINVAL); + } + + r = forbidden(rip, X_BIT); /* check if dir is searchable */ + + /* If error, return inode. */ + if (r != OK) { + put_inode(rip); + return(r); + } + + /* If OK send back inode details */ + fs_m_out.m_source = rip->i_dev; /* filled with FS endpoint by the system */ + fs_m_out.RES_INODE_NR = rip->i_num; + fs_m_out.RES_MODE = rip->i_mode; + fs_m_out.RES_FILE_SIZE = rip->i_size; + +/* +printf("MFS(%d): ", SELF_E); +for (rlp = &hash_inodes[0]; rlp < &hash_inodes[INODE_HASH_SIZE]; ++rlp) { + int elements = 0; + LIST_FOREACH(rip, rlp, i_hash) elements++; + printf("%d ", elements); +} +printf("\n"); +*/ + + return OK; +} + +/*===========================================================================* + * fs_stat * + *===========================================================================*/ +PUBLIC int fs_stat() +{ + register struct inode *rip; + register int r; + + /* Both stat() and fstat() use the same routine to do the real work. That + * routine expects an inode, so acquire it temporarily. + */ + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + if ( (rip = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) { +printf("MFS(%d) get_inode by fs_stat() failed\n", SELF_E); + return(EINVAL); + } + + r = stat_inode(rip, 0, fs_m_in.REQ_USER_ADDR, fs_m_in.REQ_WHO_E); + put_inode(rip); /* release the inode */ + return(r); +} + + +/*===========================================================================* + * fs_fstat * + *===========================================================================*/ +PUBLIC int fs_fstat() +{ + int r; + struct inode *rip; + + /* Both stat() and fstat() use the same routine to do the real work. That + * routine expects an inode, so acquire it temporarily. + */ + if ((rip = find_inode(fs_dev, fs_m_in.REQ_FD_INODE_NR)) + == NIL_INODE) { + printf("FSfstat: couldn't find inode %d\n", fs_m_in.REQ_FD_INODE_NR); + return EINVAL; + } + + r = stat_inode(rip, fs_m_in.REQ_FD_POS, fs_m_in.REQ_FD_USER_ADDR, + fs_m_in.REQ_FD_WHO_E); + + return r; +} + +/*===========================================================================* + * stat_inode * + *===========================================================================*/ +PRIVATE int stat_inode(rip, pipe_pos, user_addr, who_e) +register struct inode *rip; /* pointer to inode to stat */ +int pipe_pos; /* position in a pipe, supplied by fstat() */ +char *user_addr; /* user space address where stat buf goes */ +int who_e; /* kernel endpoint of the caller */ +{ +/* Common code for stat and fstat system calls. */ + + struct stat statbuf; + mode_t mo; + int r, s; + + /* Update the atime, ctime, and mtime fields in the inode, if need be. */ + if (rip->i_update) update_times(rip); + + /* Fill in the statbuf struct. */ + mo = rip->i_mode & I_TYPE; + + /* true iff special */ + s = (mo == I_CHAR_SPECIAL || mo == I_BLOCK_SPECIAL); + + 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 = rip->i_gid; + statbuf.st_rdev = (dev_t) (s ? rip->i_zone[0] : NO_DEV); + statbuf.st_size = rip->i_size; + + if (rip->i_pipe == I_PIPE) { + statbuf.st_mode &= ~I_REGULAR; /* wipe out I_REGULAR bit for pipes */ + statbuf.st_size -= pipe_pos; + } + + statbuf.st_atime = rip->i_atime; + statbuf.st_mtime = rip->i_mtime; + statbuf.st_ctime = rip->i_ctime; + + /* Copy the struct to user space. */ + r = sys_datacopy(SELF, (vir_bytes) &statbuf, + who_e, (vir_bytes) user_addr, (phys_bytes) sizeof(statbuf)); + + return(r); +} + + + +/*===========================================================================* + * fs_fstatfs * + *===========================================================================*/ +PUBLIC int fs_fstatfs() +{ + struct statfs st; + struct inode *rip; + int r; + + if ((rip = find_inode(fs_dev, fs_m_in.REQ_FD_INODE_NR)) + == NIL_INODE) { + printf("FSfstatfs: couldn't find inode %d\n", fs_m_in.REQ_FD_INODE_NR); + return EINVAL; + } + + st.f_bsize = rip->i_sp->s_block_size; + + /* Copy the struct to user space. */ + r = sys_datacopy(SELF, (vir_bytes) &st, fs_m_in.REQ_FD_WHO_E, + (vir_bytes) fs_m_in.REQ_FD_USER_ADDR, (phys_bytes) sizeof(st)); + + return(r); +} + +/*===========================================================================* + * fs_lstat * + *===========================================================================*/ +PUBLIC int fs_lstat() +{ + register int r; /* return value */ + register struct inode *rip; /* target inode */ + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + if ( (rip = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) { +printf("MFS(%d) get_inode by fs_lstat() failed\n", SELF_E); + return(EINVAL); + } + + r = stat_inode(rip, 0, fs_m_in.REQ_USER_ADDR, fs_m_in.REQ_WHO_E); + put_inode(rip); /* release the inode */ + return(r); +} + + + diff --git a/servers/fs/super.c b/servers/mfs/super.c similarity index 94% rename from servers/fs/super.c rename to servers/mfs/super.c index 4f1279fc2..bc94da198 100644 --- a/servers/fs/super.c +++ b/servers/mfs/super.c @@ -19,6 +19,7 @@ #include "super.h" #include "const.h" + /*===========================================================================* * alloc_bit * *===========================================================================*/ @@ -155,6 +156,7 @@ dev_t dev; /* device number whose super_block is sought */ for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) if (sp->s_dev == dev) return(sp); +printf("MFS(%d)get_super: sp->s_dev: %d, dev: %d\n", SELF_E, sp->s_dev, dev); /* Search failed. Something wrong. */ panic(__FILE__,"can't find superblock for device (in decimal)", (int) dev); @@ -187,23 +189,24 @@ PUBLIC int get_block_size(dev_t dev) /*===========================================================================* * mounted * *===========================================================================*/ -PUBLIC int mounted(rip) -register struct inode *rip; /* pointer to inode */ -{ /* Report on whether the given inode is on a mounted (or ROOT) file system. */ +/* +PUBLIC int mounted(rip) +register struct inode *rip; +{ register struct super_block *sp; register dev_t dev; dev = (dev_t) rip->i_zone[0]; - if (dev == root_dev) return(TRUE); /* inode is on root file system */ + if (dev == root_dev) return(TRUE); for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) if (sp->s_dev == dev) return(TRUE); return(FALSE); } - +*/ /*===========================================================================* * read_super * *===========================================================================*/ @@ -219,9 +222,11 @@ register struct super_block *sp; /* pointer to a superblock */ dev = sp->s_dev; /* save device (will be overwritten by copy) */ if (dev == NO_DEV) panic(__FILE__,"request for super_block of NO_DEV", NO_NUM); - r = dev_io(DEV_READ, dev, FS_PROC_NR, + + r = block_dev_io(DEV_READ, dev, SELF_E, sbbuf, SUPER_BLOCK_BYTES, _MIN_BLOCK_SIZE, 0); if (r != _MIN_BLOCK_SIZE) { +printf("MFSread_super r != _MIN_BLOCK_SIZE\n"); return EINVAL; } memcpy(sp, sbbuf, sizeof(*sp)); @@ -239,6 +244,7 @@ register struct super_block *sp; /* pointer to a superblock */ version = V3; native = 1; } else { +printf("MFSread_super invalid version\n"); return(EINVAL); } @@ -273,14 +279,17 @@ register struct super_block *sp; /* pointer to a superblock */ } else { if (version == V2) sp->s_block_size = _STATIC_BLOCK_SIZE; - if (sp->s_block_size < _MIN_BLOCK_SIZE) + if (sp->s_block_size < _MIN_BLOCK_SIZE) { +printf("MFSread_super block size ERROR1\n"); return EINVAL; + } sp->s_inodes_per_block = V2_INODES_PER_BLOCK(sp->s_block_size); sp->s_ndzones = V2_NR_DZONES; sp->s_nindirs = V2_INDIRECTS(sp->s_block_size); } if (sp->s_block_size < _MIN_BLOCK_SIZE) { +printf("MFSread_super block size ERROR2\n"); return EINVAL; } if (sp->s_block_size > _MAX_BLOCK_SIZE) { @@ -290,13 +299,16 @@ register struct super_block *sp; /* pointer to a superblock */ return EINVAL; } if ((sp->s_block_size % 512) != 0) { +printf("MFSread_super block_size !% 512 \n"); return EINVAL; } if (SUPER_SIZE > sp->s_block_size) { +printf("MFSread_super block_size < SUPER_SIZE \n"); return EINVAL; } if ((sp->s_block_size % V2_INODE_SIZE) != 0 || (sp->s_block_size % V1_INODE_SIZE) != 0) { +printf("MFSread_super block_sizr % INODE_SIZE notOK \n"); return EINVAL; } diff --git a/servers/mfs/super.h b/servers/mfs/super.h new file mode 100644 index 000000000..c9e4761a2 --- /dev/null +++ b/servers/mfs/super.h @@ -0,0 +1,61 @@ +/* Super block table. The root file system and every mounted file system + * has an entry here. The entry holds information about the sizes of the bit + * maps and inodes. The s_ninodes field gives the number of inodes available + * for files and directories, including the root directory. Inode 0 is + * on the disk, but not used. Thus s_ninodes = 4 means that 5 bits will be + * used in the bit map, bit 0, which is always 1 and not used, and bits 1-4 + * for files and directories. The disk layout is: + * + * Item # blocks + * boot block 1 + * super block 1 (offset 1kB) + * inode map s_imap_blocks + * zone map s_zmap_blocks + * inodes (s_ninodes + 'inodes per block' - 1)/'inodes per block' + * unused whatever is needed to fill out the current zone + * data zones (s_zones - s_firstdatazone) << s_log_zone_size + * + * A super_block slot is free if s_dev == NO_DEV. + */ + +EXTERN struct super_block { + ino_t s_ninodes; /* # usable inodes on the minor device */ + zone1_t s_nzones; /* total device size, including bit maps etc */ + short s_imap_blocks; /* # of blocks used by inode bit map */ + short s_zmap_blocks; /* # of blocks used by zone bit map */ + zone1_t s_firstdatazone; /* number of first data zone */ + short s_log_zone_size; /* log2 of blocks/zone */ + short s_pad; /* try to avoid compiler-dependent padding */ + off_t s_max_size; /* maximum file size on this device */ + zone_t s_zones; /* number of zones (replaces s_nzones in V2) */ + short s_magic; /* magic number to recognize super-blocks */ + + /* The following items are valid on disk only for V3 and above */ + + /* The block size in bytes. Minimum MIN_BLOCK SIZE. SECTOR_SIZE + * multiple. If V1 or V2 filesystem, this should be + * initialised to STATIC_BLOCK_SIZE. Maximum MAX_BLOCK_SIZE. + */ + short s_pad2; /* try to avoid compiler-dependent padding */ + unsigned short s_block_size; /* block size in bytes. */ + char s_disk_version; /* filesystem format sub-version */ + + /* The following items are only used when the super_block is in memory. */ + + /*struct inode *s_isup;*/ /* inode for root dir of mounted file sys */ + /*struct inode *s_imount;*/ /* inode mounted on */ + unsigned s_inodes_per_block; /* precalculated from magic number */ + dev_t s_dev; /* whose super block is this? */ + int s_rd_only; /* set to 1 iff file sys mounted read only */ + int s_native; /* set to 1 iff not byte swapped file system */ + int s_version; /* file system version, zero means bad magic */ + int s_ndzones; /* # direct zones in an inode */ + int s_nindirs; /* # indirect zones per indirect block */ + bit_t s_isearch; /* inodes below this bit number are in use */ + bit_t s_zsearch; /* all zones below this bit number are in use*/ + char s_is_root; +} super_block[NR_SUPERS]; + +#define NIL_SUPER (struct super_block *) 0 +#define IMAP 0 /* operating on the inode bit map */ +#define ZMAP 1 /* operating on the zone bit map */ diff --git a/servers/mfs/table.c b/servers/mfs/table.c new file mode 100644 index 000000000..cc7fae361 --- /dev/null +++ b/servers/mfs/table.c @@ -0,0 +1,62 @@ + +/* 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 "inode.h" +#include "buf.h" +#include "super.h" +#include "drivers.h" + +PUBLIC _PROTOTYPE (int (*fs_call_vec[]), (void) ) = { + no_sys, /* 0 not used */ + fs_getnode, /* 1 */ + fs_putnode, /* 2 */ + fs_open, /* 3 */ + fs_pipe, /* 4 */ + fs_readwrite, /* 5 */ /* read() */ + fs_readwrite, /* 6 */ /* write() */ + fs_clone_opcl, /* 7 */ + fs_ftrunc, /* 8 */ + + fs_chown, /* 9 */ + fs_chmod, /* 10 */ + fs_access, /* 11 */ + fs_mknod, /* 12 */ + fs_mkdir, /* 13 */ + fs_inhibread, /* 14 */ /* for lseek() */ + fs_stat, /* 15 */ + fs_fstat, /* 16 */ + fs_unlink, /* 17 */ /* unlink() */ + fs_unlink, /* 18 */ /* rmdir() */ + fs_utime, /* 19 */ + fs_fstatfs, /* 20 */ + fs_lstat, /* 21 */ + fs_getdir, /* 22 */ /* chdir(), chroot() */ + + no_sys, /* 23 */ + no_sys, /* 24 */ + fs_link, /* 25 */ + + fs_slink, /* 26 */ + fs_rdlink, /* 27 */ + + fs_rename, /* 28 */ + no_sys, /* 29 */ + fs_mountpoint, /* 30 */ + fs_readsuper, /* 31 */ + fs_unmount, /* 32 */ + fs_trunc, /* 33 */ + fs_sync, /* 34 */ + lookup, /* 35 */ + fs_stime, /* 36 */ + fs_new_driver, /* 37 */ + fs_breadwrite, /* 38 */ + fs_breadwrite, /* 39 */ +}; + diff --git a/servers/mfs/time.c b/servers/mfs/time.c new file mode 100644 index 000000000..32785d20c --- /dev/null +++ b/servers/mfs/time.c @@ -0,0 +1,56 @@ + + + +#include "fs.h" +#include +#include +#include "inode.h" + +#include + + +/*===========================================================================* + * fs_utime * + *===========================================================================*/ +PUBLIC int fs_utime() +{ + register struct inode *rip; + register int r; + + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + + /* Temporarily open the file. */ + if ( (rip = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) { +printf("MFS(%d) get_inode by fs_utime() failed\n", SELF_E); + return(EINVAL); + } + + /* Only the owner of a file or the super_user can change its time. */ + r = OK; + if (rip->i_uid != caller_uid && caller_uid != SU_UID) r = EPERM; + if (fs_m_in.REQ_ACTIME == 0 && r != OK) r = forbidden(rip, W_BIT); + if (read_only(rip) != OK) r = EROFS; /* not even su can touch if R/O */ + if (r == OK) { + if (fs_m_in.REQ_ACTIME == 0) { + rip->i_atime = fs_m_in.REQ_MODTIME; + rip->i_mtime = rip->i_atime; + } else { + rip->i_atime = fs_m_in.REQ_ACTIME; + rip->i_mtime = fs_m_in.REQ_MODTIME; + } + rip->i_update = CTIME; /* discard any stale ATIME and MTIME flags */ + rip->i_dirt = DIRTY; + } + + put_inode(rip); + return(r); +} + +PUBLIC int fs_stime() +{ + boottime = fs_m_in.REQ_BOOTTIME; +printf("MFS(%d) boottime: %d\n", SELF_E, boottime); + return OK; +} + diff --git a/servers/fs/type.h b/servers/mfs/type.h similarity index 100% rename from servers/fs/type.h rename to servers/mfs/type.h diff --git a/servers/mfs/utility.c b/servers/mfs/utility.c new file mode 100644 index 000000000..b9995dc19 --- /dev/null +++ b/servers/mfs/utility.c @@ -0,0 +1,93 @@ + +#include "fs.h" +#include +#include +#include +#include + +#include "buf.h" +#include "inode.h" +#include "super.h" + +#include + +static int panicking; + +/*===========================================================================* + * no_sys * + *===========================================================================*/ +PUBLIC int no_sys() +{ +/* Somebody has used an illegal system call number */ + return(EINVAL); +} + +/*===========================================================================* + * panic * + *===========================================================================*/ +PUBLIC void panic(who, mess, num) +char *who; /* who caused the panic */ +char *mess; /* panic message string */ +int num; /* number to go with it */ +{ +/* Something awful has happened. Panics are caused when an internal + * inconsistency is detected, e.g., a programming error or illegal value of a + * defined constant. + */ + if (panicking) return; /* do not panic during a sync */ + panicking = TRUE; /* prevent another panic during the sync */ + + printf("FS panic (%s): %s ", who, mess); + if (num != NO_NUM) printf("%d",num); + (void) fs_sync(); /* flush everything to the disk */ + sys_exit(SELF); +} + +/*===========================================================================* + * conv2 * + *===========================================================================*/ +PUBLIC unsigned conv2(norm, w) +int norm; /* TRUE if no swap, FALSE for byte swap */ +int w; /* promotion of 16-bit word to be swapped */ +{ +/* Possibly swap a 16-bit word between 8086 and 68000 byte order. */ + if (norm) return( (unsigned) w & 0xFFFF); + return( ((w&BYTE) << 8) | ( (w>>8) & BYTE)); +} + +/*===========================================================================* + * conv4 * + *===========================================================================*/ +PUBLIC long conv4(norm, x) +int norm; /* TRUE if no swap, FALSE for byte swap */ +long x; /* 32-bit long to be byte swapped */ +{ +/* Possibly swap a 32-bit long between 8086 and 68000 byte order. */ + unsigned lo, hi; + long l; + + if (norm) return(x); /* byte order was already ok */ + lo = conv2(FALSE, (int) x & 0xFFFF); /* low-order half, byte swapped */ + hi = conv2(FALSE, (int) (x>>16) & 0xFFFF); /* high-order half, swapped */ + l = ( (long) lo <<16) | hi; + return(l); +} + +/*===========================================================================* + * 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 k; + clock_t uptime; + + if ( (k=getuptime(&uptime)) != OK) panic(__FILE__,"clock_time err", k); + return( (time_t) (boottime + (uptime/HZ))); +} + + diff --git a/servers/fs/write.c b/servers/mfs/write.c similarity index 96% rename from servers/fs/write.c rename to servers/mfs/write.c index d4075905c..c51cb0c79 100644 --- a/servers/fs/write.c +++ b/servers/mfs/write.c @@ -1,3 +1,4 @@ + /* This file is the counterpart of "read.c". It contains the code for writing * insofar as this is not contained in read_write(). * @@ -10,23 +11,13 @@ #include "fs.h" #include #include "buf.h" -#include "file.h" -#include "fproc.h" #include "inode.h" #include "super.h" + FORWARD _PROTOTYPE( void wr_indir, (struct buf *bp, int index, zone_t zone) ); FORWARD _PROTOTYPE( int empty_indir, (struct buf *, struct super_block *) ); -/*===========================================================================* - * do_write * - *===========================================================================*/ -PUBLIC int do_write() -{ -/* Perform the write(fd, buffer, nbytes) system call. */ - - return(read_write(WRITING)); -} /*===========================================================================* * write_map * @@ -45,8 +36,8 @@ int op; /* special actions */ * Also free the double indirect block if that was the last entry in the * double indirect block. */ - int scale, ind_ex = 0, new_ind, new_dbl, - zones, nr_indirects, single, zindex, ex; + int scale, ind_ex = 0, new_ind, new_dbl, + zones, nr_indirects, single, zindex, ex; zone_t z, z1, z2 = NO_ZONE, old_zone; register block_t b; long excess, zone; @@ -337,3 +328,4 @@ register struct buf *bp; /* pointer to buffer to zero */ memset(bp->b_data, 0, _MAX_BLOCK_SIZE); bp->b_dirt = DIRTY; } + diff --git a/servers/rs/main.c b/servers/rs/main.c index 140423bfe..f47cf18c9 100644 --- a/servers/rs/main.c +++ b/servers/rs/main.c @@ -17,7 +17,7 @@ FORWARD _PROTOTYPE(void init_server, (void) ); FORWARD _PROTOTYPE(void sig_handler, (void) ); FORWARD _PROTOTYPE(void get_work, (message *m) ); -FORWARD _PROTOTYPE(void reply, (int whom, int result) ); +FORWARD _PROTOTYPE(void reply, (int whom, message *m_out) ); /* Data buffers to retrieve info during initialization. */ PRIVATE struct boot_image image[NR_BOOT_PROCS]; @@ -99,7 +99,8 @@ PUBLIC int main(void) /* Finally send reply message, unless disabled. */ if (result != EDONTREPLY) { - reply(who_e, result); + m.m_type = result; + reply(who_e, &m); } } } @@ -191,17 +192,18 @@ message *m_in; /* pointer to message */ /*===========================================================================* * reply * *===========================================================================*/ -PRIVATE void reply(who, result) +PRIVATE void reply(who, m_out) int who; /* replyee */ -int result; /* report result */ +message *m_out; /* reply message */ { - message m_out; /* reply message */ + /*message m_out;*/ /* reply message */ int s; /* send status */ - m_out.m_type = result; /* build reply message */ - if (OK != (s=send(who, &m_out))) /* send the message */ + /*m_out.m_type = result;*/ /* build reply message */ + if (OK != (s=send(who, m_out))) /* send the message */ panic("RS", "unable to send reply", s); } + diff --git a/servers/rs/manager.c b/servers/rs/manager.c index 048da7ab6..8513df17e 100644 --- a/servers/rs/manager.c +++ b/servers/rs/manager.c @@ -24,7 +24,8 @@ int nr_in_use; /* number of services */ extern int errno; /* error status */ /* Prototypes for internal functions that do the hard work. */ -FORWARD _PROTOTYPE( int start_service, (struct rproc *rp, int flags) ); +FORWARD _PROTOTYPE( int start_service, (struct rproc *rp, int flags, + endpoint_t *ep) ); FORWARD _PROTOTYPE( int stop_service, (struct rproc *rp,int how) ); FORWARD _PROTOTYPE( int fork_nb, (void) ); FORWARD _PROTOTYPE( int read_exec, (struct rproc *rp) ); @@ -56,6 +57,8 @@ int flags; /* extra flags, if any */ enum dev_style dev_style; /* device style */ int s; /* status variable */ int len; /* length of string */ + int r; + endpoint_t ep; /* new endpoint no. */ /* See if there is a free entry in the table with system processes. */ if (nr_in_use >= NR_SYS_PROCS) return(EAGAIN); @@ -128,7 +131,10 @@ int flags; /* extra flags, if any */ rp->r_set_resources= 0; /* old style */ /* All information was gathered. Now try to start the system service. */ - return(start_service(rp, flags)); + + r = start_service(rp, flags, &ep); + m_ptr->RS_ENDPOINT = ep; + return r; } @@ -149,6 +155,8 @@ message *m_ptr; /* request message pointer */ int s; /* status variable */ int len; /* length of string */ int i; + int r; + endpoint_t ep; struct rproc *tmp_rp; struct rs_start rs_start; @@ -322,7 +330,9 @@ message *m_ptr; /* request message pointer */ */ /* All information was gathered. Now try to start the system service. */ - return(start_service(rp, 0)); + r = start_service(rp, 0, &ep); + m_ptr->RS_ENDPOINT = ep; + return r; } @@ -380,8 +390,9 @@ PUBLIC int do_restart(message *m_ptr) { register struct rproc *rp; size_t len; - int s, proc; + int s, proc, r; char label[MAX_LABEL_LEN]; + endpoint_t ep; len= m_ptr->RS_CMD_LEN; if (len >= sizeof(label)) @@ -404,8 +415,9 @@ PUBLIC int do_restart(message *m_ptr) return EBUSY; } rp->r_flags &= ~(RS_EXITING|RS_REFRESHING|RS_NOPINGREPLY); - start_service(rp, 0); - return(OK); + r = start_service(rp, 0, &ep); + m_ptr->RS_ENDPOINT = ep; + return(r); } } #if VERBOSE @@ -491,7 +503,8 @@ PUBLIC void do_exit(message *m_ptr) { register struct rproc *rp; pid_t exit_pid; - int exit_status; + int exit_status, r; + endpoint_t ep; #if VERBOSE printf("RS: got SIGCHLD signal, doing wait to get exited child.\n"); @@ -538,8 +551,10 @@ PUBLIC void do_exit(message *m_ptr) rp->r_restarts = -1; /* reset counter */ if (rp->r_script[0] != '\0') run_script(rp); - else - start_service(rp, 0); /* direct restart */ + else { + start_service(rp, 0, &ep); /* direct restart */ + m_ptr->RS_ENDPOINT = ep; + } } else if (WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == EXEC_FAILED) { @@ -575,7 +590,11 @@ rp->r_restarts= 0; rp->r_backoff= 1; } else { - start_service(rp, 0); /* direct restart */ + start_service(rp, 0, &ep); /* direct restart */ + m_ptr->RS_ENDPOINT = ep; + /* Do this even if no I/O happens with the ioctl, in + * order to disambiguate requests with DEV_IOCTL_S. + */ } } break; @@ -593,6 +612,7 @@ message *m_ptr; register struct rproc *rp; clock_t now = m_ptr->NOTIFY_TIMESTAMP; int s; + endpoint_t ep; /* Search system services table. Only check slots that are in use. */ for (rp=BEG_RPROC_ADDR; rpr_backoff > 0) { rp->r_backoff -= 1; if (rp->r_backoff == 0) { - start_service(rp, 0); + start_service(rp, 0, &ep); + m_ptr->RS_ENDPOINT = ep; } } @@ -661,9 +682,10 @@ message *m_ptr; /*===========================================================================* * start_service * *===========================================================================*/ -PRIVATE int start_service(rp, flags) +PRIVATE int start_service(rp, flags, endpoint) struct rproc *rp; int flags; +endpoint_t *endpoint; { /* Try to execute the given system service. Fork a new process. The child * process will be inhibited from running by the NO_PRIV flag. Only let the @@ -771,6 +793,8 @@ int flags; getuptime(&rp->r_alive_tm); /* currently alive */ rp->r_stop_tm = 0; /* not exiting yet */ rproc_ptr[child_proc_nr_n] = rp; /* mapping for fast access */ + + if(endpoint) *endpoint = child_proc_nr_e; /* send back child endpoint */ return(OK); } diff --git a/servers/fs/Makefile b/servers/vfs/Makefile similarity index 76% rename from servers/fs/Makefile rename to servers/vfs/Makefile index 64bf4b26c..9d80d14d4 100644 --- a/servers/fs/Makefile +++ b/servers/vfs/Makefile @@ -1,5 +1,5 @@ # Makefile for File System (FS) -SERVER = fs +SERVER = vfs # directories u = /usr @@ -14,9 +14,10 @@ LDFLAGS = -i LIBS = -lsys -lsysutil -ltimers OBJ = main.o open.o read.o write.o pipe.o dmap.o \ - device.o exec.o path.o mount.o link.o super.o inode.o \ - cache.o cache2.o filedes.o stadir.o protect.o time.o \ - lock.o misc.o utility.o select.o timers.o table.o + path.o device.o mount.o link.o exec.o \ + filedes.o stadir.o protect.o time.o \ + lock.o misc.o utility.o select.o timers.o table.o \ + vnode.o vmnt.o request.o # build local binary install all build: $(SERVER) diff --git a/servers/vfs/buf.h b/servers/vfs/buf.h new file mode 100644 index 000000000..a17513683 --- /dev/null +++ b/servers/vfs/buf.h @@ -0,0 +1,75 @@ +/* Buffer (block) cache. To acquire a block, a routine calls get_block(), + * telling which block it wants. The block is then regarded as "in use" + * and has its 'b_count' field incremented. All the blocks that are not + * in use are chained together in an LRU list, with 'front' pointing + * to the least recently used block, and 'rear' to the most recently used + * block. A reverse chain, using the field b_prev is also maintained. + * Usage for LRU is measured by the time the put_block() is done. The second + * parameter to put_block() can violate the LRU order and put a block on the + * front of the list, if it will probably not be needed soon. If a block + * is modified, the modifying routine must set b_dirt to DIRTY, so the block + * will eventually be rewritten to the disk. + */ + +#include /* need struct direct */ +#include + +EXTERN struct buf { + /* Data portion of the buffer. */ + union { + char b__data[_MAX_BLOCK_SIZE]; /* ordinary user data */ +/* directory block */ + struct direct b__dir[NR_DIR_ENTRIES(_MAX_BLOCK_SIZE)]; +/* V1 indirect block */ + zone1_t b__v1_ind[V1_INDIRECTS]; +/* V2 indirect block */ + zone_t b__v2_ind[V2_INDIRECTS(_MAX_BLOCK_SIZE)]; +/* V1 inode block */ + d1_inode b__v1_ino[V1_INODES_PER_BLOCK]; +/* V2 inode block */ + d2_inode b__v2_ino[V2_INODES_PER_BLOCK(_MAX_BLOCK_SIZE)]; +/* bit map block */ + bitchunk_t b__bitmap[FS_BITMAP_CHUNKS(_MAX_BLOCK_SIZE)]; + } b; + + /* 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 */ + struct buf *b_hash; /* used to link bufs on hash chains */ + block_t b_blocknr; /* block number of its (minor) device */ + dev_t b_dev; /* major | minor device where block resides */ + char b_dirt; /* CLEAN or DIRTY */ + char b_count; /* number of users of this buffer */ +} buf[NR_BUFS]; + +/* A block is free if b_dev == NO_DEV. */ + +#define NIL_BUF ((struct buf *) 0) /* indicates absence of a buffer */ + +/* These defs make it possible to use to bp->b_data instead of bp->b.b__data */ +#define b_data b.b__data +#define b_dir b.b__dir +#define b_v1_ind b.b__v1_ind +#define b_v2_ind b.b__v2_ind +#define b_v1_ino b.b__v1_ino +#define b_v2_ino b.b__v2_ino +#define b_bitmap b.b__bitmap + +EXTERN struct buf *buf_hash[NR_BUF_HASH]; /* the buffer hash table */ + +EXTERN struct buf *front; /* points to least recently used free block */ +EXTERN struct buf *rear; /* points to most recently used free block */ +EXTERN int bufs_in_use; /* # bufs currently in use (not on free list)*/ + +/* When a block is released, the type of usage is passed to put_block(). */ +#define WRITE_IMMED 0100 /* block should be written to disk now */ +#define ONE_SHOT 0200 /* set if block not likely to be needed soon */ + +#define INODE_BLOCK 0 /* inode block */ +#define DIRECTORY_BLOCK 1 /* directory block */ +#define INDIRECT_BLOCK 2 /* pointer block */ +#define MAP_BLOCK 3 /* bit map */ +#define FULL_DATA_BLOCK 5 /* data, fully used */ +#define PARTIAL_DATA_BLOCK 6 /* data, partly used*/ + +#define HASH_MASK (NR_BUF_HASH - 1) /* mask for hashing block numbers */ diff --git a/servers/fs/const.h b/servers/vfs/const.h similarity index 97% rename from servers/fs/const.h rename to servers/vfs/const.h index d471e2312..479c8eae2 100644 --- a/servers/fs/const.h +++ b/servers/vfs/const.h @@ -4,11 +4,16 @@ #define V2_NR_DZONES 7 /* # direct zone numbers in a V2 inode */ #define V2_NR_TZONES 10 /* total # zone numbers in a V2 inode */ -#define NR_FILPS 256 /* # slots in filp table */ +#define NR_FILPS 512 /* # slots in filp table */ #define NR_INODES 256 /* # slots in "in core" inode table */ #define NR_SUPERS 12 /* # slots in super block table */ #define NR_LOCKS 8 /* # slots in the file locking table */ + +#define NR_MNTS 8 +#define NR_VNODES 512 + + /* The type of sizeof may be (unsigned) long. Use the following macro for * taking the sizes of small objects so that there are no surprises like * (small) long constants being passed to routines expecting an int. diff --git a/servers/fs/device.c b/servers/vfs/device.c similarity index 82% rename from servers/fs/device.c rename to servers/vfs/device.c index e480eee2a..914af39b0 100644 --- a/servers/fs/device.c +++ b/servers/vfs/device.c @@ -14,7 +14,7 @@ * ctty_opcl: perform controlling-tty-specific processing for open/close * ctty_io: perform controlling-tty-specific processing for I/O * do_ioctl: perform the IOCTL system call - * pm_setsid: perform the SETSID system call (FS side) + * do_setsid: perform the SETSID system call (FS side) */ #include "fs.h" @@ -24,12 +24,13 @@ #include #include #include -#include #include "file.h" #include "fproc.h" -#include "inode.h" + +#include +#include "vnode.h" +#include "vmnt.h" #include "param.h" -#include "super.h" #define ELEMENTS(a) (sizeof(a)/sizeof((a)[0])) @@ -42,6 +43,7 @@ FORWARD _PROTOTYPE( void safe_io_cleanup, (cp_grant_id_t, cp_grant_id_t *, extern int dmap_size; PRIVATE int dummyproc; + /*===========================================================================* * dev_open * *===========================================================================*/ @@ -67,6 +69,7 @@ int flags; /* mode bits and flags */ return(r); } + /*===========================================================================* * dev_close * *===========================================================================*/ @@ -88,17 +91,17 @@ endpoint_t 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. */ - struct fproc *rfp; - for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - if(rfp->fp_pid == PID_FREE) - continue; - if(rfp->fp_suspended == SUSPENDED && - rfp->fp_task == -driver && rfp->fp_grant == g) { - return rfp->fp_endpoint; - } - } + struct fproc *rfp; + for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { + if(rfp->fp_pid == PID_FREE) + continue; + if(rfp->fp_suspended == SUSPENDED && + rfp->fp_task == -driver && rfp->fp_grant == g) { + return rfp->fp_endpoint; + } + } - return NONE; + return NONE; } /*===========================================================================* @@ -246,6 +249,7 @@ off_t *pos; else size = _MINIX_IOCTL_SIZE(m_in.REQUEST); + /* Do this even if no I/O happens with the ioctl, in * order to disambiguate requests with DEV_IOCTL_S. */ @@ -491,6 +495,7 @@ int flags; /* special flags, like O_NONBLOCK */ /* fp is uninitialized at init time. */ if(!fp) panic(__FILE__,"SUSPEND on NULL fp", NO_NUM); + if (flags & O_NONBLOCK) { /* Not supposed to block. */ dev_mess.m_type = CANCEL; @@ -634,14 +639,14 @@ PUBLIC int do_ioctl() /* Perform the ioctl(ls_fd, request, argx) system call (uses m2 fmt). */ struct filp *f; - register struct inode *rip; + register struct vnode *vp; dev_t dev; if ( (f = get_filp(m_in.ls_fd)) == NIL_FILP) return(err_code); - rip = f->filp_ino; /* get inode pointer */ - if ( (rip->i_mode & I_TYPE) != I_CHAR_SPECIAL - && (rip->i_mode & I_TYPE) != I_BLOCK_SPECIAL) return(ENOTTY); - dev = (dev_t) rip->i_zone[0]; + 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); + dev = (dev_t) vp->v_sdev; return(dev_io(DEV_IOCTL, dev, who_e, m_in.ADDRESS, 0L, m_in.REQUEST, f->filp_flags)); @@ -728,6 +733,7 @@ message *mess_ptr; /* pointer to message for task */ return OK; } + /*===========================================================================* * no_dev * *===========================================================================*/ @@ -747,10 +753,12 @@ int flags; /* mode bits and flags */ PUBLIC int no_dev_io(int proc, message *m) { /* Called when doing i/o on a nonexistent device. */ - printf("FS: I/O on unmapped device number\n"); + printf("VFS: I/O on unmapped device number\n"); return EIO; } + + /*===========================================================================* * clone_opcl * *===========================================================================*/ @@ -797,24 +805,49 @@ int flags; /* mode bits and flags */ if (op == DEV_OPEN && dev_mess.REP_STATUS >= 0) { if (dev_mess.REP_STATUS != minor) { - /* A new minor device number has been returned. Create a - * temporary device file to hold it. - */ - struct inode *ip; + struct vnode *vp; + struct vmnt *vmp; - /* Device number of the new device. */ + struct clone_opcl_req req; + struct node_details res; + /* A new minor device number has been returned. + * Request root FS to create a temporary device file to hold it. + */ + + /* Device number of the new device. */ dev = (dev & ~(BYTE << MINOR)) | (dev_mess.REP_STATUS << MINOR); + + /* Fill in request */ + req.fs_e = ROOT_FS_E; + req.dev = dev; - ip = alloc_inode(root_dev, ALL_MODES | I_CHAR_SPECIAL); - if (ip == NIL_INODE) { - /* Oops, that didn't work. Undo open. */ - (void) clone_opcl(DEV_CLOSE, dev, proc_e, 0); - return(err_code); + /* Issue request */ + if ((r = req_clone_opcl(&req, &res)) != OK) { + (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; + + put_vnode(vp); + if ((vp = get_free_vnode()) == NIL_VNODE) { + printf("VFSclone_opcl: failed to get a free vnode..\n"); + vp = fp->fp_filp[m_in.fd]->filp_vno; } - ip->i_zone[0] = dev; + + vp->v_fs_e = res.fs_e; + if ((vmp = find_vmnt(vp->v_fs_e)) == NIL_VMNT) + printf("VFSclone_opcl: no vmnt found\n"); - put_inode(fp->fp_filp[m_in.fd]->filp_ino); - fp->fp_filp[m_in.fd]->filp_ino = ip; + vp->v_vmnt = vmp; + vp->v_dev = vmp->m_dev; + + vp->v_inode_nr = res.inode_nr; + vp->v_mode = res.fmode; + vp->v_sdev = dev; + vp->v_count = 1; + fp->fp_filp[m_in.fd]->filp_vno = vp; } dev_mess.REP_STATUS = OK; } @@ -826,63 +859,75 @@ int flags; /* mode bits and flags */ *===========================================================================*/ PUBLIC void dev_up(int maj) { - /* A new device driver has been mapped in. This function - * checks if any filesystems are mounted on it, and if so, - * dev_open()s them so the filesystem can be reused. - */ - struct super_block *sb; - struct filp *fp; - int r; + /* A new device driver has been mapped in. This function + * checks if any filesystems are mounted on it, and if so, + * dev_open()s them so the filesystem can be reused. + */ + struct filp *fp; + struct vmnt *vmp; + int r, new_driver_e; + message m; - /* Open a device once for every filp that's opened on it, - * and once for every filesystem mounted from it. - */ + /* Open a device once for every filp that's opened on it, + * and once for every filesystem mounted from it. + */ + new_driver_e = dmap[maj].dmap_driver; - for(sb = super_block; sb < &super_block[NR_SUPERS]; sb++) { - int minor; - if(sb->s_dev == NO_DEV) - continue; - if(((sb->s_dev >> MAJOR) & BYTE) != maj) - continue; - minor = ((sb->s_dev >> MINOR) & BYTE); - printf("FS: remounting dev %d/%d\n", maj, minor); - if((r = dev_open(sb->s_dev, FS_PROC_NR, - sb->s_rd_only ? R_BIT : (R_BIT|W_BIT))) != OK) { - printf("FS: mounted dev %d/%d re-open failed: %d.\n", - maj, minor, r); - } - } + for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) { + int minor; + if (vmp->m_dev == NO_DEV) continue; + if ( ((vmp->m_dev >> MAJOR) & BYTE) != maj) continue; + minor = ((vmp->m_dev >> MINOR) & BYTE); + + printf("VFS: re-opening dev: %d/%d\n", maj, minor); + + if ((r = dev_open(vmp->m_dev, FS_PROC_NR, + vmp->m_flags ? R_BIT : (R_BIT|W_BIT))) != OK) { + printf("VFS: mounted dev %d/%d re-open failed: %d.\n", + maj, minor, r); + } - for(fp = filp; fp < &filp[NR_FILPS]; fp++) { - struct inode *in; - int minor; + /* Send new driver endpoint */ + printf("VFS: sending new dirver for dev: %d, endpoint: %d, FS_e: %d\n", + vmp->m_dev, new_driver_e, vmp->m_fs_e); + + if (OK != req_newdriver(vmp->m_fs_e, vmp->m_dev, new_driver_e)) +printf("VFSdev_up: error sending new driver endpoint. FS_e: %d req_nr: %d\n", + vmp->m_fs_e, REQ_NEW_DRIVER); + else + vmp->m_driver_e = new_driver_e; + } - if(fp->filp_count < 1 || !(in=fp->filp_ino)) continue; - if(((in->i_zone[0] >> MAJOR) & BYTE) != maj) continue; - if(!(in->i_mode & (I_BLOCK_SPECIAL|I_CHAR_SPECIAL))) continue; - - minor = ((in->i_zone[0] >> MINOR) & BYTE); + for (fp = filp; fp < &filp[NR_FILPS]; fp++) { + struct vnode *vp; + int minor; - printf("FS: reopening special %d/%d..\n", maj, minor); + if(fp->filp_count < 1 || !(vp = fp->filp_vno)) continue; + if(((vp->v_sdev >> MAJOR) & BYTE) != maj) continue; + if(!(vp->v_mode & (I_BLOCK_SPECIAL|I_CHAR_SPECIAL))) continue; - if((r = dev_open(in->i_zone[0], FS_PROC_NR, - in->i_mode & (R_BIT|W_BIT))) != OK) { - int n; - /* This function will set the fp_filp[]s of processes - * holding that fp to NULL, but _not_ clear - * fp_filp_inuse, so that fd can't be recycled until - * it's close()d. - */ - n = inval_filp(fp); - if(n != fp->filp_count) - printf("FS: warning: invalidate/count " - "discrepancy (%d, %d)\n", n, fp->filp_count); - fp->filp_count = 0; - printf("FS: file on dev %d/%d re-open failed: %d; " - "invalidated %d fd's.\n", maj, minor, r, n); - } - } + minor = ((vp->v_sdev >> MINOR) & BYTE); - return; + printf("VFS: reopening special %d/%d..\n", maj, minor); + + if((r = dev_open(vp->v_sdev, FS_PROC_NR, + vp->v_mode & (R_BIT|W_BIT))) != OK) { + int n; + /* This function will set the fp_filp[]s of processes + * holding that fp to NULL, but _not_ clear + * fp_filp_inuse, so that fd can't be recycled until + * it's close()d. + */ + n = inval_filp(fp); + if(n != fp->filp_count) + printf("VFS: warning: invalidate/count " + "discrepancy (%d, %d)\n", n, fp->filp_count); + fp->filp_count = 0; + printf("VFS: file on dev %d/%d re-open failed: %d; " + "invalidated %d fd's.\n", maj, minor, r, n); + } + } + + return; } diff --git a/servers/fs/dmap.c b/servers/vfs/dmap.c similarity index 100% rename from servers/fs/dmap.c rename to servers/vfs/dmap.c diff --git a/servers/fs/exec.c b/servers/vfs/exec.c similarity index 58% rename from servers/fs/exec.c rename to servers/vfs/exec.c index 39755f3d7..10ca92d90 100644 --- a/servers/fs/exec.c +++ b/servers/vfs/exec.c @@ -12,6 +12,9 @@ * * The entry points into this file are: * pm_exec: perform the EXEC system call + * + * Changes for VFS: + * Aug 2006 (Balazs Gerofi) */ #include "fs.h" @@ -22,11 +25,13 @@ #include #include #include -#include "buf.h" +#include #include "fproc.h" -#include "inode.h" #include "param.h" -#include "super.h" + +#include "vnode.h" +#include "vmnt.h" +#include FORWARD _PROTOTYPE( int exec_newmem, (int proc_e, vir_bytes text_bytes, vir_bytes data_bytes, vir_bytes bss_bytes, vir_bytes tot_bytes, @@ -34,17 +39,17 @@ FORWARD _PROTOTYPE( int exec_newmem, (int proc_e, vir_bytes text_bytes, Dev_t st_dev, ino_t st_ino, time_t st_ctime, char *progname, int new_uid, int new_gid, vir_bytes *stack_topp, int *load_textp, int *allow_setuidp) ); -FORWARD _PROTOTYPE( int read_header, (struct inode *rip, int *sep_id, +FORWARD _PROTOTYPE( int read_header, (struct vnode *vp, int *sep_id, vir_bytes *text_bytes, vir_bytes *data_bytes, vir_bytes *bss_bytes, phys_bytes *tot_bytes, vir_bytes *pc, int *hdrlenp) ); -FORWARD _PROTOTYPE( int patch_stack, (struct inode *rip, +FORWARD _PROTOTYPE( int patch_stack, (struct vnode *vp, char stack[ARG_MAX], vir_bytes *stk_bytes) ); 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( int read_seg, (struct inode *rip, off_t off, +FORWARD _PROTOTYPE( int read_seg, (struct vnode *vp, off_t off, int proc_e, int seg, phys_bytes seg_bytes) ); FORWARD _PROTOTYPE( void clo_exec, (struct fproc *rfp) ); @@ -65,168 +70,218 @@ vir_bytes frame_len; * complete stack image, including pointers, args, environ, etc. The stack * is copied to a buffer inside FS, and then to the new core image. */ - int r, sep_id, round, proc_s, hdrlen, load_text, allow_setuid; - vir_bytes text_bytes, data_bytes, bss_bytes, pc; - phys_bytes tot_bytes; /* total space for program, including gap */ - vir_bytes stack_top, vsp; - off_t off; - uid_t new_uid; - gid_t new_gid; - struct fproc *rfp; - struct inode *rip; - char *cp; - char progname[PROC_NAME_LEN]; + int r, sep_id, round, proc_s, hdrlen, load_text, allow_setuid; + vir_bytes text_bytes, data_bytes, bss_bytes, pc; + phys_bytes tot_bytes; /* total space for program, including gap */ + vir_bytes stack_top, vsp; + off_t off; + uid_t new_uid; + gid_t new_gid; + struct fproc *rfp; + struct vnode vn; + struct vmnt *vmp; + time_t v_ctime; + uid_t v_uid; + gid_t v_gid; + char *cp; + char progname[PROC_NAME_LEN]; + static char mbuf[ARG_MAX]; /* buffer for stack and zeroes */ - static char mbuf[ARG_MAX]; /* buffer for stack and zeroes */ + /* Request and response structures */ + struct lookup_req lookup_req; + struct access_req access_req; + struct open_req open_req; + struct node_details res; + + 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? */ - 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? */ + /* Get the exec file name. */ + r= fetch_name(path, path_len, 0); + if (r != OK) + { + printf("pm_exec: fetch_name failed\n"); + return(r); /* file name not in user data segment */ + } - /* Get the exec file name. */ - r= fetch_name(path, path_len, 0); - if (r != OK) - { - printf("pm_exec: fetch_name failed\n"); - return(r); /* file name not in user data segment */ - } + /* Fetch the stack from the user before destroying the old core image. */ + if (frame_len > ARG_MAX) + { + printf("pm_exec: bad frame_len\n"); + return(ENOMEM); /* stack too big */ + } + r = sys_datacopy(proc_e, (vir_bytes) frame, + SELF, (vir_bytes) mbuf, (phys_bytes)frame_len); + /* can't fetch stack (e.g. bad virtual addr) */ + if (r != OK) + { + printf("pm_exec: sys_datacopy failed\n"); + return(r); + } - /* Fetch the stack from the user before destroying the old core image. */ - if (frame_len > ARG_MAX) - { - printf("pm_exec: bad frame_len\n"); - return(ENOMEM); /* stack too big */ - } - r = sys_datacopy(proc_e, (vir_bytes) frame, - SELF, (vir_bytes) mbuf, (phys_bytes)frame_len); - /* can't fetch stack (e.g. bad virtual addr) */ - if (r != OK) - { - printf("pm_exec: sys_datacopy failed\n"); - return(r); - } + /* The default is the keep the original user and group IDs */ + new_uid= rfp->fp_effuid; + new_gid= rfp->fp_effgid; - /* The default is the keep the original user and group IDs */ - new_uid= rfp->fp_effuid; - 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(user_fullpath, '/')) ? cp++ : (cp= user_fullpath); - for (round= 0; round < 2; round++) - /* round = 0 (first attempt), or 1 (interpreted script) */ - { - /* Save the name of the program */ - (cp= strrchr(user_path, '/')) ? cp++ : (cp= user_path); + strncpy(progname, cp, PROC_NAME_LEN-1); + progname[PROC_NAME_LEN-1] = '\0'; - strncpy(progname, cp, PROC_NAME_LEN-1); - progname[PROC_NAME_LEN-1] = '\0'; + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = NULL; + lookup_req.flags = EAT_PATH; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + if ((res.fmode & I_TYPE) != I_REGULAR) { + return ENOEXEC; + } + else { + /* Fill in request fields */ + access_req.fs_e = res.fs_e; + access_req.amode = X_BIT; + access_req.inode_nr = res.inode_nr; + access_req.uid = fp->fp_effuid; + access_req.gid = fp->fp_effgid; -#if 0 - printf("pm_exec: eat_path '%s'\n", user_path); -#endif - rip= eat_path(user_path); - if (rip == NIL_INODE) - { - return(err_code); - } - if ((rip->i_mode & I_TYPE) != I_REGULAR) - r = ENOEXEC; - else - r = forbidden(rip, X_BIT); /* check if file is executable */ - if (r != OK) { - put_inode(rip); - printf("pm_exec: bad executable\n"); - return(r); - } - - if (round == 0) - { - /* Deal with setuid/setgid executables */ - if (rip->i_mode & I_SET_UID_BIT) - new_uid = rip->i_uid; - if (rip->i_mode & I_SET_GID_BIT) - new_gid = rip->i_gid; - } - - /* Read the file header and extract the segment sizes. */ - r = read_header(rip, &sep_id, &text_bytes, &data_bytes, &bss_bytes, - &tot_bytes, &pc, &hdrlen); - if (r != ESCRIPT || round != 0) - break; - - /* Get fresh copy of the file name. */ - r= fetch_name(path, path_len, 0); - if (r != OK) - { - printf("pm_exec: 2nd fetch_name failed\n"); - put_inode(rip); - return(r); /* strange */ - } - r= patch_stack(rip, mbuf, &frame_len); - put_inode(rip); - if (r != OK) - { - printf("pm_exec: patch stack\n"); + + /* Issue request */ + if ((r = req_access(&access_req)) != OK) { + printf("VFSexec: access failed\n"); return r; + } + } + + /* Open request. */ + open_req.inode_nr = res.inode_nr; + open_req.fs_e = res.fs_e; + open_req.oflags = 0; + open_req.omode = 0; + open_req.lastc = NULL; + open_req.uid = 0; + open_req.gid = 0; + + /* Issue request */ + if ((r = req_open(&open_req, &res)) != OK) { + printf("VFSexec: open failed\n"); + return r; } - } - if (r != OK) - { - printf("pm_exec: returning ENOEXEC, r = %d\n", r); - return ENOEXEC; - } + /* Use the vnode to store file details */ + vn.v_inode_nr = res.inode_nr; + vn.v_mode = res.fmode; + vn.v_index = res.inode_index; + vn.v_size = res.fsize; + vn.v_fs_e = res.fs_e; + vn.v_count = 1; + if ( (vmp = find_vmnt(vn.v_fs_e)) == NIL_VMNT) + printf("VFS: vmnt not found by exec()"); + + vn.v_dev = vmp->m_dev; + vn.v_vmnt = vmp; + + v_ctime = res.ctime; + v_uid = res.uid; + v_gid = res.gid; + + if (round == 0) + { + /* Deal with setuid/setgid executables */ + if (vn.v_mode & I_SET_UID_BIT) + new_uid = v_uid; + if (vn.v_mode & I_SET_GID_BIT) + new_gid = v_gid; + } - r= exec_newmem(proc_e, text_bytes, data_bytes, bss_bytes, tot_bytes, - frame_len, sep_id, rip->i_dev, rip->i_num, rip->i_ctime, - progname, new_uid, new_gid, &stack_top, &load_text, &allow_setuid); - if (r != OK) - { - printf("pm_exec: exec_newmap failed: %d\n", r); - put_inode(rip); - return r; - } + /* Read the file header and extract the segment sizes. */ + r = read_header(&vn, &sep_id, &text_bytes, &data_bytes, &bss_bytes, + &tot_bytes, &pc, &hdrlen); + if (r != ESCRIPT || round != 0) + break; - /* Patch up stack and copy it from FS to new core image. */ - vsp = stack_top; - vsp -= frame_len; - patch_ptr(mbuf, vsp); - r = sys_datacopy(SELF, (vir_bytes) mbuf, - proc_e, (vir_bytes) vsp, (phys_bytes)frame_len); - if (r != OK) panic(__FILE__,"pm_exec stack copy err on", proc_e); + /* Get fresh copy of the file name. */ + r= fetch_name(path, path_len, 0); + if (r != OK) + { + printf("pm_exec: 2nd fetch_name failed\n"); + put_vnode(&vn); + return(r); /* strange */ + } + r= patch_stack(&vn, mbuf, &frame_len); + put_vnode(&vn); + if (r != OK) + { + printf("pm_exec: patch stack\n"); + return r; + } + } - off = hdrlen; + if (r != OK) + { + printf("pm_exec: returning ENOEXEC, r = %d\n", r); + return ENOEXEC; + } - /* Read in text and data segments. */ - if (load_text) { - r= read_seg(rip, off, proc_e, T, text_bytes); - } - off += text_bytes; - if (r == OK) - r= read_seg(rip, off, proc_e, D, data_bytes); + r= exec_newmem(proc_e, text_bytes, data_bytes, bss_bytes, tot_bytes, + frame_len, sep_id, vn.v_dev, vn.v_inode_nr, v_ctime, + progname, new_uid, new_gid, &stack_top, &load_text, &allow_setuid); + if (r != OK) + { + printf("pm_exec: exec_newmap failed: %d\n", r); + put_vnode(&vn); + return r; + } - put_inode(rip); + /* Patch up stack and copy it from FS to new core image. */ + vsp = stack_top; + vsp -= frame_len; + patch_ptr(mbuf, vsp); + r = sys_datacopy(SELF, (vir_bytes) mbuf, + proc_e, (vir_bytes) vsp, (phys_bytes)frame_len); + if (r != OK) panic(__FILE__,"pm_exec stack copy err on", proc_e); - if (r != OK) return r; + off = hdrlen; - clo_exec(rfp); + /* Read in text and data segments. */ + if (load_text) { + r= read_seg(&vn, off, proc_e, T, text_bytes); + } + off += text_bytes; + if (r == OK) + r= read_seg(&vn, off, proc_e, D, data_bytes); - if (allow_setuid) - { - rfp->fp_effuid= new_uid; - rfp->fp_effgid= new_gid; - } + put_vnode(&vn); - /* This child has now exec()ced. */ - rfp->fp_execced = 1; + if (r != OK) return r; - /* Check if this is a driver that can now be useful. */ - dmap_endpt_up(rfp->fp_endpoint); + clo_exec(rfp); - return OK; + if (allow_setuid) + { + rfp->fp_effuid= new_uid; + rfp->fp_effgid= new_gid; + } + + /* This child has now exec()ced. */ + rfp->fp_execced = 1; + + /* Check if this is a driver that can now be useful. */ + dmap_endpt_up(rfp->fp_endpoint); + +/*printf("VFSpm_exec: %s OK\n", user_fullpath);*/ + return OK; } - /*===========================================================================* * exec_newmem * *===========================================================================*/ @@ -291,9 +346,9 @@ int *allow_setuidp; /*===========================================================================* * read_header * *===========================================================================*/ -PRIVATE int read_header(rip, sep_id, text_bytes, data_bytes, bss_bytes, +PRIVATE int read_header(vp, sep_id, text_bytes, data_bytes, bss_bytes, tot_bytes, pc, hdrlenp) -struct inode *rip; /* inode for reading exec file */ +struct vnode *vp; /* inode for reading exec file */ int *sep_id; /* true iff sep I&D */ vir_bytes *text_bytes; /* place to return text size */ vir_bytes *data_bytes; /* place to return initialized data size */ @@ -304,8 +359,6 @@ int *hdrlenp; { /* Read the header and extract the text, data, bss and total sizes from it. */ off_t pos; - block_t b; - struct buf *bp; struct exec hdr; /* a.out header is read in here */ /* Read the header and check the magic number. The standard MINIX header @@ -335,25 +388,31 @@ int *hdrlenp; * is ignored here. */ + struct readwrite_req req; + struct readwrite_res res; + int r; + pos= 0; /* Read from the start of the file */ - b = read_map(rip, pos); /* get block number */ - if (b == 0) /* Hole */ - return ENOEXEC; + /* Fill in request structure */ + req.fs_e = vp->v_fs_e; + req.rw_flag = READING; + req.inode_nr = vp->v_inode_nr; + req.user_e = FS_PROC_NR; + req.seg = D; + req.pos = pos; + req.num_of_bytes = sizeof(hdr); + req.user_addr = (char*)&hdr; + req.inode_index = vp->v_index; - bp = get_block(rip->i_dev, b, NORMAL); /* get block */ + /* Issue request */ + if ((r = req_readwrite(&req, &res)) != OK) return r; /* Interpreted script? */ - if (bp->b_data[0] == '#' && bp->b_data[1] == '!' && rip->i_size >= 2) - { - put_block(bp, FULL_DATA_BLOCK); + if (((char*)&hdr)[0] == '#' && ((char*)&hdr)[1] == '!' && vp->v_size >= 2) return ESCRIPT; - } - memcpy(&hdr, bp->b_data, sizeof(hdr)); - put_block(bp, FULL_DATA_BLOCK); - - if (rip->i_size < A_MINHDR) return(ENOEXEC); + if (vp->v_size < A_MINHDR) return(ENOEXEC); /* Check magic number, cpu type, and flags. */ if (BADMAG(hdr)) return(ENOEXEC); @@ -388,8 +447,8 @@ int *hdrlenp; /*===========================================================================* * patch_stack * *===========================================================================*/ -PRIVATE int patch_stack(rip, stack, stk_bytes) -struct inode *rip; /* pointer for open script file */ +PRIVATE int patch_stack(vp, stack, stk_bytes) +struct vnode *vp; /* pointer for open script file */ char stack[ARG_MAX]; /* pointer to stack image within FS */ vir_bytes *stk_bytes; /* size of initial stack */ { @@ -398,50 +457,56 @@ vir_bytes *stk_bytes; /* size of initial stack */ * the interpreter. */ enum { INSERT=FALSE, REPLACE=TRUE }; - int n; + int n, r; off_t pos; - block_t b; - struct buf *bp; char *sp, *interp = NULL; + char buf[_MAX_BLOCK_SIZE]; + struct readwrite_req req; + struct readwrite_res res; /* Make user_path the new argv[0]. */ - if (!insert_arg(stack, stk_bytes, user_path, REPLACE)) return(ENOMEM); + if (!insert_arg(stack, stk_bytes, user_fullpath, REPLACE)) return(ENOMEM); - pos= 0; /* Read from the start of the file */ - b = read_map(rip, pos); /* get block number */ - if (b == 0) /* Hole */ - return ENOEXEC; + pos = 0; /* Read from the start of the file */ - bp = get_block(rip->i_dev, b, NORMAL); /* get block */ - n= rip->i_size; - if (n > rip->i_sp->s_block_size) - n= rip->i_sp->s_block_size; - if (n < 2) - { - put_block(bp, FULL_DATA_BLOCK); - return ENOEXEC; - } - sp= bp->b_data+2; /* just behind the #! */ + /* Fill in request structure */ + req.fs_e = vp->v_fs_e; + req.rw_flag = READING; + req.inode_nr = vp->v_inode_nr; + req.user_e = FS_PROC_NR; + req.seg = D; + req.pos = pos; + req.num_of_bytes = _MAX_BLOCK_SIZE; + req.user_addr = buf; + req.inode_index = vp->v_index; + + /* Issue request */ + if ((r = req_readwrite(&req, &res)) != OK) return r; + + n = vp->v_size; + if (n > vp->v_vmnt->m_block_size) + n = vp->v_vmnt->m_block_size; + if (n < 2) return ENOEXEC; + + sp = &(buf[2]); /* just behind the #! */ n -= 2; - if (n > PATH_MAX) - n= PATH_MAX; + if (n > PATH_MAX) n = PATH_MAX; /* Use the user_path variable for temporary storage */ - memcpy(user_path, sp, n); - put_block(bp, FULL_DATA_BLOCK); + memcpy(user_fullpath, sp, n); - if ((sp= memchr(user_path, '\n', n)) == NULL) /* must be a proper line */ + if ((sp = memchr(user_fullpath, '\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_path && (*--sp == ' ' || *sp == '\t')) {} - if (sp == user_path) break; + while (sp > user_fullpath && (*--sp == ' ' || *sp == '\t')) {} + if (sp == user_fullpath) break; sp[1] = 0; /* Move to the start of the argument. */ - while (sp > user_path && sp[-1] != ' ' && sp[-1] != '\t') --sp; + while (sp > user_fullpath && sp[-1] != ' ' && sp[-1] != '\t') --sp; interp = sp; if (!insert_arg(stack, stk_bytes, sp, INSERT)) return(ENOMEM); @@ -450,8 +515,8 @@ 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_path) - memmove(user_path, interp, strlen(interp)+1); + if (interp != user_fullpath) + memmove(user_fullpath, interp, strlen(interp)+1); return(OK); } @@ -546,8 +611,8 @@ vir_bytes base; /* virtual address of stack base inside user */ /*===========================================================================* * read_seg * *===========================================================================*/ -PRIVATE int read_seg(rip, off, proc_e, seg, seg_bytes) -struct inode *rip; /* inode descriptor to read from */ +PRIVATE int read_seg(vp, off, proc_e, seg, seg_bytes) +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 */ @@ -558,46 +623,31 @@ phys_bytes seg_bytes; /* how much is to be transferred? */ * a segment is padded out to a click multiple, and the data segment is only * partially initialized. */ - - int r, block_size; - off_t n, o, b_off, seg_off; - block_t b; - struct buf *bp; + struct readwrite_req req; + struct readwrite_res res; + int r; /* Make sure that the file is big enough */ - if (rip->i_size < off+seg_bytes) - return EIO; + if (vp->v_size < off+seg_bytes) return EIO; + + /* Fill in request structure */ + req.fs_e = vp->v_fs_e; + req.rw_flag = READING; + req.inode_nr = vp->v_inode_nr; + req.user_e = proc_e; + req.seg = seg; + req.pos = off; + req.num_of_bytes = seg_bytes; + req.user_addr = 0; + req.inode_index = vp->v_index; - block_size= rip->i_sp->s_block_size; - seg_off= 0; - for (o= off - (off % block_size); o < off+seg_bytes; o += block_size) - { - b= read_map(rip, o); - if (b == NO_BLOCK) - { - bp = get_block(NO_DEV, NO_BLOCK, NORMAL); /* get a buffer */ - zero_block(bp); - } - else - bp = get_block(rip->i_dev, b, NORMAL); /* get block */ - if (o < off) - b_off= off-o; - else - b_off= 0; - n= block_size-b_off; - if (o+b_off+n > off+seg_bytes) - n= off+seg_bytes-(o+b_off); - r= sys_vircopy(SELF, D, (vir_bytes)bp->b_data+b_off, - proc_e, seg, seg_off, n); - put_block(bp, FULL_DATA_BLOCK); + /* Issue request */ + if ((r = req_readwrite(&req, &res)) != OK) return r; + + if (r == OK && res.cum_io != seg_bytes) + printf("VFSread_seg segment has not been read properly by exec() \n"); - if (r != OK) - return r; - - seg_off += n; - } - - return OK; + return r; } @@ -618,3 +668,4 @@ struct fproc *rfp; } + diff --git a/servers/vfs/file.h b/servers/vfs/file.h new file mode 100644 index 000000000..4b1e692f4 --- /dev/null +++ b/servers/vfs/file.h @@ -0,0 +1,27 @@ +/* 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_count; /* how many file descriptors share this slot?*/ +/* struct inode *filp_ino;*/ /* pointer to the inode */ + + struct vnode *filp_vno; + + off_t filp_pos; /* file position */ + + /* 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 */ + + /* 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 NIL_FILP (struct filp *) 0 /* indicates absence of a filp slot */ diff --git a/servers/fs/filedes.c b/servers/vfs/filedes.c similarity index 88% rename from servers/fs/filedes.c rename to servers/vfs/filedes.c index 48548bfef..4b137c969 100644 --- a/servers/fs/filedes.c +++ b/servers/vfs/filedes.c @@ -13,7 +13,8 @@ #include "fs.h" #include "file.h" #include "fproc.h" -#include "inode.h" + +#include "vnode.h" /*===========================================================================* * get_fd * @@ -88,7 +89,7 @@ int fild; /* file descriptor */ /*===========================================================================* * find_filp * *===========================================================================*/ -PUBLIC struct filp *find_filp(register struct inode *rip, mode_t bits) +PUBLIC struct filp *find_filp(register struct vnode *vp, mode_t bits) { /* Find a filp slot that refers to the inode 'rip' in a way as described * by the mode bit 'bits'. Used for determining whether somebody is still @@ -100,7 +101,7 @@ PUBLIC struct filp *find_filp(register struct inode *rip, mode_t bits) register struct filp *f; for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { - if (f->filp_count != 0 && f->filp_ino == rip && (f->filp_mode & bits)){ + if (f->filp_count != 0 && f->filp_vno == vp && (f->filp_mode & bits)){ return(f); } } @@ -114,16 +115,16 @@ PUBLIC struct filp *find_filp(register struct inode *rip, mode_t bits) *===========================================================================*/ PUBLIC int inval_filp(struct filp *fp) { - 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) { - fproc[f].fp_filp[fd] = NIL_FILP; - n++; - } - } - } + 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) { + fproc[f].fp_filp[fd] = NIL_FILP; + n++; + } + } + } - return n; + return n; } diff --git a/servers/vfs/fproc.h b/servers/vfs/fproc.h new file mode 100644 index 000000000..1edfae913 --- /dev/null +++ b/servers/vfs/fproc.h @@ -0,0 +1,53 @@ +#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. + */ +EXTERN struct fproc { + mode_t fp_umask; /* mask set by umask system call */ + +/* struct inode *fp_workdir;*/ /* pointer to working directory's inode */ +/* struct inode *fp_rootdir;*/ /* pointer to current root dir (see chroot) */ + + struct filp *fp_filp[OPEN_MAX];/* the file descriptor table */ + + struct vnode *fp_wd; + struct vnode *fp_rd; + + fd_set fp_filp_inuse; /* which fd's are in use? */ + 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 */ + dev_t fp_tty; /* major/minor of controlling tty */ + int fp_fd; /* place to save fd 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 */ + char fp_suspended; /* set to indicate process hanging */ + char fp_revived; /* set to indicate process being revived */ + int 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 */ + + 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 */ +} fproc[NR_PROCS]; + +/* Field values. */ +#define NOT_SUSPENDED 0 /* process is not suspended on pipe or task */ +#define SUSPENDED 1 /* process is suspended on pipe or task */ +#define NOT_REVIVING 0 /* process is not being revived */ +#define REVIVING 1 /* process is being revived from suspension */ +#define PID_FREE 0 /* process slot free */ + +/* Check is process number is acceptable - includes system processes. */ +#define isokprocnr(n) ((unsigned)((n)+NR_TASKS) < NR_PROCS + NR_TASKS) + diff --git a/servers/vfs/fs.h b/servers/vfs/fs.h new file mode 100644 index 000000000..b9f16ff04 --- /dev/null +++ b/servers/vfs/fs.h @@ -0,0 +1,26 @@ +/* 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 VERBOSE 0 /* show messages during initialization? */ + +/* 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 "const.h" +#include "proto.h" +#include "glo.h" diff --git a/servers/fs/glo.h b/servers/vfs/glo.h similarity index 75% rename from servers/fs/glo.h rename to servers/vfs/glo.h index bcd16a868..454425cd7 100644 --- a/servers/fs/glo.h +++ b/servers/vfs/glo.h @@ -10,9 +10,11 @@ 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 off_t rdahedpos; /* position to read ahead */ -EXTERN struct inode *rdahed_inode; /* pointer to inode to read ahead */ + EXTERN Dev_t root_dev; /* device number of the root device */ +EXTERN int ROOT_FS_E; /* kernel endpoint of the root FS proc */ +EXTERN int last_login_fs_e; /* endpoint of the FS proc that logged in + before the corresponding mount request */ EXTERN time_t boottime; /* time in seconds at system boot */ /* The parameters of the call are kept here. */ @@ -20,7 +22,10 @@ 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 char user_path[PATH_MAX];/* storage for user path name */ +EXTERN message mount_m_in; /* the input message itself */ + +EXTERN char user_fullpath[PATH_MAX]; /* storage for user path name */ +EXTERN short cum_path_processed; /* number of characters processed */ /* The following variables are used for returning results to the caller. */ EXTERN int err_code; /* temporary storage for error number */ diff --git a/servers/fs/inode.h b/servers/vfs/inode.h similarity index 100% rename from servers/fs/inode.h rename to servers/vfs/inode.h diff --git a/servers/vfs/link.c b/servers/vfs/link.c new file mode 100644 index 000000000..c61686970 --- /dev/null +++ b/servers/vfs/link.c @@ -0,0 +1,413 @@ +/* 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 + * + * Changes for VFS: + * Jul 2006 (Balazs Gerofi) + */ + +#include "fs.h" +#include +#include +#include +#include +#include +#include "file.h" +#include "fproc.h" +#include "param.h" + +#include +#include "vnode.h" + +/*===========================================================================* + * do_link * + *===========================================================================*/ +PUBLIC int do_link() +{ +/* Perform the link(name1, name2) system call. */ + int linked_fs_e; + int linked_inode_nr; + int link_lastdir_fs_e; + int link_lastdir_inode_nr; + char string[NAME_MAX]; + struct link_req req; + struct lookup_req lookup_req; + struct node_details res; + int r; + + if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) + return(err_code); + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = NULL; + lookup_req.flags = EAT_PATH; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + linked_fs_e = res.fs_e; + req.linked_file = res.inode_nr; + + /* Does the final directory of 'name2' exist? */ + if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) { + return(err_code); + } + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = string; + lookup_req.flags = LAST_DIR; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + link_lastdir_fs_e = res.fs_e; + req.link_parent = res.inode_nr; + + /* Check for links across devices. */ + if (linked_fs_e != link_lastdir_fs_e) + return EXDEV; + + /* Send link request. */ + req.fs_e = linked_fs_e; + /* Send the last component of the link name */ + req.uid = fp->fp_effuid; + req.gid = fp->fp_effgid; + req.lastc = string; + + /* Issue request */ + return req_link(&req); +} + + + +/*===========================================================================* + * 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. + */ + register struct fproc *rfp; + char string[NAME_MAX]; + struct vnode *vp; + struct unlink_req req; + struct lookup_req lookup_req; + struct node_details res; + int r; + string[0] = '\0'; + + if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = NULL; + lookup_req.flags = EAT_PATH_OPAQUE; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + /* If a directory file has to be removed the following conditions have to met: + * - The directory must not be the root of a mounted file system + * - The directory must not be anybody's root/working directory + */ + if ((res.fmode & I_TYPE) == I_DIRECTORY) { + /* Only root can unlink a directory */ + if (call_nr == UNLINK && !super_user) return EPERM; + + /* Can't remove a root directory */ + if (res.inode_nr == ROOT_INODE) return EBUSY; + + /* Can't remove anybody's working directory */ + if ((vp = find_vnode(res.fs_e, res.inode_nr)) != + NIL_VNODE) { + /* Check directories */ + for (rfp = &fproc[INIT_PROC_NR + 1]; rfp < &fproc[NR_PROCS]; + rfp++) { + if (rfp->fp_pid != PID_FREE && + (rfp->fp_wd == vp || rfp->fp_rd == vp)) + return(EBUSY); + } + } + } + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = string; + lookup_req.flags = LAST_DIR; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + /* Fill in request fields. */ + req.fs_e = res.fs_e; + req.d_inode_nr = res.inode_nr; + req.uid = fp->fp_effuid; + req.gid = fp->fp_effgid; + req.lastc = string; + + /* Issue request */ + return (call_nr == UNLINK) ? req_unlink(&req) : req_rmdir(&req); +} + + +/*===========================================================================* + * do_rename * + *===========================================================================*/ +PUBLIC int do_rename() +{ +/* Perform the rename(name1, name2) system call. */ + int old_dir_inode; + int old_fs_e; + int new_dir_inode; + int new_fs_e; + char old_name[NAME_MAX]; + char new_name[NAME_MAX]; + struct vnode *vp; + struct fproc *rfp; + struct rename_req req; + struct lookup_req lookup_req; + struct node_details res; + int r; + + /* 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); + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = old_name; + lookup_req.flags = LAST_DIR; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + /* Remeber inode number and FS endpoint */ + old_fs_e = res.fs_e; + req.old_dir = res.inode_nr; + + /* See if 'name2' (new name) exists. Get dir inode */ + if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) r = err_code; + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = NULL; + lookup_req.flags = EAT_PATH_OPAQUE; + + /* Request lookup */ + r = lookup(&lookup_req, &res); + + /* If a directory file has to be removed the following conditions have to met: + * - The directory must not be the root of a mounted file system + * - The directory must not be anybody's root/working directory + */ + if (r == OK && ((res.fmode & I_TYPE) == I_DIRECTORY)) { + /* Can't remove a root directory */ + if (res.inode_nr == ROOT_INODE) return EBUSY; + + /* Can't remove anybody's working directory */ + if ((vp = find_vnode(res.fs_e, res.inode_nr)) != + NIL_VNODE) { + /* Check directories */ + for (rfp = &fproc[INIT_PROC_NR + 1]; rfp < &fproc[NR_PROCS]; + rfp++) { + if (rfp->fp_pid != PID_FREE && + (rfp->fp_wd == vp || rfp->fp_rd == vp)) + return(EBUSY); + } + } + } + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = new_name; + lookup_req.flags = LAST_DIR; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + /* Remeber inode number and FS endpoint */ + new_fs_e = res.fs_e; + req.new_dir = res.inode_nr; + + /* Both parent directories must be on the same device. */ + if (old_fs_e != new_fs_e) return EXDEV; + + /* Send actual rename request */ + req.fs_e = old_fs_e; + req.uid = fp->fp_effuid; + req.gid = fp->fp_effgid; + req.old_name = &old_name[0]; + req.new_name = &new_name[0]; + + /* Issue request */ + return req_rename(&req); +} + + +/*===========================================================================* + * do_truncate * + *===========================================================================*/ +PUBLIC int do_truncate() +{ +/* truncate_inode() 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 trunc_req req; + struct lookup_req lookup_req; + struct node_details res; + int r; + + if (fetch_name(m_in.m2_p1, m_in.m2_i1, M1) != OK) return err_code; + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = NULL; + lookup_req.flags = EAT_PATH; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + /* Check whether the file is in use or not */ + vp = find_vnode(res.fs_e, res.inode_nr); + + /* Fill in request message fields.*/ + req.fs_e = res.fs_e; + req.length = m_in.m2_l1; + req.inode_nr = res.inode_nr; + req.uid = fp->fp_effuid; + req.gid = fp->fp_effgid; + + /* Issue request */ + if ((r = req_trunc(&req)) != OK) return r; + + /* Change vnode's size if found */ + if (vp != NIL_VNODE) + vp->v_size = m_in.m2_l1; + + return OK; +} + + + +/*===========================================================================* + * do_ftruncate * + *===========================================================================*/ +PUBLIC int do_ftruncate() +{ +/* As with do_truncate(), truncate_inode() does the actual work. */ + int r; + struct filp *rfilp; + struct ftrunc_req req; + + if ( (rfilp = get_filp(m_in.m2_i1)) == NIL_FILP) + return err_code; + if ( (rfilp->filp_vno->v_mode & I_TYPE) != I_REGULAR) + return EINVAL; + + /* Fill in FS request */ + req.fs_e = rfilp->filp_vno->v_fs_e; + req.inode_nr = rfilp->filp_vno->v_inode_nr; + req.start = m_in.m2_l1; + req.end = 0; /* Indicate trunc in fs_freesp_trunc */ + + /* Issue request */ + if ((r = req_ftrunc(&req)) != OK) return r; + + rfilp->filp_vno->v_size = m_in.m2_l1; + return OK; +} + +/*===========================================================================* + * do_slink * + *===========================================================================*/ +PUBLIC int do_slink() +{ +/* Perform the symlink(name1, name2) system call. */ + char string[NAME_MAX]; /* last component of the new dir's path name */ + struct slink_req req; + struct lookup_req lookup_req; + struct node_details res; + int r; + + if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) + return(err_code); + + if (m_in.name1_length <= 1 || m_in.name1_length >= _MIN_BLOCK_SIZE) + return(ENAMETOOLONG); + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = string; + lookup_req.flags = LAST_DIR; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + /* Fill in request message */ + req.fs_e = res.fs_e; + req.parent_dir = res.inode_nr; + req.uid = fp->fp_effuid; + req.gid = fp->fp_effgid; + req.lastc = string; + req.who_e = who_e; + req.path_addr = m_in.name1; + req.path_length = m_in.name1_length - 1; + + /* Issue request */ + return req_slink(&req); +} + +/*===========================================================================* + * do_rdlink * + *===========================================================================*/ +PUBLIC int do_rdlink() +{ +/* Perform the readlink(name, buf) system call. */ + int copylen; + struct rdlink_req req; + struct lookup_req lookup_req; + struct node_details res; + int r; + + copylen = m_in.m1_i2; + if(copylen < 0) return EINVAL; + + if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = NULL; + lookup_req.flags = EAT_PATH_OPAQUE; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + /* Fill in request message */ + req.fs_e = res.fs_e; + req.inode_nr = res.inode_nr; + req.uid = fp->fp_effuid; + req.gid = fp->fp_effgid; + req.who_e = who_e; + req.path_buffer = m_in.name2; + req.max_length = copylen; + + /* Issue request */ + return req_rdlink(&req); +} + + + diff --git a/servers/fs/lock.c b/servers/vfs/lock.c similarity index 95% rename from servers/fs/lock.c rename to servers/vfs/lock.c index 737f88a9b..d8e93cb49 100644 --- a/servers/fs/lock.c +++ b/servers/vfs/lock.c @@ -11,10 +11,11 @@ #include #include "file.h" #include "fproc.h" -#include "inode.h" #include "lock.h" #include "param.h" +#include "vnode.h" + /*===========================================================================* * lock_op * *===========================================================================*/ @@ -42,7 +43,7 @@ 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_ino->i_mode & I_TYPE) != I_REGULAR) return(EINVAL); + if ( (f->filp_vno->v_mode & I_TYPE) != I_REGULAR) 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); @@ -50,7 +51,7 @@ int req; /* either F_SETLK or F_SETLKW */ switch (flock.l_whence) { case SEEK_SET: first = 0; break; case SEEK_CUR: first = f->filp_pos; break; - case SEEK_END: first = f->filp_ino->i_size; break; + case SEEK_END: first = f->filp_vno->v_size; break; default: return(EINVAL); } /* Check for overflow. */ @@ -70,7 +71,7 @@ int req; /* either F_SETLK or F_SETLKW */ if (empty == (struct file_lock *) 0) empty = flp; continue; /* 0 means unused slot */ } - if (flp->lock_inode != f->filp_ino) continue; /* different file */ + 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; @@ -118,7 +119,7 @@ int req; /* either F_SETLK or F_SETLKW */ flp2 = &file_lock[i]; flp2->lock_type = flp->lock_type; flp2->lock_pid = flp->lock_pid; - flp2->lock_inode = flp->lock_inode; + flp2->lock_vnode = flp->lock_vnode; flp2->lock_first = last + 1; flp2->lock_last = flp->lock_last; flp->lock_last = first - 1; @@ -152,7 +153,7 @@ int req; /* either F_SETLK or F_SETLKW */ if (empty == (struct file_lock *) 0) return(ENOLCK); /* table full */ empty->lock_type = ltype; empty->lock_pid = fp->fp_pid; - empty->lock_inode = f->filp_ino; + empty->lock_vnode = f->filp_vno; empty->lock_first = first; empty->lock_last = last; nr_locks++; diff --git a/servers/vfs/lock.h b/servers/vfs/lock.h new file mode 100644 index 000000000..e4453a7a3 --- /dev/null +++ b/servers/vfs/lock.h @@ -0,0 +1,10 @@ +/* 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]; diff --git a/servers/fs/main.c b/servers/vfs/main.c similarity index 73% rename from servers/fs/main.c rename to servers/vfs/main.c index 59c9dfcba..200e48d1b 100644 --- a/servers/fs/main.c +++ b/servers/vfs/main.c @@ -3,13 +3,13 @@ * replies. * * The entry points into this file are: - * main: main program of the File System + * 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) */ -struct super_block; /* proto.h needs to know this */ - #include "fs.h" #include #include @@ -26,12 +26,13 @@ struct super_block; /* proto.h needs to know this */ #include #include #include -#include "buf.h" #include "file.h" #include "fproc.h" -#include "inode.h" #include "param.h" -#include "super.h" + +#include +#include "vmnt.h" +#include "vnode.h" #if ENABLE_SYSCALL_STATS EXTERN unsigned long calls_stats[NCALLS]; @@ -42,6 +43,7 @@ FORWARD _PROTOTYPE( void get_work, (void) ); FORWARD _PROTOTYPE( void init_root, (void) ); FORWARD _PROTOTYPE( void service_pm, (void) ); + /*===========================================================================* * main * *===========================================================================*/ @@ -55,6 +57,7 @@ PUBLIC int main() fs_init(); + /* This is the main loop that gets work, processes it, and sends replies. */ while (TRUE) { get_work(); /* sets who and call_nr */ @@ -96,7 +99,7 @@ PUBLIC int main() default: /* Call the internal function that does the work. */ if (call_nr < 0 || call_nr >= NCALLS) { - error = ENOSYS; + error = SUSPEND; /* Not supposed to happen. */ printf("FS, warning illegal %d system call by %d\n", call_nr, who_e); @@ -114,9 +117,7 @@ PUBLIC int main() /* Copy the results back to the user and send reply. */ if (error != SUSPEND) { reply(who_e, error); } - if (rdahed_inode != NIL_INODE) { - read_ahead(); /* do block read ahead */ - } + } } return(OK); /* shouldn't come here */ @@ -179,32 +180,6 @@ PRIVATE void get_work() } } -/*===========================================================================* - * buf_pool * - *===========================================================================*/ -PRIVATE void buf_pool(void) -{ -/* Initialize the buffer pool. */ - - register struct buf *bp; - - bufs_in_use = 0; - front = &buf[0]; - rear = &buf[NR_BUFS - 1]; - - for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) { - bp->b_blocknr = NO_BLOCK; - bp->b_dev = NO_DEV; - bp->b_next = bp + 1; - bp->b_prev = bp - 1; - } - buf[0].b_prev = NIL_BUF; - buf[NR_BUFS - 1].b_next = NIL_BUF; - - for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) bp->b_hash = bp->b_next; - buf_hash[0] = front; - -} /*===========================================================================* * reply * @@ -217,7 +192,7 @@ int result; /* result of the call (usually OK or error #) */ int s; m_out.reply_type = result; s = send(whom, &m_out); - if (s != OK) printf("FS: couldn't send reply %d to %d: %d\n", + if (s != OK) printf("VFS: couldn't send reply %d to %d: %d\n", result, whom, s); } @@ -232,6 +207,10 @@ PRIVATE void fs_init() message mess; int s; + /* Clear endpoint field */ + last_login_fs_e = 0; + mount_m_in.m1_p3 = 0; + /* 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. @@ -254,22 +233,25 @@ PRIVATE void fs_init() } while (TRUE); /* continue until process NONE */ mess.m_type = OK; /* tell PM that we succeeded */ - s=send(PM_PROC_NR, &mess); /* send synchronization message */ + s = send(PM_PROC_NR, &mess); /* send synchronization message */ /* All process table entries have been set. Continue with FS initialization. * Certain relations must hold for the file system to work at all. Some * extra block_size requirements are checked at super-block-read-in time. */ if (OPEN_MAX > 127) panic(__FILE__,"OPEN_MAX > 127", NO_NUM); + /* if (NR_BUFS < 6) panic(__FILE__,"NR_BUFS < 6", NO_NUM); if (V1_INODE_SIZE != 32) panic(__FILE__,"V1 inode size != 32", NO_NUM); if (V2_INODE_SIZE != 64) panic(__FILE__,"V2 inode size != 64", NO_NUM); - + if (OPEN_MAX > 8 * sizeof(long)) + panic(__FILE__,"Too few bits in fp_cloexec", NO_NUM); + */ + /* The following initializations are needed to let dev_opcl succeed .*/ fp = (struct fproc *) NULL; who_e = who_p = FS_PROC_NR; - buf_pool(); /* initialize buffer pool */ build_dmap(); /* build device table and map boot driver */ init_root(); /* init root device and load super block */ init_select(); /* init select() structures */ @@ -278,10 +260,10 @@ PRIVATE void fs_init() for (rfp=&fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { FD_ZERO(&(rfp->fp_filp_inuse)); if (rfp->fp_pid != PID_FREE) { - rip = get_inode(root_dev, ROOT_INODE); - dup_inode(rip); - rfp->fp_rootdir = rip; - rfp->fp_workdir = rip; + + rfp->fp_rd = get_vnode(ROOT_FS_E, ROOT_INODE); + rfp->fp_wd = get_vnode(ROOT_FS_E, ROOT_INODE); + } else rfp->fp_endpoint = NONE; } } @@ -291,42 +273,96 @@ PRIVATE void fs_init() *===========================================================================*/ PRIVATE void init_root() { - int bad; - register struct super_block *sp; - register struct inode *rip = NIL_INODE; - int s; - + struct vmnt *vmp; + struct vnode *root_node; + struct dmap *dp; + message m; + int r = OK; + struct readsuper_req sreq; + struct readsuper_res sres; + /* Open the root device. */ root_dev = DEV_IMGRD; - if ((s=dev_open(root_dev, FS_PROC_NR, R_BIT|W_BIT)) != OK) - panic(__FILE__,"Cannot open root device", s); - -#if ENABLE_CACHE2 - /* The RAM disk is a second level block cache while not otherwise used. */ - init_cache2(ram_size); -#endif - - /* Initialize the super_block table. */ - for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) - sp->s_dev = NO_DEV; - - /* Read in super_block for the root file system. */ - sp = &super_block[0]; - sp->s_dev = root_dev; - - /* Check super_block for consistency. */ - bad = (read_super(sp) != OK); - if (!bad) { - rip = get_inode(root_dev, ROOT_INODE); /* inode for root dir */ - if ( (rip->i_mode & I_TYPE) != I_DIRECTORY || rip->i_nlinks < 3) bad++; + ROOT_FS_E = MFS_PROC_NR; + + /* Wait FS login message */ + if (last_login_fs_e != ROOT_FS_E) { + printf("VFS: Waiting for login from FS_e %d\n", ROOT_FS_E); + /* Wait FS login message */ + if (receive(ROOT_FS_E, &m) != OK) { + printf("VFS: Error receiving login request from FS_e %d\n", + ROOT_FS_E); + panic(__FILE__, "Error receiving login request from root filesystem\n", ROOT_FS_E); + } + if (m.m_type != FS_READY) { + printf("VFS: Invalid login request from FS_e %d\n", + ROOT_FS_E); + panic(__FILE__, "Error receiving login request from root filesystem\n", ROOT_FS_E); + } + printf("VFS: FS_e %d logged in\n", ROOT_FS_E); + } + last_login_fs_e = 0; + + /* 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()) == NIL_VNODE) { + panic(__FILE__,"Cannot get free vnode", r); + } + + /* Get driver process' endpoint */ + dp = &dmap[(root_dev >> MAJOR) & BYTE]; + if (dp->dmap_driver == NONE) { + panic(__FILE__,"No driver for root device", r); } - if (bad) panic(__FILE__,"Invalid root file system", NO_NUM); - sp->s_imount = rip; - dup_inode(rip); - sp->s_isup = rip; - sp->s_rd_only = 0; - return; + /* Open the device the file system lives on. */ + if ((r = dev_open(root_dev, ROOT_FS_E, (R_BIT|W_BIT))) != OK) + panic(__FILE__,"Cannot open root device", r); + + + /* Request for reading superblock and root inode */ + sreq.fs_e = ROOT_FS_E; + sreq.readonly = 0; + sreq.boottime = boottime; + sreq.driver_e = dp->dmap_driver; + sreq.dev = root_dev; + sreq.slink_storage = user_fullpath; + sreq.isroot = 1; + + /* Issue request */ + if ((r = req_readsuper(&sreq, &sres)) != OK) { + dev_close(root_dev); + panic(__FILE__,"Cannot read superblock from root", r); + } + + /* Fill in root node's fields */ + root_node->v_fs_e = sres.fs_e; + root_node->v_inode_nr = sres.inode_nr; + root_node->v_mode = sres.fmode; + root_node->v_size = sres.fsize; + root_node->v_sdev = NO_DEV; + root_node->v_count = 1; + + /* Fill in max file size and blocksize for the vmnt */ + vmp->m_fs_e = sres.fs_e; + vmp->m_dev = root_dev; + vmp->m_block_size = sres.blocksize; + vmp->m_max_file_size = sres.maxsize; + vmp->m_driver_e = dp->dmap_driver; + 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 mounted on itself */ + vmp->m_mounted_on = root_node; + vmp->m_root_node = root_node; } /*===========================================================================* @@ -335,6 +371,7 @@ PRIVATE void init_root() PRIVATE void service_pm() { int r, call; + struct vmnt *vmp; message m; /* Ask PM for work until there is nothing left to do */ @@ -344,7 +381,7 @@ PRIVATE void service_pm() r= sendrec(PM_PROC_NR, &m); if (r != OK) { - panic("fs", "service_pm: sendrec failed", r); + panic("VFS", "service_pm: sendrec failed", r); } if (m.m_type == PM_IDLE) { break; @@ -353,8 +390,13 @@ PRIVATE void service_pm() switch(call) { case PM_STIME: - boottime= m.PM_STIME_TIME; - + boottime = m.PM_STIME_TIME; + + /* Send new time for all FS processes */ + for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) { + if (vmp->m_fs_e) + req_stime(vmp->m_fs_e, boottime); + } /* No need to report status to PM */ break; case PM_SETSID: @@ -445,7 +487,8 @@ PRIVATE void service_pm() break; default: - panic("fs", "service_pm: unknown call", m.m_type); + panic("VFS", "service_pm: unknown call", m.m_type); } } } + diff --git a/servers/fs/misc.c b/servers/vfs/misc.c similarity index 64% rename from servers/fs/misc.c rename to servers/vfs/misc.c index bc2a81966..7ad28ca57 100644 --- a/servers/fs/misc.c +++ b/servers/vfs/misc.c @@ -7,12 +7,12 @@ * 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 MM has performed a FORK system call + * do_reboot: sync disks and prepare for shutdown + * do_fork: adjust the tables after MM has performed a FORK system call * do_exec: handle files with FD_CLOEXEC on after MM has done an EXEC * do_exit: a process has exited; note that in the tables - * pm_setgid: set group ids for some process - * pm_setuid: set user ids for some process + * 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 @@ -28,12 +28,13 @@ #include #include #include -#include "buf.h" #include "file.h" #include "fproc.h" -#include "inode.h" #include "param.h" -#include "super.h" + +#include +#include "vnode.h" +#include "vmnt.h" #define CORE_NAME "core" #define CORE_MODE 0777 /* mode to use on core image files */ @@ -43,14 +44,17 @@ 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)); +*/ #define FP_EXITING 1 + /*===========================================================================* * do_getsysinfo * *===========================================================================*/ @@ -140,6 +144,8 @@ PUBLIC int do_dup() return(m_in.fd2); } + + /*===========================================================================* * do_fcntl * *===========================================================================*/ @@ -149,11 +155,17 @@ PUBLIC int do_fcntl() register struct filp *f; int new_fd, r, fl; + long cloexec_mask; /* bit map for the FD_CLOEXEC flag */ + long clo_value; /* FD_CLOEXEC flag in proper position */ struct filp *dummy; + struct ftrunc_req req; /* Is the file descriptor valid? */ - if ((f = get_filp(m_in.fd)) == NIL_FILP) return(err_code); - + if ((f = get_filp(m_in.fd)) == NIL_FILP) { +/*printf("VFSfcntl: invalid filedesc %d\n", m_in.fd); */ + return(err_code); + } + switch (m_in.request) { case F_DUPFD: /* This replaces the old dup() system call. */ @@ -203,7 +215,7 @@ PUBLIC int do_fcntl() signed long offset; /* Check if it's a regular file. */ - if((f->filp_ino->i_mode & I_TYPE) != I_REGULAR) { + if((f->filp_vno->v_mode & I_TYPE) != I_REGULAR) { return EINVAL; } @@ -220,7 +232,7 @@ PUBLIC int do_fcntl() switch(flock_arg.l_whence) { case SEEK_SET: start = 0; if(offset < 0) return EINVAL; break; case SEEK_CUR: start = f->filp_pos; break; - case SEEK_END: start = f->filp_ino->i_size; break; + case SEEK_END: start = f->filp_vno->v_size; break; default: return EINVAL; } @@ -233,11 +245,19 @@ PUBLIC int do_fcntl() if(end <= start) { return EINVAL; } - r = freesp_inode(f->filp_ino, start, end); - } else { - r = truncate_inode(f->filp_ino, start); + } + else { + end = 0; } - return r; + + /* Fill in FS request */ + req.fs_e = f->filp_vno->v_fs_e; + req.inode_nr = f->filp_vno->v_inode_nr; + req.start = start; + req.end = end; + + /* Issue request */ + return req_ftrunc(&req); } default: @@ -245,28 +265,20 @@ PUBLIC int do_fcntl() } } + /*===========================================================================* * do_sync * *===========================================================================*/ PUBLIC int do_sync() { -/* Perform the sync() system call. Flush all the tables. - * The order in which the various tables are flushed is critical. The - * blocks must be flushed last, since rw_inode() leaves its results in - * the block cache. - */ - register struct inode *rip; - register struct buf *bp; - - /* Write all the dirty inodes to the disk. */ - for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++) - if (rip->i_count > 0 && rip->i_dirt == DIRTY) rw_inode(rip, WRITING); - - /* Write all the dirty blocks to the disk, one drive at a time. */ - for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) - if (bp->b_dev != NO_DEV && bp->b_dirt == DIRTY) flushall(bp->b_dev); - - return(OK); /* sync() can't fail */ + struct vmnt *vmp; + for (vmp = &vmnt[1]; vmp < &vmnt[NR_MNTS]; ++vmp) { + if (vmp->m_dev != NO_DEV) { + /* Send sync request */ + req_sync(vmp->m_fs_e); + } + } + return OK; } /*===========================================================================* @@ -288,8 +300,8 @@ PUBLIC void pm_reboot() { /* Perform the FS side of the reboot call. */ int i; - struct super_block *sp; - struct inode dummy; + struct vnode vdummy; + struct vmnt *vmp; /* Do exit processing for all leftover processes and servers, * but don't actually exit them (if they were really gone, PM @@ -302,22 +314,21 @@ PUBLIC void pm_reboot() /* The root file system is mounted onto itself, which keeps it from being * unmounted. Pull an inode out of thin air and put the root on it. */ - put_inode(super_block[0].s_imount); - super_block[0].s_imount= &dummy; - dummy.i_count = 2; /* expect one "put" */ + + put_vnode(vmnt[0].m_mounted_on); + vmnt[0].m_mounted_on = &vdummy; + vmnt[0].m_root_node = &vdummy; + vdummy.v_count = 1; /* 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. */ for (i= 0; i < NR_SUPERS; i++) { /* Unmount at least one. */ - for (sp= &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) { - if (sp->s_dev != NO_DEV) (void) unmount(sp->s_dev); + for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) { + if (vmp->m_dev != NO_DEV) (void) unmount(vmp->m_dev); } } - - /* Sync any unwritten buffers. */ - do_sync(); } /*===========================================================================* @@ -331,7 +342,7 @@ 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. + * system uses the same slot numbers as the kernel. Only MM makes this call. */ register struct fproc *cp; @@ -375,8 +386,8 @@ int cpid; /* Child process id */ cp->fp_execced = 0; /* Record the fact that both root and working dir have another user. */ - dup_inode(cp->fp_rootdir); - dup_inode(cp->fp_workdir); + dup_vnode(cp->fp_rd); + dup_vnode(cp->fp_wd); } /*===========================================================================* @@ -387,7 +398,7 @@ PRIVATE void free_proc(struct fproc *exiter, int flags) int i, task; register struct fproc *rfp; register struct filp *rfilp; - register struct inode *rip; + register struct vnode *vp; dev_t dev; fp = exiter; /* get_filp() needs 'fp' */ @@ -405,11 +416,11 @@ PRIVATE void free_proc(struct fproc *exiter, int flags) } /* Release root and working directories. */ - put_inode(fp->fp_rootdir); - put_inode(fp->fp_workdir); - fp->fp_rootdir = NIL_INODE; - fp->fp_workdir = NIL_INODE; - + put_vnode(fp->fp_rd); + put_vnode(fp->fp_wd); + fp->fp_rd = NIL_VNODE; + fp->fp_wd = NIL_VNODE; + /* 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 @@ -440,9 +451,9 @@ PRIVATE void free_proc(struct fproc *exiter, int flags) for (i = 0; i < OPEN_MAX; i++) { if ((rfilp = rfp->fp_filp[i]) == NIL_FILP) continue; if (rfilp->filp_mode == FILP_CLOSED) continue; - rip = rfilp->filp_ino; - if ((rip->i_mode & I_TYPE) != I_CHAR_SPECIAL) continue; - if ((dev_t) rip->i_zone[0] != dev) continue; + vp = rfilp->filp_vno; + if ((vp->v_mode & I_TYPE) != I_CHAR_SPECIAL) continue; + if ((dev_t) vp->v_sdev != dev) continue; dev_close(dev); rfilp->filp_mode = FILP_CLOSED; } @@ -504,7 +515,6 @@ int ruid; tfp->fp_realuid = ruid; } - /*===========================================================================* * do_svrctl * *===========================================================================*/ @@ -562,7 +572,6 @@ PUBLIC int do_svrctl() } } - /*===========================================================================* * pm_dumpcore * *===========================================================================*/ @@ -571,267 +580,15 @@ int proc_e; struct mem_map *seg_ptr; { int r, proc_s; - - r= dumpcore(proc_e, seg_ptr); - + /* Terminate the process */ okendpt(proc_e, &proc_s); free_proc(&fproc[proc_s], FP_EXITING); - - return r; -} - -/*===========================================================================* - * dumpcore * - *===========================================================================*/ -PRIVATE int dumpcore(proc_e, seg_ptr) -int proc_e; -struct mem_map *seg_ptr; -{ - int r, seg, proc_s, exists; - mode_t omode; - vir_bytes len; - off_t off, seg_off; - long trace_off, trace_data; - struct fproc *rfp; - struct inode *rip, *ldirp; - struct mem_map segs[NR_LOCAL_SEGS]; - - 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? */ - - /* We need the equivalent of - * open(CORE_NAME, O_WRONLY|O_CREAT|O_TRUNC|O_NONBLOCK, CORE_MODE) - */ - - /* Create a new inode by calling new_node(). */ - omode = I_REGULAR | (CORE_MODE & ALL_MODES & rfp->fp_umask); - rip = new_node(&ldirp, CORE_NAME, omode, NO_ZONE, 0, NULL); - r = err_code; - put_inode(ldirp); - exists= (r == EEXIST); - if (r != OK && r != EEXIST) return(r); /* error */ - - /* Only do the normal open code if we didn't just create the file. */ - if (exists) { - /* Check protections. */ - r = forbidden(rip, W_BIT); - if (r != OK) - { - put_inode(rip); - return r; - } - - /* Make sure it is a regular file */ - switch (rip->i_mode & I_TYPE) { - case I_REGULAR: - break; - - case I_DIRECTORY: - /* Directories may be read but not written. */ - r = EISDIR; - break; - - case I_CHAR_SPECIAL: - case I_BLOCK_SPECIAL: - case I_NAMED_PIPE: - r = EPERM; - break; - } - - if (r != OK) - { - put_inode(rip); - return r; - } - - /* Truncate the file */ - truncate_inode(rip, 0); - wipe_inode(rip); - /* Send the inode from the inode cache to the - * block cache, so it gets written on the next - * cache flush. - */ - rw_inode(rip, WRITING); - } - - /* Copy segments from PM */ - r= sys_datacopy(PM_PROC_NR, (vir_bytes)seg_ptr, - SELF, (vir_bytes)segs, sizeof(segs)); - if (r != OK) panic(__FILE__, "dumpcore: cannot copy segment info", r); - - off= 0; - r= write_bytes(rip, off, (char *)segs, sizeof(segs)); - if (r != OK) - { - put_inode(rip); - return r; - } - off += sizeof(segs); - - /* Write out the whole kernel process table entry to get the regs. */ - for (trace_off= 0;; trace_off += sizeof(long)) - { - r= sys_trace(T_GETUSER, proc_e, trace_off, &trace_data); - if (r != OK) - { - printf("dumpcore pid %d: sys_trace failed " - "at offset %ld: %d\n", - rfp->fp_pid, trace_off, r); - break; - } - r= write_bytes(rip, off, (char *)&trace_data, - sizeof(trace_data)); - if (r != OK) - { - put_inode(rip); - return r; - } - off += sizeof(trace_data); - } - - /* Loop through segments and write the segments themselves out. */ - for (seg = 0; seg < NR_LOCAL_SEGS; seg++) { - len= segs[seg].mem_len << CLICK_SHIFT; - seg_off= segs[seg].mem_vir << CLICK_SHIFT; - r= write_seg(rip, off, proc_e, seg, seg_off, len); - if (r != OK) - { - put_inode(rip); - return r; - } - off += len; - } - - rip->i_size= off; - rip->i_dirt = DIRTY; - - put_inode(rip); + + printf("VFSdumpcore: not implemented\n"); return OK; } -/*===========================================================================* - * write_bytes * - *===========================================================================*/ -PRIVATE int write_bytes(rip, off, buf, bytes) -struct inode *rip; /* inode descriptor to read from */ -off_t off; /* offset in file */ -char *buf; -size_t bytes; /* how much is to be transferred? */ -{ - int block_size; - off_t n, o, b_off; - block_t b; - struct buf *bp; - - block_size= rip->i_sp->s_block_size; - for (o= off - (off % block_size); o < off+bytes; o += block_size) - { - if (o < off) - b_off= off-o; - else - b_off= 0; - n= block_size-b_off; - if (o+b_off+n > off+bytes) - n= off+bytes-(o+b_off); - - b = read_map(rip, o); - - if (b == NO_BLOCK) { - /* Writing to a nonexistent block. Create and enter - * in inode. - */ - if ((bp= new_block(rip, o)) == NIL_BUF) - return(err_code); - } - else - { - /* Just read the block, no need to optimize for - * writing entire blocks. - */ - bp = get_block(rip->i_dev, b, NORMAL); - } - - if (n != block_size && o >= rip->i_size && b_off == 0) { - zero_block(bp); - } - - /* Copy a chunk from user space to the block buffer. */ - memcpy((bp->b_data+b_off), buf, n); - bp->b_dirt = DIRTY; - if (b_off + n == block_size) - put_block(bp, FULL_DATA_BLOCK); - else - put_block(bp, PARTIAL_DATA_BLOCK); - - buf += n; - } - - return OK; -} - -/*===========================================================================* - * write_seg * - *===========================================================================*/ -PRIVATE int write_seg(rip, off, proc_e, seg, seg_off, seg_bytes) -struct inode *rip; /* inode descriptor to read from */ -off_t off; /* offset in file */ -int proc_e; /* process number (endpoint) */ -int seg; /* T, D, or S */ -off_t seg_off; /* Offset in segment */ -phys_bytes seg_bytes; /* how much is to be transferred? */ -{ - int r, block_size, fl; - off_t n, o, b_off; - block_t b; - struct buf *bp; - - block_size= rip->i_sp->s_block_size; - for (o= off - (off % block_size); o < off+seg_bytes; o += block_size) - { - if (o < off) - b_off= off-o; - else - b_off= 0; - n= block_size-b_off; - if (o+b_off+n > off+seg_bytes) - n= off+seg_bytes-(o+b_off); - - b = read_map(rip, o); - if (b == NO_BLOCK) { - /* Writing to a nonexistent block. Create and enter in inode.*/ - if ((bp= new_block(rip, o)) == NIL_BUF) - return(err_code); - } else { - /* Normally an existing block to be partially overwritten is - * first read in. However, a full block need not be read in. - * If it is already in the cache, acquire it, otherwise just - * acquire a free buffer. - */ - fl = (n == block_size ? NO_READ : NORMAL); - bp = get_block(rip->i_dev, b, fl); - } - - if (n != block_size && o >= rip->i_size && b_off == 0) { - zero_block(bp); - } - - /* Copy a chunk from user space to the block buffer. */ - r = sys_vircopy(proc_e, seg, (phys_bytes) seg_off, - FS_PROC_NR, D, (phys_bytes) (bp->b_data+b_off), - (phys_bytes) n); - bp->b_dirt = DIRTY; - fl = (b_off + n == block_size ? FULL_DATA_BLOCK : PARTIAL_DATA_BLOCK); - put_block(bp, fl); - - seg_off += n; - } - - return OK; -} diff --git a/servers/vfs/mount.c b/servers/vfs/mount.c new file mode 100644 index 000000000..fd59686f1 --- /dev/null +++ b/servers/vfs/mount.c @@ -0,0 +1,602 @@ +/* This file performs the MOUNT and UMOUNT system calls. + * + * The entry points into this file are + * do_mount: perform the MOUNT system call + * do_umount: perform the UMOUNT system call + * + * Changes for VFS: + * Jul 2006 (Balazs Gerofi) + */ + +#include "fs.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "file.h" +#include "fproc.h" +#include "param.h" + +#include +#include "vnode.h" +#include "vmnt.h" + +/* Allow the root to be replaced before the first 'real' mount. */ +PRIVATE int allow_newroot = 1; + +FORWARD _PROTOTYPE( dev_t name_to_dev, (void) ); +FORWARD _PROTOTYPE( int fs_exit, (endpoint_t fs_e) ); +FORWARD _PROTOTYPE( int mount_fs, (endpoint_t fs_e) ); + +/*===========================================================================* + * do_fslogin * + *===========================================================================*/ +PUBLIC int do_fslogin() +{ + /* Login before mount request */ + if ((unsigned long)mount_m_in.m1_p3 != who_e) { + last_login_fs_e = who_e; +printf("VFS: FS_e %d logged in\n", last_login_fs_e); + return SUSPEND; + } + /* Login after a suspended mount */ + else { + /* Copy back original mount request message */ + m_in = mount_m_in; + + /* Set up last login FS */ + last_login_fs_e = who_e; + + /* Set up endpoint and call nr */ + who_e = m_in.m_source; + who_p = _ENDPOINT_P(who_e); + call_nr = m_in.m_type; + fp = &fproc[who_p]; /* pointer to proc table struct */ + super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); /* su? */ + + +printf("VFS: FS_e %d logged in. Mount WAKEN UP\n", (unsigned int)m_in.m1_p3); + return do_mount(); + } +} + +/*===========================================================================* + * do_mount * + *===========================================================================*/ +PUBLIC int do_mount() +{ + endpoint_t fs_e; + int r; + + /* FS process' endpoint number */ + fs_e = (unsigned long)m_in.m1_p3; + + /* Do the actual job */ + r = mount_fs(fs_e); + + /* If not OK and not suspended, bring down FS proc.. */ + if (r != OK && r != SUSPEND) { + /* Ask RS to bring down FS */ + if (-1 == fs_exit(fs_e)) { + printf("VFSmount: WARNING: couldn't stop FS endp: %d\n", fs_e); + } + } + + return r; +} + + +/*===========================================================================* + * mount * + *===========================================================================*/ +PRIVATE int mount_fs(endpoint_t fs_e) +{ +/* Perform the mount(name, mfile, rd_only) system call. */ + int rdir, mdir; /* TRUE iff {root|mount} file is dir */ + int i, r, found; + struct fproc *tfp; + struct dmap *dp; + dev_t dev; + message m; + struct vnode *vp, *root_node, *mounted_on, *bspec; + struct vmnt *vmp, *vmp2; + struct mountpoint_req mreq; + struct node_details res; + struct readsuper_req sreq; + struct readsuper_res sres; + struct lookup_req lookup_req; + + /* Only the super-user may do MOUNT. */ + if (!super_user) return(EPERM); + + /* If FS not yet logged in, save message and suspend mount */ + if (last_login_fs_e != fs_e) { + mount_m_in = m_in; + printf("VFS: FS_e %d not yet logged in. Mount SUSPENDED\n", fs_e); + return SUSPEND; + } + + /* Mount request got after FS login or + * FS login arrived after a suspended mount */ + last_login_fs_e = 0; + + /* Clear endpoint field */ + mount_m_in.m1_p3 = 0; + + /* If 'name' is not for a block special file, return error. */ + if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); + + /* Get free vnode for the mountpoint */ + if ((mounted_on = get_free_vnode()) == NIL_VNODE) { + printf("VFSmount: not free vnode available\n"); + return ENFILE; + } + + /* Mark it as used so that we won't find the same for the root_node */ + mounted_on->v_count = 1; + + /* Convert name to device number */ + if ((dev = name_to_dev()) == NO_DEV) 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_count > 0 && bspec->v_sdev == dev) { + /* Found, sync the buffer cache */ +printf("VFSmount: minor is opened as a block spec file, sync cache...\n"); + req_sync(bspec->v_fs_e); + break; + /* Note: there are probably some blocks in the FS process' buffer + * cache which contain data on this minor, although they will be + * purged since the handling moves to the new FS process (if + * everything goes well with the mount...) + */ + } + } + /* Didn't find? */ + if (bspec == &vnode[NR_VNODES] && bspec->v_sdev != dev) + bspec = NULL; + + /* Scan vmnt table to see if dev already mounted, if not, + * find a free slot.*/ + found = FALSE; + vmp = NIL_VMNT; + 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. */ + if (vmp->m_mounted_on != vmp->m_root_node || + vmp->m_mounted_on == fproc[FS_PROC_NR].fp_rd) { + /* Normally, m_mounted_on refers to the mount point. For a root + * filesystem, m_mounted_on is equal to the root vnode. We assume + * that the root of FS is always the real root. If the two + * vnodes are different or if the root of FS is equal two the + * root of the filesystem we found, we found a filesystem that + * is in use. */ + mounted_on->v_count = 0; + return EBUSY; /* already mounted */ + } + + if (root_dev == vmp->m_dev) + panic("fs", "inconsistency remounting old root", NO_NUM); + + /* 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); + } + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = NULL; + lookup_req.flags = EAT_PATH; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + /* Fill in request message fields.*/ + mreq.fs_e = res.fs_e; + mreq.inode_nr = res.inode_nr; + mreq.uid = fp->fp_effuid; + mreq.gid = fp->fp_effgid; + + /* Issue request */ + if ((r = req_mountpoint(&mreq, &res)) != OK) return r; + + mounted_on->v_fs_e = res.fs_e; + mounted_on->v_inode_nr = res.inode_nr; + mounted_on->v_mode = res.fmode; + mounted_on->v_size = res.fsize; + mounted_on->v_sdev = NO_DEV; + mounted_on->v_count = 1; + + /* Find the vmnt for the vnode */ + if ( (vmp2 = find_vmnt(mounted_on->v_fs_e)) == NIL_VMNT) + printf("VFS: vmnt not found by mount()\n"); + mounted_on->v_vmnt = vmp2; + mounted_on->v_dev = vmp2->m_dev; + + /* Get the root inode of the mounted file system. */ + root_node = vmp->m_root_node; + + /* File types may not conflict. */ + if (r == OK) { + mdir = ((mounted_on->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 mount point. */ + if (r != OK) { + put_vnode(mounted_on); + + return(r); + } + + /* Nothing else can go wrong. Perform the mount. */ + put_vnode(vmp->m_mounted_on); + vmp->m_mounted_on = mounted_on; + vmp->m_flags = m_in.rd_only; + allow_newroot = 0; /* The root is now fixed */ + + return(OK); + } + + /* We'll need a vnode for the root inode, check whether there is one */ + if ((root_node = get_free_vnode()) == NIL_VNODE) { + printf("VFSmount: no free vnode available\n"); + return ENFILE; + } + + /* Set it back to zero so that if st goes wrong it won't be kept in use */ + mounted_on->v_count = 0; + + /* Fetch the name of the mountpoint */ + if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) { + return(err_code); + } + + /* Get driver process' endpoint */ + dp = &dmap[(dev >> MAJOR) & BYTE]; + if (dp->dmap_driver == NONE) { + printf("VFSmount: no driver for dev %x\n", dev); + return(EINVAL); + } + + /* Open the device the file system lives on. */ + if (dev_open(dev, fs_e, m_in.rd_only ? R_BIT : (R_BIT|W_BIT)) != OK) { + return(EINVAL); + } + +printf("VFSmount: FS_e: %d mp: %s D_e: %d\n", fs_e, user_fullpath, + dp->dmap_driver); + + /* Request for reading superblock and root inode */ + sreq.fs_e = fs_e; + sreq.readonly = m_in.rd_only; + sreq.boottime = boottime; + sreq.driver_e = dp->dmap_driver; + sreq.dev = dev; + sreq.slink_storage = user_fullpath; + + if (!strcmp(user_fullpath, "/")) sreq.isroot = 1; + else sreq.isroot = 0; + + /* Issue request */ + if ((r = req_readsuper(&sreq, &sres)) != OK) { +printf("VFSmount: reading superb error dev: %d\n", dev); + dev_close(dev); + return r; + } + + /* Fill in root node's fields */ + root_node->v_fs_e = sres.fs_e; + root_node->v_inode_nr = sres.inode_nr; + root_node->v_mode = sres.fmode; + root_node->v_size = sres.fsize; + root_node->v_sdev = NO_DEV; + root_node->v_count = 1; + + /* Fill in max file size and blocksize for the vmnt */ + vmp->m_fs_e = sres.fs_e; + vmp->m_dev = dev; + vmp->m_block_size = sres.blocksize; + vmp->m_max_file_size = sres.maxsize; + vmp->m_flags = m_in.rd_only; + vmp->m_driver_e = dp->dmap_driver; + + /* Root node is indeed on the partition */ + root_node->v_vmnt = vmp; + root_node->v_dev = vmp->m_dev; + + if (strcmp(user_fullpath, "/") == 0 && allow_newroot) { + printf("Replacing root\n"); + + /* Superblock and root node already read. + * Nothing else can go wrong. Perform the mount. */ + vmp->m_root_node = root_node; + vmp->m_mounted_on = root_node; + root_dev = dev; + ROOT_FS_E = fs_e; + + /* Replace all root and working directories */ + for (i= 0, tfp= fproc; ifp_pid == PID_FREE) + continue; + + if (tfp->fp_rd == NULL) + panic("fs", "do_mount: null rootdir", i); + put_vnode(tfp->fp_rd); + dup_vnode(root_node); + tfp->fp_rd = root_node; + + if (tfp->fp_wd == NULL) + panic("fs", "do_mount: null workdir", i); + put_vnode(tfp->fp_wd); + dup_vnode(root_node); + tfp->fp_wd = root_node; + } + + return(OK); + } + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = NULL; + lookup_req.flags = EAT_PATH; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) { + put_vnode(root_node); + return r; + } + + /* Fill in request fields.*/ + mreq.fs_e = res.fs_e; + mreq.inode_nr = res.inode_nr; + mreq.uid = fp->fp_effuid; + mreq.gid = fp->fp_effgid; + + /* Issue request */ + if ((r = req_mountpoint(&mreq, &res)) != OK) { + put_vnode(root_node); + return r; + } + + /* Fill in vnode's fields */ + mounted_on->v_fs_e = res.fs_e; + mounted_on->v_inode_nr = res.inode_nr; + mounted_on->v_mode = res.fmode; + mounted_on->v_size = res.fsize; + mounted_on->v_sdev = NO_DEV; + mounted_on->v_count = 1; + + /* Find the vmnt for the vnode */ + if ( (vmp2 = find_vmnt(mounted_on->v_fs_e)) == NIL_VMNT) + printf("VFS: vmnt not found by mount()"); + mounted_on->v_vmnt = vmp2; + mounted_on->v_dev = vmp2->m_dev; + + /* File types may not conflict. */ + if (r == OK) { + mdir = ((mounted_on->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) { + put_vnode(mounted_on); + put_vnode(root_node); + + vmp->m_dev = NO_DEV; + dev_close(dev); + return(r); + } + + /* Nothing else can go wrong. Perform the mount. */ + vmp->m_mounted_on = mounted_on; + vmp->m_root_node = root_node; + + /* The root is now fixed */ + allow_newroot = 0; + + /* There was a block spec file open, and it should be handled by the + * new FS proc now */ + if (bspec) { + printf("VFSmount: moving opened block spec to new FS_e: %d...\n", fs_e); + bspec->v_bfs_e = fs_e; + } + return(OK); +} + +/*===========================================================================* + * do_umount * + *===========================================================================*/ +PUBLIC int do_umount() +{ +/* Perform the umount(name) system call. */ + dev_t dev; + + /* Only the super-user may do UMOUNT. */ + if (!super_user) return(EPERM); + + /* If 'name' is not for a block special file, return error. */ + if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); + if ( (dev = name_to_dev()) == NO_DEV) return(err_code); + + return(unmount(dev)); +} + + +/*===========================================================================* + * unmount * + *===========================================================================*/ +PUBLIC int unmount(dev) +Dev_t dev; +{ + struct vnode *vp; + struct vmnt *vmp; + struct dmap *dp; + int count, r; + int fs_e; + + /* Find vmnt */ + for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) { + if (vmp->m_dev == dev) break; + else if (vmp == &vmnt[NR_MNTS]) + return EINVAL; + } + + /* 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_count > 0 && vp->v_dev == dev) { + count += vp->v_count; + } + } + + if (count > 1) { + printf("VFSunmount: %d filesystem is busy count: %d\n", dev, count); + return(EBUSY); /* can't umount a busy file system */ + } + + /* Request FS the unmount */ + if ((r = req_unmount(vmp->m_fs_e)) != OK) return r; + + /* Close the device the file system lives on. */ + dev_close(dev); + + /* Is there a block special file that was handled by that partition? */ + for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; vp++) { + if ((vp->v_mode & I_TYPE) == I_BLOCK_SPECIAL && + 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("VFSblock_spec_open: driver not found for device %d\n", + dev); + /* What should be done, panic??? */ + continue; + } + + printf("VFSunmount: moving block spec %d to root FS\n", dev); + vp->v_bfs_e = ROOT_FS_E; + vp->v_blocksize = _MIN_BLOCK_SIZE; + + /* Send the driver endpoint (even if it is known already...) */ + if ((r = req_newdriver(vp->v_bfs_e, vp->v_sdev, dp->dmap_driver)) + != OK) { + printf("VFSunmount: error sending driver endpoint for block spec\n"); + } + } + } + + /* Root device is mounted on itself */ + if (vmp->m_root_node != vmp->m_mounted_on) { + put_vnode(vmp->m_mounted_on); + vmp->m_root_node->v_count = 0; + } + else { + vmp->m_mounted_on->v_count--; + } + + fs_e = vmp->m_fs_e; + + vmp->m_root_node = NIL_VNODE; + vmp->m_mounted_on = NIL_VNODE; + vmp->m_dev = NO_DEV; + vmp->m_fs_e = 0; + vmp->m_driver_e = 0; + + /* Ask RS to bring down FS */ + if (-1 == fs_exit(fs_e)) { + printf("VFSunmount: WARNING: couldn't stop FS endp: %d\n", fs_e); + } + + printf("VFSunmount: DEV: %d unmounted\n", dev); + return(OK); +} + +/*===========================================================================* + * name_to_dev * + *===========================================================================*/ +PRIVATE dev_t name_to_dev() +{ +/* Convert the block special file 'path' to a device number. If 'path' + * is not a block special file, return error code in 'err_code'. */ + struct lookup_req lookup_req; + struct node_details res; + int r; + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = NULL; + lookup_req.flags = EAT_PATH; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + if ((res.fmode & I_TYPE) != I_BLOCK_SPECIAL) { + err_code = ENOTBLK; + return NO_DEV; + } + + return res.dev; +} + + +/*===========================================================================* + * fs_exit * + *===========================================================================*/ +PRIVATE int fs_exit(fs_e) +endpoint_t fs_e; +{ +/* Build a message for stoping a FS server and ask RS to do it */ + message m; + pid_t fs_pid; + int r; + + /* Don't need to stop the one in the bootimage */ + if (fs_e == MFS_PROC_NR) return OK; + + /* Get pid for this endpoint */ + if (-1 == (fs_pid = getnpid(fs_e))) { + printf("VFS: couldn't find pid for fs_e: %d\n", fs_e); + return -1; + } + +printf("VFSfs_exit: Bringing down FS endp: %d (pid: %d)\n", fs_e, fs_pid); + + /* Ask RS to stop process */ + m.RS_PID = fs_pid; + if (OK != (r = _taskcall(RS_PROC_NR, RS_DOWN, &m))) { + printf("VFSfs_exit: couldn't bring FS down pid: %d\n", fs_pid); + return -1; + } + + return OK; +} + + diff --git a/servers/vfs/open.c b/servers/vfs/open.c new file mode 100644 index 000000000..4220ebce6 --- /dev/null +++ b/servers/vfs/open.c @@ -0,0 +1,528 @@ +/* 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 + * + * Changes for VFS: + * Jul 2006 (Balazs Gerofi) + */ + +#include "fs.h" +#include +#include +#include +#include +#include +#include +#include "file.h" +#include "fproc.h" +#include "lock.h" +#include "param.h" +#include + +#include +#include "vnode.h" +#include "vmnt.h" + +#define offset m2_l1 + + +PRIVATE char mode_map[] = {R_BIT, W_BIT, R_BIT|W_BIT, 0}; + +FORWARD _PROTOTYPE( int common_open, (int oflags, mode_t omode) ); +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; + + 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); + 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; + + /* 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); + } else { + r = fetch_name(m_in.name, m_in.name_length, M3); + } + + if (r != OK) { + return(err_code); /* name was bad */ + } + r = common_open(m_in.mode, create_mode); + return(r); +} + +/*===========================================================================* + * common_open * + *===========================================================================*/ +PRIVATE int common_open(register int oflags, mode_t omode) +{ +/* Common code from do_creat and do_open. */ + int r, b, found; + dev_t dev; + mode_t bits; + off_t pos; + struct dmap *dp; + struct filp *fil_ptr, *filp2; + struct vnode *vp, *vp2; + struct vmnt *vmp; + char lastc[NAME_MAX]; + + /* Request and response structures */ + struct lookup_req lookup_req; + struct open_req req; + struct node_details res; + + /* Remap the bottom two bits of oflags. */ + bits = (mode_t) mode_map[oflags & O_ACCMODE]; + + /* See if file descriptor and filp slots are available. */ + if ((r = get_fd(0, bits, &m_in.fd, &fil_ptr)) != OK) return(r); + + /* See if a free vnode is available */ + if ((vp = get_free_vnode()) == NIL_VNODE) { + printf("VFS: no vnode available!\n"); + return err_code; + } + + /* If O_CREATE, set umask */ + if (oflags & O_CREAT) { + omode = I_REGULAR | (omode & ALL_MODES & fp->fp_umask); + } + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = lastc; + lookup_req.flags = oflags&O_CREAT ? (oflags&O_EXCL ? LAST_DIR : + LAST_DIR_EATSYM) : EAT_PATH; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + /* Lookup was okay, fill in request fields for + * the actual open request. */ + req.inode_nr = res.inode_nr; + req.fs_e = res.fs_e; + req.oflags = oflags; + req.omode = omode; + req.lastc = lastc; + req.uid = fp->fp_effuid; + req.gid = fp->fp_effgid; + + /* Issue request */ + if ((r = req_open(&req, &res)) != OK) return r; + + /* Check whether the vnode is already in use */ + if ((vp2 = find_vnode(res.fs_e, res.inode_nr)) != NIL_VNODE) { + vp = vp2; + vp->v_size = res.fsize;; /* In case of trunc... */ + vp->v_count++; + } + /* Otherwise use the free one */ + else { + vp->v_fs_e = res.fs_e; + if ( (vmp = find_vmnt(vp->v_fs_e)) == NIL_VMNT) + printf("VFS: vmnt not found by open()"); + + vp->v_dev = vmp->m_dev; + vp->v_inode_nr = res.inode_nr; + vp->v_mode = res.fmode; + vp->v_size = res.fsize; + vp->v_sdev = res.dev; + vp->v_count = 1; + vp->v_vmnt = vmp; + vp->v_index = res.inode_index; + } + + /* 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_flags = oflags; + fil_ptr->filp_vno = vp; + + switch (vp->v_mode & I_TYPE) { + case I_CHAR_SPECIAL: + /* Invoke the driver for special processing. */ + r = dev_open(vp->v_sdev, who_e, bits | (oflags & ~O_ACCMODE)); + break; + + case I_BLOCK_SPECIAL: + /* Invoke the driver for special processing. */ + r = dev_open(vp->v_sdev, who_e, bits | (oflags & ~O_ACCMODE)); + + /* Check whether the device is mounted or not */ + found = 0; + if (r == OK) { +printf("VFS: opening block spec %d, handled by ", vp->v_sdev); + for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) { + if (vmp->m_dev == vp->v_sdev) { + found = 1; + break; + } + } + + /* Who is going to be responsible for this device? */ + if (found) { +printf("the FS of the mounted partition...\n"); + vp->v_bfs_e = vmp->m_fs_e; + vp->v_blocksize - vmp->m_block_size; + } + else { /* To be handled in the root FS proc if not mounted */ +printf("the root FS...\n"); + vp->v_bfs_e = ROOT_FS_E; + vp->v_blocksize = _MIN_BLOCK_SIZE; + } + + /* Get the driver endpoint of the block spec device */ + dp = &dmap[(vp->v_sdev >> MAJOR) & BYTE]; + if (dp->dmap_driver == NONE) { + printf("VFSblock_spec_open: driver not found for device %d\n", + vp->v_sdev); + r = EINVAL; + break; + } + + /* Send the driver endpoint (even if it is known already...) */ + if ((r = req_newdriver(vp->v_bfs_e, vp->v_sdev, dp->dmap_driver)) + != OK) { + printf("VFSblock_spec_open: error sending driver endpoint\n"); + } + } + break; + + case I_NAMED_PIPE: + vp->v_pipe = I_PIPE; + oflags |= O_APPEND; /* force append mode */ + fil_ptr->filp_flags = oflags; + 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); + fil_ptr->filp_count = 0; /* don't find self */ + if ((filp2 = find_filp(vp, b)) != NIL_FILP) { + /* Co-reader or writer found. Use it.*/ + fp->fp_filp[m_in.fd] = 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 + * by eatpath in FS, not knowing that we were going to + * use an existing filp entry. Correct this error. + */ + put_vnode(vp); + } else { + /* Nobody else found. Restore filp. */ + fil_ptr->filp_count = 1; + if (fil_ptr->filp_mode == R_BIT) + fil_ptr->filp_pos = vp->v_pipe_rd_pos; + else + fil_ptr->filp_pos = vp->v_pipe_wr_pos; + } + } + break; + } + + /* If error, release inode. */ + if (r != OK) { + if (r == SUSPEND) return(r); /* Oops, just suspended */ + fp->fp_filp[m_in.fd] = NIL_FILP; + FD_CLR(m_in.fd, &fp->fp_filp_inuse); + fil_ptr->filp_count= 0; + put_vnode(vp); + fil_ptr->filp_vno = NIL_VNODE; + return(r); + } + + return(m_in.fd); +} + + + +/*===========================================================================* + * pipe_open * + *===========================================================================*/ +PRIVATE int pipe_open(register struct vnode *vp, register mode_t bits, + register 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)) { + printf("pipe opened RW.\n"); + return ENXIO; + } + + if (find_filp(vp, bits & W_BIT ? R_BIT : W_BIT) == NIL_FILP) { + if (oflags & O_NONBLOCK) { + if (bits & W_BIT) return(ENXIO); + } else { + suspend(XPOPEN); /* suspend caller */ + 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; + char lastc[NAME_MAX]; /* last component of the path */ + struct mknod_req req; + struct lookup_req lookup_req; + struct node_details res; + int r; + + /* 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)) return(EPERM); + if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); + bits = (mode_bits & I_TYPE) | (mode_bits & ALL_MODES & fp->fp_umask); + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = lastc; + lookup_req.flags = LAST_DIR; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + /* Lookup was okay, fill in request fields for the actual + * mknod request. */ + req.fs_e = res.fs_e; + req.inode_nr = res.inode_nr; + req.rmode = bits; + req.dev = m_in.mk_z0; + req.lastc = lastc; + req.uid = fp->fp_effuid; + req.gid = fp->fp_effgid; + + /* Issue request */ + return req_mknod(&req); +} + + +/*===========================================================================* + * do_mkdir * + *===========================================================================*/ +PUBLIC int do_mkdir() +{ +/* Perform the mkdir(name, mode) system call. */ + mode_t bits; /* mode bits for the new inode */ + char lastc[NAME_MAX]; + struct mkdir_req req; + struct lookup_req lookup_req; + struct node_details res; + int r; + +/*printf("VFS: mkdir() START:");*/ + if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); + + bits = I_DIRECTORY | (m_in.mode & RWX_MODES & fp->fp_umask); + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = lastc; + lookup_req.flags = LAST_DIR; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + /* Lookup was okay, fill in request message fields + * for the actual mknod request. */ + req.fs_e = res.fs_e; + req.d_inode_nr = res.inode_nr; + req.rmode = bits; + req.lastc = lastc; + req.uid = fp->fp_effuid; + req.gid = fp->fp_effgid; + + /* Issue request */ + return req_mkdir(&req); +} + + + + +/*===========================================================================* + * do_lseek * + *===========================================================================*/ +PUBLIC int do_lseek() +{ +/* Perform the lseek(ls_fd, offset, whence) system call. */ + register struct filp *rfilp; + register off_t pos; + struct node_req req; + int r; + + /* Check to see if the file descriptor is valid. */ + if ( (rfilp = get_filp(m_in.ls_fd)) == NIL_FILP) return(err_code); + + /* No lseek on pipes. */ + if (rfilp->filp_vno->v_pipe == I_PIPE) return(ESPIPE); + + /* The value of 'whence' determines the start position to use. */ + switch(m_in.whence) { + case SEEK_SET: pos = 0; break; + case SEEK_CUR: pos = rfilp->filp_pos; break; + case SEEK_END: pos = rfilp->filp_vno->v_size; break; + default: return(EINVAL); + } + + /* Check for overflow. */ + if (((long)m_in.offset > 0) && ((long)(pos + m_in.offset) < (long)pos)) + return(EINVAL); + if (((long)m_in.offset < 0) && ((long)(pos + m_in.offset) > (long)pos)) + return(EINVAL); + pos = pos + m_in.offset; + + if (pos != rfilp->filp_pos) { /* Inhibit read ahead request */ + /* Fill in request message */ + req.fs_e = rfilp->filp_vno->v_fs_e; + req.inode_nr = rfilp->filp_vno->v_inode_nr; + + /* Issue request */ + if ((r = req_inhibread(&req)) != OK) return r; + } + + rfilp->filp_pos = pos; + m_out.reply_l1 = pos; /* insert the long into the output message */ + return(OK); +} + + +/*===========================================================================* + * 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 rw, mode_word, lock_count; + dev_t dev; + + /* First locate the vnode that belongs to the file descriptor. */ + if ( (rfilp = get_filp2(rfp, fd_nr)) == NIL_FILP) return(err_code); + + vp = rfilp->filp_vno; + + if (rfilp->filp_count - 1 == 0 && rfilp->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) { + /* Invalidate cache entries unless special is mounted + * or ROOT + */ + req_sync(vp->v_bfs_e); +printf("VFSclose: closed block spec %d\n", dev); + } + /* Do any special processing on device close. */ + dev_close(dev); + } + } + + /* If the inode being closed is a pipe, release everyone hanging on it. */ + if (vp->v_pipe == I_PIPE) { + rw = (rfilp->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 (--rfilp->filp_count == 0) { + if (vp->v_pipe == I_PIPE && vp->v_count > 1) { + /* Save the file position in the v-node in case needed later. + * The read and write positions are saved separately. + */ + if (rfilp->filp_mode == R_BIT) + vp->v_pipe_rd_pos = rfilp->filp_pos; + else + vp->v_pipe_wr_pos = rfilp->filp_pos; + + } + else { + /* Otherwise zero the pipe position fields */ + vp->v_pipe_rd_pos = 0; + vp->v_pipe_wr_pos = 0; + } + + put_vnode(rfilp->filp_vno); + } + + FD_CLR(fd_nr, &rfp->fp_cloexec_set); + rfp->fp_filp[fd_nr] = NIL_FILP; + 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 < lock_count) lock_revive(); /* lock released */ + return(OK); +} + + diff --git a/servers/vfs/param.h b/servers/vfs/param.h new file mode 100644 index 000000000..2ea84d819 --- /dev/null +++ b/servers/vfs/param.h @@ -0,0 +1,65 @@ +/* The following names are synonyms for the variables in the input message. */ +#define acc_time m2_l1 +#define addr m1_i3 +#define buffer m1_p1 +#define child_endpt m1_i2 +#define co_mode m1_i1 +#define eff_grp_id m1_i3 +#define eff_user_id m1_i3 +#define erki m1_p1 +#define fd m1_i1 +#define fd2 m1_i2 +#define ioflags m1_i3 +#define group m1_i3 +#define real_grp_id m1_i2 +#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 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 parent_endpt m1_i1 +#define pathname m3_ca1 +#define pid m1_i3 +#define ENDPT m1_i1 +#define ctl_req m4_l1 +#define driver_nr m4_l2 +#define dev_nr m4_l3 +#define dev_style m4_l4 +#define m_force m4_l5 +#define rd_only m1_i3 +#define real_user_id m1_i2 +#define request m1_i2 +#define sig m1_i2 +#define endpt1 m1_i1 +#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 pm_stime m1_i1 +#define info_what m1_i1 +#define info_where m1_p1 + +/* The following names are synonyms for the variables in the output message. */ +#define reply_type m_type +#define reply_l1 m2_l1 +#define reply_i1 m1_i1 +#define reply_i2 m1_i2 +#define reply_t1 m4_l1 +#define reply_t2 m4_l2 +#define reply_t3 m4_l3 +#define reply_t4 m4_l4 +#define reply_t5 m4_l5 diff --git a/servers/vfs/path.c b/servers/vfs/path.c new file mode 100644 index 000000000..86e060829 --- /dev/null +++ b/servers/vfs/path.c @@ -0,0 +1,152 @@ + +/* 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. + * + * Jul 2006 (Balazs Gerofi) + */ + +#include "fs.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include "fproc.h" +#include "vmnt.h" +#include "vnode.h" +#include "param.h" + + +/*===========================================================================* + * lookup * + *===========================================================================*/ +PUBLIC int lookup(lookup_req, node) +lookup_req_t *lookup_req; +node_details_t *node; +{ + struct vmnt *vmp; + struct vnode *start_node; + struct lookup_res res; + int r, symloop = 0; + int cum_path_processed = 0; + + /* Make a copy of the request so that the original values will be kept */ + struct lookup_req req = *lookup_req; + char *fullpath = lookup_req->path; + + /* Empty (start) path? */ + if (fullpath[0] == '\0') { + return ENOENT; + } + + /* Set user and group ids according to the system call */ + req.uid = (call_nr == ACCESS ? fp->fp_realuid : fp->fp_effuid); + req.gid = (call_nr == ACCESS ? fp->fp_realgid : fp->fp_effgid); + + /* Set the starting directories inode number and FS endpoint */ + start_node = (fullpath[0] == '/' ? fp->fp_rd : fp->fp_wd); + req.start_dir = start_node->v_inode_nr; + req.fs_e = start_node->v_fs_e; + + /* Is the process' root directory on the same partition?, + * if so, set the chroot directory too. */ + if (fp->fp_rd->v_dev == fp->fp_wd->v_dev) + req.root_dir = fp->fp_rd->v_inode_nr; + else + req.root_dir = 0; + + req.symloop = symloop; + + /* Issue the request */ + r = req_lookup(&req, &res); + + /* While the response is related to mount control set the + * new requests respectively */ + while (r == EENTERMOUNT || r == ELEAVEMOUNT || r == ESYMLINK) { + + /* If a symlink was encountered during the lookup the + * new path has been copied back and the number of characters + * processed has been started over. */ + if (r == ESYMLINK || res.symloop > symloop) { + /* The link's content is copied back to the user_fullpath + * array. Use it as the path argument from now on... */ + fullpath = user_fullpath; + cum_path_processed = res.char_processed; + } + else { + /* Otherwise, cumulate the characters already processsed from + * the path */ + cum_path_processed += res.char_processed; + } + + /* Remember the current value of the symloop counter */ + symloop = res.symloop; + + /* Symlink encountered with absolute path */ + if (r == ESYMLINK) { + start_node = fp->fp_rd; + } + /* Entering a new partition */ + else if (r == EENTERMOUNT) { + start_node = 0; + /* Start node is now the mounted partition's root node */ + for (vmp = &vmnt[0]; vmp != &vmnt[NR_MNTS]; ++vmp) { + if (vmp->m_mounted_on->v_inode_nr == res.inode_nr + && vmp->m_mounted_on->v_fs_e == res.fs_e) { + start_node = vmp->m_root_node; + break; + } + } + if (!start_node) { + printf("VFSlookup: mounted partition couldn't be found\n"); + return ENOENT; + } + + } + /* Climbing up mount */ + else { + /* Find the vmnt that represents the partition on + * which we "climb up". */ + if ((vmp = find_vmnt(res.fs_e)) == NIL_VMNT) { + printf("VFS: couldn't find vmnt during the climbup!\n"); + return ENOENT; + } + /* Start node is the vnode on which the partition is + * mounted */ + start_node = vmp->m_mounted_on; + } + /* Fill in the request fields */ + req.start_dir = start_node->v_inode_nr; + req.fs_e = start_node->v_fs_e; + + /* Is the process' root directory on the same partition?*/ + if (start_node->v_dev == fp->fp_rd->v_dev) + req.root_dir = fp->fp_rd->v_inode_nr; + else + req.root_dir = 0; + + /* Fill in the current path name */ + req.path = &fullpath[cum_path_processed]; + req.symloop = symloop; + + /* Issue the request */ + r = req_lookup(&req, &res); + } + + /* If success, fill in response fields */ + if (OK == r) { + node->inode_nr = res.inode_nr; + node->fmode = res.fmode; + node->fsize = res.fsize; + node->dev = res.dev; + node->fs_e = res.fs_e; + } + + return r; +} + diff --git a/servers/fs/pipe.c b/servers/vfs/pipe.c similarity index 82% rename from servers/fs/pipe.c rename to servers/vfs/pipe.c index 57a8ebb1c..430f97f61 100644 --- a/servers/fs/pipe.c +++ b/servers/vfs/pipe.c @@ -13,6 +13,9 @@ * 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 + * + * Changes for VFS: + * Jul 2006 (Balazs Gerofi) */ #include "fs.h" @@ -26,11 +29,16 @@ #include #include "file.h" #include "fproc.h" -#include "inode.h" #include "param.h" -#include "super.h" #include "select.h" +#include +#include "vnode.h" +#include "vmnt.h" + + + + /*===========================================================================* * do_pipe * *===========================================================================*/ @@ -39,11 +47,22 @@ PUBLIC int do_pipe() /* Perform the pipe(fil_des) system call. */ register struct fproc *rfp; - register struct inode *rip; int r; struct filp *fil_ptr0, *fil_ptr1; int fil_des[2]; /* reply goes here */ + struct vnode *vp; + struct vmnt *vmp; + + struct pipe_req req; + struct node_details res; + + /* See if a free vnode is available */ + if ( (vp = get_free_vnode()) == NIL_VNODE) { + printf("VFS: no vnode available!\n"); + return err_code; + } + /* Acquire two file descriptors. */ rfp = fp; if ( (r = get_fd(0, R_BIT, &fil_des[0], &fil_ptr0)) != OK) return(r); @@ -51,49 +70,69 @@ PUBLIC int do_pipe() FD_SET(fil_des[0], &rfp->fp_filp_inuse); fil_ptr0->filp_count = 1; if ( (r = get_fd(0, W_BIT, &fil_des[1], &fil_ptr1)) != OK) { - rfp->fp_filp[fil_des[0]] = NIL_FILP; - FD_CLR(fil_des[0], &rfp->fp_filp_inuse); - fil_ptr0->filp_count = 0; - return(r); + rfp->fp_filp[fil_des[0]] = NIL_FILP; + FD_CLR(fil_des[0], &rfp->fp_filp_inuse); + fil_ptr0->filp_count = 0; + return(r); } rfp->fp_filp[fil_des[1]] = fil_ptr1; FD_SET(fil_des[1], &rfp->fp_filp_inuse); fil_ptr1->filp_count = 1; - /* Make the inode on the pipe device. */ - if ( (rip = alloc_inode(root_dev, I_REGULAR) ) == NIL_INODE) { - rfp->fp_filp[fil_des[0]] = NIL_FILP; - FD_CLR(fil_des[0], &rfp->fp_filp_inuse); - fil_ptr0->filp_count = 0; - rfp->fp_filp[fil_des[1]] = NIL_FILP; - FD_CLR(fil_des[1], &rfp->fp_filp_inuse); - fil_ptr1->filp_count = 0; - return(err_code); + /* Fill in FS request */ + req.fs_e = ROOT_FS_E; + req.uid = fp->fp_effuid; + req.gid = fp->fp_effgid; + + /* Send request */ + r = req_pipe(&req, &res); + + /* Handle error */ + if (r != OK) { + rfp->fp_filp[fil_des[0]] = NIL_FILP; + FD_CLR(fil_des[0], &rfp->fp_filp_inuse); + fil_ptr0->filp_count = 0; + rfp->fp_filp[fil_des[1]] = NIL_FILP; + FD_CLR(fil_des[1], &rfp->fp_filp_inuse); + fil_ptr1->filp_count = 0; + return r; } - if (read_only(rip) != OK) - panic(__FILE__,"pipe device is read only", NO_NUM); - - rip->i_pipe = I_PIPE; - rip->i_mode &= ~I_REGULAR; - rip->i_mode |= I_NAMED_PIPE; /* pipes and FIFOs have this bit set */ - fil_ptr0->filp_ino = rip; + /* Fill in vnode */ + vp->v_fs_e = res.fs_e; + vp->v_inode_nr = res.inode_nr; + vp->v_mode = res.fmode; + vp->v_index = res.inode_index; + vp->v_pipe = I_PIPE; + vp->v_count = 2; /* Double usage */ + vp->v_size = 0; + + if ( (vmp = find_vmnt(vp->v_fs_e)) == NIL_VMNT) { + printf("VFS: vmnt not found by pipe() ==>> USING ROOT VMNT\n"); + vp->v_vmnt = &vmnt[0]; + } + else { + vp->v_vmnt = vmp; + vp->v_dev = vmp->m_dev; + } + + /* Fill in filp objects */ + fil_ptr0->filp_vno = vp; + fil_ptr1->filp_vno = vp; fil_ptr0->filp_flags = O_RDONLY; - dup_inode(rip); /* for double usage */ - fil_ptr1->filp_ino = rip; fil_ptr1->filp_flags = O_WRONLY; - rw_inode(rip, WRITING); /* mark inode as allocated */ + m_out.reply_i1 = fil_des[0]; m_out.reply_i2 = fil_des[1]; - rip->i_update = ATIME | CTIME | MTIME; + return(OK); } /*===========================================================================* * pipe_check * *===========================================================================*/ -PUBLIC int pipe_check(rip, rw_flag, oflags, bytes, position, canwrite, notouch) -register struct inode *rip; /* the inode of the pipe */ +PUBLIC int pipe_check(vp, rw_flag, oflags, bytes, position, canwrite, 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) */ @@ -109,10 +148,10 @@ int notouch; /* check only */ /* If reading, check for empty pipe. */ if (rw_flag == READING) { - if (position >= rip->i_size) { + if (position >= vp->v_size) { /* Process is reading from an empty pipe. */ int r = 0; - if (find_filp(rip, W_BIT) != NIL_FILP) { + if (find_filp(vp, W_BIT) != NIL_FILP) { /* Writer exists */ if (oflags & O_NONBLOCK) { r = EAGAIN; @@ -123,13 +162,13 @@ int notouch; /* check only */ } /* If need be, activate sleeping writers. */ if (susp_count > 0) - release(rip, WRITE, susp_count); + release(vp, WRITE, susp_count); } return(r); } } else { /* Process is writing to a pipe. */ - if (find_filp(rip, R_BIT) == NIL_FILP) { + if (find_filp(vp, R_BIT) == NIL_FILP) { /* Tell kernel to generate a SIGPIPE signal. */ if (!notouch) { sys_kill(fp->fp_endpoint, SIGPIPE); @@ -137,30 +176,31 @@ int notouch; /* check only */ return(EPIPE); } - if (position + bytes > PIPE_SIZE(rip->i_sp->s_block_size)) { + if (position + bytes > PIPE_SIZE(vp->v_vmnt->m_block_size)) { if ((oflags & O_NONBLOCK) - && bytes <= PIPE_SIZE(rip->i_sp->s_block_size)) + && bytes <= PIPE_SIZE(vp->v_vmnt->m_block_size)) { return(EAGAIN); + } else if ((oflags & O_NONBLOCK) - && bytes > PIPE_SIZE(rip->i_sp->s_block_size)) { - if ( (*canwrite = (PIPE_SIZE(rip->i_sp->s_block_size) + && bytes > PIPE_SIZE(vp->v_vmnt->m_block_size)) { + if ( (*canwrite = (PIPE_SIZE(vp->v_vmnt->m_block_size) - position)) > 0) { /* Do a partial write. Need to wakeup reader */ if (!notouch) - release(rip, READ, susp_count); + release(vp, READ, susp_count); return(1); } else { return(EAGAIN); } } - if (bytes > PIPE_SIZE(rip->i_sp->s_block_size)) { - if ((*canwrite = PIPE_SIZE(rip->i_sp->s_block_size) + if (bytes > PIPE_SIZE(vp->v_vmnt->m_block_size)) { + if ((*canwrite = PIPE_SIZE(vp->v_vmnt->m_block_size) - position) > 0) { /* Do a partial write. Need to wakeup reader * since we'll suspend ourself in read_write() */ if (!notouch) - release(rip, READ, susp_count); + release(vp, READ, susp_count); return(1); } } @@ -171,7 +211,7 @@ int notouch; /* check only */ /* Writing to an empty pipe. Search for suspended reader. */ if (position == 0 && !notouch) - release(rip, READ, susp_count); + release(vp, READ, susp_count); } *canwrite = 0; @@ -236,8 +276,8 @@ PUBLIC void unsuspend_by_endpt(int proc_e) /*===========================================================================* * release * *===========================================================================*/ -PUBLIC void release(ip, call_nr, count) -register struct inode *ip; /* inode of pipe */ +PUBLIC void release(vp, call_nr, count) +register struct vnode *vp; /* inode of pipe */ int call_nr; /* READ, WRITE, OPEN or CREAT */ int count; /* max number of processes to release */ { @@ -260,7 +300,7 @@ int count; /* max number of processes to release */ 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_ino != ip) + f->filp_vno != vp) continue; select_callback(f, op); f->filp_pipe_select_ops &= ~op; @@ -272,7 +312,7 @@ int count; /* max number of processes to release */ if (rp->fp_pid != PID_FREE && rp->fp_suspended == SUSPENDED && rp->fp_revived == NOT_REVIVING && (rp->fp_fd & BYTE) == call_nr && - rp->fp_filp[rp->fp_fd>>8]->filp_ino == ip) { + rp->fp_filp[rp->fp_fd>>8]->filp_vno == vp) { revive(rp->fp_endpoint, 0); susp_count--; /* keep track of who is suspended */ if (--count == 0) return; @@ -337,6 +377,7 @@ int returned; /* if hanging on task, how many bytes read */ } } + /*===========================================================================* * do_unpause * *===========================================================================*/ @@ -398,7 +439,7 @@ int proc_nr_e; if (fild < 0 || fild >= OPEN_MAX) panic(__FILE__,"unpause err 2",NO_NUM); f = rfp->fp_filp[fild]; - dev = (dev_t) f->filp_ino->i_zone[0]; /* device hung on */ + dev = (dev_t) f->filp_vno->v_sdev; /* device hung on */ mess.TTY_LINE = (dev >> MINOR) & BYTE; mess.IO_ENDPT = rfp->fp_ioproc; mess.IO_GRANT = (char *) rfp->fp_grant; @@ -424,6 +465,7 @@ int proc_nr_e; return(OK); } + /*===========================================================================* * select_request_pipe * *===========================================================================*/ @@ -432,14 +474,14 @@ PUBLIC int select_request_pipe(struct filp *f, int *ops, int block) int orig_ops, r = 0, err, canwrite; orig_ops = *ops; if ((*ops & (SEL_RD|SEL_ERR))) { - if ((err = pipe_check(f->filp_ino, READING, 0, + if ((err = pipe_check(f->filp_vno, READING, 0, 1, f->filp_pos, &canwrite, 1)) != SUSPEND) r |= SEL_RD; if (err < 0 && err != SUSPEND) r |= SEL_ERR; } if ((*ops & (SEL_WR|SEL_ERR))) { - if ((err = pipe_check(f->filp_ino, WRITING, 0, + if ((err = pipe_check(f->filp_vno, WRITING, 0, 1, f->filp_pos, &canwrite, 1)) != SUSPEND) r |= SEL_WR; if (err < 0 && err != SUSPEND) @@ -462,8 +504,11 @@ PUBLIC int select_request_pipe(struct filp *f, int *ops, int block) PUBLIC int select_match_pipe(struct filp *f) { /* recognize either pipe or named pipe (FIFO) */ - if (f && f->filp_ino && (f->filp_ino->i_mode & I_NAMED_PIPE)) + if (f && f->filp_vno && (f->filp_vno->v_mode & I_NAMED_PIPE)) return 1; return 0; } + + + diff --git a/servers/vfs/protect.c b/servers/vfs/protect.c new file mode 100644 index 000000000..35173a7ad --- /dev/null +++ b/servers/vfs/protect.c @@ -0,0 +1,165 @@ + +/* 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 + * + * Changes for VFS: + * Jul 2006 (Balazs Gerofi) + */ + +#include "fs.h" +#include +#include +#include "file.h" +#include "fproc.h" +#include "param.h" + +#include +#include "vnode.h" +#include "vmnt.h" + + + +/*===========================================================================* + * do_chmod * + *===========================================================================*/ +PUBLIC int do_chmod() +{ + struct filp *flp; + struct chmod_req req; + struct lookup_req lookup_req; + struct node_details res; + int r; + + if (call_nr == CHMOD) { + /* Perform the chmod(name, mode) system call. */ + if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = NULL; + lookup_req.flags = EAT_PATH; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + req.inode_nr = res.inode_nr; + req.fs_e = res.fs_e; + } + else if (call_nr == FCHMOD) { + if (!(flp = get_filp(m_in.m3_i1))) return err_code; + req.inode_nr = flp->filp_vno->v_inode_nr; + req.fs_e = flp->filp_vno->v_fs_e; + } + else panic(__FILE__, "do_chmod called with strange call_nr", call_nr); + + /* Fill in request message fields.*/ + req.uid = fp->fp_effuid; + req.gid = fp->fp_effgid; + req.rmode = m_in.mode; + + /* Issue request */ + return req_chmod(&req); +} + +/*===========================================================================* + * do_chown * + *===========================================================================*/ +PUBLIC int do_chown() +{ + int inode_nr; + int fs_e; + struct filp *flp; + struct chown_req req; + struct lookup_req lookup_req; + struct node_details res; + int r; + + if (call_nr == CHOWN) { + /* Perform the chmod(name, mode) system call. */ + if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = NULL; + lookup_req.flags = EAT_PATH; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + req.inode_nr = res.inode_nr; + req.fs_e = res.fs_e; + } + else if (call_nr == FCHOWN) { + if (!(flp = get_filp(m_in.m1_i1))) return err_code; + req.inode_nr = flp->filp_vno->v_inode_nr; + req.fs_e = flp->filp_vno->v_fs_e; + } + else panic(__FILE__, "do_chmod called with strange call_nr", call_nr); + + /* Fill in request message fields.*/ + req.uid = fp->fp_effuid; + req.gid = fp->fp_effgid; + req.newuid = m_in.owner; + req.newgid = m_in.group; + + /* Issue request */ + return req_chown(&req); +} + + +/*===========================================================================* + * 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. */ + struct access_req req; + struct lookup_req lookup_req; + struct node_details res; + int r; + + /* 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); + + if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = NULL; + lookup_req.flags = EAT_PATH; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + /* Fill in request fields */ + req.fs_e = res.fs_e; + req.amode = m_in.mode; + req.inode_nr = res.inode_nr; + req.uid = fp->fp_realuid; /* real user and group id */ + req.gid = fp->fp_realgid; + + /* Issue request */ + return req_access(&req); +} + diff --git a/servers/vfs/proto.h b/servers/vfs/proto.h new file mode 100644 index 000000000..9928e9731 --- /dev/null +++ b/servers/vfs/proto.h @@ -0,0 +1,224 @@ +/* Function prototypes. */ + +#include "timers.h" +#include "request.h" + +/* Structs used in prototypes must be declared as such first. */ +struct filp; +struct fproc; +struct vmnt; +struct vnode; + +/* device.c */ +_PROTOTYPE( int dev_open, (Dev_t dev, int proc, int flags) ); +_PROTOTYPE( void dev_close, (Dev_t dev) ); +_PROTOTYPE( int dev_bio, (int op, Dev_t dev, int proc, void *buf, + off_t pos, int bytes) ); +_PROTOTYPE( int dev_io, (int op, Dev_t dev, int proc, void *buf, + off_t pos, int bytes, int flags) ); +_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 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 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 dev_up, (int major) ); + +/* dmap.c */ +_PROTOTYPE( int do_devctl, (void) ); +_PROTOTYPE( int fs_devctl, (int req, int dev, int proc_nr_e, int style, + int force) ); +_PROTOTYPE( void build_dmap, (void) ); +_PROTOTYPE( int map_driver, (int major, int proc_nr, int dev_style, + int force) ); +_PROTOTYPE( int dmap_driver_match, (int proc, int major) ); +_PROTOTYPE( void dmap_unmap_by_endpt, (int proc_nr) ); +_PROTOTYPE( void dmap_endpt_up, (int proc_nr) ); + +/* exec.c */ +_PROTOTYPE( int pm_exec, (int proc_e, char *path, vir_bytes path_len, + char *frame, vir_bytes frame_len) ); + +/* filedes.c */ +_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) ); +_PROTOTYPE( struct filp *get_filp2, (struct fproc *rfp, int fild) ); +_PROTOTYPE( int inval_filp, (struct filp *) ); + +/* 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) ); + +/* 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) ); + +/* 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( 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, (int proc_e, struct mem_map *seg_ptr) ); + +/* mount.c */ +_PROTOTYPE( int do_fslogin, (void) ); +_PROTOTYPE( int do_mount, (void) ); +_PROTOTYPE( int do_umount, (void) ); +_PROTOTYPE( int unmount, (Dev_t dev) ); + +/* open.c */ +_PROTOTYPE( int do_close, (void) ); +_PROTOTYPE( int close_fd, (struct fproc *rfp, int fd_nr) ); +_PROTOTYPE( int do_creat, (void) ); +_PROTOTYPE( int do_lseek, (void) ); +_PROTOTYPE( int do_mknod, (void) ); +_PROTOTYPE( int do_mkdir, (void) ); +_PROTOTYPE( int do_open, (void) ); +_PROTOTYPE( int do_slink, (void) ); + +/* path.c */ +_PROTOTYPE( int lookup, (lookup_req_t *request, node_details_t *node) ); + +/* pipe.c */ +_PROTOTYPE( int do_pipe, (void) ); +_PROTOTYPE( int do_unpause, (void) ); +_PROTOTYPE( int unpause, (int proc_nr_e) ); +_PROTOTYPE( int pipe_check, (struct vnode *vp, int rw_flag, + int oflags, int bytes, off_t position, int *canwrite, 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( int select_request_pipe, (struct filp *f, int *ops, int bl) ); +_PROTOTYPE( int select_cancel_pipe, (struct filp *f) ); +_PROTOTYPE( int select_match_pipe, (struct filp *f) ); +_PROTOTYPE( void unsuspend_by_endpt, (int) ); + +/* protect.c */ +_PROTOTYPE( int do_access, (void) ); +_PROTOTYPE( int do_chmod, (void) ); +_PROTOTYPE( int do_chown, (void) ); +_PROTOTYPE( int do_umask, (void) ); + +/* read.c */ +_PROTOTYPE( int do_read, (void) ); +_PROTOTYPE( int read_write, (int rw_flag) ); + +/* request.c */ +_PROTOTYPE( int fs_sendrec, (endpoint_t fs_e, message *reqm) ); +_PROTOTYPE( int req_getnode, (node_req_t *req, node_details_t *res) ); +_PROTOTYPE( int req_putnode, (node_req_t *req) ); +_PROTOTYPE( int req_open, (open_req_t *req, node_details_t *res) ); +_PROTOTYPE( int req_readwrite, (readwrite_req_t *req, + readwrite_res_t *res) ); +_PROTOTYPE( int req_pipe, (pipe_req_t *req, node_details_t *res) ); +_PROTOTYPE( int req_clone_opcl, (clone_opcl_req_t *req, + node_details_t *res) ); +_PROTOTYPE( int req_ftrunc, (ftrunc_req_t *req) ); +_PROTOTYPE( int req_chown, (chown_req_t *req) ); +_PROTOTYPE( int req_chmod, (chmod_req_t *req) ); +_PROTOTYPE( int req_access, (access_req_t *req) ); +_PROTOTYPE( int req_mknod, (mknod_req_t *req) ); +_PROTOTYPE( int req_mkdir, (mkdir_req_t *req) ); +_PROTOTYPE( int req_inhibread, (node_req_t *req) ); +_PROTOTYPE( int req_stat, (stat_req_t *req) ); +_PROTOTYPE( int req_fstat, (stat_req_t *req) ); +_PROTOTYPE( int req_fstatfs, (stat_req_t *req) ); +_PROTOTYPE( int req_unlink, (unlink_req_t *req) ); +_PROTOTYPE( int req_rmdir, (unlink_req_t *req) ); +_PROTOTYPE( int req_utime, (utime_req_t *req) ); +_PROTOTYPE( int req_stime, (endpoint_t fs_e, time_t boottime) ); +_PROTOTYPE( int req_sync, (endpoint_t fs_e) ); +_PROTOTYPE( int req_getdir, (getdir_req_t *req, node_details_t *res) ); +_PROTOTYPE( int req_link, (link_req_t *req) ); +_PROTOTYPE( int req_slink, (slink_req_t *req) ); +_PROTOTYPE( int req_rdlink, (rdlink_req_t *req) ); +_PROTOTYPE( int req_rename, (rename_req_t *req) ); +_PROTOTYPE( int req_mountpoint, (mountpoint_req_t *req, + node_details_t *res) ); +_PROTOTYPE( int req_readsuper, (readsuper_req_t *req, + readsuper_res_t *res) ); +_PROTOTYPE( int req_unmount, (endpoint_t fs_e) ); +_PROTOTYPE( int req_trunc, (trunc_req_t *req) ); +_PROTOTYPE( int req_lookup, (lookup_req_t *req, lookup_res_t *res) ); +_PROTOTYPE( int req_newdriver, (endpoint_t fs_e, Dev_t dev, + endpoint_t driver_e) ); +_PROTOTYPE( int req_breadwrite, (breadwrite_req_t *req, + readwrite_res_t *res) ); + +/* 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_rdlink, (void) ); +_PROTOTYPE( int do_lstat, (void) ); + +/* time.c */ +_PROTOTYPE( int do_stime, (void) ); +_PROTOTYPE( int do_utime, (void) ); + +/* 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 no_sys, (void) ); +_PROTOTYPE( int isokendpt_f, (char *f, int l, int e, int *p, int ft)); +_PROTOTYPE( void panic, (char *who, char *mess, int num) ); + +#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( struct vmnt *get_free_vmnt, (short *index) ); +_PROTOTYPE( struct vmnt *find_vmnt, (int fs_e) ); + +/* vnode.c */ +_PROTOTYPE( struct vnode *get_free_vnode, (void) ); +_PROTOTYPE( struct vnode *find_vnode, (int fs_e, int numb) ); +_PROTOTYPE( void dup_vnode, (struct vnode *vp) ); +_PROTOTYPE( void put_vnode, (struct vnode *vp) ); +_PROTOTYPE( struct vnode *get_vnode, (int fs_e, int inode_nr) ); + +/* write.c */ +_PROTOTYPE( int do_write, (void) ); + +/* select.c */ +_PROTOTYPE( int do_select, (void) ); +_PROTOTYPE( int select_callback, (struct filp *, int ops) ); +_PROTOTYPE( void select_forget, (int fproc) ); +_PROTOTYPE( void select_timeout_check, (timer_t *) ); +_PROTOTYPE( void init_select, (void) ); +_PROTOTYPE( void select_unsuspend_by_endpt, (int proc) ); +_PROTOTYPE( int select_notified, (int major, int minor, int ops) ); + +/* timers.c */ +_PROTOTYPE( void fs_set_timer, (timer_t *tp, int delta, + tmr_func_t watchdog, int arg) ); +_PROTOTYPE( void fs_expire_timers, (clock_t now) ); +_PROTOTYPE( void fs_cancel_timer, (timer_t *tp) ); +_PROTOTYPE( void fs_init_timer, (timer_t *tp) ); + diff --git a/servers/vfs/read.c b/servers/vfs/read.c new file mode 100644 index 000000000..84e3618ef --- /dev/null +++ b/servers/vfs/read.c @@ -0,0 +1,292 @@ +/* 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 + * read_write: actually do the work of READ and WRITE + * + * Changes for VFS: + * Jul 2006 (Balazs Gerofi) + */ + +#include "fs.h" +#include +#include +#include +#include "file.h" +#include "fproc.h" +#include "param.h" +#include + +#include +#include "vnode.h" +#include "vmnt.h" + + +/*===========================================================================* + * do_read * + *===========================================================================*/ +PUBLIC int do_read() +{ + return(read_write(READING)); +} + + +/*===========================================================================* + * read_write * + *===========================================================================*/ +PUBLIC int 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; + register struct vnode *vp; + off_t bytes_left, f_size, position; + unsigned int off, cum_io; + int op, oflags, r, chunk, usr, seg, block_spec, char_spec; + int regular, partial_pipe = 0, partial_cnt = 0; + mode_t mode_word; + struct filp *wf; + phys_bytes p; + struct dmap *dp; + + /* Request and response structures */ + struct readwrite_req req; + struct readwrite_res res; + + /* For block spec files */ + struct breadwrite_req breq; + + /* PM loads segments by putting funny things in other bits of the + * message, indicated by a high bit in fd. */ + if (who_e == PM_PROC_NR && (m_in.fd & _PM_SEG_FLAG)) { + seg = (int) m_in.m1_p2; + usr = (int) m_in.m1_p3; + m_in.fd &= ~(_PM_SEG_FLAG); /* get rid of flag bit */ + } + else { + usr = who_e; /* normal case */ + seg = D; + } + + /* 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)) == NIL_FILP) 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*/ + + /* check if user process has the memory it needs. + * if not, copying will fail later. + * do this after 0-check above because umap doesn't want to map 0 bytes. */ + if ((r = sys_umap(usr, seg, (vir_bytes) m_in.buffer, m_in.nbytes, &p)) != OK) { + printf("VFS: read_write: umap failed for process %d\n", usr); + return r; + } + position = f->filp_pos; + oflags = f->filp_flags; + + vp = f->filp_vno; + f_size = vp->v_size; + + r = OK; + if (vp->v_pipe == I_PIPE) { + /* fp->fp_cum_io_partial is only nonzero when doing partial writes */ + cum_io = fp->fp_cum_io_partial; + } + else { + cum_io = 0; + } + + op = (rw_flag == READING ? DEV_READ : DEV_WRITE); + mode_word = vp->v_mode & I_TYPE; + regular = mode_word == I_REGULAR || mode_word == I_NAMED_PIPE; + + if ((char_spec = (mode_word == I_CHAR_SPECIAL ? 1 : 0))) { + if (vp->v_sdev == NO_DEV) + panic(__FILE__,"read_write tries to read from " + "character device NO_DEV", NO_NUM); + } + + if ((block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 : 0))) { + f_size = ULONG_MAX; + if (vp->v_sdev == NO_DEV) + panic(__FILE__,"read_write tries to read from " + " block device NO_DEV", NO_NUM); + } + + /* Character special files. */ + if (char_spec) { + dev_t dev; + /*dev = (dev_t) f->filp_ino->i_zone[0];*/ + dev = (dev_t) vp->v_sdev; + r = dev_io(op, dev, usr, m_in.buffer, position, m_in.nbytes, oflags); + if (r >= 0) { + cum_io = r; + position += r; + r = OK; + } + } + /* Block special files. */ + else if (block_spec) { + /* Fill in the fields of the request */ + breq.rw_flag = rw_flag; + breq.fs_e = vp->v_bfs_e; + breq.blocksize = vp->v_blocksize; + breq.dev = vp->v_sdev; + breq.user_e = usr; + breq.pos = position; + breq.num_of_bytes = m_in.nbytes; + breq.user_addr = m_in.buffer; + + /* Issue request */ + r = req_breadwrite(&breq, &res); + + position = res.new_pos; + cum_io += res.cum_io; + } + /* Regular files */ + else { + if (rw_flag == WRITING && block_spec == 0) { + /* Check in advance to see if file will grow too big. */ + if (position > vp->v_vmnt->m_max_file_size - m_in.nbytes) + return(EFBIG); + + /* Check for O_APPEND flag. */ + if (oflags & O_APPEND) position = f_size; + } + + /* Pipes are a little different. Check. */ + if (vp->v_pipe == I_PIPE) { + r = pipe_check(vp, rw_flag, oflags, + m_in.nbytes, position, &partial_cnt, 0); + if (r <= 0) return(r); + } + + if (partial_cnt > 0) { + /* So taht we don't need to deal with partial count + * in the FS process */ + m_in.nbytes = MIN(m_in.nbytes, partial_cnt); + partial_pipe = 1; + } + + /* Fill in request structure */ + req.fs_e = vp->v_fs_e; + req.rw_flag = rw_flag; + req.inode_nr = vp->v_inode_nr; + req.user_e = usr; + req.seg = seg; + req.pos = position; + req.num_of_bytes = m_in.nbytes; + req.user_addr = m_in.buffer; + req.inode_index = vp->v_index; + + /* Issue request */ + r = req_readwrite(&req, &res); + + position = res.new_pos; + cum_io += res.cum_io; + } + + /* On write, update file size and access time. */ + if (rw_flag == WRITING) { + if (regular || mode_word == I_DIRECTORY) { + if (position > f_size) vp->v_size = position; + } + } + else { + if (vp->v_pipe == I_PIPE) { + if (position >= vp->v_size) { + /* Reset pipe pointers */ + vp->v_size = 0; + position = 0; + wf = find_filp(vp, W_BIT); + if (wf != NIL_FILP) wf->filp_pos = 0; + } + } + } + + f->filp_pos = position; + + if (r == OK) { + if (partial_pipe) { + partial_pipe = 0; + /* partial write on pipe with */ + /* O_NONBLOCK, return write count */ + if (!(oflags & O_NONBLOCK)) { + fp->fp_cum_io_partial = cum_io; + suspend(XPIPE); /* partial write on pipe with */ + return(SUSPEND); /* nbyte > PIPE_SIZE - non-atomic */ + } + } + fp->fp_cum_io_partial = 0; + return cum_io; + } + + return r; +} + + +/* Original "uncached" code for block spec files */ +#if 0 + else if (block_spec) { + char buf[_MIN_BLOCK_SIZE]; + block_t b; + int bleft = m_in.nbytes; + dev_t dev = vp->v_sdev; + + b = position / _MIN_BLOCK_SIZE; + off = position % _MIN_BLOCK_SIZE; + + while (bleft) { + /* First read the whole block */ + r = dev_bio(DEV_READ, dev, FS_PROC_NR, buf, b * _MIN_BLOCK_SIZE, + _MIN_BLOCK_SIZE); + + if (r != _MIN_BLOCK_SIZE) + break; + + /* How many bytes to copy? */ + chunk = MIN(bleft, _MIN_BLOCK_SIZE - off); + + if (rw_flag == READING) { + /* Copy a chunk from the buffer to user space. */ + r = sys_vircopy(FS_PROC_NR, D, (phys_bytes) (&buf[off]), + usr, seg, (phys_bytes) m_in.buffer, + (phys_bytes) chunk); + } + else { + /* Copy a chunk from user space to the buffer. */ + r = sys_vircopy(usr, seg, (phys_bytes) m_in.buffer, + FS_PROC_NR, D, (phys_bytes) (&buf[off]), + (phys_bytes) chunk); + } + + /* Write back if WRITE */ + if (rw_flag == WRITING) { + r = dev_bio(DEV_WRITE, dev, FS_PROC_NR, buf, + b * _MIN_BLOCK_SIZE, _MIN_BLOCK_SIZE); + + if (r != _MIN_BLOCK_SIZE) + break; + } + + bleft -= chunk; + m_in.buffer += chunk; + + /* 0 offset in the next block */ + b++; + off = 0; + } + + cum_io = m_in.nbytes - bleft; + position += cum_io; + r = OK; + } +#endif + diff --git a/servers/vfs/request.c b/servers/vfs/request.c new file mode 100644 index 000000000..6849fdb45 --- /dev/null +++ b/servers/vfs/request.c @@ -0,0 +1,954 @@ + +/* This file contains the wrapper functions for issueing 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. + * The low-level fs_sendrec handles the recovery mechanism from + * a dead driver and reissues the request. + * + * Sep 2006 (Balazs Gerofi) + */ + +#include "fs.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include "fproc.h" +#include "vmnt.h" +#include "vnode.h" +#include "param.h" + + +/*===========================================================================* + * req_getnode * + *===========================================================================*/ +PUBLIC int req_getnode(req, res) +node_req_t *req; +node_details_t *res; +{ + int r; + message m; + + /* Fill in request message */ + m.m_type = REQ_GETNODE; + m.REQ_INODE_NR = req->inode_nr; + + /* Send/rec request */ + if ((r = fs_sendrec(req->fs_e, &m)) != 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; + res->dev = m.RES_DEV; + + return OK; +} + + +/*===========================================================================* + * req_putnode * + *===========================================================================*/ +PUBLIC int req_putnode(req) +node_req_t *req; +{ + message m; + + /* Fill in request message */ + m.m_type = REQ_PUTNODE; + m.REQ_INODE_NR = req->inode_nr; + + /* Send/rec request */ + return fs_sendrec(req->fs_e, &m); +} + +/*===========================================================================* + * req_open * + *===========================================================================*/ +int req_open(req, res) +open_req_t *req; +node_details_t *res; +{ + int r; + message m; + + /* Fill in request message */ + m.m_type = REQ_OPEN; + m.REQ_INODE_NR = req->inode_nr; + m.REQ_FLAGS = req->oflags; + m.REQ_MODE = req->omode; + m.REQ_UID = req->uid; + m.REQ_GID = req->gid; + m.REQ_PATH = req->lastc; + m.REQ_PATH_LEN = strlen(req->lastc) + 1; + + /* Send/rec request */ + if ((r = fs_sendrec(req->fs_e, &m)) != 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; + res->dev = m.RES_DEV; + res->inode_index = m.RES_INODE_INDEX; + /* For exec */ + res->uid = m.RES_UID; + res->gid = m.RES_GID; + res->ctime = m.RES_CTIME; + + return OK; +} + + +/*===========================================================================* + * req_readwrite * + *===========================================================================*/ +int req_readwrite(req, res) +readwrite_req_t *req; +readwrite_res_t *res; +{ + int r; + message m; + + /* Fill in request message */ + m.m_type = req->rw_flag == READING ? REQ_READ : REQ_WRITE; + m.REQ_FD_INODE_NR = req->inode_nr; + m.REQ_FD_WHO_E = req->user_e; + m.REQ_FD_SEG = req->seg; + m.REQ_FD_POS = req->pos; + m.REQ_FD_NBYTES = req->num_of_bytes; + m.REQ_FD_USER_ADDR = req->user_addr; + m.REQ_FD_INODE_INDEX = req->inode_index; + + /* Send/rec request */ + if ((r = fs_sendrec(req->fs_e, &m)) != OK) return r; + + /* Fill in response structure */ + res->new_pos = m.RES_FD_POS; + res->cum_io = m.RES_FD_CUM_IO; + + return OK; +} + + + +/*===========================================================================* + * req_pipe * + *===========================================================================*/ +PUBLIC int req_pipe(req, res) +pipe_req_t *req; +node_details_t *res; +{ + int r; + message m; + + /* Fill in request message */ + m.m_type = REQ_PIPE; + m.REQ_UID = req->uid; + m.REQ_GID = req->gid; + + /* Send/rec request */ + if ((r = fs_sendrec(req->fs_e, &m)) != 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; + res->dev = m.RES_DEV; + res->inode_index = m.RES_INODE_INDEX; + + return OK; +} + + +/*===========================================================================* + * req_clone_opcl * + *===========================================================================*/ +PUBLIC int req_clone_opcl(req, res) +clone_opcl_req_t *req; +node_details_t *res; +{ + int r; + message m; + + /* Fill in request message */ + m.m_type = REQ_CLONE_OPCL; + m.REQ_DEV = req->dev; + + /* Send/rec request */ + if ((r = fs_sendrec(req->fs_e, &m)) != 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; + res->dev = m.RES_DEV; + res->inode_index = m.RES_INODE_INDEX; + + return OK; +} + + + +/*===========================================================================* + * req_ftrunc * + *===========================================================================*/ +PUBLIC int req_ftrunc(req) +ftrunc_req_t *req; +{ + message m; + + /* Fill in request message */ + m.m_type = REQ_FTRUNC; + m.REQ_FD_INODE_NR = req->inode_nr; + m.REQ_FD_START = req->start; + m.REQ_FD_END = req->end; + + /* Send/rec request */ + return fs_sendrec(req->fs_e, &m); +} + + +/*===========================================================================* + * req_chmod * + *===========================================================================*/ +PUBLIC int req_chmod(req) +chmod_req_t *req; +{ + message m; + + /* Fill in request message */ + m.m_type = REQ_CHMOD; + m.REQ_INODE_NR = req->inode_nr; + m.REQ_MODE = req->rmode; + m.REQ_UID = req->uid; + m.REQ_GID = req->gid; + + /* Send/rec request */ + return fs_sendrec(req->fs_e, &m); +} + + +/*===========================================================================* + * req_chown * + *===========================================================================*/ +PUBLIC int req_chown(req) +chown_req_t *req; +{ + message m; + + /* Fill in request message */ + m.m_type = REQ_CHOWN; + m.REQ_INODE_NR = req->inode_nr; + m.REQ_UID = req->uid; + m.REQ_GID = req->gid; + m.REQ_NEW_UID = req->newuid; + m.REQ_NEW_GID = req->newgid; + + /* Send/rec request */ + return fs_sendrec(req->fs_e, &m); +} + + +/*===========================================================================* + * req_access * + *===========================================================================*/ +PUBLIC int req_access(req) +access_req_t *req; +{ + message m; + + /* Fill in request message */ + m.m_type = REQ_ACCESS; + m.REQ_INODE_NR = req->inode_nr; + m.REQ_MODE = req->amode; + m.REQ_UID = req->uid; + m.REQ_GID = req->gid; + + /* Send/rec request */ + return fs_sendrec(req->fs_e, &m); +} + + +/*===========================================================================* + * req_mknod * + *===========================================================================*/ +PUBLIC int req_mknod(req) +mknod_req_t *req; +{ + message m; + + /* Fill in request message */ + m.m_type = REQ_MKNOD; + m.REQ_INODE_NR = req->inode_nr; + m.REQ_MODE = req->rmode; + m.REQ_DEV = req->dev; + m.REQ_UID = req->uid; + m.REQ_GID = req->gid; + m.REQ_PATH = req->lastc; + m.REQ_PATH_LEN = strlen(req->lastc) + 1; + + /* Send/rec request */ + return fs_sendrec(req->fs_e, &m); +} + + +/*===========================================================================* + * req_mkdir * + *===========================================================================*/ +PUBLIC int req_mkdir(req) +mkdir_req_t *req; +{ + message m; + + /* Fill in request message */ + m.m_type = REQ_MKDIR; + m.REQ_INODE_NR = req->d_inode_nr; + m.REQ_MODE = req->rmode; + m.REQ_UID = req->uid; + m.REQ_GID = req->gid; + m.REQ_PATH = req->lastc; + m.REQ_PATH_LEN = strlen(req->lastc) + 1; + + /* Send/rec request */ + return fs_sendrec(req->fs_e, &m); +} + + + +/*===========================================================================* + * req_inhibread * + *===========================================================================*/ +PUBLIC int req_inhibread(req) +node_req_t *req; +{ + message m; + + /* Fill in request message */ + m.m_type = REQ_INHIBREAD; + m.REQ_INODE_NR = req->inode_nr; + + /* Send/rec request */ + return fs_sendrec(req->fs_e, &m); +} + + +/*===========================================================================* + * req_stat * + *===========================================================================*/ +PUBLIC int req_stat(req) +stat_req_t *req; +{ + message m; + + /* Fill in request message */ + m.m_type = REQ_STAT; + m.REQ_INODE_NR = req->inode_nr; + m.REQ_UID = req->uid; + m.REQ_GID = req->gid; + m.REQ_WHO_E = req->who_e; + m.REQ_USER_ADDR = req->buf; + + /* Send/rec request */ + return fs_sendrec(req->fs_e, &m); +} + + +/*===========================================================================* + * req_fstat * + *===========================================================================*/ +PUBLIC int req_fstat(req) +stat_req_t *req; +{ + message m; + + /* Fill in request message */ + m.m_type = REQ_FSTAT; + m.REQ_FD_INODE_NR = req->inode_nr; + m.REQ_FD_WHO_E = req->who_e; + m.REQ_FD_USER_ADDR = req->buf; + m.REQ_FD_POS = req->pos; + + /* Send/rec request */ + return fs_sendrec(req->fs_e, &m); +} + + +/*===========================================================================* + * req_fstatfs * + *===========================================================================*/ +PUBLIC int req_fstatfs(req) +stat_req_t *req; +{ + message m; + + /* Fill in request message */ + m.m_type = REQ_FSTATFS; + m.REQ_FD_INODE_NR = req->inode_nr; + m.REQ_FD_WHO_E = req->who_e; + m.REQ_FD_USER_ADDR = req->buf; + + /* Send/rec request */ + return fs_sendrec(req->fs_e, &m); +} + + +/*===========================================================================* + * req_unlink * + *===========================================================================*/ +PUBLIC int req_unlink(req) +unlink_req_t *req; +{ + message m; + + /* Fill in request message */ + m.m_type = REQ_UNLINK; + m.REQ_INODE_NR = req->d_inode_nr; + m.REQ_UID = req->uid; + m.REQ_GID = req->gid; + m.REQ_PATH = req->lastc; + m.REQ_PATH_LEN = strlen(req->lastc) + 1; + + /* Send/rec request */ + return fs_sendrec(req->fs_e, &m); +} + + +/*===========================================================================* + * req_rmdir * + *===========================================================================*/ +PUBLIC int req_rmdir(req) +unlink_req_t *req; +{ + message m; + + /* Fill in request message */ + m.m_type = REQ_RMDIR; + m.REQ_INODE_NR = req->d_inode_nr; + m.REQ_UID = req->uid; + m.REQ_GID = req->gid; + m.REQ_PATH = req->lastc; + m.REQ_PATH_LEN = strlen(req->lastc) + 1; + + /* Send/rec request */ + return fs_sendrec(req->fs_e, &m); +} + + +/*===========================================================================* + * req_utime * + *===========================================================================*/ +PUBLIC int req_utime(req) +utime_req_t *req; +{ + message m; + + /* Fill in request message */ + m.m_type = REQ_UTIME; + m.REQ_INODE_NR = req->inode_nr; + m.REQ_UID = req->uid; + m.REQ_GID = req->gid; + m.REQ_ACTIME = req->actime; + m.REQ_MODTIME = req->modtime; + + /* Send/rec request */ + return fs_sendrec(req->fs_e, &m); +} + + +/*===========================================================================* + * req_stime * + *===========================================================================*/ +PUBLIC int req_stime(fs_e, boottime) +endpoint_t fs_e; +time_t boottime; +{ + message m; + + /* Fill in request message */ + m.m_type = REQ_STIME; + m.REQ_BOOTTIME = boottime; + + /* Send/rec request */ + return fs_sendrec(fs_e, &m); +} + + +/*===========================================================================* + * 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_getdir * + *===========================================================================*/ +PUBLIC int req_getdir(req, res) +getdir_req_t *req; +node_details_t *res; +{ + int r; + message m; + + /* Fill in request message */ + m.m_type = REQ_GETDIR; + m.REQ_INODE_NR = req->inode_nr; + m.REQ_UID = req->uid; + m.REQ_GID = req->gid; + + /* Send/rec request */ + if ((r = fs_sendrec(req->fs_e, &m)) != 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; + + return OK; +} + + +/*===========================================================================* + * req_link * + *===========================================================================*/ +PUBLIC int req_link(req) +link_req_t *req; +{ + message m; + + /* Fill in request message */ + m.m_type = REQ_LINK; + m.REQ_LINKED_FILE = req->linked_file; + m.REQ_LINK_PARENT = req->link_parent; + m.REQ_UID = req->uid; + m.REQ_GID = req->gid; + m.REQ_PATH = req->lastc; + m.REQ_PATH_LEN = strlen(req->lastc) + 1; + + /* Send/rec request */ + return fs_sendrec(req->fs_e, &m); +} + + +/*===========================================================================* + * req_slink * + *===========================================================================*/ +PUBLIC int req_slink(req) +slink_req_t *req; +{ + message m; + + /* Fill in request message */ + m.m_type = REQ_SLINK; + m.REQ_INODE_NR = req->parent_dir; + m.REQ_UID = req->uid; + m.REQ_GID = req->gid; + m.REQ_PATH = req->lastc; + m.REQ_PATH_LEN = strlen(req->lastc) + 1; + m.REQ_WHO_E = req->who_e; + m.REQ_USER_ADDR = req->path_addr; + m.REQ_SLENGTH = req->path_length; + + /* Send/rec request */ + return fs_sendrec(req->fs_e, &m); +} + + +/*===========================================================================* + * req_rdlink * + *===========================================================================*/ +PUBLIC int req_rdlink(req) +rdlink_req_t *req; +{ + message m; + + /* Fill in request message */ + m.m_type = REQ_RDLINK; + m.REQ_INODE_NR = req->inode_nr; + m.REQ_UID = req->uid; + m.REQ_GID = req->gid; + m.REQ_WHO_E = req->who_e; + m.REQ_USER_ADDR = req->path_buffer; + m.REQ_SLENGTH = req->max_length; + + /* Send/rec request */ + return fs_sendrec(req->fs_e, &m); +} + + +/*===========================================================================* + * req_rename * + *===========================================================================*/ +PUBLIC int req_rename(req) +rename_req_t *req; +{ + message m; + + /* Fill in request message */ + m.m_type = REQ_RENAME; + m.REQ_OLD_DIR = req->old_dir; + m.REQ_NEW_DIR = req->new_dir; + m.REQ_UID = req->uid; + m.REQ_GID = req->gid; + m.REQ_PATH = req->old_name; + m.REQ_PATH_LEN = strlen(req->old_name) + 1; + m.REQ_USER_ADDR = req->new_name; + m.REQ_SLENGTH = strlen(req->new_name) + 1; + + /* Send/rec request */ + return fs_sendrec(req->fs_e, &m); +} + + +/*===========================================================================* + * req_mountpoint * + *===========================================================================*/ +PUBLIC int req_mountpoint(req, res) +mountpoint_req_t *req; +node_details_t *res; +{ + int r; + message m; + + /* Fill in request message */ + m.m_type = REQ_MOUNTPOINT; + m.REQ_INODE_NR = req->inode_nr; + m.REQ_UID = req->uid; + m.REQ_GID = req->gid; + + /* Send/rec request */ + if ((r = fs_sendrec(req->fs_e, &m)) != 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; + + return OK; +} + + +/*===========================================================================* + * req_readsuper * + *===========================================================================*/ +PUBLIC int req_readsuper(req, res) +readsuper_req_t *req; +readsuper_res_t *res; +{ + int r; + message m; + + /* Fill in request message */ + m.m_type = REQ_READSUPER; + m.REQ_READONLY = req->readonly; + m.REQ_BOOTTIME = req->boottime; + m.REQ_DRIVER_E = req->driver_e; + m.REQ_DEV = req->dev; + m.REQ_SLINK_STORAGE = req->slink_storage; + m.REQ_ISROOT = req->isroot; + + /* Send/rec request */ + if ((r = fs_sendrec(req->fs_e, &m)) != 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; + res->blocksize = m.RES_BLOCKSIZE; + res->maxsize = m.RES_MAXSIZE; + + return OK; +} + + +/*===========================================================================* + * 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_trunc * + *===========================================================================*/ +PUBLIC int req_trunc(req) +trunc_req_t *req; +{ + message m; + + /* Fill in request message */ + m.m_type = REQ_TRUNC; + m.REQ_FD_INODE_NR = req->inode_nr; + m.REQ_UID = req->uid; + m.REQ_GID = req->gid; + m.REQ_LENGTH = req->length; + + /* Send/rec request */ + return fs_sendrec(req->fs_e, &m); +} + + + +/*===========================================================================* + * req_newdriver * + *===========================================================================*/ +PUBLIC int req_newdriver(fs_e, dev, driver_e) +endpoint_t fs_e; +Dev_t dev; +endpoint_t driver_e; +{ +/* Note: this is the only request function that doesn't use the + * fs_sendrec internal routine, since we want to avoid the dead + * driver recovery mechanism here. This function is actually called + * during the recovery. + */ + message m; + int r; + + /* Fill in request message */ + m.m_type = REQ_NEW_DRIVER; + m.REQ_DEV = dev; + m.REQ_DRIVER_E = driver_e; + + /* Issue request */ + if ((r = sendrec(fs_e, &m)) != OK) { + printf("VFSreq_newdriver: error sending message to %d\n", fs_e); + return r; + } + + return OK; +} + + +/*===========================================================================* + * req_lookup * + *===========================================================================*/ +PUBLIC int req_lookup(req, res) +lookup_req_t *req; +lookup_res_t *res; +{ + int r; + message m; + + /* Fill in request message */ + m.m_type = REQ_LOOKUP; + m.REQ_PATH = req->path; + m.REQ_PATH_LEN = strlen(req->path) + 1; + m.REQ_USER_ADDR = req->lastc; + m.REQ_FLAGS = req->flags; + + m.REQ_INODE_NR = req->start_dir; + m.REQ_CHROOT_NR = req->root_dir; + m.REQ_UID = req->uid; + m.REQ_GID = req->gid; + m.REQ_SYMLOOP = req->symloop; + + /* Send/rec request */ + r = fs_sendrec(req->fs_e, &m); + + /* 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; + res->dev = m.RES_DEV; + break; + case EENTERMOUNT: + res->inode_nr = m.RES_INODE_NR; + case ELEAVEMOUNT: + case ESYMLINK: + res->char_processed = m.RES_OFFSET; + res->symloop = m.RES_SYMLOOP; + break; + } + + return r; +} + + +/*===========================================================================* + * req_breadwrite * + *===========================================================================*/ +int req_breadwrite(req, res) +breadwrite_req_t *req; +readwrite_res_t *res; +{ + int r; + message m; + + /* Fill in request message */ + m.m_type = req->rw_flag == READING ? REQ_BREAD : REQ_BWRITE; + m.REQ_FD_BDEV = req->dev; + m.REQ_FD_BLOCK_SIZE = req->blocksize; + m.REQ_FD_WHO_E = req->user_e; + m.REQ_FD_POS = req->pos; + m.REQ_FD_NBYTES = req->num_of_bytes; + m.REQ_FD_USER_ADDR = req->user_addr; + + /* Send/rec request */ + if ((r = fs_sendrec(req->fs_e, &m)) != OK) return r; + + /* Fill in response structure */ + res->new_pos = m.RES_FD_POS; + res->cum_io = m.RES_FD_CUM_IO; + + return OK; +} + + + + +#if 0 +/* Wrapper pattern: */ +/*===========================================================================* + * req_ * + *===========================================================================*/ +PUBLIC int req_(req, res) +_req_t *req; +_t *res; +{ + int r; + message m; + + /* Fill in request message */ + + + /* Send/rec request */ + if ((r = fs_sendrec(req->fs_e, &m)) != OK) return r; + + /* Fill in response structure */ + + + return OK; +} +#endif + + + + +/*===========================================================================* + * fs_sendrec * + *===========================================================================*/ +PUBLIC int fs_sendrec(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, old_driver_e, new_driver_e; + message origm, m; + struct vmnt *vmp; + + /* Make a copy of the request so that we can load it back in + * case of a dead driver */ + origm = *reqm; + + for (;;) { + /* Do the actual send, receive */ + if (OK != sendrec(fs_e, reqm)) { + printf("VFS: error sending message. FS_e: %d req_nr: %d\n", + fs_e, reqm->m_type); + } + + /* Get response type */ + r = reqm->m_type; + + /* Dead driver */ + if (r == EDEADSRCDST || r == EDSTDIED || r == ESRCDIED) { + old_driver_e = 0; + /* Find old driver enpoint */ + for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) { + if (vmp->m_fs_e == reqm->m_source) { /* found FS */ + old_driver_e = vmp->m_driver_e; + dmap_unmap_by_endpt(old_driver_e); /* unmap driver */ + break; + } + } + + /* No FS ?? */ + if (!old_driver_e) { + panic(__FILE__, "VFSdead_driver: couldn't find FS\n", + old_driver_e); + } + + /* Wait for a new driver. */ + for (;;) { + new_driver_e = 0; + printf("VFSdead_driver: waiting for new driver\n"); + r = receive(RS_PROC_NR, &m); + if (r != OK) { + panic(__FILE__, "VFSdead_driver: unable to receive from RS", + r); + } + if (m.m_type == DEVCTL) { + /* Map new driver */ + r = fs_devctl(m.ctl_req, m.dev_nr, m.driver_nr, + m.dev_style, m.m_force); + if (m.ctl_req == DEV_MAP && r == OK) { + new_driver_e = m.driver_nr; + printf("VFSdead_driver: new driver endpoint: %d\n", + new_driver_e); + } + } + else { + panic(__FILE__, "VFSdead_driver: got message from RS, type", + m.m_type); + } + m.m_type = r; + if ((r = send(RS_PROC_NR, &m)) != OK) { + panic(__FILE__, "VFSdead_driver: unable to send to RS", + r); + } + /* New driver is ready */ + if (new_driver_e) break; + } + + /* Copy back original request */ + *reqm = origm; + continue; + } + + /* Sendrec was okay */ + break; + } + /* Return message type */ + return r; +} + + + diff --git a/servers/vfs/request.h b/servers/vfs/request.h new file mode 100644 index 000000000..16795f342 --- /dev/null +++ b/servers/vfs/request.h @@ -0,0 +1,321 @@ + +/* 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 REQ_GETNODE and REQ_PUTNODE requests */ +typedef struct node_req { + endpoint_t fs_e; + ino_t inode_nr; +} node_req_t; + + +/* 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; + unsigned short inode_index; + /* For char/block special files */ + dev_t dev; + + /* Fields used by the exec() syscall */ + uid_t uid; + gid_t gid; + time_t ctime; +} node_details_t; + + +/* Structure for REQ_OPEN request */ +typedef struct open_req { + endpoint_t fs_e; + ino_t inode_nr; + char *lastc; + int oflags; + mode_t omode; + uid_t uid; + gid_t gid; +} open_req_t; + + +/* Structure for REQ_READ and REQ_WRITE request */ +typedef struct readwrite_req { + int rw_flag; + endpoint_t fs_e; + endpoint_t user_e; + ino_t inode_nr; + unsigned short inode_index; + int seg; + off_t pos; + unsigned int num_of_bytes; + char *user_addr; +} readwrite_req_t; + + +/* Structure for response of REQ_READ and REQ_WRITE */ +typedef struct readwrite_res { + off_t new_pos; + unsigned int cum_io; +} readwrite_res_t; + + +/* Structure for REQ_PIPE request */ +typedef struct pipe_req { + int fs_e; + uid_t uid; + gid_t gid; +} pipe_req_t; + + +/* Structure for REQ_CLONE_OPCL request */ +typedef struct clone_opcl_req { + int fs_e; + dev_t dev; +} clone_opcl_req_t; + + +/* Structure for REQ_FTRUNC request */ +typedef struct ftrunc_req { + int fs_e; + ino_t inode_nr; + off_t start; + off_t end; +} ftrunc_req_t; + + +/* Structure for REQ_CHOWN request */ +typedef struct chown_req { + int fs_e; + ino_t inode_nr; + uid_t uid; + gid_t gid; + uid_t newuid; + gid_t newgid; +} chown_req_t; + + +/* Structure for REQ_CHMOD request */ +typedef struct chmod_req { + int fs_e; + ino_t inode_nr; + uid_t uid; + gid_t gid; + mode_t rmode; +} chmod_req_t; + + +/* Structure for REQ_ACCESS request */ +typedef struct access_req { + int fs_e; + ino_t inode_nr; + uid_t uid; + gid_t gid; + mode_t amode; +} access_req_t; + + +/* Structure for REQ_MKNOD request */ +typedef struct mknod_req { + int fs_e; + ino_t inode_nr; + uid_t uid; + gid_t gid; + mode_t rmode; + dev_t dev; + char *lastc; +} mknod_req_t; + + +/* Structure for REQ_MKDIR request */ +typedef struct mkdir_req { + int fs_e; + ino_t d_inode_nr; + uid_t uid; + gid_t gid; + mode_t rmode; + char *lastc; +} mkdir_req_t; + + +/* Structure for REQ_STAT, REQ_FSTAT, REQ_FSTATFS requests */ +typedef struct stat_req { + int fs_e; + ino_t inode_nr; + uid_t uid; + gid_t gid; + int who_e; + char *buf; + int pos; +} stat_req_t; + +/* Structure for REQ_UNLINK request */ +typedef struct unlink_req { + int fs_e; + ino_t d_inode_nr; + uid_t uid; + gid_t gid; + char *lastc; +} unlink_req_t; + + +/* Structure for REQ_UTIME request */ +typedef struct utime_req { + int fs_e; + ino_t inode_nr; + uid_t uid; + gid_t gid; + time_t actime; + time_t modtime; +} utime_req_t; + + +/* Structure for REQ_GETDIR request */ +typedef struct getdir_req { + endpoint_t fs_e; + ino_t inode_nr; + uid_t uid; + gid_t gid; +} getdir_req_t; + + +/* Structure for REQ_LINK request */ +typedef struct link_req { + endpoint_t fs_e; + ino_t linked_file; + ino_t link_parent; + uid_t uid; + gid_t gid; + char *lastc; +} link_req_t; + + +/* Structure for REQ_SLINK request */ +typedef struct slink_req { + endpoint_t fs_e; + ino_t parent_dir; + uid_t uid; + gid_t gid; + char *lastc; + endpoint_t who_e; + char *path_addr; + unsigned short path_length; +} slink_req_t; + + +/* Structure for REQ_RDLINK request */ +typedef struct rdlink_req { + endpoint_t fs_e; + ino_t inode_nr; + uid_t uid; + gid_t gid; + endpoint_t who_e; + char *path_buffer; + unsigned short max_length; +} rdlink_req_t; + + +/* Structure for REQ_RENAME request */ +typedef struct rename_req { + endpoint_t fs_e; + ino_t old_dir; + ino_t new_dir; + uid_t uid; + gid_t gid; + char *old_name; + char *new_name; +} rename_req_t; + + +/* Structure for REQ_MOUNTPOINT request */ +typedef struct mountpoint_req { + endpoint_t fs_e; + ino_t inode_nr; + uid_t uid; + gid_t gid; +} mountpoint_req_t; + + +/* Structure for REQ_READSUPER request */ +typedef struct readsuper_req { + endpoint_t fs_e; + time_t boottime; + endpoint_t driver_e; + dev_t dev; + char *slink_storage; + char isroot; + char readonly; +} readsuper_req_t; + +/* Structure for response of READSUPER request */ +typedef struct readsuper_res { + endpoint_t fs_e; + ino_t inode_nr; + mode_t fmode; + off_t fsize; + int blocksize; + off_t maxsize; +} readsuper_res_t; + + +/* Structure for REQ_TRUNC request */ +typedef struct trunc_req { + endpoint_t fs_e; + ino_t inode_nr; + uid_t uid; + gid_t gid; + off_t length; +} trunc_req_t; + + +/* Structure for REQ_LOOKUP request */ +typedef struct lookup_req { + /* Fields filled in by the caller */ + char *path; + char *lastc; + int flags; + /* Fields filled in by the path name traversal method */ + endpoint_t fs_e; + ino_t start_dir; + ino_t root_dir; /* process' root directory */ + uid_t uid; + gid_t gid; + unsigned char symloop; +} lookup_req_t; + + +/* Structure for a lookup response */ +typedef struct lookup_res { + endpoint_t fs_e; + ino_t inode_nr; + mode_t fmode; + off_t fsize; + /* 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_BREAD and REQ_BWRITE request (block spec files) */ +typedef struct breadwrite_req { + int rw_flag; + short blocksize; + endpoint_t fs_e; + endpoint_t user_e; + endpoint_t driver_e; + dev_t dev; + off_t pos; + unsigned int num_of_bytes; + char *user_addr; +} breadwrite_req_t; + + + +/* Structure for REQ_ request */ diff --git a/servers/fs/select.c b/servers/vfs/select.c similarity index 92% rename from servers/fs/select.c rename to servers/vfs/select.c index 066e17e9b..44dd00a67 100644 --- a/servers/fs/select.c +++ b/servers/vfs/select.c @@ -15,7 +15,7 @@ #include "fs.h" #include "select.h" #include "file.h" -#include "inode.h" +#include "vnode.h" #include #include @@ -38,7 +38,6 @@ PRIVATE struct selectentry { timer_t timer; /* if expiry > 0 */ } selecttab[MAXSELECTS]; - FORWARD _PROTOTYPE(int select_reevaluate, (struct filp *fp)); FORWARD _PROTOTYPE(int select_request_file, @@ -92,7 +91,7 @@ PRIVATE int select_request_file(struct filp *f, int *ops, int block) *===========================================================================*/ PRIVATE int select_match_file(struct filp *file) { - if (file && file->filp_ino && (file->filp_ino->i_mode & I_REGULAR)) + if (file && file->filp_vno && (file->filp_vno->v_mode & I_REGULAR)) return 1; return 0; } @@ -104,7 +103,7 @@ PRIVATE int select_request_general(struct filp *f, int *ops, int block) { int rops = *ops; if (block) rops |= SEL_NOTIFY; - *ops = dev_io(DEV_SELECT, f->filp_ino->i_zone[0], rops, NULL, 0, 0, 0); + *ops = dev_io(DEV_SELECT, f->filp_vno->v_sdev, rops, NULL, 0, 0, 0); if (*ops < 0) return SEL_ERR; return SEL_OK; @@ -116,10 +115,10 @@ PRIVATE int select_request_general(struct filp *f, int *ops, int block) PRIVATE int select_major_match(int match_major, struct filp *file) { int major; - if (!(file && file->filp_ino && - (file->filp_ino->i_mode & I_TYPE) == I_CHAR_SPECIAL)) + if (!(file && file->filp_vno && + (file->filp_vno->v_mode & I_TYPE) == I_CHAR_SPECIAL)) return 0; - major = (file->filp_ino->i_zone[0] >> MAJOR) & BYTE; + major = (file->filp_vno->v_sdev >> MAJOR) & BYTE; if (major == match_major) return 1; return 0; @@ -164,22 +163,23 @@ PRIVATE void ops2tab(int ops, int fd, struct selectentry *e) *===========================================================================*/ PRIVATE void copy_fdsets(struct selectentry *e) { - int fd_setsize; - if(e->nfds < 0 || e->nfds > OPEN_MAX) - panic(__FILE__, "select copy_fdsets: e->nfds wrong", e->nfds); + int fd_setsize; + if(e->nfds < 0 || e->nfds > OPEN_MAX) + panic(__FILE__, "select copy_fdsets: e->nfds wrong", e->nfds); - /* Only copy back as many bits as the user expects. */ - fd_setsize = _FDSETWORDS(e->nfds)*_FDSETBITSPERWORD/8; + /* Only copy back as many bits as the user expects. */ + fd_setsize = _FDSETWORDS(e->nfds)*_FDSETBITSPERWORD/8; + + if (e->vir_readfds) + sys_vircopy(SELF, D, (vir_bytes) &e->ready_readfds, + e->req_endpt, D, (vir_bytes) e->vir_readfds, fd_setsize); + if (e->vir_writefds) + sys_vircopy(SELF, D, (vir_bytes) &e->ready_writefds, + e->req_endpt, D, (vir_bytes) e->vir_writefds, fd_setsize); + if (e->vir_errorfds) + sys_vircopy(SELF, D, (vir_bytes) &e->ready_errorfds, + e->req_endpt, D, (vir_bytes) e->vir_errorfds, fd_setsize); - if (e->vir_readfds) - sys_vircopy(SELF, D, (vir_bytes) &e->ready_readfds, - e->req_endpt, D, (vir_bytes) e->vir_readfds, fd_setsize); - if (e->vir_writefds) - sys_vircopy(SELF, D, (vir_bytes) &e->ready_writefds, - e->req_endpt, D, (vir_bytes) e->vir_writefds, fd_setsize); - if (e->vir_errorfds) - sys_vircopy(SELF, D, (vir_bytes) &e->ready_errorfds, - e->req_endpt, D, (vir_bytes) e->vir_errorfds, fd_setsize); return; } @@ -221,11 +221,12 @@ PUBLIC int do_select(void) selecttab[s].vir_writefds = (fd_set *) m_in.SEL_WRITEFDS; selecttab[s].vir_errorfds = (fd_set *) m_in.SEL_ERRORFDS; - /* Copy args. Our storage size is zeroed above. Only copy - * as many bits as user has supplied (nfds). - * Could be compiled with a different OPEN_MAX or FD_SETSIZE. - * If nfds is too large, we have already returned above. - */ + + /* Copy args. Our storage size is zeroed above. Only copy + * as many bits as user has supplied (nfds). + * Could be compiled with a different OPEN_MAX or FD_SETSIZE. + * If nfds is too large, we have already returned above. + */ fd_setsize = _FDSETWORDS(nfds)*_FDSETBITSPERWORD/8; if (selecttab[s].vir_readfds @@ -589,7 +590,7 @@ PUBLIC int select_notified(int major, int minor, int selected_ops) continue; ops = tab2ops(f, &selecttab[s]); s_minor = - (selecttab[s].filps[f]->filp_ino->i_zone[0] >> MINOR) + (selecttab[s].filps[f]->filp_vno->v_sdev >> MINOR) & BYTE; if ((s_minor == minor) && (selected_ops & ops)) { @@ -691,9 +692,9 @@ PUBLIC void select_unsuspend_by_endpt(int proc_e) continue; for(fd = 0; fd < selecttab[s].nfds; fd++) { int maj; - if (!selecttab[s].filps[fd] || !selecttab[s].filps[fd]->filp_ino) + if (!selecttab[s].filps[fd] || !selecttab[s].filps[fd]->filp_vno) continue; - maj = (selecttab[s].filps[fd]->filp_ino->i_zone[0] >> MAJOR)&BYTE; + maj = (selecttab[s].filps[fd]->filp_vno->v_sdev >> MAJOR)&BYTE; if(dmap_driver_match(proc_e, maj)) { select_return(&selecttab[s], EAGAIN); } diff --git a/servers/vfs/select.h b/servers/vfs/select.h new file mode 100644 index 000000000..5e2cc8ebe --- /dev/null +++ b/servers/vfs/select.h @@ -0,0 +1,9 @@ +#ifndef _FS_SELECT_H +#define _FS_SELECT_H 1 + +/* return codes for select_request_* and select_cancel_* */ +#define SEL_OK 0 /* ready */ +#define SEL_ERROR 1 /* failed */ + +#endif + diff --git a/servers/vfs/stadir.c b/servers/vfs/stadir.c new file mode 100644 index 000000000..91d2ee430 --- /dev/null +++ b/servers/vfs/stadir.c @@ -0,0 +1,334 @@ +/* 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_stat: perform the STAT system call + * do_fstat: perform the FSTAT system call + * do_fstatfs: perform the FSTATFS system call + * do_lstat: perform the LSTAT system call + * + * Changes for VFS: + * Jul 2006 (Balazs Gerofi) + */ + +#include "fs.h" +#include +#include +#include +#include +#include "file.h" +#include "fproc.h" +#include "param.h" + +#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; + struct getdir_req req; + struct node_details res; + int r; + + /* Is the file descriptor valid? */ + if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code); + + /* Is it a dir? */ + if ((rfilp->filp_vno->v_mode & I_TYPE) != I_DIRECTORY) + return ENOTDIR; + + /* Fill in request message fields.*/ + req.fs_e = rfilp->filp_vno->v_fs_e; + req.inode_nr = rfilp->filp_vno->v_inode_nr; + req.uid = fp->fp_effuid; + req.gid = fp->fp_effgid; + + /* Issue request and handle error */ + if ((r = req_getdir(&req, &res)) != OK) return r; + + /* GETDIR increased the counter in the FS proc */ + rfilp->filp_vno->v_count++; + + return change_into(&fp->fp_wd, rfilp->filp_vno); +} + +/*===========================================================================* + * do_chdir * + *===========================================================================*/ +PUBLIC int do_chdir() +{ +/* Change directory. This function is also called by MM to simulate a chdir + * in order to do EXEC, etc. It also changes the root directory, the uids and + * gids, and the umask. + */ + int r; + register struct fproc *rfp; + + if (who_e == PM_PROC_NR) { + int slot; + if(isokendpt(m_in.endpt1, &slot) != OK) + return EINVAL; + rfp = &fproc[slot]; + + put_vnode(fp->fp_rd); + dup_vnode(fp->fp_rd = rfp->fp_rd); + put_vnode(fp->fp_wd); + dup_vnode(fp->fp_wd = rfp->fp_wd); + + /* MM uses access() to check permissions. To make this work, pretend + * that the user's real ids are the same as the user's effective ids. + * FS calls other than access() do not use the real ids, so are not + * affected. + */ + fp->fp_realuid = + fp->fp_effuid = rfp->fp_effuid; + fp->fp_realgid = + fp->fp_effgid = rfp->fp_effgid; + fp->fp_umask = rfp->fp_umask; + return(OK); + } + + /* Perform the chdir(name) system call. */ + r = change(&fp->fp_wd, m_in.name, m_in.name_length); + return(r); +} + +/*===========================================================================* + * do_chroot * + *===========================================================================*/ +PUBLIC int do_chroot() +{ +/* Perform the chroot(name) system call. */ + + register int r; + + if (!super_user) return(EPERM); /* only su may chroot() */ + + r = change(&fp->fp_rd, m_in.name, m_in.name_length); + return(r); +} + + +/*===========================================================================* + * 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, *vp2; + struct vmnt *vmp; + struct getdir_req req; + struct node_details res; + struct lookup_req lookup_req; + int r; + + if (fetch_name(name_ptr, len, M3) != OK) return(err_code); + + /* See if free vnode is available */ + if ((vp = get_free_vnode()) == NIL_VNODE) { + printf("VFSchange: no free vnode available\n"); + return EINVAL; + } + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = NULL; + lookup_req.flags = EAT_PATH; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + /* Is it a dir? */ + if ((res.fmode & I_TYPE) != I_DIRECTORY) + return ENOTDIR; + + /* Fill in request message fields.*/ + req.fs_e = res.fs_e; + req.inode_nr = res.inode_nr; + req.uid = fp->fp_effuid; + req.gid = fp->fp_effgid; + + /* Issue request */ + if ((r = req_getdir(&req, &res)) != OK) return r; + + /* Check whether vnode is already in use or not */ + if ((vp2 = find_vnode(res.fs_e, res.inode_nr)) + != NIL_VNODE) { + vp2->v_count++; + vp = vp2; + } + else { + /* Fill in the free vnode's fields */ + vp->v_fs_e = res.fs_e; + vp->v_inode_nr = res.inode_nr; + vp->v_mode = res.fmode; + vp->v_size = res.fsize; + + if ( (vmp = find_vmnt(vp->v_fs_e)) == NIL_VMNT) + printf("VFSchange: vmnt not found"); + + vp->v_vmnt = vmp; + vp->v_dev = vmp->m_dev; + vp->v_count = 1; + } + + return change_into(iip, vp); +} + + +/*===========================================================================* + * 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 */ +{ + /* Everything is OK. Make the change. */ + put_vnode(*iip); /* release the old directory */ + *iip = vp; /* acquire the new one */ + + return(OK); +} + + +/*===========================================================================* + * do_stat * + *===========================================================================*/ +PUBLIC int do_stat() +{ +/* Perform the stat(name, buf) system call. */ + struct stat_req req; + struct node_details res; + struct lookup_req lookup_req; + int r; + + if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = NULL; + lookup_req.flags = EAT_PATH; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + /* Fill in request message fields.*/ + req.fs_e = res.fs_e; + req.who_e = who_e; + req.buf = m_in.name2; + req.inode_nr = res.inode_nr; + req.uid = fp->fp_effuid; + req.gid = fp->fp_effgid; + + /* Issue request */ + return req_stat(&req); +} + + + +/*===========================================================================* + * do_fstat * + *===========================================================================*/ +PUBLIC int do_fstat() +{ +/* Perform the fstat(fd, buf) system call. */ + register struct filp *rfilp; + int pipe_pos = 0; + struct stat_req req; + + /* Is the file descriptor valid? */ + if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) { + 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) + pipe_pos = rfilp->filp_pos; + } + + /* Fill in request message */ + req.fs_e = rfilp->filp_vno->v_fs_e; + req.inode_nr = rfilp->filp_vno->v_inode_nr; + req.pos = pipe_pos; + req.who_e = who_e; + req.buf = m_in.buffer; + + /* Issue request */ + return req_fstat(&req); +} + + + +/*===========================================================================* + * do_fstatfs * + *===========================================================================*/ +PUBLIC int do_fstatfs() +{ + /* Perform the fstatfs(fd, buf) system call. */ + register struct filp *rfilp; + struct stat_req req; + + /* Is the file descriptor valid? */ + if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code); + + /* Send FS request */ + req.fs_e = rfilp->filp_vno->v_fs_e; + req.inode_nr = rfilp->filp_vno->v_inode_nr; + req.who_e = who_e; + req.buf = m_in.buffer; + + /* Issue request */ + return req_fstatfs(&req); +} + + + +/*===========================================================================* + * do_lstat * + *===========================================================================*/ +PUBLIC int do_lstat() +{ +/* Perform the lstat(name, buf) system call. */ + struct stat_req req; + struct node_details res; + struct lookup_req lookup_req; + int r; + + if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = NULL; + lookup_req.flags = EAT_PATH_OPAQUE; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; + + /* Fill in request message fields.*/ + req.fs_e = res.fs_e; + req.who_e = who_e; + req.buf = m_in.name2; + req.inode_nr = res.inode_nr; + req.uid = fp->fp_effuid; + req.gid = fp->fp_effgid; + + /* Issue request */ + return req_stat(&req); +} + + + diff --git a/servers/fs/super.h b/servers/vfs/super.h similarity index 100% rename from servers/fs/super.h rename to servers/vfs/super.h diff --git a/servers/fs/table.c b/servers/vfs/table.c similarity index 96% rename from servers/fs/table.c rename to servers/vfs/table.c index 262d7f4b5..f347ac335 100644 --- a/servers/fs/table.c +++ b/servers/vfs/table.c @@ -7,12 +7,13 @@ #include "fs.h" #include #include -#include "buf.h" #include "file.h" #include "fproc.h" -#include "inode.h" #include "lock.h" -#include "super.h" + +#include "vnode.h" +#include "vmnt.h" + PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = { no_sys, /* 0 = unused */ @@ -72,7 +73,7 @@ PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = { do_ioctl, /* 54 = ioctl */ do_fcntl, /* 55 = fcntl */ no_sys, /* 56 = (mpx) */ - no_sys, /* 57 = unused */ + do_fslogin, /* 57 = FS proc login */ no_sys, /* 58 = unused */ no_sys, /* 59 = (execve) */ do_umask, /* 60 = umask */ @@ -114,7 +115,8 @@ PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = { do_ftruncate, /* 94 = truncate */ do_chmod, /* 95 = fchmod */ do_chown, /* 96 = fchown */ - no_sys, /* 97 = (getsysinfo_up) */ + no_sys, /* 97 = getsysinfo_up */ }; /* This should not fail with "array size is negative": */ extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1]; + diff --git a/servers/fs/time.c b/servers/vfs/time.c similarity index 52% rename from servers/fs/time.c rename to servers/vfs/time.c index 39fa3c546..806fee9a2 100644 --- a/servers/fs/time.c +++ b/servers/vfs/time.c @@ -10,57 +10,71 @@ #include #include "file.h" #include "fproc.h" -#include "inode.h" #include "param.h" +#include +#include "vmnt.h" + /*===========================================================================* * do_utime * *===========================================================================*/ PUBLIC int do_utime() { /* Perform the utime(name, timep) system call. */ - - register struct inode *rip; - register int len, r; - + register int len; + struct utime_req req; + struct lookup_req lookup_req; + struct node_details res; + int r; + /* 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) != OK) return(err_code); - if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code); + + /* Fill in lookup request fields */ + lookup_req.path = user_fullpath; + lookup_req.lastc = NULL; + lookup_req.flags = EAT_PATH; + + /* Request lookup */ + if ((r = lookup(&lookup_req, &res)) != OK) return r; - /* Only the owner of a file or the super_user can change its time. */ - r = OK; - if (rip->i_uid != fp->fp_effuid && !super_user) r = EPERM; - if (m_in.utime_length == 0 && r != OK) r = forbidden(rip, W_BIT); - if (read_only(rip) != OK) r = EROFS; /* not even su can touch if R/O */ - if (r == OK) { - if (m_in.utime_length == 0) { - rip->i_atime = clock_time(); - rip->i_mtime = rip->i_atime; - } else { - rip->i_atime = m_in.utime_actime; - rip->i_mtime = m_in.utime_modtime; - } - rip->i_update = CTIME; /* discard any stale ATIME and MTIME flags */ - rip->i_dirt = DIRTY; + /* Fill in request fields.*/ + if (m_in.utime_length == 0) { + req.actime = 0; + req.modtime = clock_time(); + } else { + req.actime = m_in.utime_actime; + req.modtime = m_in.utime_modtime; } - - put_inode(rip); - return(r); + req.fs_e = res.fs_e; + req.inode_nr = res.inode_nr; + req.uid = fp->fp_effuid; + req.gid = fp->fp_effgid; + + /* Issue request */ + return req_utime(&req); } + /*===========================================================================* * do_stime * *===========================================================================*/ PUBLIC int do_stime() { -/* Perform the stime(tp) system call. */ + struct vmnt *vmp; + /* Perform the stime(tp) system call. */ boottime = (long) m_in.pm_stime; - return(OK); + + /* Send new time for all FS processes */ + for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) { + if (vmp->m_fs_e) req_stime(vmp->m_fs_e, boottime); + } + + return OK; } diff --git a/servers/fs/timers.c b/servers/vfs/timers.c similarity index 100% rename from servers/fs/timers.c rename to servers/vfs/timers.c diff --git a/servers/vfs/type.h b/servers/vfs/type.h new file mode 100644 index 000000000..19749fef0 --- /dev/null +++ b/servers/vfs/type.h @@ -0,0 +1,23 @@ +/* Declaration of the V1 inode as it is on the disk (not in core). */ +typedef struct { /* V1.x disk inode */ + mode_t d1_mode; /* file type, protection, etc. */ + uid_t d1_uid; /* user id of the file's owner */ + off_t d1_size; /* current file size in bytes */ + time_t d1_mtime; /* when was file data last changed */ + u8_t d1_gid; /* group number */ + u8_t d1_nlinks; /* how many links to this file */ + u16_t d1_zone[V1_NR_TZONES]; /* block nums for direct, ind, and dbl ind */ +} d1_inode; + +/* Declaration of the V2 inode as it is on the disk (not in core). */ +typedef struct { /* V2.x disk inode */ + mode_t d2_mode; /* file type, protection, etc. */ + u16_t d2_nlinks; /* how many links to this file. HACK! */ + uid_t d2_uid; /* user id of the file's owner. */ + u16_t d2_gid; /* group number HACK! */ + off_t d2_size; /* current file size in bytes */ + time_t d2_atime; /* when was file data last accessed */ + time_t d2_mtime; /* when was file data last changed */ + time_t d2_ctime; /* when was inode data last changed */ + zone_t d2_zone[V2_NR_TZONES]; /* block nums for direct, ind, and dbl ind */ +} d2_inode; diff --git a/servers/fs/utility.c b/servers/vfs/utility.c similarity index 66% rename from servers/fs/utility.c rename to servers/vfs/utility.c index 50821f072..a73442088 100644 --- a/servers/fs/utility.c +++ b/servers/vfs/utility.c @@ -14,31 +14,12 @@ #include #include #include -#include "buf.h" #include "file.h" #include "fproc.h" -#include "inode.h" #include "param.h" PRIVATE int panicking; /* inhibits recursive panics during sync */ -/*===========================================================================* - * 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 k; - clock_t uptime; - - if ( (k=getuptime(&uptime)) != OK) panic(__FILE__,"clock_time err", k); - return( (time_t) (boottime + (uptime/HZ))); -} - /*===========================================================================* * fetch_name * *===========================================================================*/ @@ -67,15 +48,16 @@ int flag; /* M3 means path may be in message */ if (flag == M3 && len <= M3_STRING) { /* Just copy the path from the message to 'user_path'. */ - rpu = &user_path[0]; + rpu = &user_fullpath[0]; rpm = m_in.pathname; /* contained in input message */ do { *rpu++ = *rpm++; } while (--len); r = OK; } else { /* String is not contained in the message. Get it from user space. */ r = sys_datacopy(who_e, (vir_bytes) path, - FS_PROC_NR, (vir_bytes) user_path, (phys_bytes) len); + FS_PROC_NR, (vir_bytes) user_fullpath, (phys_bytes) len); } + return(r); } @@ -85,8 +67,8 @@ int flag; /* M3 means path may be in message */ PUBLIC int no_sys() { /* Somebody has used an illegal system call number */ - printf("FS: in no_sys: call %d from %d\n", call_nr, who_e); - return(EINVAL); + printf("VFSno_sys: call %d from %d\n", call_nr, who_e); + return(SUSPEND); } /*===========================================================================* @@ -110,57 +92,46 @@ int num; /* number to go with it */ sys_exit(SELF); } -/*===========================================================================* - * conv2 * - *===========================================================================*/ -PUBLIC unsigned conv2(norm, w) -int norm; /* TRUE if no swap, FALSE for byte swap */ -int w; /* promotion of 16-bit word to be swapped */ -{ -/* Possibly swap a 16-bit word between 8086 and 68000 byte order. */ - if (norm) return( (unsigned) w & 0xFFFF); - return( ((w&BYTE) << 8) | ( (w>>8) & BYTE)); -} - -/*===========================================================================* - * conv4 * - *===========================================================================*/ -PUBLIC long conv4(norm, x) -int norm; /* TRUE if no swap, FALSE for byte swap */ -long x; /* 32-bit long to be byte swapped */ -{ -/* Possibly swap a 32-bit long between 8086 and 68000 byte order. */ - unsigned lo, hi; - long l; - - if (norm) return(x); /* byte order was already ok */ - lo = conv2(FALSE, (int) x & 0xFFFF); /* low-order half, byte swapped */ - hi = conv2(FALSE, (int) (x>>16) & 0xFFFF); /* high-order half, swapped */ - l = ( (long) lo <<16) | hi; - return(l); -} /*===========================================================================* * isokendpt_f * *===========================================================================*/ PUBLIC int isokendpt_f(char *file, int line, int endpoint, int *proc, int fatal) { - int failed = 0; - *proc = _ENDPOINT_P(endpoint); - if(*proc < 0 || *proc >= NR_PROCS) { - printf("FS:%s:%d: proc (%d) from endpoint (%d) out of range\n", - file, line, *proc, endpoint); - failed = 1; - } else if(fproc[*proc].fp_endpoint != endpoint) { - printf("FS:%s:%d: proc (%d) from endpoint (%d) doesn't match " - "known endpoint (%d)\n", - file, line, *proc, endpoint, fproc[*proc].fp_endpoint); - failed = 1; - } + int failed = 0; + *proc = _ENDPOINT_P(endpoint); + if(*proc < 0 || *proc >= NR_PROCS) { + printf("FS:%s:%d: proc (%d) from endpoint (%d) out of range\n", + file, line, *proc, endpoint); + failed = 1; + } else if(fproc[*proc].fp_endpoint != endpoint) { + printf("FS:%s:%d: proc (%d) from endpoint (%d) doesn't match " + "known endpoint (%d)\n", + file, line, *proc, endpoint, fproc[*proc].fp_endpoint); + failed = 1; + } - if(failed && fatal) - panic(__FILE__, "isokendpt_f failed", NO_NUM); + if(failed && fatal) + panic(__FILE__, "isokendpt_f failed", NO_NUM); - return failed ? EDEADSRCDST : OK; + return failed ? EDEADSRCDST : 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 k; + clock_t uptime; + + if ( (k=getuptime(&uptime)) != OK) panic(__FILE__,"clock_time err", k); + return( (time_t) (boottime + (uptime/HZ))); +} + + diff --git a/servers/vfs/vmnt.c b/servers/vfs/vmnt.c new file mode 100644 index 000000000..9b92743b0 --- /dev/null +++ b/servers/vfs/vmnt.c @@ -0,0 +1,37 @@ +/* Virtual mount table related routines. + * + * Jul 2006 (Balazs Gerofi) + */ + +#include "fs.h" +#include "vmnt.h" + + +/*===========================================================================* + * get_free_vmnt * + *===========================================================================*/ +PUBLIC struct vmnt *get_free_vmnt(short *index) +{ + struct vmnt *vp; + *index = 0; + for (vp = &vmnt[0]; vp < &vmnt[NR_MNTS]; ++vp, ++(*index)) { + if (vp->m_dev == NO_DEV) return vp; + } + + return NIL_VMNT; +} + +/*===========================================================================* + * find_vmnt * + *===========================================================================*/ +PUBLIC struct vmnt *find_vmnt(int fs_e) +{ + struct vmnt *vp; + for (vp = &vmnt[0]; vp < &vmnt[NR_MNTS]; ++vp) { + if (vp->m_fs_e == fs_e) return vp; + } + + return NIL_VMNT; +} + + diff --git a/servers/vfs/vmnt.h b/servers/vfs/vmnt.h new file mode 100644 index 000000000..f1916fcdb --- /dev/null +++ b/servers/vfs/vmnt.h @@ -0,0 +1,14 @@ + + +EXTERN struct vmnt { + int m_fs_e; /* FS process' kernel endpoint */ + dev_t m_dev; /* device number */ + int m_driver_e; /* device driver process' kernel endpoint */ + int m_flags; /* mount flags */ + int m_max_file_size; /* maximum file size on partition */ + unsigned short m_block_size; /* block size */ + struct vnode *m_mounted_on; /* the vnode on which the partition is mounted */ + struct vnode *m_root_node; /* root vnode */ +} vmnt[NR_MNTS]; + +#define NIL_VMNT (struct vmnt *) 0 diff --git a/servers/vfs/vnode.c b/servers/vfs/vnode.c new file mode 100644 index 000000000..0646bc4c7 --- /dev/null +++ b/servers/vfs/vnode.c @@ -0,0 +1,161 @@ + +/* 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) + * + * Jul 2006 (Balazs Gerofi) + */ +#include "fs.h" +#include "vnode.h" +#include "vmnt.h" + +#include + +/*===========================================================================* + * get_vnode * + *===========================================================================*/ +PUBLIC struct vnode *get_vnode(int fs_e, int inode_nr) +{ +/* get_vnode() is called to get the details of the specified inode. + * Note that inode's usage counter in the FS is supposed to be incremented. + */ + struct vnode *vp, *vp2; + struct vmnt *vmp; + + /* Request & response structures */ + struct node_req req; + struct node_details res; + + /* Check whether a free vnode is avaliable */ + if ((vp = get_free_vnode()) == NIL_VNODE) { + printf("VFSget_vnode: no vnode available\n"); + return NIL_VNODE; + } + + /* Fill req struct */ + req.inode_nr = inode_nr; + req.fs_e = fs_e; + + /* Send request to FS */ + if (req_getnode(&req, &res) != OK) { + printf("VFSget_vnode: couldn't find vnode\n"); + return NIL_VNODE; + } + + /* Fill in the free vnode's fields and return it */ + 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_sdev = res.dev; + + /* Find corresponding virtual mount object */ + if ( (vmp = find_vmnt(vp->v_fs_e)) == NIL_VMNT) + printf("VFS: vmnt not found by get_vnode()\n"); + + vp->v_vmnt = vmp; + vp->v_dev = vmp->m_dev; + vp->v_count = 1; + + return vp; +} + + +/*===========================================================================* + * get_free_vnode * + *===========================================================================*/ +PUBLIC struct vnode *get_free_vnode() +{ +/* Find a free vnode slot in the vnode table */ + struct vnode *vp; + + for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; ++vp) + if (vp->v_count == 0) return vp; + + err_code = ENFILE; + return NIL_VNODE; +} + +/*===========================================================================* + * find_vnode * + *===========================================================================*/ +PUBLIC struct vnode *find_vnode(int fs_e, int numb) +{ +/* 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_count > 0 && vp->v_inode_nr == numb + && vp->v_fs_e == fs_e) return vp; + + return NIL_VNODE; +} + + +/*===========================================================================* + * dup_vnode * + *===========================================================================*/ +PUBLIC void dup_vnode(struct vnode *vp) +{ +/* dup_vnode() is called to increment the vnode and therefore the + * referred inode's counter. + */ + struct node_req req; + struct node_details res; + + if (vp == NIL_VNODE) { + printf("VFSdup_vnode NIL_VNODE\n"); + return; + } + + /* Fill req struct */ + req.inode_nr = vp->v_inode_nr; + req.fs_e = vp->v_fs_e; + + /* Send request to FS */ + if (req_getnode(&req, &res) != OK) + printf("VFSdup_vnode Warning: inode doesn't exist\n"); + else + vp->v_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. + */ + struct node_req req; + + if (vp == NIL_VNODE) { + /*printf("VFSput_vnode NIL_VNODE\n");*/ + return; + } + + /* Fill in request fields */ + req.fs_e = vp->v_fs_e; + req.inode_nr = vp->v_inode_nr; + + /* Send request */ + if (req_putnode(&req) == OK) { + /* Decrease counter */ + if (--vp->v_count == 0) { + vp->v_pipe = NO_PIPE; + vp->v_sdev = NO_DEV; + vp->v_index = 0; + } + } + else + printf("VFSput_vnode Warning: inode doesn't exist\n"); +} + + diff --git a/servers/vfs/vnode.h b/servers/vfs/vnode.h new file mode 100644 index 000000000..afd8565fb --- /dev/null +++ b/servers/vfs/vnode.h @@ -0,0 +1,34 @@ + + +EXTERN struct vnode { + endpoint_t v_fs_e; /* FS process' endpoint number */ + ino_t v_inode_nr; /* inode number on its (minor) device */ + mode_t v_mode; /* file type, protection, etc. */ + off_t v_size; /* current file size in bytes */ + int v_count; /* # times vnode used; 0 means slot is free */ + 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 */ + int v_blocksize; /* block size of the filesys */ + unsigned short v_index; /* inode's index in the FS inode table */ + struct vmnt *v_vmnt; /* vmnt object of the partition */ +} vnode[NR_VNODES]; + +#define NIL_VNODE (struct vnode *) 0 /* indicates absence of vnode slot */ + +/* Field values. Note that CLEAN and DIRTY are defined in "const.h" */ +#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 */ +#define NO_MOUNT 0 /* i_mount is NO_MOUNT if file not mounted on*/ +#define I_MOUNT 1 /* i_mount is I_MOUNT if file mounted on */ +#define NO_SEEK 0 /* i_seek = NO_SEEK if last op was not SEEK */ +#define ISEEK 1 /* i_seek = ISEEK if last op was SEEK */ + + diff --git a/servers/vfs/write.c b/servers/vfs/write.c new file mode 100644 index 000000000..4a8390b40 --- /dev/null +++ b/servers/vfs/write.c @@ -0,0 +1,22 @@ +/* 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 +#include "file.h" +#include "fproc.h" + + +/*===========================================================================* + * do_write * + *===========================================================================*/ +PUBLIC int do_write() +{ +/* Perform the write(fd, buffer, nbytes) system call. */ + return(read_write(WRITING)); +} + diff --git a/tools/Makefile b/tools/Makefile index 2b5537681..9d3d2ba83 100755 --- a/tools/Makefile +++ b/tools/Makefile @@ -8,12 +8,13 @@ MDEC= /usr/mdec # Specify the programs that are part of the system image. PROGRAMS= ../kernel/kernel \ ../servers/pm/pm \ - ../servers/fs/fs \ + ../servers/vfs/vfs \ ../servers/rs/rs \ ../servers/ds/ds \ ../drivers/tty/tty \ ../drivers/memory/memory \ ../drivers/log/log \ + ../servers/mfs/mfs \ ../servers/init/init usage: