]> Zhao Yanbai Git Server - minix.git/commitdiff
Mount updates:
authorDavid van Moolenbroek <david@minix3.org>
Tue, 12 Jan 2010 23:08:50 +0000 (23:08 +0000)
committerDavid van Moolenbroek <david@minix3.org>
Tue, 12 Jan 2010 23:08:50 +0000 (23:08 +0000)
- allow mounting with "none" block device
- allow unmounting by mountpoint
- make VFS aware of file system process labels
- allow m3_ca1 to use the full available message size
- use *printf in u/mount(1), as mount(2) uses it already
- fix reference leaks for some mount error cases in VFS

21 files changed:
commands/simple/mount.c
commands/simple/umount.c
include/minix/dmap.h
include/minix/ipc.h
include/sys/mount.h
lib/other/_mount.c
lib/other/loadname.c
man/man1/mount.1
man/man1/umount.1
man/man2/mount.2
servers/vfs/const.h
servers/vfs/dmap.c
servers/vfs/dmap.h
servers/vfs/fscall.c
servers/vfs/glo.h
servers/vfs/main.c
servers/vfs/misc.c
servers/vfs/mount.c
servers/vfs/param.h
servers/vfs/proto.h
servers/vfs/vmnt.h

index fb8d84b6e8ffe5c90958f2706a9e59d692edbf1d..abbd533e0712d9ab4cfca1cbe1c02339f535055c 100644 (file)
 _PROTOTYPE(int main, (int argc, char **argv));
 _PROTOTYPE(void list, (void));
 _PROTOTYPE(void usage, (void));
-_PROTOTYPE(void tell, (char *this));
 
 int main(argc, argv)
 int argc;
 char *argv[];
 {
   int i, n, v, mountflags;
-  char **ap, *vs, *opt, *err, *type, *args;
+  char **ap, *vs, *opt, *err, *type, *args, *device;
   char special[PATH_MAX+1], mounted_on[PATH_MAX+1], version[10], rw_flag[10];
 
   if (argc == 1) list();       /* just list /etc/mtab */
@@ -57,25 +56,21 @@ char *argv[];
   *ap = NULL;
   argc = (ap - argv);
 
-  if (argc != 3) usage();
-  if (mount(argv[1], argv[2], mountflags, type, args) < 0) {
+  if (argc != 3 || *argv[1] == 0) usage();
+
+  device = argv[1];
+  if (!strcmp(device, "none")) device = NULL;
+
+  if (mount(device, argv[2], mountflags, type, args) < 0) {
        err = strerror(errno);
-       std_err("mount: Can't mount ");
-       std_err(argv[1]);
-       std_err(" on ");
-       std_err(argv[2]);
-       std_err(": ");
-       std_err(err);
-       std_err("\n");
+       fprintf(stderr, "mount: Can't mount %s on %s: %s\n",
+               argv[1], argv[2], err);
        exit(1);
   }
+
   /* The mount has completed successfully. Tell the user. */
-  tell(argv[1]);
-  tell(" is read-");
-  tell(mountflags & MS_RDONLY ? "only" : "write");
-  tell(" mounted on ");
-  tell(argv[2]);
-  tell("\n");
+  printf("%s is read-%s mounted on %s\n",
+       argv[1], mountflags & MS_RDONLY ? "only" : "write", argv[2]);
 
   /* Update /etc/mtab. */
   n = load_mtab("mount");
@@ -133,12 +128,9 @@ void list()
   while (1) {
        n = get_mtab_entry(special, mounted_on, version, rw_flag);
        if  (n < 0) break;
-       write(1, special, strlen(special));
-       tell(" is read-");
-       tell(strcmp(rw_flag, "rw") == 0 ? "write" : "only");
-       tell(" mounted on ");
-       tell(mounted_on);
-       tell("\n");
+       printf("%s is read-%s mounted on %s (type %s)\n",
+               special, strcmp(rw_flag, "rw") == 0 ? "write" : "only",
+               mounted_on, version);
   }
   exit(0);
 }
@@ -149,10 +141,3 @@ void usage()
   std_err("Usage: mount [-r] [-t type] [-o options] special name\n");
   exit(1);
 }
-
-
-void tell(this)
-char *this;
-{
-  write(1, this, strlen(this));
-}
index 893a4c4eb855e33b03e1ce4331f5199ce220be7b..bf2fe1c6fbd53c956c2076b9b3817ecd40ce2f84 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <minix/type.h>
 #include <sys/types.h>
-#include <sys/svrctl.h>
+#include <sys/stat.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <limits.h>
 #include <stdio.h>
 
 _PROTOTYPE(int main, (int argc, char **argv));
-_PROTOTYPE(void update_mtab, (char *devname));
+_PROTOTYPE(int find_mtab_entry, (char *name));
+_PROTOTYPE(void update_mtab, (void));
 _PROTOTYPE(void usage, (void));
-_PROTOTYPE(void tell, (char *this));
 
-static char mountpoint[PATH_MAX+1];
+static char device[PATH_MAX+1], mountpoint[PATH_MAX+1], vs[10], rw[10];
 
 int main(argc, argv)
 int argc;
 char *argv[];
 {
+  int found;
+
   if (argc != 2) usage();
+  found = find_mtab_entry(argv[1]);
   if (umount(argv[1]) < 0) {
        if (errno == EINVAL)
-               std_err("Device not mounted\n");
+               std_err("umount: Device not mounted\n");
+       else if (errno == ENOTBLK)
+               std_err("unount: Not a mountpoint\n");
        else
                perror("umount");
        exit(1);
   }
-  update_mtab(argv[1]);
-  tell(argv[1]);
-  tell(" unmounted");
-  if (*mountpoint != '\0') {
-       tell(" from ");
-       tell(mountpoint);
+  if (found) {
+       printf("%s unmounted from %s\n", device, mountpoint);
+       update_mtab();
   }
-  tell("\n");
+  else printf("%s unmounted (mtab not updated)\n", argv[1]);
   return(0);
 }
 
-void update_mtab(devname)
-char *devname;
+int find_mtab_entry(name)
+char *name;
 {
-/* Remove an entry from /etc/mtab. */
-  int n;
+/* Find a matching mtab entry for 'name' which may be a special or a path,
+ * and generate a new mtab file without this entry on the fly. Do not write
+ * out the result yet. Return whether we found a matching entry.
+ */
   char special[PATH_MAX+1], mounted_on[PATH_MAX+1], version[10], rw_flag[10];
+  struct stat nstat, mstat;
+  int n, found;
 
-  if (load_mtab("umount") < 0) {
-       std_err("/etc/mtab not updated.\n");
-       exit(1);
-  }
+  if (load_mtab("umount") < 0) return 0;
+
+  if (stat(name, &nstat) != 0) return 0;
+
+  found = 0;
   while (1) {
        n = get_mtab_entry(special, mounted_on, version, rw_flag);
        if (n < 0) break;
-       if (strcmp(devname, special) == 0) {
+       if (strcmp(name, special) == 0 || (stat(mounted_on, &mstat) == 0 &&
+               mstat.st_dev == nstat.st_dev && mstat.st_ino == nstat.st_ino))
+       {
+               /* If we found an earlier match, keep that one. Mountpoints
+                * may be stacked on top of each other, and unmounting should
+                * take place in the reverse order of mounting.
+                */
+               if (found) {
+                       (void) put_mtab_entry(device, mountpoint, vs, rw);
+               }
+
+               strcpy(device, special);
                strcpy(mountpoint, mounted_on);
+               strcpy(vs, version);
+               strcpy(rw, rw_flag);
+               found = 1;
                continue;
        }
        (void) put_mtab_entry(special, mounted_on, version, rw_flag);
   }
+
+  return found;
+}
+
+void update_mtab()
+{
+/* Write out the new mtab file. */
+  int n;
+
   n = rewrite_mtab("umount");
   if (n < 0) {
        std_err("/etc/mtab not updated.\n");
@@ -75,12 +105,6 @@ char *devname;
 
 void usage()
 {
-  std_err("Usage: umount special\n");
+  std_err("Usage: umount name\n");
   exit(1);
 }
-
-void tell(this)
-char *this;
-{
-  write(1, this, strlen(this));
-}
index 7559bdc4aea73f907dfec1703fab203e2806d490..11598ad8471e71a7b1575e3e6eb85f86a901cfd5 100644 (file)
@@ -11,7 +11,11 @@ enum dev_style { STYLE_DEV, STYLE_NDEV, STYLE_TTY, STYLE_CLONE };
  *===========================================================================*/
 
 /* Total number of different devices. */
-#define NR_DEVICES               32                    /* number of (major) devices */
+#define NR_DEVICES               32            /* number of (major) devices */
+
+#define NONE_MAJOR                0    /* pseudo device for mounting file
+                                        * systems without a real block device
+                                        */
 
 /* Major and minor device numbers for MEMORY driver. */
 #define MEMORY_MAJOR              1    /* major device for memory devices */
index dd3c08414111bef9744215166731479f13937797..9bb459e91b798bd1ddb310cd2a12e184d1297cb2 100644 (file)
 #define M1                 1
 #define M3                 3
 #define M4                 4
-#define M3_STRING         14
+#define M3_STRING         14   /* legacy m3_ca1 size (must not be changed) */
+#define M3_LONG_STRING    16   /* current m3_ca1 size (may be increased) */
 
 typedef struct {int m1i1, m1i2, m1i3; char *m1p1, *m1p2, *m1p3;} mess_1;
 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 {int m3i1, m3i2; char *m3p1; char m3ca1[M3_LONG_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;
index 10d48c6873b669d62612bf430668bb1c9cb6184d..bee73a8ffca492c74cfcd394b9de5b8186976a40 100644 (file)
@@ -7,6 +7,7 @@
 
 #define MS_RDONLY      0x001   /* Mount device read only */
 #define MS_REUSE       0x002   /* Tell RS to try reusing binary from memory */
+#define MS_LABEL16     0x004   /* Mount message points to 16-byte label */
 
 
 /* Function Prototypes. */
index 7a668f14cf4abd8e3534633472b89b676e1593ad..5d930ae912f75008ce8b2be2cb3379b56bab6975 100644 (file)
@@ -25,40 +25,17 @@ PRIVATE int rs_down(char *label)
        return system(cmd);
 }
 
-PRIVATE char *makelabel(_CONST char *special)
-{
-  static char label[40];
-  _CONST char *dev;
-
-  /* Make label name. */
-  dev = strrchr(special, '/');
-  if(dev) dev++;
-  else dev = special;
-  if(strchr(dev, '\'') != NULL) {
-       errno = EINVAL;
-       return NULL;
-  }
-  if(strlen(dev)+4 >= sizeof(label)) {
-       errno = E2BIG;
-       return NULL;
-  }
-  sprintf(label, "fs_%s", dev);
-  return label;
-}
-
 PUBLIC int mount(special, name, mountflags, type, args)
 char *name, *special, *type, *args;
 int mountflags;
 {
   int r;
   message m;
-  struct rs_start rs_start;
   struct stat statbuf;
-  char *label;
+  char label[16];
   char path[60];
   char cmd[200];
-  FILE *pipe;
-  int ep;
+  char *p;
   int reuse;
 
   /* Default values. */
@@ -68,15 +45,33 @@ int mountflags;
 
   /* Check mount flags */
   if(mountflags & MS_REUSE) {
-    reuse = 1;
-    mountflags &= ~MS_REUSE; /* Temporary: turn off to not confuse VFS */
+       reuse = 1;
+       mountflags &= ~MS_REUSE; /* Temporary: turn off to not confuse VFS */
   }
 
-  /* Make FS process label for RS from special name. */
-  if(!(label=makelabel(special))) {
-       return -1;
+  /* Make a label for the file system process. This label must be unique and
+   * may currently not exceed 16 characters including terminating null. For
+   * requests with an associated block device, we use the last path component
+   * name of the block special file (truncated to 12 characters, which is
+   * hopefully enough). For requests with no associated block device, we use
+   * the device number and inode of the mount point, in hexadecimal form.
+   */
+  if (special) {
+       p = strrchr(special, '/');
+       p = p ? p + 1 : special;
+       if (strchr(p, '\'')) {
+               errno = EINVAL;
+               return -1;
+       }
+       sprintf(label, "fs_%.12s", p);
+  } else {
+       if (stat(name, &statbuf) < 0) return -1;
+       sprintf(label, "fs_%04x%x", statbuf.st_dev, statbuf.st_ino);
   }
 
+  /* Tell VFS that we are passing in a 16-byte label. */
+  mountflags |= MS_LABEL16;
+
   /* See if the given type is even remotely valid. */
   if(strlen(FSPATH)+strlen(type) >= sizeof(path)) {
        errno = E2BIG;
@@ -102,32 +97,23 @@ int mountflags;
        return -1;
   }
 
-
-
   sprintf(cmd, _PATH_SERVICE " %sup %s -label '%s' -config " _PATH_SYSTEM_CONF
-       " -args '%s%s' -printep yes",
+       " -args '%s%s'",
          reuse ? "-r ": "", path, label, args[0] ? "-o " : "", args);
 
-  if(!(pipe = popen(cmd, "r"))) {
+  if((r = system(cmd)) != 0) {
        fprintf(stderr, "mount: couldn't run %s\n", cmd);
+       errno = r;
        return -1;
   }
   
-  if(fscanf(pipe, "%d", &ep) != 1 || ep <= 0) {
-       fprintf(stderr, "mount: couldn't parse endpoint from %s\n", cmd);
-       errno = EINVAL;
-       pclose(pipe);
-       return -1;
-  }
-  pclose(pipe);
-  
   /* Now perform mount(). */
-  m.m1_i1 = strlen(special) + 1;
+  m.m1_i1 = special ? strlen(special) + 1 : 0;
   m.m1_i2 = strlen(name) + 1;
   m.m1_i3 = mountflags;
   m.m1_p1 = special;
   m.m1_p2 = name;
-  m.m1_p3 = (char*) ep;
+  m.m1_p3 = label;
   r = _syscall(FS, MOUNT, &m);
 
   if(r != OK) {
@@ -144,19 +130,16 @@ PUBLIC int umount(name)
 _CONST char *name;
 {
   message m;
-  char *label;
   int r;
 
-  /* Make MFS process label for RS from special name. */
-  if(!(label=makelabel(name))) {
-       return -1;
-  }
-
   _loadname(name, &m);
   r = _syscall(FS, UMOUNT, &m);
 
   if(r == OK) {
-       rs_down(label);
+       /* VFS returns the label of the unmounted file system in the reply.
+        * As of writing, the size of the m3_ca1 field is 16 bytes.
+        */
+       rs_down(m.m3_ca1);
   }
 
   return r;
index 1329b26747f66261bafe177e142cc0252b21154b..77ff26ce53f7809c2ec77aa44f02b3df684f8e32 100644 (file)
@@ -15,5 +15,5 @@ message *msgptr;
   k = strlen(name) + 1;
   msgptr->m3_i1 = k;
   msgptr->m3_p1 = (char *) name;
-  if (k <= sizeof msgptr->m3_ca1) strcpy(msgptr->m3_ca1, name);
+  if (k <= M3_STRING) strcpy(msgptr->m3_ca1, name);
 }
index a811adae02946bc02fca8567a3e70ce634e0d2d7..937a4e8a0eb7131129e8c6753662c4001b312436 100644 (file)
@@ -20,10 +20,13 @@ mount \- mount a file system
 .FL "\-o" "Options passed to FS server"
 .SH EXAMPLES
 .EX "mount /dev/fd1 /user" "Mount diskette 1 on \fI/user\fP"
+.EX "mount -t procfs none /proc" "Mount proc file system on \fI/proc\fP"
 .SH DESCRIPTION
 .PP
-The file system contained on the special file is mounted on \fIfile\fP.
-In the example above, the root directory of the file system in drive 1
+The file system contained on the special file \fIspecial\fP is mounted on
+\fIfile\fP. If the value of "\fBnone\fP" is given for \fIspecial\fP,
+the file system is mounted without a block special device underneath it.
+In the first example above, the root directory of the file system in drive 1
 can be accessed as
 .B /user
 after the mount.
@@ -37,6 +40,10 @@ The
 .B \-o
 flag may be used to pass options to the file system server.
 The interpretation of these options is up to the server.
+.PP
+If \fBmount\fP is invoked without any parameters, it will print the list of
+currently mounted file systems according to
+.BR mtab (5).
 .SH "SEE ALSO"
 .BR df (1),
 .BR mkfs (1),
index f082d610d1377dad6c6e91159cf970578b3a76f7..6b83e733a23f35a907da2dfdd1e7fe22491d4c10 100644 (file)
@@ -2,7 +2,7 @@
 .SH NAME
 umount \- unmount a mounted file system
 .SH SYNOPSIS
-\fBumount \fIspecial\fR
+\fBumount \fIname\fR
 .br
 .de FL
 .TP
@@ -16,8 +16,13 @@ umount \- unmount a mounted file system
 ..
 .SH EXAMPLES
 .EX "umount /dev/fd1" "Unmount diskette 1"
+.EX "umount /mnt" "Unmount the file system mounted on /mnt"
 .SH DESCRIPTION
 .PP
+This command unmounts a file system identified by
+.IR name .
+This name may be either a block special file, or the path name of a mount
+point.
 A mounted file system is unmounted after the cache has been flushed to disk.
 A diskette should never be removed while it is mounted.
 If this happens, and is discovered before another diskette is inserted, the
index 2a03e3dc2f4931e5acafe581f916b47860764b38..7d7036e499ca63c4f6654ca9809305f79f3c576b 100644 (file)
@@ -27,12 +27,18 @@ is a directory, then
 .I name
 must also be a directory.
 .I Special
-must be a block special file, except for loopback mounts.  For loopback
-mounts a normal file or directory is used for
-.IR special ,
-which must be seen as the root of a virtual device.
-.I Flag
-is 0 for a read-write mount, 1 for read-only.
+must be a block special file, or a NULL pointer.
+If a NULL pointer is passed, the file system is
+mounted without a block device.
+.I Mountflags
+may be a bitwise combination of the following flags:
+.TP 2
+.B MS_RDONLY
+Mount file system read-only, rather than read-write.
+.TP
+.B MS_REUSE
+Reuse the file system server image if possible.
+.PP
 .I Type
 is the type of the file system (e.g. "mfs"), used to pick a file system server.
 If this parameter is NULL, the default type is used.
index b4a0b07fb396b8cf124a8a95071e544bb2f2e57e..2ad3bf8828f6cfe985b68749c86523412c56e6d2 100644 (file)
@@ -4,6 +4,8 @@
 #define NR_MNTS             8  /* # slots in mount table */
 #define NR_VNODES         512  /* # slots in vnode table */
 
+#define NR_NONEDEVS    NR_MNTS /* # slots in nonedev bitmap */
+
 /* Miscellaneous constants */
 #define SU_UID          ((uid_t) 0)    /* super_user's uid_t */
 #define SERVERS_UID ((uid_t) 11) /* who may do FSSIGNON */
 
 #define ROOT_INODE         1           /* inode number for root directory */
 
+#define LABEL_MAX      16      /* maximum label size (including '\0'). Should
+                                * not be smaller than 16 or bigger than
+                                * M3_LONG_STRING.
+                                */
+
 /* Args to dev_io */
 #define VFS_DEV_READ   2001
 #define        VFS_DEV_WRITE   2002
index 0dea2da5fb3f2b5219b093713d1180b18f2e2e14..14a6be49725058a2345e1268d272e6eb25f0bce1 100644 (file)
@@ -65,7 +65,7 @@ PUBLIC int do_mapdriver()
        unsigned long tasknr;
        vir_bytes label_vir;
        size_t label_len;
-       char label[16];
+       char label[LABEL_MAX];
 
        if (!super_user)
        {
index 883f115bb79015591695cda2ba1d6116a7afb930..9ed775ddd8c2bf475d63a4a83f5bd3740b84e82e 100644 (file)
@@ -20,7 +20,7 @@ extern struct dmap {
   int _PROTOTYPE ((*dmap_io), (int, message *) );
   endpoint_t dmap_driver;
   int dmap_flags;
-  char dmap_label[16];
+  char dmap_label[LABEL_MAX];
   int dmap_async_driver;
   struct filp *dmap_sel_filp;
 } dmap[];
index e3c3462e00d9271f6f46e50c00e61920d7ddde67..9550585a7e1dcc41ccef9b08372bd1e4229b974f 100644 (file)
@@ -24,7 +24,6 @@ PRIVATE struct {
   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];
 
@@ -56,7 +55,6 @@ PRIVATE int push_globals()
   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));
@@ -89,7 +87,6 @@ PRIVATE void pop_globals()
   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));
 }
index 27731b9b25eb1922c28e6497d9dcae8720d6d548..3a56399fedc4fa796371ca047f7af198d41008ec 100644 (file)
@@ -22,10 +22,12 @@ 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 message mount_m_in;     /* the input message itself */
+
+EXTERN message mount_m_in;     /* the input message for a mount request */
+EXTERN endpoint_t mount_fs_e;  /* endpoint of file system to mount */
+EXTERN char mount_label[LABEL_MAX];    /* label of file system to mount */
 
 EXTERN char user_fullpath[PATH_MAX+1];    /* 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 */
index 1d7431f9db70134f4be30b9612352bb227c04ccc..4508025d6eb3780d29d9554ece2377d8ab9152f9 100644 (file)
@@ -517,6 +517,7 @@ PRIVATE void init_root()
   /* Root directory is not mounted on a vnode. */
   vmp->m_mounted_on = NULL;
   vmp->m_root_node = root_node;
+  strcpy(vmp->m_label, "fs_imgrd");    /* FIXME: obtain this from RS */
 }
 
 /*===========================================================================*
index a2805cb38a48d3c4f9b0c6215628bba912f99612..4178f736a736bf03767758ceee29567b02c5480d 100644 (file)
@@ -293,7 +293,7 @@ PRIVATE void unmount_all(void)
        /* Unmount at least one. */
        for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) {
                if (vmp->m_dev != NO_DEV) 
-                       unmount(vmp->m_dev); 
+                       unmount(vmp->m_dev, NULL);
        }
   }
 }
index 3d6725fb9964c735b77b814985bdbd11309116f3..bb9e19ef2d12660a27b1a91231cc8402b4b4cd27 100644 (file)
@@ -1,8 +1,10 @@
 /* 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
+ *   do_fslogin:       perform the FSLOGIN system call
+ *   do_mount:         perform the MOUNT system call
+ *   do_umount:                perform the UMOUNT system call
+ *   unmount:          unmount a file system
  */
 
 #include "fs.h"
 #include <minix/const.h>
 #include <minix/endpoint.h>
 #include <minix/syslib.h>
+#include <minix/bitmap.h>
+#include <minix/ds.h>
 #include <unistd.h>
 #include <sys/stat.h>
+#include <sys/mount.h>
 #include <dirent.h>
 #include "file.h"
 #include "fproc.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 mount_fs, (endpoint_t fs_e)                     );
+/* Bitmap of in-use "none" pseudo devices. */
+PRIVATE bitchunk_t nonedev[BITMAP_CHUNKS(NR_NONEDEVS)] = { 0 };
 
+#define alloc_nonedev(dev) SET_BIT(nonedev, minor(dev) - 1)
+#define free_nonedev(dev) UNSET_BIT(nonedev, minor(dev) - 1)
+
+FORWARD _PROTOTYPE( dev_t name_to_dev, (int allow_mountpt)             );
+FORWARD _PROTOTYPE( int mount_fs, (endpoint_t fs_e)                    );
+FORWARD _PROTOTYPE( int is_nonedev, (Dev_t dev)                                );
+FORWARD _PROTOTYPE( dev_t find_free_nonedev, (void)                            );
 
 /*===========================================================================*
  *                              do_fslogin                                   *
@@ -39,7 +51,7 @@ PUBLIC int do_fslogin()
   int r;
 
   /* Login before mount request */
-  if ((unsigned long)mount_m_in.m1_p3 != who_e) {
+  if (mount_fs_e != who_e) {
       last_login_fs_e = who_e;
       r = SUSPEND;
   }
@@ -58,7 +70,7 @@ PUBLIC int do_fslogin()
        fp = &fproc[who_p];       /* pointer to proc table struct */
        super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE);   /* su? */
       
-       r = do_mount();
+       r = mount_fs(mount_fs_e);
   }
   return(r);
 }
@@ -69,13 +81,30 @@ PUBLIC int do_fslogin()
  *===========================================================================*/
 PUBLIC int do_mount()
 {
-  endpoint_t fs_e; 
+  u32_t fs_e;
+  int r, proc_nr;
 
   /* Only the super-user may do MOUNT. */
   if (!super_user) return(EPERM);
        
   /* FS process' endpoint number */ 
-  fs_e = (unsigned long) m_in.fs_endpt;
+  if (m_in.mount_flags & MS_LABEL16) {
+       /* Get the label from the caller, and ask DS for the endpoint. */
+       r = sys_datacopy(who_e, (vir_bytes) m_in.fs_label, SELF,
+               (vir_bytes) mount_label, (phys_bytes) sizeof(mount_label));
+       if (r != OK) return(r);
+
+       mount_label[sizeof(mount_label)-1] = 0;
+
+       r = ds_retrieve_u32(mount_label, &fs_e);
+       if (r != OK) return(r);
+
+       if (isokendpt(fs_e, &proc_nr) != OK) return(EINVAL);
+  } else {
+       /* Legacy support: get the endpoint from the request itself. */
+       fs_e = (unsigned long) m_in.fs_label;
+       mount_label[0] = 0;
+  }
 
   /* Sanity check on process number. */
   if(fs_e <= 0) {
@@ -93,9 +122,9 @@ PUBLIC int do_mount()
  *===========================================================================*/
 PRIVATE int mount_fs(endpoint_t fs_e)
 {
-/* Perform the mount(name, mfile, rd_only) system call. */
+/* Perform the mount(name, mfile, mount_flags) system call. */
   int rdir, mdir;               /* TRUE iff {root|mount} file is dir */
-  int i, r, found, isroot, replace_root;
+  int i, r, found, rdonly, nodev, isroot, replace_root;
   struct fproc *tfp;
   struct dmap *dp;
   dev_t dev;
@@ -110,19 +139,37 @@ PRIVATE int mount_fs(endpoint_t fs_e)
 
   /* If FS not yet logged in, save message and suspend mount */
   if (last_login_fs_e != fs_e) {
-       mount_m_in = m_in; 
+       mount_m_in = m_in;
+       mount_fs_e = fs_e;
+       /* mount_label is already saved */
        return(SUSPEND);
   }
   
-  /* Mount request got after FS login or FS login arrived after a suspended mount */
+  /* Mount request got after FS login or FS login arrived after a suspended
+   * mount.
+   */
   last_login_fs_e = NONE;
   
   /* Clear endpoint field */
-  mount_m_in.fs_endpt = (char *) NONE;
-
-  /* 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()) == NO_DEV) return(err_code);
+  mount_fs_e = NONE;
+
+  /* Should the file system be mounted read-only? */
+  rdonly = (m_in.mount_flags & MS_RDONLY);
+
+  /* A null string for block special device means don't use a device at all. */
+  nodev = (m_in.name1_length == 0);
+
+  if (!nodev) {
+       /* 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(FALSE /*allow_mountpt*/)) == NO_DEV)
+               return(err_code);
+  } else {
+       /* Find a free pseudo-device as substitute for an actual device. */
+       if ((dev = find_free_nonedev()) == NO_DEV)
+               return(err_code);
+  }
 
   /* Check whether there is a block special file open which uses the 
    * same device (partition) */
@@ -158,24 +205,13 @@ PRIVATE int mount_fs(endpoint_t fs_e)
   /* 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_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
-                * to the root of the filesystem we found, we found a
-                * filesystem that is in use.
-                */
-               return(EBUSY);   /* already mounted */
+        * needs to be remounted. This could for example be a boot
+        * ramdisk that has already been replaced by the real root.
+        */
+       if(vmp->m_mounted_on || root_dev == vmp->m_dev) {
+               return(EBUSY);   /* not a root or still mounted */
        }
-         
-       if(vmp->m_mounted_on)
-               panic("vfs", "root unexpectedly mounted somewhere", NO_NUM);
-         
-       if (root_dev == vmp->m_dev)
-               panic("vfs", "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 ((vp = eat_path(PATH_NOFLAGS)) == NIL_VNODE) return(err_code);
@@ -201,8 +237,10 @@ PRIVATE int mount_fs(endpoint_t fs_e)
 
        /* Nothing else can go wrong.  Perform the mount. */
        vmp->m_mounted_on = vp;
-       vmp->m_flags = m_in.rd_only;
-       allow_newroot = 0;              /* The root is now fixed */
+       vmp->m_flags = rdonly;
+       strcpy(vmp->m_label, mount_label);
+       allow_newroot = 0;              /* The root is now fixed */
+       if (nodev) alloc_nonedev(dev);  /* Make the allocation final */
 
        return(OK);
   }
@@ -224,21 +262,29 @@ PRIVATE int mount_fs(endpoint_t fs_e)
   }
 
   /* We'll need a vnode for the root inode, check whether there is one */
-  if ((root_node = get_free_vnode()) == NIL_VNODE) return(ENFILE);  
-
-  /* Get driver process' endpoint */  
-  dp = &dmap[(dev >> MAJOR) & BYTE];
-  if (dp->dmap_driver == NONE) {
-         printf("VFS: no driver for dev %x\n", dev);
-         return(EINVAL);
+  if ((root_node = get_free_vnode()) == NIL_VNODE) {
+       if (vp != NIL_VNODE) put_vnode(vp);
+       return(ENFILE);
   }
 
-  label = dp->dmap_label;
-  if (strlen(label) == 0)
-       panic(__FILE__, "VFS mount_fs: no label for major", dev >> MAJOR);
+  label = "";
+  if (!nodev) {
+       /* Get driver process' endpoint */
+       dp = &dmap[(dev >> MAJOR) & BYTE];
+       if (dp->dmap_driver == NONE) {
+               printf("VFS: no driver for dev %x\n", dev);
+               if (vp != NIL_VNODE) put_vnode(vp);
+               return(EINVAL);
+       }
+
+       label = dp->dmap_label;
+       if (strlen(label) == 0)
+               panic(__FILE__, "VFS mount_fs: no label for major",
+                       dev >> MAJOR);
+  }
 
   /* Tell FS which device to mount */
-  if ((r = req_readsuper(fs_e, label, dev, m_in.rd_only, isroot, &res)) != OK){
+  if ((r = req_readsuper(fs_e, label, dev, rdonly, isroot, &res)) != OK) {
        if (vp != NIL_VNODE) put_vnode(vp);
        return(r);
   }
@@ -257,7 +303,7 @@ PRIVATE int mount_fs(endpoint_t fs_e)
   /* Fill in max file size and blocksize for the vmnt */
   vmp->m_fs_e = res.fs_e;
   vmp->m_dev = dev;
-  vmp->m_flags = m_in.rd_only;
+  vmp->m_flags = rdonly;
   
   /* Root node is indeed on the partition */
   root_node->v_vmnt = vmp;
@@ -268,6 +314,8 @@ PRIVATE int mount_fs(endpoint_t fs_e)
         * Nothing else can go wrong. Perform the mount. */
        vmp->m_root_node = root_node;
        vmp->m_mounted_on = NULL;
+       strcpy(vmp->m_label, mount_label);
+       if (nodev) alloc_nonedev(dev);
 
        root_dev = dev;
        ROOT_FS_E = fs_e;
@@ -291,11 +339,9 @@ PRIVATE int mount_fs(endpoint_t fs_e)
   }
   
   /* File types may not conflict. */
-  if (r == OK) {
-       mdir = ((vp->v_mode & I_TYPE) == I_DIRECTORY); /*TRUE iff dir*/
-       rdir = ((root_node->v_mode & I_TYPE) == I_DIRECTORY);
-       if (!mdir && rdir) r = EISDIR;
-  }
+  mdir = ((vp->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) {
@@ -308,9 +354,13 @@ PRIVATE int mount_fs(endpoint_t fs_e)
   /* Nothing else can go wrong.  Perform the mount. */
   vmp->m_mounted_on = vp;
   vmp->m_root_node = root_node;
+  strcpy(vmp->m_label, mount_label);
   
   /* The root is now fixed */
-  allow_newroot = 0;            
+  allow_newroot = 0;
+
+  /* Allocate the pseudo device that was found, if not using a real device. */
+  if (nodev) alloc_nonedev(dev);
 
   /* There was a block spec file open, and it should be handled by the 
    * new FS proc now */
@@ -326,23 +376,35 @@ PRIVATE int mount_fs(endpoint_t fs_e)
 PUBLIC int do_umount()
 {
 /* Perform the umount(name) system call. */
+  char label[LABEL_MAX];
   dev_t dev;
+  int r;
        
   /* Only the super-user may do umount. */
   if (!super_user) return(EPERM);
        
-  /* If 'name' is not for a block special file, return error. */
+  /* If 'name' is not for a block special file or mountpoint, 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);
+  if((dev = name_to_dev(TRUE /*allow_mountpt*/)) == NO_DEV) return(err_code);
+
+  if((r = unmount(dev, label)) != OK) return(r);
+
+  /* Return the label of the mounted file system, so that the caller
+   * can shut down the corresponding server process.
+   */
+  if (strlen(label) >= M3_LONG_STRING) /* should never evaluate to true */
+       label[M3_LONG_STRING-1] = 0;
+  strcpy(m_out.umount_label, label);
+  return(OK);
 }
 
 
 /*===========================================================================*
  *                              unmount                                      *
  *===========================================================================*/
-PUBLIC int unmount(dev)
-Dev_t dev;
+PUBLIC int unmount(dev, label)
+Dev_t dev;                             /* block-special device */
+char *label;                           /* buffer to retrieve label, or NULL */
 {
   struct vnode *vp, *vi;
   struct vmnt *vmp_i = NULL, *vmp = NULL;
@@ -371,19 +433,25 @@ Dev_t dev;
   
   /* Tell FS to drop all inode references for root inode except 1. */
   vnode_clean_refs(vmp->m_root_node);
-         
+
   if (vmp->m_mounted_on) {
        put_vnode(vmp->m_mounted_on);
        vmp->m_mounted_on = NIL_VNODE;
   }
-       
+
   /* Tell FS to unmount */
   if(vmp->m_fs_e <= 0 || vmp->m_fs_e == NONE)
        panic(__FILE__, "unmount: strange fs endpoint", vmp->m_fs_e);
 
   if ((r = req_unmount(vmp->m_fs_e)) != OK)              /* Not recoverable. */
        printf("VFS: ignoring failed umount attempt (%d)\n", r);
-  
+
+  if (is_nonedev(vmp->m_dev))
+       free_nonedev(vmp->m_dev);
+
+  if (label != NULL)
+       strcpy(label, vmp->m_label);
   vmp->m_root_node->v_ref_count = 0;
   vmp->m_root_node->v_fs_count = 0;
   vmp->m_root_node->v_sdev = NO_DEV;
@@ -421,27 +489,63 @@ Dev_t dev;
 /*===========================================================================*
  *                              name_to_dev                                  *
  *===========================================================================*/
-PRIVATE dev_t name_to_dev()
+PRIVATE dev_t name_to_dev(allow_mountpt)
+int allow_mountpt;
 {
-/* Convert the block special file 'path' to a device number.  If 'path'
- * is not a block special file, return error code in 'err_code'. */
+/* Convert the block special file in 'user_fullpath' to a device number.
+ * If the given path is not a block special file, but 'allow_mountpt' is set
+ * and the path is the root node of a mounted file system, return that device
+ * number. In all other cases, return NO_DEV and an error code in 'err_code'.
+ */
   int r;
   dev_t dev;
   struct vnode *vp;
   
   /* Request lookup */
   if ((vp = eat_path(PATH_NOFLAGS)) == NIL_VNODE) {
-       printf("VFS: name_to_dev: lookup of '%s' failed\n", user_fullpath);
        return(NO_DEV);
   }
 
-  if ((vp->v_mode & I_TYPE) != I_BLOCK_SPECIAL) {
+  if ((vp->v_mode & I_TYPE) == I_BLOCK_SPECIAL) {
+       dev = vp->v_sdev;
+  } else if (allow_mountpt && vp->v_vmnt->m_root_node == vp) {
+       dev = vp->v_dev;
+  } else {
        err_code = ENOTBLK;
        dev = NO_DEV;
-  } else
-       dev = vp->v_sdev;
+  }
 
   put_vnode(vp);
   return(dev);
 }
 
+
+/*===========================================================================*
+ *                              is_nonedev                                  *
+ *===========================================================================*/
+PRIVATE int is_nonedev(dev)
+{
+/* Return whether the given device is a "none" pseudo device.
+ */
+
+  return (major(dev) == NONE_MAJOR &&
+       minor(dev) > 0 && minor(dev) <= NR_NONEDEVS);
+}
+
+
+/*===========================================================================*
+ *                              find_free_nonedev                           *
+ *===========================================================================*/
+PRIVATE dev_t find_free_nonedev()
+{
+/* Find a free "none" pseudo device. Do not allocate it yet.
+ */
+  int i;
+
+  for (i = 0; i < NR_NONEDEVS; i++)
+       if (!GET_BIT(nonedev, i))
+               return makedev(NONE_MAJOR, i + 1);
+
+  err_code = EMFILE;
+  return NO_DEV;
+}
index 057b2dfab402bff85e204aa08ef20d5eca4eaac6..58941dae76f731616955ccacf875aac0c37def9e 100644 (file)
 #define dev_nr       m4_l3
 #define dev_style     m4_l4
 #define m_force              m4_l5
-#define rd_only              m1_i3
+#define mount_flags   m1_i3
 #define request       m1_i2
 #define sig          m1_i2
 #define endpt1       m1_i1
-#define fs_endpt      m1_p3
+#define fs_label      m1_p3
+#define umount_label  m3_ca1
 #define tp           m2_l1
 #define utime_actime  m2_l1
 #define utime_modtime m2_l2
index d7d5191a39c6a82012275567c093e112f7e2c94a..1d8968e685a9e2186a83ecb32d1b33b336cd2a5c 100644 (file)
@@ -94,7 +94,7 @@ _PROTOTYPE( int do_vm_mmap, (void)                                    );
 _PROTOTYPE( int do_fslogin, (void)                                      );
 _PROTOTYPE( int do_mount, (void)                                       );
 _PROTOTYPE( int do_umount, (void)                                      );
-_PROTOTYPE( int unmount, (Dev_t dev)                                   );
+_PROTOTYPE( int unmount, (Dev_t dev, char *label)                      );
 
 /* open.c */
 _PROTOTYPE( int do_close, (void)                                       );
index 598a304da1f14d5564578fdbfe6a5adf9ffdf1be..199f67efc16d74c6b0d66e81e717dc5ace63dee4 100644 (file)
@@ -4,8 +4,9 @@ EXTERN struct vmnt {
   int m_fs_e;                   /* FS process' kernel endpoint */
   dev_t m_dev;                  /* device number */
   int m_flags;                  /* mount flags */
-  struct vnode *m_mounted_on;   /* the vnode on which the partition is mounted */
+  struct vnode *m_mounted_on;   /* vnode on which the partition is mounted */
   struct vnode *m_root_node;    /* root vnode */
+  char m_label[LABEL_MAX];     /* label of the file system process */
 } vmnt[NR_MNTS];
 
 #define NIL_VMNT (struct vmnt *) 0