2 * Copyright (c) 1998 David Greenman. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * $DragonFly: src/sys/kern/kern_sfbuf.c,v 1.1 2003/12/10 23:48:07 hsu Exp $
28 #include <sys/param.h>
29 #include <sys/types.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/malloc.h>
33 #include <sys/queue.h>
34 #include <sys/sfbuf.h>
36 #include <vm/vm_extern.h>
37 #include <vm/vm_kern.h>
38 #include <vm/vm_page.h>
41 static void sf_buf_init(void *arg);
42 SYSINIT(sock_sf, SI_SUB_MBUF, SI_ORDER_ANY, sf_buf_init, NULL)
44 LIST_HEAD(sf_buf_list, sf_buf);
47 * A hash table of active sendfile(2) buffers
49 static struct sf_buf_list *sf_buf_hashtable;
50 static u_long sf_buf_hashmask;
52 #define SF_BUF_HASH(m) (((m) - vm_page_array) & sf_buf_hashmask)
54 static TAILQ_HEAD(, sf_buf) sf_buf_freelist;
55 static u_int sf_buf_alloc_want;
57 static vm_offset_t sf_base;
58 static struct sf_buf *sf_bufs;
61 * Allocate a pool of sf_bufs (sendfile(2) or "super-fast" if you prefer. :-))
64 sf_buf_init(void *arg)
68 sf_buf_hashtable = hashinit(nsfbufs, M_TEMP, &sf_buf_hashmask);
69 TAILQ_INIT(&sf_buf_freelist);
70 sf_base = kmem_alloc_pageable(kernel_map, nsfbufs * PAGE_SIZE);
71 sf_bufs = malloc(nsfbufs * sizeof(struct sf_buf), M_TEMP,
73 for (i = 0; i < nsfbufs; i++) {
74 sf_bufs[i].kva = sf_base + i * PAGE_SIZE;
75 TAILQ_INSERT_TAIL(&sf_buf_freelist, &sf_bufs[i], free_entry);
80 * Get an sf_buf from the freelist. Will block if none are available.
83 sf_buf_alloc(struct vm_page *m)
85 struct sf_buf_list *hash_chain;
91 hash_chain = &sf_buf_hashtable[SF_BUF_HASH(m)];
92 LIST_FOREACH(sf, hash_chain, list_entry) {
94 if (sf->refcnt == 0) {
95 /* reclaim cached entry off freelist */
96 TAILQ_REMOVE(&sf_buf_freelist, sf, free_entry);
99 goto done; /* found existing mapping */
104 * Didn't find old mapping. Get a buffer off the freelist.
106 while ((sf = TAILQ_FIRST(&sf_buf_freelist)) == NULL) {
108 error = tsleep(&sf_buf_freelist, PCATCH, "sfbufa", 0);
111 /* If we got a signal, don't risk going back to sleep. */
115 TAILQ_REMOVE(&sf_buf_freelist, sf, free_entry);
117 if (sf->m != NULL) /* remove previous mapping from hash table */
118 LIST_REMOVE(sf, list_entry);
119 LIST_INSERT_HEAD(hash_chain, sf, list_entry);
122 pmap_qenter(sf->kva, &sf->m, 1);
128 #define dtosf(x) (&sf_bufs[((uintptr_t)(x) - (uintptr_t)sf_base) >> PAGE_SHIFT])
131 sf_buf_ref(caddr_t addr, u_int size)
137 panic("sf_buf_ref: referencing a free sf_buf");
142 * Lose a reference to an sf_buf. When none left, detach mapped page
143 * and release resources back to the system.
145 * Must be called at splimp.
148 sf_buf_free(caddr_t addr, u_int size)
156 panic("sf_buf_free: freeing free sf_buf");
158 if (sf->refcnt == 0) {
161 vm_page_unwire(m, 0);
163 * Check for the object going away on us. This can
164 * happen since we don't hold a reference to it.
165 * If so, we're responsible for freeing the page.
167 if (m->wire_count == 0 && m->object == NULL)
171 TAILQ_INSERT_TAIL(&sf_buf_freelist, sf, free_entry);
172 if (sf_buf_alloc_want > 0)
173 wakeup_one(&sf_buf_freelist);