Index: sys/kern/uipc_syscalls.c =================================================================== RCS file: /home/ncvs/src/sys/kern/uipc_syscalls.c,v retrieving revision 1.142 diff -u -r1.142 uipc_syscalls.c --- sys/kern/uipc_syscalls.c 6 Mar 2003 04:48:19 -0000 1.142 +++ sys/kern/uipc_syscalls.c 10 Mar 2003 23:29:55 -0000 @@ -1637,12 +1637,16 @@ * Get an sf_buf from the freelist. Will block if none are available. */ struct sf_buf * -sf_buf_alloc() +sf_buf_alloc(struct vm_page *m) { struct sf_buf *sf; int error; mtx_lock(&sf_freelist.sf_lock); + if ((sf = m->sf_buf) != NULL) { + sf->ref_count++; + goto done; + } while ((sf = SLIST_FIRST(&sf_freelist.sf_head)) == NULL) { sf_buf_alloc_want++; error = msleep(&sf_freelist, &sf_freelist.sf_lock, PVM|PCATCH, @@ -1650,13 +1654,42 @@ sf_buf_alloc_want--; /* - * If we got a signal, don't risk going back to sleep. + * If we got a signal, don't risk going back to sleep. */ if (error) - break; + goto done; } - if (sf != NULL) + SLIST_REMOVE_HEAD(&sf_freelist.sf_head, free_list); + sf->ref_count = 1; + sf->m = m; + pmap_qenter(sf->kva, &m, 1); + m->sf_buf = sf; + done: + mtx_unlock(&sf_freelist.sf_lock); + return (sf); +} + +/* + * Get an sf_buf from the freelist. Will return NULL if none are + * available. + */ +struct sf_buf * +sf_buf_alloc_nb(struct vm_page *m) +{ + struct sf_buf *sf; + + mtx_lock(&sf_freelist.sf_lock); + if ((sf = m->sf_buf) != NULL) { + sf->ref_count++; + goto done; + } + sf_buf_alloc_want++; + sf = SLIST_FIRST(&sf_freelist.sf_head); + if (sf != NULL) { SLIST_REMOVE_HEAD(&sf_freelist.sf_head, free_list); + sf_buf_alloc_want--; + } + done: mtx_unlock(&sf_freelist.sf_lock); return (sf); } @@ -1673,8 +1706,19 @@ struct vm_page *m; sf = dtosf(addr); - pmap_qremove((vm_offset_t)addr, 1); + mtx_lock(&sf_freelist.sf_lock); m = sf->m; + sf->ref_count--; + if (sf->ref_count == 0) { + m->sf_buf = NULL; + pmap_qremove((vm_offset_t)addr, 1); + sf->m = NULL; + SLIST_INSERT_HEAD(&sf_freelist.sf_head, sf, free_list); + if (sf_buf_alloc_want > 0) + wakeup_one(&sf_freelist); + } + mtx_unlock(&sf_freelist.sf_lock); + vm_page_lock_queues(); vm_page_unwire(m, 0); /* @@ -1685,12 +1729,6 @@ if (m->wire_count == 0 && m->object == NULL) vm_page_free(m); vm_page_unlock_queues(); - sf->m = NULL; - mtx_lock(&sf_freelist.sf_lock); - SLIST_INSERT_HEAD(&sf_freelist.sf_head, sf, free_list); - if (sf_buf_alloc_want > 0) - wakeup_one(&sf_freelist); - mtx_unlock(&sf_freelist.sf_lock); } /* @@ -1929,26 +1967,25 @@ vm_page_unlock_queues(); /* - * Get a sendfile buf. We usually wait as long as necessary, - * but this wait can be interrupted. + * Get a sendfile buf. */ - if ((sf = sf_buf_alloc()) == NULL) { + if (so->so_state & SS_NBIO) { + if ((sf = sf_buf_alloc_nb(pg)) == NULL) + error = EAGAIN; + } else { + if ((sf = sf_buf_alloc(pg)) == NULL) + error = EINTR; + } + if (sf == NULL) { vm_page_lock_queues(); vm_page_unwire(pg, 0); if (pg->wire_count == 0 && pg->object == NULL) vm_page_free(pg); vm_page_unlock_queues(); sbunlock(&so->so_snd); - error = EINTR; goto done; } - /* - * Allocate a kernel virtual page and insert the physical page - * into it. - */ - sf->m = pg; - pmap_qenter(sf->kva, &pg, 1); /* * Get an mbuf header and set it up as having external storage. */ Index: sys/sys/socketvar.h =================================================================== RCS file: /home/ncvs/src/sys/sys/socketvar.h,v retrieving revision 1.102 diff -u -r1.102 socketvar.h --- sys/sys/socketvar.h 2 Mar 2003 16:54:39 -0000 1.102 +++ sys/sys/socketvar.h 10 Mar 2003 23:29:55 -0000 @@ -316,6 +316,7 @@ SLIST_ENTRY(sf_buf) free_list; /* list of free buffer slots */ struct vm_page *m; /* currently mapped page */ vm_offset_t kva; /* va of mapping */ + int ref_count; }; struct accept_filter { @@ -371,7 +372,9 @@ void sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb); int sbwait(struct sockbuf *sb); struct sf_buf * - sf_buf_alloc(void); + sf_buf_alloc(struct vm_page *m); +struct sf_buf * + sf_buf_alloc_nb(struct vm_page *m); void sf_buf_free(void *addr, void *args); int sb_lock(struct sockbuf *sb); int soabort(struct socket *so); Index: sys/vm/vm_page.h =================================================================== RCS file: /home/ncvs/src/sys/vm/vm_page.h,v retrieving revision 1.117 diff -u -r1.117 vm_page.h --- sys/vm/vm_page.h 19 Dec 2002 07:23:46 -0000 1.117 +++ sys/vm/vm_page.h 10 Mar 2003 23:29:55 -0000 @@ -118,6 +118,7 @@ vm_pindex_t pindex; /* offset into object (O,P) */ vm_offset_t phys_addr; /* physical address of page */ struct md_page md; /* machine dependant stuff */ + struct sf_buf *sf_buf; u_short queue; /* page queue index */ u_short flags, /* see below */ pc; /* page color */