1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
|
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
#ifndef _VM_AS_H
#define _VM_AS_H
#include <sys/watchpoint.h>
#include <vm/seg.h>
#include <vm/faultcode.h>
#include <vm/hat.h>
#include <sys/avl.h>
#include <sys/proc.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* VM - Address spaces.
*/
/*
* Each address space consists of a sorted list of segments
* and machine dependent address translation information.
*
* All the hard work is in the segment drivers and the
* hardware address translation code.
*
* The segment list is represented as an AVL tree.
*
* The address space lock (a_lock) is a long term lock which serializes
* access to certain operations (as_map, as_unmap) and protects the
* underlying generic segment data (seg.h) along with some fields in the
* address space structure as shown below:
*
* address space structure segment structure
*
* a_segtree s_base
* a_size s_size
* a_lastgap s_link
* a_seglast s_ops
* s_as
* s_data
*
* The address space contents lock (a_contents) is a short term
* lock that protects most of the data in the address space structure.
* This lock is always acquired after the "a_lock" in all situations
* except while dealing with AS_CLAIMGAP to avoid deadlocks.
*
* The following fields are protected by this lock:
*
* a_flags (AS_PAGLCK, AS_CLAIMGAP, etc.)
* a_unmapwait
* a_seglast
*
* The address space lock (a_lock) is always held prior to any segment
* operation. Some segment drivers use the address space lock to protect
* some or all of their segment private data, provided the version of
* "a_lock" (read vs. write) is consistent with the use of the data.
*
* The following fields are protected by the hat layer lock:
*
* a_vbits
* a_hat
* a_hrm
*/
struct as {
kmutex_t a_contents; /* protect certain fields in the structure */
uchar_t a_flags; /* as attributes */
uchar_t a_vbits; /* used for collecting statistics */
kcondvar_t a_cv; /* used by as_rangelock */
struct hat *a_hat; /* hat structure */
struct hrmstat *a_hrm; /* ref and mod bits */
caddr_t a_userlimit; /* highest allowable address in this as */
struct seg *a_seglast; /* last segment hit on the addr space */
krwlock_t a_lock; /* protects segment related fields */
size_t a_size; /* total size of address space */
struct seg *a_lastgap; /* last seg found by as_gap() w/ AS_HI (mmap) */
struct seg *a_lastgaphl; /* last seg saved in as_gap() either for */
/* AS_HI or AS_LO used in as_addseg() */
avl_tree_t a_segtree; /* segments in this address space. (AVL tree) */
avl_tree_t a_wpage; /* watched pages (procfs) */
uchar_t a_updatedir; /* mappings changed, rebuild a_objectdir */
timespec_t a_updatetime; /* time when mappings last changed */
vnode_t **a_objectdir; /* object directory (procfs) */
size_t a_sizedir; /* size of object directory */
struct as_callback *a_callbacks; /* callback list */
proc_t *a_proc; /* back pointer to proc */
size_t a_resvsize; /* size of reserved part of address space */
};
#define AS_PAGLCK 0x80
#define AS_CLAIMGAP 0x40
#define AS_UNMAPWAIT 0x20
#define AS_NEEDSPURGE 0x10 /* mostly for seg_nf, see as_purge() */
#define AS_NOUNMAPWAIT 0x02
#define AS_ISPGLCK(as) ((as)->a_flags & AS_PAGLCK)
#define AS_ISCLAIMGAP(as) ((as)->a_flags & AS_CLAIMGAP)
#define AS_ISUNMAPWAIT(as) ((as)->a_flags & AS_UNMAPWAIT)
#define AS_ISNOUNMAPWAIT(as) ((as)->a_flags & AS_NOUNMAPWAIT)
#define AS_SETPGLCK(as) ((as)->a_flags |= AS_PAGLCK)
#define AS_SETCLAIMGAP(as) ((as)->a_flags |= AS_CLAIMGAP)
#define AS_SETUNMAPWAIT(as) ((as)->a_flags |= AS_UNMAPWAIT)
#define AS_SETNOUNMAPWAIT(as) ((as)->a_flags |= AS_NOUNMAPWAIT)
#define AS_CLRPGLCK(as) ((as)->a_flags &= ~AS_PAGLCK)
#define AS_CLRCLAIMGAP(as) ((as)->a_flags &= ~AS_CLAIMGAP)
#define AS_CLRUNMAPWAIT(as) ((as)->a_flags &= ~AS_UNMAPWAIT)
#define AS_CLRNOUNMAPWAIT(as) ((as)->a_flags &= ~AS_NOUNMAPWAIT)
#define AS_TYPE_64BIT(as) \
(((as)->a_userlimit > (caddr_t)UINT32_MAX) ? 1 : 0)
/*
* Flags for as_map/as_map_ansegs
*/
#define AS_MAP_NO_LPOOB ((uint_t)-1)
#define AS_MAP_HEAP ((uint_t)-2)
#define AS_MAP_STACK ((uint_t)-3)
/*
* The as_callback is the basic structure which supports the ability to
* inform clients of specific events pertaining to address space management.
* A user calls as_add_callback to register an address space callback
* for a range of pages, specifying the events that need to occur.
* When as_do_callbacks is called and finds a 'matching' entry, the
* callback is called once, and the callback function MUST call
* as_delete_callback when all callback activities are complete.
* The thread calling as_do_callbacks blocks until the as_delete_callback
* is called. This allows for asynchorous events to subside before the
* as_do_callbacks thread continues.
*
* An example of the need for this is a driver which has done long-term
* locking of memory. Address space management operations (events) such
* as as_free, as_umap, and as_setprot will block indefinitely until the
* pertinent memory is unlocked. The callback mechanism provides the
* way to inform the driver of the event so that the driver may do the
* necessary unlocking.
*
* The contents of this structure is protected by a_contents lock
*/
typedef void (*callback_func_t)(struct as *, void *, uint_t);
struct as_callback {
struct as_callback *ascb_next; /* list link */
uint_t ascb_events; /* event types */
callback_func_t ascb_func; /* callback function */
void *ascb_arg; /* callback argument */
caddr_t ascb_saddr; /* start address */
size_t ascb_len; /* address range */
};
/*
* Callback events
*/
#define AS_FREE_EVENT 0x1
#define AS_SETPROT_EVENT 0x2
#define AS_UNMAP_EVENT 0x4
#define AS_CALLBACK_CALLED ((uint_t)(1U << (8 * sizeof (uint_t) - 1U)))
#define AS_UNMAPWAIT_EVENT \
(AS_FREE_EVENT | AS_SETPROT_EVENT | AS_UNMAP_EVENT)
#define AS_ALL_EVENT \
(AS_FREE_EVENT | AS_SETPROT_EVENT | AS_UNMAP_EVENT)
/* Return code values for as_callback_delete */
enum as_cbdelete_rc {
AS_CALLBACK_DELETED,
AS_CALLBACK_NOTFOUND,
AS_CALLBACK_DELETE_DEFERRED
};
#ifdef _KERNEL
/*
* Flags for as_gap.
*/
#define AH_DIR 0x1 /* direction flag mask */
#define AH_LO 0x0 /* find lowest hole */
#define AH_HI 0x1 /* find highest hole */
#define AH_CONTAIN 0x2 /* hole must contain `addr' */
extern struct as kas; /* kernel's address space */
/*
* Macros for address space locking. Note that we use RW_READER_STARVEWRITER
* whenever we acquire the address space lock as reader to assure that it can
* be used without regard to lock order in conjunction with filesystem locks.
* This allows filesystems to safely induce user-level page faults with
* filesystem locks held while concurrently allowing filesystem entry points
* acquiring those same locks to be called with the address space lock held as
* reader. RW_READER_STARVEWRITER thus prevents reader/reader+RW_WRITE_WANTED
* deadlocks in the style of fop_write()+as_fault()/as_*()+fop_putpage() and
* fop_read()+as_fault()/as_*()+fop_getpage(). (See the Big Theory Statement
* in rwlock.c for more information on the semantics of and motivation behind
* RW_READER_STARVEWRITER.)
*/
#define AS_LOCK_ENTER(as, type) rw_enter(&(as)->a_lock, \
(type) == RW_READER ? RW_READER_STARVEWRITER : (type))
#define AS_LOCK_EXIT(as) rw_exit(&(as)->a_lock)
#define AS_LOCK_DESTROY(as) rw_destroy(&(as)->a_lock)
#define AS_LOCK_TRYENTER(as, type) rw_tryenter(&(as)->a_lock, \
(type) == RW_READER ? RW_READER_STARVEWRITER : (type))
/*
* Macros to test lock states.
*/
#define AS_LOCK_HELD(as) RW_LOCK_HELD(&(as)->a_lock)
#define AS_READ_HELD(as) RW_READ_HELD(&(as)->a_lock)
#define AS_WRITE_HELD(as) RW_WRITE_HELD(&(as)->a_lock)
/*
* macros to walk thru segment lists
*/
#define AS_SEGFIRST(as) avl_first(&(as)->a_segtree)
#define AS_SEGNEXT(as, seg) AVL_NEXT(&(as)->a_segtree, (seg))
#define AS_SEGPREV(as, seg) AVL_PREV(&(as)->a_segtree, (seg))
void as_init(void);
void as_avlinit(struct as *);
struct seg *as_segat(struct as *as, caddr_t addr);
void as_rangelock(struct as *as);
void as_rangeunlock(struct as *as);
struct as *as_alloc();
void as_free(struct as *as);
int as_dup(struct as *as, struct proc *forkedproc);
struct seg *as_findseg(struct as *as, caddr_t addr, int tail);
int as_addseg(struct as *as, struct seg *newseg);
struct seg *as_removeseg(struct as *as, struct seg *seg);
faultcode_t as_fault(struct hat *hat, struct as *as, caddr_t addr, size_t size,
enum fault_type type, enum seg_rw rw);
faultcode_t as_faulta(struct as *as, caddr_t addr, size_t size);
int as_setprot(struct as *as, caddr_t addr, size_t size, uint_t prot);
int as_checkprot(struct as *as, caddr_t addr, size_t size, uint_t prot);
int as_unmap(struct as *as, caddr_t addr, size_t size);
int as_map(struct as *as, caddr_t addr, size_t size, int ((*crfp)()),
void *argsp);
void as_purge(struct as *as);
int as_gap(struct as *as, size_t minlen, caddr_t *basep, size_t *lenp,
uint_t flags, caddr_t addr);
int as_gap_aligned(struct as *as, size_t minlen, caddr_t *basep,
size_t *lenp, uint_t flags, caddr_t addr, size_t align,
size_t redzone, size_t off);
int as_memory(struct as *as, caddr_t *basep, size_t *lenp);
size_t as_swapout(struct as *as);
int as_incore(struct as *as, caddr_t addr, size_t size, char *vec,
size_t *sizep);
int as_ctl(struct as *as, caddr_t addr, size_t size, int func, int attr,
uintptr_t arg, ulong_t *lock_map, size_t pos);
int as_pagelock(struct as *as, struct page ***ppp, caddr_t addr,
size_t size, enum seg_rw rw);
void as_pageunlock(struct as *as, struct page **pp, caddr_t addr,
size_t size, enum seg_rw rw);
int as_setpagesize(struct as *as, caddr_t addr, size_t size, uint_t szc,
boolean_t wait);
int as_set_default_lpsize(struct as *as, caddr_t addr, size_t size);
void as_setwatch(struct as *as);
void as_clearwatch(struct as *as);
int as_getmemid(struct as *, caddr_t, memid_t *);
int as_add_callback(struct as *, void (*)(), void *, uint_t,
caddr_t, size_t, int);
uint_t as_delete_callback(struct as *, void *);
#endif /* _KERNEL */
#ifdef __cplusplus
}
#endif
#endif /* _VM_AS_H */
|