uipc_cow.c revision 216702
1139804Simp/*-- 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 216702 2010-12-26 01:42:52Z 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> 53151559Salc#include <vm/vm_extern.h> 5498849Sken#include <vm/vm_param.h> 5598849Sken#include <vm/pmap.h> 5698849Sken#include <vm/vm_map.h> 5798849Sken#include <vm/vm_page.h> 5898849Sken#include <vm/vm_object.h> 5998849Sken 6098849Sken 6198849Skenstruct netsend_cow_stats { 6298849Sken int attempted; 6398849Sken int fail_not_mapped; 64124639Sgallatin int fail_sf_buf; 6598849Sken int success; 6698849Sken int iodone; 6798849Sken}; 6898849Sken 69124639Sgallatinstatic struct netsend_cow_stats socow_stats; 7098849Sken 7199008Salfredstatic void socow_iodone(void *addr, void *args); 7298849Sken 7398849Skenstatic void 7499008Salfredsocow_iodone(void *addr, void *args) 7598849Sken{ 7698849Sken struct sf_buf *sf; 7798849Sken vm_page_t pp; 7898849Sken 79112316Salc sf = args; 80122780Salc pp = sf_buf_page(sf); 81127150Salc sf_buf_free(sf); 8298849Sken /* remove COW mapping */ 83207548Salc vm_page_lock(pp); 8498849Sken vm_page_cowclear(pp); 85127150Salc vm_page_unwire(pp, 0); 86127150Salc /* 87127150Salc * Check for the object going away on us. This can 88127150Salc * happen since we don't hold a reference to it. 89127150Salc * If so, we're responsible for freeing the page. 90127150Salc */ 91127150Salc if (pp->wire_count == 0 && pp->object == NULL) 92127150Salc vm_page_free(pp); 93207548Salc vm_page_unlock(pp); 9498849Sken socow_stats.iodone++; 9598849Sken} 9698849Sken 9798849Skenint 9898849Skensocow_setup(struct mbuf *m0, struct uio *uio) 9998849Sken{ 10098849Sken struct sf_buf *sf; 10198849Sken vm_page_t pp; 10298849Sken struct iovec *iov; 10398849Sken struct vmspace *vmspace; 10498849Sken struct vm_map *map; 105147009Sgallatin vm_offset_t offset, uva; 106216699Salc vm_size_t len; 10798849Sken 108151559Salc socow_stats.attempted++; 109113267Salc vmspace = curproc->p_vmspace; 11098849Sken map = &vmspace->vm_map; 11198849Sken uva = (vm_offset_t) uio->uio_iov->iov_base; 112147009Sgallatin offset = uva & PAGE_MASK; 113216699Salc len = PAGE_SIZE - offset; 11498849Sken 115151559Salc /* 116151559Salc * Verify that access to the given address is allowed from user-space. 117151559Salc */ 118216702Salc if (vm_fault_quick_hold_pages(map, uva, len, VM_PROT_READ, &pp, 1) < 119216699Salc 0) { 12098849Sken socow_stats.fail_not_mapped++; 12198849Sken return(0); 12298849Sken } 12398849Sken 12498849Sken /* 12598849Sken * set up COW 12698849Sken */ 127207410Skmacy vm_page_lock(pp); 128186719Skib if (vm_page_cowsetup(pp) != 0) { 129186719Skib vm_page_unhold(pp); 130207410Skmacy vm_page_unlock(pp); 131186719Skib return (0); 132186719Skib } 13398849Sken 13498849Sken /* 13598849Sken * wire the page for I/O 13698849Sken */ 13798849Sken vm_page_wire(pp); 138151579Salc vm_page_unhold(pp); 139207410Skmacy vm_page_unlock(pp); 140112382Sgallatin /* 141112382Sgallatin * Allocate an sf buf 142112382Sgallatin */ 143137372Salc sf = sf_buf_alloc(pp, SFB_CATCH); 144207708Salc if (sf == NULL) { 145207548Salc vm_page_lock(pp); 146124639Sgallatin vm_page_cowclear(pp); 147124639Sgallatin vm_page_unwire(pp, 0); 148124639Sgallatin /* 149124639Sgallatin * Check for the object going away on us. This can 150124639Sgallatin * happen since we don't hold a reference to it. 151124639Sgallatin * If so, we're responsible for freeing the page. 152124639Sgallatin */ 153124639Sgallatin if (pp->wire_count == 0 && pp->object == NULL) 154124639Sgallatin vm_page_free(pp); 155207548Salc vm_page_unlock(pp); 156124639Sgallatin socow_stats.fail_sf_buf++; 157124639Sgallatin return(0); 158124639Sgallatin } 15998849Sken /* 16098849Sken * attach to mbuf 16198849Sken */ 162175872Sphk MEXTADD(m0, sf_buf_kva(sf), PAGE_SIZE, socow_iodone, 163175872Sphk (void*)sf_buf_kva(sf), sf, M_RDONLY, EXT_SFBUF); 164216699Salc m0->m_len = len; 165147009Sgallatin m0->m_data = (caddr_t)sf_buf_kva(sf) + offset; 16698849Sken socow_stats.success++; 16798849Sken 16898849Sken iov = uio->uio_iov; 169147009Sgallatin iov->iov_base = (char *)iov->iov_base + m0->m_len; 170147009Sgallatin iov->iov_len -= m0->m_len; 171147009Sgallatin uio->uio_resid -= m0->m_len; 172147009Sgallatin uio->uio_offset += m0->m_len; 17398849Sken if (iov->iov_len == 0) { 17498849Sken uio->uio_iov++; 17598849Sken uio->uio_iovcnt--; 17698849Sken } 17798849Sken 178147009Sgallatin return(m0->m_len); 17998849Sken} 180