diff options
author | iedowse <iedowse@FreeBSD.org> | 2003-07-01 17:40:23 +0000 |
---|---|---|
committer | iedowse <iedowse@FreeBSD.org> | 2003-07-01 17:40:23 +0000 |
commit | a627a459f84a3abc8e8fb30ee0148fc52b5b3a77 (patch) | |
tree | 1027d5dd057a3d0ef01110534de81d0fc8bb748b | |
parent | 8f11363180f469db6f07c7834bdbc137428e8b06 (diff) | |
download | FreeBSD-src-a627a459f84a3abc8e8fb30ee0148fc52b5b3a77.zip FreeBSD-src-a627a459f84a3abc8e8fb30ee0148fc52b5b3a77.tar.gz |
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
-rw-r--r-- | lib/libc/sys/mount.2 | 18 | ||||
-rw-r--r-- | sbin/umount/umount.c | 141 | ||||
-rw-r--r-- | sys/kern/vfs_mount.c | 55 | ||||
-rw-r--r-- | sys/sys/mount.h | 7 |
4 files changed, 122 insertions, 99 deletions
diff --git a/lib/libc/sys/mount.2 b/lib/libc/sys/mount.2 index 838c1e6..1b551ed 100644 --- a/lib/libc/sys/mount.2 +++ b/lib/libc/sys/mount.2 @@ -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 diff --git a/sbin/umount/umount.c b/sbin/umount/umount.c index 8ffdbce..19e4400 100644 --- a/sbin/umount/umount.c +++ b/sbin/umount/umount.c @@ -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 diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index 02997c3..7d166f0 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -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)); } diff --git a/sys/sys/mount.h b/sys/sys/mount.h index 7c4c471..eed3ed4 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -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. * |