From owner-svn-src-all@freebsd.org Fri Jan 17 14:42:27 2020 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 125021F0114; Fri, 17 Jan 2020 14:42:27 +0000 (UTC) (envelope-from mjg@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 47zkLB6qprz4YcJ; Fri, 17 Jan 2020 14:42:26 +0000 (UTC) (envelope-from mjg@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id E5CB5A516; Fri, 17 Jan 2020 14:42:26 +0000 (UTC) (envelope-from mjg@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 00HEgQHi066820; Fri, 17 Jan 2020 14:42:26 GMT (envelope-from mjg@FreeBSD.org) Received: (from mjg@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 00HEgPo2066815; Fri, 17 Jan 2020 14:42:25 GMT (envelope-from mjg@FreeBSD.org) Message-Id: <202001171442.00HEgPo2066815@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: mjg set sender to mjg@FreeBSD.org using -f From: Mateusz Guzik Date: Fri, 17 Jan 2020 14:42:25 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r356830 - in head: lib/libc/gen lib/libc/sys sys/fs/unionfs sys/kern sys/sys X-SVN-Group: head X-SVN-Commit-Author: mjg X-SVN-Commit-Paths: in head: lib/libc/gen lib/libc/sys sys/fs/unionfs sys/kern sys/sys X-SVN-Commit-Revision: 356830 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 17 Jan 2020 14:42:27 -0000 Author: mjg Date: Fri Jan 17 14:42:25 2020 New Revision: 356830 URL: https://svnweb.freebsd.org/changeset/base/356830 Log: vfs: provide F_ISUNIONSTACK as a kludge for libc Prior to introduction of this op libc's readdir would call fstatfs(2), in effect unnecessarily copying kilobytes of data just to check fs name and a mount flag. Reviewed by: kib (previous version) Differential Revision: https://reviews.freebsd.org/D23162 Modified: head/lib/libc/gen/opendir.c head/lib/libc/sys/fcntl.2 head/sys/fs/unionfs/union_vfsops.c head/sys/kern/kern_descrip.c head/sys/sys/fcntl.h head/sys/sys/mount.h Modified: head/lib/libc/gen/opendir.c ============================================================================== --- head/lib/libc/gen/opendir.c Fri Jan 17 14:40:09 2020 (r356829) +++ head/lib/libc/gen/opendir.c Fri Jan 17 14:42:25 2020 (r356830) @@ -273,7 +273,25 @@ _filldir(DIR *dirp, bool use_current_pos) return (true); } +static bool +is_unionstack(int fd) +{ + struct statfs sfb; + int unionstack; + unionstack = _fcntl(fd, F_ISUNIONSTACK); + if (unionstack != -1) + return (unionstack); + + /* + * Temporary compat for kernels which don't provide F_ISUNIONSTACK. + */ + if (_fstatfs(fd, &sfb) < 0) + return (true); + return (strcmp(sfb.f_fstypename, "unionfs") == 0 || + (sfb.f_flags & MNT_UNION)); +} + /* * Common routine for opendir(3), __opendir2(3) and fdopendir(3). */ @@ -312,12 +330,7 @@ __opendir_common(int fd, int flags, bool use_current_p */ unionstack = false; if (flags & DTF_NODUP) { - struct statfs sfb; - - if (_fstatfs(fd, &sfb) == 0) { - unionstack = strcmp(sfb.f_fstypename, "unionfs") == 0 || - (sfb.f_flags & MNT_UNION); - } + unionstack = is_unionstack(fd); } if (unionstack) { Modified: head/lib/libc/sys/fcntl.2 ============================================================================== --- head/lib/libc/sys/fcntl.2 Fri Jan 17 14:40:09 2020 (r356829) +++ head/lib/libc/sys/fcntl.2 Fri Jan 17 14:42:25 2020 (r356830) @@ -28,7 +28,7 @@ .\" @(#)fcntl.2 8.2 (Berkeley) 1/12/94 .\" $FreeBSD$ .\" -.Dd September 4, 2019 +.Dd January 17, 2020 .Dt FCNTL 2 .Os .Sh NAME @@ -185,6 +185,11 @@ Add seals to the file as described below, if the under seals. .It Dv F_GET_SEALS Get seals associated with the file, if the underlying filesystem supports seals. +.It Dv F_ISUNIONSTACK +Check if the vnode is part of a union stack (either the "union" flag from +.Xr mount 2 +or unionfs). +This is a hack not intended to be used outside of libc. .El .Pp The flags for the Modified: head/sys/fs/unionfs/union_vfsops.c ============================================================================== --- head/sys/fs/unionfs/union_vfsops.c Fri Jan 17 14:40:09 2020 (r356829) +++ head/sys/fs/unionfs/union_vfsops.c Fri Jan 17 14:42:25 2020 (r356830) @@ -296,7 +296,7 @@ unionfs_domount(struct mount *mp) if ((ump->um_lowervp->v_mount->mnt_flag & MNT_LOCAL) && (ump->um_uppervp->v_mount->mnt_flag & MNT_LOCAL)) mp->mnt_flag |= MNT_LOCAL; - mp->mnt_kern_flag |= MNTK_NOMSYNC; + mp->mnt_kern_flag |= MNTK_NOMSYNC | MNTK_UNIONFS; MNT_IUNLOCK(mp); /* Modified: head/sys/kern/kern_descrip.c ============================================================================== --- head/sys/kern/kern_descrip.c Fri Jan 17 14:40:09 2020 (r356829) +++ head/sys/kern/kern_descrip.c Fri Jan 17 14:42:25 2020 (r356830) @@ -489,6 +489,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_ struct filedescent *fde; struct proc *p; struct vnode *vp; + struct mount *mp; int error, flg, seals, tmp; uint64_t bsize; off_t foffset; @@ -813,6 +814,49 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_ atomic_clear_int(&fp->f_flag, FRDAHEAD); } VOP_UNLOCK(vp); + fdrop(fp, td); + break; + + case F_ISUNIONSTACK: + /* + * Check if the vnode is part of a union stack (either the + * "union" flag from mount(2) or unionfs). + * + * Prior to introduction of this op libc's readdir would call + * fstatfs(2), in effect unnecessarily copying kilobytes of + * data just to check fs name and a mount flag. + * + * Fixing the code to handle everything in the kernel instead + * is a non-trivial endeavor and has low priority, thus this + * horrible kludge facilitates the current behavior in a much + * cheaper manner until someone(tm) sorts this out. + */ + error = fget_unlocked(fdp, fd, &cap_no_rights, &fp, NULL); + if (error != 0) + break; + if (fp->f_type != DTYPE_VNODE) { + fdrop(fp, td); + error = EBADF; + break; + } + vp = fp->f_vnode; + /* + * Since we don't prevent dooming the vnode even non-null mp + * found can become immediately stale. This is tolerable since + * mount points are type-stable (providing safe memory access) + * and any vfs op on this vnode going forward will return an + * error (meaning return value in this case is meaningless). + */ + mp = (struct mount *)atomic_load_ptr(&vp->v_mount); + if (__predict_false(mp == NULL)) { + fdrop(fp, td); + error = EBADF; + break; + } + td->td_retval[0] = 0; + if (mp->mnt_kern_flag & MNTK_UNIONFS || + mp->mnt_flag & MNT_UNION) + td->td_retval[0] = 1; fdrop(fp, td); break; Modified: head/sys/sys/fcntl.h ============================================================================== --- head/sys/sys/fcntl.h Fri Jan 17 14:40:09 2020 (r356829) +++ head/sys/sys/fcntl.h Fri Jan 17 14:42:25 2020 (r356830) @@ -250,6 +250,7 @@ typedef __pid_t pid_t; #define F_DUP2FD_CLOEXEC 18 /* Like F_DUP2FD, but FD_CLOEXEC is set */ #define F_ADD_SEALS 19 #define F_GET_SEALS 20 +#define F_ISUNIONSTACK 21 /* Kludge for libc, don't use it. */ /* Seals (F_ADD_SEALS, F_GET_SEALS). */ #define F_SEAL_SEAL 0x0001 /* Prevent adding sealings */ Modified: head/sys/sys/mount.h ============================================================================== --- head/sys/sys/mount.h Fri Jan 17 14:40:09 2020 (r356829) +++ head/sys/sys/mount.h Fri Jan 17 14:42:25 2020 (r356830) @@ -414,6 +414,7 @@ void __mnt_vnode_markerfree_lazy(struct vnode #define MNTK_USES_BCACHE 0x00004000 /* FS uses the buffer cache. */ #define MNTK_TEXT_REFS 0x00008000 /* Keep use ref for text */ #define MNTK_VMSETSIZE_BUG 0x00010000 +#define MNTK_UNIONFS 0x00020000 /* A hack for F_ISUNIONSTACK */ #define MNTK_NOASYNC 0x00800000 /* disable async */ #define MNTK_UNMOUNT 0x01000000 /* unmount in progress */ #define MNTK_MWAIT 0x02000000 /* waiting for unmount to finish */