xref: /illumos-gate/usr/src/uts/common/vm/seg_hole.c (revision 284ce987)
1*284ce987SPatrick Mooney /*
2*284ce987SPatrick Mooney  * This file and its contents are supplied under the terms of the
3*284ce987SPatrick Mooney  * Common Development and Distribution License ("CDDL"), version 1.0.
4*284ce987SPatrick Mooney  * You may only use this file in accordance with the terms of version
5*284ce987SPatrick Mooney  * 1.0 of the CDDL.
6*284ce987SPatrick Mooney  *
7*284ce987SPatrick Mooney  * A full copy of the text of the CDDL should have accompanied this
8*284ce987SPatrick Mooney  * source.  A copy of the CDDL is also available via the Internet at
9*284ce987SPatrick Mooney  * http://www.illumos.org/license/CDDL.
10*284ce987SPatrick Mooney  */
11*284ce987SPatrick Mooney 
12*284ce987SPatrick Mooney /*
13*284ce987SPatrick Mooney  * Copyright 2018 Joyent, Inc.
14*284ce987SPatrick Mooney  */
15*284ce987SPatrick Mooney 
16*284ce987SPatrick Mooney 
17*284ce987SPatrick Mooney #include <sys/types.h>
18*284ce987SPatrick Mooney #include <sys/param.h>
19*284ce987SPatrick Mooney #include <sys/errno.h>
20*284ce987SPatrick Mooney #include <sys/cred.h>
21*284ce987SPatrick Mooney #include <sys/kmem.h>
22*284ce987SPatrick Mooney #include <sys/lgrp.h>
23*284ce987SPatrick Mooney #include <sys/mman.h>
24*284ce987SPatrick Mooney 
25*284ce987SPatrick Mooney #include <vm/hat.h>
26*284ce987SPatrick Mooney #include <vm/as.h>
27*284ce987SPatrick Mooney #include <vm/seg.h>
28*284ce987SPatrick Mooney #include <vm/seg_hole.h>
29*284ce987SPatrick Mooney 
30*284ce987SPatrick Mooney 
31*284ce987SPatrick Mooney static int seghole_dup(struct seg *, struct seg *);
32*284ce987SPatrick Mooney static int seghole_unmap(struct seg *, caddr_t, size_t);
33*284ce987SPatrick Mooney static void seghole_free(struct seg *);
34*284ce987SPatrick Mooney static faultcode_t seghole_fault(struct hat *, struct seg *, caddr_t, size_t,
35*284ce987SPatrick Mooney     enum fault_type, enum seg_rw);
36*284ce987SPatrick Mooney static faultcode_t seghole_faulta(struct seg *, caddr_t);
37*284ce987SPatrick Mooney static int seghole_setprot(struct seg *, caddr_t, size_t, uint_t);
38*284ce987SPatrick Mooney static int seghole_checkprot(struct seg *, caddr_t, size_t, uint_t);
39*284ce987SPatrick Mooney static int seghole_sync(struct seg *, caddr_t, size_t, int, uint_t);
40*284ce987SPatrick Mooney static size_t seghole_incore(struct seg *, caddr_t, size_t, char *);
41*284ce987SPatrick Mooney static int seghole_lockop(struct seg *, caddr_t, size_t, int, int, ulong_t *,
42*284ce987SPatrick Mooney     size_t);
43*284ce987SPatrick Mooney static int seghole_getprot(struct seg *, caddr_t, size_t, uint_t *);
44*284ce987SPatrick Mooney static u_offset_t seghole_getoffset(struct seg *, caddr_t);
45*284ce987SPatrick Mooney static int seghole_gettype(struct seg *, caddr_t);
46*284ce987SPatrick Mooney static int seghole_getvp(struct seg *, caddr_t, struct vnode **);
47*284ce987SPatrick Mooney static int seghole_advise(struct seg *, caddr_t, size_t, uint_t);
48*284ce987SPatrick Mooney static void seghole_dump(struct seg *);
49*284ce987SPatrick Mooney static int seghole_pagelock(struct seg *, caddr_t, size_t, struct page ***,
50*284ce987SPatrick Mooney     enum lock_type, enum seg_rw);
51*284ce987SPatrick Mooney static int seghole_setpagesize(struct seg *, caddr_t, size_t, uint_t);
52*284ce987SPatrick Mooney static int seghole_capable(struct seg *, segcapability_t);
53*284ce987SPatrick Mooney 
54*284ce987SPatrick Mooney static struct seg_ops seghole_ops = {
55*284ce987SPatrick Mooney 	seghole_dup,
56*284ce987SPatrick Mooney 	seghole_unmap,
57*284ce987SPatrick Mooney 	seghole_free,
58*284ce987SPatrick Mooney 	seghole_fault,
59*284ce987SPatrick Mooney 	seghole_faulta,
60*284ce987SPatrick Mooney 	seghole_setprot,
61*284ce987SPatrick Mooney 	seghole_checkprot,
62*284ce987SPatrick Mooney 	NULL,			/* kluster: disabled */
63*284ce987SPatrick Mooney 	NULL,			/* swapout: disabled */
64*284ce987SPatrick Mooney 	seghole_sync,
65*284ce987SPatrick Mooney 	seghole_incore,
66*284ce987SPatrick Mooney 	seghole_lockop,
67*284ce987SPatrick Mooney 	seghole_getprot,
68*284ce987SPatrick Mooney 	seghole_getoffset,
69*284ce987SPatrick Mooney 	seghole_gettype,
70*284ce987SPatrick Mooney 	seghole_getvp,
71*284ce987SPatrick Mooney 	seghole_advise,
72*284ce987SPatrick Mooney 	seghole_dump,
73*284ce987SPatrick Mooney 	seghole_pagelock,
74*284ce987SPatrick Mooney 	seghole_setpagesize,
75*284ce987SPatrick Mooney 	NULL,			/* getmemid: disabled */
76*284ce987SPatrick Mooney 	NULL,			/* getpolicy: disabled */
77*284ce987SPatrick Mooney 	seghole_capable,
78*284ce987SPatrick Mooney 	seg_inherit_notsup
79*284ce987SPatrick Mooney };
80*284ce987SPatrick Mooney 
81*284ce987SPatrick Mooney /*
82*284ce987SPatrick Mooney  * Create a hole in the AS.
83*284ce987SPatrick Mooney  */
84*284ce987SPatrick Mooney int
seghole_create(struct seg ** segpp,void * argsp)85*284ce987SPatrick Mooney seghole_create(struct seg **segpp, void *argsp)
86*284ce987SPatrick Mooney {
87*284ce987SPatrick Mooney 	struct seg *seg = *segpp;
88*284ce987SPatrick Mooney 	seghole_crargs_t *crargs = argsp;
89*284ce987SPatrick Mooney 	seghole_data_t *data;
90*284ce987SPatrick Mooney 
91*284ce987SPatrick Mooney 	data = kmem_alloc(sizeof (seghole_data_t), KM_SLEEP);
92*284ce987SPatrick Mooney 	data->shd_name = crargs->name;
93*284ce987SPatrick Mooney 
94*284ce987SPatrick Mooney 	seg->s_ops = &seghole_ops;
95*284ce987SPatrick Mooney 	seg->s_data = data;
96*284ce987SPatrick Mooney 	seg->s_flags = S_HOLE;
97*284ce987SPatrick Mooney 
98*284ce987SPatrick Mooney 	return (0);
99*284ce987SPatrick Mooney }
100*284ce987SPatrick Mooney 
101*284ce987SPatrick Mooney static int
seghole_dup(struct seg * seg,struct seg * newseg)102*284ce987SPatrick Mooney seghole_dup(struct seg *seg, struct seg *newseg)
103*284ce987SPatrick Mooney {
104*284ce987SPatrick Mooney 	seghole_data_t *shd = (seghole_data_t *)seg->s_data;
105*284ce987SPatrick Mooney 	seghole_data_t *newshd;
106*284ce987SPatrick Mooney 
107*284ce987SPatrick Mooney 	ASSERT(seg->s_as && AS_WRITE_HELD(seg->s_as));
108*284ce987SPatrick Mooney 
109*284ce987SPatrick Mooney 	newshd = kmem_zalloc(sizeof (seghole_data_t), KM_SLEEP);
110*284ce987SPatrick Mooney 	newshd->shd_name = shd->shd_name;
111*284ce987SPatrick Mooney 
112*284ce987SPatrick Mooney 	newseg->s_ops = seg->s_ops;
113*284ce987SPatrick Mooney 	newseg->s_data = newshd;
114*284ce987SPatrick Mooney 	newseg->s_flags = S_HOLE;
115*284ce987SPatrick Mooney 
116*284ce987SPatrick Mooney 	return (0);
117*284ce987SPatrick Mooney }
118*284ce987SPatrick Mooney 
119*284ce987SPatrick Mooney static int
seghole_unmap(struct seg * seg,caddr_t addr,size_t len)120*284ce987SPatrick Mooney seghole_unmap(struct seg *seg, caddr_t addr, size_t len)
121*284ce987SPatrick Mooney {
122*284ce987SPatrick Mooney 	ASSERT(seg->s_as && AS_WRITE_HELD(seg->s_as));
123*284ce987SPatrick Mooney 
124*284ce987SPatrick Mooney 	/* Entire segment is being unmapped */
125*284ce987SPatrick Mooney 	if (addr == seg->s_base && len == seg->s_size) {
126*284ce987SPatrick Mooney 		seg_free(seg);
127*284ce987SPatrick Mooney 		return (0);
128*284ce987SPatrick Mooney 	}
129*284ce987SPatrick Mooney 
130*284ce987SPatrick Mooney 	/* Shrinking from low address side */
131*284ce987SPatrick Mooney 	if (addr == seg->s_base) {
132*284ce987SPatrick Mooney 		seg->s_base += len;
133*284ce987SPatrick Mooney 		seg->s_size -= len;
134*284ce987SPatrick Mooney 		return (0);
135*284ce987SPatrick Mooney 	}
136*284ce987SPatrick Mooney 
137*284ce987SPatrick Mooney 	/* Shrinking from high address side */
138*284ce987SPatrick Mooney 	if ((addr + len) == (seg->s_base + seg->s_size)) {
139*284ce987SPatrick Mooney 		seg->s_size -= len;
140*284ce987SPatrick Mooney 		return (0);
141*284ce987SPatrick Mooney 	}
142*284ce987SPatrick Mooney 
143*284ce987SPatrick Mooney 	/* Do not tolerate splitting the segment */
144*284ce987SPatrick Mooney 	return (EINVAL);
145*284ce987SPatrick Mooney }
146*284ce987SPatrick Mooney 
147*284ce987SPatrick Mooney static void
seghole_free(struct seg * seg)148*284ce987SPatrick Mooney seghole_free(struct seg *seg)
149*284ce987SPatrick Mooney {
150*284ce987SPatrick Mooney 	seghole_data_t *data = (seghole_data_t *)seg->s_data;
151*284ce987SPatrick Mooney 
152*284ce987SPatrick Mooney 	ASSERT(data != NULL);
153*284ce987SPatrick Mooney 
154*284ce987SPatrick Mooney 	kmem_free(data, sizeof (*data));
155*284ce987SPatrick Mooney 	seg->s_data = NULL;
156*284ce987SPatrick Mooney }
157*284ce987SPatrick Mooney 
158*284ce987SPatrick Mooney /* ARGSUSED */
159*284ce987SPatrick Mooney static faultcode_t
seghole_fault(struct hat * hat,struct seg * seg,caddr_t addr,size_t len,enum fault_type type,enum seg_rw tw)160*284ce987SPatrick Mooney seghole_fault(struct hat *hat, struct seg *seg, caddr_t addr, size_t len,
161*284ce987SPatrick Mooney     enum fault_type type, enum seg_rw tw)
162*284ce987SPatrick Mooney {
163*284ce987SPatrick Mooney 	ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
164*284ce987SPatrick Mooney 
165*284ce987SPatrick Mooney 	return (FC_NOMAP);
166*284ce987SPatrick Mooney }
167*284ce987SPatrick Mooney 
168*284ce987SPatrick Mooney /* ARGSUSED */
169*284ce987SPatrick Mooney static faultcode_t
seghole_faulta(struct seg * seg,caddr_t addr)170*284ce987SPatrick Mooney seghole_faulta(struct seg *seg, caddr_t addr)
171*284ce987SPatrick Mooney {
172*284ce987SPatrick Mooney 	return (FC_NOMAP);
173*284ce987SPatrick Mooney }
174*284ce987SPatrick Mooney 
175*284ce987SPatrick Mooney /* ARGSUSED */
176*284ce987SPatrick Mooney static int
seghole_setprot(struct seg * seg,caddr_t addr,size_t len,uint_t prot)177*284ce987SPatrick Mooney seghole_setprot(struct seg *seg, caddr_t addr, size_t len, uint_t prot)
178*284ce987SPatrick Mooney {
179*284ce987SPatrick Mooney 	ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
180*284ce987SPatrick Mooney 
181*284ce987SPatrick Mooney 	return (ENOMEM);
182*284ce987SPatrick Mooney }
183*284ce987SPatrick Mooney 
184*284ce987SPatrick Mooney /* ARGSUSED */
185*284ce987SPatrick Mooney static int
seghole_checkprot(struct seg * seg,caddr_t addr,size_t len,uint_t prot)186*284ce987SPatrick Mooney seghole_checkprot(struct seg *seg, caddr_t addr, size_t len, uint_t prot)
187*284ce987SPatrick Mooney {
188*284ce987SPatrick Mooney 	ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
189*284ce987SPatrick Mooney 
190*284ce987SPatrick Mooney 	return (ENOMEM);
191*284ce987SPatrick Mooney }
192*284ce987SPatrick Mooney 
193*284ce987SPatrick Mooney /* ARGSUSED */
194*284ce987SPatrick Mooney static int
seghole_sync(struct seg * seg,caddr_t addr,size_t len,int attr,uint_t flags)195*284ce987SPatrick Mooney seghole_sync(struct seg *seg, caddr_t addr, size_t len, int attr, uint_t flags)
196*284ce987SPatrick Mooney {
197*284ce987SPatrick Mooney 	/* Always succeed since there are no backing store to sync */
198*284ce987SPatrick Mooney 	return (0);
199*284ce987SPatrick Mooney }
200*284ce987SPatrick Mooney 
201*284ce987SPatrick Mooney /* ARGSUSED */
202*284ce987SPatrick Mooney static size_t
seghole_incore(struct seg * seg,caddr_t addr,size_t len,char * vec)203*284ce987SPatrick Mooney seghole_incore(struct seg *seg, caddr_t addr, size_t len, char *vec)
204*284ce987SPatrick Mooney {
205*284ce987SPatrick Mooney 	ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
206*284ce987SPatrick Mooney 
207*284ce987SPatrick Mooney 	return (0);
208*284ce987SPatrick Mooney }
209*284ce987SPatrick Mooney 
210*284ce987SPatrick Mooney /* ARGSUSED */
211*284ce987SPatrick Mooney static int
seghole_lockop(struct seg * seg,caddr_t addr,size_t len,int attr,int op,ulong_t * lockmap,size_t pos)212*284ce987SPatrick Mooney seghole_lockop(struct seg *seg, caddr_t addr, size_t len, int attr, int op,
213*284ce987SPatrick Mooney     ulong_t *lockmap, size_t pos)
214*284ce987SPatrick Mooney {
215*284ce987SPatrick Mooney 	/*
216*284ce987SPatrick Mooney 	 * Emit an error consistent with there being no segment in this hole in
217*284ce987SPatrick Mooney 	 * the AS.  The MC_LOCKAS and MC_UNLOCKAS commands will explicitly skip
218*284ce987SPatrick Mooney 	 * hole segments, allowing such operations to proceed as expected.
219*284ce987SPatrick Mooney 	 */
220*284ce987SPatrick Mooney 	return (ENOMEM);
221*284ce987SPatrick Mooney }
222*284ce987SPatrick Mooney 
223*284ce987SPatrick Mooney static int
seghole_getprot(struct seg * seg,caddr_t addr,size_t len,uint_t * protv)224*284ce987SPatrick Mooney seghole_getprot(struct seg *seg, caddr_t addr, size_t len, uint_t *protv)
225*284ce987SPatrick Mooney {
226*284ce987SPatrick Mooney 	size_t pgno;
227*284ce987SPatrick Mooney 
228*284ce987SPatrick Mooney 	ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
229*284ce987SPatrick Mooney 
230*284ce987SPatrick Mooney 	/*
231*284ce987SPatrick Mooney 	 * Few SEGOP_GETPROT callers actually check for an error, so it's
232*284ce987SPatrick Mooney 	 * necessary to report zeroed protection for the length of the request.
233*284ce987SPatrick Mooney 	 */
234*284ce987SPatrick Mooney 	pgno = seg_page(seg, addr + len) - seg_page(seg, addr) + 1;
235*284ce987SPatrick Mooney 	while (pgno > 0) {
236*284ce987SPatrick Mooney 		protv[--pgno] = 0;
237*284ce987SPatrick Mooney 	}
238*284ce987SPatrick Mooney 
239*284ce987SPatrick Mooney 	return (ENOMEM);
240*284ce987SPatrick Mooney }
241*284ce987SPatrick Mooney 
242*284ce987SPatrick Mooney /* ARGSUSED */
243*284ce987SPatrick Mooney static u_offset_t
seghole_getoffset(struct seg * seg,caddr_t addr)244*284ce987SPatrick Mooney seghole_getoffset(struct seg *seg, caddr_t addr)
245*284ce987SPatrick Mooney {
246*284ce987SPatrick Mooney 	/*
247*284ce987SPatrick Mooney 	 * To avoid leaking information about the layout of the kernel address
248*284ce987SPatrick Mooney 	 * space, always report '0' as the offset.
249*284ce987SPatrick Mooney 	 */
250*284ce987SPatrick Mooney 	return (0);
251*284ce987SPatrick Mooney }
252*284ce987SPatrick Mooney 
253*284ce987SPatrick Mooney /* ARGSUSED */
254*284ce987SPatrick Mooney static int
seghole_gettype(struct seg * seg,caddr_t addr)255*284ce987SPatrick Mooney seghole_gettype(struct seg *seg, caddr_t addr)
256*284ce987SPatrick Mooney {
257*284ce987SPatrick Mooney 	return (MAP_PRIVATE);
258*284ce987SPatrick Mooney }
259*284ce987SPatrick Mooney 
260*284ce987SPatrick Mooney /* ARGSUSED */
261*284ce987SPatrick Mooney static int
seghole_getvp(struct seg * seg,caddr_t addr,struct vnode ** vpp)262*284ce987SPatrick Mooney seghole_getvp(struct seg *seg, caddr_t addr, struct vnode **vpp)
263*284ce987SPatrick Mooney {
264*284ce987SPatrick Mooney 	ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
265*284ce987SPatrick Mooney 
266*284ce987SPatrick Mooney 	return (ENOMEM);
267*284ce987SPatrick Mooney }
268*284ce987SPatrick Mooney 
269*284ce987SPatrick Mooney /* ARGSUSED */
270*284ce987SPatrick Mooney static int
seghole_advise(struct seg * seg,caddr_t addr,size_t len,uint_t behav)271*284ce987SPatrick Mooney seghole_advise(struct seg *seg, caddr_t addr, size_t len, uint_t behav)
272*284ce987SPatrick Mooney {
273*284ce987SPatrick Mooney 	return (ENOMEM);
274*284ce987SPatrick Mooney }
275*284ce987SPatrick Mooney 
276*284ce987SPatrick Mooney /* ARGSUSED */
277*284ce987SPatrick Mooney static void
seghole_dump(struct seg * seg)278*284ce987SPatrick Mooney seghole_dump(struct seg *seg)
279*284ce987SPatrick Mooney {
280*284ce987SPatrick Mooney 	/* There's nothing to dump from a hole in the AS */
281*284ce987SPatrick Mooney }
282*284ce987SPatrick Mooney 
283*284ce987SPatrick Mooney /* ARGSUSED */
284*284ce987SPatrick Mooney static int
seghole_pagelock(struct seg * seg,caddr_t addr,size_t len,struct page *** ppp,enum lock_type type,enum seg_rw rw)285*284ce987SPatrick Mooney seghole_pagelock(struct seg *seg, caddr_t addr, size_t len, struct page ***ppp,
286*284ce987SPatrick Mooney     enum lock_type type, enum seg_rw rw)
287*284ce987SPatrick Mooney {
288*284ce987SPatrick Mooney 	return (EFAULT);
289*284ce987SPatrick Mooney }
290*284ce987SPatrick Mooney 
291*284ce987SPatrick Mooney /* ARGSUSED */
292*284ce987SPatrick Mooney static int
seghole_setpagesize(struct seg * seg,caddr_t addr,size_t len,uint_t szc)293*284ce987SPatrick Mooney seghole_setpagesize(struct seg *seg, caddr_t addr, size_t len, uint_t szc)
294*284ce987SPatrick Mooney {
295*284ce987SPatrick Mooney 	return (ENOMEM);
296*284ce987SPatrick Mooney }
297*284ce987SPatrick Mooney 
298*284ce987SPatrick Mooney /* ARGSUSED */
299*284ce987SPatrick Mooney static int
seghole_capable(struct seg * seg,segcapability_t capability)300*284ce987SPatrick Mooney seghole_capable(struct seg *seg, segcapability_t capability)
301*284ce987SPatrick Mooney {
302*284ce987SPatrick Mooney 	/* no special capablities */
303*284ce987SPatrick Mooney 	return (0);
304*284ce987SPatrick Mooney }