Merge illumos-gate
[unleashed.git] / kernel / vm / seg_hole.c
blob27f124ef328d6dddd6329d0a1b1e278af4216fed
1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
13 * Copyright 2018 Joyent, Inc.
17 #include <sys/types.h>
18 #include <sys/param.h>
19 #include <sys/errno.h>
20 #include <sys/cred.h>
21 #include <sys/kmem.h>
22 #include <sys/lgrp.h>
23 #include <sys/mman.h>
25 #include <vm/hat.h>
26 #include <vm/as.h>
27 #include <vm/seg.h>
28 #include <vm/seg_hole.h>
31 static int seghole_dup(struct seg *, struct seg *);
32 static int seghole_unmap(struct seg *, caddr_t, size_t);
33 static void seghole_free(struct seg *);
34 static faultcode_t seghole_fault(struct hat *, struct seg *, caddr_t, size_t,
35 enum fault_type, enum seg_rw);
36 static faultcode_t seghole_faulta(struct seg *, caddr_t);
37 static int seghole_setprot(struct seg *, caddr_t, size_t, uint_t);
38 static int seghole_checkprot(struct seg *, caddr_t, size_t, uint_t);
39 static int seghole_sync(struct seg *, caddr_t, size_t, int, uint_t);
40 static size_t seghole_incore(struct seg *, caddr_t, size_t, char *);
41 static int seghole_lockop(struct seg *, caddr_t, size_t, int, int, ulong_t *,
42 size_t);
43 static int seghole_getprot(struct seg *, caddr_t, size_t, uint_t *);
44 static uoff_t seghole_getoffset(struct seg *, caddr_t);
45 static int seghole_gettype(struct seg *, caddr_t);
46 static int seghole_getvp(struct seg *, caddr_t, struct vnode **);
47 static int seghole_advise(struct seg *, caddr_t, size_t, uint_t);
48 static int seghole_pagelock(struct seg *, caddr_t, size_t, struct page ***,
49 enum lock_type, enum seg_rw);
50 static int seghole_setpagesize(struct seg *, caddr_t, size_t, uint_t);
52 static struct seg_ops seghole_ops = {
53 .dup = seghole_dup,
54 .unmap = seghole_unmap,
55 .free = seghole_free,
56 .fault = seghole_fault,
57 .faulta = seghole_faulta,
58 .setprot = seghole_setprot,
59 .checkprot = seghole_checkprot,
60 .sync = seghole_sync,
61 .incore = seghole_incore,
62 .lockop = seghole_lockop,
63 .getprot = seghole_getprot,
64 .getoffset = seghole_getoffset,
65 .gettype = seghole_gettype,
66 .getvp = seghole_getvp,
67 .advise = seghole_advise,
68 .pagelock = seghole_pagelock,
69 .setpagesize = seghole_setpagesize,
73 * Create a hole in the AS.
75 int
76 seghole_create(struct seg **segpp, void *argsp)
78 struct seg *seg = *segpp;
79 seghole_crargs_t *crargs = argsp;
80 seghole_data_t *data;
82 data = kmem_alloc(sizeof (seghole_data_t), KM_SLEEP);
83 data->shd_name = crargs->name;
85 seg->s_ops = &seghole_ops;
86 seg->s_data = data;
87 seg->s_flags = S_HOLE;
89 return (0);
92 static int
93 seghole_dup(struct seg *seg, struct seg *newseg)
95 seghole_data_t *shd = (seghole_data_t *)seg->s_data;
96 seghole_data_t *newshd;
98 ASSERT(seg->s_as && AS_WRITE_HELD(seg->s_as));
100 newshd = kmem_zalloc(sizeof (seghole_data_t), KM_SLEEP);
101 newshd->shd_name = shd->shd_name;
103 newseg->s_ops = seg->s_ops;
104 newseg->s_data = newshd;
105 newseg->s_flags = S_HOLE;
107 return (0);
110 static int
111 seghole_unmap(struct seg *seg, caddr_t addr, size_t len)
113 ASSERT(seg->s_as && AS_WRITE_HELD(seg->s_as));
115 /* Entire segment is being unmapped */
116 if (addr == seg->s_base && len == seg->s_size) {
117 seg_free(seg);
118 return (0);
121 /* Shrinking from low address side */
122 if (addr == seg->s_base) {
123 seg->s_base += len;
124 seg->s_size -= len;
125 return (0);
128 /* Shrinking from high address side */
129 if ((addr + len) == (seg->s_base + seg->s_size)) {
130 seg->s_size -= len;
131 return (0);
134 /* Do not tolerate splitting the segment */
135 return (EINVAL);
138 static void
139 seghole_free(struct seg *seg)
141 seghole_data_t *data = (seghole_data_t *)seg->s_data;
143 ASSERT(data != NULL);
145 kmem_free(data, sizeof (*data));
146 seg->s_data = NULL;
149 /* ARGSUSED */
150 static faultcode_t
151 seghole_fault(struct hat *hat, struct seg *seg, caddr_t addr, size_t len,
152 enum fault_type type, enum seg_rw tw)
154 ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
156 return (FC_NOMAP);
159 /* ARGSUSED */
160 static faultcode_t
161 seghole_faulta(struct seg *seg, caddr_t addr)
163 return (FC_NOMAP);
166 /* ARGSUSED */
167 static int
168 seghole_setprot(struct seg *seg, caddr_t addr, size_t len, uint_t prot)
170 ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
172 return (ENOMEM);
175 /* ARGSUSED */
176 static int
177 seghole_checkprot(struct seg *seg, caddr_t addr, size_t len, uint_t prot)
179 ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
181 return (ENOMEM);
184 /* ARGSUSED */
185 static int
186 seghole_sync(struct seg *seg, caddr_t addr, size_t len, int attr, uint_t flags)
188 /* Always succeed since there are no backing store to sync */
189 return (0);
192 /* ARGSUSED */
193 static size_t
194 seghole_incore(struct seg *seg, caddr_t addr, size_t len, char *vec)
196 ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
198 return (0);
201 /* ARGSUSED */
202 static int
203 seghole_lockop(struct seg *seg, caddr_t addr, size_t len, int attr, int op,
204 ulong_t *lockmap, size_t pos)
207 * Emit an error consistent with there being no segment in this hole in
208 * the AS. The MC_LOCKAS and MC_UNLOCKAS commands will explicitly skip
209 * hole segments, allowing such operations to proceed as expected.
211 return (ENOMEM);
214 static int
215 seghole_getprot(struct seg *seg, caddr_t addr, size_t len, uint_t *protv)
217 size_t pgno;
219 ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
222 * Few SEGOP_GETPROT callers actually check for an error, so it's
223 * necessary to report zeroed protection for the length of the request.
225 pgno = seg_page(seg, addr + len) - seg_page(seg, addr) + 1;
226 while (pgno > 0) {
227 protv[--pgno] = 0;
230 return (ENOMEM);
233 /* ARGSUSED */
234 static uoff_t
235 seghole_getoffset(struct seg *seg, caddr_t addr)
238 * To avoid leaking information about the layout of the kernel address
239 * space, always report '0' as the offset.
241 return (0);
244 /* ARGSUSED */
245 static int
246 seghole_gettype(struct seg *seg, caddr_t addr)
248 return (MAP_PRIVATE);
251 /* ARGSUSED */
252 static int
253 seghole_getvp(struct seg *seg, caddr_t addr, struct vnode **vpp)
255 ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
257 return (ENOMEM);
260 /* ARGSUSED */
261 static int
262 seghole_advise(struct seg *seg, caddr_t addr, size_t len, uint_t behav)
264 return (ENOMEM);
267 /* ARGSUSED */
268 static int
269 seghole_pagelock(struct seg *seg, caddr_t addr, size_t len, struct page ***ppp,
270 enum lock_type type, enum seg_rw rw)
272 return (EFAULT);
275 /* ARGSUSED */
276 static int
277 seghole_setpagesize(struct seg *seg, caddr_t addr, size_t len, uint_t szc)
279 return (ENOMEM);