From owner-svn-src-projects@FreeBSD.ORG Tue Nov 11 20:40:42 2014 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 4EDE298A; Tue, 11 Nov 2014 20:40:42 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 32EB9A0E; Tue, 11 Nov 2014 20:40:42 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id sABKeguw099066; Tue, 11 Nov 2014 20:40:42 GMT (envelope-from glebius@FreeBSD.org) Received: (from glebius@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id sABKeesV099057; Tue, 11 Nov 2014 20:40:40 GMT (envelope-from glebius@FreeBSD.org) Message-Id: <201411112040.sABKeesV099057@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: glebius set sender to glebius@FreeBSD.org using -f From: Gleb Smirnoff Date: Tue, 11 Nov 2014 20:40:40 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r274404 - in projects/sendfile: gnu/usr.bin/gdb/kgdb sys/boot/i386/loader sys/compat/freebsd32 sys/dev/acpica sys/dev/cxgbe sys/kern sys/sys usr.sbin/bsdconfig/timezone usr.sbin/tzsetup X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 11 Nov 2014 20:40:42 -0000 Author: glebius Date: Tue Nov 11 20:40:39 2014 New Revision: 274404 URL: https://svnweb.freebsd.org/changeset/base/274404 Log: Merge head r274391 through 274403. Deleted: projects/sendfile/sys/sys/sf_base.h projects/sendfile/sys/sys/sf_sync.h Modified: projects/sendfile/gnu/usr.bin/gdb/kgdb/kgdb.h projects/sendfile/gnu/usr.bin/gdb/kgdb/trgt_i386.c projects/sendfile/sys/boot/i386/loader/conf.c projects/sendfile/sys/compat/freebsd32/freebsd32_misc.c projects/sendfile/sys/dev/acpica/acpi.c projects/sendfile/sys/dev/cxgbe/t4_main.c projects/sendfile/sys/kern/kern_descrip.c projects/sendfile/sys/kern/uipc_syscalls.c projects/sendfile/sys/sys/file.h projects/sendfile/sys/sys/socket.h projects/sendfile/usr.sbin/bsdconfig/timezone/timezone projects/sendfile/usr.sbin/tzsetup/tzsetup.c Directory Properties: projects/sendfile/ (props changed) projects/sendfile/gnu/usr.bin/gdb/ (props changed) projects/sendfile/sys/ (props changed) projects/sendfile/sys/boot/ (props changed) Modified: projects/sendfile/gnu/usr.bin/gdb/kgdb/kgdb.h ============================================================================== --- projects/sendfile/gnu/usr.bin/gdb/kgdb/kgdb.h Tue Nov 11 20:32:46 2014 (r274403) +++ projects/sendfile/gnu/usr.bin/gdb/kgdb/kgdb.h Tue Nov 11 20:40:39 2014 (r274404) @@ -41,7 +41,7 @@ struct kthr { uintptr_t pcb; int tid; int pid; - u_char cpu; + int cpu; }; extern struct kthr *curkthr; Modified: projects/sendfile/gnu/usr.bin/gdb/kgdb/trgt_i386.c ============================================================================== --- projects/sendfile/gnu/usr.bin/gdb/kgdb/trgt_i386.c Tue Nov 11 20:32:46 2014 (r274403) +++ projects/sendfile/gnu/usr.bin/gdb/kgdb/trgt_i386.c Tue Nov 11 20:40:39 2014 (r274404) @@ -139,7 +139,7 @@ kgdb_trgt_fetch_tss(void) uintptr_t addr, cpu0prvpage, tss; kt = kgdb_thr_lookup_tid(ptid_get_pid(inferior_ptid)); - if (kt == NULL || kt->cpu == NOCPU) + if (kt == NULL || kt->cpu == NOCPU || kt->cpu < 0) return (0); addr = kgdb_lookup("gdt"); Modified: projects/sendfile/sys/boot/i386/loader/conf.c ============================================================================== --- projects/sendfile/sys/boot/i386/loader/conf.c Tue Nov 11 20:32:46 2014 (r274403) +++ projects/sendfile/sys/boot/i386/loader/conf.c Tue Nov 11 20:40:39 2014 (r274404) @@ -80,8 +80,11 @@ struct fs_ops *file_system[] = { #if defined(LOADER_NANDFS_SUPPORT) &nandfs_fsops, #endif -#ifdef LOADER_SPLIT_SUPPORT - &splitfs_fsops, +#ifdef LOADER_NFS_SUPPORT + &nfs_fsops, +#endif +#ifdef LOADER_TFTP_SUPPORT + &tftp_fsops, #endif #ifdef LOADER_GZIP_SUPPORT &gzipfs_fsops, @@ -89,11 +92,8 @@ struct fs_ops *file_system[] = { #ifdef LOADER_BZIP2_SUPPORT &bzipfs_fsops, #endif -#ifdef LOADER_NFS_SUPPORT - &nfs_fsops, -#endif -#ifdef LOADER_TFTP_SUPPORT - &tftp_fsops, +#ifdef LOADER_SPLIT_SUPPORT + &splitfs_fsops, #endif NULL }; Modified: projects/sendfile/sys/compat/freebsd32/freebsd32_misc.c ============================================================================== --- projects/sendfile/sys/compat/freebsd32/freebsd32_misc.c Tue Nov 11 20:32:46 2014 (r274403) +++ projects/sendfile/sys/compat/freebsd32/freebsd32_misc.c Tue Nov 11 20:40:39 2014 (r274404) @@ -83,10 +83,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include -#include -#include #ifdef INET #include @@ -1567,26 +1563,16 @@ struct sf_hdtr32 { int trl_cnt; }; -struct sf_hdtr_kq32 { - int kq_fd; - uint32_t kq_flags; - uint32_t kq_udata; /* 32-bit void ptr */ - uint32_t kq_ident; /* 32-bit uintptr_t */ -}; - static int freebsd32_do_sendfile(struct thread *td, struct freebsd32_sendfile_args *uap, int compat) { struct sf_hdtr32 hdtr32; struct sf_hdtr hdtr; - struct sf_hdtr_kq32 hdtr_kq32; - struct sf_hdtr_kq hdtr_kq; struct uio *hdr_uio, *trl_uio; struct iovec32 *iov32; - off_t offset; + off_t offset, sbytes; int error; - off_t sbytes; offset = PAIR32TO64(off_t, uap->offset); if (offset < 0) @@ -1617,31 +1603,17 @@ freebsd32_do_sendfile(struct thread *td, if (error) goto out; } - - /* - * If SF_KQUEUE is set, then we need to also copy in - * the kqueue data after the normal hdtr set and set do_kqueue=1. - */ - if (uap->flags & SF_KQUEUE) { - error = copyin(((char *) uap->hdtr) + sizeof(hdtr32), - &hdtr_kq32, - sizeof(hdtr_kq32)); - if (error != 0) - goto out; - - /* 32->64 bit fields */ - CP(hdtr_kq32, hdtr_kq, kq_fd); - CP(hdtr_kq32, hdtr_kq, kq_flags); - PTRIN_CP(hdtr_kq32, hdtr_kq, kq_udata); - CP(hdtr_kq32, hdtr_kq, kq_ident); - } } + AUDIT_ARG_FD(uap->fd); - /* Call sendfile */ - /* XXX stack depth! */ - error = _do_sendfile(td, uap->fd, uap->s, uap->flags, compat, - offset, uap->nbytes, &sbytes, hdr_uio, trl_uio, &hdtr_kq); + if ((error = fget_read(td, uap->fd, + cap_rights_init(&rights, CAP_PREAD), &fp)) != 0) + goto out; + + error = fo_sendfile(fp, uap->s, hdr_uio, trl_uio, offset, + uap->nbytes, &sbytes, uap->flags, compat ? SFK_COMPAT : 0, td); + fdrop(fp, td); if (uap->sbytes != NULL) copyout(&sbytes, uap->sbytes, sizeof(off_t)); Modified: projects/sendfile/sys/dev/acpica/acpi.c ============================================================================== --- projects/sendfile/sys/dev/acpica/acpi.c Tue Nov 11 20:32:46 2014 (r274403) +++ projects/sendfile/sys/dev/acpica/acpi.c Tue Nov 11 20:40:39 2014 (r274404) @@ -694,7 +694,7 @@ acpi_attach(device_t dev) static void acpi_set_power_children(device_t dev, int state) { - device_t child, parent; + device_t child; device_t *devlist; int dstate, i, numdevs; @@ -705,12 +705,11 @@ acpi_set_power_children(device_t dev, in * Retrieve and set D-state for the sleep state if _SxD is present. * Skip children who aren't attached since they are handled separately. */ - parent = device_get_parent(dev); for (i = 0; i < numdevs; i++) { child = devlist[i]; dstate = state; if (device_is_attached(child) && - acpi_device_pwr_for_sleep(parent, child, &dstate) == 0) + acpi_device_pwr_for_sleep(dev, child, &dstate) == 0) acpi_set_powerstate(child, dstate); } free(devlist, M_TEMP); Modified: projects/sendfile/sys/dev/cxgbe/t4_main.c ============================================================================== --- projects/sendfile/sys/dev/cxgbe/t4_main.c Tue Nov 11 20:32:46 2014 (r274403) +++ projects/sendfile/sys/dev/cxgbe/t4_main.c Tue Nov 11 20:40:39 2014 (r274404) @@ -490,6 +490,7 @@ struct { {0x5411, "Chelsio T520-LL-CR"}, /* 2 x 10G */ {0x5412, "Chelsio T560-CR"}, /* 1 x 40G, 2 x 10G */ {0x5414, "Chelsio T580-LP-SO-CR"}, /* 2 x 40G, nomem */ + {0x5415, "Chelsio T502-BT"}, /* 2 x 1G */ #ifdef notyet {0x5404, "Chelsio T520-BCH"}, {0x5405, "Chelsio T540-BCH"}, Modified: projects/sendfile/sys/kern/kern_descrip.c ============================================================================== --- projects/sendfile/sys/kern/kern_descrip.c Tue Nov 11 20:32:46 2014 (r274403) +++ projects/sendfile/sys/kern/kern_descrip.c Tue Nov 11 20:40:39 2014 (r274404) @@ -3684,7 +3684,7 @@ badfo_chown(struct file *fp, uid_t uid, static int badfo_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio, struct uio *trl_uio, off_t offset, size_t nbytes, off_t *sent, int flags, - int kflags, struct sendfile_sync *sfs, struct thread *td) + int kflags, struct thread *td) { return (EBADF); @@ -3770,7 +3770,7 @@ invfo_chown(struct file *fp, uid_t uid, int invfo_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio, struct uio *trl_uio, off_t offset, size_t nbytes, off_t *sent, int flags, - int kflags, struct sendfile_sync *sfs, struct thread *td) + int kflags, struct thread *td) { return (EINVAL); Modified: projects/sendfile/sys/kern/uipc_syscalls.c ============================================================================== --- projects/sendfile/sys/kern/uipc_syscalls.c Tue Nov 11 20:32:46 2014 (r274403) +++ projects/sendfile/sys/kern/uipc_syscalls.c Tue Nov 11 20:40:39 2014 (r274404) @@ -63,8 +63,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include #include #include #include @@ -115,32 +113,6 @@ static int getpeername1(struct thread *t counter_u64_t sfstat[sizeof(struct sfstat) / sizeof(uint64_t)]; -static int filt_sfsync_attach(struct knote *kn); -static void filt_sfsync_detach(struct knote *kn); -static int filt_sfsync(struct knote *kn, long hint); - -#ifdef SFSYNC_DEBUG -static int sf_sync_debug = 0; -SYSCTL_INT(_debug, OID_AUTO, sf_sync_debug, CTLFLAG_RW, - &sf_sync_debug, 0, "Output debugging during sf_sync lifecycle"); -#define SFSYNC_DPRINTF(s, ...) \ - do { \ - if (sf_sync_debug) \ - printf((s), ##__VA_ARGS__); \ - } while (0) -#else -#define SFSYNC_DPRINTF(c, ...) -#endif - -static uma_zone_t zone_sfsync; - -static struct filterops sendfile_filtops = { - .f_isfd = 0, - .f_attach = filt_sfsync_attach, - .f_detach = filt_sfsync_detach, - .f_event = filt_sfsync, -}; - static void sfstat_init(const void *unused) { @@ -150,19 +122,6 @@ sfstat_init(const void *unused) } SYSINIT(sfstat, SI_SUB_MBUF, SI_ORDER_FIRST, sfstat_init, NULL); -static void -sf_sync_init(const void *unused) -{ - - zone_sfsync = uma_zcreate("sendfile_sync", sizeof(struct sendfile_sync), - NULL, NULL, - NULL, NULL, - UMA_ALIGN_CACHE, - 0); - kqueue_add_filteropts(EVFILT_SENDFILE, &sendfile_filtops); -} -SYSINIT(sf_sync, SI_SUB_MBUF, SI_ORDER_FIRST, sf_sync_init, NULL); - static int sfstat_sysctl(SYSCTL_HANDLER_ARGS) { @@ -1855,116 +1814,11 @@ getsockaddr(namp, uaddr, len) return (error); } -static int -filt_sfsync_attach(struct knote *kn) -{ - struct sendfile_sync *sfs = (struct sendfile_sync *) kn->kn_sdata; - struct knlist *knl = &sfs->klist; - - SFSYNC_DPRINTF("%s: kn=%p, sfs=%p\n", __func__, kn, sfs); - - /* - * Validate that we actually received this via the kernel API. - */ - if ((kn->kn_flags & EV_FLAG1) == 0) - return (EPERM); - - kn->kn_ptr.p_v = sfs; - kn->kn_flags &= ~EV_FLAG1; - - knl->kl_lock(knl->kl_lockarg); - /* - * If we're in the "freeing" state, - * don't allow the add. That way we don't - * end up racing with some other thread that - * is trying to finish some setup. - */ - if (sfs->state == SF_STATE_FREEING) { - knl->kl_unlock(knl->kl_lockarg); - return (EINVAL); - } - knlist_add(&sfs->klist, kn, 1); - knl->kl_unlock(knl->kl_lockarg); - - return (0); -} - -/* - * Called when a knote is being detached. - */ -static void -filt_sfsync_detach(struct knote *kn) -{ - struct knlist *knl; - struct sendfile_sync *sfs; - int do_free = 0; - - sfs = kn->kn_ptr.p_v; - knl = &sfs->klist; - - SFSYNC_DPRINTF("%s: kn=%p, sfs=%p\n", __func__, kn, sfs); - - knl->kl_lock(knl->kl_lockarg); - if (!knlist_empty(knl)) - knlist_remove(knl, kn, 1); - - /* - * If the list is empty _AND_ the refcount is 0 - * _AND_ we've finished the setup phase and now - * we're in the running phase, we can free the - * underlying sendfile_sync. - * - * But we shouldn't do it before finishing the - * underlying divorce from the knote. - * - * So, we have the sfsync lock held; transition - * it to "freeing", then unlock, then free - * normally. - */ - if (knlist_empty(knl)) { - if (sfs->state == SF_STATE_COMPLETED && sfs->count == 0) { - SFSYNC_DPRINTF("%s: (%llu) sfs=%p; completed, " - "count==0, empty list: time to free!\n", - __func__, - (unsigned long long) curthread->td_tid, - sfs); - sf_sync_set_state(sfs, SF_STATE_FREEING, 1); - do_free = 1; - } - } - knl->kl_unlock(knl->kl_lockarg); - - /* - * Only call free if we're the one who has transitioned things - * to free. Otherwise we could race with another thread that - * is currently tearing things down. - */ - if (do_free == 1) { - SFSYNC_DPRINTF("%s: (%llu) sfs=%p, %s:%d\n", - __func__, - (unsigned long long) curthread->td_tid, - sfs, - __FILE__, - __LINE__); - sf_sync_free(sfs); - } -} - -static int -filt_sfsync(struct knote *kn, long hint) -{ - struct sendfile_sync *sfs = (struct sendfile_sync *) kn->kn_ptr.p_v; - int ret; - - SFSYNC_DPRINTF("%s: kn=%p, sfs=%p\n", __func__, kn, sfs); - - /* - * XXX add a lock assertion here! - */ - ret = (sfs->count == 0 && sfs->state == SF_STATE_COMPLETED); - - return (ret); -} +struct sendfile_sync { + struct mtx mtx; + struct cv cv; + unsigned count; +}; /* * Add more references to a vm_page + sf_buf + sendfile_sync. @@ -2013,8 +1867,13 @@ sf_ext_free(void *arg1, void *arg2) vm_page_free(pg); vm_page_unlock(pg); - if (sfs != NULL) - sf_sync_deref(sfs); + if (sfs != NULL) { + mtx_lock(&sfs->mtx); + KASSERT(sfs->count > 0, ("Sendfile sync botchup count == 0")); + if (--sfs->count == 0) + cv_signal(&sfs->cv); + mtx_unlock(&sfs->mtx); + } } /* @@ -2044,344 +1903,13 @@ sf_ext_free_nocache(void *arg1, void *ar } vm_page_unlock(pg); - if (sfs != NULL) - sf_sync_deref(sfs); -} - -/* - * Called to remove a reference to a sf_sync object. - * - * This is generally done during the mbuf free path to signify - * that one of the mbufs in the transaction has been completed. - * - * If we're doing SF_SYNC and the refcount is zero then we'll wake - * up any waiters. - * - * IF we're doing SF_KQUEUE and the refcount is zero then we'll - * fire off the knote. - */ -void -sf_sync_deref(struct sendfile_sync *sfs) -{ - int do_free = 0; - - if (sfs == NULL) - return; - - mtx_lock(&sfs->mtx); - KASSERT(sfs->count> 0, ("Sendfile sync botchup count == 0")); - sfs->count --; - - /* - * Only fire off the wakeup / kqueue notification if - * we are in the running state. - */ - if (sfs->count == 0 && sfs->state == SF_STATE_COMPLETED) { - if (sfs->flags & SF_SYNC) + if (sfs != NULL) { + mtx_lock(&sfs->mtx); + KASSERT(sfs->count > 0, ("Sendfile sync botchup count == 0")); + if (--sfs->count == 0) cv_signal(&sfs->cv); - - if (sfs->flags & SF_KQUEUE) { - SFSYNC_DPRINTF("%s: (%llu) sfs=%p: knote!\n", - __func__, - (unsigned long long) curthread->td_tid, - sfs); - KNOTE_LOCKED(&sfs->klist, 1); - } - - /* - * If we're not waiting around for a sync, - * check if the knote list is empty. - * If it is, we transition to free. - * - * XXX I think it's about time I added some state - * or flag that says whether we're supposed to be - * waiting around until we've done a signal. - * - * XXX Ie, the reason that I don't free it here - * is because the caller will free the last reference, - * not us. That should be codified in some flag - * that indicates "self-free" rather than checking - * for SF_SYNC all the time. - */ - if ((sfs->flags & SF_SYNC) == 0 && knlist_empty(&sfs->klist)) { - SFSYNC_DPRINTF("%s: (%llu) sfs=%p; completed, " - "count==0, empty list: time to free!\n", - __func__, - (unsigned long long) curthread->td_tid, - sfs); - sf_sync_set_state(sfs, SF_STATE_FREEING, 1); - do_free = 1; - } - - } - mtx_unlock(&sfs->mtx); - - /* - * Attempt to do a free here. - * - * We do this outside of the lock because it may destroy the - * lock in question as it frees things. We can optimise this - * later. - * - * XXX yes, we should make it a requirement to hold the - * lock across sf_sync_free(). - */ - if (do_free == 1) { - SFSYNC_DPRINTF("%s: (%llu) sfs=%p\n", - __func__, - (unsigned long long) curthread->td_tid, - sfs); - sf_sync_free(sfs); - } -} - -/* - * Allocate a sendfile_sync state structure. - * - * For now this only knows about the "sleep" sync, but later it will - * grow various other personalities. - */ -struct sendfile_sync * -sf_sync_alloc(uint32_t flags) -{ - struct sendfile_sync *sfs; - - sfs = uma_zalloc(zone_sfsync, M_WAITOK | M_ZERO); - mtx_init(&sfs->mtx, "sendfile", NULL, MTX_DEF); - cv_init(&sfs->cv, "sendfile"); - sfs->flags = flags; - sfs->state = SF_STATE_SETUP; - knlist_init_mtx(&sfs->klist, &sfs->mtx); - - SFSYNC_DPRINTF("%s: sfs=%p, flags=0x%08x\n", __func__, sfs, sfs->flags); - - return (sfs); -} - -/* - * Take a reference to a sfsync instance. - * - * This has to map 1:1 to free calls coming in via sf_ext_free(), - * so typically this will be referenced once for each mbuf allocated. - */ -void -sf_sync_ref(struct sendfile_sync *sfs) -{ - - if (sfs == NULL) - return; - - mtx_lock(&sfs->mtx); - sfs->count++; - mtx_unlock(&sfs->mtx); -} - -void -sf_sync_syscall_wait(struct sendfile_sync *sfs) -{ - - if (sfs == NULL) - return; - - KASSERT(mtx_owned(&sfs->mtx), ("%s: sfs=%p: not locked but should be!", - __func__, - sfs)); - - /* - * If we're not requested to wait during the syscall, - * don't bother waiting. - */ - if ((sfs->flags & SF_SYNC) == 0) - goto out; - - /* - * This is a bit suboptimal and confusing, so bear with me. - * - * Ideally sf_sync_syscall_wait() will wait until - * all pending mbuf transmit operations are done. - * This means that when sendfile becomes async, it'll - * run in the background and will transition from - * RUNNING to COMPLETED when it's finished acquiring - * new things to send. Then, when the mbufs finish - * sending, COMPLETED + sfs->count == 0 is enough to - * know that no further work is being done. - * - * So, we will sleep on both RUNNING and COMPLETED. - * It's up to the (in progress) async sendfile loop - * to transition the sf_sync from RUNNING to - * COMPLETED so the wakeup above will actually - * do the cv_signal() call. - */ - if (sfs->state != SF_STATE_COMPLETED && sfs->state != SF_STATE_RUNNING) - goto out; - - if (sfs->count != 0) - cv_wait(&sfs->cv, &sfs->mtx); - KASSERT(sfs->count == 0, ("sendfile sync still busy")); - -out: - return; -} - -/* - * Free an sf_sync if it's appropriate to. - */ -void -sf_sync_free(struct sendfile_sync *sfs) -{ - - if (sfs == NULL) - return; - - SFSYNC_DPRINTF("%s: (%lld) sfs=%p; called; state=%d, flags=0x%08x " - "count=%d\n", - __func__, - (long long) curthread->td_tid, - sfs, - sfs->state, - sfs->flags, - sfs->count); - - mtx_lock(&sfs->mtx); - - /* - * We keep the sf_sync around if the state is active, - * we are doing kqueue notification and we have active - * knotes. - * - * If the caller wants to free us right this second it - * should transition this to the freeing state. - * - * So, complain loudly if they break this rule. - */ - if (sfs->state != SF_STATE_FREEING) { - printf("%s: (%llu) sfs=%p; not freeing; let's wait!\n", - __func__, - (unsigned long long) curthread->td_tid, - sfs); mtx_unlock(&sfs->mtx); - return; - } - - KASSERT(sfs->count == 0, ("sendfile sync still busy")); - cv_destroy(&sfs->cv); - /* - * This doesn't call knlist_detach() on each knote; it just frees - * the entire list. - */ - knlist_delete(&sfs->klist, curthread, 1); - mtx_destroy(&sfs->mtx); - SFSYNC_DPRINTF("%s: (%llu) sfs=%p; freeing\n", - __func__, - (unsigned long long) curthread->td_tid, - sfs); - uma_zfree(zone_sfsync, sfs); -} - -/* - * Setup a sf_sync to post a kqueue notification when things are complete. - */ -int -sf_sync_kqueue_setup(struct sendfile_sync *sfs, struct sf_hdtr_kq *sfkq) -{ - struct kevent kev; - int error; - - sfs->flags |= SF_KQUEUE; - - /* Check the flags are valid */ - if ((sfkq->kq_flags & ~(EV_CLEAR | EV_DISPATCH | EV_ONESHOT)) != 0) - return (EINVAL); - - SFSYNC_DPRINTF("%s: sfs=%p: kqfd=%d, flags=0x%08x, ident=%p, udata=%p\n", - __func__, - sfs, - sfkq->kq_fd, - sfkq->kq_flags, - (void *) sfkq->kq_ident, - (void *) sfkq->kq_udata); - - /* Setup and register a knote on the given kqfd. */ - kev.ident = (uintptr_t) sfkq->kq_ident; - kev.filter = EVFILT_SENDFILE; - kev.flags = EV_ADD | EV_ENABLE | EV_FLAG1 | sfkq->kq_flags; - kev.data = (intptr_t) sfs; - kev.udata = sfkq->kq_udata; - - error = kqfd_register(sfkq->kq_fd, &kev, curthread, 1); - if (error != 0) { - SFSYNC_DPRINTF("%s: returned %d\n", __func__, error); - } - return (error); -} - -void -sf_sync_set_state(struct sendfile_sync *sfs, sendfile_sync_state_t state, - int islocked) -{ - sendfile_sync_state_t old_state; - - if (! islocked) - mtx_lock(&sfs->mtx); - - /* - * Update our current state. - */ - old_state = sfs->state; - sfs->state = state; - SFSYNC_DPRINTF("%s: (%llu) sfs=%p; going from %d to %d\n", - __func__, - (unsigned long long) curthread->td_tid, - sfs, - old_state, - state); - - /* - * If we're transitioning from RUNNING to COMPLETED and the count is - * zero, then post the knote. The caller may have completed the - * send before we updated the state to COMPLETED and we need to make - * sure this is communicated. - */ - if (old_state == SF_STATE_RUNNING - && state == SF_STATE_COMPLETED - && sfs->count == 0 - && sfs->flags & SF_KQUEUE) { - SFSYNC_DPRINTF("%s: (%llu) sfs=%p: triggering knote!\n", - __func__, - (unsigned long long) curthread->td_tid, - sfs); - KNOTE_LOCKED(&sfs->klist, 1); } - - if (! islocked) - mtx_unlock(&sfs->mtx); -} - -/* - * Set the retval/errno for the given transaction. - * - * This will eventually/ideally be used when the KNOTE is fired off - * to signify the completion of this transaction. - * - * The sfsync lock should be held before entering this function. - */ -void -sf_sync_set_retval(struct sendfile_sync *sfs, off_t retval, int xerrno) -{ - - KASSERT(mtx_owned(&sfs->mtx), ("%s: sfs=%p: not locked but should be!", - __func__, - sfs)); - - SFSYNC_DPRINTF("%s: (%llu) sfs=%p: errno=%d, retval=%jd\n", - __func__, - (unsigned long long) curthread->td_tid, - sfs, - xerrno, - (intmax_t) retval); - - sfs->retval = retval; - sfs->xerrno = xerrno; } /* @@ -2402,174 +1930,15 @@ sys_sendfile(struct thread *td, struct s return (do_sendfile(td, uap, 0)); } -int -_do_sendfile(struct thread *td, int src_fd, int sock_fd, int flags, - int compat, off_t offset, size_t nbytes, off_t *sbytes, - struct uio *hdr_uio, - struct uio *trl_uio, struct sf_hdtr_kq *hdtr_kq) -{ - cap_rights_t rights; - struct sendfile_sync *sfs = NULL; - struct file *fp; - int error; - int do_kqueue = 0; - int do_free = 0; - - AUDIT_ARG_FD(src_fd); - - if (hdtr_kq != NULL) - do_kqueue = 1; - - /* - * sendfile(2) can start at any offset within a file so we require - * CAP_READ+CAP_SEEK = CAP_PREAD. - */ - if ((error = fget_read(td, src_fd, - cap_rights_init(&rights, CAP_PREAD), &fp)) != 0) { - goto out; - } - - /* - * IF SF_KQUEUE is set but we haven't copied in anything for - * kqueue data, error out. - */ - if (flags & SF_KQUEUE && do_kqueue == 0) { - SFSYNC_DPRINTF("%s: SF_KQUEUE but no KQUEUE data!\n", __func__); - goto out; - } - - /* - * If we need to wait for completion, initialise the sfsync - * state here. - */ - if (flags & (SF_SYNC | SF_KQUEUE)) - sfs = sf_sync_alloc(flags & (SF_SYNC | SF_KQUEUE)); - - if (flags & SF_KQUEUE) { - error = sf_sync_kqueue_setup(sfs, hdtr_kq); - if (error) { - SFSYNC_DPRINTF("%s: (%llu) error; sfs=%p\n", - __func__, - (unsigned long long) curthread->td_tid, - sfs); - sf_sync_set_state(sfs, SF_STATE_FREEING, 0); - sf_sync_free(sfs); - goto out; - } - } - - /* - * Do the sendfile call. - * - * If this fails, it'll free the mbuf chain which will free up the - * sendfile_sync references. - */ - error = fo_sendfile(fp, sock_fd, hdr_uio, trl_uio, offset, - nbytes, sbytes, flags, compat ? SFK_COMPAT : 0, sfs, td); - - /* - * If the sendfile call succeeded, transition the sf_sync state - * to RUNNING, then COMPLETED. - * - * If the sendfile call failed, then the sendfile call may have - * actually sent some data first - so we check to see whether - * any data was sent. If some data was queued (ie, count > 0) - * then we can't call free; we have to wait until the partial - * transaction completes before we continue along. - * - * This has the side effect of firing off the knote - * if the refcount has hit zero by the time we get here. - */ - if (sfs != NULL) { - mtx_lock(&sfs->mtx); - if (error == 0 || sfs->count > 0) { - /* - * When it's time to do async sendfile, the transition - * to RUNNING signifies that we're actually actively - * adding and completing mbufs. When the last disk - * buffer is read (ie, when we're not doing any - * further read IO and all subsequent stuff is mbuf - * transmissions) we'll transition to COMPLETED - * and when the final mbuf is freed, the completion - * will be signaled. - */ - sf_sync_set_state(sfs, SF_STATE_RUNNING, 1); - - /* - * Set the retval before we signal completed. - * If we do it the other way around then transitioning to - * COMPLETED may post the knote before you set the return - * status! - * - * XXX for now, errno is always 0, as we don't post - * knotes if sendfile failed. Maybe that'll change later. - */ - sf_sync_set_retval(sfs, *sbytes, error); - - /* - * And now transition to completed, which will kick off - * the knote if required. - */ - sf_sync_set_state(sfs, SF_STATE_COMPLETED, 1); - } else { - /* - * Error isn't zero, sfs_count is zero, so we - * won't have some other thing to wake things up. - * Thus free. - */ - sf_sync_set_state(sfs, SF_STATE_FREEING, 1); - do_free = 1; - } - - /* - * Next - wait if appropriate. - */ - sf_sync_syscall_wait(sfs); - - /* - * If we're not doing kqueue notifications, we can - * transition this immediately to the freeing state. - */ - if ((sfs->flags & SF_KQUEUE) == 0) { - sf_sync_set_state(sfs, SF_STATE_FREEING, 1); - do_free = 1; - } - - mtx_unlock(&sfs->mtx); - } - - /* - * If do_free is set, free here. - * - * If we're doing no-kqueue notification and it's just sleep notification, - * we also do free; it's the only chance we have. - */ - if (sfs != NULL && do_free == 1) { - sf_sync_free(sfs); - } - - /* - * XXX Should we wait until the send has completed before freeing the source - * file handle? It's the previous behaviour, sure, but is it required? - * We've wired down the page references after all. - */ - fdrop(fp, td); - -out: - /* Return error */ - return (error); -} - - static int do_sendfile(struct thread *td, struct sendfile_args *uap, int compat) { struct sf_hdtr hdtr; - struct sf_hdtr_kq hdtr_kq; struct uio *hdr_uio, *trl_uio; - int error; + struct file *fp; + cap_rights_t rights; off_t sbytes; - int do_kqueue = 0; + int error; /* * File offset must be positive. If it goes beyond EOF @@ -2585,38 +1954,37 @@ do_sendfile(struct thread *td, struct se if (error != 0) goto out; if (hdtr.headers != NULL) { - error = copyinuio(hdtr.headers, hdtr.hdr_cnt, &hdr_uio); + error = copyinuio(hdtr.headers, hdtr.hdr_cnt, + &hdr_uio); if (error != 0) goto out; } if (hdtr.trailers != NULL) { - error = copyinuio(hdtr.trailers, hdtr.trl_cnt, &trl_uio); + error = copyinuio(hdtr.trailers, hdtr.trl_cnt, + &trl_uio); if (error != 0) goto out; } + } - /* - * If SF_KQUEUE is set, then we need to also copy in - * the kqueue data after the normal hdtr set and set - * do_kqueue=1. - */ - if (uap->flags & SF_KQUEUE) { - error = copyin(((char *) uap->hdtr) + sizeof(hdtr), - &hdtr_kq, - sizeof(hdtr_kq)); - if (error != 0) - goto out; - do_kqueue = 1; - } + AUDIT_ARG_FD(src_fd); + + /* + * sendfile(2) can start at any offset within a file so we require + * CAP_READ+CAP_SEEK = CAP_PREAD. + */ + if ((error = fget_read(td, uap->fd, + cap_rights_init(&rights, CAP_PREAD), &fp)) != 0) { + goto out; } - /* Call sendfile */ - error = _do_sendfile(td, uap->fd, uap->s, uap->flags, compat, - uap->offset, uap->nbytes, &sbytes, hdr_uio, trl_uio, &hdtr_kq); + error = fo_sendfile(fp, uap->s, hdr_uio, trl_uio, uap->offset, + uap->nbytes, &sbytes, uap->flags, compat ? SFK_COMPAT : 0, td); + fdrop(fp, td); - if (uap->sbytes != NULL) { + if (uap->sbytes != NULL) copyout(&sbytes, uap->sbytes, sizeof(off_t)); - } + out: free(hdr_uio, M_IOV); free(trl_uio, M_IOV); @@ -2903,7 +2271,7 @@ kern_sendfile_getsock(struct thread *td, int vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio, struct uio *trl_uio, off_t offset, size_t nbytes, off_t *sent, int flags, - int kflags, struct sendfile_sync *sfs, struct thread *td) + int kflags, struct thread *td) { struct file *sock_fp; struct vnode *vp; @@ -2912,6 +2280,7 @@ vn_sendfile(struct file *fp, int sockfd, struct mbuf *m, *mh, *mhtail; struct sf_buf *sf; struct shmfd *shmfd; + struct sendfile_sync *sfs; struct vattr va; off_t off, sbytes, rem, obj_size; int error, softerr, bsize, hdrlen; @@ -2919,6 +2288,7 @@ vn_sendfile(struct file *fp, int sockfd, obj = NULL; so = NULL; m = mh = NULL; + sfs = NULL; sbytes = 0; softerr = 0; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***