Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F132935814
D21458.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D21458.id.diff
View Options
Index: head/lib/libc/sys/mount.2
===================================================================
--- head/lib/libc/sys/mount.2
+++ head/lib/libc/sys/mount.2
@@ -28,7 +28,7 @@
.\" @(#)mount.2 8.3 (Berkeley) 5/24/95
.\" $FreeBSD$
.\"
-.Dd December 1, 2017
+.Dd August 28, 2019
.Dt MOUNT 2
.Os
.Sh NAME
@@ -157,6 +157,10 @@
Disable read clustering.
.It Dv MNT_NOCLUSTERW
Disable write clustering.
+.It Dv MNT_NOCOVER
+Do not mount over the root of another mount point.
+.It Dv MNT_EMPTYDIR
+Require an empty directory for the mount point directory.
.El
.Pp
The flag
@@ -260,6 +264,11 @@
.It Bq Er EBUSY
Another process currently holds a reference to
.Fa dir .
+.It Bq Er EBUSY
+The
+.Dv MNT_NOCOVER
+option was given, and the requested mount point
+is already the root of another mount point.
.It Bq Er EFAULT
The
.Fa dir
@@ -280,6 +289,11 @@
.Fa fspec
argument
is not a block device.
+.It Bq Er ENOTEMPTY
+The
+.Dv MNT_EMPTYDIR
+option was specified, and the requested mount point
+is not an empty directory.
.It Bq Er ENXIO
The major device number of
.Fa fspec
Index: head/sbin/mount/mntopts.h
===================================================================
--- head/sbin/mount/mntopts.h
+++ head/sbin/mount/mntopts.h
@@ -65,7 +65,8 @@
#define MOPT_UPDATE { "update", 0, MNT_UPDATE, 0 }
#define MOPT_RO { "ro", 0, MNT_RDONLY, 0 }
#define MOPT_RW { "rw", 1, MNT_RDONLY, 0 }
-
+#define MOPT_NOCOVER { "cover", 1, MNT_NOCOVER, 0 }
+#define MOPT_EMPTYDIR { "emptydir", 0, MNT_EMPTYDIR, 0 }
/* This is parsed by mount(8), but is ignored by specific mount_*(8)s. */
#define MOPT_AUTO { "auto", 0, 0, 0 }
@@ -95,7 +96,9 @@
MOPT_ACLS, \
MOPT_NFS4ACLS, \
MOPT_AUTOMOUNTED, \
- MOPT_UNTRUSTED
+ MOPT_UNTRUSTED, \
+ MOPT_NOCOVER, \
+ MOPT_EMPTYDIR
void getmntopts(const char *, const struct mntopt *, int *, int *);
void rmslashes(char *, char *);
Index: head/sbin/mount/mount.8
===================================================================
--- head/sbin/mount/mount.8
+++ head/sbin/mount/mount.8
@@ -28,7 +28,7 @@
.\" @(#)mount.8 8.8 (Berkeley) 6/16/94
.\" $FreeBSD$
.\"
-.Dd March 22, 2017
+.Dd August 28, 2019
.Dt MOUNT 8
.Os
.Sh NAME
@@ -162,6 +162,8 @@
.Fl u
flag, this is the same as specifying the options currently in effect for
the mounted file system.
+.It Cm emptydir
+Require that the mount point directory be empty.
.It Cm force
The same as
.Fl f ;
@@ -237,6 +239,9 @@
Disable read clustering.
.It Cm noclusterw
Disable write clustering.
+.It Cm nocover
+Do not mount if the requested mount point is already
+the root of a mount point.
.It Cm noexec
Do not allow execution of any binaries on the mounted file system.
This option is useful for a server that has file systems containing
Index: head/sbin/mount/mount.c
===================================================================
--- head/sbin/mount/mount.c
+++ head/sbin/mount/mount.c
@@ -119,6 +119,8 @@
{ MNT_AUTOMOUNTED, "automounted" },
{ MNT_VERIFIED, "verified" },
{ MNT_UNTRUSTED, "untrusted" },
+ { MNT_NOCOVER, "nocover" },
+ { MNT_EMPTYDIR, "emptydir" },
{ 0, NULL }
};
@@ -975,6 +977,8 @@
if (flags & MNT_ACLS) res = catopt(res, "acls");
if (flags & MNT_NFS4ACLS) res = catopt(res, "nfsv4acls");
if (flags & MNT_UNTRUSTED) res = catopt(res, "untrusted");
+ if (flags & MNT_NOCOVER) res = catopt(res, "nocover");
+ if (flags & MNT_EMPTYDIR) res = catopt(res, "emptydir");
return (res);
}
Index: head/sys/kern/vfs_mount.c
===================================================================
--- head/sys/kern/vfs_mount.c
+++ head/sys/kern/vfs_mount.c
@@ -668,19 +668,21 @@
* when we want to update the root filesystem.
*/
TAILQ_FOREACH_SAFE(opt, optlist, link, tmp_opt) {
+ int do_freeopt = 0;
+
if (strcmp(opt->name, "update") == 0) {
fsflags |= MNT_UPDATE;
- vfs_freeopt(optlist, opt);
+ do_freeopt = 1;
}
else if (strcmp(opt->name, "async") == 0)
fsflags |= MNT_ASYNC;
else if (strcmp(opt->name, "force") == 0) {
fsflags |= MNT_FORCE;
- vfs_freeopt(optlist, opt);
+ do_freeopt = 1;
}
else if (strcmp(opt->name, "reload") == 0) {
fsflags |= MNT_RELOAD;
- vfs_freeopt(optlist, opt);
+ do_freeopt = 1;
}
else if (strcmp(opt->name, "multilabel") == 0)
fsflags |= MNT_MULTILABEL;
@@ -741,7 +743,7 @@
autoro = false;
}
else if (strcmp(opt->name, "autoro") == 0) {
- vfs_freeopt(optlist, opt);
+ do_freeopt = 1;
autoro = true;
}
else if (strcmp(opt->name, "suiddir") == 0)
@@ -752,8 +754,22 @@
fsflags |= MNT_UNION;
else if (strcmp(opt->name, "automounted") == 0) {
fsflags |= MNT_AUTOMOUNTED;
- vfs_freeopt(optlist, opt);
+ do_freeopt = 1;
+ } else if (strcmp(opt->name, "nocover") == 0) {
+ fsflags |= MNT_NOCOVER;
+ do_freeopt = 1;
+ } else if (strcmp(opt->name, "cover") == 0) {
+ fsflags &= ~MNT_NOCOVER;
+ do_freeopt = 1;
+ } else if (strcmp(opt->name, "emptydir") == 0) {
+ fsflags |= MNT_EMPTYDIR;
+ do_freeopt = 1;
+ } else if (strcmp(opt->name, "noemptydir") == 0) {
+ fsflags &= ~MNT_EMPTYDIR;
+ do_freeopt = 1;
}
+ if (do_freeopt)
+ vfs_freeopt(optlist, opt);
}
/*
@@ -889,6 +905,14 @@
ASSERT_VOP_ELOCKED(vp, __func__);
KASSERT((fsflags & MNT_UPDATE) == 0, ("MNT_UPDATE shouldn't be here"));
+ if ((fsflags & MNT_EMPTYDIR) != 0) {
+ error = vfs_emptydir(vp);
+ if (error != 0) {
+ vput(vp);
+ return (error);
+ }
+ }
+
/*
* If the jail of the calling thread lacks permission for this type of
* file system, deny immediately.
@@ -1229,6 +1253,11 @@
NDFREE(&nd, NDF_ONLY_PNBUF);
vp = nd.ni_vp;
if ((fsflags & MNT_UPDATE) == 0) {
+ if ((vp->v_vflag & VV_ROOT) != 0 &&
+ (fsflags & MNT_NOCOVER) != 0) {
+ vput(vp);
+ return (EBUSY);
+ }
pathbuf = malloc(MNAMELEN, M_TEMP, M_WAITOK);
strcpy(pathbuf, fspath);
error = vn_path_to_global_path(td, vp, pathbuf, MNAMELEN);
Index: head/sys/kern/vfs_subr.c
===================================================================
--- head/sys/kern/vfs_subr.c
+++ head/sys/kern/vfs_subr.c
@@ -5535,6 +5535,76 @@
return (res);
}
+/*
+ * Returns whether the directory is empty or not.
+ * If it is empty, the return value is 0; otherwise
+ * the return value is an error value (which may
+ * be ENOTEMPTY).
+ */
+int
+vfs_emptydir(struct vnode *vp)
+{
+ struct uio uio;
+ struct iovec iov;
+ struct dirent *dirent, *dp, *endp;
+ int error, eof;
+
+ error = 0;
+ eof = 0;
+
+ ASSERT_VOP_LOCKED(vp, "vfs_emptydir");
+
+ dirent = malloc(sizeof(struct dirent), M_TEMP, M_WAITOK);
+ iov.iov_base = dirent;
+ iov.iov_len = sizeof(struct dirent);
+
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = 0;
+ uio.uio_resid = sizeof(struct dirent);
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_rw = UIO_READ;
+ uio.uio_td = curthread;
+
+ while (eof == 0 && error == 0) {
+ error = VOP_READDIR(vp, &uio, curthread->td_ucred, &eof,
+ NULL, NULL);
+ if (error != 0)
+ break;
+ endp = (void *)((uint8_t *)dirent +
+ sizeof(struct dirent) - uio.uio_resid);
+ for (dp = dirent; dp < endp;
+ dp = (void *)((uint8_t *)dp + GENERIC_DIRSIZ(dp))) {
+ if (dp->d_type == DT_WHT)
+ continue;
+ if (dp->d_namlen == 0)
+ continue;
+ if (dp->d_type != DT_DIR &&
+ dp->d_type != DT_UNKNOWN) {
+ error = ENOTEMPTY;
+ break;
+ }
+ if (dp->d_namlen > 2) {
+ error = ENOTEMPTY;
+ break;
+ }
+ if (dp->d_namlen == 1 &&
+ dp->d_name[0] != '.') {
+ error = ENOTEMPTY;
+ break;
+ }
+ if (dp->d_namlen == 2 &&
+ dp->d_name[1] != '.') {
+ error = ENOTEMPTY;
+ break;
+ }
+ uio.uio_resid = sizeof(struct dirent);
+ }
+ }
+ free(dirent, M_TEMP);
+ return (error);
+}
+
int
vfs_read_dirent(struct vop_readdir_args *ap, struct dirent *dp, off_t off)
{
Index: head/sys/sys/mount.h
===================================================================
--- head/sys/sys/mount.h
+++ head/sys/sys/mount.h
@@ -373,9 +373,11 @@
#define MNT_SNAPSHOT 0x0000000001000000ULL /* snapshot the filesystem */
#define MNT_NONBUSY 0x0000000004000000ULL /* check vnode use counts. */
#define MNT_BYFSID 0x0000000008000000ULL /* specify filesystem by ID. */
+#define MNT_NOCOVER 0x0000001000000000ULL /* Do not cover a mount point */
+#define MNT_EMPTYDIR 0x0000002000000000ULL /* Only mount on empty dir */
#define MNT_CMDFLAGS (MNT_UPDATE | MNT_DELEXPORT | MNT_RELOAD | \
MNT_FORCE | MNT_SNAPSHOT | MNT_NONBUSY | \
- MNT_BYFSID)
+ MNT_BYFSID | MNT_NOCOVER | MNT_EMPTYDIR)
/*
* Internal filesystem control flags stored in mnt_kern_flag.
*
Index: head/sys/sys/vnode.h
===================================================================
--- head/sys/sys/vnode.h
+++ head/sys/sys/vnode.h
@@ -930,6 +930,7 @@
void vfs_mark_atime(struct vnode *vp, struct ucred *cred);
struct dirent;
int vfs_read_dirent(struct vop_readdir_args *ap, struct dirent *dp, off_t off);
+int vfs_emptydir(struct vnode *vp);
int vfs_unixify_accmode(accmode_t *accmode);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Oct 22, 7:46 AM (3 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24049148
Default Alt Text
D21458.id.diff (8 KB)
Attached To
Mode
D21458: Add mount options to prevent covering
Attached
Detach File
Event Timeline
Log In to Comment