git: 62849eef5b57 - main - fd: split fget_unlocked_seq depending on CAPABILITIES
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 11 Feb 2022 13:58:03 UTC
The branch main has been updated by mjg: URL: https://cgit.FreeBSD.org/src/commit/?id=62849eef5b573b9907257f20318f4bd48fcf7b3a commit 62849eef5b573b9907257f20318f4bd48fcf7b3a Author: Mateusz Guzik <mjg@FreeBSD.org> AuthorDate: 2022-02-11 11:54:34 +0000 Commit: Mateusz Guzik <mjg@FreeBSD.org> CommitDate: 2022-02-11 12:27:22 +0000 fd: split fget_unlocked_seq depending on CAPABILITIES This will simplify an upcoming change. --- sys/kern/kern_descrip.c | 81 ++++++++++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 84622e163503..c4f435002907 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -3027,56 +3027,47 @@ fgetvp_lookup_smr(int fd, struct nameidata *ndp, struct vnode **vpp, bool *fsear } #endif +/* + * Fetch the descriptor locklessly. + * + * We avoid fdrop() races by never raising a refcount above 0. To accomplish + * this we have to use a cmpset loop rather than an atomic_add. The descriptor + * must be re-verified once we acquire a reference to be certain that the + * identity is still correct and we did not lose a race due to preemption. + * + * Force a reload of fdt when looping. Another thread could reallocate + * the table before this fd was closed, so it is possible that there is + * a stale fp pointer in cached version. + */ +#ifdef CAPABILITIES static int fget_unlocked_seq(struct filedesc *fdp, int fd, cap_rights_t *needrightsp, struct file **fpp, seqc_t *seqp) { -#ifdef CAPABILITIES const struct filedescent *fde; -#endif const struct fdescenttbl *fdt; struct file *fp; -#ifdef CAPABILITIES seqc_t seq; cap_rights_t haverights; int error; -#endif fdt = fdp->fd_files; if (__predict_false((u_int)fd >= fdt->fdt_nfiles)) return (EBADF); - /* - * Fetch the descriptor locklessly. We avoid fdrop() races by - * never raising a refcount above 0. To accomplish this we have - * to use a cmpset loop rather than an atomic_add. The descriptor - * must be re-verified once we acquire a reference to be certain - * that the identity is still correct and we did not lose a race - * due to preemption. - */ + for (;;) { -#ifdef CAPABILITIES seq = seqc_read_notmodify(fd_seqc(fdt, fd)); fde = &fdt->fdt_ofiles[fd]; haverights = *cap_rights_fde_inline(fde); fp = fde->fde_file; if (!seqc_consistent(fd_seqc(fdt, fd), seq)) continue; -#else - fp = fdt->fdt_ofiles[fd].fde_file; -#endif - if (fp == NULL) + if (__predict_false(fp == NULL)) return (EBADF); -#ifdef CAPABILITIES error = cap_check_inline(&haverights, needrightsp); - if (error != 0) + if (__predict_false(error != 0)) return (error); -#endif if (__predict_false(!refcount_acquire_if_not_zero(&fp->f_count))) { - /* - * Force a reload. Other thread could reallocate the - * table before this fd was closed, so it is possible - * that there is a stale fp pointer in cached version. - */ fdt = atomic_load_ptr(&fdp->fd_files); continue; } @@ -3086,22 +3077,50 @@ fget_unlocked_seq(struct filedesc *fdp, int fd, cap_rights_t *needrightsp, */ atomic_thread_fence_acq(); fdt = fdp->fd_files; -#ifdef CAPABILITIES if (seqc_consistent_nomb(fd_seqc(fdt, fd), seq)) -#else - if (fp == fdt->fdt_ofiles[fd].fde_file) -#endif break; fdrop(fp, curthread); } *fpp = fp; if (seqp != NULL) { -#ifdef CAPABILITIES *seqp = seq; -#endif } return (0); } +#else +static int +fget_unlocked_seq(struct filedesc *fdp, int fd, cap_rights_t *needrightsp, + struct file **fpp, seqc_t *seqp __unused) +{ + const struct fdescenttbl *fdt; + struct file *fp; + + fdt = fdp->fd_files; + if (__predict_false((u_int)fd >= fdt->fdt_nfiles)) + return (EBADF); + + for (;;) { + fp = fdt->fdt_ofiles[fd].fde_file; + if (__predict_false(fp == NULL)) + return (EBADF); + if (__predict_false(!refcount_acquire_if_not_zero(&fp->f_count))) { + fdt = atomic_load_ptr(&fdp->fd_files); + continue; + } + /* + * Use an acquire barrier to force re-reading of fdt so it is + * refreshed for verification. + */ + atomic_thread_fence_acq(); + fdt = fdp->fd_files; + if (__predict_true(fp == fdt->fdt_ofiles[fd].fde_file)) + break; + fdrop(fp, curthread); + } + *fpp = fp; + return (0); +} +#endif /* * See the comments in fget_unlocked_seq for an explanation of how this works.