Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/vm/sg_pager.c
39478 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2009 Hudson River Trading LLC
5
* Written by: John H. Baldwin <[email protected]>
6
* All rights reserved.
7
*
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions
10
* are met:
11
* 1. Redistributions of source code must retain the above copyright
12
* notice, this list of conditions and the following disclaimer.
13
* 2. Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in the
15
* documentation and/or other materials provided with the distribution.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*/
29
30
#include <sys/cdefs.h>
31
/*
32
* This pager manages OBJT_SG objects. These objects are backed by
33
* a scatter/gather list of physical address ranges.
34
*/
35
36
#include <sys/param.h>
37
#include <sys/event.h>
38
#include <sys/lock.h>
39
#include <sys/mutex.h>
40
#include <sys/rwlock.h>
41
#include <sys/sglist.h>
42
#include <sys/user.h>
43
#include <sys/vmmeter.h>
44
45
#include <vm/vm.h>
46
#include <vm/vm_param.h>
47
#include <vm/vm_object.h>
48
#include <vm/vm_page.h>
49
#include <vm/vm_pager.h>
50
#include <vm/vm_phys.h>
51
#include <vm/uma.h>
52
53
static vm_object_t sg_pager_alloc(void *, vm_ooffset_t, vm_prot_t,
54
vm_ooffset_t, struct ucred *);
55
static void sg_pager_dealloc(vm_object_t);
56
static int sg_pager_getpages(vm_object_t, vm_page_t *, int, int *, int *);
57
static void sg_pager_putpages(vm_object_t, vm_page_t *, int,
58
int, int *);
59
static boolean_t sg_pager_haspage(vm_object_t, vm_pindex_t, int *,
60
int *);
61
62
const struct pagerops sgpagerops = {
63
.pgo_kvme_type = KVME_TYPE_SG,
64
.pgo_alloc = sg_pager_alloc,
65
.pgo_dealloc = sg_pager_dealloc,
66
.pgo_getpages = sg_pager_getpages,
67
.pgo_putpages = sg_pager_putpages,
68
.pgo_haspage = sg_pager_haspage,
69
};
70
71
static vm_object_t
72
sg_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot,
73
vm_ooffset_t foff, struct ucred *cred)
74
{
75
struct sglist *sg;
76
vm_object_t object;
77
vm_pindex_t npages, pindex;
78
int i;
79
80
/*
81
* Offset should be page aligned.
82
*/
83
if (foff & PAGE_MASK)
84
return (NULL);
85
86
/*
87
* The scatter/gather list must only include page-aligned
88
* ranges.
89
*/
90
npages = 0;
91
sg = handle;
92
for (i = 0; i < sg->sg_nseg; i++) {
93
if ((sg->sg_segs[i].ss_paddr % PAGE_SIZE) != 0 ||
94
(sg->sg_segs[i].ss_len % PAGE_SIZE) != 0)
95
return (NULL);
96
npages += sg->sg_segs[i].ss_len / PAGE_SIZE;
97
}
98
99
/*
100
* The scatter/gather list has a fixed size. Refuse requests
101
* to map beyond that.
102
*/
103
size = round_page(size);
104
pindex = OFF_TO_IDX(foff) + OFF_TO_IDX(size);
105
if (pindex > npages || pindex < OFF_TO_IDX(foff) ||
106
pindex < OFF_TO_IDX(size))
107
return (NULL);
108
109
/*
110
* Allocate a new object and associate it with the
111
* scatter/gather list. It is ok for our purposes to have
112
* multiple VM objects associated with the same scatter/gather
113
* list because scatter/gather lists are static. This is also
114
* simpler than ensuring a unique object per scatter/gather
115
* list.
116
*/
117
object = vm_object_allocate(OBJT_SG, npages);
118
object->handle = sglist_hold(sg);
119
TAILQ_INIT(&object->un_pager.sgp.sgp_pglist);
120
return (object);
121
}
122
123
static void
124
sg_pager_dealloc(vm_object_t object)
125
{
126
struct sglist *sg;
127
vm_page_t m;
128
129
/*
130
* Free up our fake pages.
131
*/
132
while ((m = TAILQ_FIRST(&object->un_pager.sgp.sgp_pglist)) != 0) {
133
if (vm_page_busy_acquire(m, VM_ALLOC_WAITFAIL) == 0)
134
continue;
135
TAILQ_REMOVE(&object->un_pager.sgp.sgp_pglist, m, plinks.q);
136
vm_page_putfake(m);
137
}
138
139
sg = object->handle;
140
sglist_free(sg);
141
object->handle = NULL;
142
object->type = OBJT_DEAD;
143
}
144
145
static int
146
sg_pager_getpages(vm_object_t object, vm_page_t *m, int count, int *rbehind,
147
int *rahead)
148
{
149
struct sglist *sg;
150
vm_page_t m_paddr, page;
151
vm_pindex_t offset;
152
vm_paddr_t paddr;
153
vm_memattr_t memattr;
154
size_t space;
155
int i;
156
157
/* Since our haspage reports zero after/before, the count is 1. */
158
KASSERT(count == 1, ("%s: count %d", __func__, count));
159
/* Handle is stable while paging is in progress. */
160
sg = object->handle;
161
memattr = object->memattr;
162
offset = m[0]->pindex;
163
164
/*
165
* Lookup the physical address of the requested page. An initial
166
* value of '1' instead of '0' is used so we can assert that the
167
* page is found since '0' can be a valid page-aligned physical
168
* address.
169
*/
170
space = 0;
171
paddr = 1;
172
for (i = 0; i < sg->sg_nseg; i++) {
173
if (space + sg->sg_segs[i].ss_len <= (offset * PAGE_SIZE)) {
174
space += sg->sg_segs[i].ss_len;
175
continue;
176
}
177
paddr = sg->sg_segs[i].ss_paddr + offset * PAGE_SIZE - space;
178
break;
179
}
180
KASSERT(paddr != 1, ("invalid SG page index"));
181
182
/* If "paddr" is a real page, perform a sanity check on "memattr". */
183
if ((m_paddr = vm_phys_paddr_to_vm_page(paddr)) != NULL &&
184
pmap_page_get_memattr(m_paddr) != memattr) {
185
memattr = pmap_page_get_memattr(m_paddr);
186
printf(
187
"WARNING: A device driver has set \"memattr\" inconsistently.\n");
188
}
189
190
/* Return a fake page for the requested page. */
191
KASSERT(!(m[0]->flags & PG_FICTITIOUS),
192
("backing page for SG is fake"));
193
194
/* Construct a new fake page. */
195
page = vm_page_getfake(paddr, memattr);
196
VM_OBJECT_WLOCK(object);
197
TAILQ_INSERT_TAIL(&object->un_pager.sgp.sgp_pglist, page, plinks.q);
198
vm_page_replace(page, object, offset, m[0]);
199
VM_OBJECT_WUNLOCK(object);
200
m[0] = page;
201
vm_page_valid(page);
202
203
if (rbehind)
204
*rbehind = 0;
205
if (rahead)
206
*rahead = 0;
207
208
return (VM_PAGER_OK);
209
}
210
211
static void
212
sg_pager_putpages(vm_object_t object, vm_page_t *m, int count,
213
int flags, int *rtvals)
214
{
215
216
panic("sg_pager_putpage called");
217
}
218
219
static boolean_t
220
sg_pager_haspage(vm_object_t object, vm_pindex_t pindex, int *before,
221
int *after)
222
{
223
224
if (before != NULL)
225
*before = 0;
226
if (after != NULL)
227
*after = 0;
228
return (TRUE);
229
}
230
231