The branch main has been updated by mjg:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=eaad8d1303da500ed691bd774742a4555a05e729

commit eaad8d1303da500ed691bd774742a4555a05e729
Author:     Mateusz Guzik <[email protected]>
AuthorDate: 2021-01-28 23:27:44 +0000
Commit:     Mateusz Guzik <[email protected]>
CommitDate: 2021-01-29 11:23:43 +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.
---
 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 *
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to