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
This commit is contained in:
parent
c21d87a88c
commit
2544b8e00c
@ -1160,7 +1160,7 @@ vfs_domount_first(
|
|||||||
error = ENOTDIR;
|
error = ENOTDIR;
|
||||||
}
|
}
|
||||||
if (error == 0 && (fsflags & MNT_EMPTYDIR) != 0)
|
if (error == 0 && (fsflags & MNT_EMPTYDIR) != 0)
|
||||||
error = vfs_emptydir(vp);
|
error = vn_dir_check_empty(vp);
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
VI_LOCK(vp);
|
VI_LOCK(vp);
|
||||||
if ((vp->v_iflag & VI_MOUNT) == 0 && vp->v_mountedhere == NULL)
|
if ((vp->v_iflag & VI_MOUNT) == 0 && vp->v_mountedhere == NULL)
|
||||||
|
@ -6382,96 +6382,6 @@ filt_vfsvnode(struct knote *kn, long hint)
|
|||||||
return (res);
|
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
|
int
|
||||||
vfs_read_dirent(struct vop_readdir_args *ap, struct dirent *dp, off_t off)
|
vfs_read_dirent(struct vop_readdir_args *ap, struct dirent *dp, off_t off)
|
||||||
{
|
{
|
||||||
|
@ -3897,6 +3897,97 @@ vn_dir_next_dirent(struct vnode *vp, struct thread *td,
|
|||||||
return (error);
|
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;
|
static u_long vn_lock_pair_pause_cnt;
|
||||||
SYSCTL_ULONG(_debug, OID_AUTO, vn_lock_pair_pause, CTLFLAG_RD,
|
SYSCTL_ULONG(_debug, OID_AUTO, vn_lock_pair_pause, CTLFLAG_RD,
|
||||||
|
@ -1102,8 +1102,8 @@ struct dirent;
|
|||||||
int vn_dir_next_dirent(struct vnode *vp, struct thread *td,
|
int vn_dir_next_dirent(struct vnode *vp, struct thread *td,
|
||||||
char *dirbuf, size_t dirbuflen,
|
char *dirbuf, size_t dirbuflen,
|
||||||
struct dirent **dpp, size_t *len, off_t *off, int *eofflag);
|
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_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);
|
int vfs_unixify_accmode(accmode_t *accmode);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user