From: David van Moolenbroek Date: Mon, 11 May 2009 10:02:28 +0000 (+0000) Subject: Limited support for nested FS->VFS requests during VFS->FS call. X-Git-Tag: v3.1.4~47 X-Git-Url: http://zhaoyanbai.com/repos/%22/xml/v3/zones/static/Bv9ARM.ch05.html?a=commitdiff_plain;h=0ac1aacccaa3b59bec5ea1160008b8783f57ac64;p=minix.git Limited support for nested FS->VFS requests during VFS->FS call. - Changed VFS-FS protocol to only store OK or negative error code in m_type field of reply messages. - Changed VFS to treat nonzero positive replies from FS as requests. - Added backwards compatibility to VFS and MFS. No protection of global data structures is provided in VFS, so many VFS calls cannot be made safely by FS servers during many FS calls. Use with caution (or, preferably, not at all). --- diff --git a/include/minix/vfsif.h b/include/minix/vfsif.h index 686beb20e..d79465de2 100644 --- a/include/minix/vfsif.h +++ b/include/minix/vfsif.h @@ -124,6 +124,10 @@ /* For REQ_GETDENTS */ #define RES_GDE_POS_CHANGE m2_l1 +#define RES_GDE_CUM_IO m2_i1 + +/* For REQ_RDLINK */ +#define RES_RDL_LENGTH m6_l1 /* Request numbers */ #define REQ_GETNODE (VFS_BASE + 1) /* Should be removed */ @@ -145,7 +149,7 @@ #define REQ_UNLINK_O (VFS_BASE + 17) /* Replaced with REQ_UNLINK_S */ #define REQ_RMDIR_O (VFS_BASE + 18) /* Replaced with REQ_RMDIR_S */ #define REQ_UTIME (VFS_BASE + 19) -#define REQ_RDLINK_S (VFS_BASE + 20) +#define REQ_RDLINK_SO (VFS_BASE + 20) /* Replaced with REQ_RDLINK_S */ #define REQ_FSTATFS (VFS_BASE + 21) #define REQ_BREAD_S (VFS_BASE + 22) #define REQ_BWRITE_S (VFS_BASE + 23) @@ -165,7 +169,7 @@ #define REQ_NEW_DRIVER (VFS_BASE + 37) #define REQ_BREAD_O (VFS_BASE + 38) /* Replaced with REQ_BREAD_S */ #define REQ_BWRITE_O (VFS_BASE + 39) /* Replaced with REQ_BWRITE_S */ -#define REQ_GETDENTS (VFS_BASE + 40) +#define REQ_GETDENTS_O (VFS_BASE + 40) /* Replaced with REQ_GETDENTS */ #define REQ_FLUSH (VFS_BASE + 41) #define REQ_READ_S (VFS_BASE + 42) #define REQ_WRITE_S (VFS_BASE + 43) @@ -178,13 +182,15 @@ #define REQ_MOUNTPOINT_S (VFS_BASE + 50) #define REQ_READSUPER_S (VFS_BASE + 51) #define REQ_NEWNODE (VFS_BASE + 52) +#define REQ_RDLINK_S (VFS_BASE + 53) +#define REQ_GETDENTS (VFS_BASE + 54) -#define NREQS 53 +#define NREQS 55 -#define EENTERMOUNT 301 -#define ELEAVEMOUNT 302 -#define ESYMLINK 303 +#define EENTERMOUNT -301 +#define ELEAVEMOUNT -302 +#define ESYMLINK -303 /* REQ_L_FLAGS */ #define PATH_RET_SYMLINK 1 /* Return a symlink object (i.e. diff --git a/servers/mfs/link.c b/servers/mfs/link.c index 4dbfa8bce..c9edb16fe 100644 --- a/servers/mfs/link.c +++ b/servers/mfs/link.c @@ -397,7 +397,8 @@ PUBLIC int fs_rdlink_s() (vir_bytes) bp->b_data, (vir_bytes) copylen, D); put_block(bp, DIRECTORY_BLOCK); - if (r == OK) r = copylen; + if (r == OK) + fs_m_out.RES_RDL_LENGTH = copylen; } put_inode(rip); @@ -405,6 +406,25 @@ PUBLIC int fs_rdlink_s() } +/*===========================================================================* + * fs_rdlink_so * + *===========================================================================*/ +PUBLIC int fs_rdlink_so() +{ +/* Legacy support: wrapper around new rdlink, returning the resulting number of + * bytes in the m_type field of the reply message instead. + */ + int r; + + r = fs_rdlink_s(); + + if (r == OK) + r = fs_m_out.RES_RDL_LENGTH; + + return(r); +} + + /*===========================================================================* * remove_dir_o * *===========================================================================*/ diff --git a/servers/mfs/proto.h b/servers/mfs/proto.h index bd2747047..3aaa98005 100644 --- a/servers/mfs/proto.h +++ b/servers/mfs/proto.h @@ -27,6 +27,7 @@ int fs_trunc(void); int fs_sync(void); int fs_stime(void); +int fs_getdents_o(void); int fs_getdents(void); int fs_flush(void); @@ -68,6 +69,7 @@ _PROTOTYPE( void wipe_inode, (struct inode *rip) ); int fs_link_o(void); int fs_link_s(void); int fs_rdlink_o(void); +int fs_rdlink_so(void); int fs_rdlink_s(void); int fs_rename_o(void); int fs_rename_s(void); diff --git a/servers/mfs/read.c b/servers/mfs/read.c index 063461dbb..cf948f289 100644 --- a/servers/mfs/read.c +++ b/servers/mfs/read.c @@ -1007,17 +1007,36 @@ printf("MFS(%d) get_inode by fs_getdents() failed\n", SELF_E); userbuf_off += tmpbuf_off; } - r= ENOSYS; - fs_m_out.RES_GDE_POS_CHANGE= 0; /* No change in case of an error */ if (done && userbuf_off == 0) r= EINVAL; /* The user's buffer is too small */ else { - r= userbuf_off; + fs_m_out.RES_GDE_CUM_IO= userbuf_off; if (new_pos >= pos) fs_m_out.RES_GDE_POS_CHANGE= new_pos-pos; + else + fs_m_out.RES_GDE_POS_CHANGE= 0; + r= OK; } put_inode(rip); /* release the inode */ return(r); } + +/*===========================================================================* + * fs_getdents_o * + *===========================================================================*/ +PUBLIC int fs_getdents_o(void) +{ +/* Legacy support: wrapper around new getdents, returning the resulting number + * of bytes in the m_type field of the reply message instead. + */ + int r; + + r = fs_getdents(); + + if (r == OK) + r = fs_m_out.RES_GDE_CUM_IO; + + return(r); +} diff --git a/servers/mfs/table.c b/servers/mfs/table.c index 0b2c0e00e..75ca006d7 100644 --- a/servers/mfs/table.c +++ b/servers/mfs/table.c @@ -34,7 +34,7 @@ PUBLIC _PROTOTYPE (int (*fs_call_vec[]), (void) ) = { fs_unlink_o, /* 17 */ /* unlink() */ fs_unlink_o, /* 18 */ /* rmdir() */ fs_utime, /* 19 */ - fs_rdlink_s, /* 20 */ + fs_rdlink_so, /* 20 */ fs_fstatfs, /* 21 */ fs_breadwrite_s, /* 22 */ fs_breadwrite_s, /* 23 */ @@ -54,7 +54,7 @@ PUBLIC _PROTOTYPE (int (*fs_call_vec[]), (void) ) = { fs_new_driver, /* 37 */ fs_breadwrite_o, /* 38 */ fs_breadwrite_o, /* 39 */ - fs_getdents, /* 40 */ + fs_getdents_o, /* 40 */ fs_flush, /* 41 */ fs_readwrite_s, /* 42 */ fs_readwrite_s, /* 43 */ @@ -67,5 +67,7 @@ PUBLIC _PROTOTYPE (int (*fs_call_vec[]), (void) ) = { fs_mountpoint_s, /* 50 */ fs_readsuper_s, /* 51 */ fs_newnode, /* 52 */ + fs_rdlink_s, /* 53 */ + fs_getdents, /* 54 */ }; diff --git a/servers/vfs/Makefile b/servers/vfs/Makefile index a3a922a65..18d983ce6 100644 --- a/servers/vfs/Makefile +++ b/servers/vfs/Makefile @@ -17,7 +17,7 @@ OBJ = main.o open.o read.o write.o pipe.o dmap.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 mmap.o + vnode.o vmnt.o request.o mmap.o fscall.o # build local binary install all build: $(SERVER) diff --git a/servers/vfs/fscall.c b/servers/vfs/fscall.c new file mode 100644 index 000000000..e3c3462e0 --- /dev/null +++ b/servers/vfs/fscall.c @@ -0,0 +1,154 @@ +/* This file handles nested counter-request calls to VFS sent by file system + * (FS) servers in response to VFS requests. + * + * The entry points into this file are + * nested_fs_call perform a nested call from a file system server + */ + +#include "fs.h" +#include "fproc.h" +#include +#include +#include +#include + +/* maximum nested call stack depth */ +#define MAX_DEPTH 1 + +/* global variables stack */ +PRIVATE struct { + struct fproc *g_fp; /* pointer to caller process */ + message g_m_in; /* request message */ + message g_m_out; /* reply message */ + int g_who_e; /* endpoint of caller process */ + int g_who_p; /* slot number of caller process */ + int g_call_nr; /* call number */ + int g_super_user; /* is the caller root? */ + short g_cum_path_processed; /* how many path chars processed? */ + char g_user_fullpath[PATH_MAX+1]; /* path to look up */ +} globals[MAX_DEPTH]; + +PRIVATE int depth = 0; /* current globals stack level */ + +#if ENABLE_SYSCALL_STATS +EXTERN unsigned long calls_stats[NCALLS]; +#endif + +FORWARD _PROTOTYPE( int push_globals, (void) ); +FORWARD _PROTOTYPE( void pop_globals, (void) ); +FORWARD _PROTOTYPE( void set_globals, (message *m) ); + +/*===========================================================================* + * push_globals * + *===========================================================================*/ +PRIVATE int push_globals() +{ +/* Save the global variables of the current call onto the globals stack. + */ + + if (depth == MAX_DEPTH) + return EPERM; + + globals[depth].g_fp = fp; + globals[depth].g_m_in = m_in; + globals[depth].g_m_out = m_out; + globals[depth].g_who_e = who_e; + globals[depth].g_who_p = who_p; + globals[depth].g_call_nr = call_nr; + globals[depth].g_super_user = super_user; + globals[depth].g_cum_path_processed = cum_path_processed; + + /* XXX is it safe to strcpy this? */ + assert(sizeof(globals[0].g_user_fullpath) == sizeof(user_fullpath)); + memcpy(globals[depth].g_user_fullpath, user_fullpath, sizeof(user_fullpath)); + + /* err_code is not used across blocking calls */ + + depth++; + + return OK; +} + +/*===========================================================================* + * pop_globals * + *===========================================================================*/ +PRIVATE void pop_globals() +{ +/* Restore the global variables of a call from the globals stack. + */ + + if (depth == 0) + panic("VFS", "Popping from empty globals stack!", NO_NUM); + + depth--; + + fp = globals[depth].g_fp; + m_in = globals[depth].g_m_in; + m_out = globals[depth].g_m_out; + who_e = globals[depth].g_who_e; + who_p = globals[depth].g_who_p; + call_nr = globals[depth].g_call_nr; + super_user = globals[depth].g_super_user; + cum_path_processed = globals[depth].g_cum_path_processed; + + memcpy(user_fullpath, globals[depth].g_user_fullpath, sizeof(user_fullpath)); +} + +/*===========================================================================* + * set_globals * + *===========================================================================*/ +PRIVATE void set_globals(m) +message *m; /* request message */ +{ +/* Initialize global variables based on a request message. + */ + + m_in = *m; + who_e = m_in.m_source; + who_p = _ENDPOINT_P(who_e); + call_nr = m_in.m_type; + fp = &fproc[who_p]; + super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); + /* the rest need not be initialized */ +} + +/*===========================================================================* + * nested_fs_call * + *===========================================================================*/ +PUBLIC void nested_fs_call(m) +message *m; /* request/reply message pointer */ +{ +/* Handle a nested call from a file system server. + */ + int r; + + /* Save global variables of the current call */ + if ((r = push_globals()) != OK) { + printf("VFS: error saving global variables in call %d from FS %d\n", + m->m_type, m->m_source); + } else { + /* Initialize global variables for the nested call */ + set_globals(m); + + /* Perform the nested call */ + if (call_nr < 0 || call_nr >= NCALLS) { + printf("VFS: invalid nested call %d from FS %d\n", call_nr, + who_e); + + r = ENOSYS; + } else { +#if ENABLE_SYSCALL_STATS + calls_stats[call_nr]++; +#endif + + r = (*call_vec[call_nr])(); + } + + /* Store the result, and restore original global variables */ + *m = m_out; + + pop_globals(); + } + + m->m_type = r; +} diff --git a/servers/vfs/proto.h b/servers/vfs/proto.h index d4d0a19a5..ea583f5a4 100644 --- a/servers/vfs/proto.h +++ b/servers/vfs/proto.h @@ -56,6 +56,9 @@ _PROTOTYPE( struct filp *get_filp, (int fild) ); _PROTOTYPE( struct filp *get_filp2, (struct fproc *rfp, int fild) ); _PROTOTYPE( int inval_filp, (struct filp *) ); +/* fscall.c */ +_PROTOTYPE( void nested_fs_call, (message *m) ); + /* kputc.c */ _PROTOTYPE( void diag_repl, (void) ); diff --git a/servers/vfs/request.c b/servers/vfs/request.c index 0c50df5de..0db338bcf 100644 --- a/servers/vfs/request.c +++ b/servers/vfs/request.c @@ -282,6 +282,25 @@ off_t *pos_change; m.REQ_GDE_POS= pos; r = fs_sendrec(fs_e, &m); + + if (r != ENOSYS && r != EINVAL) { + *pos_change= m.RES_GDE_POS_CHANGE; + + if (r == OK) + r = m.RES_GDE_CUM_IO; + + return r; + } + + /* Legacy support: try the old getdents */ + m.m_type = REQ_GETDENTS_O; + m.REQ_GDE_INODE= inode_nr; + m.REQ_GDE_GRANT= gid; + m.REQ_GDE_SIZE= size; + m.REQ_GDE_POS= pos; + + r = fs_sendrec(fs_e, &m); + *pos_change= m.RES_GDE_POS_CHANGE; return r; } @@ -633,6 +652,23 @@ size_t len; /* Send/rec request */ r= fs_sendrec(fs_e, &m); + if (r != ENOSYS && r != EINVAL) { + cpf_revoke(gid); + + if (r == OK) + r = m.RES_RDL_LENGTH; + + return r; + } + + /* Legacy support: try the old rdlink */ + m.m_type = REQ_RDLINK_SO; + m.REQ_INODE_NR = inode_nr; + m.REQ_GRANT = gid; + m.REQ_SLENGTH = len; + + r= fs_sendrec(fs_e, &m); + cpf_revoke(gid); return r; @@ -1026,10 +1062,18 @@ PRIVATE int fs_sendrec_f(char *file, int line, endpoint_t fs_e, message *reqm) /* Make a copy of the request so that we can load it back in * case of a dead driver */ origm = *reqm; - -#if 0 + + /* In response to the request we sent, some file systems may send back their + * own VFS request, instead of a reply. VFS currently offers limited support + * for this. As long as the FS keeps sending requests, we process them and + * send back a reply. We break out of the loop as soon as the FS sends a + * reply to the original request. + * + * There is no form of locking or whatever on global data structures, so it + * is quite easy to mess things up; hence, 'limited' support. A future async + * VFS will solve this problem for good. + */ for (;;) { -#endif /* Do the actual send, receive */ if (OK != (r=sendrec(fs_e, reqm))) { printf("VFS:fs_sendrec:%s:%d: error sending message. FS_e: %d req_nr: %d err: %d\n", @@ -1038,6 +1082,28 @@ PRIVATE int fs_sendrec_f(char *file, int line, endpoint_t fs_e, message *reqm) return r; } + /* If the type field is 0 (OK) or negative (E*), this is a reply. If it + * contains a positive nonzero value, this is a request. + */ + if (reqm->m_type <= 0) + break; /* Reply */ + + /* Legacy support: hacks for old nonzero nonnegative replies */ + if (origm.m_type == REQ_GETDENTS_O || origm.m_type == REQ_RDLINK_SO) + break; /* Reply */ + + if (reqm->m_type == -EENTERMOUNT || reqm->m_type == -ELEAVEMOUNT || + reqm->m_type == -ESYMLINK) { + + reqm->m_type = -reqm->m_type; + + break; /* Reply */ + } + + /* Request */ + nested_fs_call(reqm); + } + #if 0 if(r == OK) { /* Sendrec was okay */