_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 */
*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");
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);
}
std_err("Usage: mount [-r] [-t type] [-o options] special name\n");
exit(1);
}
-
-
-void tell(this)
-char *this;
-{
- write(1, this, strlen(this));
-}
#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");
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));
-}
*===========================================================================*/
/* 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 */
#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;
#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. */
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. */
/* 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;
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) {
_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;
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);
}
.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.
.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),
.SH NAME
umount \- unmount a mounted file system
.SH SYNOPSIS
-\fBumount \fIspecial\fR
+\fBumount \fIname\fR
.br
.de FL
.TP
..
.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
.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.
#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
unsigned long tasknr;
vir_bytes label_vir;
size_t label_len;
- char label[16];
+ char label[LABEL_MAX];
if (!super_user)
{
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[];
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];
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));
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));
}
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 */
/* 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 */
}
/*===========================================================================*
/* 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);
}
}
}
/* 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 *
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;
}
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);
}
*===========================================================================*/
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) {
*===========================================================================*/
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;
/* 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) */
/* 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);
/* 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);
}
}
/* 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);
}
/* 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;
* 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;
}
/* 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) {
/* 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 */
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;
/* 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;
/*===========================================================================*
* 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;
+}
#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
_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) );
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