]> Zhao Yanbai Git Server - minix.git/commitdiff
Limited support for nested FS->VFS requests during VFS->FS call.
authorDavid van Moolenbroek <david@minix3.org>
Mon, 11 May 2009 10:02:28 +0000 (10:02 +0000)
committerDavid van Moolenbroek <david@minix3.org>
Mon, 11 May 2009 10:02:28 +0000 (10:02 +0000)
- 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).

include/minix/vfsif.h
servers/mfs/link.c
servers/mfs/proto.h
servers/mfs/read.c
servers/mfs/table.c
servers/vfs/Makefile
servers/vfs/fscall.c [new file with mode: 0644]
servers/vfs/proto.h
servers/vfs/request.c

index 686beb20e349bf5c690e710ea9d6a4fa4b584646..d79465de22760e8cd2e50cb1731200d6000d3c17 100644 (file)
 
 /* 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.
index 4dbfa8bce4900fe5ae2372493bc6c79bf5257d24..c9edb16febfc93b8ccacf532e5cf73eaadf440b8 100644 (file)
@@ -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                                 *
  *===========================================================================*/
index bd2747047b2b6cf38c128e551278fc80542592de..3aaa980054ef039aadda8f7e9f5b9efaf7b866ec 100644 (file)
@@ -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);
index 063461dbb9234e0aced3688a6631935155524177..cf948f289b4156c42950dd5e78f7be058e9b4395 100644 (file)
@@ -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);
+}
index 0b2c0e00edc4478aaa1c016491aa57da2cc5663b..75ca006d757735947645cd17b752d8b577890a2b 100644 (file)
@@ -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  */
 };
 
index a3a922a652b19b8593de2082e7fd0a0efa70e911..18d983ce69c701abf3f34dc453464b8de070d75d 100644 (file)
@@ -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 (file)
index 0000000..e3c3462
--- /dev/null
@@ -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 <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;
+}
index d4d0a19a54efa4b02e38ff56321c067b79a0aa8a..ea583f5a4f948c92fd3b4e72bd39372006159e0b 100644 (file)
@@ -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)                                     );
 
index 0c50df5debc780dd45bf906d231c082c8d55cd24..0db338bcf49d318856554824c46288028e55528e 100644 (file)
@@ -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 */