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
#include <minix/const.h>
#include <minix/type.h>
-#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"
#include <minix/const.h>
#include <minix/type.h>
-#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 <minix/fslib.h>
#include "de.h"
#include <minix/const.h>
#include <minix/type.h>
-#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 <minix/fslib.h>
#include "de.h"
#include <minix/config.h>
#include <minix/const.h>
-#include "../../servers/fs/const.h"
-#include "../../servers/fs/inode.h"
+#include "../../servers/mfs/const.h"
+#include "../../servers/mfs/inode.h"
#include "de.h"
#include <minix/const.h>
#include <minix/type.h>
-#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 <minix/fslib.h>
#include "de.h"
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
#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 ------*/
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: diff.c
$(CCLD) -o $@ $?
- @install -S 40kw $@
+ @install -S 512kw $@
dirname: dirname.c
$(CCLD) -o $@ $?
#include <dirent.h>
#include <stdlib.h>
-#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 <string.h>
#include <stdio.h>
#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));
#include <string.h>
#include <unistd.h>
-#include "../../servers/fs/const.h"
+#include "../../servers/vfs/const.h"
char pvd[CD_SECTOR];
#include <minix/config.h>
#include <minix/const.h>
#include <minix/type.h>
-#include <servers/fs/const.h>
-#include <servers/fs/type.h>
-#include <servers/fs/super.h>
+#include <servers/mfs/const.h>
+#include <servers/mfs/type.h>
+#include <servers/mfs/super.h>
#undef printf
#if !__minix_vmd
#include <minix/config.h>
#include <minix/const.h>
#include <minix/type.h>
-#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 <minix/fslib.h>
#include <stdio.h>
#include <sys/stat.h>
#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 */
#include <minix/config.h>
#include <minix/const.h>
#include <minix/type.h>
-#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 <minix/fslib.h>
#include <stdio.h>
#include <dirent.h>
#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 */
#include <minix/const.h>
#include <minix/type.h>
#include <minix/minlib.h>
-#include "../../servers/fs/const.h"
+#include "../../servers/mfs/const.h"
#if (MACHINE == IBM_PC)
#include <minix/partition.h>
#include <minix/u64.h>
#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 <minix/fslib.h>
#ifndef max
#include <minix/u64.h>
#include <minix/partition.h>
#include <minix/swap.h>
-#include <servers/fs/const.h>
-#include <servers/fs/type.h>
-#include <servers/fs/super.h>
+#include <servers/mfs/const.h>
+#include <servers/mfs/type.h>
+#include <servers/mfs/super.h>
static void usage(void)
{
#include <minix/swap.h>
#include <sys/svrctl.h>
#include <stdio.h>
-#include "../../servers/fs/const.h"
+#include "../../servers/vfs/const.h"
_PROTOTYPE(int main, (int argc, char **argv));
_PROTOTYPE(void list, (void));
#include <minix/config.h>
#include <minix/const.h>
#include <minix/type.h>
-#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 <stdio.h>
/* 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 */
# 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
../../../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
boot
-200 250
+210 250
d--755 0 0
bin d--755 0 0
at_wini ---755 0 0 at_wini
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@
#!/bin/sh
+PATH=/bin:/sbin:/usr/bin:/usr/sbin
sed -n '1,/@DEV/p' <proto | grep -v @DEV@
(
cd /dev
#define LOG_PROC_NR 4 /* log device driver */
#define TTY_PROC_NR 5 /* terminal (TTY) driver */
#define DS_PROC_NR 6 /* data store server */
-#define INIT_PROC_NR 7 /* init -- goes multiuser */
+#define MFS_PROC_NR 7 /* minix root filesystem */
+#define INIT_PROC_NR 8 /* init -- goes multiuser */
/* Number of processes contained in the system image. */
#define NR_BOOT_PROCS (NR_TASKS + INIT_PROC_NR + 1)
# define RS_PERIOD m1_i2 /* heartbeat period */
# define RS_DEV_MAJOR m1_i3 /* major device number */
+# define RS_ENDPOINT m1_i1 /* endpoint number in reply */
+
/*===========================================================================*
* Messages for the Data Store Server *
*===========================================================================*/
#define M3_STRING 14
typedef struct {int m1i1, m1i2, m1i3; char *m1p1, *m1p2, *m1p3;} mess_1;
-typedef struct {int m2i1, m2i2, m2i3; long m2l1, m2l2; char *m2p1;} mess_2;
+typedef struct {int m2i1, m2i2, m2i3; long m2l1, m2l2; char *m2p1;
+ short m2s1;} mess_2;
typedef struct {int m3i1, m3i2; char *m3p1; char m3ca1[M3_STRING];} mess_3;
typedef struct {long m4l1, m4l2, m4l3, m4l4, m4l5;} mess_4;
typedef struct {short m5c1, m5c2; int m5i1, m5i2; long m5l1, m5l2, m5l3;}mess_5;
+typedef struct {long m6l1, m6l2, m6l3; short m6s1, m6s2, m6s3; char m6c1, m6c2;
+ char *m6p1, *m6p2;} mess_6;
typedef struct {int m7i1, m7i2, m7i3, m7i4; char *m7p1, *m7p2;} mess_7;
typedef struct {int m8i1, m8i2; char *m8p1, *m8p2, *m8p3, *m8p4;} mess_8;
mess_5 m_m5;
mess_7 m_m7;
mess_8 m_m8;
+ mess_6 m_m6;
} m_u;
} message;
#define m2_l2 m_u.m_m2.m2l2
#define m2_p1 m_u.m_m2.m2p1
+#define m2_s1 m_u.m_m2.m2s1
+
#define m3_i1 m_u.m_m3.m3i1
#define m3_i2 m_u.m_m3.m3i2
#define m3_p1 m_u.m_m3.m3p1
#define m5_l2 m_u.m_m5.m5l2
#define m5_l3 m_u.m_m5.m5l3
+#define m6_l1 m_u.m_m6.m6l1
+#define m6_l2 m_u.m_m6.m6l2
+#define m6_l3 m_u.m_m6.m6l3
+#define m6_s1 m_u.m_m6.m6s1
+#define m6_s2 m_u.m_m6.m6s2
+#define m6_s3 m_u.m_m6.m6s3
+#define m6_c1 m_u.m_m6.m6c1
+#define m6_c2 m_u.m_m6.m6c2
+#define m6_p1 m_u.m_m6.m6p1
+#define m6_p2 m_u.m_m6.m6p2
+
#define m7_i1 m_u.m_m7.m7i1
#define m7_i2 m_u.m_m7.m7i2
#define m7_i3 m_u.m_m7.m7i3
_PROTOTYPE( int echo, (message *m_ptr) );
_PROTOTYPE( int notify, (endpoint_t dest) );
_PROTOTYPE( int sendrec, (endpoint_t src_dest, message *m_ptr) );
-_PROTOTYPE( int receive, (endpoint_t src, message *m_ptr) );
+_PROTOTYPE( int receive, (endpoint_t src, message *m_ptr) );
_PROTOTYPE( int send, (endpoint_t dest, message *m_ptr) );
#define ipc_request _ipc_request
--- /dev/null
+
+/* Fields of VFS/FS request messages */
+#define REQ_INODE_NR m6_l1
+#define REQ_CHROOT_NR m6_l2
+#define REQ_UID m6_s1
+#define REQ_GID m6_c1
+#define REQ_MODE m6_s3
+#define REQ_PATH m6_p1
+#define REQ_PATH_LEN m6_s2
+#define REQ_FLAGS m6_l3
+#define REQ_DEV m6_l3
+#define REQ_WHO_E m6_l3
+#define REQ_USER_ADDR m6_p2
+#define REQ_LENGTH m6_l3
+#define REQ_SYMLOOP m6_c2
+
+#define REQ_NEW_UID m6_s3
+#define REQ_NEW_GID m6_c2
+
+#define REQ_INODE_INDEX m6_l3
+
+#define REQ_ACTIME m6_l2
+#define REQ_MODTIME m6_l3
+
+#define REQ_VMNT_IND m6_c2
+#define REQ_SLINK_STORAGE m6_p1
+#define REQ_BOOTTIME m6_l1
+#define REQ_DRIVER_E m6_l2
+#define REQ_READONLY m6_c1
+#define REQ_ISROOT m6_c2
+
+#define REQ_REMOUNT m6_c2
+
+#define REQ_LINKED_FILE m6_l1
+#define REQ_LINK_PARENT m6_l2
+
+#define REQ_OLD_DIR m6_l2
+#define REQ_NEW_DIR m6_l3
+#define REQ_SLENGTH m6_s3
+
+#define REQ_PIPE_POS m6_l1
+
+#define REQ_FD_INODE_NR m2_i1
+#define REQ_FD_WHO_E m2_i2
+#define REQ_FD_POS m2_i3
+#define REQ_FD_NBYTES m2_l1
+#define REQ_FD_SEG m2_l2
+#define REQ_FD_INODE_INDEX m2_s1
+
+#define REQ_FD_USER_ADDR m2_p1
+#define REQ_FD_LENGTH m2_i2
+#define REQ_FD_START m2_i2
+#define REQ_FD_END m2_i3
+
+#define REQ_FD_BLOCK_SIZE m2_s1
+#define REQ_FD_BDRIVER_E m2_i1
+#define REQ_FD_BDEV m2_l2
+
+/* Fields of VFS/FS respons messages */
+#define RES_MOUNTED m6_s1
+#define RES_OFFSET m6_s2
+#define RES_INODE_NR m6_l1
+#define RES_MODE m6_s1
+#define RES_FILE_SIZE m6_l2
+#define RES_DEV m6_l3
+#define RES_POS m6_l3
+#define RES_INODE_INDEX m6_s2
+#define RES_NLINKS m6_s3
+#define RES_SYMLOOP m6_c1
+
+#define RES_UID m6_s3
+#define RES_GID m6_c1
+#define RES_CTIME m6_l3
+
+#define RES_FD_POS m2_i1
+#define RES_FD_CUM_IO m2_i2
+#define RES_FD_SIZE m2_i3
+
+#define RES_DIR m6_l1
+#define RES_FILE m6_l2
+
+#define RES_MAXSIZE m6_l3
+#define RES_BLOCKSIZE m6_s2
+
+
+/* Request numbers (offset in the fs callvector) */
+#define REQ_GETNODE 1
+#define REQ_PUTNODE 2
+#define REQ_OPEN 3
+#define REQ_PIPE 4
+#define REQ_READ 5
+#define REQ_WRITE 6
+#define REQ_CLONE_OPCL 7
+#define REQ_FTRUNC 8
+
+#define REQ_CHOWN 9
+#define REQ_CHMOD 10
+#define REQ_ACCESS 11
+#define REQ_MKNOD 12
+#define REQ_MKDIR 13
+#define REQ_INHIBREAD 14
+#define REQ_STAT 15
+#define REQ_FSTAT 16
+#define REQ_UNLINK 17
+#define REQ_RMDIR 18
+#define REQ_UTIME 19
+#define REQ_FSTATFS 20
+#define REQ_LSTAT 21 /* NO POINT !!! */
+#define REQ_GETDIR 22
+
+#define REQ_LINK 25
+
+#define REQ_SLINK 26
+#define REQ_RDLINK 27
+
+#define REQ_RENAME 28
+
+#define REQ_MOUNTPOINT 30
+#define REQ_READSUPER 31
+#define REQ_UNMOUNT 32
+#define REQ_TRUNC 33
+#define REQ_SYNC 34
+
+#define REQ_LOOKUP 35
+#define REQ_STIME 36
+#define REQ_NEW_DRIVER 37
+
+#define REQ_BREAD 38
+#define REQ_BWRITE 39
+
+#define NREQS 40
+
+#define FS_READY 57
+
+#define EENTERMOUNT 301
+#define ELEAVEMOUNT 302
+#define ESYMLINK 303
+
+
+
+
+
+
+
+
+
{SYSTEM, sys_task,TSK_F, 8, TASK_Q, TSK_S, TSK_T, 0, no_c,"system"},
{HARDWARE, 0,TSK_F, 8, TASK_Q, HRD_S, 0, 0, no_c,"kernel"},
{PM_PROC_NR, 0,SRV_F, 32, 3, 0, SRV_T, SRV_M, c(pm_c),"pm" },
-{FS_PROC_NR, 0,SRV_F, 32, 4, 0, SRV_T, SRV_M, c(fs_c),"fs" },
+{FS_PROC_NR, 0,SRV_F, 32, 4, 0, SRV_T, SRV_M, c(fs_c),"vfs" },
{RS_PROC_NR, 0,SRV_F, 4, 3, 0, SRV_T, SYS_M, c(rs_c),"rs" },
{DS_PROC_NR, 0,SRV_F, 4, 3, 0, SRV_T, SYS_M, c(ds_c),"ds" },
{TTY_PROC_NR, 0,SRV_F, 4, 1, 0, SRV_T, SYS_M,c(tty_c),"tty" },
{MEM_PROC_NR, 0,SRV_F, 4, 2, 0, SRV_T, SYS_M,c(mem_c),"memory"},
{LOG_PROC_NR, 0,SRV_F, 4, 2, 0, SRV_T, SYS_M,c(drv_c),"log" },
+{MFS_PROC_NR, 0,SRV_F, 32, 4, 0, SRV_T, SRV_M, c(fs_c),"mfs" },
{INIT_PROC_NR, 0,USR_F, 8, USER_Q, 0, USR_T, USR_M, no_c,"init" },
};
#endif
#include <stdlib.h>
#include <signal.h>
+#include <limits.h>
extern pid_t _fork(void);
extern pid_t _wait(int *);
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 */
#include <sys/types.h>
#include <minix/const.h>
#include <minix/type.h> /* 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 <minix/fslib.h>
/* The next routine is copied from fsck.c and mkfs.c... (Re)define some
#include <unistd.h>
#include <stdio.h>
-#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;
+
#include <lib.h>
#define mount _mount
#include <string.h>
#include <unistd.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <minix/syslib.h>
+
+#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;
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) $@
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
+++ /dev/null
-/* 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 <minix/com.h>
-#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 */
+++ /dev/null
-/* 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 <fcntl.h>
-#include <string.h>
-#include <minix/com.h>
-#include <sys/stat.h>
-#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; i<NR_PROCS; i++, tfp++)
- {
- if (tfp->fp_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);
-}
+++ /dev/null
-/* 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 <sys/stat.h>
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h>
-#include <minix/callnr.h>
-#include <minix/com.h>
-#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);
-}
-
+++ /dev/null
-/* 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 <sys/stat.h>
-#include <sys/statfs.h>
-#include <minix/com.h>
-#include <string.h>
-#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);
-}
-
*/
#include "inc.h"
-#include "../fs/const.h"
-#include "../fs/fproc.h"
+#include "../mfs/const.h"
+#include "../vfs/fproc.h"
#include <minix/dmap.h>
PUBLIC struct fproc fproc[NR_PROCS];
--- /dev/null
+# 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
+
+
#include "fs.h"
#include <minix/com.h>
#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 *
*===========================================================================*/
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. */
/* This block is not the one sought. */
bp = bp->b_hash; /* move to next block on hash chain */
}
-
}
}
} 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.
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.
*/
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 */
* 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;
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 */
-
- /* Report read errors to interested parties. */
- if (rw_flag == READING) rdwt_err = r;
- }
+ 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;
+ }
}
bp->b_dirt = CLEAN;
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.
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; i<NR_BUFS; i++)
- {
- bp= &buf[i];
- nbp= bp->b_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<NR_BUFS; i++)
- {
- bp= &buf[i];
- while (bp)
- {
- if (bp < buf || bp >= &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<NR_BUF_HASH; i++)
- {
- bp= buf_hash[i];
- while (bp)
- {
- if (bp < buf || bp >= &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
--- /dev/null
+/* 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<<INODE_HASH_LOG2)
+#define INODE_HASH_MASK (((unsigned long)1<<INODE_HASH_LOG2)-1)
+
+
+/* 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.
+ */
+#define usizeof(t) ((unsigned) sizeof(t))
+
+/* File system types. */
+#define SUPER_MAGIC 0x137F /* magic number contained in super-block */
+#define SUPER_REV 0x7F13 /* magic # when 68000 disk read on PC or vv */
+#define SUPER_V2 0x2468 /* magic # for V2 file systems */
+#define SUPER_V2_REV 0x6824 /* V2 magic written on PC, read on 68K or vv */
+#define SUPER_V3 0x4d5a /* magic # for V3 file systems */
+
+#define V1 1 /* version number of V1 file systems */
+#define V2 2 /* version number of V2 file systems */
+#define V3 3 /* version number of V3 file systems */
+
+/* Miscellaneous constants */
+#define SU_UID ((uid_t) 0) /* super_user's uid_t */
+#define SERVERS_UID ((uid_t) 11) /* who may do FSSIGNON */
+#define SYS_UID ((uid_t) 0) /* uid_t for processes MM and INIT */
+#define SYS_GID ((gid_t) 0) /* gid_t for processes MM and INIT */
+#define NORMAL 0 /* forces get_block to do disk read */
+#define NO_READ 1 /* prevents get_block from doing disk read */
+#define PREFETCH 2 /* tells get_block not to read or mark dev */
+
+#define XPIPE (-NR_TASKS-1) /* used in fp_task when susp'd on pipe */
+#define XLOCK (-NR_TASKS-2) /* used in fp_task when susp'd on lock */
+#define XPOPEN (-NR_TASKS-3) /* used in fp_task when susp'd on pipe open */
+#define XSELECT (-NR_TASKS-4) /* used in fp_task when susp'd on select */
+
+#define NO_BIT ((bit_t) 0) /* returned by alloc_bit() to signal failure */
+
+#define DUP_MASK 0100 /* mask to distinguish dup2 from dup */
+
+#define LOOK_UP 0 /* tells search_dir to lookup string */
+#define ENTER 1 /* tells search_dir to make dir entry */
+#define DELETE 2 /* tells search_dir to delete entry */
+#define IS_EMPTY 3 /* tells search_dir to ret. OK or ENOTEMPTY */
+
+/* write_map() args */
+#define WMAP_FREE (1 << 0)
+
+#define PATH_TRANSPARENT 000 /* parse_path stops at final object */
+#define PATH_PENULTIMATE 001 /* parse_path stops at last but one name */
+#define PATH_OPAQUE 002 /* parse_path stops at final name */
+#define PATH_NONSYMBOLIC 004 /* parse_path scans final name if symbolic */
+#define PATH_STRIPDOT 010 /* parse_path strips /. from path */
+#define EAT_PATH PATH_TRANSPARENT
+#define EAT_PATH_OPAQUE PATH_OPAQUE
+#define LAST_DIR PATH_PENULTIMATE
+#define LAST_DIR_NOTDOT PATH_PENULTIMATE | PATH_STRIPDOT
+#define LAST_DIR_EATSYM PATH_NONSYMBOLIC
+#define SYMLOOP 16
+
+#define CLEAN 0 /* disk and memory copies identical */
+#define DIRTY 1 /* disk and memory copies differ */
+#define ATIME 002 /* set if atime field needs updating */
+#define CTIME 004 /* set if ctime field needs updating */
+#define MTIME 010 /* set if mtime field needs updating */
+
+#define BYTE_SWAP 0 /* tells conv2/conv4 to swap bytes */
+
+#define END_OF_FILE (-104) /* eof detected */
+
+#define ROOT_INODE 1 /* inode number for root directory */
+#define BOOT_BLOCK ((block_t) 0) /* block number of boot block */
+#define SUPER_BLOCK_BYTES (1024) /* bytes offset */
+#define START_BLOCK 2 /* first block of FS (not counting SB) */
+
+#define DIR_ENTRY_SIZE usizeof (struct direct) /* # bytes/dir entry */
+#define NR_DIR_ENTRIES(b) ((b)/DIR_ENTRY_SIZE) /* # dir entries/blk */
+#define SUPER_SIZE usizeof (struct super_block) /* super_block size */
+#define PIPE_SIZE(b) (V1_NR_DZONES*(b)) /* pipe size in bytes */
+
+#define FS_BITMAP_CHUNKS(b) ((b)/usizeof (bitchunk_t))/* # map chunks/blk */
+#define FS_BITCHUNK_BITS (usizeof(bitchunk_t) * CHAR_BIT)
+#define FS_BITS_PER_BLOCK(b) (FS_BITMAP_CHUNKS(b) * FS_BITCHUNK_BITS)
+
+/* Derived sizes pertaining to the V1 file system. */
+#define V1_ZONE_NUM_SIZE usizeof (zone1_t) /* # bytes in V1 zone */
+#define V1_INODE_SIZE usizeof (d1_inode) /* bytes in V1 dsk ino */
+
+/* # zones/indir block */
+#define V1_INDIRECTS (_STATIC_BLOCK_SIZE/V1_ZONE_NUM_SIZE)
+
+/* # V1 dsk inodes/blk */
+#define V1_INODES_PER_BLOCK (_STATIC_BLOCK_SIZE/V1_INODE_SIZE)
+
+/* Derived sizes pertaining to the V2 file system. */
+#define V2_ZONE_NUM_SIZE usizeof (zone_t) /* # bytes in V2 zone */
+#define V2_INODE_SIZE usizeof (d2_inode) /* bytes in V2 dsk ino */
+#define V2_INDIRECTS(b) ((b)/V2_ZONE_NUM_SIZE) /* # zones/indir block */
+#define V2_INODES_PER_BLOCK(b) ((b)/V2_INODE_SIZE)/* # V2 dsk inodes/blk */
--- /dev/null
+
+#include "fs.h"
+#include <fcntl.h>
+#include <assert.h>
+#include <minix/callnr.h>
+#include <minix/com.h>
+#include <minix/endpoint.h>
+#include <minix/ioctl.h>
+#include <minix/safecopies.h>
+#include <string.h>
+#include "inode.h"
+#include "super.h"
+#include "const.h"
+#include "drivers.h"
+
+#include <minix/vfsif.h>
+
+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);
+}
+
+
+
+
+
+
+
+
--- /dev/null
+
+/* 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];
+
+
--- /dev/null
+/* 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 */
+
+
+
--- /dev/null
+
+#define _SYSTEM 1 /* get OK and negative error codes */
+#define _MINIX 1 /* tell headers to include MINIX stuff */
+
+#define VERBOSE 0 /* display diagnostics */
+
+#include <ansi.h>
+#include <sys/types.h>
+#include <limits.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <minix/callnr.h>
+#include <minix/config.h>
+#include <minix/type.h>
+#include <minix/const.h>
+#include <minix/com.h>
+#include <minix/syslib.h>
+#include <minix/sysutil.h>
+#include <minix/keymap.h>
+#include <minix/bitmap.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "proto.h"
+
#include "fs.h"
#include "buf.h"
-#include "file.h"
-#include "fproc.h"
#include "inode.h"
#include "super.h"
+#include <minix/vfsif.h>
+
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 *
*===========================================================================*/
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;
-
- /* 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 */
- }
+ int hashi;
+
+ 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);
+
+ /* 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);
+
+ /* 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;
- /* 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 */
+ hashi = numb & INODE_HASH_MASK;
- return(xp);
+ /* 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 *
*===========================================================================*/
*/
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. */
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 *
*===========================================================================*/
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 */
/* 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*/
--- /dev/null
+/* 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 */
-/* 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 <sys/stat.h>
#include <string.h>
#include <minix/com.h>
#include <minix/callnr.h>
+
#include "buf.h"
-#include "file.h"
-#include "fproc.h"
#include "inode.h"
-#include "param.h"
#include "super.h"
+#include <minix/vfsif.h>
+
#define SAME 1000
FORWARD _PROTOTYPE( int remove_dir, (struct inode *rldirp, struct inode *rip,
#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. */
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))
/* 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) {
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) {
}
}
- /* 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);
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;
/* 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 */
}
return(r);
}
+
+
/*===========================================================================*
- * do_rename *
+ * fs_rdlink *
*===========================================================================*/
-PUBLIC int do_rename()
+PUBLIC int fs_rdlink()
{
-/* Perform the rename(name1, name2) system call. */
+ 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;
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)
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. */
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;
+ }
}
}
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 */
-
- 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);
+ 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);
- 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 *
*===========================================================================*/
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);
-}
--- /dev/null
+
+#include "inc.h"
+#include <minix/dmap.h>
+#include <minix/endpoint.h>
+
+#include <minix/vfsif.h>
+#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;
+ }
+}
+
+
+
--- /dev/null
+
+#include "fs.h"
+#include <fcntl.h>
+
+#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 */
+}
+
+
--- /dev/null
+
+
+#include "fs.h"
+#include <fcntl.h>
+#include <string.h>
+#include <minix/com.h>
+#include <sys/stat.h>
+#include "buf.h"
+#include "inode.h"
+#include "super.h"
+#include "drivers.h"
+#include <minix/vfsif.h>
+
+
+
+
+
+/*===========================================================================*
+ * 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;
+}
+
+
+
--- /dev/null
+
+
+#include "fs.h"
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <minix/callnr.h>
+#include <minix/com.h>
+#include "buf.h"
+#include "inode.h"
+#include "super.h"
+
+#include <minix/vfsif.h>
+
+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;
+}
+
#include "fs.h"
#include <string.h>
#include <minix/callnr.h>
+#include <minix/endpoint.h>
#include <sys/stat.h>
#include "buf.h"
-#include "file.h"
-#include "fproc.h"
#include "inode.h"
#include "super.h"
+#include <minix/vfsif.h>
+
+
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 *
*/
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);
}
+ /* 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. */
/* 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);
+
+ /* 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) {
- err_code = ELOOP;
- put_inode(rip);
- rip = NIL_INODE;
+ 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;
}
}
-/*===========================================================================*
- * 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) {
/* 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 *
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,
* 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 *
*===========================================================================*/
if ( (ldir_ptr->i_mode & I_TYPE) != I_DIRECTORY) {
return(ENOTDIR);
}
-
+
r = OK;
if (flag != 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;
}
}
}
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);
+}
--- /dev/null
+
+#include "fs.h"
+#include <fcntl.h>
+#include <signal.h>
+#include <minix/callnr.h>
+#include <minix/endpoint.h>
+#include <minix/com.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include "inode.h"
+#include "super.h"
+
+#include <minix/vfsif.h>
+
+
+
+/*===========================================================================*
+ * 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;
+}
+
+
-/* 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 <unistd.h>
#include <minix/callnr.h>
#include "buf.h"
-#include "file.h"
-#include "fproc.h"
#include "inode.h"
-#include "param.h"
#include "super.h"
+#include <minix/vfsif.h>
+
+
/*===========================================================================*
- * 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);
}
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.
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);
}
if (rip != old_rip) put_inode(rip);
+/*printf("FSforbidden: %s %s\n", user_path, (r == OK ? "OK" : "notOK")); */
return(r);
}
sp = ip->i_sp;
return(sp->s_rd_only ? EROFS : OK);
}
+
+
+
#include "timers.h"
-#include <minix/safecopies.h>
-
/* 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) );
#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) );
_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) );
/* 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) );
/* 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]));
_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) );
_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) );
--- /dev/null
+
+#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 */
-/* 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 <fcntl.h>
#include <unistd.h>
#include <minix/com.h>
#include "buf.h"
-#include "file.h"
-#include "fproc.h"
#include "inode.h"
-#include "param.h"
#include "super.h"
+#include <minix/vfsif.h>
+
+
+
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;
- }
- op = (rw_flag == READING ? DEV_READ : DEV_WRITE);
- mode_word = rip->i_mode & I_TYPE;
- regular = mode_word == I_REGULAR || mode_word == I_NAMED_PIPE;
-
- 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]);
+
+ /* 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];
}
- 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]);
+ 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;
+ }
}
- if (!char_spec && !block_spec)
- block_size = rip->i_sp->s_block_size;
+ mode_word = rip->i_mode & I_TYPE;
+ 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);
+ 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 */
-
- /* 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);
-
- /* Check for O_APPEND flag. */
- if (oflags & O_APPEND) position = f_size;
-
- /* 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);
- }
-
- /* 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;
- }
- }
+
+ 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;
+
+ 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, seg, 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; /* 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;
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 *
*===========================================================================*/
*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;
}
/* 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.
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);
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;
}
rw_scattered(dev, read_q, read_q_size, READING);
return(get_block(dev, baseblock, NORMAL));
}
+
--- /dev/null
+
+
+#include "fs.h"
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <minix/com.h>
+#include <string.h>
+#include "buf.h"
+#include "inode.h"
+#include "super.h"
+
+#include <minix/vfsif.h>
+
+
+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);
+}
+
+
+
#include "super.h"
#include "const.h"
+
/*===========================================================================*
* alloc_bit *
*===========================================================================*/
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);
/*===========================================================================*
* mounted *
*===========================================================================*/
+/* Report on whether the given inode is on a mounted (or ROOT) file system. */
+/*
PUBLIC int mounted(rip)
-register struct inode *rip; /* pointer to inode */
+register struct inode *rip;
{
-/* Report on whether the given inode is on a mounted (or ROOT) file system. */
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 *
*===========================================================================*/
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));
version = V3;
native = 1;
} else {
+printf("MFSread_super invalid version\n");
return(EINVAL);
}
} 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) {
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;
}
--- /dev/null
+/* 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 */
--- /dev/null
+
+/* This file contains the table used to map system call numbers onto the
+ * routines that perform them.
+ */
+
+#define _TABLE
+
+#include "fs.h"
+#include <minix/callnr.h>
+#include <minix/com.h>
+#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 */
+};
+
--- /dev/null
+
+
+
+#include "fs.h"
+#include <minix/callnr.h>
+#include <minix/com.h>
+#include "inode.h"
+
+#include <minix/vfsif.h>
+
+
+/*===========================================================================*
+ * 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;
+}
+
--- /dev/null
+
+#include "fs.h"
+#include <sys/stat.h>
+#include <string.h>
+#include <minix/com.h>
+#include <minix/callnr.h>
+
+#include "buf.h"
+#include "inode.h"
+#include "super.h"
+
+#include <minix/vfsif.h>
+
+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)));
+}
+
+
+
/* This file is the counterpart of "read.c". It contains the code for writing
* insofar as this is not contained in read_write().
*
#include "fs.h"
#include <string.h>
#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 *
* 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;
memset(bp->b_data, 0, _MAX_BLOCK_SIZE);
bp->b_dirt = DIRTY;
}
+
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];
/* Finally send reply message, unless disabled. */
if (result != EDONTREPLY) {
- reply(who_e, result);
+ m.m_type = result;
+ reply(who_e, &m);
}
}
}
/*===========================================================================*
* 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);
}
+
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) );
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);
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;
}
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;
*/
/* 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;
}
{
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))
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
{
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");
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) {
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;
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; rp<END_RPROC_ADDR; rp++) {
if (rp->r_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;
}
}
/*===========================================================================*
* 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
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);
}
# Makefile for File System (FS)
-SERVER = fs
+SERVER = vfs
# directories
u = /usr
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)
--- /dev/null
+/* 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 <sys/dir.h> /* need struct direct */
+#include <dirent.h>
+
+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 */
#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.
* 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"
#include <minix/com.h>
#include <minix/endpoint.h>
#include <minix/ioctl.h>
-#include <sys/ioc_tty.h>
#include "file.h"
#include "fproc.h"
-#include "inode.h"
+
+#include <minix/vfsif.h>
+#include "vnode.h"
+#include "vmnt.h"
#include "param.h"
-#include "super.h"
#define ELEMENTS(a) (sizeof(a)/sizeof((a)[0]))
extern int dmap_size;
PRIVATE int dummyproc;
+
/*===========================================================================*
* dev_open *
*===========================================================================*/
return(r);
}
+
/*===========================================================================*
* dev_close *
*===========================================================================*/
/* 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;
- }
- }
-
- return NONE;
+ 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;
}
/*===========================================================================*
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.
*/
/* 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;
/* 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));
return OK;
}
+
/*===========================================================================*
* no_dev *
*===========================================================================*/
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 *
*===========================================================================*/
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;
-
- /* Device number of the new device. */
+ struct vnode *vp;
+ struct vmnt *vmp;
+
+ 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);
-
- 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);
+
+ /* Fill in request */
+ req.fs_e = ROOT_FS_E;
+ req.dev = dev;
+
+ /* 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;
-
- put_inode(fp->fp_filp[m_in.fd]->filp_ino);
- fp->fp_filp[m_in.fd]->filp_ino = ip;
+
+ vp->v_fs_e = res.fs_e;
+ if ((vmp = find_vmnt(vp->v_fs_e)) == NIL_VMNT)
+ printf("VFSclone_opcl: no vmnt found\n");
+
+ 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;
}
*===========================================================================*/
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;
-
- /* Open a device once for every filp that's opened on it,
- * and once for every filesystem mounted from it.
- */
-
- 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(fp = filp; fp < &filp[NR_FILPS]; fp++) {
- struct inode *in;
- int minor;
-
- 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);
-
- printf("FS: reopening special %d/%d..\n", maj, minor);
-
- 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);
- }
- }
-
- return;
+ /* 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.
+ */
+ new_driver_e = dmap[maj].dmap_driver;
+
+ 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);
+ }
+
+ /* 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;
+ }
+
+ for (fp = filp; fp < &filp[NR_FILPS]; fp++) {
+ struct vnode *vp;
+ int 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;
+
+ minor = ((vp->v_sdev >> MINOR) & BYTE);
+
+ 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;
}
*
* The entry points into this file are:
* pm_exec: perform the EXEC system call
+ *
+ * Changes for VFS:
+ * Aug 2006 (Balazs Gerofi)
*/
#include "fs.h"
#include <a.out.h>
#include <signal.h>
#include <string.h>
-#include "buf.h"
+#include <dirent.h>
#include "fproc.h"
-#include "inode.h"
#include "param.h"
-#include "super.h"
+
+#include "vnode.h"
+#include "vmnt.h"
+#include <minix/vfsif.h>
FORWARD _PROTOTYPE( int exec_newmem, (int proc_e, vir_bytes text_bytes,
vir_bytes data_bytes, vir_bytes bss_bytes, vir_bytes tot_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) );
* 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];
-
- static char mbuf[ARG_MAX]; /* buffer for stack and zeroes */
-
- 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 */
- }
-
- /* 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;
-
- 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';
-
-#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");
+ 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 */
+
+ /* 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? */
+
+ /* 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);
+ }
+
+ /* 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);
+
+ 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;
+
+
+ /* 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;
- }
-
- 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;
- }
- /* 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);
-
- off = hdrlen;
-
- /* 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);
-
- put_inode(rip);
-
- if (r != OK) return r;
-
- clo_exec(rfp);
-
- 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);
-
- return OK;
+ /* 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;
+ }
+
+ /* 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;
+
+ /* 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;
+ }
+ }
+
+ if (r != OK)
+ {
+ printf("pm_exec: returning ENOEXEC, r = %d\n", r);
+ return ENOEXEC;
+ }
+
+ 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;
+ }
+
+ /* 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);
+
+ off = hdrlen;
+
+ /* 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);
+
+ put_vnode(&vn);
+
+ if (r != OK) return r;
+
+ clo_exec(rfp);
+
+ 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 *
*===========================================================================*/
/*===========================================================================*
* 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 */
{
/* 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
* 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);
/*===========================================================================*
* 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 */
{
* 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);
-
- pos= 0; /* Read from the start of the file */
- b = read_map(rip, pos); /* get block number */
- if (b == 0) /* Hole */
- return ENOEXEC;
-
- 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 #! */
+ if (!insert_arg(stack, stk_bytes, user_fullpath, REPLACE)) return(ENOMEM);
+
+ pos = 0; /* Read from the start of the file */
+
+ /* 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);
/* 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);
}
/*===========================================================================*
* 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 */
* 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;
-
- 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);
-
- if (r != OK)
- return r;
-
- seg_off += n;
- }
-
- return OK;
+ 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;
+
+ /* 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");
+
+ return r;
}
}
+
--- /dev/null
+/* 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 */
#include "fs.h"
#include "file.h"
#include "fproc.h"
-#include "inode.h"
+
+#include "vnode.h"
/*===========================================================================*
* get_fd *
/*===========================================================================*
* 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
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);
}
}
*===========================================================================*/
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++;
- }
- }
- }
-
- return 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;
}
--- /dev/null
+#include <sys/select.h>
+#include <minix/safecopies.h>
+
+/* 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)
+
--- /dev/null
+/* 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 <minix/config.h> /* MUST be first */
+#include <ansi.h> /* MUST be second */
+#include <sys/types.h>
+#include <minix/const.h>
+#include <minix/type.h>
+#include <minix/dmap.h>
+
+#include <limits.h>
+#include <errno.h>
+
+#include <minix/syslib.h>
+#include <minix/sysutil.h>
+
+#include "const.h"
+#include "proto.h"
+#include "glo.h"
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. */
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 */
--- /dev/null
+/* 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 <sys/stat.h>
+#include <string.h>
+#include <minix/com.h>
+#include <minix/callnr.h>
+#include <dirent.h>
+#include "file.h"
+#include "fproc.h"
+#include "param.h"
+
+#include <minix/vfsif.h>
+#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);
+}
+
+
+
#include <unistd.h>
#include "file.h"
#include "fproc.h"
-#include "inode.h"
#include "lock.h"
#include "param.h"
+#include "vnode.h"
+
/*===========================================================================*
* lock_op *
*===========================================================================*/
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);
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. */
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;
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;
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++;
--- /dev/null
+/* 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];
* 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 <fcntl.h>
#include <string.h>
#include <minix/const.h>
#include <minix/endpoint.h>
#include <minix/safecopies.h>
-#include "buf.h"
#include "file.h"
#include "fproc.h"
-#include "inode.h"
#include "param.h"
-#include "super.h"
+
+#include <minix/vfsif.h>
+#include "vmnt.h"
+#include "vnode.h"
#if ENABLE_SYSCALL_STATS
EXTERN unsigned long calls_stats[NCALLS];
FORWARD _PROTOTYPE( void init_root, (void) );
FORWARD _PROTOTYPE( void service_pm, (void) );
+
/*===========================================================================*
* 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 */
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);
/* 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 */
}
}
-/*===========================================================================*
- * 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 *
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);
}
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.
} 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 */
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;
}
}
*===========================================================================*/
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;
}
/*===========================================================================*
PRIVATE void service_pm()
{
int r, call;
+ struct vmnt *vmp;
message m;
/* Ask PM for work until there is nothing left to do */
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;
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:
break;
default:
- panic("fs", "service_pm: unknown call", m.m_type);
+ panic("VFS", "service_pm: unknown call", m.m_type);
}
}
}
+
* 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
#include <minix/com.h>
#include <sys/ptrace.h>
#include <sys/svrctl.h>
-#include "buf.h"
#include "file.h"
#include "fproc.h"
-#include "inode.h"
#include "param.h"
-#include "super.h"
+
+#include <minix/vfsif.h>
+#include "vnode.h"
+#include "vmnt.h"
#define CORE_NAME "core"
#define CORE_MODE 0777 /* mode to use on core image files */
#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 *
*===========================================================================*/
return(m_in.fd2);
}
+
+
/*===========================================================================*
* 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. */
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;
}
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;
}
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:
}
}
+
/*===========================================================================*
* 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;
}
/*===========================================================================*
{
/* 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
/* 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();
}
/*===========================================================================*
/* 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;
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);
}
/*===========================================================================*
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' */
}
/* 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
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;
}
tfp->fp_realuid = ruid;
}
-
/*===========================================================================*
* do_svrctl *
*===========================================================================*/
}
}
-
/*===========================================================================*
* pm_dumpcore *
*===========================================================================*/
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;
-}
--- /dev/null
+/* 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 <fcntl.h>
+#include <string.h>
+#include <minix/callnr.h>
+#include <minix/com.h>
+#include <minix/keymap.h>
+#include <minix/const.h>
+#include <minix/endpoint.h>
+#include <minix/syslib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include "file.h"
+#include "fproc.h"
+#include "param.h"
+
+#include <minix/vfsif.h>
+#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; i<NR_PROCS; i++, tfp++) {
+ if (tfp->fp_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;
+}
+
+
--- /dev/null
+/* 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 <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <minix/callnr.h>
+#include <minix/com.h>
+#include "file.h"
+#include "fproc.h"
+#include "lock.h"
+#include "param.h"
+#include <dirent.h>
+
+#include <minix/vfsif.h>
+#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);
+}
+
+
--- /dev/null
+/* 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
--- /dev/null
+
+/* 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 <string.h>
+#include <minix/callnr.h>
+#include <minix/com.h>
+#include <minix/keymap.h>
+#include <minix/const.h>
+#include <minix/endpoint.h>
+#include <unistd.h>
+
+#include <minix/vfsif.h>
+#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;
+}
+
* 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"
#include <sys/time.h>
#include "file.h"
#include "fproc.h"
-#include "inode.h"
#include "param.h"
-#include "super.h"
#include "select.h"
+#include <minix/vfsif.h>
+#include "vnode.h"
+#include "vmnt.h"
+
+
+
+
/*===========================================================================*
* 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);
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;
+ }
+
+ /* 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;
}
- 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 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) */
/* 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;
}
/* 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);
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);
}
}
/* 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;
/*===========================================================================*
* 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 */
{
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;
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;
}
}
+
/*===========================================================================*
* do_unpause *
*===========================================================================*/
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;
return(OK);
}
+
/*===========================================================================*
* select_request_pipe *
*===========================================================================*/
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)
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;
}
+
+
+
--- /dev/null
+
+/* 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 <unistd.h>
+#include <minix/callnr.h>
+#include "file.h"
+#include "fproc.h"
+#include "param.h"
+
+#include <minix/vfsif.h>
+#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);
+}
+
--- /dev/null
+/* 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) );
+
--- /dev/null
+/* 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 <fcntl.h>
+#include <unistd.h>
+#include <minix/com.h>
+#include "file.h"
+#include "fproc.h"
+#include "param.h"
+#include <dirent.h>
+
+#include <minix/vfsif.h>
+#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
+
--- /dev/null
+
+/* 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 <string.h>
+#include <minix/callnr.h>
+#include <minix/com.h>
+#include <minix/keymap.h>
+#include <minix/const.h>
+#include <minix/endpoint.h>
+#include <unistd.h>
+
+#include <minix/vfsif.h>
+#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;
+}
+
+
+
--- /dev/null
+
+/* 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 <sys/types.h>
+
+
+/* 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 */
#include "fs.h"
#include "select.h"
#include "file.h"
-#include "inode.h"
+#include "vnode.h"
#include <sys/time.h>
#include <sys/select.h>
timer_t timer; /* if expiry > 0 */
} selecttab[MAXSELECTS];
-
FORWARD _PROTOTYPE(int select_reevaluate, (struct filp *fp));
FORWARD _PROTOTYPE(int select_request_file,
*===========================================================================*/
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;
}
{
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;
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;
*===========================================================================*/
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);
-
- /* 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);
+ 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;
+
+ 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;
}
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
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)) {
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);
}
--- /dev/null
+#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
+
--- /dev/null
+/* 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 <sys/stat.h>
+#include <sys/statfs.h>
+#include <minix/com.h>
+#include <string.h>
+#include "file.h"
+#include "fproc.h"
+#include "param.h"
+
+#include <minix/vfsif.h>
+#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);
+}
+
+
+
#include "fs.h"
#include <minix/callnr.h>
#include <minix/com.h>
-#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 */
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 */
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];
+
#include <minix/com.h>
#include "file.h"
#include "fproc.h"
-#include "inode.h"
#include "param.h"
+#include <minix/vfsif.h>
+#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;
}
--- /dev/null
+/* 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;
#include <minix/com.h>
#include <minix/endpoint.h>
#include <unistd.h>
-#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 *
*===========================================================================*/
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);
}
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);
}
/*===========================================================================*
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 *
+ * isokendpt_f *
*===========================================================================*/
-PUBLIC long conv4(norm, x)
-int norm; /* TRUE if no swap, FALSE for byte swap */
-long x; /* 32-bit long to be byte swapped */
+PUBLIC int isokendpt_f(char *file, int line, int endpoint, int *proc, int fatal)
{
-/* 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);
+ 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);
+
+ return failed ? EDEADSRCDST : OK;
}
/*===========================================================================*
- * isokendpt_f *
+ * clock_time *
*===========================================================================*/
-PUBLIC int isokendpt_f(char *file, int line, int endpoint, int *proc, int fatal)
+PUBLIC time_t clock_time()
{
- 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);
-
- return failed ? EDEADSRCDST : OK;
+/* 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)));
}
+
--- /dev/null
+/* 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;
+}
+
+
--- /dev/null
+
+
+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
--- /dev/null
+
+/* 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 <minix/vfsif.h>
+
+/*===========================================================================*
+ * 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");
+}
+
+
--- /dev/null
+
+
+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 */
+
+
--- /dev/null
+/* 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 <string.h>
+#include "file.h"
+#include "fproc.h"
+
+
+/*===========================================================================*
+ * do_write *
+ *===========================================================================*/
+PUBLIC int do_write()
+{
+/* Perform the write(fd, buffer, nbytes) system call. */
+ return(read_write(WRITING));
+}
+
# 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: