/* 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 */
#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)
#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)
#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.
(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);
}
+/*===========================================================================*
+ * 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 *
*===========================================================================*/
int fs_sync(void);
int fs_stime(void);
+int fs_getdents_o(void);
int fs_getdents(void);
int fs_flush(void);
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);
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);
+}
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 */
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 */
fs_mountpoint_s, /* 50 */
fs_readsuper_s, /* 51 */
fs_newnode, /* 52 */
+ fs_rdlink_s, /* 53 */
+ fs_getdents, /* 54 */
};
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)
--- /dev/null
+/* 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 <string.h>
+#include <assert.h>
+#include <minix/callnr.h>
+#include <minix/endpoint.h>
+
+/* 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;
+}
_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) );
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;
}
/* 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;
/* 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",
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 */