Add a new mount flag MNT_BYFSID that can be used to unmount a file

system by specifying the file system ID instead of a path. Use this
by default in umount(8). This avoids the need to perform any vnode
operations to look up the mount point, so it makes it possible to
unmount a file system whose root vnode cannot be looked up (e.g.
due to a dead NFS server, or a file system that has become detached
from the hierarchy because an underlying file system was unmounted).
It also provides an unambiguous way to specify which file system is
to be unmunted.

Since the ability to unmount using a path name is retained only for
compatibility, that case now just uses a simple string comparison
of the supplied path against f_mntonname of each mounted file system.

Discussed on:	freebsd-arch
mdoc help from:	ru
This commit is contained in:
Ian Dowse 2003-07-01 17:40:23 +00:00
parent 9c3f1b326f
commit 318f2fb4bf
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=117132
4 changed files with 122 additions and 99 deletions

View File

@ -32,7 +32,7 @@
.\" @(#)mount.2 8.3 (Berkeley) 5/24/95
.\" $FreeBSD$
.\"
.Dd June 30, 2003
.Dd July 1, 2003
.Dt MOUNT 2
.Os
.Sh NAME
@ -183,6 +183,22 @@ even if files are still active.
Active special devices continue to work,
but any further accesses to any other active files result in errors
even if the file system is later remounted.
.Pp
If the
.Dv MNT_BYFSID
flag is specified,
.Fa dir
should instead be a file system ID encoded as
.Dq Li FSID : Ns Ar val0 : Ns Ar val1 ,
where
.Ar val0
and
.Ar val1
are the contents of the
.Vt fsid_t
.Va val[]
array in decimal.
The file system that has the specified file system ID will be unmounted.
.Sh RETURN VALUES
.Rv -std
.Sh ERRORS

View File

@ -54,6 +54,7 @@ static const char rcsid[] =
#include <nfs/rpcv2.h>
#include <err.h>
#include <errno.h>
#include <fstab.h>
#include <stdio.h>
#include <stdlib.h>
@ -72,10 +73,10 @@ struct addrinfo *nfshost_ai = NULL;
int fflag, vflag;
char *nfshost;
void checkmntlist (char *, char **, char **, char **);
struct statfs *checkmntlist (char *, char **);
int checkvfsname (const char *, char **);
char *getmntname (const char *, const char *,
mntwhat, char **, dowhat);
struct statfs *getmntentry (const char *, const char *, mntwhat, char **,
dowhat);
char *getrealname(char *, char *resolved_path);
char **makevfslist (const char *);
size_t mntinfo (struct statfs **);
@ -83,7 +84,7 @@ int namematch (struct addrinfo *);
int sacmp (struct sockaddr *, struct sockaddr *);
int umountall (char **);
int checkname (char *, char **);
int umountfs (char *, char *, char *);
int umountfs (char *, char *, fsid_t *, char *);
void usage (void);
int xdr_dir (XDR *, char *);
@ -92,8 +93,8 @@ main(int argc, char *argv[])
{
int all, errs, ch, mntsize, error;
char **typelist = NULL, *mntonname, *mntfromname;
char *type, *mntfromnamerev, *mntonnamerev;
struct statfs *mntbuf;
char *type;
struct statfs *mntbuf, *sfsrev;
struct addrinfo hints;
/* Start disks transferring immediately. */
@ -166,18 +167,16 @@ main(int argc, char *argv[])
*/
mntonname = mntbuf[mntsize].f_mntonname;
mntfromname = mntbuf[mntsize].f_mntfromname;
mntonnamerev = getmntname(getmntname(mntonname,
NULL, MNTFROM, &type, NAME), NULL,
MNTON, &type, NAME);
mntfromnamerev = getmntname(mntonnamerev,
NULL, MNTFROM, &type, NAME);
sfsrev = getmntentry(mntonname, NULL, MNTON, &type,
NAME);
if (strcmp(mntonnamerev, mntonname) == 0 &&
strcmp(mntfromnamerev, mntfromname ) != 0)
if (!fflag && bcmp(&sfsrev->f_fsid,
&mntbuf[mntsize].f_fsid, sizeof(fsid_t)) != 0) {
warnx("cannot umount %s, %s\n "
"is mounted there, umount it first",
mntonname, mntfromnamerev);
mntonname, sfsrev->f_mntfromname);
}
if (checkname(mntbuf[mntsize].f_mntonname,
typelist) != 0)
@ -196,7 +195,7 @@ main(int argc, char *argv[])
errs = 1;
break;
}
(void)getmntname(NULL, NULL, NOTHING, NULL, FREE);
(void)getmntentry(NULL, NULL, NOTHING, NULL, FREE);
exit(errs);
}
@ -258,29 +257,29 @@ checkname(char *name, char **typelist)
{
size_t len;
int speclen;
char *mntonname, *mntfromname;
char *mntfromnamerev;
char *resolved, realname[MAXPATHLEN];
char *type, *hostp, *delimp, *origname;
struct statfs *sfs, *sfsrev;
len = 0;
mntfromname = mntonname = delimp = hostp = NULL;
delimp = hostp = NULL;
sfs = NULL;
/*
* 1. Check if the name exists in the mounttable.
*/
(void)checkmntlist(name, &mntfromname, &mntonname, &type);
sfs = checkmntlist(name, &type);
/*
* 2. Remove trailing slashes if there are any. After that
* we look up the name in the mounttable again.
*/
if (mntfromname == NULL && mntonname == NULL) {
if (sfs == NULL) {
speclen = strlen(name);
for (speclen = strlen(name);
speclen > 1 && name[speclen - 1] == '/';
speclen--)
name[speclen - 1] = '\0';
(void)checkmntlist(name, &mntfromname, &mntonname, &type);
sfs = checkmntlist(name, &type);
resolved = name;
/* Save off original name in origname */
if ((origname = strdup(name)) == NULL)
@ -290,7 +289,7 @@ checkname(char *name, char **typelist)
* has been used and translate it to the ':' syntax.
* Look up the name in the mounttable again.
*/
if (mntfromname == NULL && mntonname == NULL) {
if (sfs == NULL) {
if ((delimp = strrchr(name, '@')) != NULL) {
hostp = delimp + 1;
if (*hostp != '\0') {
@ -313,8 +312,7 @@ checkname(char *name, char **typelist)
speclen--)
name[speclen - 1] = '\0';
name[len + speclen + 1] = '\0';
(void)checkmntlist(name, &mntfromname,
&mntonname, &type);
sfs = checkmntlist(name, &type);
resolved = name;
}
/*
@ -325,11 +323,10 @@ checkname(char *name, char **typelist)
* basedir of mountpoint and add the dirname again.
* Check the name in mounttable one last time.
*/
if (mntfromname == NULL && mntonname == NULL) {
if (sfs == NULL) {
(void)strcpy(name, origname);
if ((getrealname(name, realname)) != NULL) {
(void)checkmntlist(realname,
&mntfromname, &mntonname, &type);
sfs = checkmntlist(realname, &type);
resolved = realname;
}
/*
@ -343,9 +340,9 @@ checkname(char *name, char **typelist)
* fstat structure get's more reliable,
* but at the moment we cannot thrust it.
*/
if (mntfromname == NULL && mntonname == NULL) {
if (sfs == NULL) {
(void)strcpy(name, origname);
if (umountfs(NULL, origname,
if (umountfs(NULL, origname, NULL,
"none") == 0) {;
warnx("%s not found in "
"mount table, "
@ -370,38 +367,37 @@ checkname(char *name, char **typelist)
* Check if the reverse entrys of the mounttable are really the
* same as the normal ones.
*/
if ((mntfromnamerev = strdup(getmntname(getmntname(mntfromname,
NULL, MNTON, &type, NAME), NULL, MNTFROM, &type, NAME))) == NULL)
err(1, "strdup");
sfsrev = getmntentry(sfs->f_mntonname, NULL, MNTON, &type, NAME);
/*
* Mark the uppermost mount as unmounted.
*/
(void)getmntname(mntfromname, mntonname, NOTHING, &type, MARK);
(void)getmntentry(sfs->f_mntfromname, sfs->f_mntonname, NOTHING, &type,
MARK);
/*
* If several equal mounts are in the mounttable, check the order
* and warn the user if necessary.
*/
if (strcmp(mntfromnamerev, mntfromname ) != 0 &&
strcmp(resolved, mntonname) != 0) {
if (fflag != MNT_FORCE && sfsrev != sfs) {
warnx("cannot umount %s, %s\n "
"is mounted there, umount it first",
mntonname, mntfromnamerev);
sfs->f_mntonname, sfsrev->f_mntfromname);
/* call getmntname again to set mntcheck[i] to 0 */
(void)getmntname(mntfromname, mntonname,
/* call getmntentry again to set mntcheck[i] to 0 */
(void)getmntentry(sfs->f_mntfromname, sfs->f_mntonname,
NOTHING, &type, UNMARK);
return (1);
}
free(mntfromnamerev);
return (umountfs(mntfromname, mntonname, type));
return (umountfs(sfs->f_mntfromname, sfs->f_mntonname, &sfs->f_fsid,
type));
}
/*
* NFS stuff and unmount(2) call
*/
int
umountfs(char *mntfromname, char *mntonname, char *type)
umountfs(char *mntfromname, char *mntonname, fsid_t *fsid, char *type)
{
char fsidbuf[64];
enum clnt_stat clnt_stat;
struct timeval try;
struct addrinfo *ai, hints;
@ -439,14 +435,27 @@ umountfs(char *mntfromname, char *mntonname, char *type)
* A non-NULL return means that this is the last
* mount from mntfromname that is still mounted.
*/
if (getmntname(mntfromname, NULL, NOTHING, &type, COUNT)
!= NULL)
if (getmntentry(mntfromname, NULL, NOTHING, &type, COUNT)
!= NULL)
do_rpc = 1;
}
if (!namematch(ai))
return (1);
if (unmount(mntonname, fflag) != 0 ) {
/* First try to unmount using the specified file system ID. */
if (fsid != NULL) {
snprintf(fsidbuf, sizeof(fsidbuf), "FSID:%d:%d", fsid->val[0],
fsid->val[1]);
if (unmount(fsidbuf, fflag | MNT_BYFSID) != 0) {
warn("unmount of %s failed", mntonname);
if (errno != ENOENT)
return (1);
/* Compatability for old kernels. */
warnx("retrying using path instead of file system ID");
fsid = NULL;
}
}
if (fsid == NULL && unmount(mntonname, fflag) != 0) {
warn("unmount of %s failed", mntonname);
return (1);
}
@ -490,9 +499,9 @@ umountfs(char *mntfromname, char *mntonname, char *type)
return (0);
}
char *
getmntname(const char *fromname, const char *onname,
mntwhat what, char **type, dowhat mark)
struct statfs *
getmntentry(const char *fromname, const char *onname, mntwhat what,
char **type, dowhat mark)
{
static struct statfs *mntbuf;
static size_t mntsize = 0;
@ -523,21 +532,15 @@ getmntname(const char *fromname, const char *onname,
case NAME:
/* Return only the specific name */
for (i = mntsize - 1; i >= 0; i--) {
if (fromname != NULL && what == MNTON &&
!strcmp(mntbuf[i].f_mntfromname, fromname) &&
mntcheck[i] != 1) {
if (fromname != NULL && !strcmp((what == MNTFROM) ?
mntbuf[i].f_mntfromname : mntbuf[i].f_mntonname,
fromname) && mntcheck[i] != 1) {
if (type)
*type = mntbuf[i].f_fstypename;
return (mntbuf[i].f_mntonname);
}
if (fromname != NULL && what == MNTFROM &&
!strcmp(mntbuf[i].f_mntonname, fromname) &&
mntcheck[i] != 1) {
if (type)
*type = mntbuf[i].f_fstypename;
return (mntbuf[i].f_mntfromname);
return (&mntbuf[i]);
}
}
return (NULL);
case MARK:
/* Mark current mount with '1' and return name */
@ -546,7 +549,7 @@ getmntname(const char *fromname, const char *onname,
(strcmp(mntbuf[i].f_mntonname, onname) == 0) &&
(strcmp(mntbuf[i].f_mntfromname, fromname) == 0)) {
mntcheck[i] = 1;
return (mntbuf[i].f_mntonname);
return (&mntbuf[i]);
}
}
return (NULL);
@ -557,7 +560,7 @@ getmntname(const char *fromname, const char *onname,
(strcmp(mntbuf[i].f_mntonname, onname) == 0) &&
(strcmp(mntbuf[i].f_mntfromname, fromname) == 0)) {
mntcheck[i] = 0;
return (mntbuf[i].f_mntonname);
return (&mntbuf[i]);
}
}
return (NULL);
@ -582,7 +585,7 @@ getmntname(const char *fromname, const char *onname,
}
}
if (count <= 1)
return (mntbuf[i].f_mntonname);
return (&mntbuf[i]);
else
return (NULL);
case FREE:
@ -646,17 +649,15 @@ namematch(struct addrinfo *ai)
return (0);
}
void
checkmntlist(char *name, char **fromname, char **onname, char **type)
struct statfs *
checkmntlist(char *name, char **type)
{
struct statfs *sfs;
*fromname = getmntname(name, NULL, MNTFROM, type, NAME);
if (*fromname == NULL) {
*onname = getmntname(name, NULL, MNTON, type, NAME);
if (*onname != NULL)
*fromname = name;
} else
*onname = name;
sfs = getmntentry(name, NULL, MNTON, type, NAME);
if (sfs == NULL)
sfs = getmntentry(name, NULL, MNTFROM, type, NAME);
return (sfs);
}
size_t

View File

@ -1224,17 +1224,39 @@ unmount(td, uap)
int flags;
} */ *uap;
{
register struct vnode *vp;
struct mount *mp;
int error;
struct nameidata nd;
char *pathbuf;
int error, id0, id1;
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, td);
if ((error = namei(&nd)) != 0)
pathbuf = malloc(MNAMELEN, M_TEMP, M_WAITOK);
error = copyinstr(uap->path, pathbuf, MNAMELEN, NULL);
if (error) {
free(pathbuf, M_TEMP);
return (error);
vp = nd.ni_vp;
NDFREE(&nd, NDF_ONLY_PNBUF);
mp = vp->v_mount;
}
if (uap->flags & MNT_BYFSID) {
/* Decode the filesystem ID. */
if (sscanf(pathbuf, "FSID:%d:%d", &id0, &id1) != 2) {
free(pathbuf, M_TEMP);
return (EINVAL);
}
mtx_lock(&mountlist_mtx);
TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list)
if (mp->mnt_stat.f_fsid.val[0] == id0 &&
mp->mnt_stat.f_fsid.val[1] == id1)
break;
mtx_unlock(&mountlist_mtx);
} else {
mtx_lock(&mountlist_mtx);
TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list)
if (strcmp(mp->mnt_stat.f_mntonname, pathbuf) == 0)
break;
mtx_unlock(&mountlist_mtx);
}
free(pathbuf, M_TEMP);
if (mp == NULL)
return (ENOENT);
/*
* Only root, or the user that did the original mount is
@ -1242,28 +1264,15 @@ unmount(td, uap)
*/
if (mp->mnt_cred->cr_uid != td->td_ucred->cr_uid) {
error = suser(td);
if (error) {
vput(vp);
if (error)
return (error);
}
}
/*
* Don't allow unmounting the root filesystem.
*/
if (mp->mnt_flag & MNT_ROOTFS) {
vput(vp);
if (mp->mnt_flag & MNT_ROOTFS)
return (EINVAL);
}
/*
* Must be the root of the filesystem
*/
if ((vp->v_vflag & VV_ROOT) == 0) {
vput(vp);
return (EINVAL);
}
vput(vp);
return (dounmount(mp, uap->flags, td));
}

View File

@ -224,12 +224,9 @@ struct mount {
#define MNT_RELOAD 0x00040000 /* reload filesystem data */
#define MNT_FORCE 0x00080000 /* force unmount or readonly change */
#define MNT_SNAPSHOT 0x01000000 /* snapshot the filesystem */
#define MNT_BYFSID 0x08000000 /* specify filesystem by ID. */
#define MNT_CMDFLAGS (MNT_UPDATE | MNT_DELEXPORT | MNT_RELOAD | \
MNT_FORCE | MNT_SNAPSHOT)
/*
* Still available
*/
#define MNT_SPARE3 0x08000000
MNT_FORCE | MNT_SNAPSHOT | MNT_BYFSID)
/*
* Internal filesystem control flags stored in mnt_kern_flag.
*