Page MenuHomeFreeBSD

D21458.id61427.diff
No OneTemporary

D21458.id61427.diff

Index: lib/libc/sys/mount.2
===================================================================
--- lib/libc/sys/mount.2
+++ lib/libc/sys/mount.2
@@ -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: sbin/mount/mntopts.h
===================================================================
--- sbin/mount/mntopts.h
+++ 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: sbin/mount/mount.8
===================================================================
--- sbin/mount/mount.8
+++ sbin/mount/mount.8
@@ -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: sbin/mount/mount.c
===================================================================
--- sbin/mount/mount.c
+++ 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: sys/kern/vfs_mount.c
===================================================================
--- sys/kern/vfs_mount.c
+++ sys/kern/vfs_mount.c
@@ -711,6 +711,16 @@
else if (strcmp(opt->name, "automounted") == 0) {
fsflags |= MNT_AUTOMOUNTED;
vfs_freeopt(optlist, opt);
+ } else if (strcmp(opt->name, "nocover") == 0) {
+ /*
+ * This is handled below, so we don't pass it
+ * down to the filesystem-specific code.
+ */
+ fsflags |= MNT_NOCOVER;
+ vfs_freeopt(optlist, opt);
+ } else if (strcmp(opt->name, "emptydir") == 0) {
+ fsflags |= MNT_EMPTYDIR;
+ vfs_freeopt(optlist, opt);
}
}
@@ -847,6 +857,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, td);
+ if (error) {
+ vput(vp);
+ return (error);
+ }
+ }
+
/*
* If the jail of the calling thread lacks permission for this type of
* file system, deny immediately.
@@ -1126,6 +1144,8 @@
char *pathbuf;
int error;
+// printf("%s(%p, %s, %s, %#lx, %p)\n", __FUNCTION__, td, fstype, fspath, fsflags, optlist);
+
/*
* Be ultra-paranoid about making sure the type and fspath
* variables will fit in our mp buffers, including the
@@ -1183,6 +1203,12 @@
NDFREE(&nd, NDF_ONLY_PNBUF);
vp = nd.ni_vp;
if ((fsflags & MNT_UPDATE) == 0) {
+ if ((vp->v_vflag & VV_ROOT) &&
+ (fsflags & MNT_NOCOVER)) {
+ vput(vp);
+ error = EBUSY;
+ return (error);
+ }
pathbuf = malloc(MNAMELEN, M_TEMP, M_WAITOK);
strcpy(pathbuf, fspath);
error = vn_path_to_global_path(td, vp, pathbuf, MNAMELEN);
Index: sys/kern/vfs_subr.c
===================================================================
--- sys/kern/vfs_subr.c
+++ sys/kern/vfs_subr.c
@@ -5344,6 +5344,92 @@
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 thread *td)
+{
+ struct uio uio;
+ struct ucred *cred = td->td_ucred;
+ struct iovec iov;
+ struct dirent *dirent, *dp, *endp;
+ int error = 0;
+ int eof = 0;
+ int dolock = 0;
+
+ dirent = malloc(sizeof(struct dirent), M_TEMP, M_WAITOK);
+ endp = (void*)((uint8_t*)dirent + sizeof(struct dirent));
+ iov.iov_base = dirent;
+ iov.iov_len = sizeof(struct dirent);
+
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = 0; // Start at the beginning
+ uio.uio_resid = sizeof(struct dirent);
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_rw = UIO_READ;
+ uio.uio_td = curthread;
+
+
+ if (VOP_ISLOCKED(vp) == 0) {
+ dolock = 1;
+ vn_lock(vp, LK_SHARED | LK_RETRY);
+ }
+
+ while (eof == 0) {
+ error = VOP_READDIR(vp, &uio, cred, &eof, NULL, NULL);
+ if (error == 0) {
+ 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;
+ goto done;
+ }
+ if (dp->d_namlen > 2) {
+ error = ENOTEMPTY;
+ goto done;
+ }
+ if (dp->d_namlen == 1 &&
+ dp->d_name[0] != '.') {
+ error = ENOTEMPTY;
+ goto done;
+ }
+ if (dp->d_namlen == 2 &&
+ dp->d_name[1] != '.') {
+ error = ENOTEMPTY;
+ goto done;
+ }
+ }
+ uio.uio_resid = sizeof(struct dirent);
+ } else {
+ printf("%s(%d): Error = %d\n", __FUNCTION__, __LINE__, error);
+ break;
+ }
+ }
+ /* If we got here, there were no other entries */
+ error = 0;
+done:
+ if (dirent)
+ free(dirent, M_TEMP);
+ if (dolock)
+ VOP_UNLOCK(vp, LK_SHARED | LK_RETRY);
+ return (error);
+}
+
int
vfs_read_dirent(struct vop_readdir_args *ap, struct dirent *dp, off_t off)
{
Index: sys/sys/mount.h
===================================================================
--- sys/sys/mount.h
+++ sys/sys/mount.h
@@ -366,9 +366,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: sys/sys/vnode.h
===================================================================
--- sys/sys/vnode.h
+++ sys/sys/vnode.h
@@ -922,6 +922,8 @@
struct dirent;
int vfs_read_dirent(struct vop_readdir_args *ap, struct dirent *dp, off_t off);
+int vfs_emptydir(struct vnode *vp, struct thread *td);
+
int vfs_unixify_accmode(accmode_t *accmode);
void vfs_unp_reclaim(struct vnode *vp);

File Metadata

Mime Type
text/plain
Expires
Fri, May 22, 10:42 PM (22 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33433121
Default Alt Text
D21458.id61427.diff (8 KB)

Event Timeline