From: David van Moolenbroek Date: Tue, 12 Jan 2010 23:08:50 +0000 (+0000) Subject: Mount updates: X-Git-Tag: v3.1.6~91 X-Git-Url: http://zhaoyanbai.com/repos/Bv9ARM.ch13.html?a=commitdiff_plain;h=b31119abf5dd71c40db625c808e6d689533d58ba;p=minix.git 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 --- diff --git a/commands/simple/mount.c b/commands/simple/mount.c index fb8d84b6e..abbd533e0 100644 --- a/commands/simple/mount.c +++ b/commands/simple/mount.c @@ -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)); -} diff --git a/commands/simple/umount.c b/commands/simple/umount.c index 893a4c4eb..bf2fe1c6f 100644 --- a/commands/simple/umount.c +++ b/commands/simple/umount.c @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include #include @@ -17,55 +17,85 @@ #include _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)); -} diff --git a/include/minix/dmap.h b/include/minix/dmap.h index 7559bdc4a..11598ad84 100644 --- a/include/minix/dmap.h +++ b/include/minix/dmap.h @@ -11,7 +11,11 @@ enum dev_style { STYLE_DEV, STYLE_NDEV, STYLE_TTY, STYLE_CLONE }; *===========================================================================*/ /* Total number of different devices. */ -#define NR_DEVICES 32 /* number of (major) devices */ +#define NR_DEVICES 32 /* number of (major) devices */ + +#define NONE_MAJOR 0 /* pseudo device for mounting file + * systems without a real block device + */ /* Major and minor device numbers for MEMORY driver. */ #define MEMORY_MAJOR 1 /* major device for memory devices */ diff --git a/include/minix/ipc.h b/include/minix/ipc.h index dd3c08414..9bb459e91 100644 --- a/include/minix/ipc.h +++ b/include/minix/ipc.h @@ -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; diff --git a/include/sys/mount.h b/include/sys/mount.h index 10d48c687..bee73a8ff 100644 --- a/include/sys/mount.h +++ b/include/sys/mount.h @@ -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. */ diff --git a/lib/other/_mount.c b/lib/other/_mount.c index 7a668f14c..5d930ae91 100644 --- a/lib/other/_mount.c +++ b/lib/other/_mount.c @@ -25,40 +25,17 @@ PRIVATE int rs_down(char *label) return system(cmd); } -PRIVATE char *makelabel(_CONST char *special) -{ - static char label[40]; - _CONST char *dev; - - /* Make label name. */ - dev = strrchr(special, '/'); - if(dev) dev++; - else dev = special; - if(strchr(dev, '\'') != NULL) { - errno = EINVAL; - return NULL; - } - if(strlen(dev)+4 >= sizeof(label)) { - errno = E2BIG; - return NULL; - } - sprintf(label, "fs_%s", dev); - return label; -} - PUBLIC int mount(special, name, mountflags, type, args) char *name, *special, *type, *args; int mountflags; { int r; message m; - struct rs_start rs_start; struct stat statbuf; - char *label; + char label[16]; char path[60]; char cmd[200]; - FILE *pipe; - int ep; + char *p; int reuse; /* Default values. */ @@ -68,15 +45,33 @@ int mountflags; /* Check mount flags */ if(mountflags & MS_REUSE) { - reuse = 1; - mountflags &= ~MS_REUSE; /* Temporary: turn off to not confuse VFS */ + reuse = 1; + mountflags &= ~MS_REUSE; /* Temporary: turn off to not confuse VFS */ } - /* Make FS process label for RS from special name. */ - if(!(label=makelabel(special))) { - return -1; + /* Make a label for the file system process. This label must be unique and + * may currently not exceed 16 characters including terminating null. For + * requests with an associated block device, we use the last path component + * name of the block special file (truncated to 12 characters, which is + * hopefully enough). For requests with no associated block device, we use + * the device number and inode of the mount point, in hexadecimal form. + */ + if (special) { + p = strrchr(special, '/'); + p = p ? p + 1 : special; + if (strchr(p, '\'')) { + errno = EINVAL; + return -1; + } + sprintf(label, "fs_%.12s", p); + } else { + if (stat(name, &statbuf) < 0) return -1; + sprintf(label, "fs_%04x%x", statbuf.st_dev, statbuf.st_ino); } + /* Tell VFS that we are passing in a 16-byte label. */ + mountflags |= MS_LABEL16; + /* See if the given type is even remotely valid. */ if(strlen(FSPATH)+strlen(type) >= sizeof(path)) { errno = E2BIG; @@ -102,32 +97,23 @@ int mountflags; return -1; } - - sprintf(cmd, _PATH_SERVICE " %sup %s -label '%s' -config " _PATH_SYSTEM_CONF - " -args '%s%s' -printep yes", + " -args '%s%s'", reuse ? "-r ": "", path, label, args[0] ? "-o " : "", args); - if(!(pipe = popen(cmd, "r"))) { + if((r = system(cmd)) != 0) { fprintf(stderr, "mount: couldn't run %s\n", cmd); + errno = r; return -1; } - if(fscanf(pipe, "%d", &ep) != 1 || ep <= 0) { - fprintf(stderr, "mount: couldn't parse endpoint from %s\n", cmd); - errno = EINVAL; - pclose(pipe); - return -1; - } - pclose(pipe); - /* Now perform mount(). */ - m.m1_i1 = strlen(special) + 1; + m.m1_i1 = special ? strlen(special) + 1 : 0; m.m1_i2 = strlen(name) + 1; m.m1_i3 = mountflags; m.m1_p1 = special; m.m1_p2 = name; - m.m1_p3 = (char*) ep; + m.m1_p3 = label; r = _syscall(FS, MOUNT, &m); if(r != OK) { @@ -144,19 +130,16 @@ PUBLIC int umount(name) _CONST char *name; { message m; - char *label; int r; - /* Make MFS process label for RS from special name. */ - if(!(label=makelabel(name))) { - return -1; - } - _loadname(name, &m); r = _syscall(FS, UMOUNT, &m); if(r == OK) { - rs_down(label); + /* VFS returns the label of the unmounted file system in the reply. + * As of writing, the size of the m3_ca1 field is 16 bytes. + */ + rs_down(m.m3_ca1); } return r; diff --git a/lib/other/loadname.c b/lib/other/loadname.c index 1329b2674..77ff26ce5 100644 --- a/lib/other/loadname.c +++ b/lib/other/loadname.c @@ -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); } diff --git a/man/man1/mount.1 b/man/man1/mount.1 index a811adae0..937a4e8a0 100644 --- a/man/man1/mount.1 +++ b/man/man1/mount.1 @@ -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), diff --git a/man/man1/umount.1 b/man/man1/umount.1 index f082d610d..6b83e733a 100644 --- a/man/man1/umount.1 +++ b/man/man1/umount.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 diff --git a/man/man2/mount.2 b/man/man2/mount.2 index 2a03e3dc2..7d7036e49 100644 --- a/man/man2/mount.2 +++ b/man/man2/mount.2 @@ -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. diff --git a/servers/vfs/const.h b/servers/vfs/const.h index b4a0b07fb..2ad3bf882 100644 --- a/servers/vfs/const.h +++ b/servers/vfs/const.h @@ -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 diff --git a/servers/vfs/dmap.c b/servers/vfs/dmap.c index 0dea2da5f..14a6be497 100644 --- a/servers/vfs/dmap.c +++ b/servers/vfs/dmap.c @@ -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) { diff --git a/servers/vfs/dmap.h b/servers/vfs/dmap.h index 883f115bb..9ed775ddd 100644 --- a/servers/vfs/dmap.h +++ b/servers/vfs/dmap.h @@ -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[]; diff --git a/servers/vfs/fscall.c b/servers/vfs/fscall.c index e3c3462e0..9550585a7 100644 --- a/servers/vfs/fscall.c +++ b/servers/vfs/fscall.c @@ -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)); } diff --git a/servers/vfs/glo.h b/servers/vfs/glo.h index 27731b9b2..3a56399fe 100644 --- a/servers/vfs/glo.h +++ b/servers/vfs/glo.h @@ -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 */ diff --git a/servers/vfs/main.c b/servers/vfs/main.c index 1d7431f9d..4508025d6 100644 --- a/servers/vfs/main.c +++ b/servers/vfs/main.c @@ -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 */ } /*===========================================================================* diff --git a/servers/vfs/misc.c b/servers/vfs/misc.c index a2805cb38..4178f736a 100644 --- a/servers/vfs/misc.c +++ b/servers/vfs/misc.c @@ -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); } } } diff --git a/servers/vfs/mount.c b/servers/vfs/mount.c index 3d6725fb9..bb9e19ef2 100644 --- a/servers/vfs/mount.c +++ b/servers/vfs/mount.c @@ -1,8 +1,10 @@ /* This file performs the MOUNT and UMOUNT system calls. * * The entry points into this file are - * do_mount: perform the MOUNT system call - * do_umount: perform the UMOUNT system call + * do_fslogin: perform the FSLOGIN system call + * do_mount: perform the MOUNT system call + * do_umount: perform the UMOUNT system call + * unmount: unmount a file system */ #include "fs.h" @@ -14,8 +16,11 @@ #include #include #include +#include +#include #include #include +#include #include #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; @@ -110,19 +139,37 @@ PRIVATE int mount_fs(endpoint_t fs_e) /* If FS not yet logged in, save message and suspend mount */ if (last_login_fs_e != fs_e) { - mount_m_in = m_in; + mount_m_in = m_in; + mount_fs_e = fs_e; + /* mount_label is already saved */ return(SUSPEND); } - /* Mount request got after FS login or FS login arrived after a suspended mount */ + /* Mount request got after FS login or FS login arrived after a suspended + * mount. + */ last_login_fs_e = NONE; /* Clear endpoint field */ - mount_m_in.fs_endpt = (char *) NONE; - - /* If 'name' is not for a block special file, return error. */ - if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((dev = name_to_dev()) == NO_DEV) return(err_code); + mount_fs_e = NONE; + + /* Should the file system be mounted read-only? */ + rdonly = (m_in.mount_flags & MS_RDONLY); + + /* A null string for block special device means don't use a device at all. */ + nodev = (m_in.name1_length == 0); + + if (!nodev) { + /* If 'name' is not for a block special file, return error. */ + if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) + return(err_code); + if ((dev = name_to_dev(FALSE /*allow_mountpt*/)) == NO_DEV) + return(err_code); + } else { + /* Find a free pseudo-device as substitute for an actual device. */ + if ((dev = find_free_nonedev()) == NO_DEV) + return(err_code); + } /* Check whether there is a block special file open which uses the * same device (partition) */ @@ -158,24 +205,13 @@ PRIVATE int mount_fs(endpoint_t fs_e) /* Partition was/is already mounted */ if (found) { /* It is possible that we have an old root lying around that - * needs to be remounted. */ - if(vmp->m_mounted_on || vmp->m_mounted_on == fproc[FS_PROC_NR].fp_rd) { - /* Normally, m_mounted_on refers to the mount point. For a - * root filesystem, m_mounted_on is equal to the root vnode. - * We assume that the root of FS is always the real root. If - * the two vnodes are different or if the root of FS is equal - * to the root of the filesystem we found, we found a - * filesystem that is in use. - */ - return(EBUSY); /* already mounted */ + * needs to be remounted. This could for example be a boot + * ramdisk that has already been replaced by the real root. + */ + if(vmp->m_mounted_on || root_dev == vmp->m_dev) { + return(EBUSY); /* not a root or still mounted */ } - - if(vmp->m_mounted_on) - panic("vfs", "root unexpectedly mounted somewhere", NO_NUM); - - if (root_dev == vmp->m_dev) - panic("vfs", "inconsistency remounting old root", NO_NUM); - + /* Now get the inode of the file to be mounted on. */ if (fetch_name(m_in.name2, m_in.name2_length, M1)!=OK) return(err_code); if ((vp = eat_path(PATH_NOFLAGS)) == NIL_VNODE) return(err_code); @@ -201,8 +237,10 @@ PRIVATE int mount_fs(endpoint_t fs_e) /* Nothing else can go wrong. Perform the mount. */ vmp->m_mounted_on = vp; - vmp->m_flags = m_in.rd_only; - allow_newroot = 0; /* The root is now fixed */ + vmp->m_flags = rdonly; + strcpy(vmp->m_label, mount_label); + allow_newroot = 0; /* The root is now fixed */ + if (nodev) alloc_nonedev(dev); /* Make the allocation final */ return(OK); } @@ -224,21 +262,29 @@ PRIVATE int mount_fs(endpoint_t fs_e) } /* We'll need a vnode for the root inode, check whether there is one */ - if ((root_node = get_free_vnode()) == NIL_VNODE) return(ENFILE); - - /* Get driver process' endpoint */ - dp = &dmap[(dev >> MAJOR) & BYTE]; - if (dp->dmap_driver == NONE) { - printf("VFS: no driver for dev %x\n", dev); - return(EINVAL); + if ((root_node = get_free_vnode()) == NIL_VNODE) { + if (vp != NIL_VNODE) put_vnode(vp); + return(ENFILE); } - label = dp->dmap_label; - if (strlen(label) == 0) - panic(__FILE__, "VFS mount_fs: no label for major", dev >> MAJOR); + label = ""; + if (!nodev) { + /* Get driver process' endpoint */ + dp = &dmap[(dev >> MAJOR) & BYTE]; + if (dp->dmap_driver == NONE) { + printf("VFS: no driver for dev %x\n", dev); + if (vp != NIL_VNODE) put_vnode(vp); + return(EINVAL); + } + + label = dp->dmap_label; + if (strlen(label) == 0) + panic(__FILE__, "VFS mount_fs: no label for major", + dev >> MAJOR); + } /* Tell FS which device to mount */ - if ((r = req_readsuper(fs_e, label, dev, m_in.rd_only, isroot, &res)) != OK){ + if ((r = req_readsuper(fs_e, label, dev, rdonly, isroot, &res)) != OK) { if (vp != NIL_VNODE) put_vnode(vp); return(r); } @@ -257,7 +303,7 @@ PRIVATE int mount_fs(endpoint_t fs_e) /* Fill in max file size and blocksize for the vmnt */ vmp->m_fs_e = res.fs_e; vmp->m_dev = dev; - vmp->m_flags = m_in.rd_only; + vmp->m_flags = rdonly; /* Root node is indeed on the partition */ root_node->v_vmnt = vmp; @@ -268,6 +314,8 @@ PRIVATE int mount_fs(endpoint_t fs_e) * Nothing else can go wrong. Perform the mount. */ vmp->m_root_node = root_node; vmp->m_mounted_on = NULL; + strcpy(vmp->m_label, mount_label); + if (nodev) alloc_nonedev(dev); root_dev = dev; ROOT_FS_E = fs_e; @@ -291,11 +339,9 @@ PRIVATE int mount_fs(endpoint_t fs_e) } /* File types may not conflict. */ - if (r == OK) { - mdir = ((vp->v_mode & I_TYPE) == I_DIRECTORY); /*TRUE iff dir*/ - rdir = ((root_node->v_mode & I_TYPE) == I_DIRECTORY); - if (!mdir && rdir) r = EISDIR; - } + mdir = ((vp->v_mode & I_TYPE) == I_DIRECTORY); /*TRUE iff dir*/ + rdir = ((root_node->v_mode & I_TYPE) == I_DIRECTORY); + if (!mdir && rdir) r = EISDIR; /* If error, return the super block and both inodes; release the vmnt. */ if (r != OK) { @@ -308,9 +354,13 @@ PRIVATE int mount_fs(endpoint_t fs_e) /* Nothing else can go wrong. Perform the mount. */ vmp->m_mounted_on = vp; vmp->m_root_node = root_node; + strcpy(vmp->m_label, mount_label); /* The root is now fixed */ - allow_newroot = 0; + allow_newroot = 0; + + /* Allocate the pseudo device that was found, if not using a real device. */ + if (nodev) alloc_nonedev(dev); /* There was a block spec file open, and it should be handled by the * new FS proc now */ @@ -326,23 +376,35 @@ PRIVATE int mount_fs(endpoint_t fs_e) PUBLIC int do_umount() { /* Perform the umount(name) system call. */ + char label[LABEL_MAX]; dev_t dev; + int r; /* Only the super-user may do umount. */ if (!super_user) return(EPERM); - /* If 'name' is not for a block special file, return error. */ + /* If 'name' is not for a block special file or mountpoint, return error. */ if(fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); - if((dev = name_to_dev()) == NO_DEV) return(err_code); - return unmount(dev); + if((dev = name_to_dev(TRUE /*allow_mountpt*/)) == NO_DEV) return(err_code); + + if((r = unmount(dev, label)) != OK) return(r); + + /* Return the label of the mounted file system, so that the caller + * can shut down the corresponding server process. + */ + if (strlen(label) >= M3_LONG_STRING) /* should never evaluate to true */ + label[M3_LONG_STRING-1] = 0; + strcpy(m_out.umount_label, label); + return(OK); } /*===========================================================================* * unmount * *===========================================================================*/ -PUBLIC int unmount(dev) -Dev_t dev; +PUBLIC int unmount(dev, label) +Dev_t dev; /* block-special device */ +char *label; /* buffer to retrieve label, or NULL */ { struct vnode *vp, *vi; struct vmnt *vmp_i = NULL, *vmp = NULL; @@ -371,19 +433,25 @@ Dev_t dev; /* Tell FS to drop all inode references for root inode except 1. */ vnode_clean_refs(vmp->m_root_node); - + if (vmp->m_mounted_on) { put_vnode(vmp->m_mounted_on); vmp->m_mounted_on = NIL_VNODE; } - + /* Tell FS to unmount */ if(vmp->m_fs_e <= 0 || vmp->m_fs_e == NONE) panic(__FILE__, "unmount: strange fs endpoint", vmp->m_fs_e); if ((r = req_unmount(vmp->m_fs_e)) != OK) /* Not recoverable. */ printf("VFS: ignoring failed umount attempt (%d)\n", r); - + + if (is_nonedev(vmp->m_dev)) + free_nonedev(vmp->m_dev); + + if (label != NULL) + strcpy(label, vmp->m_label); + vmp->m_root_node->v_ref_count = 0; vmp->m_root_node->v_fs_count = 0; vmp->m_root_node->v_sdev = NO_DEV; @@ -421,27 +489,63 @@ Dev_t dev; /*===========================================================================* * name_to_dev * *===========================================================================*/ -PRIVATE dev_t name_to_dev() +PRIVATE dev_t name_to_dev(allow_mountpt) +int allow_mountpt; { -/* Convert the block special file 'path' to a device number. If 'path' - * is not a block special file, return error code in 'err_code'. */ +/* Convert the block special file in 'user_fullpath' to a device number. + * If the given path is not a block special file, but 'allow_mountpt' is set + * and the path is the root node of a mounted file system, return that device + * number. In all other cases, return NO_DEV and an error code in 'err_code'. + */ int r; dev_t dev; struct vnode *vp; /* Request lookup */ if ((vp = eat_path(PATH_NOFLAGS)) == NIL_VNODE) { - printf("VFS: name_to_dev: lookup of '%s' failed\n", user_fullpath); return(NO_DEV); } - if ((vp->v_mode & I_TYPE) != I_BLOCK_SPECIAL) { + if ((vp->v_mode & I_TYPE) == I_BLOCK_SPECIAL) { + dev = vp->v_sdev; + } else if (allow_mountpt && vp->v_vmnt->m_root_node == vp) { + dev = vp->v_dev; + } else { err_code = ENOTBLK; dev = NO_DEV; - } else - dev = vp->v_sdev; + } put_vnode(vp); return(dev); } + +/*===========================================================================* + * is_nonedev * + *===========================================================================*/ +PRIVATE int is_nonedev(dev) +{ +/* Return whether the given device is a "none" pseudo device. + */ + + return (major(dev) == NONE_MAJOR && + minor(dev) > 0 && minor(dev) <= NR_NONEDEVS); +} + + +/*===========================================================================* + * find_free_nonedev * + *===========================================================================*/ +PRIVATE dev_t find_free_nonedev() +{ +/* Find a free "none" pseudo device. Do not allocate it yet. + */ + int i; + + for (i = 0; i < NR_NONEDEVS; i++) + if (!GET_BIT(nonedev, i)) + return makedev(NONE_MAJOR, i + 1); + + err_code = EMFILE; + return NO_DEV; +} diff --git a/servers/vfs/param.h b/servers/vfs/param.h index 057b2dfab..58941dae7 100644 --- a/servers/vfs/param.h +++ b/servers/vfs/param.h @@ -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 diff --git a/servers/vfs/proto.h b/servers/vfs/proto.h index d7d5191a3..1d8968e68 100644 --- a/servers/vfs/proto.h +++ b/servers/vfs/proto.h @@ -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) ); diff --git a/servers/vfs/vmnt.h b/servers/vfs/vmnt.h index 598a304da..199f67efc 100644 --- a/servers/vfs/vmnt.h +++ b/servers/vfs/vmnt.h @@ -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