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
|
/*
* 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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* 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_SEG_MAP_H
#define _VM_SEG_MAP_H
#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef __cplusplus
extern "C" {
#endif
/*
* When segmap is created it is possible to program its behavior,
* using the create args [needed for performance reasons].
* Segmap creates n lists of pages.
* For VAC machines, there will be at least one free list
* per color. If more than one free list per color is needed,
* set nfreelist as needed.
*
* For PAC machines, it will be treated as VAC with only one
* color- every page is of the same color. Again, set nfreelist
* to get more than one free list.
*/
struct segmap_crargs {
uint_t prot;
uint_t shmsize; /* shm_alignment for VAC, 0 for PAC. */
uint_t nfreelist; /* number of freelist per color, >= 1 */
};
#include <vm/kpm.h>
#include <vm/vpm.h>
/*
* Each smap struct represents a MAXBSIZE sized mapping to the
* <sm_vp, sm_off> given in the structure. The location of the
* the structure in the array gives the virtual address of the
* mapping. Structure rearranged for 64bit sm_off.
*/
struct smap {
kmutex_t sm_mtx; /* protect non-list fields */
struct vnode *sm_vp; /* vnode pointer (if mapped) */
struct smap *sm_hash; /* hash pointer */
struct smap *sm_next; /* next pointer */
struct smap *sm_prev; /* previous pointer */
u_offset_t sm_off; /* file offset for mapping */
ushort_t sm_bitmap; /* bit map for locked translations */
ushort_t sm_refcnt; /* reference count for uses */
ushort_t sm_flags; /* smap flags */
ushort_t sm_free_ndx; /* freelist */
#ifdef SEGKPM_SUPPORT
struct kpme sm_kpme; /* segkpm */
#endif
};
#ifdef SEGKPM_SUPPORT
#define GET_KPME(smp) (&(smp)->sm_kpme)
#define sm_kpme_next sm_kpme.kpe_next
#define sm_kpme_prev sm_kpme.kpe_prev
#define sm_kpme_page sm_kpme.kpe_page
#else
#define GET_KPME(smp) ((struct kpme *)NULL)
#endif
/* sm_flags */
#define SM_KPM_NEWPAGE 0x00000001 /* page created in segmap_getmapft */
#define SM_NOTKPM_RELEASED 0x00000002 /* released smap not in segkpm mode */
#define SM_QNDX_ZERO 0x00000004 /* on the index 0 freelist */
#define SM_READ_DATA 0x00000010 /* page created for read */
#define SM_WRITE_DATA 0x00000020 /* page created for write */
/*
* Multiple smap free lists are maintained so that allocations
* will scale with cpu count. Each free list is made up of 2 queues
* so that allocations and deallocations can proceed concurrently.
* Each queue structure is padded to 64 bytes to avoid false sharing.
*/
#define SM_FREEQ_PAD (64 - sizeof (struct smap *) - sizeof (kmutex_t))
struct sm_freeq {
struct smap *smq_free; /* points into freelist */
kmutex_t smq_mtx; /* protects smq_free */
char smq_pad[SM_FREEQ_PAD];
};
struct smfree {
struct sm_freeq sm_freeq[2]; /* alloc and release queues */
struct sm_freeq *sm_allocq; /* current allocq */
struct sm_freeq *sm_releq; /* current releq */
kcondvar_t sm_free_cv;
ushort_t sm_want; /* someone wants a slot of this color */
};
/*
* Cached smaps are kept on hash chains to enable fast reclaim lookups.
*/
struct smaphash {
kmutex_t sh_mtx; /* protects this hash chain */
struct smap *sh_hash_list; /* start of hash chain */
};
/*
* (Semi) private data maintained by the segmap driver per SEGMENT mapping
* All fields in segmap_data are read-only after the segment is created.
*
*/
struct segmap_data {
struct smap *smd_sm; /* array of smap structures */
long smd_npages; /* size of smap array */
struct smfree *smd_free; /* ptr to freelist header array */
struct smaphash *smd_hash; /* ptr to hash header array */
int smd_nfree; /* number of free lists */
uchar_t smd_prot; /* protections for all smap's */
};
/*
* Statistics for segmap operations.
*
* No explicit locking to protect these stats.
*/
struct segmapcnt {
kstat_named_t smp_fault; /* number of segmap_faults */
kstat_named_t smp_faulta; /* number of segmap_faultas */
kstat_named_t smp_getmap; /* number of segmap_getmaps */
kstat_named_t smp_get_use; /* getmaps that reuse existing map */
kstat_named_t smp_get_reclaim; /* getmaps that do a reclaim */
kstat_named_t smp_get_reuse; /* getmaps that reuse a slot */
kstat_named_t smp_get_unused; /* getmaps that reuse existing map */
kstat_named_t smp_get_nofree; /* getmaps with no free slots */
kstat_named_t smp_rel_async; /* releases that are async */
kstat_named_t smp_rel_write; /* releases that write */
kstat_named_t smp_rel_free; /* releases that free */
kstat_named_t smp_rel_abort; /* releases that abort */
kstat_named_t smp_rel_dontneed; /* releases with dontneed set */
kstat_named_t smp_release; /* releases with no other action */
kstat_named_t smp_pagecreate; /* pagecreates */
kstat_named_t smp_free_notfree; /* pages not freed in */
/* segmap_pagefree */
kstat_named_t smp_free_dirty; /* dirty pages freeed */
/* in segmap_pagefree */
kstat_named_t smp_free; /* clean pages freeed in */
/* segmap_pagefree */
kstat_named_t smp_stolen; /* segmap_getmapflt() stole */
/* from get_free_smp() */
kstat_named_t smp_get_nomtx; /* free smaps but no mutex */
};
/*
* These are flags used on release. Some of these might get handled
* by segment operations needed for msync (when we figure them out).
* SM_ASYNC modifies SM_WRITE. SM_DONTNEED modifies SM_FREE. SM_FREE
* and SM_INVAL as well as SM_FREE and SM_DESTROY are mutually exclusive.
* SM_DESTROY behaves like SM_INVAL but also forces the pages to be
* destroyed -- this prevents them from being written to the backing
* store.
*/
#define SM_WRITE 0x01 /* write back the pages upon release */
#define SM_ASYNC 0x02 /* do the write asynchronously */
#define SM_FREE 0x04 /* put pages back on free list */
#define SM_INVAL 0x08 /* invalidate page (no caching) */
#define SM_DONTNEED 0x10 /* less likely to be needed soon */
#define SM_DESTROY 0x20 /* invalidate page, don't write back */
/*
* These are the forcefault flags used on getmapflt.
*
* The orginal semantic was extended to allow using the segkpm mapping
* scheme w/o a major segmap interface change for MAXBSIZE == PAGESIZE
* (which is required to enable segkpm for MAXBSIZE > PAGESIZE).
* Most segmap consumers needn't to be changed at all or only need to
* be changed slightly to take advantage of segkpm. Because the segkpm
* virtual address is based on the physical address of a page, a page is
* required to determine the virtual address (return value). Pages mapped
* with segkpm are always at least read locked and are hence protected
* from pageout or fsflush from segmap_getmap until segmap_release. This
* implies, that the segkpm mappings are locked within this period too.
* No trap driven segmap_fault's are possible in segkpm mode.
*
* The following combinations of "forcefault" and "rw" allow segkpm mode.
* (1) SM_FAULT, S_READ
* (2) SM_FAULT, S_WRITE
* (3) SM_PAGECREATE, S_WRITE
* (4) SM_LOCKPROTO, {S_READ, S_WRITE, S_OTHER}
*
* The regular additional operations (come in pairs in most of the cases):
* . segmap_pagecreate/segmap_pageunlock
* . segmap_fault(F_SOFTLOCK)/segmap_fault(F_SOFTUNLOCK)
*
* are mostly a no-op in segkpm mode with the following exceptions:
* . The "newpage" return value of segmap_pagecreate is still supported
* for zeroout operations needed on newly created pages.
*
* . segmap_fault() must follow when a error could be expected in
* the VOP_GETPAGE. In segkpm mode this error is recognized in
* segmap_getmapflt and returned from the following segmap_fault()
* call. The "hole" optimization (read only after first VOP_GETPAGE
* mapping in segmap_getmapflt followed by a trap driven protection
* fault and a second VOP_GETPAGE via segmap_fault) cannot be used.
*
* . segmap_fault(F_SOFTUNLOCK) must follow when segmap_getmapflt was
* called w/ (SM_LOCKPROTO, S_OTHER). S_WRITE has to be applied, when
* the page should be marked "dirty". Otherwise the page is not
* written to the backing store later (as mentioned above, no page
* or protection faults are possible in segkpm mode). Caller cannot
* use only S_OTHER and rely on a protection fault to force the page
* to become dirty.
*
* . The segmap_pagecreate parameter softlock is ignored, pages and
* mappings are locked anyway.
*
* SM_LOCKPROTO is used in the fbio layer and some special segmap consumers.
*/
#define SM_PAGECREATE 0x00 /* create page in segkpm mode, no I/O */
#define SM_FAULT 0x01 /* fault in page if necessary */
#define SM_LOCKPROTO 0x02 /* lock/unlock protocol used */
#define MAXBSHIFT 13 /* log2(MAXBSIZE) */
#define MAXBOFFSET (MAXBSIZE - 1)
#define MAXBMASK (~MAXBOFFSET)
/*
* SMAP_HASHAVELEN is the average length desired for this chain, from
* which the size of the smd_hash table is derived at segment create time.
* SMAP_HASHVPSHIFT is defined so that 1 << SMAP_HASHVPSHIFT is the
* approximate size of a vnode struct.
*/
#define SMAP_HASHAVELEN 4
#define SMAP_HASHVPSHIFT 6
#ifdef _KERNEL
/*
* The kernel generic mapping segment.
*/
extern struct seg *segkmap;
/*
* Public seg_map segment operations.
*/
extern int segmap_create(struct seg *, void *);
extern int segmap_pagecreate(struct seg *, caddr_t, size_t, int);
extern void segmap_pageunlock(struct seg *, caddr_t, size_t, enum seg_rw);
extern faultcode_t segmap_fault(struct hat *, struct seg *, caddr_t, size_t,
enum fault_type, enum seg_rw);
extern caddr_t segmap_getmap(struct seg *, struct vnode *, u_offset_t);
extern caddr_t segmap_getmapflt(struct seg *, struct vnode *, u_offset_t,
size_t, int, enum seg_rw);
extern int segmap_release(struct seg *, caddr_t, uint_t);
extern void segmap_flush(struct seg *, struct vnode *);
extern void segmap_inval(struct seg *, struct vnode *, u_offset_t);
#endif /* _KERNEL */
#ifdef __cplusplus
}
#endif
#endif /* _VM_SEG_MAP_H */
|