From owner-dev-commits-src-all@freebsd.org Mon Feb 1 12:41:05 2021 Return-Path: Delivered-To: dev-commits-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 391674FEA5B; Mon, 1 Feb 2021 12:41:05 +0000 (UTC) (envelope-from git@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) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4DTncJ5mKDz3DvW; Mon, 1 Feb 2021 12:41:04 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 6D1591B170; Mon, 1 Feb 2021 12:41:00 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 111Cf0cS098357; Mon, 1 Feb 2021 12:41:00 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 111Cf0mm098356; Mon, 1 Feb 2021 12:41:00 GMT (envelope-from git) Date: Mon, 1 Feb 2021 12:41:00 GMT Message-Id: <202102011241.111Cf0mm098356@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Mateusz Guzik Subject: git: 1077e49657fa - stable/13 - fd: add fget_only_user MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: mjg X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: 1077e49657faaae1477a31fd534375e113df2bd4 Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-all@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commit messages for all branches of the src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Feb 2021 12:41:05 -0000 The branch stable/13 has been updated by mjg: URL: https://cgit.FreeBSD.org/src/commit/?id=1077e49657faaae1477a31fd534375e113df2bd4 commit 1077e49657faaae1477a31fd534375e113df2bd4 Author: Mateusz Guzik AuthorDate: 2021-01-28 23:27:44 +0000 Commit: Mateusz Guzik CommitDate: 2021-02-01 12:39:18 +0000 fd: add fget_only_user This can be used by single-threaded processes which don't share a file descriptor table to access their file objects without having to reference them. For example select consumers tend to match the requirement and have several file descriptors to inspect. (cherry picked from commit eaad8d1303da500ed691bd774742a4555a05e729) --- sys/kern/kern_descrip.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++--- sys/sys/filedesc.h | 12 +++++++++ 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 257b1de2a6ac..059e5123c7b5 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -1860,10 +1860,14 @@ fdgrowtable(struct filedesc *fdp, int nfd) * which must not be freed. */ if (onfiles > NDFILE) { - if (curproc->p_numthreads == 1 && - refcount_load(&fdp->fd_refcnt) == 1) + /* + * Note we may be called here from fdinit while allocating a + * table for a new process in which case ->p_fd points + * elsewhere. + */ + if (curproc->p_fd != fdp || FILEDESC_IS_ONLY_USER(fdp)) { free(otable, M_FILEDESC); - else { + } else { ft = (struct freetable *)&otable->fdt_ofiles[onfiles]; fdp0 = (struct filedesc0 *)fdp; ft->ft_table = otable; @@ -3176,6 +3180,66 @@ out_fallback: return (fget_unlocked_seq(fdp, fd, needrightsp, fpp, NULL)); } +/* + * Translate fd -> file when the caller guarantees the file descriptor table + * can't be changed by others. + * + * Note this does not mean the file object itself is only visible to the caller, + * merely that it wont disappear without having to be referenced. + * + * Must be paired with fput_only_user. + */ +#ifdef CAPABILITIES +int +fget_only_user(struct filedesc *fdp, int fd, cap_rights_t *needrightsp, + struct file **fpp) +{ + const struct filedescent *fde; + const struct fdescenttbl *fdt; + const cap_rights_t *haverights; + struct file *fp; + int error; + + MPASS(FILEDESC_IS_ONLY_USER(fdp)); + + if (__predict_false(fd >= fdp->fd_nfiles)) + return (EBADF); + + fdt = fdp->fd_files; + fde = &fdt->fdt_ofiles[fd]; + fp = fde->fde_file; + if (__predict_false(fp == NULL)) + return (EBADF); + MPASS(refcount_load(&fp->f_count) > 0); + haverights = cap_rights_fde_inline(fde); + error = cap_check_inline(haverights, needrightsp); + if (__predict_false(error != 0)) + return (EBADF); + *fpp = fp; + return (0); +} +#else +int +fget_only_user(struct filedesc *fdp, int fd, cap_rights_t *needrightsp, + struct file **fpp) +{ + struct file *fp; + + MPASS(FILEDESC_IS_ONLY_USER(fdp)); + + if (__predict_false(fd >= fdp->fd_nfiles)) + return (EBADF); + + fp = fdp->fd_ofiles[fd].fde_file; + if (__predict_false(fp == NULL)) + return (EBADF); + + MPASS(refcount_load(&fp->f_count) > 0); + *fpp = fp; + return (0); +} +#endif + /* * Extract the file pointer associated with the specified descriptor for the * current user process. diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h index 9b65c7a66054..890232b7f160 100644 --- a/sys/sys/filedesc.h +++ b/sys/sys/filedesc.h @@ -177,6 +177,11 @@ struct filedesc_to_leader { SX_NOTRECURSED) #define FILEDESC_UNLOCK_ASSERT(fdp) sx_assert(&(fdp)->fd_sx, SX_UNLOCKED) +#define FILEDESC_IS_ONLY_USER(fdp) ({ \ + struct filedesc *_fdp = (fdp); \ + MPASS(curproc->p_fd == _fdp); \ + (curproc->p_numthreads == 1 && refcount_load(&_fdp->fd_refcnt) == 1); \ +}) #else /* @@ -272,6 +277,13 @@ int fget_unlocked_seq(struct filedesc *fdp, int fd, cap_rights_t *needrightsp, struct file **fpp, seqc_t *seqp); int fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t *needrightsp, struct file **fpp); +/* Return a file pointer without a ref. FILEDESC_IS_ONLY_USER must be true. */ +int fget_only_user(struct filedesc *fdp, int fd, cap_rights_t *needrightsp, + struct file **fpp); +#define fput_only_user(fdp, fp) ({ \ + MPASS(FILEDESC_IS_ONLY_USER(fdp)); \ + MPASS(refcount_load(&fp->f_count) > 0); \ +}) /* Requires a FILEDESC_{S,X}LOCK held and returns without a ref. */ static __inline struct file *