uipc_cow.c revision 127150
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. 1699479Sgallatin * 3. The name of Duke University may not be used to endorse or promote 1798849Sken * products derived from this software without specific prior written 1898849Sken * permission. 1998849Sken * 2098849Sken * THIS SOFTWARE IS PROVIDED BY DUKE UNIVERSITY ``AS IS'' AND ANY 2198849Sken * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2298849Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2398849Sken * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DUKE UNIVERSITY BE LIABLE 2498849Sken * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2598849Sken * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2698849Sken * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITSOR BUSINESS 2798849Sken * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 2898849Sken * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2998849Sken * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 3098849Sken * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3198849Sken */ 32116182Sobrien 3398849Sken/* 3498849Sken * This is a set of routines for enabling and disabling copy on write 3598849Sken * protection for data written into sockets. 3698849Sken */ 3798849Sken 38116182Sobrien#include <sys/cdefs.h> 39116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/uipc_cow.c 127150 2004-03-17 23:25:04Z alc $"); 40116182Sobrien 4198849Sken#include <sys/param.h> 4298849Sken#include <sys/systm.h> 4398849Sken#include <sys/kernel.h> 4498849Sken#include <sys/proc.h> 4598849Sken#include <sys/lock.h> 4698849Sken#include <sys/mutex.h> 4798849Sken#include <sys/mbuf.h> 48122780Salc#include <sys/sf_buf.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 5998849Sken 6098849Skenstruct netsend_cow_stats { 6198849Sken int attempted; 6298849Sken int fail_not_mapped; 63124639Sgallatin int fail_sf_buf; 6498849Sken int success; 6598849Sken int iodone; 6698849Sken}; 6798849Sken 68124639Sgallatinstatic struct netsend_cow_stats socow_stats; 6998849Sken 7099008Salfredstatic void socow_iodone(void *addr, void *args); 7198849Sken 7298849Skenstatic void 7399008Salfredsocow_iodone(void *addr, void *args) 7498849Sken{ 7598849Sken struct sf_buf *sf; 7698849Sken vm_page_t pp; 7798849Sken 78112316Salc sf = args; 79122780Salc pp = sf_buf_page(sf); 80127150Salc sf_buf_free(sf); 8198849Sken /* remove COW mapping */ 82102835Salc vm_page_lock_queues(); 8398849Sken vm_page_cowclear(pp); 84127150Salc vm_page_unwire(pp, 0); 85127150Salc /* 86127150Salc * Check for the object going away on us. This can 87127150Salc * happen since we don't hold a reference to it. 88127150Salc * If so, we're responsible for freeing the page. 89127150Salc */ 90127150Salc if (pp->wire_count == 0 && pp->object == NULL) 91127150Salc vm_page_free(pp); 92102835Salc vm_page_unlock_queues(); 9398849Sken socow_stats.iodone++; 9498849Sken} 9598849Sken 9698849Skenint 9798849Skensocow_setup(struct mbuf *m0, struct uio *uio) 9898849Sken{ 9998849Sken struct sf_buf *sf; 10098849Sken vm_page_t pp; 101112569Sjake vm_paddr_t pa; 10298849Sken struct iovec *iov; 10398849Sken struct vmspace *vmspace; 10498849Sken struct vm_map *map; 10598849Sken vm_offset_t uva; 10698849Sken int s; 10798849Sken 108113267Salc vmspace = curproc->p_vmspace; 10998849Sken map = &vmspace->vm_map; 11098849Sken uva = (vm_offset_t) uio->uio_iov->iov_base; 11198849Sken 11298849Sken s = splvm(); 11398849Sken 11498849Sken /* 11598849Sken * verify page is mapped & not already wired for i/o 11698849Sken */ 11798849Sken socow_stats.attempted++; 11898849Sken pa=pmap_extract(map->pmap, uva); 11998849Sken if(!pa) { 12098849Sken socow_stats.fail_not_mapped++; 12198849Sken splx(s); 12298849Sken return(0); 12398849Sken } 12498849Sken pp = PHYS_TO_VM_PAGE(pa); 12598849Sken 12698849Sken /* 12798849Sken * set up COW 12898849Sken */ 129102835Salc vm_page_lock_queues(); 13098849Sken vm_page_cowsetup(pp); 13198849Sken 13298849Sken /* 13398849Sken * wire the page for I/O 13498849Sken */ 13598849Sken vm_page_wire(pp); 13699902Salc vm_page_unlock_queues(); 13798849Sken 138112382Sgallatin /* 139112382Sgallatin * Allocate an sf buf 140112382Sgallatin */ 141112778Salc sf = sf_buf_alloc(pp); 142124639Sgallatin if (!sf) { 143124639Sgallatin vm_page_lock_queues(); 144124639Sgallatin vm_page_cowclear(pp); 145124639Sgallatin vm_page_unwire(pp, 0); 146124639Sgallatin /* 147124639Sgallatin * Check for the object going away on us. This can 148124639Sgallatin * happen since we don't hold a reference to it. 149124639Sgallatin * If so, we're responsible for freeing the page. 150124639Sgallatin */ 151124639Sgallatin if (pp->wire_count == 0 && pp->object == NULL) 152124639Sgallatin vm_page_free(pp); 153124639Sgallatin vm_page_unlock_queues(); 154124639Sgallatin socow_stats.fail_sf_buf++; 155124639Sgallatin splx(s); 156124639Sgallatin return(0); 157124639Sgallatin } 15898849Sken /* 15998849Sken * attach to mbuf 16098849Sken */ 161122780Salc m0->m_data = (caddr_t)sf_buf_kva(sf); 16298849Sken m0->m_len = PAGE_SIZE; 163122780Salc MEXTADD(m0, sf_buf_kva(sf), PAGE_SIZE, socow_iodone, sf, M_RDONLY, 164122780Salc EXT_SFBUF); 16598849Sken socow_stats.success++; 16698849Sken 16798849Sken iov = uio->uio_iov; 168104908Smike iov->iov_base = (char *)iov->iov_base + PAGE_SIZE; 16998849Sken iov->iov_len -= PAGE_SIZE; 17098849Sken uio->uio_resid -= PAGE_SIZE; 17198849Sken uio->uio_offset += PAGE_SIZE; 17298849Sken if (iov->iov_len == 0) { 17398849Sken uio->uio_iov++; 17498849Sken uio->uio_iovcnt--; 17598849Sken } 17698849Sken 17798849Sken splx(s); 17898849Sken return(1); 17998849Sken} 180