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
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>
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
*,
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
= {
54 .unmap
= seghole_unmap
,
56 .fault
= seghole_fault
,
57 .faulta
= seghole_faulta
,
58 .setprot
= seghole_setprot
,
59 .checkprot
= seghole_checkprot
,
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.
76 seghole_create(struct seg
**segpp
, void *argsp
)
78 struct seg
*seg
= *segpp
;
79 seghole_crargs_t
*crargs
= argsp
;
82 data
= kmem_alloc(sizeof (seghole_data_t
), KM_SLEEP
);
83 data
->shd_name
= crargs
->name
;
85 seg
->s_ops
= &seghole_ops
;
87 seg
->s_flags
= S_HOLE
;
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
;
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
) {
121 /* Shrinking from low address side */
122 if (addr
== seg
->s_base
) {
128 /* Shrinking from high address side */
129 if ((addr
+ len
) == (seg
->s_base
+ seg
->s_size
)) {
134 /* Do not tolerate splitting the segment */
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
));
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
));
161 seghole_faulta(struct seg
*seg
, caddr_t addr
)
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
));
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
));
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 */
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
));
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.
215 seghole_getprot(struct seg
*seg
, caddr_t addr
, size_t len
, uint_t
*protv
)
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;
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.
246 seghole_gettype(struct seg
*seg
, caddr_t addr
)
248 return (MAP_PRIVATE
);
253 seghole_getvp(struct seg
*seg
, caddr_t addr
, struct vnode
**vpp
)
255 ASSERT(seg
->s_as
&& AS_LOCK_HELD(seg
->s_as
));
262 seghole_advise(struct seg
*seg
, caddr_t addr
, size_t len
, uint_t behav
)
269 seghole_pagelock(struct seg
*seg
, caddr_t addr
, size_t len
, struct page
***ppp
,
270 enum lock_type type
, enum seg_rw rw
)
277 seghole_setpagesize(struct seg
*seg
, caddr_t addr
, size_t len
, uint_t szc
)