uipc_cow.c revision 98849
198849Sken/*- 298849Sken * Copyright (c) 1997, Duke University 398849Sken * All rights reserved. 498849Sken * 598849Sken * Author: 698849Sken * Andrew Gallatin <gallatin@cs.duke.edu> 798849Sken * 898849Sken * Redistribution and use in source and binary forms, with or without 998849Sken * modification, are permitted provided that the following conditions 1098849Sken * are met: 1198849Sken * 1. Redistributions of source code must retain the above copyright 1298849Sken * notice, this list of conditions and the following disclaimer. 1398849Sken * 2. Redistributions in binary form must reproduce the above copyright 1498849Sken * notice, this list of conditions and the following disclaimer in the 1598849Sken * documentation and/or other materials provided with the distribution. 1698849Sken * 3. All advertising materials mentioning features or use of this software 1798849Sken * must display the following acknowledgements: 1898849Sken * This product includes software developed by Duke University 1998849Sken * 4. The name of Duke University may not be used to endorse or promote 2098849Sken * products derived from this software without specific prior written 2198849Sken * permission. 2298849Sken * 2398849Sken * THIS SOFTWARE IS PROVIDED BY DUKE UNIVERSITY ``AS IS'' AND ANY 2498849Sken * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2598849Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2698849Sken * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DUKE UNIVERSITY BE LIABLE 2798849Sken * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2898849Sken * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2998849Sken * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITSOR BUSINESS 3098849Sken * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 3198849Sken * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 3298849Sken * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 3398849Sken * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3498849Sken * 3598849Sken * $FreeBSD: head/sys/kern/uipc_cow.c 98849 2002-06-26 03:37:47Z ken $ 3698849Sken */ 3798849Sken/* 3898849Sken * This is a set of routines for enabling and disabling copy on write 3998849Sken * protection for data written into sockets. 4098849Sken */ 4198849Sken 4298849Sken#include <sys/param.h> 4398849Sken#include <sys/systm.h> 4498849Sken#include <sys/kernel.h> 4598849Sken#include <sys/proc.h> 4698849Sken#include <sys/lock.h> 4798849Sken#include <sys/mutex.h> 4898849Sken#include <sys/mbuf.h> 4998849Sken#include <sys/socketvar.h> 5098849Sken#include <sys/uio.h> 5198849Sken 5298849Sken#include <vm/vm.h> 5398849Sken#include <vm/vm_param.h> 5498849Sken#include <vm/pmap.h> 5598849Sken#include <vm/vm_map.h> 5698849Sken#include <vm/vm_page.h> 5798849Sken#include <vm/vm_object.h> 5898849Sken#if 0 5998849Sken#include <vm/vm_pager.h> 6098849Sken#include <vm/vm_kern.h> 6198849Sken#include <vm/vm_extern.h> 6298849Sken#include <vm/vm_zone.h> 6398849Sken#include <vm/swap_pager.h> 6498849Sken#endif 6598849Sken 6698849Sken 6798849Skenstruct netsend_cow_stats { 6898849Sken int attempted; 6998849Sken int fail_not_mapped; 7098849Sken int fail_wired; 7198849Sken int fail_not_anon; 7298849Sken int fail_pmap_cow; 7398849Sken int fail_pg_error; 7498849Sken int fail_kva; 7598849Sken int free_post_exit; 7698849Sken int success; 7798849Sken int iodone; 7898849Sken int freed; 7998849Sken}; 8098849Sken 8198849Skenstatic struct netsend_cow_stats socow_stats = {0,0,0,0,0,0,0,0,0,0,0}; 8298849Sken 8398849Skenextern struct sf_buf *sf_bufs; 8498849Skenextern vm_offset_t sf_base; 8598849Sken#define dtosf(x) (&sf_bufs[((uintptr_t)(x) - (uintptr_t)sf_base) >> PAGE_SHIFT]) 8698849Skenvoid sf_buf_free(caddr_t addr, void *args); 8798849Skenstruct sf_buf *sf_buf_alloc(void); 8898849Skenstatic void socow_iodone(caddr_t addr, void *args); 8998849Sken 9098849Skenstatic void 9198849Skensocow_iodone(caddr_t addr, void *args) 9298849Sken{ 9398849Sken int s; 9498849Sken struct sf_buf *sf; 9598849Sken 9698849Sken vm_offset_t paddr; 9798849Sken vm_page_t pp; 9898849Sken 9998849Sken sf = dtosf(addr); 10098849Sken paddr = vtophys((vm_offset_t)addr); 10198849Sken pp = PHYS_TO_VM_PAGE(paddr); 10298849Sken s = splvm(); 10398849Sken /* remove COW mapping */ 10498849Sken vm_page_cowclear(pp); 10598849Sken vm_object_deallocate(pp->object); 10698849Sken splx(s); 10798849Sken /* note that sf_buf_free() unwires the page for us*/ 10898849Sken sf_buf_free(addr, NULL); 10998849Sken socow_stats.iodone++; 11098849Sken} 11198849Sken 11298849Skenint 11398849Skensocow_setup(struct mbuf *m0, struct uio *uio) 11498849Sken{ 11598849Sken struct sf_buf *sf; 11698849Sken vm_page_t pp; 11798849Sken vm_offset_t pa; 11898849Sken struct iovec *iov; 11998849Sken struct vmspace *vmspace; 12098849Sken struct vm_map *map; 12198849Sken vm_offset_t uva; 12298849Sken int s; 12398849Sken 12498849Sken vmspace = curproc->p_vmspace;; 12598849Sken map = &vmspace->vm_map; 12698849Sken uva = (vm_offset_t) uio->uio_iov->iov_base; 12798849Sken 12898849Sken s = splvm(); 12998849Sken 13098849Sken /* 13198849Sken * verify page is mapped & not already wired for i/o 13298849Sken */ 13398849Sken socow_stats.attempted++; 13498849Sken pa=pmap_extract(map->pmap, uva); 13598849Sken if(!pa) { 13698849Sken socow_stats.fail_not_mapped++; 13798849Sken splx(s); 13898849Sken return(0); 13998849Sken } 14098849Sken pp = PHYS_TO_VM_PAGE(pa); 14198849Sken 14298849Sken sf = sf_buf_alloc(); 14398849Sken sf->m = pp; 14498849Sken pmap_qenter(sf->kva, &pp, 1); 14598849Sken 14698849Sken /* 14798849Sken * set up COW 14898849Sken */ 14998849Sken vm_page_cowsetup(pp); 15098849Sken 15198849Sken /* 15298849Sken * wire the page for I/O 15398849Sken */ 15498849Sken vm_page_wire(pp); 15598849Sken 15698849Sken /* 15798849Sken * prevent the process from exiting on us. 15898849Sken */ 15998849Sken vm_object_reference(pp->object); 16098849Sken 16198849Sken /* 16298849Sken * attach to mbuf 16398849Sken */ 16498849Sken m0->m_data = (caddr_t)sf->kva; 16598849Sken m0->m_len = PAGE_SIZE; 16698849Sken MEXTADD(m0, sf->kva, PAGE_SIZE, socow_iodone, NULL, 0, EXT_SFBUF); 16798849Sken socow_stats.success++; 16898849Sken 16998849Sken iov = uio->uio_iov; 17098849Sken iov->iov_base += PAGE_SIZE; 17198849Sken iov->iov_len -= PAGE_SIZE; 17298849Sken uio->uio_resid -= PAGE_SIZE; 17398849Sken uio->uio_offset += PAGE_SIZE; 17498849Sken if (iov->iov_len == 0) { 17598849Sken uio->uio_iov++; 17698849Sken uio->uio_iovcnt--; 17798849Sken } 17898849Sken 17998849Sken splx(s); 18098849Sken return(1); 18198849Sken} 182