Merge of VFS by Balasz Gerofi with Minix trunk.

This commit is contained in:
Ben Gras 2006-10-25 13:40:36 +00:00
parent 21ed846479
commit fa0ba56bc9
116 changed files with 9042 additions and 3209 deletions

View file

@ -12,7 +12,7 @@ BIGFILES=#-D_FILE_OFFSET_BITS=64
CFLAGS=-Wall -Winline -O -g $(BIGFILES) -Dlstat=stat -D_POSIX_SOURCE=1
# Where you want it installed when you do 'make install'
PREFIX=/usr/local
PREFIX=/usr
PREFIX_BIN=$(PREFIX)/bin
PREFIX_LIB=$(PREFIX)/lib
PREFIX_MAN=$(PREFIX)/man

View file

@ -27,9 +27,9 @@
#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"

View file

@ -18,10 +18,10 @@
#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"

View file

@ -23,9 +23,9 @@
#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"

View file

@ -17,8 +17,8 @@
#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"

View file

@ -25,9 +25,9 @@
#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"

View file

@ -11,7 +11,7 @@ all: ps
ps: ps.c /usr/include/minix/config.h /usr/include/minix/const.h \
../../kernel/const.h ../../kernel/type.h \
../../kernel/proc.h ../../servers/pm/mproc.h \
../../servers/fs/fproc.h ../../servers/fs/const.h
../../servers/vfs/fproc.h ../../servers/mfs/const.h
$(CC) -i $(CFLAGS) -o $@ ps.c
install -S 32kw $@
install: /usr/bin/ps

View file

@ -81,8 +81,8 @@
#include "../../kernel/proc.h"
#include "../../servers/pm/mproc.h"
#include "../../servers/fs/fproc.h"
#include "../../servers/fs/const.h"
#include "../../servers/vfs/fproc.h"
#include "../../servers/mfs/const.h"
/*----- ps's local stuff below this line ------*/

View file

@ -13,6 +13,7 @@ TMPDIR=/usr/tmp/packages
mkdir -p $TMPDIR
URL1=http://www.minix3.org/packages/$PACKDIR
SRCURL1=http://www.minix3.org/software
PATH=/bin:/sbin:/usr/bin:/usr/sbin
# can we execute bunzip2?
if bunzip2 --help 2>&1 | grep usage >/dev/null

View file

@ -355,7 +355,7 @@ dhrystone: dhrystone.c
diff: diff.c
$(CCLD) -o $@ $?
@install -S 40kw $@
@install -S 512kw $@
dirname: dirname.c
$(CCLD) -o $@ $?

View file

@ -28,15 +28,15 @@
#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));

View file

@ -22,7 +22,7 @@
#include <string.h>
#include <unistd.h>
#include "../../servers/fs/const.h"
#include "../../servers/vfs/const.h"
char pvd[CD_SECTOR];

View file

@ -30,9 +30,9 @@
#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

View file

@ -47,9 +47,9 @@
#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>
@ -87,7 +87,7 @@ unsigned int fs_version = 2, block_size = 0;
#define ZONE_CT 360 /* default zones (when making file system) */
#define INODE_CT 95 /* default inodes (when making file system) */
#include "../../servers/fs/super.h"
#include "../../servers/mfs/super.h"
static struct super_block sb;
#define STICKY_BIT 01000 /* not defined anywhere else */

View file

@ -49,9 +49,9 @@
#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>
@ -71,7 +71,7 @@
#define ZONE_CT 360 /* default zones (when making file system) */
#define INODE_CT 95 /* default inodes (when making file system) */
#include "../../servers/fs/super.h"
#include "../../servers/mfs/super.h"
struct super_block sb;
#define STICKY_BIT 01000 /* not defined anywhere else */

View file

@ -23,7 +23,7 @@
#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>
@ -35,8 +35,8 @@
#undef EXTERN
#define EXTERN /* get rid of EXTERN by making it null */
#include "../../servers/fs/type.h"
#include "../../servers/fs/super.h"
#include "../../servers/mfs/type.h"
#include "../../servers/mfs/super.h"
#include <minix/fslib.h>
#ifndef max

View file

@ -19,9 +19,9 @@
#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)
{

View file

@ -14,7 +14,7 @@
#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));

View file

@ -41,10 +41,10 @@
#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>

View file

@ -1923,7 +1923,7 @@ PRIVATE void w_intr_wait()
/* Wait for an interrupt that sets w_status to "not busy". */
while (w_wn->w_status & (STATUS_ADMBSY|STATUS_BSY)) {
int rr;
if((rr=receive(ANY, &m)) != OK) { /* expect HARD_INT message */
if((rr=receive(HARDWARE, &m)) != OK) { /* expect HARD_INT message */
printf("w_intr_wait: receive from ANY failed (%d)\n",
r);
continue; /* try again */

View file

@ -1,7 +1,7 @@
# Makefile for ramdisk image
PROGRAMS=at_wini bios_wini cdprobe dev2name floppy loadramdisk newroot \
pci sh service sysenv
pci sh service sysenv mfs
MAKEDEV=/usr/bin/MAKEDEV
@ -90,6 +90,12 @@ service: ../../../servers/rs/service
../../../servers/rs/service:
cd ../../../servers/rs && make service
mfs: ../../../servers/mfs/mfs
install -s ../../../servers/mfs/$@ $@
../../../servers/mfs/mfs:
cd ../../../servers/mfs && make
depend:
/usr/bin/mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend

View file

@ -1,5 +1,5 @@
boot
200 250
210 250
d--755 0 0
bin d--755 0 0
at_wini ---755 0 0 at_wini
@ -13,6 +13,7 @@ d--755 0 0
sh ---755 0 0 sh
service ---755 0 0 service
sysenv ---755 0 0 sysenv
mfs ---755 0 0 mfs
$
dev d--755 0 0
@DEV@

View file

@ -1,4 +1,5 @@
#!/bin/sh
PATH=/bin:/sbin:/usr/bin:/usr/sbin
sed -n '1,/@DEV/p' <proto | grep -v @DEV@
(
cd /dev

View file

@ -41,7 +41,8 @@
#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)
@ -559,6 +560,8 @@
# 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 *
*===========================================================================*/

View file

@ -11,10 +11,13 @@
#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;
@ -29,6 +32,7 @@ typedef struct {
mess_5 m_m5;
mess_7 m_m7;
mess_8 m_m8;
mess_6 m_m6;
} m_u;
} message;
@ -47,6 +51,8 @@ typedef struct {
#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
@ -66,6 +72,17 @@ typedef struct {
#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
@ -94,7 +111,7 @@ typedef struct {
_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

146
include/minix/vfsif.h Normal file
View file

@ -0,0 +1,146 @@
/* 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

View file

@ -115,12 +115,13 @@ PUBLIC struct boot_image image[] = {
{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" },
};

View file

@ -9,6 +9,7 @@
#endif
#include <stdlib.h>
#include <signal.h>
#include <limits.h>
extern pid_t _fork(void);
extern pid_t _wait(int *);
@ -35,7 +36,7 @@ system(const char *str)
if ((pid = _fork()) < 0) return str ? -1 : 0;
if (pid == 0) {
for (i = 3; i <= 20; i++)
for (i = 3; i <= OPEN_MAX; i++)
_close(i);
if (!str) str = "cd ."; /* just testing for a shell */
exec_tab[2] = str; /* fill in command */

View file

@ -7,10 +7,10 @@
#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

View file

@ -17,9 +17,9 @@
#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;

View file

@ -1,14 +1,51 @@
#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;

View file

@ -16,7 +16,8 @@ usage:
build: all
all install depend clean:
cd ./pm && $(MAKE) $@
cd ./fs && $(MAKE) $@
cd ./vfs && $(MAKE) $@
cd ./mfs && $(MAKE) $@
cd ./rs && $(MAKE) $@
cd ./ds && $(MAKE) $@
cd ./is && $(MAKE) $@
@ -25,7 +26,8 @@ all install depend clean:
image:
cd ./pm && $(MAKE) EXTRA_OPTS=$(EXTRA_OPTS) build
cd ./fs && $(MAKE) EXTRA_OPTS=$(EXTRA_OPTS) build
cd ./vfs && $(MAKE) EXTRA_OPTS=$(EXTRA_OPTS) build
cd ./mfs && $(MAKE) EXTRA_OPTS=$(EXTRA_OPTS) build
cd ./rs && $(MAKE) EXTRA_OPTS=$(EXTRA_OPTS) build
cd ./ds && $(MAKE) EXTRA_OPTS=$(EXTRA_OPTS) build
cd ./init && $(MAKE) EXTRA_OPTS=$(EXTRA_OPTS) build

View file

@ -1,126 +0,0 @@
/* Second level block cache to supplement the file system cache. The block
* cache of a 16-bit Minix system is very small, too small to prevent trashing.
* A generic 32-bit system also doesn't have a very large cache to allow it
* to run on systems with little memory. On a system with lots of memory one
* can use the RAM disk as a read-only second level cache. Any blocks pushed
* out of the primary cache are cached on the RAM disk. This code manages the
* second level cache. The cache is a simple FIFO where old blocks are put
* into and drop out at the other end. Must be searched backwards.
*
* The entry points into this file are:
* init_cache2: initialize the second level cache
* get_block2: get a block from the 2nd level cache
* put_block2: store a block in the 2nd level cache
* invalidate2: remove all the cache blocks on some device
*/
#include "fs.h"
#include <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 */

View file

@ -1,353 +0,0 @@
/* This file performs the MOUNT and UMOUNT system calls.
*
* The entry points into this file are
* do_mount: perform the MOUNT system call
* do_umount: perform the UMOUNT system call
*/
#include "fs.h"
#include <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);
}

View file

@ -1,573 +0,0 @@
/* This file contains the procedures for creating, opening, closing, and
* seeking on files.
*
* The entry points into this file are
* do_creat: perform the CREAT system call
* do_open: perform the OPEN system call
* do_mknod: perform the MKNOD system call
* do_mkdir: perform the MKDIR system call
* do_close: perform the CLOSE system call
* do_lseek: perform the LSEEK system call
* new_node: create a new file, directory, etc.
*/
#include "fs.h"
#include <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);
}

View file

@ -1,303 +0,0 @@
/* This file contains the code for performing four system calls relating to
* status and directories.
*
* The entry points into this file are
* do_chdir: perform the CHDIR system call
* do_chroot: perform the CHROOT system call
* do_stat: perform the STAT system call
* do_fstat: perform the FSTAT system call
* do_fstatfs: perform the FSTATFS system call
* do_lstat: perform the LSTAT system call
* do_rdlink: perform the RDLNK system call
*/
#include "fs.h"
#include <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);
}

View file

@ -9,8 +9,8 @@
*/
#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];

37
servers/mfs/Makefile Normal file
View file

@ -0,0 +1,37 @@
# Makefile for File System (FS)
SERVER = mfs
# directories
u = /usr
i = $u/include
s = $i/sys
h = $i/minix
# programs, flags, etc.
CC = exec cc
CFLAGS = -I$i $(EXTRA_OPTS)
LDFLAGS = -i
LIBS = -lsys -lsysutil -ltimers
OBJ = cache.o device.o link.o \
mount.o misc.o open.o pipe.o protect.o read.o \
stadir.o table.o time.o utility.o \
write.o inode.o main.o path.o super.o
# build local binary
install all build: $(SERVER)
$(SERVER): $(OBJ)
$(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS)
install -S 16k $@ /sbin
# clean up local files
clean:
rm -f $(SERVER) *.o *.bak
depend:
/usr/bin/mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend
# Include generated dependencies.
include .depend

View file

@ -17,13 +17,13 @@
#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 *
*===========================================================================*/
@ -58,7 +58,6 @@ int only_search; /* if NO_READ, don't read, else act normal */
if (dev != NO_DEV) {
b = (int) block & HASH_MASK;
bp = buf_hash[b];
while (bp != NIL_BUF) {
if (bp->b_blocknr == block && bp->b_dev == dev) {
/* Block needed has been found. */
@ -70,7 +69,6 @@ int only_search; /* if NO_READ, don't read, else act normal */
/* This block is not the one sought. */
bp = bp->b_hash; /* move to next block on hash chain */
}
}
}
@ -86,14 +84,12 @@ int only_search; /* if NO_READ, don't read, else act normal */
} else {
/* The block just taken is not on the front of its hash chain. */
while (prev_ptr->b_hash != NIL_BUF)
{
if (prev_ptr->b_hash == bp) {
prev_ptr->b_hash = bp->b_hash; /* found it */
break;
} else {
prev_ptr = prev_ptr->b_hash; /* keep looking */
}
}
}
/* If the block taken is dirty, make it clean by writing it to the disk.
@ -167,7 +163,8 @@ int block_type; /* INODE_BLOCK, DIRECTORY_BLOCK, or whatever */
else
front->b_prev = bp;
front = bp;
} else {
}
else {
/* Block probably will be needed quickly. Put it on rear of chain.
* It will not be evicted from the cache for a long time.
*/
@ -222,8 +219,7 @@ zone_t z; /* try to allocate new zone near this one */
err_code = ENOSPC;
major = (int) (sp->s_dev >> MAJOR) & BYTE;
minor = (int) (sp->s_dev >> MINOR) & BYTE;
printf("No space on %sdevice %d/%d\n",
sp->s_dev == root_dev ? "root " : "", major, minor);
printf("No space on device %d/%d\n", major, minor);
return(NO_ZONE);
}
if (z == sp->s_firstdatazone) sp->s_zsearch = b; /* for next time */
@ -262,7 +258,6 @@ int rw_flag; /* READING or WRITING */
* is not reported to the caller. If the error occurred while purging a block
* from the cache, it is not clear what the caller could do about it anyway.
*/
int r, op;
off_t pos;
dev_t dev;
@ -271,19 +266,21 @@ int rw_flag; /* READING or WRITING */
block_size = get_block_size(bp->b_dev);
if ( (dev = bp->b_dev) != NO_DEV) {
pos = (off_t) bp->b_blocknr * block_size;
op = (rw_flag == READING ? DEV_READ : DEV_WRITE);
r = dev_bio(op, dev, FS_PROC_NR, bp->b_data, pos, block_size);
if (r != block_size) {
if (r >= 0) r = END_OF_FILE;
if (r != END_OF_FILE)
printf("Unrecoverable disk error on device %d/%d, block %ld\n",
(dev>>MAJOR)&BYTE, (dev>>MINOR)&BYTE, bp->b_blocknr);
bp->b_dev = NO_DEV; /* invalidate block */
pos = (off_t) bp->b_blocknr * block_size;
op = (rw_flag == READING ? DEV_READ : DEV_WRITE);
r = block_dev_io(op, dev, SELF_E, bp->b_data, pos, block_size, 0);
if (r != block_size) {
if (r >= 0) r = END_OF_FILE;
if (r != END_OF_FILE)
printf("MFS(%d) I/O error on device %d/%d, block %ld\n",
SELF_E, (dev>>MAJOR)&BYTE, (dev>>MINOR)&BYTE,
bp->b_blocknr);
bp->b_dev = NO_DEV; /* invalidate block */
/* Report read errors to interested parties. */
if (rw_flag == READING) rdwt_err = r;
}
/* Report read errors to interested parties. */
if (rw_flag == READING) rdwt_err = r;
}
}
bp->b_dirt = CLEAN;
@ -375,9 +372,9 @@ int rw_flag; /* READING or WRITING */
iop->iov_addr = (vir_bytes) bp->b_data;
iop->iov_size = block_size;
}
r = dev_bio(rw_flag == WRITING ? DEV_SCATTER : DEV_GATHER,
dev, FS_PROC_NR, iovec,
(off_t) bufq[0]->b_blocknr * block_size, j);
r = block_dev_io(rw_flag == WRITING ? DEV_SCATTER : DEV_GATHER,
dev, SELF_E, iovec,
(off_t) bufq[0]->b_blocknr * block_size, j, 0);
/* Harvest the results. Dev_io reports the first error it may have
* encountered, but we only care if it's the first block that failed.
@ -437,123 +434,12 @@ struct buf *bp;
next_ptr = bp->b_next; /* successor on LRU chain */
prev_ptr = bp->b_prev; /* predecessor on LRU chain */
if (prev_ptr != NIL_BUF)
{
prev_ptr->b_next = next_ptr;
}
else
front = next_ptr; /* this block was at front of chain */
if (next_ptr != NIL_BUF)
{
next_ptr->b_prev = prev_ptr;
}
else
rear = prev_ptr; /* this block was at rear of chain */
}
#if 0
PRIVATE void check_lru()
{
int i;
struct buf *bp, *nbp;
for (i= 0; 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

108
servers/mfs/const.h Normal file
View file

@ -0,0 +1,108 @@
/* Tables sizes */
#define V1_NR_DZONES 7 /* # direct zone numbers in a V1 inode */
#define V1_NR_TZONES 9 /* total # zone numbers in a V1 inode */
#define V2_NR_DZONES 7 /* # direct zone numbers in a V2 inode */
#define V2_NR_TZONES 10 /* total # zone numbers in a V2 inode */
#define NR_INODES 256 /* # slots in "in core" inode table */
#define NR_SUPERS 1 /* # slots in super block table */
#define INODE_HASH_LOG2 7 /* 2 based logarithm of the inode hash size */
#define INODE_HASH_SIZE ((unsigned long)1<<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 */

299
servers/mfs/device.c Normal file
View file

@ -0,0 +1,299 @@
#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);
}

9
servers/mfs/drivers.h Normal file
View file

@ -0,0 +1,9 @@
/* Driver endpoints for major devices. Only the block devices
* are mapped here, it's a subset of the mapping in the VFS */
EXTERN struct driver_endpoints {
endpoint_t driver_e;
} driver_endpoints[NR_DEVICES];

43
servers/mfs/glo.h Normal file
View file

@ -0,0 +1,43 @@
/* EXTERN should be extern except for the table file */
#ifdef _TABLE
#undef EXTERN
#define EXTERN
#endif
EXTERN off_t rdahedpos; /* position to read ahead */
EXTERN struct inode *rdahed_inode; /* pointer to inode to read ahead */
/* The following variables are used for returning results to the caller. */
EXTERN int err_code; /* temporary storage for error number */
EXTERN int rdwt_err; /* status of last disk i/o request */
EXTERN int cch[NR_INODES];
extern char dot1[2]; /* dot1 (&dot1[0]) and dot2 (&dot2[0]) have a special */
extern char dot2[3]; /* meaning to search_dir: no access permission check. */
extern _PROTOTYPE (int (*fs_call_vec[]), (void) ); /* fs call table */
EXTERN message fs_m_in;
EXTERN message fs_m_out;
EXTERN int FS_STATE;
EXTERN uid_t caller_uid;
EXTERN gid_t caller_gid;
EXTERN time_t boottime; /* time in seconds at system boot */
EXTERN int req_nr;
EXTERN int SELF_E;
EXTERN struct inode *chroot_dir;
EXTERN short path_processed; /* number of characters processed */
EXTERN char user_path[PATH_MAX]; /* pathname to be processed */
EXTERN char *vfs_slink_storage;
EXTERN int symloop;
EXTERN dev_t fs_dev; /* the device that is handled by this FS proc */

31
servers/mfs/inc.h Normal file
View file

@ -0,0 +1,31 @@
#define _SYSTEM 1 /* get OK and negative error codes */
#define _MINIX 1 /* tell headers to include MINIX stuff */
#define VERBOSE 0 /* display diagnostics */
#include <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"

View file

@ -18,16 +18,121 @@
#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 *
*===========================================================================*/
@ -35,42 +140,81 @@ PUBLIC struct inode *get_inode(dev, numb)
dev_t dev; /* device on which inode resides */
int numb; /* inode number (ANSI: may not be unshort) */
{
/* Find a slot in the inode table, load the specified inode into it, and
* return a pointer to the slot. If 'dev' == NO_DEV, just return a free slot.
/* Find the inode in the hash table. If it is not there, get a free inode
* load it from the disk if it's necessary and put on the hash list
*/
register struct inode *rip, *xp;
int hashi;
/* Search the inode table both for (dev, numb) and a free slot. */
xp = NIL_INODE;
for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++) {
if (rip->i_count > 0) { /* only check used slots for (dev, numb) */
if (rip->i_dev == dev && rip->i_num == numb) {
/* This is the inode that we are looking for. */
rip->i_count++;
return(rip); /* (dev, numb) found */
}
} else {
xp = rip; /* remember this free slot for later */
}
hashi = numb & INODE_HASH_MASK;
/* Search inode in the hash table */
LIST_FOREACH(rip, &hash_inodes[hashi], i_hash) {
if (rip->i_num == numb && rip->i_dev == dev) {
/* If unused, remove it from the unused/free list */
if (rip->i_count == 0) {
inode_cache_hit++;
TAILQ_REMOVE(&unused_inodes, rip, i_unused);
}
++rip->i_count;
return rip;
}
}
/* Inode we want is not currently in use. Did we find a free slot? */
if (xp == NIL_INODE) { /* inode table completely full */
err_code = ENFILE;
return(NIL_INODE);
inode_cache_miss++;
/* Inode is not on the hash, get a free one */
if (TAILQ_EMPTY(&unused_inodes)) {
err_code = ENFILE;
return NIL_INODE;
}
rip = TAILQ_FIRST(&unused_inodes);
/* A free inode slot has been located. Load the inode into it. */
xp->i_dev = dev;
xp->i_num = numb;
xp->i_count = 1;
if (dev != NO_DEV) rw_inode(xp, READING); /* get inode from disk */
xp->i_update = 0; /* all the times are initially up-to-date */
/* If not free unhash it */
if (rip->i_num != 0)
unhash_inode(rip);
/* Inode is not unused any more */
TAILQ_REMOVE(&unused_inodes, rip, i_unused);
return(xp);
/* Load the inode. */
rip->i_dev = dev;
rip->i_num = numb;
rip->i_count = 1;
if (dev != NO_DEV) rw_inode(rip, READING); /* get inode from disk */
rip->i_update = 0; /* all the times are initially up-to-date */
/* Add to hash */
addhash_inode(rip);
return(rip);
}
/*===========================================================================*
* find_inode *
*===========================================================================*/
PUBLIC struct inode *find_inode(dev, numb)
dev_t dev; /* device on which inode resides */
int numb; /* inode number (ANSI: may not be unshort) */
{
/* Find the inode specified by the inode and device number.
*/
struct inode *rip;
int hashi;
hashi = numb & INODE_HASH_MASK;
/* Search inode in the hash table */
LIST_FOREACH(rip, &hash_inodes[hashi], i_hash) {
if (rip->i_count > 0 && rip->i_num == numb && rip->i_dev == dev) {
return rip;
}
}
return NIL_INODE;
}
/*===========================================================================*
* put_inode *
*===========================================================================*/
@ -83,6 +227,7 @@ register struct inode *rip; /* pointer to inode to be released */
*/
if (rip == NIL_INODE) return; /* checking here is easier than in caller */
if (--rip->i_count == 0) { /* i_count == 0 means no one is using it now */
if (rip->i_nlinks == 0) {
/* i_nlinks == 0 means free the inode. */
@ -90,14 +235,28 @@ register struct inode *rip; /* pointer to inode to be released */
rip->i_mode = I_NOT_ALLOC; /* clear I_TYPE field */
rip->i_dirt = DIRTY;
free_inode(rip->i_dev, rip->i_num);
} else {
}
else {
if (rip->i_pipe == I_PIPE) truncate_inode(rip, 0);
}
rip->i_mount = NO_MOUNT;
rip->i_pipe = NO_PIPE; /* should always be cleared */
if (rip->i_dirt == DIRTY) rw_inode(rip, WRITING);
if (rip->i_nlinks == 0) {
/* free, put at the front of the LRU list */
unhash_inode(rip);
rip->i_num = 0;
TAILQ_INSERT_HEAD(&unused_inodes, rip, i_unused);
}
else {
/* unused, put at the back of the LRU (cache it) */
TAILQ_INSERT_TAIL(&unused_inodes, rip, i_unused);
}
}
}
/*===========================================================================*
* alloc_inode *
*===========================================================================*/
@ -122,8 +281,7 @@ PUBLIC struct inode *alloc_inode(dev_t dev, mode_t bits)
err_code = ENFILE;
major = (int) (sp->s_dev >> MAJOR) & BYTE;
minor = (int) (sp->s_dev >> MINOR) & BYTE;
printf("Out of i-nodes on %sdevice %d/%d\n",
sp->s_dev == root_dev ? "root " : "", major, minor);
printf("Out of i-nodes on device %d/%d\n", major, minor);
return(NIL_INODE);
}
sp->s_isearch = b; /* next time start here */
@ -137,8 +295,8 @@ PUBLIC struct inode *alloc_inode(dev_t dev, mode_t bits)
/* An inode slot is available. Put the inode just allocated into it. */
rip->i_mode = bits; /* set up RWX bits */
rip->i_nlinks = 0; /* initial no links */
rip->i_uid = fp->fp_effuid; /* file's uid is owner's */
rip->i_gid = fp->fp_effgid; /* ditto group id */
rip->i_uid = caller_uid; /* file's uid is owner's */
rip->i_gid = caller_gid; /* ditto group id */
rip->i_dev = dev; /* mark which device it is on */
rip->i_ndzones = sp->s_ndzones; /* number of direct zones */
rip->i_nindirs = sp->s_nindirs; /* number of indirect zones per blk*/

62
servers/mfs/inode.h Normal file
View file

@ -0,0 +1,62 @@
/* Inode table. This table holds inodes that are currently in use. In some
* cases they have been opened by an open() or creat() system call, in other
* cases the file system itself needs the inode for one reason or another,
* such as to search a directory for a path name.
* The first part of the struct holds fields that are present on the
* disk; the second part holds fields not present on the disk.
* The disk inode part is also declared in "type.h" as 'd1_inode' for V1
* file systems and 'd2_inode' for V2 file systems.
*/
#include "queue.h"
EXTERN struct inode {
mode_t i_mode; /* file type, protection, etc. */
nlink_t i_nlinks; /* how many links to this file */
uid_t i_uid; /* user id of the file's owner */
gid_t i_gid; /* group number */
off_t i_size; /* current file size in bytes */
time_t i_atime; /* time of last access (V2 only) */
time_t i_mtime; /* when was file data last changed */
time_t i_ctime; /* when was inode itself changed (V2 only)*/
zone_t i_zone[V2_NR_TZONES]; /* zone numbers for direct, ind, and dbl ind */
/* The following items are not present on the disk. */
dev_t i_dev; /* which device is the inode on */
ino_t i_num; /* inode number on its (minor) device */
int i_count; /* # times inode used; 0 means slot is free */
int i_ndzones; /* # direct zones (Vx_NR_DZONES) */
int i_nindirs; /* # indirect zones per indirect block */
struct super_block *i_sp; /* pointer to super block for inode's device */
char i_dirt; /* CLEAN or DIRTY */
char i_pipe; /* set to I_PIPE if pipe */
char i_mount; /* this bit is set if file mounted on */
short i_vmnt_ind; /* index of the vmnt mounted on */
char i_seek; /* set on LSEEK, cleared on READ/WRITE */
char i_update; /* the ATIME, CTIME, and MTIME bits are here */
LIST_ENTRY(inode) i_hash; /* hash list */
TAILQ_ENTRY(inode) i_unused; /* free and unused list */
} inode[NR_INODES];
/* list of unused/free inodes */
EXTERN TAILQ_HEAD(unused_inodes_t, inode) unused_inodes;
/* inode hashtable */
EXTERN LIST_HEAD(inodelist, inode) hash_inodes[INODE_HASH_SIZE];
EXTERN unsigned int inode_cache_hit;
EXTERN unsigned int inode_cache_miss;
#define NIL_INODE (struct inode *) 0 /* indicates absence of inode slot */
/* Field values. Note that CLEAN and DIRTY are defined in "const.h" */
#define NO_PIPE 0 /* i_pipe is NO_PIPE if inode is not a pipe */
#define I_PIPE 1 /* i_pipe is I_PIPE if inode is a pipe */
#define NO_MOUNT 0 /* i_mount is NO_MOUNT if file not mounted on*/
#define I_MOUNT 1 /* i_mount is I_MOUNT if file mounted on */
#define NO_SEEK 0 /* i_seek = NO_SEEK if last op was not SEEK */
#define ISEEK 1 /* i_seek = ISEEK if last op was SEEK */

View file

@ -1,29 +1,17 @@
/* This file handles the LINK and UNLINK system calls. It also deals with
* deallocating the storage used by a file when the last UNLINK is done to a
* file and the blocks must be returned to the free block pool.
*
* The entry points into this file are
* do_link: perform the LINK system call
* do_unlink: perform the UNLINK and RMDIR system calls
* do_rename: perform the RENAME system call
* do_truncate: perform the TRUNCATE system call
* do_ftruncate: perform the FTRUNCATE system call
* truncate_inode: release the blocks associated with an inode up to a size
* freesp_inode: release a range of blocks without setting the size
*/
#include "fs.h"
#include <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,
@ -38,10 +26,11 @@ FORWARD _PROTOTYPE( void zeroblock_range, (struct inode *i, off_t p, off_t h));
#define FIRST_HALF 0
#define LAST_HALF 1
/*===========================================================================*
* do_link *
* fs_link *
*===========================================================================*/
PUBLIC int do_link()
PUBLIC int fs_link()
{
/* Perform the link(name1, name2) system call. */
@ -50,10 +39,20 @@ PUBLIC int do_link()
char string[NAME_MAX];
struct inode *new_ip;
/* See if 'name' (file to be linked) exists. */
if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
caller_uid = fs_m_in.REQ_UID;
caller_gid = fs_m_in.REQ_GID;
/* Copy the link name's last component */
r = sys_datacopy(FS_PROC_NR, (vir_bytes) fs_m_in.REQ_PATH,
SELF, (vir_bytes) string,
(phys_bytes) fs_m_in.REQ_PATH_LEN);
/* Temporarily open the file. */
if ( (rip = get_inode(fs_dev, fs_m_in.REQ_LINKED_FILE)) == NIL_INODE) {
printf("MFS(%d) get_inode by fs_link() failed\n", SELF_E);
return(EINVAL);
}
/* Check to see if the file has maximum number of links already. */
r = OK;
if (rip->i_nlinks >= (rip->i_sp->s_version == V1 ? CHAR_MAX : SHRT_MAX))
@ -61,7 +60,8 @@ PUBLIC int do_link()
/* Only super_user may link to directories. */
if (r == OK)
if ( (rip->i_mode & I_TYPE) == I_DIRECTORY && !super_user) r = EPERM;
if ( (rip->i_mode & I_TYPE) == I_DIRECTORY && caller_uid != SU_UID)
r = EPERM;
/* If error with 'name', return the inode. */
if (r != OK) {
@ -69,12 +69,11 @@ PUBLIC int do_link()
return(r);
}
/* Does the final directory of 'name2' exist? */
if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) {
put_inode(rip);
return(err_code);
/* Temporarily open the last dir */
if ( (ip = get_inode(fs_dev, fs_m_in.REQ_LINK_PARENT)) == NIL_INODE) {
printf("MFS(%d) get_inode by fs_link() failed\n", SELF_E);
return(EINVAL);
}
if ( (ip = last_dir(user_path, string)) == NIL_INODE) r = err_code;
/* If 'name2' exists in full (even if no space) set 'r' to error. */
if (r == OK) {
@ -87,10 +86,6 @@ PUBLIC int do_link()
}
}
/* Check for links across devices. */
if (r == OK)
if (rip->i_dev != ip->i_dev) r = EXDEV;
/* Try to link. */
if (r == OK)
r = search_dir(ip, string, &rip->i_num, ENTER);
@ -108,47 +103,54 @@ PUBLIC int do_link()
return(r);
}
/*===========================================================================*
* do_unlink *
* fs_unlink *
*===========================================================================*/
PUBLIC int do_unlink()
PUBLIC int fs_unlink()
{
/* Perform the unlink(name) or rmdir(name) system call. The code for these two
* is almost the same. They differ only in some condition testing. Unlink()
* may be used by the superuser to do dangerous things; rmdir() may not.
*/
register struct inode *rip;
struct inode *rldirp;
int r;
char string[NAME_MAX];
caller_uid = fs_m_in.REQ_UID;
caller_gid = fs_m_in.REQ_GID;
/* Copy the last component */
r = sys_datacopy(FS_PROC_NR, (vir_bytes) fs_m_in.REQ_PATH,
SELF, (vir_bytes) string,
(phys_bytes) fs_m_in.REQ_PATH_LEN);
/* Get the last directory in the path. */
if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code);
if ( (rldirp = last_dir(user_path, string)) == NIL_INODE)
return(err_code);
if (r != OK) return r;
/* Temporarily open the dir. */
if ( (rldirp = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) {
return(EINVAL);
}
/* The last directory exists. Does the file also exist? */
r = OK;
if ( (rip = advance(&rldirp, string)) == NIL_INODE) r = err_code;
/* If error, return inode. */
if (r != OK) {
/* Mount point? */
if (r == EENTERMOUNT || r == ELEAVEMOUNT)
r = EBUSY;
put_inode(rldirp);
return(r);
}
/* Do not remove a mount point. */
if (rip->i_num == ROOT_INODE) {
put_inode(rldirp);
put_inode(rip);
return(EBUSY);
}
/* Now test if the call is allowed, separately for unlink() and rmdir(). */
if (call_nr == UNLINK) {
if (fs_m_in.m_type == REQ_UNLINK) {
/* Only the su may unlink directories, but the su can unlink any dir.*/
if ( (rip->i_mode & I_TYPE) == I_DIRECTORY && !super_user) r = EPERM;
if ( (rip->i_mode & I_TYPE) == I_DIRECTORY
&& caller_uid != SU_UID) r = EPERM;
/* Don't unlink a file if it is the root of a mounted file system. */
if (rip->i_num == ROOT_INODE) r = EBUSY;
@ -156,7 +158,8 @@ PUBLIC int do_unlink()
/* Actually try to unlink the file; fails if parent is mode 0 etc. */
if (r == OK) r = unlink_file(rldirp, rip, string);
} else {
}
else {
r = remove_dir(rldirp, rip, string); /* call is RMDIR */
}
@ -166,13 +169,126 @@ PUBLIC int do_unlink()
return(r);
}
/*===========================================================================*
* do_rename *
* fs_rdlink *
*===========================================================================*/
PUBLIC int do_rename()
PUBLIC int fs_rdlink()
{
block_t b; /* block containing link text */
struct buf *bp; /* buffer containing link text */
register struct inode *rip; /* target inode */
register int r; /* return value */
int copylen;
copylen = fs_m_in.REQ_SLENGTH;
caller_uid = fs_m_in.REQ_UID;
caller_gid = fs_m_in.REQ_GID;
/* Temporarily open the file. */
if ( (rip = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) {
return(EINVAL);
}
r = EACCES;
if (S_ISLNK(rip->i_mode) && (b = read_map(rip, (off_t) 0)) != NO_BLOCK) {
if (copylen <= 0) r = EINVAL;
else if (copylen < rip->i_size) r = ERANGE;
else {
if(rip->i_size < copylen) copylen = rip->i_size;
bp = get_block(rip->i_dev, b, NORMAL);
r = sys_vircopy(SELF, D, (vir_bytes) bp->b_data,
fs_m_in.REQ_WHO_E, D, (vir_bytes) fs_m_in.REQ_USER_ADDR,
(vir_bytes) copylen);
if (r == OK) r = copylen;
put_block(bp, DIRECTORY_BLOCK);
}
}
put_inode(rip);
return(r);
}
/*===========================================================================*
* remove_dir *
*===========================================================================*/
PRIVATE int remove_dir(rldirp, rip, dir_name)
struct inode *rldirp; /* parent directory */
struct inode *rip; /* directory to be removed */
char dir_name[NAME_MAX]; /* name of directory to be removed */
{
/* A directory file has to be removed. Five conditions have to met:
* - The file must be a directory
* - The directory must be empty (except for . and ..)
* - The final component of the path must not be . or ..
* - The directory must not be the root of a mounted file system (VFS)
* - The directory must not be anybody's root/working directory (VFS)
*/
int r;
/* search_dir checks that rip is a directory too. */
if ((r = search_dir(rip, "", (ino_t *) 0, IS_EMPTY)) != OK) return r;
if (strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0)return(EINVAL);
if (rip->i_num == ROOT_INODE) return(EBUSY); /* can't remove 'root' */
/* Actually try to unlink the file; fails if parent is mode 0 etc. */
if ((r = unlink_file(rldirp, rip, dir_name)) != OK) return r;
/* Unlink . and .. from the dir. The super user can link and unlink any dir,
* so don't make too many assumptions about them.
*/
(void) unlink_file(rip, NIL_INODE, dot1);
(void) unlink_file(rip, NIL_INODE, dot2);
return(OK);
}
/*===========================================================================*
* unlink_file *
*===========================================================================*/
PRIVATE int unlink_file(dirp, rip, file_name)
struct inode *dirp; /* parent directory of file */
struct inode *rip; /* inode of file, may be NIL_INODE too. */
char file_name[NAME_MAX]; /* name of file to be removed */
{
/* Unlink 'file_name'; rip must be the inode of 'file_name' or NIL_INODE. */
ino_t numb; /* inode number */
int r;
/* If rip is not NIL_INODE, it is used to get faster access to the inode. */
if (rip == NIL_INODE) {
/* Search for file in directory and try to get its inode. */
err_code = search_dir(dirp, file_name, &numb, LOOK_UP);
if (err_code == OK) rip = get_inode(dirp->i_dev, (int) numb);
if (err_code != OK || rip == NIL_INODE) return(err_code);
} else {
dup_inode(rip); /* inode will be returned with put_inode */
}
r = search_dir(dirp, file_name, (ino_t *) 0, DELETE);
if (r == OK) {
rip->i_nlinks--; /* entry deleted from parent's dir */
rip->i_update |= CTIME;
rip->i_dirt = DIRTY;
}
put_inode(rip);
return(r);
}
/*===========================================================================*
* fs_rename *
*===========================================================================*/
PUBLIC int fs_rename()
{
/* Perform the rename(name1, name2) system call. */
struct inode *old_dirp, *old_ip; /* ptrs to old dir, file inodes */
struct inode *new_dirp, *new_ip; /* ptrs to new dir, file inodes */
struct inode *new_superdirp, *next_new_superdirp;
@ -183,15 +299,30 @@ PUBLIC int do_rename()
ino_t numb;
int r1;
/* See if 'name1' (existing file) exists. Get dir and file inodes. */
if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
if ( (old_dirp = last_dir(user_path, old_name))==NIL_INODE) return(err_code);
caller_uid = fs_m_in.REQ_UID;
caller_gid = fs_m_in.REQ_GID;
/* Copy the last component of the old name */
r = sys_datacopy(FS_PROC_NR, (vir_bytes) fs_m_in.REQ_PATH,
SELF, (vir_bytes) old_name,
(phys_bytes) fs_m_in.REQ_PATH_LEN);
if (r != OK) return r;
/* Copy the last component of the new name */
r = sys_datacopy(FS_PROC_NR, (vir_bytes) fs_m_in.REQ_USER_ADDR,
SELF, (vir_bytes) new_name,
(phys_bytes) fs_m_in.REQ_SLENGTH);
if (r != OK) return r;
/* Get old dir inode */
if ( (old_dirp = get_inode(fs_dev, fs_m_in.REQ_OLD_DIR)) == NIL_INODE)
return(err_code);
if ( (old_ip = advance(&old_dirp, old_name)) == NIL_INODE) r = err_code;
/* See if 'name2' (new name) exists. Get dir and file inodes. */
if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) r = err_code;
if ( (new_dirp = last_dir(user_path, new_name)) == NIL_INODE) r = err_code;
/* Get new dir inode */
if ( (new_dirp = get_inode(fs_dev, fs_m_in.REQ_NEW_DIR)) == NIL_INODE)
r = err_code;
new_ip = advance(&new_dirp, new_name); /* not required to exist */
if (old_ip != NIL_INODE)
@ -206,13 +337,25 @@ PUBLIC int do_rename()
dup_inode(new_superdirp = new_dirp);
while (TRUE) { /* may hang in a file system loop */
if (new_superdirp == old_ip) {
put_inode(new_superdirp);
r = EINVAL;
break;
}
next_new_superdirp = advance(&new_superdirp, dot2);
put_inode(new_superdirp);
if (next_new_superdirp == new_superdirp)
break; /* back at system root directory */
/*
if (next_new_superdirp == new_superdirp) {
put_inode(new_superdirp);
break;
}
*/
if (err_code == ELEAVEMOUNT) {
/* imitate that we are back at the root,
* cross device checked already on VFS */
/*next_new_superdirp = new_superdirp;*/
err_code = OK;
break;
}
new_superdirp = next_new_superdirp;
if (new_superdirp == NIL_INODE) {
/* Missing ".." entry. Assume the worst. */
@ -220,36 +363,49 @@ PUBLIC int do_rename()
break;
}
}
put_inode(new_superdirp);
/*put_inode(new_superdirp);*/
}
/* The old or new name must not be . or .. */
if (strcmp(old_name, ".")==0 || strcmp(old_name, "..")==0 ||
strcmp(new_name, ".")==0 || strcmp(new_name, "..")==0) r = EINVAL;
/* Both parent directories must be on the same device. */
if (old_dirp->i_dev != new_dirp->i_dev) r = EXDEV;
strcmp(new_name, ".")==0 || strcmp(new_name, "..")==0) {
r = EINVAL;
}
/* Both parent directories must be on the same device.
if (old_dirp->i_dev != new_dirp->i_dev) r = EXDEV; */
/* Parent dirs must be writable, searchable and on a writable device */
if ((r1 = forbidden(old_dirp, W_BIT | X_BIT)) != OK ||
(r1 = forbidden(new_dirp, W_BIT | X_BIT)) != OK) r = r1;
(r1 = forbidden(new_dirp, W_BIT | X_BIT)) != OK) {
r = r1;
}
/* Some tests apply only if the new path exists. */
if (new_ip == NIL_INODE) {
/* don't rename a file with a file system mounted on it. */
if (old_ip->i_dev != old_dirp->i_dev) r = EXDEV;
/* don't rename a file with a file system mounted on it.
if (old_ip->i_dev != old_dirp->i_dev) r = EXDEV;*/
if (odir && new_dirp->i_nlinks >=
(new_dirp->i_sp->s_version == V1 ? CHAR_MAX : SHRT_MAX) &&
!same_pdir && r == OK) r = EMLINK;
} else {
if (old_ip == new_ip) r = SAME; /* old=new */
/* has the old file or new file a file system mounted on it? */
!same_pdir && r == OK) {
r = EMLINK;
}
}
else {
if (old_ip == new_ip) {
r = SAME; /* old=new */
}
/* has the old file or new file a file system mounted on it?
if (old_ip->i_dev != new_ip->i_dev) r = EXDEV;
*/
ndir = ((new_ip->i_mode & I_TYPE) == I_DIRECTORY); /* dir ? */
if (odir == TRUE && ndir == FALSE) r = ENOTDIR;
if (odir == FALSE && ndir == TRUE) r = EISDIR;
if (odir == TRUE && ndir == FALSE) {
r = ENOTDIR;
}
if (odir == FALSE && ndir == TRUE) {
r = EISDIR;
}
}
}
@ -320,46 +476,65 @@ PUBLIC int do_rename()
return(r == SAME ? OK : r);
}
/*===========================================================================*
* do_truncate *
* fs_trunc *
*===========================================================================*/
PUBLIC int do_truncate()
PUBLIC int fs_trunc()
{
/* truncate_inode() does the actual work of do_truncate() and do_ftruncate().
* do_truncate() and do_ftruncate() have to get hold of the inode, either
* by name or fd, do checks on it, and call truncate_inode() to do the
* work.
*/
int r;
struct inode *rip; /* pointer to inode to be truncated */
struct inode *rip;
int r = OK;
caller_uid = fs_m_in.REQ_UID;
caller_gid = fs_m_in.REQ_GID;
/* Temporarily open the file. */
if ( (rip = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) {
printf("MFS(%d) get_inode by fs_chmod() failed\n", SELF_E);
return(EINVAL);
}
if ( (rip->i_mode & I_TYPE) != I_REGULAR)
r = EINVAL;
else
r = truncate_inode(rip, fs_m_in.REQ_LENGTH);
put_inode(rip);
if (fetch_name(m_in.m2_p1, m_in.m2_i1, M1) != OK)
return err_code;
if( (rip = eat_path(user_path)) == NIL_INODE)
return err_code;
if ( (rip->i_mode & I_TYPE) != I_REGULAR)
r = EINVAL;
else
r = truncate_inode(rip, m_in.m2_l1);
put_inode(rip);
return r;
return r;
}
/*===========================================================================*
* do_ftruncate *
* fs_ftrunc *
*===========================================================================*/
PUBLIC int do_ftruncate()
PUBLIC int fs_ftrunc(void)
{
/* As with do_truncate(), truncate_inode() does the actual work. */
struct filp *rfilp;
if ( (rfilp = get_filp(m_in.m2_i1)) == NIL_FILP)
return err_code;
if ( (rfilp->filp_ino->i_mode & I_TYPE) != I_REGULAR)
return EINVAL;
return truncate_inode(rfilp->filp_ino, m_in.m2_l1);
struct inode *rip;
off_t start, end;
int r;
if ( (rip = find_inode(fs_dev, fs_m_in.REQ_FD_INODE_NR))
== NIL_INODE) {
printf("FSfreesp: couldn't find inode %d\n",
fs_m_in.REQ_FD_INODE_NR);
return EINVAL;
}
start = fs_m_in.REQ_FD_START;
end = fs_m_in.REQ_FD_END;
if (end == 0) {
r = truncate_inode(rip, start);
}
else {
r = freesp_inode(rip, start, end);
}
return r;
}
/*===========================================================================*
* truncate_inode *
*===========================================================================*/
@ -539,78 +714,4 @@ off_t len;
put_block(bp, FULL_DATA_BLOCK);
}
/*===========================================================================*
* remove_dir *
*===========================================================================*/
PRIVATE int remove_dir(rldirp, rip, dir_name)
struct inode *rldirp; /* parent directory */
struct inode *rip; /* directory to be removed */
char dir_name[NAME_MAX]; /* name of directory to be removed */
{
/* A directory file has to be removed. Five conditions have to met:
* - The file must be a directory
* - The directory must be empty (except for . and ..)
* - The final component of the path must not be . or ..
* - The directory must not be the root of a mounted file system
* - The directory must not be anybody's root/working directory
*/
int r;
register struct fproc *rfp;
/* search_dir checks that rip is a directory too. */
if ((r = search_dir(rip, "", (ino_t *) 0, IS_EMPTY)) != OK) return r;
if (strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0)return(EINVAL);
if (rip->i_num == ROOT_INODE) return(EBUSY); /* can't remove 'root' */
for (rfp = &fproc[INIT_PROC_NR + 1]; rfp < &fproc[NR_PROCS]; rfp++)
if (rfp->fp_pid != PID_FREE &&
(rfp->fp_workdir == rip || rfp->fp_rootdir == rip))
return(EBUSY); /* can't remove anybody's working dir */
/* Actually try to unlink the file; fails if parent is mode 0 etc. */
if ((r = unlink_file(rldirp, rip, dir_name)) != OK) return r;
/* Unlink . and .. from the dir. The super user can link and unlink any dir,
* so don't make too many assumptions about them.
*/
(void) unlink_file(rip, NIL_INODE, dot1);
(void) unlink_file(rip, NIL_INODE, dot2);
return(OK);
}
/*===========================================================================*
* unlink_file *
*===========================================================================*/
PRIVATE int unlink_file(dirp, rip, file_name)
struct inode *dirp; /* parent directory of file */
struct inode *rip; /* inode of file, may be NIL_INODE too. */
char file_name[NAME_MAX]; /* name of file to be removed */
{
/* Unlink 'file_name'; rip must be the inode of 'file_name' or NIL_INODE. */
ino_t numb; /* inode number */
int r;
/* If rip is not NIL_INODE, it is used to get faster access to the inode. */
if (rip == NIL_INODE) {
/* Search for file in directory and try to get its inode. */
err_code = search_dir(dirp, file_name, &numb, LOOK_UP);
if (err_code == OK) rip = get_inode(dirp->i_dev, (int) numb);
if (err_code != OK || rip == NIL_INODE) return(err_code);
} else {
dup_inode(rip); /* inode will be returned with put_inode */
}
r = search_dir(dirp, file_name, (ino_t *) 0, DELETE);
if (r == OK) {
rip->i_nlinks--; /* entry deleted from parent's dir */
rip->i_update |= CTIME;
rip->i_dirt = DIRTY;
}
put_inode(rip);
return(r);
}

198
servers/mfs/main.c Normal file
View file

@ -0,0 +1,198 @@
#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;
}
}

34
servers/mfs/misc.c Normal file
View file

@ -0,0 +1,34 @@
#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 */
}

196
servers/mfs/mount.c Normal file
View file

@ -0,0 +1,196 @@
#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;
}

426
servers/mfs/open.c Normal file
View file

@ -0,0 +1,426 @@
#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;
}

View file

@ -12,20 +12,74 @@
#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 *
@ -44,22 +98,69 @@ int action; /* action on last part of path */
*/
struct inode *rip, *dir_ip;
struct inode *ver_rip;
char *new_name;
int symloop;
char lstring[NAME_MAX];
/* Find starting inode inode according to the request message */
if ((rip = find_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE) {
printf("FS: couldn't find starting inode req_nr: %d %s\n", req_nr,
user_path);
err_code = ENOENT;
return NIL_INODE;
}
/* Is the path absolute or relative? Initialize 'rip' accordingly. */
rip = (*path == '/' ? fp->fp_rootdir : fp->fp_workdir);
/* Find chroot inode according to the request message */
if (fs_m_in.REQ_CHROOT_NR != 0) {
if ((chroot_dir = find_inode(fs_dev, fs_m_in.REQ_CHROOT_NR))
== NIL_INODE) {
printf("FS: couldn't find chroot inode\n");
err_code = ENOENT;
return NIL_INODE;
}
}
else chroot_dir = NIL_INODE;
/* If dir has been removed or path is empty, return ENOENT. */
if (rip->i_nlinks == 0 || *path == '\0') {
/* Set user and group ID */
caller_uid = fs_m_in.REQ_UID;
caller_gid = fs_m_in.REQ_GID;
/* No characters were processed yet */
path_processed = 0;
/* Current number of symlinks encountered */
symloop = fs_m_in.REQ_SYMLOOP;
/* If dir has been removed return ENOENT. */
/* Note: empty (start) path is checked in the VFS process */
if (rip->i_nlinks == 0/* || *path == '\0'*/) {
err_code = ENOENT;
return(NIL_INODE);
}
dup_inode(rip); /* inode will be returned with put_inode */
/* There is only one way how the starting directory of the lookup
* can be a mount point which is not a root directory,
* namely: climbing up on a mount (ELEAVEMOUNT).
* In this case the lookup is intrested in the parent dir of the mount
* point, but the last ".." component was processed in the 'previous'
* FS process. Let's do that first.
*/
if (rip->i_mount == I_MOUNT && rip->i_num != ROOT_INODE) {
dir_ip = rip;
rip = advance(&dir_ip, "..");
if (rip == NIL_INODE) return rip;
put_inode(rip); /* advance() increased the counter */
}
dup_inode(rip); /* inode will be returned with put_inode */
/* Looking for the starting directory?
* Note: this happens after EENTERMOUNT or ELEAVEMOUNT
* without more path component */
if (*path == '\0') {
return rip;
}
symloop = 0; /* symbolic link traversal count */
if (string == (char *) 0) string = lstring;
/* Scan the path component by component. */
@ -83,31 +184,64 @@ int action; /* action on last part of path */
/* There is more path. Keep parsing. */
dir_ip = rip;
rip = advance(&dir_ip, string);
/* Mount point encountered? */
if (rip == NIL_INODE && (err_code == EENTERMOUNT ||
err_code == ELEAVEMOUNT)) {
put_inode(dir_ip);
return NIL_INODE;
}
if (rip == NIL_INODE) {
if (*new_name == '\0' && (action & PATH_NONSYMBOLIC) != 0)
return(dir_ip);
else {
put_inode(dir_ip);
return(NIL_INODE);
}
}
if (rip == NIL_INODE) {
if (*new_name == '\0' && (action & PATH_NONSYMBOLIC) != 0)
return(dir_ip);
else {
put_inode(dir_ip);
return(NIL_INODE);
}
}
/* The call to advance() succeeded. Fetch next component. */
if (S_ISLNK(rip->i_mode)) {
if (*new_name != '\0' || (action & PATH_OPAQUE) == 0) {
if (*new_name != '\0' || (action & PATH_OPAQUE) == 0) {
if (*new_name != '\0') new_name--;
rip = ltraverse(rip, path, new_name, dir_ip);
put_inode(dir_ip);
if (++symloop > SYMLOOP) {
err_code = ELOOP;
put_inode(rip);
rip = NIL_INODE;
/* Extract path name from the symlink file */
if (ltraverse(rip, user_path, new_name) != OK) {
put_inode(dir_ip);
err_code = ENOENT;
return NIL_INODE;
}
/* Symloop limit reached? */
if (++symloop > SYMLOOP) {
put_inode(dir_ip);
err_code = ELOOP;
return NIL_INODE;
}
/* Start over counting */
path_processed = 0;
/* Check whether new path is relative or absolute */
if (user_path[0] == '/') {
/* Go back to VFS */
put_inode(dir_ip);
err_code = ESYMLINK;
fs_m_out.RES_OFFSET = path_processed;
fs_m_out.RES_SYMLOOP = symloop;
return NIL_INODE;
}
/* Path is relative */
else {
rip = dir_ip;
path = user_path;
continue;
}
if (rip == NIL_INODE) return(NIL_INODE);
continue;
}
} else if (*new_name != '\0') {
}
else if (*new_name != '\0') {
put_inode(dir_ip);
path = new_name;
continue;
@ -124,60 +258,27 @@ int action; /* action on last part of path */
}
}
/*===========================================================================*
* eat_path *
*===========================================================================*/
PUBLIC struct inode *eat_path(path)
char *path; /* the path name to be parsed */
{
/* Parse the path 'path' and put its inode in the inode table. If not possible,
* return NIL_INODE as function value and an error code in 'err_code'.
*/
return parse_path(path, (char *) 0, EAT_PATH);
}
/*===========================================================================*
* last_dir *
*===========================================================================*/
PUBLIC struct inode *last_dir(path, string)
char *path; /* the path name to be parsed */
char string[NAME_MAX]; /* the final component is returned here */
{
/* Given a path, 'path', located in the fs address space, parse it as
* far as the last directory, fetch the inode for the last directory into
* the inode table, and return a pointer to the inode. In
* addition, return the final component of the path in 'string'.
* If the last directory can't be opened, return NIL_INODE and
* the reason for failure in 'err_code'.
*/
return parse_path(path, string, LAST_DIR);
}
/*===========================================================================*
* ltraverse *
*===========================================================================*/
PRIVATE struct inode *ltraverse(rip, path, suffix, ldip)
PRIVATE int ltraverse(rip, path, suffix)
register struct inode *rip; /* symbolic link */
char *path; /* path containing link */
char *suffix; /* suffix following link within path */
register struct inode *ldip; /* directory containing link */
{
/* Traverse a symbolic link. Copy the link text from the inode and insert
* the text into the path. Return the inode of base directory and the
* ammended path. The symbolic link inode is always freed. The inode
* returned is already duplicated. NIL_INODE is returned on error.
* the text into the path. Return error code or report success. Base
* directory has to be determined according to the first character of the
* new pathname.
*/
block_t b; /* block containing link text */
struct inode *bip; /* inode of base directory */
struct buf *bp; /* buffer containing link text */
size_t sl; /* length of link */
size_t tl; /* length of suffix */
char *sp; /* start of link text */
int r = OK;
bip = NIL_INODE;
bp = NIL_BUF;
if ((b = read_map(rip, (off_t) 0)) != NO_BLOCK) {
@ -188,62 +289,30 @@ register struct inode *ldip; /* directory containing link */
/* Insert symbolic text into path name. */
tl = strlen(suffix);
if (sl > 0 && sl + tl <= PATH_MAX-1) {
memmove(path+sl, suffix, tl);
memmove(path, sp, sl);
path[sl+tl] = 0;
dup_inode(bip = path[0] == '/' ? fp->fp_rootdir : ldip);
memmove(path+sl, suffix, tl);
memmove(path, sp, sl);
path[sl+tl] = 0;
/* Copy back to VFS layer THIS SHOULD BE IN parse_path */
r = sys_datacopy(SELF_E, (vir_bytes) path, FS_PROC_NR,
(vir_bytes) vfs_slink_storage, (phys_bytes) sl+tl+1);
/*
dup_inode(bip = path[0] == '/' ? chroot_dir : ldip);
*/
}
}
else {
r = ENOENT;
}
put_block(bp, DIRECTORY_BLOCK);
put_inode(rip);
if (bip == NIL_INODE)
{
err_code = ENOENT;
}
return (bip);
return r;
}
/*===========================================================================*
* get_name *
*===========================================================================*/
PRIVATE char *get_name(old_name, string)
char *old_name; /* path name to parse */
char string[NAME_MAX]; /* component extracted from 'old_name' */
{
/* Given a pointer to a path name in fs space, 'old_name', copy the next
* component to 'string' and pad with zeros. A pointer to that part of
* the name as yet unparsed is returned. Roughly speaking,
* 'get_name' = 'old_name' - 'string'.
*
* This routine follows the standard convention that /usr/ast, /usr//ast,
* //usr///ast and /usr/ast/ are all equivalent.
*/
register int c;
register char *np, *rnp;
np = string; /* 'np' points to current position */
rnp = old_name; /* 'rnp' points to unparsed string */
while ( (c = *rnp) == '/') rnp++; /* skip leading slashes */
/* Copy the unparsed path, 'old_name', to the array, 'string'. */
while ( rnp < &old_name[PATH_MAX] && c != '/' && c != '\0') {
if (np < &string[NAME_MAX]) *np++ = c;
c = *++rnp; /* advance to next character */
}
/* To make /usr/ast/ equivalent to /usr/ast, skip trailing slashes. */
while (c == '/' && rnp < &old_name[PATH_MAX]) c = *++rnp;
if (np < &string[NAME_MAX]) *np = '\0'; /* Terminate string */
if (rnp >= &old_name[PATH_MAX]) {
err_code = ENAMETOOLONG;
return((char *) 0);
}
return(rnp);
}
/*===========================================================================*
* advance *
@ -277,14 +346,18 @@ char string[NAME_MAX]; /* component name to look for */
return(NIL_INODE);
}
/* Don't go beyond the current root directory, unless the string is dot2. */
if (dirp == fp->fp_rootdir && strcmp(string, "..") == 0 && string != dot2)
return(get_inode(dirp->i_dev, (int) dirp->i_num));
/* Don't go beyond the current root directory, unless the string is dot2.
* Note: it has to be checked only if this FS process owns the chroot
* directory of the process */
if (chroot_dir != NIL_INODE) {
if (dirp == chroot_dir && strcmp(string, "..") == 0 && string != dot2)
return(get_inode(dirp->i_dev, (int) dirp->i_num));
}
/* The component has been found in the directory. Get inode. */
if ( (rip = get_inode(dirp->i_dev, (int) numb)) == NIL_INODE) {
return(NIL_INODE);
}
}
/* The following test is for "mountpoint/.." where mountpoint is a
* mountpoint. ".." will refer to the root of the mounted filesystem,
@ -296,46 +369,97 @@ char string[NAME_MAX]; /* component name to look for */
* root inode, _and_ the name[1] being '.'. (This is a test for '..'
* and excludes '.'.)
*/
if (rip->i_num == ROOT_INODE)
if (dirp->i_num == ROOT_INODE) {
if (string[1] == '.') {
sp= rip->i_sp;
if (sp->s_imount != sp->s_isup)
{
/* Release the root inode. Replace by the
* inode mounted on. Update parent.
*/
put_inode(rip);
put_inode(dirp);
mnt_dev = sp->s_imount->i_dev;
inumb = (int) sp->s_imount->i_num;
dirp = *pdirp = get_inode(mnt_dev, inumb);
rip = advance(pdirp, string);
}
}
}
if (rip->i_num == ROOT_INODE) {
if (dirp->i_num == ROOT_INODE) {
if (string[1] == '.') {
sp = rip->i_sp;
if (!sp->s_is_root) {
/*printf("FSadvance: ELEAVEMOUNT callnr: %d, cp: %d, restp: %s\n",
call_nr, path_processed, user_path + path_processed);*/
/* Climbing up mountpoint */
err_code = ELEAVEMOUNT;
/* This will be the FS process endoint */
fs_m_out.m_source = rip->i_dev;
fs_m_out.RES_OFFSET = path_processed;
fs_m_out.RES_SYMLOOP = symloop;
put_inode(rip);
/*put_inode(dirp);*/
rip = NIL_INODE;
}
}
}
}
if (rip == NIL_INODE) return(NIL_INODE);
/* See if the inode is mounted on. If so, switch to root directory of the
* mounted file system. The super_block provides the linkage between the
* inode mounted on and the root directory of the mounted file system.
*/
while (rip != NIL_INODE && rip->i_mount == I_MOUNT) {
/* The inode is indeed mounted on. */
for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) {
if (sp->s_imount == rip) {
/* Release the inode mounted on. Replace by the
* inode of the root inode of the mounted device.
*/
put_inode(rip);
rip = get_inode(sp->s_dev, ROOT_INODE);
break;
}
}
if (rip != NIL_INODE && rip->i_mount == I_MOUNT) {
/*printf("FSadvance: EENTERMOUNT callnr: %d, cp: %d, vmnti: %d, restp: %s\n",
call_nr, path_processed, rip->i_vmnt_ind, user_path + path_processed);*/
/* Mountpoint encountered, report it */
err_code = EENTERMOUNT;
fs_m_out.RES_INODE_NR = rip->i_num;
fs_m_out.RES_OFFSET = path_processed;
fs_m_out.RES_SYMLOOP = symloop;
put_inode(rip);
rip = NIL_INODE;
}
return(rip); /* return pointer to inode's component */
}
/*===========================================================================*
* get_name *
*===========================================================================*/
PRIVATE char *get_name(old_name, string)
char *old_name; /* path name to parse */
char string[NAME_MAX]; /* component extracted from 'old_name' */
{
/* Given a pointer to a path name in fs space, 'old_name', copy the next
* component to 'string' and pad with zeros. A pointer to that part of
* the name as yet unparsed is returned. Roughly speaking,
* 'get_name' = 'old_name' - 'string'.
*
* This routine follows the standard convention that /usr/ast, /usr//ast,
* //usr///ast and /usr/ast/ are all equivalent.
*/
register int c;
register char *np, *rnp;
np = string; /* 'np' points to current position */
rnp = old_name; /* 'rnp' points to unparsed string */
while ( (c = *rnp) == '/') {
rnp++; /* skip leading slashes */
path_processed++; /* count characters */
}
/* Copy the unparsed path, 'old_name', to the array, 'string'. */
while ( rnp < &old_name[PATH_MAX] && c != '/' && c != '\0') {
if (np < &string[NAME_MAX]) *np++ = c;
c = *++rnp; /* advance to next character */
path_processed++; /* count characters */
}
/* To make /usr/ast/ equivalent to /usr/ast, skip trailing slashes. */
while (c == '/' && rnp < &old_name[PATH_MAX]) {
c = *++rnp;
path_processed++; /* count characters */
}
if (np < &string[NAME_MAX]) *np = '\0'; /* Terminate string */
if (rnp >= &old_name[PATH_MAX]) {
err_code = ENAMETOOLONG;
return((char *) 0);
}
return(rnp);
}
/*===========================================================================*
* search_dir *
*===========================================================================*/
@ -368,7 +492,7 @@ int flag; /* LOOK_UP, ENTER, DELETE or IS_EMPTY */
if ( (ldir_ptr->i_mode & I_TYPE) != I_DIRECTORY) {
return(ENOTDIR);
}
r = OK;
if (flag != IS_EMPTY) {
@ -413,7 +537,7 @@ int flag; /* LOOK_UP, ENTER, DELETE or IS_EMPTY */
if (strcmp(dp->d_name, "." ) != 0 &&
strcmp(dp->d_name, "..") != 0) match = 1;
} else {
if (strncmp(dp->d_name, string, NAME_MAX) == 0) {
if (strncmp(dp->d_name, string, NAME_MAX) == 0){
match = 1;
}
}
@ -484,3 +608,35 @@ int flag; /* LOOK_UP, ENTER, DELETE or IS_EMPTY */
}
return(OK);
}
/*===========================================================================*
* eat_path *
*===========================================================================*/
PUBLIC struct inode *eat_path(path)
char *path; /* the path name to be parsed */
{
/* Parse the path 'path' and put its inode in the inode table. If not possible,
* return NIL_INODE as function value and an error code in 'err_code'.
*/
return parse_path(path, (char *) 0, EAT_PATH);
}
/*===========================================================================*
* last_dir *
*===========================================================================*/
PUBLIC struct inode *last_dir(path, string)
char *path; /* the path name to be parsed */
char string[NAME_MAX]; /* the final component is returned here */
{
/* Given a path, 'path', located in the fs address space, parse it as
* far as the last directory, fetch the inode for the last directory into
* the inode table, and return a pointer to the inode. In
* addition, return the final component of the path in 'string'.
* If the last directory can't be opened, return NIL_INODE and
* the reason for failure in 'err_code'.
*/
return parse_path(path, string, LAST_DIR);
}

57
servers/mfs/pipe.c Normal file
View file

@ -0,0 +1,57 @@
#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;
}

View file

@ -1,146 +1,123 @@
/* This file deals with protection in the file system. It contains the code
* for four system calls that relate to protection.
*
* The entry points into this file are
* do_chmod: perform the CHMOD and FCHMOD system calls
* do_chown: perform the CHOWN and FCHOWN system calls
* do_umask: perform the UMASK system call
* do_access: perform the ACCESS system call
* forbidden: check to see if a given access is allowed on a given inode
*/
#include "fs.h"
#include <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);
}
@ -159,20 +136,20 @@ PUBLIC int forbidden(register struct inode *rip, mode_t access_desired)
register struct inode *old_rip = rip;
register struct super_block *sp;
register mode_t bits, perm_bits;
int r, shift, test_uid, test_gid, type;
int r, shift, type;
if (rip->i_mount == I_MOUNT) /* The inode is mounted on. */
/*
if (rip->i_mount == I_MOUNT)
for (sp = &super_block[1]; sp < &super_block[NR_SUPERS]; sp++)
if (sp->s_imount == rip) {
rip = get_inode(sp->s_dev, ROOT_INODE);
break;
} /* if */
}
*/
/* Isolate the relevant rwx bits from the mode. */
bits = rip->i_mode;
test_uid = (call_nr == ACCESS ? fp->fp_realuid : fp->fp_effuid);
test_gid = (call_nr == ACCESS ? fp->fp_realgid : fp->fp_effgid);
if (test_uid == SU_UID) {
if (caller_uid == SU_UID) {
/* Grant read and write permission. Grant search permission for
* directories. Grant execute permission (for non-directories) if
* and only if one of the 'X' bits is set.
@ -183,8 +160,8 @@ PUBLIC int forbidden(register struct inode *rip, mode_t access_desired)
else
perm_bits = R_BIT | W_BIT;
} else {
if (test_uid == rip->i_uid) shift = 6; /* owner */
else if (test_gid == rip->i_gid ) shift = 3; /* group */
if (caller_uid == rip->i_uid) shift = 6; /* owner */
else if (caller_gid == rip->i_gid ) shift = 3; /* group */
else shift = 0; /* other */
perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT);
}
@ -203,6 +180,7 @@ PUBLIC int forbidden(register struct inode *rip, mode_t access_desired)
if (rip != old_rip) put_inode(rip);
/*printf("FSforbidden: %s %s\n", user_path, (r == OK ? "OK" : "notOK")); */
return(r);
}
@ -221,3 +199,6 @@ struct inode *ip; /* ptr to inode whose file sys is to be cked */
sp = ip->i_sp;
return(sp->s_rd_only ? EROFS : OK);
}

View file

@ -2,15 +2,53 @@
#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) );
@ -30,51 +68,13 @@ _PROTOTYPE( void invalidate2, (Dev_t device) );
#endif
/* device.c */
_PROTOTYPE( int dev_open, (Dev_t dev, int proc, int flags) );
_PROTOTYPE( void dev_close, (Dev_t dev) );
_PROTOTYPE( int dev_bio, (int op, Dev_t dev, int proc, void *buf,
off_t pos, int bytes) );
_PROTOTYPE( int dev_io, (int op, Dev_t dev, int proc, void *buf,
_PROTOTYPE( int block_dev_io, (int op, Dev_t dev, int proc, void *buf,
off_t pos, int bytes, int flags) );
_PROTOTYPE( int gen_opcl, (int op, Dev_t dev, int proc, int flags) );
_PROTOTYPE( int gen_io, (int task_nr, message *mess_ptr) );
_PROTOTYPE( int no_dev, (int op, Dev_t dev, int proc, int flags) );
_PROTOTYPE( int no_dev_io, (int, message *) );
_PROTOTYPE( int tty_opcl, (int op, Dev_t dev, int proc, int flags) );
_PROTOTYPE( int ctty_opcl, (int op, Dev_t dev, int proc, int flags) );
_PROTOTYPE( int clone_opcl, (int op, Dev_t dev, int proc, int flags) );
_PROTOTYPE( int ctty_io, (int task_nr, message *mess_ptr) );
_PROTOTYPE( int do_ioctl, (void) );
_PROTOTYPE( void pm_setsid, (int proc_e) );
_PROTOTYPE( void dev_status, (message *) );
_PROTOTYPE( void dev_up, (int major) );
/* dmp.c */
_PROTOTYPE( int do_fkey_pressed, (void) );
/* dmap.c */
_PROTOTYPE( int do_devctl, (void) );
_PROTOTYPE( int fs_devctl, (int req, int dev, int proc_nr_e, int style,
int force) );
_PROTOTYPE( void build_dmap, (void) );
_PROTOTYPE( int map_driver, (int major, int proc_nr, int dev_style,
int force) );
_PROTOTYPE( int dmap_driver_match, (int proc, int major) );
_PROTOTYPE( void dmap_unmap_by_endpt, (int proc_nr) );
_PROTOTYPE( void dmap_endpt_up, (int proc_nr) );
/* exec.c */
_PROTOTYPE( int pm_exec, (int proc_e, char *path, vir_bytes path_len,
char *frame, vir_bytes frame_len) );
/* filedes.c */
_PROTOTYPE( struct filp *find_filp, (struct inode *rip, mode_t bits) );
_PROTOTYPE( int get_fd, (int start, mode_t bits, int *k, struct filp **fpt) );
_PROTOTYPE( struct filp *get_filp, (int fild) );
_PROTOTYPE( struct filp *get_filp2, (struct fproc *rfp, int fild) );
_PROTOTYPE( int inval_filp, (struct filp *) );
/* inode.c */
_PROTOTYPE( struct inode *find_inode, (Dev_t dev, int numb) );
_PROTOTYPE( struct inode *alloc_inode, (dev_t dev, mode_t bits) );
_PROTOTYPE( void dup_inode, (struct inode *ip) );
_PROTOTYPE( void free_inode, (Dev_t dev, Ino_t numb) );
@ -85,11 +85,6 @@ _PROTOTYPE( void rw_inode, (struct inode *rip, int rw_flag) );
_PROTOTYPE( void wipe_inode, (struct inode *rip) );
/* link.c */
_PROTOTYPE( int do_link, (void) );
_PROTOTYPE( int do_unlink, (void) );
_PROTOTYPE( int do_rename, (void) );
_PROTOTYPE( int do_truncate, (void) );
_PROTOTYPE( int do_ftruncate, (void) );
_PROTOTYPE( int truncate_inode, (struct inode *rip, off_t len) );
_PROTOTYPE( int freesp_inode, (struct inode *rip, off_t st, off_t end) );
@ -99,21 +94,21 @@ _PROTOTYPE( void lock_revive, (void) );
/* main.c */
_PROTOTYPE( int main, (void) );
_PROTOTYPE( void reply, (int whom, int result) );
_PROTOTYPE( void reply, (int who, message *m_out) );
/* misc.c */
_PROTOTYPE( int do_dup, (void) );
_PROTOTYPE( void pm_exit, (int proc) );
_PROTOTYPE( int do_exit, (void) );
_PROTOTYPE( int do_fcntl, (void) );
_PROTOTYPE( void pm_fork, (int pproc, int cproc, int cpid) );
_PROTOTYPE( void pm_setgid, (int proc_e, int egid, int rgid) );
_PROTOTYPE( void pm_setuid, (int proc_e, int euid, int ruid) );
_PROTOTYPE( int do_fork, (void) );
_PROTOTYPE( int do_exec, (void) );
_PROTOTYPE( int do_revive, (void) );
_PROTOTYPE( int do_set, (void) );
_PROTOTYPE( int do_sync, (void) );
_PROTOTYPE( int do_fsync, (void) );
_PROTOTYPE( void pm_reboot, (void) );
_PROTOTYPE( int do_reboot, (void) );
_PROTOTYPE( int do_svrctl, (void) );
_PROTOTYPE( int do_getsysinfo, (void) );
_PROTOTYPE( int pm_dumpcore, (int proc_e, struct mem_map *seg_ptr) );
/* mount.c */
_PROTOTYPE( int do_mount, (void) );
@ -122,15 +117,12 @@ _PROTOTYPE( int unmount, (Dev_t dev) );
/* open.c */
_PROTOTYPE( int do_close, (void) );
_PROTOTYPE( int close_fd, (struct fproc *rfp, int fd_nr) );
_PROTOTYPE( int do_creat, (void) );
_PROTOTYPE( int do_lseek, (void) );
_PROTOTYPE( int do_mknod, (void) );
_PROTOTYPE( int do_mkdir, (void) );
_PROTOTYPE( int do_open, (void) );
_PROTOTYPE( int do_slink, (void) );
_PROTOTYPE( struct inode *new_node, (struct inode **ldirp,
char *path, mode_t bits, zone_t z0, int opaque, char *string) );
_PROTOTYPE( int do_slink, (void) );
/* path.c */
_PROTOTYPE( struct inode *advance,(struct inode **dirp, char string[NAME_MAX]));
@ -141,19 +133,6 @@ _PROTOTYPE( struct inode *last_dir, (char *path, char string [NAME_MAX]));
_PROTOTYPE( struct inode *parse_path, (char *path, char string[NAME_MAX],
int action) );
/* pipe.c */
_PROTOTYPE( int do_pipe, (void) );
_PROTOTYPE( int do_unpause, (void) );
_PROTOTYPE( int unpause, (int proc_nr_e) );
_PROTOTYPE( int pipe_check, (struct inode *rip, int rw_flag,
int oflags, int bytes, off_t position, int *canwrite, int notouch));
_PROTOTYPE( void release, (struct inode *ip, int call_nr, int count) );
_PROTOTYPE( void revive, (int proc_nr, int bytes) );
_PROTOTYPE( void suspend, (int task) );
_PROTOTYPE( int select_request_pipe, (struct filp *f, int *ops, int bl) );
_PROTOTYPE( int select_cancel_pipe, (struct filp *f) );
_PROTOTYPE( int select_match_pipe, (struct filp *f) );
_PROTOTYPE( void unsuspend_by_endpt, (int) );
/* protect.c */
_PROTOTYPE( int do_access, (void) );
@ -228,3 +207,6 @@ _PROTOTYPE( void fs_set_timer, (timer_t *tp, int delta, tmr_func_t watchdog, int
_PROTOTYPE( void fs_expire_timers, (clock_t now) );
_PROTOTYPE( void fs_cancel_timer, (timer_t *tp) );
_PROTOTYPE( void fs_init_timer, (timer_t *tp) );
/* cdprobe.c */
_PROTOTYPE( int cdprobe, (void) );

215
servers/mfs/queue.h Normal file
View file

@ -0,0 +1,215 @@
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
#define __offsetof(type, field) ((size_t)(&((type *)0)->field))
#define __rangeof(type, start, end) \
(__offsetof(type, end) - __offsetof(type, start))
#define QMD_TRACE_ELEM(elem)
#define QMD_TRACE_HEAD(head)
#define TRACEBUF
#define TRASHIT(x)
/*
* List declarations.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List functions.
*/
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_FOREACH(var, head, field) \
for ((var) = LIST_FIRST((head)); \
(var); \
(var) = LIST_NEXT((var), field))
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST((head)); \
(var) && ((tvar) = LIST_NEXT((var), field), 1); \
(var) = (tvar))
#define LIST_INIT(head) do { \
LIST_FIRST((head)) = NULL; \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
LIST_NEXT((listelm), field)->field.le_prev = \
&LIST_NEXT((elm), field); \
LIST_NEXT((listelm), field) = (elm); \
(elm)->field.le_prev = &LIST_NEXT((listelm), field); \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.le_prev = (listelm)->field.le_prev; \
LIST_NEXT((elm), field) = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &LIST_NEXT((elm), field); \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
LIST_FIRST((head)) = (elm); \
(elm)->field.le_prev = &LIST_FIRST((head)); \
} while (0)
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_REMOVE(elm, field) do { \
if (LIST_NEXT((elm), field) != NULL) \
LIST_NEXT((elm), field)->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = LIST_NEXT((elm), field); \
} while (0)
/*
* Tail queue declarations.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
TRACEBUF \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
TRACEBUF \
}
/*
* Tail queue functions.
*/
#define TAILQ_CONCAT(head1, head2, field) do { \
if (!TAILQ_EMPTY(head2)) { \
*(head1)->tqh_last = (head2)->tqh_first; \
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_HEAD(head2); \
} \
} while (0)
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_FOREACH(var, head, field) \
for ((var) = TAILQ_FIRST((head)); \
(var); \
(var) = TAILQ_NEXT((var), field))
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST((head)); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for ((var) = TAILQ_LAST((head), headname); \
(var); \
(var) = TAILQ_PREV((var), headname, field))
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = TAILQ_LAST((head), headname); \
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
(var) = (tvar))
#define TAILQ_INIT(head) do { \
TAILQ_FIRST((head)) = NULL; \
(head)->tqh_last = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
TAILQ_NEXT((elm), field)->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else { \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
} \
TAILQ_NEXT((listelm), field) = (elm); \
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
TAILQ_NEXT((elm), field) = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
TAILQ_FIRST((head))->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
TAILQ_FIRST((head)) = (elm); \
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
TAILQ_NEXT((elm), field) = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_REMOVE(head, elm, field) do { \
if ((TAILQ_NEXT((elm), field)) != NULL) \
TAILQ_NEXT((elm), field)->field.tqe_prev = \
(elm)->field.tqe_prev; \
else { \
(head)->tqh_last = (elm)->field.tqe_prev; \
QMD_TRACE_HEAD(head); \
} \
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
TRASHIT((elm)->field.tqe_next); \
TRASHIT((elm)->field.tqe_prev); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#endif /* _SYS_QUEUE_H */

View file

@ -1,213 +1,135 @@
/* This file contains the heart of the mechanism used to read (and write)
* files. Read and write requests are split up into chunks that do not cross
* block boundaries. Each chunk is then processed in turn. Reads on special
* files are also detected and handled.
*
* The entry points into this file are
* do_read: perform the READ system call by calling read_write
* read_write: actually do the work of READ and WRITE
* read_map: given an inode and file position, look up its zone number
* rd_indir: read an entry in an indirect block
* read_ahead: manage the block read ahead business
*/
#include "fs.h"
#include <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;
/* Try to get inode according to its index */
if (fs_m_in.REQ_FD_INODE_INDEX >= 0 &&
fs_m_in.REQ_FD_INODE_INDEX < NR_INODES &&
inode[fs_m_in.REQ_FD_INODE_INDEX].i_num == fs_m_in.REQ_FD_INODE_NR) {
rip = &inode[fs_m_in.REQ_FD_INODE_INDEX];
}
op = (rw_flag == READING ? DEV_READ : DEV_WRITE);
else {
/* Find the inode referred */
rip = find_inode(fs_dev, fs_m_in.REQ_FD_INODE_NR);
if (!rip) {
printf("FS: unavaliable inode by fs_readwrite(), nr: %d\n",
fs_m_in.REQ_FD_INODE_NR);
return EINVAL;
}
}
mode_word = rip->i_mode & I_TYPE;
regular = mode_word == I_REGULAR || mode_word == I_NAMED_PIPE;
regular = (mode_word == I_REGULAR || mode_word == I_NAMED_PIPE);
block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 : 0);
/* Determine blocksize */
block_size = (block_spec ? get_block_size(rip->i_zone[0])
: rip->i_sp->s_block_size);
if ((char_spec = (mode_word == I_CHAR_SPECIAL ? 1 : 0))) {
if (rip->i_zone[0] == NO_DEV)
panic(__FILE__,"read_write tries to read from "
"character device NO_DEV", NO_NUM);
block_size = get_block_size(rip->i_zone[0]);
}
if ((block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 : 0))) {
f_size = ULONG_MAX;
if (rip->i_zone[0] == NO_DEV)
panic(__FILE__,"read_write tries to read from "
" block device NO_DEV", NO_NUM);
block_size = get_block_size(rip->i_zone[0]);
}
if (!char_spec && !block_spec)
block_size = rip->i_sp->s_block_size;
f_size = (block_spec ? ULONG_MAX : rip->i_size);
/* Get the values from the request message */
rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING);
usr = fs_m_in.REQ_FD_WHO_E;
seg = fs_m_in.REQ_FD_SEG;
position = fs_m_in.REQ_FD_POS;
nrbytes = (unsigned) fs_m_in.REQ_FD_NBYTES;
/*partial_cnt = fs_m_in.REQ_FD_PARTIAL;*/
user_addr = fs_m_in.REQ_FD_USER_ADDR;
/*if (partial_cnt > 0) partial_pipe = 1;*/
rdwt_err = OK; /* set to EIO if disk error occurs */
if (rw_flag == WRITING && block_spec == 0) {
/* Clear the zone containing present EOF if hole about
* to be created. This is necessary because all unwritten
* blocks prior to the EOF must read as zeros.
*/
if (position > f_size) clear_zone(rip, f_size, 0);
}
cum_io = 0;
/* Split the transfer into chunks that don't span two blocks. */
while (nrbytes != 0) {
off = (unsigned int) (position % block_size);/* offset in blk*/
chunk = MIN(nrbytes, block_size - off);
if (chunk < 0) chunk = block_size - off;
/* Check for character special files. */
if (char_spec) {
dev_t dev;
dev = (dev_t) rip->i_zone[0];
r = dev_io(op, dev, usr, m_in.buffer, position, m_in.nbytes, oflags);
if (r >= 0) {
cum_io = r;
position += r;
r = OK;
}
} else {
if (rw_flag == WRITING && block_spec == 0) {
/* Check in advance to see if file will grow too big. */
if (position > rip->i_sp->s_max_size - m_in.nbytes)
return(EFBIG);
if (rw_flag == READING) {
bytes_left = f_size - position;
if (position >= f_size) break; /* we are beyond EOF */
if (chunk > bytes_left) chunk = (int) bytes_left;
}
/* Check for O_APPEND flag. */
if (oflags & O_APPEND) position = f_size;
/* Read or write 'chunk' bytes. */
r = rw_chunk(rip, position, off, chunk, (unsigned) nrbytes,
rw_flag, user_addr, seg, usr, block_size, &completed);
/* Clear the zone containing present EOF if hole about
* to be created. This is necessary because all unwritten
* blocks prior to the EOF must read as zeros.
*/
if (position > f_size) clear_zone(rip, f_size, 0);
}
if (r != OK) break; /* EOF reached */
if (rdwt_err < 0) break;
/* Pipes are a little different. Check. */
if (rip->i_pipe == I_PIPE) {
r = pipe_check(rip, rw_flag, oflags,
m_in.nbytes, position, &partial_cnt, 0);
if (r <= 0) return(r);
}
if (partial_cnt > 0) partial_pipe = 1;
/* Split the transfer into chunks that don't span two blocks. */
while (m_in.nbytes != 0) {
off = (unsigned int) (position % block_size);/* offset in blk*/
if (partial_pipe) { /* pipes only */
chunk = MIN(partial_cnt, block_size - off);
} else
chunk = MIN(m_in.nbytes, block_size - off);
if (chunk < 0) chunk = block_size - off;
if (rw_flag == READING) {
bytes_left = f_size - position;
if (position >= f_size) break; /* we are beyond EOF */
if (chunk > bytes_left) chunk = (int) bytes_left;
}
/* Read or write 'chunk' bytes. */
r = rw_chunk(rip, position, off, chunk, (unsigned) m_in.nbytes,
rw_flag, m_in.buffer, seg, usr, block_size, &completed);
if (r != OK) break; /* EOF reached */
if (rdwt_err < 0) break;
/* Update counters and pointers. */
m_in.buffer += chunk; /* user buffer address */
m_in.nbytes -= chunk; /* bytes yet to be read */
cum_io += chunk; /* bytes read so far */
position += chunk; /* position within the file */
if (partial_pipe) {
partial_cnt -= chunk;
if (partial_cnt <= 0) break;
}
}
/* Update counters and pointers. */
user_addr += chunk; /* user buffer address */
nrbytes -= chunk; /* bytes yet to be read */
cum_io += chunk; /* bytes read so far */
position += chunk; /* position within the file */
}
fs_m_out.RES_FD_POS = position; /* It might change later and the VFS has
to know this value */
/* On write, update file size and access time. */
if (rw_flag == WRITING) {
if (regular || mode_word == I_DIRECTORY) {
if (position > f_size) rip->i_size = position;
}
} else {
}
else {
if (rip->i_pipe == I_PIPE) {
if ( position >= rip->i_size) {
/* Reset pipe pointers. */
rip->i_size = 0; /* no data left */
position = 0; /* reset reader(s) */
wf = find_filp(rip, W_BIT);
if (wf != NIL_FILP) wf->filp_pos = 0;
}
}
}
f->filp_pos = position;
/* Check to see if read-ahead is called for, and if so, set it up. */
if (rw_flag == READING && rip->i_seek == NO_SEEK && position % block_size== 0
if (rw_flag == READING && rip->i_seek == NO_SEEK && position % block_size == 0
&& (regular || mode_word == I_DIRECTORY)) {
rdahed_inode = rip;
rdahedpos = position;
@ -221,26 +143,94 @@ int rw_flag; /* READING or WRITING */
if (r == OK && r2 != OK) {
r = r2;
}
if (r == OK) {
if (rw_flag == READING) rip->i_update |= ATIME;
if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME;
rip->i_dirt = DIRTY; /* inode is thus now dirty */
if (partial_pipe) {
partial_pipe = 0;
/* partial write on pipe with */
/* O_NONBLOCK, return write count */
if (!(oflags & O_NONBLOCK)) {
fp->fp_cum_io_partial = cum_io;
suspend(XPIPE); /* partial write on pipe with */
return(SUSPEND); /* nbyte > PIPE_SIZE - non-atomic */
}
}
fp->fp_cum_io_partial = 0;
return(cum_io);
}
fs_m_out.RES_FD_CUM_IO = cum_io;
fs_m_out.RES_FD_SIZE = rip->i_size;
return(r);
}
/*===========================================================================*
* fs_breadwrite *
*===========================================================================*/
PUBLIC int fs_breadwrite(void)
{
int r, usr, rw_flag, chunk, block_size;
int nrbytes;
off_t position, f_size, bytes_left;
unsigned int off, cum_io;
mode_t mode_word;
int completed, r2 = OK;
char *user_addr;
/* Pseudo inode for rw_chunk */
struct inode rip;
r = OK;
f_size = ULONG_MAX;
/* Get the values from the request message */
rw_flag = (fs_m_in.m_type == REQ_BREAD ? READING : WRITING);
usr = fs_m_in.REQ_FD_WHO_E;
position = fs_m_in.REQ_FD_POS;
nrbytes = (unsigned) fs_m_in.REQ_FD_NBYTES;
user_addr = fs_m_in.REQ_FD_USER_ADDR;
block_size = get_block_size(fs_m_in.REQ_FD_BDEV);
rip.i_zone[0] = fs_m_in.REQ_FD_BDEV;
rip.i_mode = I_BLOCK_SPECIAL;
rip.i_size = f_size;
rdwt_err = OK; /* set to EIO if disk error occurs */
cum_io = 0;
/* Split the transfer into chunks that don't span two blocks. */
while (nrbytes != 0) {
off = (unsigned int) (position % block_size);/* offset in blk*/
chunk = MIN(nrbytes, block_size - off);
if (chunk < 0) chunk = block_size - off;
if (rw_flag == READING) {
bytes_left = f_size - position;
if (position >= f_size) break; /* we are beyond EOF */
if (chunk > bytes_left) chunk = (int) bytes_left;
}
/* Read or write 'chunk' bytes. */
r = rw_chunk(&rip, position, off, chunk, (unsigned) nrbytes,
rw_flag, user_addr, D, usr, block_size, &completed);
if (r != OK) break; /* EOF reached */
if (rdwt_err < 0) break;
/* Update counters and pointers. */
user_addr += chunk; /* user buffer address */
nrbytes -= chunk; /* bytes yet to be read */
cum_io += chunk; /* bytes read so far */
position += chunk; /* position within the file */
}
fs_m_out.RES_FD_POS = position;
if (rdwt_err != OK) r = rdwt_err; /* check for disk error */
if (rdwt_err == END_OF_FILE) r = OK;
fs_m_out.RES_FD_CUM_IO = cum_io;
fs_m_out.RES_FD_SIZE = rip.i_size;
return(r);
}
/*===========================================================================*
* rw_chunk *
*===========================================================================*/
@ -269,10 +259,12 @@ int *completed; /* number of bytes copied */
*completed = 0;
block_spec = (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL;
if (block_spec) {
b = position/block_size;
dev = (dev_t) rip->i_zone[0];
} else {
}
else {
b = read_map(rip, position);
dev = rip->i_dev;
}
@ -282,14 +274,17 @@ int *completed; /* number of bytes copied */
/* Reading from a nonexistent block. Must read as all zeros.*/
bp = get_block(NO_DEV, NO_BLOCK, NORMAL); /* get a buffer */
zero_block(bp);
} else {
}
else {
/* Writing to a nonexistent block. Create and enter in inode.*/
if ((bp= new_block(rip, position)) == NIL_BUF)return(err_code);
}
} else if (rw_flag == READING) {
}
else if (rw_flag == READING) {
/* Read and read ahead if convenient. */
bp = rahead(rip, b, position, left);
} else {
}
else {
/* Normally an existing block to be partially overwritten is first read
* in. However, a full block need not be read in. If it is already in
* the cache, acquire it, otherwise just acquire a free buffer.
@ -303,6 +298,7 @@ int *completed; /* number of bytes copied */
if (bp == NIL_BUF) {
panic(__FILE__,"bp not valid in rw_chunk, this can't happen", NO_NUM);
}
if (rw_flag == WRITING && chunk != block_size && !block_spec &&
position >= rip->i_size && off == 0) {
zero_block(bp);
@ -310,13 +306,14 @@ int *completed; /* number of bytes copied */
if (rw_flag == READING) {
/* Copy a chunk from the block buffer to user space. */
r = sys_vircopy(FS_PROC_NR, D, (phys_bytes) (bp->b_data+off),
r = sys_vircopy(SELF_E, D, (phys_bytes) (bp->b_data+off),
usr, seg, (phys_bytes) buff,
(phys_bytes) chunk);
} else {
}
else {
/* Copy a chunk from user space to the block buffer. */
r = sys_vircopy(usr, seg, (phys_bytes) buff,
FS_PROC_NR, D, (phys_bytes) (bp->b_data+off),
SELF_E, D, (phys_bytes) (bp->b_data+off),
(phys_bytes) chunk);
bp->b_dirt = DIRTY;
}
@ -558,3 +555,4 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */
rw_scattered(dev, read_q, read_q_size, READING);
return(get_block(dev, baseblock, NORMAL));
}

209
servers/mfs/stadir.c Normal file
View file

@ -0,0 +1,209 @@
#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);
}

View file

@ -19,6 +19,7 @@
#include "super.h"
#include "const.h"
/*===========================================================================*
* alloc_bit *
*===========================================================================*/
@ -155,6 +156,7 @@ dev_t dev; /* device number whose super_block is sought */
for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++)
if (sp->s_dev == dev) return(sp);
printf("MFS(%d)get_super: sp->s_dev: %d, dev: %d\n", SELF_E, sp->s_dev, dev);
/* Search failed. Something wrong. */
panic(__FILE__,"can't find superblock for device (in decimal)", (int) dev);
@ -187,23 +189,24 @@ PUBLIC int get_block_size(dev_t dev)
/*===========================================================================*
* mounted *
*===========================================================================*/
PUBLIC int mounted(rip)
register struct inode *rip; /* pointer to inode */
{
/* Report on whether the given inode is on a mounted (or ROOT) file system. */
/*
PUBLIC int mounted(rip)
register struct inode *rip;
{
register struct super_block *sp;
register dev_t dev;
dev = (dev_t) rip->i_zone[0];
if (dev == root_dev) return(TRUE); /* inode is on root file system */
if (dev == root_dev) return(TRUE);
for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++)
if (sp->s_dev == dev) return(TRUE);
return(FALSE);
}
*/
/*===========================================================================*
* read_super *
*===========================================================================*/
@ -219,9 +222,11 @@ register struct super_block *sp; /* pointer to a superblock */
dev = sp->s_dev; /* save device (will be overwritten by copy) */
if (dev == NO_DEV)
panic(__FILE__,"request for super_block of NO_DEV", NO_NUM);
r = dev_io(DEV_READ, dev, FS_PROC_NR,
r = block_dev_io(DEV_READ, dev, SELF_E,
sbbuf, SUPER_BLOCK_BYTES, _MIN_BLOCK_SIZE, 0);
if (r != _MIN_BLOCK_SIZE) {
printf("MFSread_super r != _MIN_BLOCK_SIZE\n");
return EINVAL;
}
memcpy(sp, sbbuf, sizeof(*sp));
@ -239,6 +244,7 @@ register struct super_block *sp; /* pointer to a superblock */
version = V3;
native = 1;
} else {
printf("MFSread_super invalid version\n");
return(EINVAL);
}
@ -273,14 +279,17 @@ register struct super_block *sp; /* pointer to a superblock */
} else {
if (version == V2)
sp->s_block_size = _STATIC_BLOCK_SIZE;
if (sp->s_block_size < _MIN_BLOCK_SIZE)
if (sp->s_block_size < _MIN_BLOCK_SIZE) {
printf("MFSread_super block size ERROR1\n");
return EINVAL;
}
sp->s_inodes_per_block = V2_INODES_PER_BLOCK(sp->s_block_size);
sp->s_ndzones = V2_NR_DZONES;
sp->s_nindirs = V2_INDIRECTS(sp->s_block_size);
}
if (sp->s_block_size < _MIN_BLOCK_SIZE) {
printf("MFSread_super block size ERROR2\n");
return EINVAL;
}
if (sp->s_block_size > _MAX_BLOCK_SIZE) {
@ -290,13 +299,16 @@ register struct super_block *sp; /* pointer to a superblock */
return EINVAL;
}
if ((sp->s_block_size % 512) != 0) {
printf("MFSread_super block_size !% 512 \n");
return EINVAL;
}
if (SUPER_SIZE > sp->s_block_size) {
printf("MFSread_super block_size < SUPER_SIZE \n");
return EINVAL;
}
if ((sp->s_block_size % V2_INODE_SIZE) != 0 ||
(sp->s_block_size % V1_INODE_SIZE) != 0) {
printf("MFSread_super block_sizr % INODE_SIZE notOK \n");
return EINVAL;
}

61
servers/mfs/super.h Normal file
View file

@ -0,0 +1,61 @@
/* Super block table. The root file system and every mounted file system
* has an entry here. The entry holds information about the sizes of the bit
* maps and inodes. The s_ninodes field gives the number of inodes available
* for files and directories, including the root directory. Inode 0 is
* on the disk, but not used. Thus s_ninodes = 4 means that 5 bits will be
* used in the bit map, bit 0, which is always 1 and not used, and bits 1-4
* for files and directories. The disk layout is:
*
* Item # blocks
* boot block 1
* super block 1 (offset 1kB)
* inode map s_imap_blocks
* zone map s_zmap_blocks
* inodes (s_ninodes + 'inodes per block' - 1)/'inodes per block'
* unused whatever is needed to fill out the current zone
* data zones (s_zones - s_firstdatazone) << s_log_zone_size
*
* A super_block slot is free if s_dev == NO_DEV.
*/
EXTERN struct super_block {
ino_t s_ninodes; /* # usable inodes on the minor device */
zone1_t s_nzones; /* total device size, including bit maps etc */
short s_imap_blocks; /* # of blocks used by inode bit map */
short s_zmap_blocks; /* # of blocks used by zone bit map */
zone1_t s_firstdatazone; /* number of first data zone */
short s_log_zone_size; /* log2 of blocks/zone */
short s_pad; /* try to avoid compiler-dependent padding */
off_t s_max_size; /* maximum file size on this device */
zone_t s_zones; /* number of zones (replaces s_nzones in V2) */
short s_magic; /* magic number to recognize super-blocks */
/* The following items are valid on disk only for V3 and above */
/* The block size in bytes. Minimum MIN_BLOCK SIZE. SECTOR_SIZE
* multiple. If V1 or V2 filesystem, this should be
* initialised to STATIC_BLOCK_SIZE. Maximum MAX_BLOCK_SIZE.
*/
short s_pad2; /* try to avoid compiler-dependent padding */
unsigned short s_block_size; /* block size in bytes. */
char s_disk_version; /* filesystem format sub-version */
/* The following items are only used when the super_block is in memory. */
/*struct inode *s_isup;*/ /* inode for root dir of mounted file sys */
/*struct inode *s_imount;*/ /* inode mounted on */
unsigned s_inodes_per_block; /* precalculated from magic number */
dev_t s_dev; /* whose super block is this? */
int s_rd_only; /* set to 1 iff file sys mounted read only */
int s_native; /* set to 1 iff not byte swapped file system */
int s_version; /* file system version, zero means bad magic */
int s_ndzones; /* # direct zones in an inode */
int s_nindirs; /* # indirect zones per indirect block */
bit_t s_isearch; /* inodes below this bit number are in use */
bit_t s_zsearch; /* all zones below this bit number are in use*/
char s_is_root;
} super_block[NR_SUPERS];
#define NIL_SUPER (struct super_block *) 0
#define IMAP 0 /* operating on the inode bit map */
#define ZMAP 1 /* operating on the zone bit map */

62
servers/mfs/table.c Normal file
View file

@ -0,0 +1,62 @@
/* This file contains the table used to map system call numbers onto the
* routines that perform them.
*/
#define _TABLE
#include "fs.h"
#include <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 */
};

56
servers/mfs/time.c Normal file
View file

@ -0,0 +1,56 @@
#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;
}

93
servers/mfs/utility.c Normal file
View file

@ -0,0 +1,93 @@
#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)));
}

View file

@ -1,3 +1,4 @@
/* This file is the counterpart of "read.c". It contains the code for writing
* insofar as this is not contained in read_write().
*
@ -10,23 +11,13 @@
#include "fs.h"
#include <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 *
@ -45,8 +36,8 @@ int op; /* special actions */
* Also free the double indirect block if that was the last entry in the
* double indirect block.
*/
int scale, ind_ex = 0, new_ind, new_dbl,
zones, nr_indirects, single, zindex, ex;
int scale, ind_ex = 0, new_ind, new_dbl,
zones, nr_indirects, single, zindex, ex;
zone_t z, z1, z2 = NO_ZONE, old_zone;
register block_t b;
long excess, zone;
@ -337,3 +328,4 @@ register struct buf *bp; /* pointer to buffer to zero */
memset(bp->b_data, 0, _MAX_BLOCK_SIZE);
bp->b_dirt = DIRTY;
}

View file

@ -17,7 +17,7 @@
FORWARD _PROTOTYPE(void init_server, (void) );
FORWARD _PROTOTYPE(void sig_handler, (void) );
FORWARD _PROTOTYPE(void get_work, (message *m) );
FORWARD _PROTOTYPE(void reply, (int whom, int result) );
FORWARD _PROTOTYPE(void reply, (int whom, message *m_out) );
/* Data buffers to retrieve info during initialization. */
PRIVATE struct boot_image image[NR_BOOT_PROCS];
@ -99,7 +99,8 @@ PUBLIC int main(void)
/* Finally send reply message, unless disabled. */
if (result != EDONTREPLY) {
reply(who_e, result);
m.m_type = result;
reply(who_e, &m);
}
}
}
@ -191,17 +192,18 @@ message *m_in; /* pointer to message */
/*===========================================================================*
* reply *
*===========================================================================*/
PRIVATE void reply(who, result)
PRIVATE void reply(who, m_out)
int who; /* replyee */
int result; /* report result */
message *m_out; /* reply message */
{
message m_out; /* reply message */
/*message m_out;*/ /* reply message */
int s; /* send status */
m_out.m_type = result; /* build reply message */
if (OK != (s=send(who, &m_out))) /* send the message */
/*m_out.m_type = result;*/ /* build reply message */
if (OK != (s=send(who, m_out))) /* send the message */
panic("RS", "unable to send reply", s);
}

View file

@ -24,7 +24,8 @@ int nr_in_use; /* number of services */
extern int errno; /* error status */
/* Prototypes for internal functions that do the hard work. */
FORWARD _PROTOTYPE( int start_service, (struct rproc *rp, int flags) );
FORWARD _PROTOTYPE( int start_service, (struct rproc *rp, int flags,
endpoint_t *ep) );
FORWARD _PROTOTYPE( int stop_service, (struct rproc *rp,int how) );
FORWARD _PROTOTYPE( int fork_nb, (void) );
FORWARD _PROTOTYPE( int read_exec, (struct rproc *rp) );
@ -56,6 +57,8 @@ int flags; /* extra flags, if any */
enum dev_style dev_style; /* device style */
int s; /* status variable */
int len; /* length of string */
int r;
endpoint_t ep; /* new endpoint no. */
/* See if there is a free entry in the table with system processes. */
if (nr_in_use >= NR_SYS_PROCS) return(EAGAIN);
@ -128,7 +131,10 @@ int flags; /* extra flags, if any */
rp->r_set_resources= 0; /* old style */
/* All information was gathered. Now try to start the system service. */
return(start_service(rp, flags));
r = start_service(rp, flags, &ep);
m_ptr->RS_ENDPOINT = ep;
return r;
}
@ -149,6 +155,8 @@ message *m_ptr; /* request message pointer */
int s; /* status variable */
int len; /* length of string */
int i;
int r;
endpoint_t ep;
struct rproc *tmp_rp;
struct rs_start rs_start;
@ -322,7 +330,9 @@ message *m_ptr; /* request message pointer */
*/
/* All information was gathered. Now try to start the system service. */
return(start_service(rp, 0));
r = start_service(rp, 0, &ep);
m_ptr->RS_ENDPOINT = ep;
return r;
}
@ -380,8 +390,9 @@ PUBLIC int do_restart(message *m_ptr)
{
register struct rproc *rp;
size_t len;
int s, proc;
int s, proc, r;
char label[MAX_LABEL_LEN];
endpoint_t ep;
len= m_ptr->RS_CMD_LEN;
if (len >= sizeof(label))
@ -404,8 +415,9 @@ PUBLIC int do_restart(message *m_ptr)
return EBUSY;
}
rp->r_flags &= ~(RS_EXITING|RS_REFRESHING|RS_NOPINGREPLY);
start_service(rp, 0);
return(OK);
r = start_service(rp, 0, &ep);
m_ptr->RS_ENDPOINT = ep;
return(r);
}
}
#if VERBOSE
@ -491,7 +503,8 @@ PUBLIC void do_exit(message *m_ptr)
{
register struct rproc *rp;
pid_t exit_pid;
int exit_status;
int exit_status, r;
endpoint_t ep;
#if VERBOSE
printf("RS: got SIGCHLD signal, doing wait to get exited child.\n");
@ -538,8 +551,10 @@ PUBLIC void do_exit(message *m_ptr)
rp->r_restarts = -1; /* reset counter */
if (rp->r_script[0] != '\0')
run_script(rp);
else
start_service(rp, 0); /* direct restart */
else {
start_service(rp, 0, &ep); /* direct restart */
m_ptr->RS_ENDPOINT = ep;
}
}
else if (WIFEXITED(exit_status) &&
WEXITSTATUS(exit_status) == EXEC_FAILED) {
@ -575,7 +590,11 @@ rp->r_restarts= 0;
rp->r_backoff= 1;
}
else {
start_service(rp, 0); /* direct restart */
start_service(rp, 0, &ep); /* direct restart */
m_ptr->RS_ENDPOINT = ep;
/* Do this even if no I/O happens with the ioctl, in
* order to disambiguate requests with DEV_IOCTL_S.
*/
}
}
break;
@ -593,6 +612,7 @@ message *m_ptr;
register struct rproc *rp;
clock_t now = m_ptr->NOTIFY_TIMESTAMP;
int s;
endpoint_t ep;
/* Search system services table. Only check slots that are in use. */
for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
@ -605,7 +625,8 @@ message *m_ptr;
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;
}
}
@ -661,9 +682,10 @@ message *m_ptr;
/*===========================================================================*
* start_service *
*===========================================================================*/
PRIVATE int start_service(rp, flags)
PRIVATE int start_service(rp, flags, endpoint)
struct rproc *rp;
int flags;
endpoint_t *endpoint;
{
/* Try to execute the given system service. Fork a new process. The child
* process will be inhibited from running by the NO_PRIV flag. Only let the
@ -771,6 +793,8 @@ int flags;
getuptime(&rp->r_alive_tm); /* currently alive */
rp->r_stop_tm = 0; /* not exiting yet */
rproc_ptr[child_proc_nr_n] = rp; /* mapping for fast access */
if(endpoint) *endpoint = child_proc_nr_e; /* send back child endpoint */
return(OK);
}

View file

@ -1,5 +1,5 @@
# Makefile for File System (FS)
SERVER = fs
SERVER = vfs
# directories
u = /usr
@ -14,9 +14,10 @@ LDFLAGS = -i
LIBS = -lsys -lsysutil -ltimers
OBJ = main.o open.o read.o write.o pipe.o dmap.o \
device.o exec.o path.o mount.o link.o super.o inode.o \
cache.o cache2.o filedes.o stadir.o protect.o time.o \
lock.o misc.o utility.o select.o timers.o table.o
path.o device.o mount.o link.o exec.o \
filedes.o stadir.o protect.o time.o \
lock.o misc.o utility.o select.o timers.o table.o \
vnode.o vmnt.o request.o
# build local binary
install all build: $(SERVER)

75
servers/vfs/buf.h Normal file
View file

@ -0,0 +1,75 @@
/* Buffer (block) cache. To acquire a block, a routine calls get_block(),
* telling which block it wants. The block is then regarded as "in use"
* and has its 'b_count' field incremented. All the blocks that are not
* in use are chained together in an LRU list, with 'front' pointing
* to the least recently used block, and 'rear' to the most recently used
* block. A reverse chain, using the field b_prev is also maintained.
* Usage for LRU is measured by the time the put_block() is done. The second
* parameter to put_block() can violate the LRU order and put a block on the
* front of the list, if it will probably not be needed soon. If a block
* is modified, the modifying routine must set b_dirt to DIRTY, so the block
* will eventually be rewritten to the disk.
*/
#include <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 */

View file

@ -4,11 +4,16 @@
#define V2_NR_DZONES 7 /* # direct zone numbers in a V2 inode */
#define V2_NR_TZONES 10 /* total # zone numbers in a V2 inode */
#define NR_FILPS 256 /* # slots in filp table */
#define NR_FILPS 512 /* # slots in filp table */
#define NR_INODES 256 /* # slots in "in core" inode table */
#define NR_SUPERS 12 /* # slots in super block table */
#define NR_LOCKS 8 /* # slots in the file locking table */
#define NR_MNTS 8
#define NR_VNODES 512
/* The type of sizeof may be (unsigned) long. Use the following macro for
* taking the sizes of small objects so that there are no surprises like
* (small) long constants being passed to routines expecting an int.

View file

@ -14,7 +14,7 @@
* ctty_opcl: perform controlling-tty-specific processing for open/close
* ctty_io: perform controlling-tty-specific processing for I/O
* do_ioctl: perform the IOCTL system call
* pm_setsid: perform the SETSID system call (FS side)
* do_setsid: perform the SETSID system call (FS side)
*/
#include "fs.h"
@ -24,12 +24,13 @@
#include <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]))
@ -42,6 +43,7 @@ FORWARD _PROTOTYPE( void safe_io_cleanup, (cp_grant_id_t, cp_grant_id_t *,
extern int dmap_size;
PRIVATE int dummyproc;
/*===========================================================================*
* dev_open *
*===========================================================================*/
@ -67,6 +69,7 @@ int flags; /* mode bits and flags */
return(r);
}
/*===========================================================================*
* dev_close *
*===========================================================================*/
@ -88,17 +91,17 @@ endpoint_t suspended_ep(endpoint_t driver, cp_grant_id_t g)
/* A process is suspended on a driver for which FS issued
* a grant. Find out which process it was.
*/
struct fproc *rfp;
for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
if(rfp->fp_pid == PID_FREE)
continue;
if(rfp->fp_suspended == SUSPENDED &&
rfp->fp_task == -driver && rfp->fp_grant == g) {
return rfp->fp_endpoint;
}
}
struct fproc *rfp;
for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
if(rfp->fp_pid == PID_FREE)
continue;
if(rfp->fp_suspended == SUSPENDED &&
rfp->fp_task == -driver && rfp->fp_grant == g) {
return rfp->fp_endpoint;
}
}
return NONE;
return NONE;
}
/*===========================================================================*
@ -246,6 +249,7 @@ off_t *pos;
else
size = _MINIX_IOCTL_SIZE(m_in.REQUEST);
/* Do this even if no I/O happens with the ioctl, in
* order to disambiguate requests with DEV_IOCTL_S.
*/
@ -491,6 +495,7 @@ int flags; /* special flags, like O_NONBLOCK */
/* fp is uninitialized at init time. */
if(!fp)
panic(__FILE__,"SUSPEND on NULL fp", NO_NUM);
if (flags & O_NONBLOCK) {
/* Not supposed to block. */
dev_mess.m_type = CANCEL;
@ -634,14 +639,14 @@ PUBLIC int do_ioctl()
/* Perform the ioctl(ls_fd, request, argx) system call (uses m2 fmt). */
struct filp *f;
register struct inode *rip;
register struct vnode *vp;
dev_t dev;
if ( (f = get_filp(m_in.ls_fd)) == NIL_FILP) return(err_code);
rip = f->filp_ino; /* get inode pointer */
if ( (rip->i_mode & I_TYPE) != I_CHAR_SPECIAL
&& (rip->i_mode & I_TYPE) != I_BLOCK_SPECIAL) return(ENOTTY);
dev = (dev_t) rip->i_zone[0];
vp = f->filp_vno; /* get vnode pointer */
if ( (vp->v_mode & I_TYPE) != I_CHAR_SPECIAL
&& (vp->v_mode & I_TYPE) != I_BLOCK_SPECIAL) return(ENOTTY);
dev = (dev_t) vp->v_sdev;
return(dev_io(DEV_IOCTL, dev, who_e, m_in.ADDRESS, 0L,
m_in.REQUEST, f->filp_flags));
@ -728,6 +733,7 @@ message *mess_ptr; /* pointer to message for task */
return OK;
}
/*===========================================================================*
* no_dev *
*===========================================================================*/
@ -747,10 +753,12 @@ int flags; /* mode bits and flags */
PUBLIC int no_dev_io(int proc, message *m)
{
/* Called when doing i/o on a nonexistent device. */
printf("FS: I/O on unmapped device number\n");
printf("VFS: I/O on unmapped device number\n");
return EIO;
}
/*===========================================================================*
* clone_opcl *
*===========================================================================*/
@ -797,24 +805,49 @@ int flags; /* mode bits and flags */
if (op == DEV_OPEN && dev_mess.REP_STATUS >= 0) {
if (dev_mess.REP_STATUS != minor) {
/* A new minor device number has been returned. Create a
* temporary device file to hold it.
*/
struct inode *ip;
struct vnode *vp;
struct vmnt *vmp;
/* Device number of the new device. */
struct clone_opcl_req req;
struct node_details res;
/* A new minor device number has been returned.
* Request root FS to create a temporary device file to hold it.
*/
/* Device number of the new device. */
dev = (dev & ~(BYTE << MINOR)) | (dev_mess.REP_STATUS << MINOR);
/* Fill in request */
req.fs_e = ROOT_FS_E;
req.dev = dev;
ip = alloc_inode(root_dev, ALL_MODES | I_CHAR_SPECIAL);
if (ip == NIL_INODE) {
/* Oops, that didn't work. Undo open. */
(void) clone_opcl(DEV_CLOSE, dev, proc_e, 0);
return(err_code);
/* Issue request */
if ((r = req_clone_opcl(&req, &res)) != OK) {
(void) clone_opcl(DEV_CLOSE, dev, proc_e, 0);
return r;
}
/* Drop old node and use the new values */
vp = fp->fp_filp[m_in.fd]->filp_vno;
put_vnode(vp);
if ((vp = get_free_vnode()) == NIL_VNODE) {
printf("VFSclone_opcl: failed to get a free vnode..\n");
vp = fp->fp_filp[m_in.fd]->filp_vno;
}
ip->i_zone[0] = dev;
vp->v_fs_e = res.fs_e;
if ((vmp = find_vmnt(vp->v_fs_e)) == NIL_VMNT)
printf("VFSclone_opcl: no vmnt found\n");
put_inode(fp->fp_filp[m_in.fd]->filp_ino);
fp->fp_filp[m_in.fd]->filp_ino = ip;
vp->v_vmnt = vmp;
vp->v_dev = vmp->m_dev;
vp->v_inode_nr = res.inode_nr;
vp->v_mode = res.fmode;
vp->v_sdev = dev;
vp->v_count = 1;
fp->fp_filp[m_in.fd]->filp_vno = vp;
}
dev_mess.REP_STATUS = OK;
}
@ -826,63 +859,75 @@ int flags; /* mode bits and flags */
*===========================================================================*/
PUBLIC void dev_up(int maj)
{
/* A new device driver has been mapped in. This function
* checks if any filesystems are mounted on it, and if so,
* dev_open()s them so the filesystem can be reused.
*/
struct super_block *sb;
struct filp *fp;
int r;
/* A new device driver has been mapped in. This function
* checks if any filesystems are mounted on it, and if so,
* dev_open()s them so the filesystem can be reused.
*/
struct filp *fp;
struct vmnt *vmp;
int r, new_driver_e;
message m;
/* Open a device once for every filp that's opened on it,
* and once for every filesystem mounted from it.
*/
/* Open a device once for every filp that's opened on it,
* and once for every filesystem mounted from it.
*/
new_driver_e = dmap[maj].dmap_driver;
for(sb = super_block; sb < &super_block[NR_SUPERS]; sb++) {
int minor;
if(sb->s_dev == NO_DEV)
continue;
if(((sb->s_dev >> MAJOR) & BYTE) != maj)
continue;
minor = ((sb->s_dev >> MINOR) & BYTE);
printf("FS: remounting dev %d/%d\n", maj, minor);
if((r = dev_open(sb->s_dev, FS_PROC_NR,
sb->s_rd_only ? R_BIT : (R_BIT|W_BIT))) != OK) {
printf("FS: mounted dev %d/%d re-open failed: %d.\n",
maj, minor, r);
}
}
for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) {
int minor;
if (vmp->m_dev == NO_DEV) continue;
if ( ((vmp->m_dev >> MAJOR) & BYTE) != maj) continue;
minor = ((vmp->m_dev >> MINOR) & BYTE);
printf("VFS: re-opening dev: %d/%d\n", maj, minor);
if ((r = dev_open(vmp->m_dev, FS_PROC_NR,
vmp->m_flags ? R_BIT : (R_BIT|W_BIT))) != OK) {
printf("VFS: mounted dev %d/%d re-open failed: %d.\n",
maj, minor, r);
}
for(fp = filp; fp < &filp[NR_FILPS]; fp++) {
struct inode *in;
int minor;
/* Send new driver endpoint */
printf("VFS: sending new dirver for dev: %d, endpoint: %d, FS_e: %d\n",
vmp->m_dev, new_driver_e, vmp->m_fs_e);
if (OK != req_newdriver(vmp->m_fs_e, vmp->m_dev, new_driver_e))
printf("VFSdev_up: error sending new driver endpoint. FS_e: %d req_nr: %d\n",
vmp->m_fs_e, REQ_NEW_DRIVER);
else
vmp->m_driver_e = new_driver_e;
}
if(fp->filp_count < 1 || !(in=fp->filp_ino)) continue;
if(((in->i_zone[0] >> MAJOR) & BYTE) != maj) continue;
if(!(in->i_mode & (I_BLOCK_SPECIAL|I_CHAR_SPECIAL))) continue;
minor = ((in->i_zone[0] >> MINOR) & BYTE);
for (fp = filp; fp < &filp[NR_FILPS]; fp++) {
struct vnode *vp;
int minor;
printf("FS: reopening special %d/%d..\n", maj, minor);
if(fp->filp_count < 1 || !(vp = fp->filp_vno)) continue;
if(((vp->v_sdev >> MAJOR) & BYTE) != maj) continue;
if(!(vp->v_mode & (I_BLOCK_SPECIAL|I_CHAR_SPECIAL))) continue;
if((r = dev_open(in->i_zone[0], FS_PROC_NR,
in->i_mode & (R_BIT|W_BIT))) != OK) {
int n;
/* This function will set the fp_filp[]s of processes
* holding that fp to NULL, but _not_ clear
* fp_filp_inuse, so that fd can't be recycled until
* it's close()d.
*/
n = inval_filp(fp);
if(n != fp->filp_count)
printf("FS: warning: invalidate/count "
"discrepancy (%d, %d)\n", n, fp->filp_count);
fp->filp_count = 0;
printf("FS: file on dev %d/%d re-open failed: %d; "
"invalidated %d fd's.\n", maj, minor, r, n);
}
}
minor = ((vp->v_sdev >> MINOR) & BYTE);
return;
printf("VFS: reopening special %d/%d..\n", maj, minor);
if((r = dev_open(vp->v_sdev, FS_PROC_NR,
vp->v_mode & (R_BIT|W_BIT))) != OK) {
int n;
/* This function will set the fp_filp[]s of processes
* holding that fp to NULL, but _not_ clear
* fp_filp_inuse, so that fd can't be recycled until
* it's close()d.
*/
n = inval_filp(fp);
if(n != fp->filp_count)
printf("VFS: warning: invalidate/count "
"discrepancy (%d, %d)\n", n, fp->filp_count);
fp->filp_count = 0;
printf("VFS: file on dev %d/%d re-open failed: %d; "
"invalidated %d fd's.\n", maj, minor, r, n);
}
}
return;
}

View file

@ -12,6 +12,9 @@
*
* The entry points into this file are:
* pm_exec: perform the EXEC system call
*
* Changes for VFS:
* Aug 2006 (Balazs Gerofi)
*/
#include "fs.h"
@ -22,11 +25,13 @@
#include <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,
@ -34,17 +39,17 @@ FORWARD _PROTOTYPE( int exec_newmem, (int proc_e, vir_bytes text_bytes,
Dev_t st_dev, ino_t st_ino, time_t st_ctime, char *progname,
int new_uid, int new_gid,
vir_bytes *stack_topp, int *load_textp, int *allow_setuidp) );
FORWARD _PROTOTYPE( int read_header, (struct inode *rip, int *sep_id,
FORWARD _PROTOTYPE( int read_header, (struct vnode *vp, int *sep_id,
vir_bytes *text_bytes, vir_bytes *data_bytes,
vir_bytes *bss_bytes, phys_bytes *tot_bytes, vir_bytes *pc,
int *hdrlenp) );
FORWARD _PROTOTYPE( int patch_stack, (struct inode *rip,
FORWARD _PROTOTYPE( int patch_stack, (struct vnode *vp,
char stack[ARG_MAX], vir_bytes *stk_bytes) );
FORWARD _PROTOTYPE( int insert_arg, (char stack[ARG_MAX],
vir_bytes *stk_bytes, char *arg, int replace) );
FORWARD _PROTOTYPE( void patch_ptr, (char stack[ARG_MAX],
vir_bytes base) );
FORWARD _PROTOTYPE( int read_seg, (struct inode *rip, off_t off,
FORWARD _PROTOTYPE( int read_seg, (struct vnode *vp, off_t off,
int proc_e, int seg, phys_bytes seg_bytes) );
FORWARD _PROTOTYPE( void clo_exec, (struct fproc *rfp) );
@ -65,168 +70,218 @@ vir_bytes frame_len;
* complete stack image, including pointers, args, environ, etc. The stack
* is copied to a buffer inside FS, and then to the new core image.
*/
int r, sep_id, round, proc_s, hdrlen, load_text, allow_setuid;
vir_bytes text_bytes, data_bytes, bss_bytes, pc;
phys_bytes tot_bytes; /* total space for program, including gap */
vir_bytes stack_top, vsp;
off_t off;
uid_t new_uid;
gid_t new_gid;
struct fproc *rfp;
struct inode *rip;
char *cp;
char progname[PROC_NAME_LEN];
int r, sep_id, round, proc_s, hdrlen, load_text, allow_setuid;
vir_bytes text_bytes, data_bytes, bss_bytes, pc;
phys_bytes tot_bytes; /* total space for program, including gap */
vir_bytes stack_top, vsp;
off_t off;
uid_t new_uid;
gid_t new_gid;
struct fproc *rfp;
struct vnode vn;
struct vmnt *vmp;
time_t v_ctime;
uid_t v_uid;
gid_t v_gid;
char *cp;
char progname[PROC_NAME_LEN];
static char mbuf[ARG_MAX]; /* buffer for stack and zeroes */
static char mbuf[ARG_MAX]; /* buffer for stack and zeroes */
/* Request and response structures */
struct lookup_req lookup_req;
struct access_req access_req;
struct open_req open_req;
struct node_details res;
okendpt(proc_e, &proc_s);
rfp= fp= &fproc[proc_s];
who_e= proc_e;
who_p= proc_s;
super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); /* su? */
okendpt(proc_e, &proc_s);
rfp= fp= &fproc[proc_s];
who_e= proc_e;
who_p= proc_s;
super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); /* su? */
/* Get the exec file name. */
r= fetch_name(path, path_len, 0);
if (r != OK)
{
printf("pm_exec: fetch_name failed\n");
return(r); /* file name not in user data segment */
}
/* Get the exec file name. */
r= fetch_name(path, path_len, 0);
if (r != OK)
{
printf("pm_exec: fetch_name failed\n");
return(r); /* file name not in user data segment */
}
/* Fetch the stack from the user before destroying the old core image. */
if (frame_len > ARG_MAX)
{
printf("pm_exec: bad frame_len\n");
return(ENOMEM); /* stack too big */
}
r = sys_datacopy(proc_e, (vir_bytes) frame,
SELF, (vir_bytes) mbuf, (phys_bytes)frame_len);
/* can't fetch stack (e.g. bad virtual addr) */
if (r != OK)
{
printf("pm_exec: sys_datacopy failed\n");
return(r);
}
/* Fetch the stack from the user before destroying the old core image. */
if (frame_len > ARG_MAX)
{
printf("pm_exec: bad frame_len\n");
return(ENOMEM); /* stack too big */
}
r = sys_datacopy(proc_e, (vir_bytes) frame,
SELF, (vir_bytes) mbuf, (phys_bytes)frame_len);
/* can't fetch stack (e.g. bad virtual addr) */
if (r != OK)
{
printf("pm_exec: sys_datacopy failed\n");
return(r);
}
/* The default is the keep the original user and group IDs */
new_uid= rfp->fp_effuid;
new_gid= rfp->fp_effgid;
/* The default is the keep the original user and group IDs */
new_uid= rfp->fp_effuid;
new_gid= rfp->fp_effgid;
for (round= 0; round < 2; round++)
/* round = 0 (first attempt), or 1 (interpreted script) */
{
/* Save the name of the program */
(cp= strrchr(user_fullpath, '/')) ? cp++ : (cp= user_fullpath);
for (round= 0; round < 2; round++)
/* round = 0 (first attempt), or 1 (interpreted script) */
{
/* Save the name of the program */
(cp= strrchr(user_path, '/')) ? cp++ : (cp= user_path);
strncpy(progname, cp, PROC_NAME_LEN-1);
progname[PROC_NAME_LEN-1] = '\0';
strncpy(progname, cp, PROC_NAME_LEN-1);
progname[PROC_NAME_LEN-1] = '\0';
/* Fill in lookup request fields */
lookup_req.path = user_fullpath;
lookup_req.lastc = NULL;
lookup_req.flags = EAT_PATH;
/* Request lookup */
if ((r = lookup(&lookup_req, &res)) != OK) return r;
if ((res.fmode & I_TYPE) != I_REGULAR) {
return ENOEXEC;
}
else {
/* Fill in request fields */
access_req.fs_e = res.fs_e;
access_req.amode = X_BIT;
access_req.inode_nr = res.inode_nr;
access_req.uid = fp->fp_effuid;
access_req.gid = fp->fp_effgid;
#if 0
printf("pm_exec: eat_path '%s'\n", user_path);
#endif
rip= eat_path(user_path);
if (rip == NIL_INODE)
{
return(err_code);
}
if ((rip->i_mode & I_TYPE) != I_REGULAR)
r = ENOEXEC;
else
r = forbidden(rip, X_BIT); /* check if file is executable */
if (r != OK) {
put_inode(rip);
printf("pm_exec: bad executable\n");
return(r);
}
if (round == 0)
{
/* Deal with setuid/setgid executables */
if (rip->i_mode & I_SET_UID_BIT)
new_uid = rip->i_uid;
if (rip->i_mode & I_SET_GID_BIT)
new_gid = rip->i_gid;
}
/* Read the file header and extract the segment sizes. */
r = read_header(rip, &sep_id, &text_bytes, &data_bytes, &bss_bytes,
&tot_bytes, &pc, &hdrlen);
if (r != ESCRIPT || round != 0)
break;
/* Get fresh copy of the file name. */
r= fetch_name(path, path_len, 0);
if (r != OK)
{
printf("pm_exec: 2nd fetch_name failed\n");
put_inode(rip);
return(r); /* strange */
}
r= patch_stack(rip, mbuf, &frame_len);
put_inode(rip);
if (r != OK)
{
printf("pm_exec: patch stack\n");
/* Issue request */
if ((r = req_access(&access_req)) != OK) {
printf("VFSexec: access failed\n");
return r;
}
}
/* Open request. */
open_req.inode_nr = res.inode_nr;
open_req.fs_e = res.fs_e;
open_req.oflags = 0;
open_req.omode = 0;
open_req.lastc = NULL;
open_req.uid = 0;
open_req.gid = 0;
/* Issue request */
if ((r = req_open(&open_req, &res)) != OK) {
printf("VFSexec: open failed\n");
return r;
}
}
if (r != OK)
{
printf("pm_exec: returning ENOEXEC, r = %d\n", r);
return ENOEXEC;
}
/* Use the vnode to store file details */
vn.v_inode_nr = res.inode_nr;
vn.v_mode = res.fmode;
vn.v_index = res.inode_index;
vn.v_size = res.fsize;
vn.v_fs_e = res.fs_e;
vn.v_count = 1;
if ( (vmp = find_vmnt(vn.v_fs_e)) == NIL_VMNT)
printf("VFS: vmnt not found by exec()");
vn.v_dev = vmp->m_dev;
vn.v_vmnt = vmp;
v_ctime = res.ctime;
v_uid = res.uid;
v_gid = res.gid;
if (round == 0)
{
/* Deal with setuid/setgid executables */
if (vn.v_mode & I_SET_UID_BIT)
new_uid = v_uid;
if (vn.v_mode & I_SET_GID_BIT)
new_gid = v_gid;
}
r= exec_newmem(proc_e, text_bytes, data_bytes, bss_bytes, tot_bytes,
frame_len, sep_id, rip->i_dev, rip->i_num, rip->i_ctime,
progname, new_uid, new_gid, &stack_top, &load_text, &allow_setuid);
if (r != OK)
{
printf("pm_exec: exec_newmap failed: %d\n", r);
put_inode(rip);
return r;
}
/* Read the file header and extract the segment sizes. */
r = read_header(&vn, &sep_id, &text_bytes, &data_bytes, &bss_bytes,
&tot_bytes, &pc, &hdrlen);
if (r != ESCRIPT || round != 0)
break;
/* Patch up stack and copy it from FS to new core image. */
vsp = stack_top;
vsp -= frame_len;
patch_ptr(mbuf, vsp);
r = sys_datacopy(SELF, (vir_bytes) mbuf,
proc_e, (vir_bytes) vsp, (phys_bytes)frame_len);
if (r != OK) panic(__FILE__,"pm_exec stack copy err on", proc_e);
/* Get fresh copy of the file name. */
r= fetch_name(path, path_len, 0);
if (r != OK)
{
printf("pm_exec: 2nd fetch_name failed\n");
put_vnode(&vn);
return(r); /* strange */
}
r= patch_stack(&vn, mbuf, &frame_len);
put_vnode(&vn);
if (r != OK)
{
printf("pm_exec: patch stack\n");
return r;
}
}
off = hdrlen;
if (r != OK)
{
printf("pm_exec: returning ENOEXEC, r = %d\n", r);
return ENOEXEC;
}
/* Read in text and data segments. */
if (load_text) {
r= read_seg(rip, off, proc_e, T, text_bytes);
}
off += text_bytes;
if (r == OK)
r= read_seg(rip, off, proc_e, D, data_bytes);
r= exec_newmem(proc_e, text_bytes, data_bytes, bss_bytes, tot_bytes,
frame_len, sep_id, vn.v_dev, vn.v_inode_nr, v_ctime,
progname, new_uid, new_gid, &stack_top, &load_text, &allow_setuid);
if (r != OK)
{
printf("pm_exec: exec_newmap failed: %d\n", r);
put_vnode(&vn);
return r;
}
put_inode(rip);
/* Patch up stack and copy it from FS to new core image. */
vsp = stack_top;
vsp -= frame_len;
patch_ptr(mbuf, vsp);
r = sys_datacopy(SELF, (vir_bytes) mbuf,
proc_e, (vir_bytes) vsp, (phys_bytes)frame_len);
if (r != OK) panic(__FILE__,"pm_exec stack copy err on", proc_e);
if (r != OK) return r;
off = hdrlen;
clo_exec(rfp);
/* Read in text and data segments. */
if (load_text) {
r= read_seg(&vn, off, proc_e, T, text_bytes);
}
off += text_bytes;
if (r == OK)
r= read_seg(&vn, off, proc_e, D, data_bytes);
if (allow_setuid)
{
rfp->fp_effuid= new_uid;
rfp->fp_effgid= new_gid;
}
put_vnode(&vn);
/* This child has now exec()ced. */
rfp->fp_execced = 1;
if (r != OK) return r;
/* Check if this is a driver that can now be useful. */
dmap_endpt_up(rfp->fp_endpoint);
clo_exec(rfp);
return OK;
if (allow_setuid)
{
rfp->fp_effuid= new_uid;
rfp->fp_effgid= new_gid;
}
/* This child has now exec()ced. */
rfp->fp_execced = 1;
/* Check if this is a driver that can now be useful. */
dmap_endpt_up(rfp->fp_endpoint);
/*printf("VFSpm_exec: %s OK\n", user_fullpath);*/
return OK;
}
/*===========================================================================*
* exec_newmem *
*===========================================================================*/
@ -291,9 +346,9 @@ int *allow_setuidp;
/*===========================================================================*
* read_header *
*===========================================================================*/
PRIVATE int read_header(rip, sep_id, text_bytes, data_bytes, bss_bytes,
PRIVATE int read_header(vp, sep_id, text_bytes, data_bytes, bss_bytes,
tot_bytes, pc, hdrlenp)
struct inode *rip; /* inode for reading exec file */
struct vnode *vp; /* inode for reading exec file */
int *sep_id; /* true iff sep I&D */
vir_bytes *text_bytes; /* place to return text size */
vir_bytes *data_bytes; /* place to return initialized data size */
@ -304,8 +359,6 @@ int *hdrlenp;
{
/* Read the header and extract the text, data, bss and total sizes from it. */
off_t pos;
block_t b;
struct buf *bp;
struct exec hdr; /* a.out header is read in here */
/* Read the header and check the magic number. The standard MINIX header
@ -335,25 +388,31 @@ int *hdrlenp;
* is ignored here.
*/
struct readwrite_req req;
struct readwrite_res res;
int r;
pos= 0; /* Read from the start of the file */
b = read_map(rip, pos); /* get block number */
if (b == 0) /* Hole */
return ENOEXEC;
/* Fill in request structure */
req.fs_e = vp->v_fs_e;
req.rw_flag = READING;
req.inode_nr = vp->v_inode_nr;
req.user_e = FS_PROC_NR;
req.seg = D;
req.pos = pos;
req.num_of_bytes = sizeof(hdr);
req.user_addr = (char*)&hdr;
req.inode_index = vp->v_index;
bp = get_block(rip->i_dev, b, NORMAL); /* get block */
/* Issue request */
if ((r = req_readwrite(&req, &res)) != OK) return r;
/* Interpreted script? */
if (bp->b_data[0] == '#' && bp->b_data[1] == '!' && rip->i_size >= 2)
{
put_block(bp, FULL_DATA_BLOCK);
if (((char*)&hdr)[0] == '#' && ((char*)&hdr)[1] == '!' && vp->v_size >= 2)
return ESCRIPT;
}
memcpy(&hdr, bp->b_data, sizeof(hdr));
put_block(bp, FULL_DATA_BLOCK);
if (rip->i_size < A_MINHDR) return(ENOEXEC);
if (vp->v_size < A_MINHDR) return(ENOEXEC);
/* Check magic number, cpu type, and flags. */
if (BADMAG(hdr)) return(ENOEXEC);
@ -388,8 +447,8 @@ int *hdrlenp;
/*===========================================================================*
* patch_stack *
*===========================================================================*/
PRIVATE int patch_stack(rip, stack, stk_bytes)
struct inode *rip; /* pointer for open script file */
PRIVATE int patch_stack(vp, stack, stk_bytes)
struct vnode *vp; /* pointer for open script file */
char stack[ARG_MAX]; /* pointer to stack image within FS */
vir_bytes *stk_bytes; /* size of initial stack */
{
@ -398,50 +457,56 @@ vir_bytes *stk_bytes; /* size of initial stack */
* the interpreter.
*/
enum { INSERT=FALSE, REPLACE=TRUE };
int n;
int n, r;
off_t pos;
block_t b;
struct buf *bp;
char *sp, *interp = NULL;
char buf[_MAX_BLOCK_SIZE];
struct readwrite_req req;
struct readwrite_res res;
/* Make user_path the new argv[0]. */
if (!insert_arg(stack, stk_bytes, user_path, REPLACE)) return(ENOMEM);
if (!insert_arg(stack, stk_bytes, user_fullpath, REPLACE)) return(ENOMEM);
pos= 0; /* Read from the start of the file */
b = read_map(rip, pos); /* get block number */
if (b == 0) /* Hole */
return ENOEXEC;
pos = 0; /* Read from the start of the file */
bp = get_block(rip->i_dev, b, NORMAL); /* get block */
n= rip->i_size;
if (n > rip->i_sp->s_block_size)
n= rip->i_sp->s_block_size;
if (n < 2)
{
put_block(bp, FULL_DATA_BLOCK);
return ENOEXEC;
}
sp= bp->b_data+2; /* just behind the #! */
/* Fill in request structure */
req.fs_e = vp->v_fs_e;
req.rw_flag = READING;
req.inode_nr = vp->v_inode_nr;
req.user_e = FS_PROC_NR;
req.seg = D;
req.pos = pos;
req.num_of_bytes = _MAX_BLOCK_SIZE;
req.user_addr = buf;
req.inode_index = vp->v_index;
/* Issue request */
if ((r = req_readwrite(&req, &res)) != OK) return r;
n = vp->v_size;
if (n > vp->v_vmnt->m_block_size)
n = vp->v_vmnt->m_block_size;
if (n < 2) return ENOEXEC;
sp = &(buf[2]); /* just behind the #! */
n -= 2;
if (n > PATH_MAX)
n= PATH_MAX;
if (n > PATH_MAX) n = PATH_MAX;
/* Use the user_path variable for temporary storage */
memcpy(user_path, sp, n);
put_block(bp, FULL_DATA_BLOCK);
memcpy(user_fullpath, sp, n);
if ((sp= memchr(user_path, '\n', n)) == NULL) /* must be a proper line */
if ((sp = memchr(user_fullpath, '\n', n)) == NULL) /* must be a proper line */
return(ENOEXEC);
/* Move sp backwards through script[], prepending each string to stack. */
for (;;) {
/* skip spaces behind argument. */
while (sp > user_path && (*--sp == ' ' || *sp == '\t')) {}
if (sp == user_path) break;
while (sp > user_fullpath && (*--sp == ' ' || *sp == '\t')) {}
if (sp == user_fullpath) break;
sp[1] = 0;
/* Move to the start of the argument. */
while (sp > user_path && sp[-1] != ' ' && sp[-1] != '\t') --sp;
while (sp > user_fullpath && sp[-1] != ' ' && sp[-1] != '\t') --sp;
interp = sp;
if (!insert_arg(stack, stk_bytes, sp, INSERT)) return(ENOMEM);
@ -450,8 +515,8 @@ vir_bytes *stk_bytes; /* size of initial stack */
/* Round *stk_bytes up to the size of a pointer for alignment contraints. */
*stk_bytes= ((*stk_bytes + PTRSIZE - 1) / PTRSIZE) * PTRSIZE;
if (interp != user_path)
memmove(user_path, interp, strlen(interp)+1);
if (interp != user_fullpath)
memmove(user_fullpath, interp, strlen(interp)+1);
return(OK);
}
@ -546,8 +611,8 @@ vir_bytes base; /* virtual address of stack base inside user */
/*===========================================================================*
* read_seg *
*===========================================================================*/
PRIVATE int read_seg(rip, off, proc_e, seg, seg_bytes)
struct inode *rip; /* inode descriptor to read from */
PRIVATE int read_seg(vp, off, proc_e, seg, seg_bytes)
struct vnode *vp; /* inode descriptor to read from */
off_t off; /* offset in file */
int proc_e; /* process number (endpoint) */
int seg; /* T, D, or S */
@ -558,46 +623,31 @@ phys_bytes seg_bytes; /* how much is to be transferred? */
* a segment is padded out to a click multiple, and the data segment is only
* partially initialized.
*/
int r, block_size;
off_t n, o, b_off, seg_off;
block_t b;
struct buf *bp;
struct readwrite_req req;
struct readwrite_res res;
int r;
/* Make sure that the file is big enough */
if (rip->i_size < off+seg_bytes)
return EIO;
if (vp->v_size < off+seg_bytes) return EIO;
/* Fill in request structure */
req.fs_e = vp->v_fs_e;
req.rw_flag = READING;
req.inode_nr = vp->v_inode_nr;
req.user_e = proc_e;
req.seg = seg;
req.pos = off;
req.num_of_bytes = seg_bytes;
req.user_addr = 0;
req.inode_index = vp->v_index;
block_size= rip->i_sp->s_block_size;
seg_off= 0;
for (o= off - (off % block_size); o < off+seg_bytes; o += block_size)
{
b= read_map(rip, o);
if (b == NO_BLOCK)
{
bp = get_block(NO_DEV, NO_BLOCK, NORMAL); /* get a buffer */
zero_block(bp);
}
else
bp = get_block(rip->i_dev, b, NORMAL); /* get block */
if (o < off)
b_off= off-o;
else
b_off= 0;
n= block_size-b_off;
if (o+b_off+n > off+seg_bytes)
n= off+seg_bytes-(o+b_off);
r= sys_vircopy(SELF, D, (vir_bytes)bp->b_data+b_off,
proc_e, seg, seg_off, n);
put_block(bp, FULL_DATA_BLOCK);
/* Issue request */
if ((r = req_readwrite(&req, &res)) != OK) return r;
if (r == OK && res.cum_io != seg_bytes)
printf("VFSread_seg segment has not been read properly by exec() \n");
if (r != OK)
return r;
seg_off += n;
}
return OK;
return r;
}
@ -618,3 +668,4 @@ struct fproc *rfp;
}

27
servers/vfs/file.h Normal file
View file

@ -0,0 +1,27 @@
/* This is the filp table. It is an intermediary between file descriptors and
* inodes. A slot is free if filp_count == 0.
*/
EXTERN struct filp {
mode_t filp_mode; /* RW bits, telling how file is opened */
int filp_flags; /* flags from open and fcntl */
int filp_count; /* how many file descriptors share this slot?*/
/* struct inode *filp_ino;*/ /* pointer to the inode */
struct vnode *filp_vno;
off_t filp_pos; /* file position */
/* the following fields are for select() and are owned by the generic
* select() code (i.e., fd-type-specific select() code can't touch these).
*/
int filp_selectors; /* select()ing processes blocking on this fd */
int filp_select_ops; /* interested in these SEL_* operations */
/* following are for fd-type-specific select() */
int filp_pipe_select_ops;
} filp[NR_FILPS];
#define FILP_CLOSED 0 /* filp_mode: associated device closed */
#define NIL_FILP (struct filp *) 0 /* indicates absence of a filp slot */

View file

@ -13,7 +13,8 @@
#include "fs.h"
#include "file.h"
#include "fproc.h"
#include "inode.h"
#include "vnode.h"
/*===========================================================================*
* get_fd *
@ -88,7 +89,7 @@ int fild; /* file descriptor */
/*===========================================================================*
* find_filp *
*===========================================================================*/
PUBLIC struct filp *find_filp(register struct inode *rip, mode_t bits)
PUBLIC struct filp *find_filp(register struct vnode *vp, mode_t bits)
{
/* Find a filp slot that refers to the inode 'rip' in a way as described
* by the mode bit 'bits'. Used for determining whether somebody is still
@ -100,7 +101,7 @@ PUBLIC struct filp *find_filp(register struct inode *rip, mode_t bits)
register struct filp *f;
for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
if (f->filp_count != 0 && f->filp_ino == rip && (f->filp_mode & bits)){
if (f->filp_count != 0 && f->filp_vno == vp && (f->filp_mode & bits)){
return(f);
}
}
@ -114,16 +115,16 @@ PUBLIC struct filp *find_filp(register struct inode *rip, mode_t bits)
*===========================================================================*/
PUBLIC int inval_filp(struct filp *fp)
{
int f, fd, n = 0;
for(f = 0; f < NR_PROCS; f++) {
if(fproc[f].fp_pid == PID_FREE) continue;
for(fd = 0; fd < OPEN_MAX; fd++) {
if(fproc[f].fp_filp[fd] && fproc[f].fp_filp[fd] == fp) {
fproc[f].fp_filp[fd] = NIL_FILP;
n++;
}
}
}
int f, fd, n = 0;
for(f = 0; f < NR_PROCS; f++) {
if(fproc[f].fp_pid == PID_FREE) continue;
for(fd = 0; fd < OPEN_MAX; fd++) {
if(fproc[f].fp_filp[fd] && fproc[f].fp_filp[fd] == fp) {
fproc[f].fp_filp[fd] = NIL_FILP;
n++;
}
}
}
return n;
return n;
}

53
servers/vfs/fproc.h Normal file
View file

@ -0,0 +1,53 @@
#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)

26
servers/vfs/fs.h Normal file
View file

@ -0,0 +1,26 @@
/* This is the master header for fs. It includes some other files
* and defines the principal constants.
*/
#define _POSIX_SOURCE 1 /* tell headers to include POSIX stuff */
#define _MINIX 1 /* tell headers to include MINIX stuff */
#define _SYSTEM 1 /* tell headers that this is the kernel */
#define VERBOSE 0 /* show messages during initialization? */
/* The following are so basic, all the *.c files get them automatically. */
#include <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"

View file

@ -10,9 +10,11 @@ EXTERN int super_user; /* 1 if caller is super_user, else 0 */
EXTERN int susp_count; /* number of procs suspended on pipe */
EXTERN int nr_locks; /* number of locks currently in place */
EXTERN int reviving; /* number of pipe processes to be revived */
EXTERN off_t rdahedpos; /* position to read ahead */
EXTERN struct inode *rdahed_inode; /* pointer to inode to read ahead */
EXTERN Dev_t root_dev; /* device number of the root device */
EXTERN int ROOT_FS_E; /* kernel endpoint of the root FS proc */
EXTERN int last_login_fs_e; /* endpoint of the FS proc that logged in
before the corresponding mount request */
EXTERN time_t boottime; /* time in seconds at system boot */
/* The parameters of the call are kept here. */
@ -20,7 +22,10 @@ EXTERN message m_in; /* the input message itself */
EXTERN message m_out; /* the output message used for reply */
EXTERN int who_p, who_e; /* caller's proc number, endpoint */
EXTERN int call_nr; /* system call number */
EXTERN char user_path[PATH_MAX];/* storage for user path name */
EXTERN message mount_m_in; /* the input message itself */
EXTERN char user_fullpath[PATH_MAX]; /* storage for user path name */
EXTERN short cum_path_processed; /* number of characters processed */
/* The following variables are used for returning results to the caller. */
EXTERN int err_code; /* temporary storage for error number */

413
servers/vfs/link.c Normal file
View file

@ -0,0 +1,413 @@
/* This file handles the LINK and UNLINK system calls. It also deals with
* deallocating the storage used by a file when the last UNLINK is done to a
* file and the blocks must be returned to the free block pool.
*
* The entry points into this file are
* do_link: perform the LINK system call
* do_unlink: perform the UNLINK and RMDIR system calls
* do_rename: perform the RENAME system call
* do_truncate: perform the TRUNCATE system call
* do_ftruncate: perform the FTRUNCATE system call
* do_rdlink: perform the RDLNK system call
*
* Changes for VFS:
* Jul 2006 (Balazs Gerofi)
*/
#include "fs.h"
#include <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);
}

View file

@ -11,10 +11,11 @@
#include <unistd.h>
#include "file.h"
#include "fproc.h"
#include "inode.h"
#include "lock.h"
#include "param.h"
#include "vnode.h"
/*===========================================================================*
* lock_op *
*===========================================================================*/
@ -42,7 +43,7 @@ int req; /* either F_SETLK or F_SETLKW */
mo = f->filp_mode;
if (ltype != F_UNLCK && ltype != F_RDLCK && ltype != F_WRLCK) return(EINVAL);
if (req == F_GETLK && ltype == F_UNLCK) return(EINVAL);
if ( (f->filp_ino->i_mode & I_TYPE) != I_REGULAR) return(EINVAL);
if ( (f->filp_vno->v_mode & I_TYPE) != I_REGULAR) return(EINVAL);
if (req != F_GETLK && ltype == F_RDLCK && (mo & R_BIT) == 0) return(EBADF);
if (req != F_GETLK && ltype == F_WRLCK && (mo & W_BIT) == 0) return(EBADF);
@ -50,7 +51,7 @@ int req; /* either F_SETLK or F_SETLKW */
switch (flock.l_whence) {
case SEEK_SET: first = 0; break;
case SEEK_CUR: first = f->filp_pos; break;
case SEEK_END: first = f->filp_ino->i_size; break;
case SEEK_END: first = f->filp_vno->v_size; break;
default: return(EINVAL);
}
/* Check for overflow. */
@ -70,7 +71,7 @@ int req; /* either F_SETLK or F_SETLKW */
if (empty == (struct file_lock *) 0) empty = flp;
continue; /* 0 means unused slot */
}
if (flp->lock_inode != f->filp_ino) continue; /* different file */
if (flp->lock_vnode != f->filp_vno) continue; /* different file */
if (last < flp->lock_first) continue; /* new one is in front */
if (first > flp->lock_last) continue; /* new one is afterwards */
if (ltype == F_RDLCK && flp->lock_type == F_RDLCK) continue;
@ -118,7 +119,7 @@ int req; /* either F_SETLK or F_SETLKW */
flp2 = &file_lock[i];
flp2->lock_type = flp->lock_type;
flp2->lock_pid = flp->lock_pid;
flp2->lock_inode = flp->lock_inode;
flp2->lock_vnode = flp->lock_vnode;
flp2->lock_first = last + 1;
flp2->lock_last = flp->lock_last;
flp->lock_last = first - 1;
@ -152,7 +153,7 @@ int req; /* either F_SETLK or F_SETLKW */
if (empty == (struct file_lock *) 0) return(ENOLCK); /* table full */
empty->lock_type = ltype;
empty->lock_pid = fp->fp_pid;
empty->lock_inode = f->filp_ino;
empty->lock_vnode = f->filp_vno;
empty->lock_first = first;
empty->lock_last = last;
nr_locks++;

10
servers/vfs/lock.h Normal file
View file

@ -0,0 +1,10 @@
/* This is the file locking table. Like the filp table, it points to the
* inode table, however, in this case to achieve advisory locking.
*/
EXTERN struct file_lock {
short lock_type; /* F_RDLOCK or F_WRLOCK; 0 means unused slot */
pid_t lock_pid; /* pid of the process holding the lock */
struct vnode *lock_vnode;
off_t lock_first; /* offset of first byte locked */
off_t lock_last; /* offset of last byte locked */
} file_lock[NR_LOCKS];

View file

@ -3,13 +3,13 @@
* replies.
*
* The entry points into this file are:
* main: main program of the File System
* main: main program of the Virtual File System
* reply: send a reply to a process after the requested work is done
*
* Changes for VFS:
* Jul 2006 (Balazs Gerofi)
*/
struct super_block; /* proto.h needs to know this */
#include "fs.h"
#include <fcntl.h>
#include <string.h>
@ -26,12 +26,13 @@ struct super_block; /* proto.h needs to know this */
#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];
@ -42,6 +43,7 @@ FORWARD _PROTOTYPE( void get_work, (void) );
FORWARD _PROTOTYPE( void init_root, (void) );
FORWARD _PROTOTYPE( void service_pm, (void) );
/*===========================================================================*
* main *
*===========================================================================*/
@ -55,6 +57,7 @@ PUBLIC int main()
fs_init();
/* This is the main loop that gets work, processes it, and sends replies. */
while (TRUE) {
get_work(); /* sets who and call_nr */
@ -96,7 +99,7 @@ PUBLIC int main()
default:
/* Call the internal function that does the work. */
if (call_nr < 0 || call_nr >= NCALLS) {
error = ENOSYS;
error = SUSPEND;
/* Not supposed to happen. */
printf("FS, warning illegal %d system call by %d\n",
call_nr, who_e);
@ -114,9 +117,7 @@ PUBLIC int main()
/* Copy the results back to the user and send reply. */
if (error != SUSPEND) { reply(who_e, error); }
if (rdahed_inode != NIL_INODE) {
read_ahead(); /* do block read ahead */
}
}
}
return(OK); /* shouldn't come here */
@ -179,32 +180,6 @@ PRIVATE void get_work()
}
}
/*===========================================================================*
* buf_pool *
*===========================================================================*/
PRIVATE void buf_pool(void)
{
/* Initialize the buffer pool. */
register struct buf *bp;
bufs_in_use = 0;
front = &buf[0];
rear = &buf[NR_BUFS - 1];
for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) {
bp->b_blocknr = NO_BLOCK;
bp->b_dev = NO_DEV;
bp->b_next = bp + 1;
bp->b_prev = bp - 1;
}
buf[0].b_prev = NIL_BUF;
buf[NR_BUFS - 1].b_next = NIL_BUF;
for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) bp->b_hash = bp->b_next;
buf_hash[0] = front;
}
/*===========================================================================*
* reply *
@ -217,7 +192,7 @@ int result; /* result of the call (usually OK or error #) */
int s;
m_out.reply_type = result;
s = send(whom, &m_out);
if (s != OK) printf("FS: couldn't send reply %d to %d: %d\n",
if (s != OK) printf("VFS: couldn't send reply %d to %d: %d\n",
result, whom, s);
}
@ -232,6 +207,10 @@ PRIVATE void fs_init()
message mess;
int s;
/* Clear endpoint field */
last_login_fs_e = 0;
mount_m_in.m1_p3 = 0;
/* Initialize the process table with help of the process manager messages.
* Expect one message for each system process with its slot number and pid.
* When no more processes follow, the magic process number NONE is sent.
@ -254,22 +233,25 @@ PRIVATE void fs_init()
} while (TRUE); /* continue until process NONE */
mess.m_type = OK; /* tell PM that we succeeded */
s=send(PM_PROC_NR, &mess); /* send synchronization message */
s = send(PM_PROC_NR, &mess); /* send synchronization message */
/* All process table entries have been set. Continue with FS initialization.
* Certain relations must hold for the file system to work at all. Some
* extra block_size requirements are checked at super-block-read-in time.
*/
if (OPEN_MAX > 127) panic(__FILE__,"OPEN_MAX > 127", NO_NUM);
/*
if (NR_BUFS < 6) panic(__FILE__,"NR_BUFS < 6", NO_NUM);
if (V1_INODE_SIZE != 32) panic(__FILE__,"V1 inode size != 32", NO_NUM);
if (V2_INODE_SIZE != 64) panic(__FILE__,"V2 inode size != 64", NO_NUM);
if (OPEN_MAX > 8 * sizeof(long))
panic(__FILE__,"Too few bits in fp_cloexec", NO_NUM);
*/
/* The following initializations are needed to let dev_opcl succeed .*/
fp = (struct fproc *) NULL;
who_e = who_p = FS_PROC_NR;
buf_pool(); /* initialize buffer pool */
build_dmap(); /* build device table and map boot driver */
init_root(); /* init root device and load super block */
init_select(); /* init select() structures */
@ -278,10 +260,10 @@ PRIVATE void fs_init()
for (rfp=&fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
FD_ZERO(&(rfp->fp_filp_inuse));
if (rfp->fp_pid != PID_FREE) {
rip = get_inode(root_dev, ROOT_INODE);
dup_inode(rip);
rfp->fp_rootdir = rip;
rfp->fp_workdir = rip;
rfp->fp_rd = get_vnode(ROOT_FS_E, ROOT_INODE);
rfp->fp_wd = get_vnode(ROOT_FS_E, ROOT_INODE);
} else rfp->fp_endpoint = NONE;
}
}
@ -291,42 +273,96 @@ PRIVATE void fs_init()
*===========================================================================*/
PRIVATE void init_root()
{
int bad;
register struct super_block *sp;
register struct inode *rip = NIL_INODE;
int s;
struct vmnt *vmp;
struct vnode *root_node;
struct dmap *dp;
message m;
int r = OK;
struct readsuper_req sreq;
struct readsuper_res sres;
/* Open the root device. */
root_dev = DEV_IMGRD;
if ((s=dev_open(root_dev, FS_PROC_NR, R_BIT|W_BIT)) != OK)
panic(__FILE__,"Cannot open root device", s);
#if ENABLE_CACHE2
/* The RAM disk is a second level block cache while not otherwise used. */
init_cache2(ram_size);
#endif
/* Initialize the super_block table. */
for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++)
sp->s_dev = NO_DEV;
/* Read in super_block for the root file system. */
sp = &super_block[0];
sp->s_dev = root_dev;
/* Check super_block for consistency. */
bad = (read_super(sp) != OK);
if (!bad) {
rip = get_inode(root_dev, ROOT_INODE); /* inode for root dir */
if ( (rip->i_mode & I_TYPE) != I_DIRECTORY || rip->i_nlinks < 3) bad++;
ROOT_FS_E = MFS_PROC_NR;
/* Wait FS login message */
if (last_login_fs_e != ROOT_FS_E) {
printf("VFS: Waiting for login from FS_e %d\n", ROOT_FS_E);
/* Wait FS login message */
if (receive(ROOT_FS_E, &m) != OK) {
printf("VFS: Error receiving login request from FS_e %d\n",
ROOT_FS_E);
panic(__FILE__, "Error receiving login request from root filesystem\n", ROOT_FS_E);
}
if (m.m_type != FS_READY) {
printf("VFS: Invalid login request from FS_e %d\n",
ROOT_FS_E);
panic(__FILE__, "Error receiving login request from root filesystem\n", ROOT_FS_E);
}
printf("VFS: FS_e %d logged in\n", ROOT_FS_E);
}
last_login_fs_e = 0;
/* Initialize vmnt table */
for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp)
vmp->m_dev = NO_DEV;
vmp = &vmnt[0];
/* We'll need a vnode for the root inode, check whether there is one */
if ((root_node = get_free_vnode()) == NIL_VNODE) {
panic(__FILE__,"Cannot get free vnode", r);
}
/* Get driver process' endpoint */
dp = &dmap[(root_dev >> MAJOR) & BYTE];
if (dp->dmap_driver == NONE) {
panic(__FILE__,"No driver for root device", r);
}
if (bad) panic(__FILE__,"Invalid root file system", NO_NUM);
sp->s_imount = rip;
dup_inode(rip);
sp->s_isup = rip;
sp->s_rd_only = 0;
return;
/* Open the device the file system lives on. */
if ((r = dev_open(root_dev, ROOT_FS_E, (R_BIT|W_BIT))) != OK)
panic(__FILE__,"Cannot open root device", r);
/* Request for reading superblock and root inode */
sreq.fs_e = ROOT_FS_E;
sreq.readonly = 0;
sreq.boottime = boottime;
sreq.driver_e = dp->dmap_driver;
sreq.dev = root_dev;
sreq.slink_storage = user_fullpath;
sreq.isroot = 1;
/* Issue request */
if ((r = req_readsuper(&sreq, &sres)) != OK) {
dev_close(root_dev);
panic(__FILE__,"Cannot read superblock from root", r);
}
/* Fill in root node's fields */
root_node->v_fs_e = sres.fs_e;
root_node->v_inode_nr = sres.inode_nr;
root_node->v_mode = sres.fmode;
root_node->v_size = sres.fsize;
root_node->v_sdev = NO_DEV;
root_node->v_count = 1;
/* Fill in max file size and blocksize for the vmnt */
vmp->m_fs_e = sres.fs_e;
vmp->m_dev = root_dev;
vmp->m_block_size = sres.blocksize;
vmp->m_max_file_size = sres.maxsize;
vmp->m_driver_e = dp->dmap_driver;
vmp->m_flags = 0;
/* Root node is indeed on the partition */
root_node->v_vmnt = vmp;
root_node->v_dev = vmp->m_dev;
/* Root directory is mounted on itself */
vmp->m_mounted_on = root_node;
vmp->m_root_node = root_node;
}
/*===========================================================================*
@ -335,6 +371,7 @@ PRIVATE void init_root()
PRIVATE void service_pm()
{
int r, call;
struct vmnt *vmp;
message m;
/* Ask PM for work until there is nothing left to do */
@ -344,7 +381,7 @@ PRIVATE void service_pm()
r= sendrec(PM_PROC_NR, &m);
if (r != OK)
{
panic("fs", "service_pm: sendrec failed", r);
panic("VFS", "service_pm: sendrec failed", r);
}
if (m.m_type == PM_IDLE) {
break;
@ -353,8 +390,13 @@ PRIVATE void service_pm()
switch(call)
{
case PM_STIME:
boottime= m.PM_STIME_TIME;
boottime = m.PM_STIME_TIME;
/* Send new time for all FS processes */
for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) {
if (vmp->m_fs_e)
req_stime(vmp->m_fs_e, boottime);
}
/* No need to report status to PM */
break;
case PM_SETSID:
@ -445,7 +487,8 @@ PRIVATE void service_pm()
break;
default:
panic("fs", "service_pm: unknown call", m.m_type);
panic("VFS", "service_pm: unknown call", m.m_type);
}
}
}

View file

@ -7,12 +7,12 @@
* do_fcntl: perform the FCNTL system call
* do_sync: perform the SYNC system call
* do_fsync: perform the FSYNC system call
* pm_reboot: sync disks and prepare for shutdown
* pm_fork: adjust the tables after MM has performed a FORK system call
* do_reboot: sync disks and prepare for shutdown
* do_fork: adjust the tables after MM has performed a FORK system call
* do_exec: handle files with FD_CLOEXEC on after MM has done an EXEC
* do_exit: a process has exited; note that in the tables
* pm_setgid: set group ids for some process
* pm_setuid: set user ids for some process
* do_set: set uid or gid for some process
* do_revive: revive a process that was waiting for something (e.g. TTY)
* do_svrctl: file system control
* do_getsysinfo: request copy of FS data structure
* pm_dumpcore: create a core dump
@ -28,12 +28,13 @@
#include <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 */
@ -43,14 +44,17 @@ PUBLIC unsigned long calls_stats[NCALLS];
#endif
FORWARD _PROTOTYPE( void free_proc, (struct fproc *freed, int flags));
/*
FORWARD _PROTOTYPE( int dumpcore, (int proc_e, struct mem_map *seg_ptr));
FORWARD _PROTOTYPE( int write_bytes, (struct inode *rip, off_t off,
char *buf, size_t bytes));
FORWARD _PROTOTYPE( int write_seg, (struct inode *rip, off_t off, int proc_e,
int seg, off_t seg_off, phys_bytes seg_bytes));
*/
#define FP_EXITING 1
/*===========================================================================*
* do_getsysinfo *
*===========================================================================*/
@ -140,6 +144,8 @@ PUBLIC int do_dup()
return(m_in.fd2);
}
/*===========================================================================*
* do_fcntl *
*===========================================================================*/
@ -149,11 +155,17 @@ PUBLIC int do_fcntl()
register struct filp *f;
int new_fd, r, fl;
long cloexec_mask; /* bit map for the FD_CLOEXEC flag */
long clo_value; /* FD_CLOEXEC flag in proper position */
struct filp *dummy;
struct ftrunc_req req;
/* Is the file descriptor valid? */
if ((f = get_filp(m_in.fd)) == NIL_FILP) return(err_code);
if ((f = get_filp(m_in.fd)) == NIL_FILP) {
/*printf("VFSfcntl: invalid filedesc %d\n", m_in.fd); */
return(err_code);
}
switch (m_in.request) {
case F_DUPFD:
/* This replaces the old dup() system call. */
@ -203,7 +215,7 @@ PUBLIC int do_fcntl()
signed long offset;
/* Check if it's a regular file. */
if((f->filp_ino->i_mode & I_TYPE) != I_REGULAR) {
if((f->filp_vno->v_mode & I_TYPE) != I_REGULAR) {
return EINVAL;
}
@ -220,7 +232,7 @@ PUBLIC int do_fcntl()
switch(flock_arg.l_whence) {
case SEEK_SET: start = 0; if(offset < 0) return EINVAL; break;
case SEEK_CUR: start = f->filp_pos; break;
case SEEK_END: start = f->filp_ino->i_size; break;
case SEEK_END: start = f->filp_vno->v_size; break;
default: return EINVAL;
}
@ -233,11 +245,19 @@ PUBLIC int do_fcntl()
if(end <= start) {
return EINVAL;
}
r = freesp_inode(f->filp_ino, start, end);
} else {
r = truncate_inode(f->filp_ino, start);
}
else {
end = 0;
}
return r;
/* Fill in FS request */
req.fs_e = f->filp_vno->v_fs_e;
req.inode_nr = f->filp_vno->v_inode_nr;
req.start = start;
req.end = end;
/* Issue request */
return req_ftrunc(&req);
}
default:
@ -245,28 +265,20 @@ PUBLIC int do_fcntl()
}
}
/*===========================================================================*
* do_sync *
*===========================================================================*/
PUBLIC int do_sync()
{
/* Perform the sync() system call. Flush all the tables.
* The order in which the various tables are flushed is critical. The
* blocks must be flushed last, since rw_inode() leaves its results in
* the block cache.
*/
register struct inode *rip;
register struct buf *bp;
/* Write all the dirty inodes to the disk. */
for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++)
if (rip->i_count > 0 && rip->i_dirt == DIRTY) rw_inode(rip, WRITING);
/* Write all the dirty blocks to the disk, one drive at a time. */
for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++)
if (bp->b_dev != NO_DEV && bp->b_dirt == DIRTY) flushall(bp->b_dev);
return(OK); /* sync() can't fail */
struct vmnt *vmp;
for (vmp = &vmnt[1]; vmp < &vmnt[NR_MNTS]; ++vmp) {
if (vmp->m_dev != NO_DEV) {
/* Send sync request */
req_sync(vmp->m_fs_e);
}
}
return OK;
}
/*===========================================================================*
@ -288,8 +300,8 @@ PUBLIC void pm_reboot()
{
/* Perform the FS side of the reboot call. */
int i;
struct super_block *sp;
struct inode dummy;
struct vnode vdummy;
struct vmnt *vmp;
/* Do exit processing for all leftover processes and servers,
* but don't actually exit them (if they were really gone, PM
@ -302,22 +314,21 @@ PUBLIC void pm_reboot()
/* The root file system is mounted onto itself, which keeps it from being
* unmounted. Pull an inode out of thin air and put the root on it.
*/
put_inode(super_block[0].s_imount);
super_block[0].s_imount= &dummy;
dummy.i_count = 2; /* expect one "put" */
put_vnode(vmnt[0].m_mounted_on);
vmnt[0].m_mounted_on = &vdummy;
vmnt[0].m_root_node = &vdummy;
vdummy.v_count = 1;
/* Unmount all filesystems. File systems are mounted on other file systems,
* so you have to pull off the loose bits repeatedly to get it all undone.
*/
for (i= 0; i < NR_SUPERS; i++) {
/* Unmount at least one. */
for (sp= &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) {
if (sp->s_dev != NO_DEV) (void) unmount(sp->s_dev);
for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) {
if (vmp->m_dev != NO_DEV) (void) unmount(vmp->m_dev);
}
}
/* Sync any unwritten buffers. */
do_sync();
}
/*===========================================================================*
@ -331,7 +342,7 @@ int cpid; /* Child process id */
/* Perform those aspects of the fork() system call that relate to files.
* In particular, let the child inherit its parent's file descriptors.
* The parent and child parameters tell who forked off whom. The file
* system uses the same slot numbers as the kernel.
* system uses the same slot numbers as the kernel. Only MM makes this call.
*/
register struct fproc *cp;
@ -375,8 +386,8 @@ int cpid; /* Child process id */
cp->fp_execced = 0;
/* Record the fact that both root and working dir have another user. */
dup_inode(cp->fp_rootdir);
dup_inode(cp->fp_workdir);
dup_vnode(cp->fp_rd);
dup_vnode(cp->fp_wd);
}
/*===========================================================================*
@ -387,7 +398,7 @@ PRIVATE void free_proc(struct fproc *exiter, int flags)
int i, task;
register struct fproc *rfp;
register struct filp *rfilp;
register struct inode *rip;
register struct vnode *vp;
dev_t dev;
fp = exiter; /* get_filp() needs 'fp' */
@ -405,11 +416,11 @@ PRIVATE void free_proc(struct fproc *exiter, int flags)
}
/* Release root and working directories. */
put_inode(fp->fp_rootdir);
put_inode(fp->fp_workdir);
fp->fp_rootdir = NIL_INODE;
fp->fp_workdir = NIL_INODE;
put_vnode(fp->fp_rd);
put_vnode(fp->fp_wd);
fp->fp_rd = NIL_VNODE;
fp->fp_wd = NIL_VNODE;
/* Check if any process is SUSPENDed on this driver.
* If a driver exits, unmap its entries in the dmap table.
* (unmapping has to be done after the first step, because the
@ -440,9 +451,9 @@ PRIVATE void free_proc(struct fproc *exiter, int flags)
for (i = 0; i < OPEN_MAX; i++) {
if ((rfilp = rfp->fp_filp[i]) == NIL_FILP) continue;
if (rfilp->filp_mode == FILP_CLOSED) continue;
rip = rfilp->filp_ino;
if ((rip->i_mode & I_TYPE) != I_CHAR_SPECIAL) continue;
if ((dev_t) rip->i_zone[0] != dev) continue;
vp = rfilp->filp_vno;
if ((vp->v_mode & I_TYPE) != I_CHAR_SPECIAL) continue;
if ((dev_t) vp->v_sdev != dev) continue;
dev_close(dev);
rfilp->filp_mode = FILP_CLOSED;
}
@ -504,7 +515,6 @@ int ruid;
tfp->fp_realuid = ruid;
}
/*===========================================================================*
* do_svrctl *
*===========================================================================*/
@ -562,7 +572,6 @@ PUBLIC int do_svrctl()
}
}
/*===========================================================================*
* pm_dumpcore *
*===========================================================================*/
@ -571,267 +580,15 @@ int proc_e;
struct mem_map *seg_ptr;
{
int r, proc_s;
r= dumpcore(proc_e, seg_ptr);
/* Terminate the process */
okendpt(proc_e, &proc_s);
free_proc(&fproc[proc_s], FP_EXITING);
return r;
}
/*===========================================================================*
* dumpcore *
*===========================================================================*/
PRIVATE int dumpcore(proc_e, seg_ptr)
int proc_e;
struct mem_map *seg_ptr;
{
int r, seg, proc_s, exists;
mode_t omode;
vir_bytes len;
off_t off, seg_off;
long trace_off, trace_data;
struct fproc *rfp;
struct inode *rip, *ldirp;
struct mem_map segs[NR_LOCAL_SEGS];
okendpt(proc_e, &proc_s);
rfp= fp= &fproc[proc_s];
who_e= proc_e;
who_p= proc_s;
super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); /* su? */
/* We need the equivalent of
* open(CORE_NAME, O_WRONLY|O_CREAT|O_TRUNC|O_NONBLOCK, CORE_MODE)
*/
/* Create a new inode by calling new_node(). */
omode = I_REGULAR | (CORE_MODE & ALL_MODES & rfp->fp_umask);
rip = new_node(&ldirp, CORE_NAME, omode, NO_ZONE, 0, NULL);
r = err_code;
put_inode(ldirp);
exists= (r == EEXIST);
if (r != OK && r != EEXIST) return(r); /* error */
/* Only do the normal open code if we didn't just create the file. */
if (exists) {
/* Check protections. */
r = forbidden(rip, W_BIT);
if (r != OK)
{
put_inode(rip);
return r;
}
/* Make sure it is a regular file */
switch (rip->i_mode & I_TYPE) {
case I_REGULAR:
break;
case I_DIRECTORY:
/* Directories may be read but not written. */
r = EISDIR;
break;
case I_CHAR_SPECIAL:
case I_BLOCK_SPECIAL:
case I_NAMED_PIPE:
r = EPERM;
break;
}
if (r != OK)
{
put_inode(rip);
return r;
}
/* Truncate the file */
truncate_inode(rip, 0);
wipe_inode(rip);
/* Send the inode from the inode cache to the
* block cache, so it gets written on the next
* cache flush.
*/
rw_inode(rip, WRITING);
}
/* Copy segments from PM */
r= sys_datacopy(PM_PROC_NR, (vir_bytes)seg_ptr,
SELF, (vir_bytes)segs, sizeof(segs));
if (r != OK) panic(__FILE__, "dumpcore: cannot copy segment info", r);
off= 0;
r= write_bytes(rip, off, (char *)segs, sizeof(segs));
if (r != OK)
{
put_inode(rip);
return r;
}
off += sizeof(segs);
/* Write out the whole kernel process table entry to get the regs. */
for (trace_off= 0;; trace_off += sizeof(long))
{
r= sys_trace(T_GETUSER, proc_e, trace_off, &trace_data);
if (r != OK)
{
printf("dumpcore pid %d: sys_trace failed "
"at offset %ld: %d\n",
rfp->fp_pid, trace_off, r);
break;
}
r= write_bytes(rip, off, (char *)&trace_data,
sizeof(trace_data));
if (r != OK)
{
put_inode(rip);
return r;
}
off += sizeof(trace_data);
}
/* Loop through segments and write the segments themselves out. */
for (seg = 0; seg < NR_LOCAL_SEGS; seg++) {
len= segs[seg].mem_len << CLICK_SHIFT;
seg_off= segs[seg].mem_vir << CLICK_SHIFT;
r= write_seg(rip, off, proc_e, seg, seg_off, len);
if (r != OK)
{
put_inode(rip);
return r;
}
off += len;
}
rip->i_size= off;
rip->i_dirt = DIRTY;
put_inode(rip);
printf("VFSdumpcore: not implemented\n");
return OK;
}
/*===========================================================================*
* write_bytes *
*===========================================================================*/
PRIVATE int write_bytes(rip, off, buf, bytes)
struct inode *rip; /* inode descriptor to read from */
off_t off; /* offset in file */
char *buf;
size_t bytes; /* how much is to be transferred? */
{
int block_size;
off_t n, o, b_off;
block_t b;
struct buf *bp;
block_size= rip->i_sp->s_block_size;
for (o= off - (off % block_size); o < off+bytes; o += block_size)
{
if (o < off)
b_off= off-o;
else
b_off= 0;
n= block_size-b_off;
if (o+b_off+n > off+bytes)
n= off+bytes-(o+b_off);
b = read_map(rip, o);
if (b == NO_BLOCK) {
/* Writing to a nonexistent block. Create and enter
* in inode.
*/
if ((bp= new_block(rip, o)) == NIL_BUF)
return(err_code);
}
else
{
/* Just read the block, no need to optimize for
* writing entire blocks.
*/
bp = get_block(rip->i_dev, b, NORMAL);
}
if (n != block_size && o >= rip->i_size && b_off == 0) {
zero_block(bp);
}
/* Copy a chunk from user space to the block buffer. */
memcpy((bp->b_data+b_off), buf, n);
bp->b_dirt = DIRTY;
if (b_off + n == block_size)
put_block(bp, FULL_DATA_BLOCK);
else
put_block(bp, PARTIAL_DATA_BLOCK);
buf += n;
}
return OK;
}
/*===========================================================================*
* write_seg *
*===========================================================================*/
PRIVATE int write_seg(rip, off, proc_e, seg, seg_off, seg_bytes)
struct inode *rip; /* inode descriptor to read from */
off_t off; /* offset in file */
int proc_e; /* process number (endpoint) */
int seg; /* T, D, or S */
off_t seg_off; /* Offset in segment */
phys_bytes seg_bytes; /* how much is to be transferred? */
{
int r, block_size, fl;
off_t n, o, b_off;
block_t b;
struct buf *bp;
block_size= rip->i_sp->s_block_size;
for (o= off - (off % block_size); o < off+seg_bytes; o += block_size)
{
if (o < off)
b_off= off-o;
else
b_off= 0;
n= block_size-b_off;
if (o+b_off+n > off+seg_bytes)
n= off+seg_bytes-(o+b_off);
b = read_map(rip, o);
if (b == NO_BLOCK) {
/* Writing to a nonexistent block. Create and enter in inode.*/
if ((bp= new_block(rip, o)) == NIL_BUF)
return(err_code);
} else {
/* Normally an existing block to be partially overwritten is
* first read in. However, a full block need not be read in.
* If it is already in the cache, acquire it, otherwise just
* acquire a free buffer.
*/
fl = (n == block_size ? NO_READ : NORMAL);
bp = get_block(rip->i_dev, b, fl);
}
if (n != block_size && o >= rip->i_size && b_off == 0) {
zero_block(bp);
}
/* Copy a chunk from user space to the block buffer. */
r = sys_vircopy(proc_e, seg, (phys_bytes) seg_off,
FS_PROC_NR, D, (phys_bytes) (bp->b_data+b_off),
(phys_bytes) n);
bp->b_dirt = DIRTY;
fl = (b_off + n == block_size ? FULL_DATA_BLOCK : PARTIAL_DATA_BLOCK);
put_block(bp, fl);
seg_off += n;
}
return OK;
}

602
servers/vfs/mount.c Normal file
View file

@ -0,0 +1,602 @@
/* This file performs the MOUNT and UMOUNT system calls.
*
* The entry points into this file are
* do_mount: perform the MOUNT system call
* do_umount: perform the UMOUNT system call
*
* Changes for VFS:
* Jul 2006 (Balazs Gerofi)
*/
#include "fs.h"
#include <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;
}

528
servers/vfs/open.c Normal file
View file

@ -0,0 +1,528 @@
/* This file contains the procedures for creating, opening, closing, and
* seeking on files.
*
* The entry points into this file are
* do_creat: perform the CREAT system call
* do_open: perform the OPEN system call
* do_mknod: perform the MKNOD system call
* do_mkdir: perform the MKDIR system call
* do_close: perform the CLOSE system call
* do_lseek: perform the LSEEK system call
*
* Changes for VFS:
* Jul 2006 (Balazs Gerofi)
*/
#include "fs.h"
#include <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);
}

65
servers/vfs/param.h Normal file
View file

@ -0,0 +1,65 @@
/* The following names are synonyms for the variables in the input message. */
#define acc_time m2_l1
#define addr m1_i3
#define buffer m1_p1
#define child_endpt m1_i2
#define co_mode m1_i1
#define eff_grp_id m1_i3
#define eff_user_id m1_i3
#define erki m1_p1
#define fd m1_i1
#define fd2 m1_i2
#define ioflags m1_i3
#define group m1_i3
#define real_grp_id m1_i2
#define ls_fd m2_i1
#define mk_mode m1_i2
#define mk_z0 m1_i3
#define mode m3_i2
#define c_mode m1_i3
#define c_name m1_p1
#define name m3_p1
#define name1 m1_p1
#define name2 m1_p2
#define name_length m3_i1
#define name1_length m1_i1
#define name2_length m1_i2
#define nbytes m1_i2
#define owner m1_i2
#define parent_endpt m1_i1
#define pathname m3_ca1
#define pid m1_i3
#define ENDPT m1_i1
#define ctl_req m4_l1
#define driver_nr m4_l2
#define dev_nr m4_l3
#define dev_style m4_l4
#define m_force m4_l5
#define rd_only m1_i3
#define real_user_id m1_i2
#define request m1_i2
#define sig m1_i2
#define endpt1 m1_i1
#define tp m2_l1
#define utime_actime m2_l1
#define utime_modtime m2_l2
#define utime_file m2_p1
#define utime_length m2_i1
#define utime_strlen m2_i2
#define whence m2_i2
#define svrctl_req m2_i1
#define svrctl_argp m2_p1
#define pm_stime m1_i1
#define info_what m1_i1
#define info_where m1_p1
/* The following names are synonyms for the variables in the output message. */
#define reply_type m_type
#define reply_l1 m2_l1
#define reply_i1 m1_i1
#define reply_i2 m1_i2
#define reply_t1 m4_l1
#define reply_t2 m4_l2
#define reply_t3 m4_l3
#define reply_t4 m4_l4
#define reply_t5 m4_l5

152
servers/vfs/path.c Normal file
View file

@ -0,0 +1,152 @@
/* lookup() is the main routine that controls the path name lookup. It
* handles mountpoints and symbolic links. The actual lookup requests
* are sent through the req_lookup wrapper function.
*
* Jul 2006 (Balazs Gerofi)
*/
#include "fs.h"
#include <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;
}

View file

@ -13,6 +13,9 @@
* revive: mark a suspended process as able to run again
* unsuspend_by_endpt: revive all processes blocking on a given process
* do_unpause: a signal has been sent to a process; see if it suspended
*
* Changes for VFS:
* Jul 2006 (Balazs Gerofi)
*/
#include "fs.h"
@ -26,11 +29,16 @@
#include <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 *
*===========================================================================*/
@ -39,11 +47,22 @@ PUBLIC int do_pipe()
/* Perform the pipe(fil_des) system call. */
register struct fproc *rfp;
register struct inode *rip;
int r;
struct filp *fil_ptr0, *fil_ptr1;
int fil_des[2]; /* reply goes here */
struct vnode *vp;
struct vmnt *vmp;
struct pipe_req req;
struct node_details res;
/* See if a free vnode is available */
if ( (vp = get_free_vnode()) == NIL_VNODE) {
printf("VFS: no vnode available!\n");
return err_code;
}
/* Acquire two file descriptors. */
rfp = fp;
if ( (r = get_fd(0, R_BIT, &fil_des[0], &fil_ptr0)) != OK) return(r);
@ -51,49 +70,69 @@ PUBLIC int do_pipe()
FD_SET(fil_des[0], &rfp->fp_filp_inuse);
fil_ptr0->filp_count = 1;
if ( (r = get_fd(0, W_BIT, &fil_des[1], &fil_ptr1)) != OK) {
rfp->fp_filp[fil_des[0]] = NIL_FILP;
FD_CLR(fil_des[0], &rfp->fp_filp_inuse);
fil_ptr0->filp_count = 0;
return(r);
rfp->fp_filp[fil_des[0]] = NIL_FILP;
FD_CLR(fil_des[0], &rfp->fp_filp_inuse);
fil_ptr0->filp_count = 0;
return(r);
}
rfp->fp_filp[fil_des[1]] = fil_ptr1;
FD_SET(fil_des[1], &rfp->fp_filp_inuse);
fil_ptr1->filp_count = 1;
/* Make the inode on the pipe device. */
if ( (rip = alloc_inode(root_dev, I_REGULAR) ) == NIL_INODE) {
rfp->fp_filp[fil_des[0]] = NIL_FILP;
FD_CLR(fil_des[0], &rfp->fp_filp_inuse);
fil_ptr0->filp_count = 0;
rfp->fp_filp[fil_des[1]] = NIL_FILP;
FD_CLR(fil_des[1], &rfp->fp_filp_inuse);
fil_ptr1->filp_count = 0;
return(err_code);
/* Fill in FS request */
req.fs_e = ROOT_FS_E;
req.uid = fp->fp_effuid;
req.gid = fp->fp_effgid;
/* Send request */
r = req_pipe(&req, &res);
/* Handle error */
if (r != OK) {
rfp->fp_filp[fil_des[0]] = NIL_FILP;
FD_CLR(fil_des[0], &rfp->fp_filp_inuse);
fil_ptr0->filp_count = 0;
rfp->fp_filp[fil_des[1]] = NIL_FILP;
FD_CLR(fil_des[1], &rfp->fp_filp_inuse);
fil_ptr1->filp_count = 0;
return r;
}
if (read_only(rip) != OK)
panic(__FILE__,"pipe device is read only", NO_NUM);
rip->i_pipe = I_PIPE;
rip->i_mode &= ~I_REGULAR;
rip->i_mode |= I_NAMED_PIPE; /* pipes and FIFOs have this bit set */
fil_ptr0->filp_ino = rip;
/* Fill in vnode */
vp->v_fs_e = res.fs_e;
vp->v_inode_nr = res.inode_nr;
vp->v_mode = res.fmode;
vp->v_index = res.inode_index;
vp->v_pipe = I_PIPE;
vp->v_count = 2; /* Double usage */
vp->v_size = 0;
if ( (vmp = find_vmnt(vp->v_fs_e)) == NIL_VMNT) {
printf("VFS: vmnt not found by pipe() ==>> USING ROOT VMNT\n");
vp->v_vmnt = &vmnt[0];
}
else {
vp->v_vmnt = vmp;
vp->v_dev = vmp->m_dev;
}
/* Fill in filp objects */
fil_ptr0->filp_vno = vp;
fil_ptr1->filp_vno = vp;
fil_ptr0->filp_flags = O_RDONLY;
dup_inode(rip); /* for double usage */
fil_ptr1->filp_ino = rip;
fil_ptr1->filp_flags = O_WRONLY;
rw_inode(rip, WRITING); /* mark inode as allocated */
m_out.reply_i1 = fil_des[0];
m_out.reply_i2 = fil_des[1];
rip->i_update = ATIME | CTIME | MTIME;
return(OK);
}
/*===========================================================================*
* pipe_check *
*===========================================================================*/
PUBLIC int pipe_check(rip, rw_flag, oflags, bytes, position, canwrite, notouch)
register struct inode *rip; /* the inode of the pipe */
PUBLIC int pipe_check(vp, rw_flag, oflags, bytes, position, canwrite, notouch)
register struct vnode *vp; /* the inode of the pipe */
int rw_flag; /* READING or WRITING */
int oflags; /* flags set by open or fcntl */
register int bytes; /* bytes to be read or written (all chunks) */
@ -109,10 +148,10 @@ int notouch; /* check only */
/* If reading, check for empty pipe. */
if (rw_flag == READING) {
if (position >= rip->i_size) {
if (position >= vp->v_size) {
/* Process is reading from an empty pipe. */
int r = 0;
if (find_filp(rip, W_BIT) != NIL_FILP) {
if (find_filp(vp, W_BIT) != NIL_FILP) {
/* Writer exists */
if (oflags & O_NONBLOCK) {
r = EAGAIN;
@ -123,13 +162,13 @@ int notouch; /* check only */
}
/* If need be, activate sleeping writers. */
if (susp_count > 0)
release(rip, WRITE, susp_count);
release(vp, WRITE, susp_count);
}
return(r);
}
} else {
/* Process is writing to a pipe. */
if (find_filp(rip, R_BIT) == NIL_FILP) {
if (find_filp(vp, R_BIT) == NIL_FILP) {
/* Tell kernel to generate a SIGPIPE signal. */
if (!notouch) {
sys_kill(fp->fp_endpoint, SIGPIPE);
@ -137,30 +176,31 @@ int notouch; /* check only */
return(EPIPE);
}
if (position + bytes > PIPE_SIZE(rip->i_sp->s_block_size)) {
if (position + bytes > PIPE_SIZE(vp->v_vmnt->m_block_size)) {
if ((oflags & O_NONBLOCK)
&& bytes <= PIPE_SIZE(rip->i_sp->s_block_size))
&& bytes <= PIPE_SIZE(vp->v_vmnt->m_block_size)) {
return(EAGAIN);
}
else if ((oflags & O_NONBLOCK)
&& bytes > PIPE_SIZE(rip->i_sp->s_block_size)) {
if ( (*canwrite = (PIPE_SIZE(rip->i_sp->s_block_size)
&& bytes > PIPE_SIZE(vp->v_vmnt->m_block_size)) {
if ( (*canwrite = (PIPE_SIZE(vp->v_vmnt->m_block_size)
- position)) > 0) {
/* Do a partial write. Need to wakeup reader */
if (!notouch)
release(rip, READ, susp_count);
release(vp, READ, susp_count);
return(1);
} else {
return(EAGAIN);
}
}
if (bytes > PIPE_SIZE(rip->i_sp->s_block_size)) {
if ((*canwrite = PIPE_SIZE(rip->i_sp->s_block_size)
if (bytes > PIPE_SIZE(vp->v_vmnt->m_block_size)) {
if ((*canwrite = PIPE_SIZE(vp->v_vmnt->m_block_size)
- position) > 0) {
/* Do a partial write. Need to wakeup reader
* since we'll suspend ourself in read_write()
*/
if (!notouch)
release(rip, READ, susp_count);
release(vp, READ, susp_count);
return(1);
}
}
@ -171,7 +211,7 @@ int notouch; /* check only */
/* Writing to an empty pipe. Search for suspended reader. */
if (position == 0 && !notouch)
release(rip, READ, susp_count);
release(vp, READ, susp_count);
}
*canwrite = 0;
@ -236,8 +276,8 @@ PUBLIC void unsuspend_by_endpt(int proc_e)
/*===========================================================================*
* release *
*===========================================================================*/
PUBLIC void release(ip, call_nr, count)
register struct inode *ip; /* inode of pipe */
PUBLIC void release(vp, call_nr, count)
register struct vnode *vp; /* inode of pipe */
int call_nr; /* READ, WRITE, OPEN or CREAT */
int count; /* max number of processes to release */
{
@ -260,7 +300,7 @@ int count; /* max number of processes to release */
op = SEL_WR;
for(f = &filp[0]; f < &filp[NR_FILPS]; f++) {
if (f->filp_count < 1 || !(f->filp_pipe_select_ops & op) ||
f->filp_ino != ip)
f->filp_vno != vp)
continue;
select_callback(f, op);
f->filp_pipe_select_ops &= ~op;
@ -272,7 +312,7 @@ int count; /* max number of processes to release */
if (rp->fp_pid != PID_FREE && rp->fp_suspended == SUSPENDED &&
rp->fp_revived == NOT_REVIVING &&
(rp->fp_fd & BYTE) == call_nr &&
rp->fp_filp[rp->fp_fd>>8]->filp_ino == ip) {
rp->fp_filp[rp->fp_fd>>8]->filp_vno == vp) {
revive(rp->fp_endpoint, 0);
susp_count--; /* keep track of who is suspended */
if (--count == 0) return;
@ -337,6 +377,7 @@ int returned; /* if hanging on task, how many bytes read */
}
}
/*===========================================================================*
* do_unpause *
*===========================================================================*/
@ -398,7 +439,7 @@ int proc_nr_e;
if (fild < 0 || fild >= OPEN_MAX)
panic(__FILE__,"unpause err 2",NO_NUM);
f = rfp->fp_filp[fild];
dev = (dev_t) f->filp_ino->i_zone[0]; /* device hung on */
dev = (dev_t) f->filp_vno->v_sdev; /* device hung on */
mess.TTY_LINE = (dev >> MINOR) & BYTE;
mess.IO_ENDPT = rfp->fp_ioproc;
mess.IO_GRANT = (char *) rfp->fp_grant;
@ -424,6 +465,7 @@ int proc_nr_e;
return(OK);
}
/*===========================================================================*
* select_request_pipe *
*===========================================================================*/
@ -432,14 +474,14 @@ PUBLIC int select_request_pipe(struct filp *f, int *ops, int block)
int orig_ops, r = 0, err, canwrite;
orig_ops = *ops;
if ((*ops & (SEL_RD|SEL_ERR))) {
if ((err = pipe_check(f->filp_ino, READING, 0,
if ((err = pipe_check(f->filp_vno, READING, 0,
1, f->filp_pos, &canwrite, 1)) != SUSPEND)
r |= SEL_RD;
if (err < 0 && err != SUSPEND)
r |= SEL_ERR;
}
if ((*ops & (SEL_WR|SEL_ERR))) {
if ((err = pipe_check(f->filp_ino, WRITING, 0,
if ((err = pipe_check(f->filp_vno, WRITING, 0,
1, f->filp_pos, &canwrite, 1)) != SUSPEND)
r |= SEL_WR;
if (err < 0 && err != SUSPEND)
@ -462,8 +504,11 @@ PUBLIC int select_request_pipe(struct filp *f, int *ops, int block)
PUBLIC int select_match_pipe(struct filp *f)
{
/* recognize either pipe or named pipe (FIFO) */
if (f && f->filp_ino && (f->filp_ino->i_mode & I_NAMED_PIPE))
if (f && f->filp_vno && (f->filp_vno->v_mode & I_NAMED_PIPE))
return 1;
return 0;
}

165
servers/vfs/protect.c Normal file
View file

@ -0,0 +1,165 @@
/* This file deals with protection in the file system. It contains the code
* for four system calls that relate to protection.
*
* The entry points into this file are
* do_chmod: perform the CHMOD and FCHMOD system calls
* do_chown: perform the CHOWN and FCHOWN system calls
* do_umask: perform the UMASK system call
* do_access: perform the ACCESS system call
*
* Changes for VFS:
* Jul 2006 (Balazs Gerofi)
*/
#include "fs.h"
#include <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);
}

224
servers/vfs/proto.h Normal file
View file

@ -0,0 +1,224 @@
/* Function prototypes. */
#include "timers.h"
#include "request.h"
/* Structs used in prototypes must be declared as such first. */
struct filp;
struct fproc;
struct vmnt;
struct vnode;
/* device.c */
_PROTOTYPE( int dev_open, (Dev_t dev, int proc, int flags) );
_PROTOTYPE( void dev_close, (Dev_t dev) );
_PROTOTYPE( int dev_bio, (int op, Dev_t dev, int proc, void *buf,
off_t pos, int bytes) );
_PROTOTYPE( int dev_io, (int op, Dev_t dev, int proc, void *buf,
off_t pos, int bytes, int flags) );
_PROTOTYPE( int gen_opcl, (int op, Dev_t dev, int proc, int flags) );
_PROTOTYPE( int gen_io, (int task_nr, message *mess_ptr) );
_PROTOTYPE( int no_dev, (int op, Dev_t dev, int proc, int flags) );
_PROTOTYPE( int no_dev_io, (int, message *) );
_PROTOTYPE( int tty_opcl, (int op, Dev_t dev, int proc, int flags) );
_PROTOTYPE( int ctty_opcl, (int op, Dev_t dev, int proc, int flags) );
_PROTOTYPE( int clone_opcl, (int op, Dev_t dev, int proc, int flags) );
_PROTOTYPE( int ctty_io, (int task_nr, message *mess_ptr) );
_PROTOTYPE( int do_ioctl, (void) );
_PROTOTYPE( void pm_setsid, (int proc_e) );
_PROTOTYPE( void dev_status, (message *) );
_PROTOTYPE( void dev_up, (int major) );
/* dmap.c */
_PROTOTYPE( int do_devctl, (void) );
_PROTOTYPE( int fs_devctl, (int req, int dev, int proc_nr_e, int style,
int force) );
_PROTOTYPE( void build_dmap, (void) );
_PROTOTYPE( int map_driver, (int major, int proc_nr, int dev_style,
int force) );
_PROTOTYPE( int dmap_driver_match, (int proc, int major) );
_PROTOTYPE( void dmap_unmap_by_endpt, (int proc_nr) );
_PROTOTYPE( void dmap_endpt_up, (int proc_nr) );
/* exec.c */
_PROTOTYPE( int pm_exec, (int proc_e, char *path, vir_bytes path_len,
char *frame, vir_bytes frame_len) );
/* filedes.c */
_PROTOTYPE( struct filp *find_filp, (struct vnode *vp, mode_t bits) );
_PROTOTYPE( int get_fd, (int start, mode_t bits, int *k,
struct filp **fpt) );
_PROTOTYPE( struct filp *get_filp, (int fild) );
_PROTOTYPE( struct filp *get_filp2, (struct fproc *rfp, int fild) );
_PROTOTYPE( int inval_filp, (struct filp *) );
/* link.c */
_PROTOTYPE( int do_link, (void) );
_PROTOTYPE( int do_unlink, (void) );
_PROTOTYPE( int do_rename, (void) );
_PROTOTYPE( int do_truncate, (void) );
_PROTOTYPE( int do_ftruncate, (void) );
/* lock.c */
_PROTOTYPE( int lock_op, (struct filp *f, int req) );
_PROTOTYPE( void lock_revive, (void) );
/* main.c */
_PROTOTYPE( int main, (void) );
_PROTOTYPE( void reply, (int whom, int result) );
/* misc.c */
_PROTOTYPE( int do_dup, (void) );
_PROTOTYPE( void pm_exit, (int proc) );
_PROTOTYPE( int do_fcntl, (void) );
_PROTOTYPE( void pm_fork, (int pproc, int cproc, int cpid) );
_PROTOTYPE( void pm_setgid, (int proc_e, int egid, int rgid) );
_PROTOTYPE( void pm_setuid, (int proc_e, int euid, int ruid) );
_PROTOTYPE( int do_sync, (void) );
_PROTOTYPE( int do_fsync, (void) );
_PROTOTYPE( void pm_reboot, (void) );
_PROTOTYPE( int do_svrctl, (void) );
_PROTOTYPE( int do_getsysinfo, (void) );
_PROTOTYPE( int pm_dumpcore, (int proc_e, struct mem_map *seg_ptr) );
/* mount.c */
_PROTOTYPE( int do_fslogin, (void) );
_PROTOTYPE( int do_mount, (void) );
_PROTOTYPE( int do_umount, (void) );
_PROTOTYPE( int unmount, (Dev_t dev) );
/* open.c */
_PROTOTYPE( int do_close, (void) );
_PROTOTYPE( int close_fd, (struct fproc *rfp, int fd_nr) );
_PROTOTYPE( int do_creat, (void) );
_PROTOTYPE( int do_lseek, (void) );
_PROTOTYPE( int do_mknod, (void) );
_PROTOTYPE( int do_mkdir, (void) );
_PROTOTYPE( int do_open, (void) );
_PROTOTYPE( int do_slink, (void) );
/* path.c */
_PROTOTYPE( int lookup, (lookup_req_t *request, node_details_t *node) );
/* pipe.c */
_PROTOTYPE( int do_pipe, (void) );
_PROTOTYPE( int do_unpause, (void) );
_PROTOTYPE( int unpause, (int proc_nr_e) );
_PROTOTYPE( int pipe_check, (struct vnode *vp, int rw_flag,
int oflags, int bytes, off_t position, int *canwrite, int notouch));
_PROTOTYPE( void release, (struct vnode *vp, int call_nr, int count) );
_PROTOTYPE( void revive, (int proc_nr, int bytes) );
_PROTOTYPE( void suspend, (int task) );
_PROTOTYPE( int select_request_pipe, (struct filp *f, int *ops, int bl) );
_PROTOTYPE( int select_cancel_pipe, (struct filp *f) );
_PROTOTYPE( int select_match_pipe, (struct filp *f) );
_PROTOTYPE( void unsuspend_by_endpt, (int) );
/* protect.c */
_PROTOTYPE( int do_access, (void) );
_PROTOTYPE( int do_chmod, (void) );
_PROTOTYPE( int do_chown, (void) );
_PROTOTYPE( int do_umask, (void) );
/* read.c */
_PROTOTYPE( int do_read, (void) );
_PROTOTYPE( int read_write, (int rw_flag) );
/* request.c */
_PROTOTYPE( int fs_sendrec, (endpoint_t fs_e, message *reqm) );
_PROTOTYPE( int req_getnode, (node_req_t *req, node_details_t *res) );
_PROTOTYPE( int req_putnode, (node_req_t *req) );
_PROTOTYPE( int req_open, (open_req_t *req, node_details_t *res) );
_PROTOTYPE( int req_readwrite, (readwrite_req_t *req,
readwrite_res_t *res) );
_PROTOTYPE( int req_pipe, (pipe_req_t *req, node_details_t *res) );
_PROTOTYPE( int req_clone_opcl, (clone_opcl_req_t *req,
node_details_t *res) );
_PROTOTYPE( int req_ftrunc, (ftrunc_req_t *req) );
_PROTOTYPE( int req_chown, (chown_req_t *req) );
_PROTOTYPE( int req_chmod, (chmod_req_t *req) );
_PROTOTYPE( int req_access, (access_req_t *req) );
_PROTOTYPE( int req_mknod, (mknod_req_t *req) );
_PROTOTYPE( int req_mkdir, (mkdir_req_t *req) );
_PROTOTYPE( int req_inhibread, (node_req_t *req) );
_PROTOTYPE( int req_stat, (stat_req_t *req) );
_PROTOTYPE( int req_fstat, (stat_req_t *req) );
_PROTOTYPE( int req_fstatfs, (stat_req_t *req) );
_PROTOTYPE( int req_unlink, (unlink_req_t *req) );
_PROTOTYPE( int req_rmdir, (unlink_req_t *req) );
_PROTOTYPE( int req_utime, (utime_req_t *req) );
_PROTOTYPE( int req_stime, (endpoint_t fs_e, time_t boottime) );
_PROTOTYPE( int req_sync, (endpoint_t fs_e) );
_PROTOTYPE( int req_getdir, (getdir_req_t *req, node_details_t *res) );
_PROTOTYPE( int req_link, (link_req_t *req) );
_PROTOTYPE( int req_slink, (slink_req_t *req) );
_PROTOTYPE( int req_rdlink, (rdlink_req_t *req) );
_PROTOTYPE( int req_rename, (rename_req_t *req) );
_PROTOTYPE( int req_mountpoint, (mountpoint_req_t *req,
node_details_t *res) );
_PROTOTYPE( int req_readsuper, (readsuper_req_t *req,
readsuper_res_t *res) );
_PROTOTYPE( int req_unmount, (endpoint_t fs_e) );
_PROTOTYPE( int req_trunc, (trunc_req_t *req) );
_PROTOTYPE( int req_lookup, (lookup_req_t *req, lookup_res_t *res) );
_PROTOTYPE( int req_newdriver, (endpoint_t fs_e, Dev_t dev,
endpoint_t driver_e) );
_PROTOTYPE( int req_breadwrite, (breadwrite_req_t *req,
readwrite_res_t *res) );
/* stadir.c */
_PROTOTYPE( int do_chdir, (void) );
_PROTOTYPE( int do_fchdir, (void) );
_PROTOTYPE( int do_chroot, (void) );
_PROTOTYPE( int do_fstat, (void) );
_PROTOTYPE( int do_stat, (void) );
_PROTOTYPE( int do_fstatfs, (void) );
_PROTOTYPE( int do_rdlink, (void) );
_PROTOTYPE( int do_lstat, (void) );
/* time.c */
_PROTOTYPE( int do_stime, (void) );
_PROTOTYPE( int do_utime, (void) );
/* utility.c */
_PROTOTYPE( time_t clock_time, (void) );
_PROTOTYPE( unsigned conv2, (int norm, int w) );
_PROTOTYPE( long conv4, (int norm, long x) );
_PROTOTYPE( int fetch_name, (char *path, int len, int flag) );
_PROTOTYPE( int no_sys, (void) );
_PROTOTYPE( int isokendpt_f, (char *f, int l, int e, int *p, int ft));
_PROTOTYPE( void panic, (char *who, char *mess, int num) );
#define okendpt(e, p) isokendpt_f(__FILE__, __LINE__, (e), (p), 1)
#define isokendpt(e, p) isokendpt_f(__FILE__, __LINE__, (e), (p), 0)
/* vmnt.c */
_PROTOTYPE( struct vmnt *get_free_vmnt, (short *index) );
_PROTOTYPE( struct vmnt *find_vmnt, (int fs_e) );
/* vnode.c */
_PROTOTYPE( struct vnode *get_free_vnode, (void) );
_PROTOTYPE( struct vnode *find_vnode, (int fs_e, int numb) );
_PROTOTYPE( void dup_vnode, (struct vnode *vp) );
_PROTOTYPE( void put_vnode, (struct vnode *vp) );
_PROTOTYPE( struct vnode *get_vnode, (int fs_e, int inode_nr) );
/* write.c */
_PROTOTYPE( int do_write, (void) );
/* select.c */
_PROTOTYPE( int do_select, (void) );
_PROTOTYPE( int select_callback, (struct filp *, int ops) );
_PROTOTYPE( void select_forget, (int fproc) );
_PROTOTYPE( void select_timeout_check, (timer_t *) );
_PROTOTYPE( void init_select, (void) );
_PROTOTYPE( void select_unsuspend_by_endpt, (int proc) );
_PROTOTYPE( int select_notified, (int major, int minor, int ops) );
/* timers.c */
_PROTOTYPE( void fs_set_timer, (timer_t *tp, int delta,
tmr_func_t watchdog, int arg) );
_PROTOTYPE( void fs_expire_timers, (clock_t now) );
_PROTOTYPE( void fs_cancel_timer, (timer_t *tp) );
_PROTOTYPE( void fs_init_timer, (timer_t *tp) );

292
servers/vfs/read.c Normal file
View file

@ -0,0 +1,292 @@
/* This file contains the heart of the mechanism used to read (and write)
* files. Read and write requests are split up into chunks that do not cross
* block boundaries. Each chunk is then processed in turn. Reads on special
* files are also detected and handled.
*
* The entry points into this file are
* do_read: perform the READ system call by calling read_write
* read_write: actually do the work of READ and WRITE
*
* Changes for VFS:
* Jul 2006 (Balazs Gerofi)
*/
#include "fs.h"
#include <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

954
servers/vfs/request.c Normal file
View file

@ -0,0 +1,954 @@
/* This file contains the wrapper functions for issueing a request
* and receiving response from FS processes.
* Each function builds a request message according to the request
* parameter, calls the most low-level fs_sendrec and copies
* back the response.
* The low-level fs_sendrec handles the recovery mechanism from
* a dead driver and reissues the request.
*
* Sep 2006 (Balazs Gerofi)
*/
#include "fs.h"
#include <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;
}

Some files were not shown because too many files have changed in this diff Show more