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:
parent
483160f3d4
commit
b31119abf5
21 changed files with 331 additions and 202 deletions
|
@ -21,14 +21,13 @@
|
|||
_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));
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
@ -17,55 +17,85 @@
|
|||
#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));
|
||||
}
|
||||
|
|
|
@ -13,6 +13,10 @@ 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 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 RAM_DEV_OLD 0 /* minor device for /dev/ram */
|
||||
|
|
|
@ -10,12 +10,13 @@
|
|||
#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;
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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. */
|
||||
|
@ -72,10 +49,28 @@ int mountflags;
|
|||
mountflags &= ~MS_REUSE; /* Temporary: turn off to not confuse VFS */
|
||||
}
|
||||
|
||||
/* Make FS process label for RS from special name. */
|
||||
if(!(label=makelabel(special))) {
|
||||
/* 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)) {
|
||||
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 */
|
||||
|
@ -33,6 +35,11 @@
|
|||
|
||||
#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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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[];
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
/* This file performs the MOUNT and UMOUNT system calls.
|
||||
*
|
||||
* The entry points into this file are
|
||||
* 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"
|
||||
|
@ -14,8 +16,11 @@
|
|||
#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"
|
||||
|
@ -27,9 +32,16 @@
|
|||
/* 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;
|
||||
|
@ -111,18 +140,36 @@ 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_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;
|
||||
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()) == NO_DEV) return(err_code);
|
||||
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.
|
||||
* needs to be remounted. This could for example be a boot
|
||||
* ramdisk that has already been replaced by the real root.
|
||||
*/
|
||||
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. */
|
||||
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;
|
||||
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);
|
||||
if ((root_node = get_free_vnode()) == NIL_VNODE) {
|
||||
if (vp != NIL_VNODE) put_vnode(vp);
|
||||
return(ENFILE);
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
/* If error, return the super block and both inodes; release the vmnt. */
|
||||
if (r != OK) {
|
||||
|
@ -308,10 +354,14 @@ 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;
|
||||
|
||||
/* 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 */
|
||||
if (bspec) bspec->v_bfs_e = fs_e;
|
||||
|
@ -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;
|
||||
|
@ -384,6 +446,12 @@ Dev_t dev;
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -31,11 +31,12 @@
|
|||
#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
|
||||
|
|
|
@ -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) );
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue