Index: sys/compat/linuxkpi/common/include/linux/file.h =================================================================== --- sys/compat/linuxkpi/common/include/linux/file.h +++ sys/compat/linuxkpi/common/include/linux/file.h @@ -71,17 +71,24 @@ static inline void fput(struct linux_file *filp) { - if (refcount_release(filp->_file == NULL ? - &filp->f_count : &filp->_file->f_count)) { + refcntlong_t *count; + + count = &filp->f_count; + if (filp->_file != NULL) + count = &filp->_file->f_count; + if (refcntlong_release(count)) linux_file_free(filp); - } } -static inline unsigned int +static inline unsigned long file_count(struct linux_file *filp) { - return (filp->_file == NULL ? - filp->f_count : filp->_file->f_count); + refcntlong_t *count; + + count = &filp->f_count; + if (filp->_file != NULL) + count = &filp->_file->f_count; + return (refcntlong_read(count)); } static inline void @@ -108,6 +115,7 @@ fd_install(unsigned int fd, struct linux_file *filp) { struct file *file; + u_long count; if (fget_unlocked(curthread->td_proc->p_fd, fd, &cap_no_rights, &file, NULL) != 0) { @@ -117,8 +125,8 @@ finit(file, filp->f_mode, DTYPE_DEV, filp, &linuxfileops); /* transfer reference count from "filp" to "file" */ - while (refcount_release(&filp->f_count) == 0) - refcount_acquire(&file->f_count); + count = refcntlong_clear(&file->f_count); + refcntlong_acquiren(&file->f_count, count); } /* drop the extra reference */ Index: sys/compat/linuxkpi/common/include/linux/fs.h =================================================================== --- sys/compat/linuxkpi/common/include/linux/fs.h +++ sys/compat/linuxkpi/common/include/linux/fs.h @@ -92,7 +92,7 @@ struct sigio *f_sigio; struct vnode *f_vnode; #define f_inode f_vnode - volatile u_int f_count; + refcntlong_t f_count; /* anonymous shmem object */ vm_object_t f_shmem; @@ -250,8 +250,12 @@ static inline struct linux_file * get_file(struct linux_file *f) { + refcntlong_t *count; - refcount_acquire(f->_file == NULL ? &f->f_count : &f->_file->f_count); + count = &f->f_count; + if (f->_file != NULL) + count = &f->_file->f_count; + refcntlong_acquire(count); return (f); } Index: sys/compat/linuxkpi/common/src/linux_compat.c =================================================================== --- sys/compat/linuxkpi/common/src/linux_compat.c +++ sys/compat/linuxkpi/common/src/linux_compat.c @@ -448,7 +448,7 @@ filp = kzalloc(sizeof(*filp), GFP_KERNEL); /* set initial refcount */ - filp->f_count = 1; + refcntlong_init(&filp->f_count, 1); /* setup fields needed by kqueue support */ spin_lock_init(&filp->f_kqlock); @@ -1496,7 +1496,7 @@ filp = (struct linux_file *)file->f_data; KASSERT(file_count(filp) == 0, - ("File refcount(%d) is not zero", file_count(filp))); + ("File refcount(%ld) is not zero", file_count(filp))); if (td == NULL) td = curthread; Index: sys/compat/linuxkpi/common/src/linux_page.c =================================================================== --- sys/compat/linuxkpi/common/src/linux_page.c +++ sys/compat/linuxkpi/common/src/linux_page.c @@ -314,7 +314,7 @@ filp = &fileobj->file; vp = &fileobj->vnode; - filp->f_count = 1; + refcntlong_init(&filp->f_count, 1); filp->f_vnode = vp; filp->f_shmem = vm_pager_allocate(OBJT_DEFAULT, NULL, size, VM_PROT_READ | VM_PROT_WRITE, 0, curthread->td_ucred); Index: sys/kern/kern_descrip.c =================================================================== --- sys/kern/kern_descrip.c +++ sys/kern/kern_descrip.c @@ -922,10 +922,6 @@ goto unlock; } - oldfde = &fdp->fd_ofiles[old]; - if (!fhold(oldfde->fde_file)) - goto unlock; - /* * If the caller specified a file descriptor, make sure the file * table is large enough to hold it, and grab it. Otherwise, just @@ -934,17 +930,13 @@ switch (mode) { case FDDUP_NORMAL: case FDDUP_FCNTL: - if ((error = fdalloc(td, new, &new)) != 0) { - fdrop(oldfde->fde_file, td); + if ((error = fdalloc(td, new, &new)) != 0) goto unlock; - } break; case FDDUP_MUSTREPLACE: /* Target file descriptor must exist. */ - if (fget_locked(fdp, new) == NULL) { - fdrop(oldfde->fde_file, td); + if (fget_locked(fdp, new) == NULL) goto unlock; - } break; case FDDUP_FIXED: if (new >= fdp->fd_nfiles) { @@ -961,7 +953,6 @@ error = racct_set_unlocked(p, RACCT_NOFILE, new + 1); if (error != 0) { error = EMFILE; - fdrop(oldfde->fde_file, td); goto unlock; } } @@ -977,6 +968,8 @@ KASSERT(old != new, ("new fd is same as old")); + oldfde = &fdp->fd_ofiles[old]; + fhold(oldfde->fde_file); newfde = &fdp->fd_ofiles[new]; delfp = newfde->fde_file; @@ -1932,7 +1925,7 @@ } fp = uma_zalloc(file_zone, M_WAITOK); bzero(fp, sizeof(*fp)); - refcount_init(&fp->f_count, 1); + refcntlong_init(&fp->f_count, 1); fp->f_cred = crhold(td->td_ucred); fp->f_ops = &badfileops; *resultfp = fp; @@ -1977,8 +1970,7 @@ MPASS(fd != NULL); - if (!fhold(fp)) - return (EBADF); + fhold(fp); FILEDESC_XLOCK(fdp); if ((error = fdalloc(td, 0, fd))) { FILEDESC_XUNLOCK(fdp); @@ -2125,8 +2117,7 @@ for (i = 0; i <= fdp->fd_lastfile; ++i) { ofde = &fdp->fd_ofiles[i]; if (ofde->fde_file == NULL || - (ofde->fde_file->f_ops->fo_flags & DFLAG_PASSABLE) == 0 || - !fhold(ofde->fde_file)) { + (ofde->fde_file->f_ops->fo_flags & DFLAG_PASSABLE) == 0) { if (newfdp->fd_freefile == -1) newfdp->fd_freefile = i; continue; @@ -2134,6 +2125,7 @@ nfde = &newfdp->fd_ofiles[i]; *nfde = *ofde; filecaps_copy(&ofde->fde_caps, &nfde->fde_caps, true); + fhold(nfde->fde_file); fdused_init(newfdp, i); newfdp->fd_lastfile = i; } @@ -2186,13 +2178,10 @@ error = EINVAL; goto bad; } - if (!fhold(nfde->fde_file)) { - error = EBADF; - goto bad; - } nfde = &newfdp->fd_ofiles[i]; *nfde = *ofde; filecaps_copy(&ofde->fde_caps, &nfde->fde_caps, true); + fhold(nfde->fde_file); fdused_init(newfdp, i); newfdp->fd_lastfile = i; } @@ -2234,9 +2223,9 @@ (p->p_leader->p_flag & P_ADVLOCK) != 0) { for (i = 0; i <= fdp->fd_lastfile; i++) { fp = fdp->fd_ofiles[i].fde_file; - if (fp == NULL || fp->f_type != DTYPE_VNODE || - !fhold(fp)) + if (fp == NULL || fp->f_type != DTYPE_VNODE) continue; + fhold(fp); FILEDESC_XUNLOCK(fdp); lf.l_whence = SEEK_SET; lf.l_start = 0; @@ -2677,8 +2666,8 @@ get_locked: FILEDESC_SLOCK(fdp); error = fget_cap_locked(fdp, fd, needrightsp, fpp, havecapsp); - if (error == 0 && !fhold(*fpp)) - error = EBADF; + if (error == 0) + fhold(*fpp); FILEDESC_SUNLOCK(fdp); #endif return (error); @@ -2728,13 +2717,12 @@ if (error != 0) return (error); #endif - if (__predict_false(!refcount_acquire_if_not_zero(&fp->f_count))) { + if (__predict_false(!refcntlong_acquire_if_gt(&fp->f_count, 0))) { /* - * The count was found either saturated or zero. - * This re-read is not any more racy than using the - * return value from fcmpset. + * This re-read is not any more racy than using a read + * upfront of the value returned by failed fcmpset. */ - if (fp->f_count != 0) + if (refcntlong_read(&fp->f_count) != 0) return (EBADF); /* * Force a reload. Other thread could reallocate the @@ -3016,8 +3004,8 @@ { int error; - if (fp->f_count != 0) - panic("fdrop: count %d", fp->f_count); + if (refcntlong_read(&fp->f_count) != 0) + panic("fdrop: count %lu", refcntlong_read(&fp->f_count)); error = fo_close(fp, td); atomic_subtract_int(&openfiles, 1); crfree(fp->f_cred); @@ -3132,11 +3120,7 @@ FILEDESC_XUNLOCK(fdp); return (EACCES); } - if (!fhold(fp)) { - fdunused(fdp, indx); - FILEDESC_XUNLOCK(fdp); - return (EBADF); - } + fhold(fp); newfde = &fdp->fd_ofiles[indx]; oldfde = &fdp->fd_ofiles[dfd]; ioctls = filecaps_copy_prep(&oldfde->fde_caps); @@ -3445,7 +3429,7 @@ xf.xf_data = (uintptr_t)fp->f_data; xf.xf_vnode = (uintptr_t)fp->f_vnode; xf.xf_type = (uintptr_t)fp->f_type; - xf.xf_count = fp->f_count; + xf.xf_count = refcntlong_read(&fp->f_count); xf.xf_msgcount = 0; xf.xf_offset = foffset_get(fp); xf.xf_flag = fp->f_flag; @@ -3528,7 +3512,7 @@ else cap_rights_init(&kif->kf_cap_rights); kif->kf_fd = fd; - kif->kf_ref_count = fp->f_count; + kif->kf_ref_count = refcntlong_read(&fp->f_count); kif->kf_offset = foffset_get(fp); /* @@ -4039,10 +4023,10 @@ "GCFl", "Count", "MCount", XPTRWIDTH, "Vnode", "FPID", "FCmd"); p = file_to_first_proc(fp); - db_printf("%*p %6s %*p %08x %04x %5d %6d %*p %5d %s\n", XPTRWIDTH, + db_printf("%*p %6s %*p %08x %04x %5lu %6d %*p %5d %s\n", XPTRWIDTH, fp, file_type_to_name(fp->f_type), XPTRWIDTH, fp->f_data, - fp->f_flag, 0, fp->f_count, 0, XPTRWIDTH, fp->f_vnode, - p != NULL ? p->p_pid : -1, p != NULL ? p->p_comm : "-"); + fp->f_flag, 0, refcntlong_read(&fp->f_count), 0, XPTRWIDTH, + fp->f_vnode, p != NULL ? p->p_pid : -1, p != NULL ? p->p_comm : "-"); #undef XPTRWIDTH } Index: sys/kern/sys_generic.c =================================================================== --- sys/kern/sys_generic.c +++ sys/kern/sys_generic.c @@ -754,11 +754,7 @@ fp = NULL; /* fhold() was not called yet */ goto out; } - if (!fhold(fp)) { - error = EBADF; - fp = NULL; - goto out; - } + fhold(fp); if (locked == LA_SLOCKED) { FILEDESC_SUNLOCK(fdp); locked = LA_UNLOCKED; Index: sys/kern/uipc_usrreq.c =================================================================== --- sys/kern/uipc_usrreq.c +++ sys/kern/uipc_usrreq.c @@ -2152,7 +2152,7 @@ struct timespec *ts; void *data; socklen_t clen, datalen; - int i, j, error, *fdp, oldfds; + int i, error, *fdp, oldfds; u_int newlen; UNP_LINK_UNLOCK_ASSERT(); @@ -2235,19 +2235,6 @@ goto out; } fdp = data; - for (i = 0; i < oldfds; i++, fdp++) { - if (!fhold(fdesc->fd_ofiles[*fdp].fde_file)) { - fdp = data; - for (j = 0; j < i; j++, fdp++) { - fdrop(fdesc->fd_ofiles[*fdp]. - fde_file, td); - } - FILEDESC_SUNLOCK(fdesc); - error = EBADF; - goto out; - } - } - fdp = data; fdep = (struct filedescent **) CMSG_DATA(mtod(*controlp, struct cmsghdr *)); fdev = malloc(sizeof(*fdev) * oldfds, M_FILECAPS, @@ -2452,6 +2439,7 @@ unp->unp_file = fp; unp->unp_msgcount++; } + fhold(fp); unp_rights++; UNP_LINK_WUNLOCK(); } @@ -2607,7 +2595,7 @@ * NULL. */ if (f != NULL && unp->unp_msgcount != 0 && - f->f_count == unp->unp_msgcount) { + refcntlong_read(&f->f_count) == unp->unp_msgcount) { LIST_INSERT_HEAD(&unp_deadhead, unp, unp_dead); unp->unp_gcflag |= UNPGC_DEAD; unp->unp_gcrefs = unp->unp_msgcount; @@ -2670,10 +2658,10 @@ unp->unp_gcflag &= ~UNPGC_DEAD; f = unp->unp_file; if (unp->unp_msgcount == 0 || f == NULL || - f->f_count != unp->unp_msgcount || - !fhold(f)) + refcntlong_read(&f->f_count) != unp->unp_msgcount) continue; unref[total++] = f; + fhold(f); KASSERT(total <= unp_unreachable, ("%s: incorrect unreachable count.", __func__)); } Index: sys/sys/file.h =================================================================== --- sys/sys/file.h +++ sys/sys/file.h @@ -182,7 +182,7 @@ short f_type; /* descriptor type */ short f_vnread_flags; /* (f) Sleep lock for f_offset */ volatile u_int f_flag; /* see fcntl.h */ - volatile u_int f_count; /* reference count */ + refcntlong_t f_count; /* reference count */ /* * DTYPE_VNODE specific fields. */ @@ -200,10 +200,6 @@ * DFLAG_SEEKABLE specific fields */ off_t f_offset; - /* - * Mandatory Access control information. - */ - void *f_label; /* Place-holder for MAC label. */ }; #define f_cdevpriv f_vnun.fvn_cdevpriv @@ -282,21 +278,17 @@ int fgetvp_write(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp); -static __inline int -_fnoop(void) -{ - - return (0); -} - -static __inline __result_use_check bool -fhold(struct file *fp) -{ - return (refcount_acquire_checked(&fp->f_count)); -} - -#define fdrop(fp, td) \ - (refcount_release(&(fp)->f_count) ? _fdrop((fp), (td)) : _fnoop()) +#define fhold(fp) refcntlong_acquire(&(fp)->f_count) + +#define fdrop(fp, td) ({ \ + struct file *_fp = fp; \ + int _ret; \ + \ + _ret = 0; \ + if (refcntlong_release(&_fp->f_count)) \ + _ret = _fdrop(fp, td); \ + _ret; \ +}) static __inline fo_rdwr_t fo_read; static __inline fo_rdwr_t fo_write; Index: sys/sys/unpcb.h =================================================================== --- sys/sys/unpcb.h +++ sys/sys/unpcb.h @@ -85,8 +85,8 @@ struct unp_head unp_refs; /* referencing socket linked list */ unp_gen_t unp_gencnt; /* generation count of this instance */ struct file *unp_file; /* back-pointer to file for gc. */ - u_int unp_msgcount; /* references from message queue */ - u_int unp_gcrefs; /* garbage collector refcount */ + u_long unp_msgcount; /* references from message queue */ + u_long unp_gcrefs; /* garbage collector refcount */ ino_t unp_ino; /* fake inode number */ LIST_ENTRY(unpcb) unp_dead; /* link in dead list */ } __aligned(CACHE_LINE_SIZE);