Mount updates:

- 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
This commit is contained in:
David van Moolenbroek 2010-01-12 23:08:50 +00:00
parent 483160f3d4
commit b31119abf5
21 changed files with 331 additions and 202 deletions

View file

@ -21,14 +21,13 @@
_PROTOTYPE(int main, (int argc, char **argv)); _PROTOTYPE(int main, (int argc, char **argv));
_PROTOTYPE(void list, (void)); _PROTOTYPE(void list, (void));
_PROTOTYPE(void usage, (void)); _PROTOTYPE(void usage, (void));
_PROTOTYPE(void tell, (char *this));
int main(argc, argv) int main(argc, argv)
int argc; int argc;
char *argv[]; char *argv[];
{ {
int i, n, v, mountflags; 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]; char special[PATH_MAX+1], mounted_on[PATH_MAX+1], version[10], rw_flag[10];
if (argc == 1) list(); /* just list /etc/mtab */ if (argc == 1) list(); /* just list /etc/mtab */
@ -57,25 +56,21 @@ char *argv[];
*ap = NULL; *ap = NULL;
argc = (ap - argv); argc = (ap - argv);
if (argc != 3) usage(); if (argc != 3 || *argv[1] == 0) usage();
if (mount(argv[1], argv[2], mountflags, type, args) < 0) {
device = argv[1];
if (!strcmp(device, "none")) device = NULL;
if (mount(device, argv[2], mountflags, type, args) < 0) {
err = strerror(errno); err = strerror(errno);
std_err("mount: Can't mount "); fprintf(stderr, "mount: Can't mount %s on %s: %s\n",
std_err(argv[1]); argv[1], argv[2], err);
std_err(" on ");
std_err(argv[2]);
std_err(": ");
std_err(err);
std_err("\n");
exit(1); exit(1);
} }
/* The mount has completed successfully. Tell the user. */ /* The mount has completed successfully. Tell the user. */
tell(argv[1]); printf("%s is read-%s mounted on %s\n",
tell(" is read-"); argv[1], mountflags & MS_RDONLY ? "only" : "write", argv[2]);
tell(mountflags & MS_RDONLY ? "only" : "write");
tell(" mounted on ");
tell(argv[2]);
tell("\n");
/* Update /etc/mtab. */ /* Update /etc/mtab. */
n = load_mtab("mount"); n = load_mtab("mount");
@ -133,12 +128,9 @@ void list()
while (1) { while (1) {
n = get_mtab_entry(special, mounted_on, version, rw_flag); n = get_mtab_entry(special, mounted_on, version, rw_flag);
if (n < 0) break; if (n < 0) break;
write(1, special, strlen(special)); printf("%s is read-%s mounted on %s (type %s)\n",
tell(" is read-"); special, strcmp(rw_flag, "rw") == 0 ? "write" : "only",
tell(strcmp(rw_flag, "rw") == 0 ? "write" : "only"); mounted_on, version);
tell(" mounted on ");
tell(mounted_on);
tell("\n");
} }
exit(0); exit(0);
} }
@ -149,10 +141,3 @@ void usage()
std_err("Usage: mount [-r] [-t type] [-o options] special name\n"); std_err("Usage: mount [-r] [-t type] [-o options] special name\n");
exit(1); exit(1);
} }
void tell(this)
char *this;
{
write(1, this, strlen(this));
}

View file

@ -5,7 +5,7 @@
#include <minix/type.h> #include <minix/type.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/svrctl.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
@ -17,55 +17,85 @@
#include <stdio.h> #include <stdio.h>
_PROTOTYPE(int main, (int argc, char **argv)); _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 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 main(argc, argv)
int argc; int argc;
char *argv[]; char *argv[];
{ {
int found;
if (argc != 2) usage(); if (argc != 2) usage();
found = find_mtab_entry(argv[1]);
if (umount(argv[1]) < 0) { if (umount(argv[1]) < 0) {
if (errno == EINVAL) 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 else
perror("umount"); perror("umount");
exit(1); exit(1);
} }
update_mtab(argv[1]); if (found) {
tell(argv[1]); printf("%s unmounted from %s\n", device, mountpoint);
tell(" unmounted"); update_mtab();
if (*mountpoint != '\0') {
tell(" from ");
tell(mountpoint);
} }
tell("\n"); else printf("%s unmounted (mtab not updated)\n", argv[1]);
return(0); return(0);
} }
void update_mtab(devname) int find_mtab_entry(name)
char *devname; char *name;
{ {
/* Remove an entry from /etc/mtab. */ /* Find a matching mtab entry for 'name' which may be a special or a path,
int n; * 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]; 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) { if (load_mtab("umount") < 0) return 0;
std_err("/etc/mtab not updated.\n");
exit(1); if (stat(name, &nstat) != 0) return 0;
}
found = 0;
while (1) { while (1) {
n = get_mtab_entry(special, mounted_on, version, rw_flag); n = get_mtab_entry(special, mounted_on, version, rw_flag);
if (n < 0) break; 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(mountpoint, mounted_on);
strcpy(vs, version);
strcpy(rw, rw_flag);
found = 1;
continue; continue;
} }
(void) put_mtab_entry(special, mounted_on, version, rw_flag); (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"); n = rewrite_mtab("umount");
if (n < 0) { if (n < 0) {
std_err("/etc/mtab not updated.\n"); std_err("/etc/mtab not updated.\n");
@ -75,12 +105,6 @@ char *devname;
void usage() void usage()
{ {
std_err("Usage: umount special\n"); std_err("Usage: umount name\n");
exit(1); exit(1);
} }
void tell(this)
char *this;
{
write(1, this, strlen(this));
}

View file

@ -13,6 +13,10 @@ enum dev_style { STYLE_DEV, STYLE_NDEV, STYLE_TTY, STYLE_CLONE };
/* Total number of different devices. */ /* 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. */ /* Major and minor device numbers for MEMORY driver. */
#define MEMORY_MAJOR 1 /* major device for memory devices */ #define MEMORY_MAJOR 1 /* major device for memory devices */
# define RAM_DEV_OLD 0 /* minor device for /dev/ram */ # define RAM_DEV_OLD 0 /* minor device for /dev/ram */

View file

@ -10,12 +10,13 @@
#define M1 1 #define M1 1
#define M3 3 #define M3 3
#define M4 4 #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 m1i1, m1i2, m1i3; char *m1p1, *m1p2, *m1p3;} mess_1;
typedef struct {int m2i1, m2i2, m2i3; long m2l1, m2l2; char *m2p1; typedef struct {int m2i1, m2i2, m2i3; long m2l1, m2l2; char *m2p1;
short m2s1;} mess_2; 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 {long m4l1, m4l2, m4l3, m4l4, m4l5;} mess_4;
typedef struct {short m5c1, m5c2; int m5i1, m5i2; long m5l1, m5l2, m5l3;}mess_5; 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; typedef struct {long m6l1, m6l2, m6l3; short m6s1, m6s2, m6s3; char m6c1, m6c2;

View file

@ -7,6 +7,7 @@
#define MS_RDONLY 0x001 /* Mount device read only */ #define MS_RDONLY 0x001 /* Mount device read only */
#define MS_REUSE 0x002 /* Tell RS to try reusing binary from memory */ #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. */ /* Function Prototypes. */

View file

@ -25,40 +25,17 @@ PRIVATE int rs_down(char *label)
return system(cmd); 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) PUBLIC int mount(special, name, mountflags, type, args)
char *name, *special, *type, *args; char *name, *special, *type, *args;
int mountflags; int mountflags;
{ {
int r; int r;
message m; message m;
struct rs_start rs_start;
struct stat statbuf; struct stat statbuf;
char *label; char label[16];
char path[60]; char path[60];
char cmd[200]; char cmd[200];
FILE *pipe; char *p;
int ep;
int reuse; int reuse;
/* Default values. */ /* Default values. */
@ -72,10 +49,28 @@ int mountflags;
mountflags &= ~MS_REUSE; /* Temporary: turn off to not confuse VFS */ mountflags &= ~MS_REUSE; /* Temporary: turn off to not confuse VFS */
} }
/* Make FS process label for RS from special name. */ /* Make a label for the file system process. This label must be unique and
if(!(label=makelabel(special))) { * 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; 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. */ /* See if the given type is even remotely valid. */
if(strlen(FSPATH)+strlen(type) >= sizeof(path)) { if(strlen(FSPATH)+strlen(type) >= sizeof(path)) {
@ -102,32 +97,23 @@ int mountflags;
return -1; return -1;
} }
sprintf(cmd, _PATH_SERVICE " %sup %s -label '%s' -config " _PATH_SYSTEM_CONF 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); 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); fprintf(stderr, "mount: couldn't run %s\n", cmd);
errno = r;
return -1; 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(). */ /* 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_i2 = strlen(name) + 1;
m.m1_i3 = mountflags; m.m1_i3 = mountflags;
m.m1_p1 = special; m.m1_p1 = special;
m.m1_p2 = name; m.m1_p2 = name;
m.m1_p3 = (char*) ep; m.m1_p3 = label;
r = _syscall(FS, MOUNT, &m); r = _syscall(FS, MOUNT, &m);
if(r != OK) { if(r != OK) {
@ -144,19 +130,16 @@ PUBLIC int umount(name)
_CONST char *name; _CONST char *name;
{ {
message m; message m;
char *label;
int r; int r;
/* Make MFS process label for RS from special name. */
if(!(label=makelabel(name))) {
return -1;
}
_loadname(name, &m); _loadname(name, &m);
r = _syscall(FS, UMOUNT, &m); r = _syscall(FS, UMOUNT, &m);
if(r == OK) { 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; return r;

View file

@ -15,5 +15,5 @@ message *msgptr;
k = strlen(name) + 1; k = strlen(name) + 1;
msgptr->m3_i1 = k; msgptr->m3_i1 = k;
msgptr->m3_p1 = (char *) name; 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);
} }

View file

@ -20,10 +20,13 @@ mount \- mount a file system
.FL "\-o" "Options passed to FS server" .FL "\-o" "Options passed to FS server"
.SH EXAMPLES .SH EXAMPLES
.EX "mount /dev/fd1 /user" "Mount diskette 1 on \fI/user\fP" .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 .SH DESCRIPTION
.PP .PP
The file system contained on the special file is mounted on \fIfile\fP. The file system contained on the special file \fIspecial\fP is mounted on
In the example above, the root directory of the file system in drive 1 \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 can be accessed as
.B /user .B /user
after the mount. after the mount.
@ -37,6 +40,10 @@ The
.B \-o .B \-o
flag may be used to pass options to the file system server. flag may be used to pass options to the file system server.
The interpretation of these options is up to the 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" .SH "SEE ALSO"
.BR df (1), .BR df (1),
.BR mkfs (1), .BR mkfs (1),

View file

@ -2,7 +2,7 @@
.SH NAME .SH NAME
umount \- unmount a mounted file system umount \- unmount a mounted file system
.SH SYNOPSIS .SH SYNOPSIS
\fBumount \fIspecial\fR \fBumount \fIname\fR
.br .br
.de FL .de FL
.TP .TP
@ -16,8 +16,13 @@ umount \- unmount a mounted file system
.. ..
.SH EXAMPLES .SH EXAMPLES
.EX "umount /dev/fd1" "Unmount diskette 1" .EX "umount /dev/fd1" "Unmount diskette 1"
.EX "umount /mnt" "Unmount the file system mounted on /mnt"
.SH DESCRIPTION .SH DESCRIPTION
.PP .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 mounted file system is unmounted after the cache has been flushed to disk.
A diskette should never be removed while it is mounted. A diskette should never be removed while it is mounted.
If this happens, and is discovered before another diskette is inserted, the If this happens, and is discovered before another diskette is inserted, the

View file

@ -27,12 +27,18 @@ is a directory, then
.I name .I name
must also be a directory. must also be a directory.
.I Special .I Special
must be a block special file, except for loopback mounts. For loopback must be a block special file, or a NULL pointer.
mounts a normal file or directory is used for If a NULL pointer is passed, the file system is
.IR special , mounted without a block device.
which must be seen as the root of a virtual device. .I Mountflags
.I Flag may be a bitwise combination of the following flags:
is 0 for a read-write mount, 1 for read-only. .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 .I Type
is the type of the file system (e.g. "mfs"), used to pick a file system server. 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. If this parameter is NULL, the default type is used.

View file

@ -4,6 +4,8 @@
#define NR_MNTS 8 /* # slots in mount table */ #define NR_MNTS 8 /* # slots in mount table */
#define NR_VNODES 512 /* # slots in vnode table */ #define NR_VNODES 512 /* # slots in vnode table */
#define NR_NONEDEVS NR_MNTS /* # slots in nonedev bitmap */
/* Miscellaneous constants */ /* Miscellaneous constants */
#define SU_UID ((uid_t) 0) /* super_user's uid_t */ #define SU_UID ((uid_t) 0) /* super_user's uid_t */
#define SERVERS_UID ((uid_t) 11) /* who may do FSSIGNON */ #define SERVERS_UID ((uid_t) 11) /* who may do FSSIGNON */
@ -33,6 +35,11 @@
#define ROOT_INODE 1 /* inode number for root directory */ #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 */ /* Args to dev_io */
#define VFS_DEV_READ 2001 #define VFS_DEV_READ 2001
#define VFS_DEV_WRITE 2002 #define VFS_DEV_WRITE 2002

View file

@ -65,7 +65,7 @@ PUBLIC int do_mapdriver()
unsigned long tasknr; unsigned long tasknr;
vir_bytes label_vir; vir_bytes label_vir;
size_t label_len; size_t label_len;
char label[16]; char label[LABEL_MAX];
if (!super_user) if (!super_user)
{ {

View file

@ -20,7 +20,7 @@ extern struct dmap {
int _PROTOTYPE ((*dmap_io), (int, message *) ); int _PROTOTYPE ((*dmap_io), (int, message *) );
endpoint_t dmap_driver; endpoint_t dmap_driver;
int dmap_flags; int dmap_flags;
char dmap_label[16]; char dmap_label[LABEL_MAX];
int dmap_async_driver; int dmap_async_driver;
struct filp *dmap_sel_filp; struct filp *dmap_sel_filp;
} dmap[]; } dmap[];

View file

@ -24,7 +24,6 @@ PRIVATE struct {
int g_who_p; /* slot number of caller process */ int g_who_p; /* slot number of caller process */
int g_call_nr; /* call number */ int g_call_nr; /* call number */
int g_super_user; /* is the caller root? */ 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 */ char g_user_fullpath[PATH_MAX+1]; /* path to look up */
} globals[MAX_DEPTH]; } globals[MAX_DEPTH];
@ -56,7 +55,6 @@ PRIVATE int push_globals()
globals[depth].g_who_p = who_p; globals[depth].g_who_p = who_p;
globals[depth].g_call_nr = call_nr; globals[depth].g_call_nr = call_nr;
globals[depth].g_super_user = super_user; globals[depth].g_super_user = super_user;
globals[depth].g_cum_path_processed = cum_path_processed;
/* XXX is it safe to strcpy this? */ /* XXX is it safe to strcpy this? */
assert(sizeof(globals[0].g_user_fullpath) == sizeof(user_fullpath)); 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; who_p = globals[depth].g_who_p;
call_nr = globals[depth].g_call_nr; call_nr = globals[depth].g_call_nr;
super_user = globals[depth].g_super_user; 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)); memcpy(user_fullpath, globals[depth].g_user_fullpath, sizeof(user_fullpath));
} }

View file

@ -22,10 +22,12 @@ EXTERN message m_in; /* the input message itself */
EXTERN message m_out; /* the output message used for reply */ EXTERN message m_out; /* the output message used for reply */
EXTERN int who_p, who_e; /* caller's proc number, endpoint */ EXTERN int who_p, who_e; /* caller's proc number, endpoint */
EXTERN int call_nr; /* system call number */ 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 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. */ /* The following variables are used for returning results to the caller. */
EXTERN int err_code; /* temporary storage for error number */ EXTERN int err_code; /* temporary storage for error number */

View file

@ -517,6 +517,7 @@ PRIVATE void init_root()
/* Root directory is not mounted on a vnode. */ /* Root directory is not mounted on a vnode. */
vmp->m_mounted_on = NULL; vmp->m_mounted_on = NULL;
vmp->m_root_node = root_node; vmp->m_root_node = root_node;
strcpy(vmp->m_label, "fs_imgrd"); /* FIXME: obtain this from RS */
} }
/*===========================================================================* /*===========================================================================*

View file

@ -293,7 +293,7 @@ PRIVATE void unmount_all(void)
/* Unmount at least one. */ /* Unmount at least one. */
for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) { for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) {
if (vmp->m_dev != NO_DEV) if (vmp->m_dev != NO_DEV)
unmount(vmp->m_dev); unmount(vmp->m_dev, NULL);
} }
} }
} }

View file

@ -1,8 +1,10 @@
/* This file performs the MOUNT and UMOUNT system calls. /* This file performs the MOUNT and UMOUNT system calls.
* *
* The entry points into this file are * The entry points into this file are
* do_fslogin: perform the FSLOGIN system call
* do_mount: perform the MOUNT system call * do_mount: perform the MOUNT system call
* do_umount: perform the UMOUNT system call * do_umount: perform the UMOUNT system call
* unmount: unmount a file system
*/ */
#include "fs.h" #include "fs.h"
@ -14,8 +16,11 @@
#include <minix/const.h> #include <minix/const.h>
#include <minix/endpoint.h> #include <minix/endpoint.h>
#include <minix/syslib.h> #include <minix/syslib.h>
#include <minix/bitmap.h>
#include <minix/ds.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/mount.h>
#include <dirent.h> #include <dirent.h>
#include "file.h" #include "file.h"
#include "fproc.h" #include "fproc.h"
@ -27,9 +32,16 @@
/* Allow the root to be replaced before the first 'real' mount. */ /* Allow the root to be replaced before the first 'real' mount. */
PRIVATE int allow_newroot = 1; PRIVATE int allow_newroot = 1;
FORWARD _PROTOTYPE( dev_t name_to_dev, (void) ); /* Bitmap of in-use "none" pseudo devices. */
FORWARD _PROTOTYPE( int mount_fs, (endpoint_t fs_e) ); 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 * * do_fslogin *
@ -39,7 +51,7 @@ PUBLIC int do_fslogin()
int r; int r;
/* Login before mount request */ /* 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; last_login_fs_e = who_e;
r = SUSPEND; r = SUSPEND;
} }
@ -58,7 +70,7 @@ PUBLIC int do_fslogin()
fp = &fproc[who_p]; /* pointer to proc table struct */ fp = &fproc[who_p]; /* pointer to proc table struct */
super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); /* su? */ super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); /* su? */
r = do_mount(); r = mount_fs(mount_fs_e);
} }
return(r); return(r);
} }
@ -69,13 +81,30 @@ PUBLIC int do_fslogin()
*===========================================================================*/ *===========================================================================*/
PUBLIC int do_mount() PUBLIC int do_mount()
{ {
endpoint_t fs_e; u32_t fs_e;
int r, proc_nr;
/* Only the super-user may do MOUNT. */ /* Only the super-user may do MOUNT. */
if (!super_user) return(EPERM); if (!super_user) return(EPERM);
/* FS process' endpoint number */ /* 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. */ /* Sanity check on process number. */
if(fs_e <= 0) { if(fs_e <= 0) {
@ -93,9 +122,9 @@ PUBLIC int do_mount()
*===========================================================================*/ *===========================================================================*/
PRIVATE int mount_fs(endpoint_t fs_e) 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 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 fproc *tfp;
struct dmap *dp; struct dmap *dp;
dev_t dev; dev_t dev;
@ -111,18 +140,36 @@ PRIVATE int mount_fs(endpoint_t fs_e)
/* If FS not yet logged in, save message and suspend mount */ /* If FS not yet logged in, save message and suspend mount */
if (last_login_fs_e != fs_e) { 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); 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; last_login_fs_e = NONE;
/* Clear endpoint field */ /* Clear endpoint field */
mount_m_in.fs_endpt = (char *) NONE; 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 '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 (fetch_name(m_in.name1, m_in.name1_length, M1) != OK)
if ((dev = name_to_dev()) == NO_DEV) return(err_code); 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 /* Check whether there is a block special file open which uses the
* same device (partition) */ * same device (partition) */
@ -158,24 +205,13 @@ PRIVATE int mount_fs(endpoint_t fs_e)
/* Partition was/is already mounted */ /* Partition was/is already mounted */
if (found) { if (found) {
/* It is possible that we have an old root lying around that /* It is possible that we have an old root lying around that
* needs to be remounted. */ * needs to be remounted. This could for example be a boot
if(vmp->m_mounted_on || vmp->m_mounted_on == fproc[FS_PROC_NR].fp_rd) { * ramdisk that has already been replaced by the real root.
/* 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 */ 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. */ /* 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 (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); 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. */ /* Nothing else can go wrong. Perform the mount. */
vmp->m_mounted_on = vp; vmp->m_mounted_on = vp;
vmp->m_flags = m_in.rd_only; vmp->m_flags = rdonly;
strcpy(vmp->m_label, mount_label);
allow_newroot = 0; /* The root is now fixed */ allow_newroot = 0; /* The root is now fixed */
if (nodev) alloc_nonedev(dev); /* Make the allocation final */
return(OK); 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 */ /* We'll need a vnode for the root inode, check whether there is one */
if ((root_node = get_free_vnode()) == NIL_VNODE) return(ENFILE); if ((root_node = get_free_vnode()) == NIL_VNODE) {
if (vp != NIL_VNODE) put_vnode(vp);
return(ENFILE);
}
label = "";
if (!nodev) {
/* Get driver process' endpoint */ /* Get driver process' endpoint */
dp = &dmap[(dev >> MAJOR) & BYTE]; dp = &dmap[(dev >> MAJOR) & BYTE];
if (dp->dmap_driver == NONE) { if (dp->dmap_driver == NONE) {
printf("VFS: no driver for dev %x\n", dev); printf("VFS: no driver for dev %x\n", dev);
if (vp != NIL_VNODE) put_vnode(vp);
return(EINVAL); return(EINVAL);
} }
label = dp->dmap_label; label = dp->dmap_label;
if (strlen(label) == 0) if (strlen(label) == 0)
panic(__FILE__, "VFS mount_fs: no label for major", dev >> MAJOR); panic(__FILE__, "VFS mount_fs: no label for major",
dev >> MAJOR);
}
/* Tell FS which device to mount */ /* 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); if (vp != NIL_VNODE) put_vnode(vp);
return(r); return(r);
} }
@ -257,7 +303,7 @@ PRIVATE int mount_fs(endpoint_t fs_e)
/* Fill in max file size and blocksize for the vmnt */ /* Fill in max file size and blocksize for the vmnt */
vmp->m_fs_e = res.fs_e; vmp->m_fs_e = res.fs_e;
vmp->m_dev = dev; vmp->m_dev = dev;
vmp->m_flags = m_in.rd_only; vmp->m_flags = rdonly;
/* Root node is indeed on the partition */ /* Root node is indeed on the partition */
root_node->v_vmnt = vmp; 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. */ * Nothing else can go wrong. Perform the mount. */
vmp->m_root_node = root_node; vmp->m_root_node = root_node;
vmp->m_mounted_on = NULL; vmp->m_mounted_on = NULL;
strcpy(vmp->m_label, mount_label);
if (nodev) alloc_nonedev(dev);
root_dev = dev; root_dev = dev;
ROOT_FS_E = fs_e; ROOT_FS_E = fs_e;
@ -291,11 +339,9 @@ PRIVATE int mount_fs(endpoint_t fs_e)
} }
/* File types may not conflict. */ /* File types may not conflict. */
if (r == OK) {
mdir = ((vp->v_mode & I_TYPE) == I_DIRECTORY); /*TRUE iff dir*/ mdir = ((vp->v_mode & I_TYPE) == I_DIRECTORY); /*TRUE iff dir*/
rdir = ((root_node->v_mode & I_TYPE) == I_DIRECTORY); rdir = ((root_node->v_mode & I_TYPE) == I_DIRECTORY);
if (!mdir && rdir) r = EISDIR; if (!mdir && rdir) r = EISDIR;
}
/* If error, return the super block and both inodes; release the vmnt. */ /* If error, return the super block and both inodes; release the vmnt. */
if (r != OK) { if (r != OK) {
@ -308,10 +354,14 @@ PRIVATE int mount_fs(endpoint_t fs_e)
/* Nothing else can go wrong. Perform the mount. */ /* Nothing else can go wrong. Perform the mount. */
vmp->m_mounted_on = vp; vmp->m_mounted_on = vp;
vmp->m_root_node = root_node; vmp->m_root_node = root_node;
strcpy(vmp->m_label, mount_label);
/* The root is now fixed */ /* 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 /* There was a block spec file open, and it should be handled by the
* new FS proc now */ * new FS proc now */
if (bspec) bspec->v_bfs_e = fs_e; if (bspec) bspec->v_bfs_e = fs_e;
@ -326,23 +376,35 @@ PRIVATE int mount_fs(endpoint_t fs_e)
PUBLIC int do_umount() PUBLIC int do_umount()
{ {
/* Perform the umount(name) system call. */ /* Perform the umount(name) system call. */
char label[LABEL_MAX];
dev_t dev; dev_t dev;
int r;
/* Only the super-user may do umount. */ /* Only the super-user may do umount. */
if (!super_user) return(EPERM); 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(fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code);
if((dev = name_to_dev()) == NO_DEV) return(err_code); if((dev = name_to_dev(TRUE /*allow_mountpt*/)) == NO_DEV) return(err_code);
return unmount(dev);
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 * * unmount *
*===========================================================================*/ *===========================================================================*/
PUBLIC int unmount(dev) PUBLIC int unmount(dev, label)
Dev_t dev; Dev_t dev; /* block-special device */
char *label; /* buffer to retrieve label, or NULL */
{ {
struct vnode *vp, *vi; struct vnode *vp, *vi;
struct vmnt *vmp_i = NULL, *vmp = NULL; struct vmnt *vmp_i = NULL, *vmp = NULL;
@ -384,6 +446,12 @@ Dev_t dev;
if ((r = req_unmount(vmp->m_fs_e)) != OK) /* Not recoverable. */ if ((r = req_unmount(vmp->m_fs_e)) != OK) /* Not recoverable. */
printf("VFS: ignoring failed umount attempt (%d)\n", r); 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_ref_count = 0;
vmp->m_root_node->v_fs_count = 0; vmp->m_root_node->v_fs_count = 0;
vmp->m_root_node->v_sdev = NO_DEV; vmp->m_root_node->v_sdev = NO_DEV;
@ -421,27 +489,63 @@ Dev_t dev;
/*===========================================================================* /*===========================================================================*
* name_to_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' /* Convert the block special file in 'user_fullpath' to a device number.
* is not a block special file, return error code in 'err_code'. */ * 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; int r;
dev_t dev; dev_t dev;
struct vnode *vp; struct vnode *vp;
/* Request lookup */ /* Request lookup */
if ((vp = eat_path(PATH_NOFLAGS)) == NIL_VNODE) { if ((vp = eat_path(PATH_NOFLAGS)) == NIL_VNODE) {
printf("VFS: name_to_dev: lookup of '%s' failed\n", user_fullpath);
return(NO_DEV); 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; err_code = ENOTBLK;
dev = NO_DEV; dev = NO_DEV;
} else }
dev = vp->v_sdev;
put_vnode(vp); put_vnode(vp);
return(dev); 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;
}

View file

@ -31,11 +31,12 @@
#define dev_nr m4_l3 #define dev_nr m4_l3
#define dev_style m4_l4 #define dev_style m4_l4
#define m_force m4_l5 #define m_force m4_l5
#define rd_only m1_i3 #define mount_flags m1_i3
#define request m1_i2 #define request m1_i2
#define sig m1_i2 #define sig m1_i2
#define endpt1 m1_i1 #define endpt1 m1_i1
#define fs_endpt m1_p3 #define fs_label m1_p3
#define umount_label m3_ca1
#define tp m2_l1 #define tp m2_l1
#define utime_actime m2_l1 #define utime_actime m2_l1
#define utime_modtime m2_l2 #define utime_modtime m2_l2

View file

@ -94,7 +94,7 @@ _PROTOTYPE( int do_vm_mmap, (void) );
_PROTOTYPE( int do_fslogin, (void) ); _PROTOTYPE( int do_fslogin, (void) );
_PROTOTYPE( int do_mount, (void) ); _PROTOTYPE( int do_mount, (void) );
_PROTOTYPE( int do_umount, (void) ); _PROTOTYPE( int do_umount, (void) );
_PROTOTYPE( int unmount, (Dev_t dev) ); _PROTOTYPE( int unmount, (Dev_t dev, char *label) );
/* open.c */ /* open.c */
_PROTOTYPE( int do_close, (void) ); _PROTOTYPE( int do_close, (void) );

View file

@ -4,8 +4,9 @@ EXTERN struct vmnt {
int m_fs_e; /* FS process' kernel endpoint */ int m_fs_e; /* FS process' kernel endpoint */
dev_t m_dev; /* device number */ dev_t m_dev; /* device number */
int m_flags; /* mount flags */ 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 */ struct vnode *m_root_node; /* root vnode */
char m_label[LABEL_MAX]; /* label of the file system process */
} vmnt[NR_MNTS]; } vmnt[NR_MNTS];
#define NIL_VMNT (struct vmnt *) 0 #define NIL_VMNT (struct vmnt *) 0