aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Certner <olce.freebsd@certner.fr>2023-04-28 09:00:11 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2023-04-28 19:37:35 +0000
commit2544b8e00ca1afea64b00a6ddaf7b584244ade90 (patch)
tree6c1812907abcb8cc2c1c071a693d8f5ed5acf3d0
parentc21d87a88c72804bc4fb86d7b0e8a846230e4ad0 (diff)
downloadsrc-2544b8e00ca1afea64b00a6ddaf7b584244ade90.tar.gz
src-2544b8e00ca1afea64b00a6ddaf7b584244ade90.zip
vfs: Rename vfs_emptydir() to vn_dir_check_empty()
No functional change. While here, adapt comments to style(9). Reviewed by: kib MFC after: 1 week
-rw-r--r--sys/kern/vfs_mount.c2
-rw-r--r--sys/kern/vfs_subr.c90
-rw-r--r--sys/kern/vfs_vnops.c91
-rw-r--r--sys/sys/vnode.h2
4 files changed, 93 insertions, 92 deletions
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c
index bf532df335bf..e7f9eab33158 100644
--- a/sys/kern/vfs_mount.c
+++ b/sys/kern/vfs_mount.c
@@ -1160,7 +1160,7 @@ vfs_domount_first(
error = ENOTDIR;
}
if (error == 0 && (fsflags & MNT_EMPTYDIR) != 0)
- error = vfs_emptydir(vp);
+ error = vn_dir_check_empty(vp);
if (error == 0) {
VI_LOCK(vp);
if ((vp->v_iflag & VI_MOUNT) == 0 && vp->v_mountedhere == NULL)
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 3c783f7326d0..9901a20172a4 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -6382,96 +6382,6 @@ filt_vfsvnode(struct knote *kn, long hint)
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 *const td = curthread;
- char *dirbuf;
- size_t dirbuflen, len;
- off_t off;
- int eofflag, error;
- struct dirent *dp;
- struct vattr va;
-
- ASSERT_VOP_LOCKED(vp, "vfs_emptydir");
- VNPASS(vp->v_type == VDIR, vp);
-
- error = VOP_GETATTR(vp, &va, td->td_ucred);
- if (error != 0)
- return (error);
-
- dirbuflen = max(DEV_BSIZE, GENERIC_MAXDIRSIZ);
- if (dirbuflen < va.va_blocksize)
- dirbuflen = va.va_blocksize;
- dirbuf = malloc(dirbuflen, M_TEMP, M_WAITOK);
-
- len = 0;
- off = 0;
- eofflag = 0;
-
- for (;;) {
- error = vn_dir_next_dirent(vp, td, dirbuf, dirbuflen,
- &dp, &len, &off, &eofflag);
- if (error != 0)
- goto end;
-
- if (len == 0) {
- /* EOF */
- error = 0;
- goto end;
- }
-
- /*
- * Skip whiteouts. Unionfs operates on filesystems only and not
- * on hierarchies, so these whiteouts would be shadowed on the
- * system hierarchy but not for a union using the filesystem of
- * their directories as the upper layer. Additionally, unionfs
- * currently transparently exposes union-specific metadata of
- * its upper layer, meaning that whiteouts can be seen through
- * the union view in empty directories. Taking into account
- * these whiteouts would then prevent mounting another
- * filesystem on such effectively empty directories.
- */
- if (dp->d_type == DT_WHT)
- continue;
-
- /*
- * Any file in the directory which is not '.' or '..' indicates
- * the directory is not empty.
- */
- switch (dp->d_namlen) {
- case 2:
- if (dp->d_name[1] != '.') {
- /* Can't be '..' (nor '.') */
- error = ENOTEMPTY;
- goto end;
- }
- /* FALLTHROUGH */
- case 1:
- if (dp->d_name[0] != '.') {
- /* Can't be '..' nor '.' */
- error = ENOTEMPTY;
- goto end;
- }
- break;
-
- default:
- error = ENOTEMPTY;
- goto end;
- }
- }
-
-end:
- free(dirbuf, M_TEMP);
- return (error);
-}
-
int
vfs_read_dirent(struct vop_readdir_args *ap, struct dirent *dp, off_t off)
{
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index d2b1a9b0570b..33cb3ebed60f 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -3897,6 +3897,97 @@ out:
return (error);
}
+/*
+ * Checks whether a directory is empty or not.
+ *
+ * If the directory is empty, returns 0, and if it is not, ENOTEMPTY. Other
+ * values are genuine errors preventing the check.
+ */
+int
+vn_dir_check_empty(struct vnode *vp)
+{
+ struct thread *const td = curthread;
+ char *dirbuf;
+ size_t dirbuflen, len;
+ off_t off;
+ int eofflag, error;
+ struct dirent *dp;
+ struct vattr va;
+
+ ASSERT_VOP_LOCKED(vp, "vfs_emptydir");
+ VNPASS(vp->v_type == VDIR, vp);
+
+ error = VOP_GETATTR(vp, &va, td->td_ucred);
+ if (error != 0)
+ return (error);
+
+ dirbuflen = max(DEV_BSIZE, GENERIC_MAXDIRSIZ);
+ if (dirbuflen < va.va_blocksize)
+ dirbuflen = va.va_blocksize;
+ dirbuf = malloc(dirbuflen, M_TEMP, M_WAITOK);
+
+ len = 0;
+ off = 0;
+ eofflag = 0;
+
+ for (;;) {
+ error = vn_dir_next_dirent(vp, td, dirbuf, dirbuflen,
+ &dp, &len, &off, &eofflag);
+ if (error != 0)
+ goto end;
+
+ if (len == 0) {
+ /* EOF */
+ error = 0;
+ goto end;
+ }
+
+ /*
+ * Skip whiteouts. Unionfs operates on filesystems only and
+ * not on hierarchies, so these whiteouts would be shadowed on
+ * the system hierarchy but not for a union using the
+ * filesystem of their directories as the upper layer.
+ * Additionally, unionfs currently transparently exposes
+ * union-specific metadata of its upper layer, meaning that
+ * whiteouts can be seen through the union view in empty
+ * directories. Taking into account these whiteouts would then
+ * prevent mounting another filesystem on such effectively
+ * empty directories.
+ */
+ if (dp->d_type == DT_WHT)
+ continue;
+
+ /*
+ * Any file in the directory which is not '.' or '..' indicates
+ * the directory is not empty.
+ */
+ switch (dp->d_namlen) {
+ case 2:
+ if (dp->d_name[1] != '.') {
+ /* Can't be '..' (nor '.') */
+ error = ENOTEMPTY;
+ goto end;
+ }
+ /* FALLTHROUGH */
+ case 1:
+ if (dp->d_name[0] != '.') {
+ /* Can't be '..' nor '.' */
+ error = ENOTEMPTY;
+ goto end;
+ }
+ break;
+
+ default:
+ error = ENOTEMPTY;
+ goto end;
+ }
+ }
+
+end:
+ free(dirbuf, M_TEMP);
+ return (error);
+}
+
static u_long vn_lock_pair_pause_cnt;
SYSCTL_ULONG(_debug, OID_AUTO, vn_lock_pair_pause, CTLFLAG_RD,
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index 8403dd8c035b..7ba95de34b5d 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -1102,8 +1102,8 @@ struct dirent;
int vn_dir_next_dirent(struct vnode *vp, struct thread *td,
char *dirbuf, size_t dirbuflen,
struct dirent **dpp, size_t *len, off_t *off, int *eofflag);
+int vn_dir_check_empty(struct vnode *vp);
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);