summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/vm/seg.h
blob: 2ada345960aa851c514b96d378544cd2bc716158 (plain)
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
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (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 2003 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_H
#define	_VM_SEG_H

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <sys/vnode.h>
#include <sys/avl.h>
#include <vm/seg_enum.h>
#include <vm/faultcode.h>
#include <vm/hat.h>

#ifdef	__cplusplus
extern "C" {
#endif

/*
 * VM - Segments.
 */

/*
 * kstat statistics for segment advise
 */
typedef struct {
	kstat_named_t MADV_FREE_hit;
	kstat_named_t MADV_FREE_miss;
} segadvstat_t;

/*
 * memory object ids
 */
typedef struct memid { u_longlong_t val[2]; } memid_t;

/*
 * An address space contains a set of segments, managed by drivers.
 * Drivers support mapped devices, sharing, copy-on-write, etc.
 *
 * The seg structure contains a lock to prevent races, the base virtual
 * address and size of the segment, a back pointer to the containing
 * address space, pointers to maintain an AVL tree of segments in the
 * same address space, and procedure and data hooks for the driver.
 * The AVL tree of segments for the address space is sorted by
 * ascending base addresses and overlapping segments are not allowed.
 *
 * After a segment is created, faults may occur on pages of the segment.
 * When a fault occurs, the fault handling code must get the desired
 * object and set up the hardware translation to the object.  For some
 * objects, the fault handling code also implements copy-on-write.
 *
 * When the hat wants to unload a translation, it can call the unload
 * routine which is responsible for processing reference and modify bits.
 *
 * Each segment is protected by it's containing address space lock.  To
 * access any field in the segment structure, the "as" must be locked.
 * If a segment field is to be modified, the address space lock must be
 * write locked.
 */

struct seg {
	caddr_t	s_base;			/* base virtual address */
	size_t	s_size;			/* size in bytes */
	uint_t	s_szc;			/* max page size code */
	uint_t	s_flags;		/* flags for segment, see below */
	struct	as *s_as;		/* containing address space */
	avl_node_t s_tree;		/* AVL tree links to segs in this as */
	struct	seg_ops *s_ops;		/* ops vector: see below */
	void *s_data;			/* private data for instance */
};

#define	S_PURGE		(0x01)		/* seg should be purged in as_gap() */

struct	seg_ops {
	int	(*dup)(struct seg *, struct seg *);
	int	(*unmap)(struct seg *, caddr_t, size_t);
	void	(*free)(struct seg *);
	faultcode_t (*fault)(struct hat *, struct seg *, caddr_t, size_t,
	    enum fault_type, enum seg_rw);
	faultcode_t (*faulta)(struct seg *, caddr_t);
	int	(*setprot)(struct seg *, caddr_t, size_t, uint_t);
	int	(*checkprot)(struct seg *, caddr_t, size_t, uint_t);
	int	(*kluster)(struct seg *, caddr_t, ssize_t);
	size_t	(*swapout)(struct seg *);
	int	(*sync)(struct seg *, caddr_t, size_t, int, uint_t);
	size_t	(*incore)(struct seg *, caddr_t, size_t, char *);
	int	(*lockop)(struct seg *, caddr_t, size_t, int, int, ulong_t *,
			size_t);
	int	(*getprot)(struct seg *, caddr_t, size_t, uint_t *);
	u_offset_t	(*getoffset)(struct seg *, caddr_t);
	int	(*gettype)(struct seg *, caddr_t);
	int	(*getvp)(struct seg *, caddr_t, struct vnode **);
	int	(*advise)(struct seg *, caddr_t, size_t, uint_t);
	void	(*dump)(struct seg *);
	int	(*pagelock)(struct seg *, caddr_t, size_t, struct page ***,
			enum lock_type, enum seg_rw);
	int	(*setpagesize)(struct seg *, caddr_t, size_t, uint_t);
	int	(*getmemid)(struct seg *, caddr_t, memid_t *);
	struct lgrp_mem_policy_info	*(*getpolicy)(struct seg *, caddr_t);
};

#ifdef _KERNEL
/*
 * Generic segment operations
 */
extern	void	seg_init(void);
extern	struct	seg *seg_alloc(struct as *as, caddr_t base, size_t size);
extern	int	seg_attach(struct as *as, caddr_t base, size_t size,
			struct seg *seg);
extern	void	seg_unmap(struct seg *seg);
extern	void	seg_free(struct seg *seg);

/*
 * functions for pagelock cache support
 */
extern	void	seg_ppurge(struct seg *seg);
extern	void	seg_ppurge_seg(int (*callback)());
extern	void	seg_pinactive(struct seg *seg, caddr_t addr, size_t len,
			struct page **pp, enum seg_rw rw, int (*callback)());
extern	int	seg_pinsert_check(struct seg *seg, size_t len, uint_t flags);
extern	int	seg_pinsert(struct seg *seg, caddr_t addr, size_t len,
			struct page **pp, enum seg_rw rw, uint_t flags,
			int (*callback)());
extern	struct	page **seg_plookup(struct seg *seg, caddr_t addr,
			size_t len, enum seg_rw rw);
extern	void	seg_pasync_thread(void);
extern	void	seg_preap(void);

extern	int	seg_preapahead;
extern	segadvstat_t  segadvstat;
/*
 * Flags for pagelock cache support
 */
#define	SEGP_ASYNC_FLUSH	0x1	/* flushed by async thread */
#define	SEGP_FORCE_WIRED	0x2	/* skip check against seg_pwindow */

/*
 * Return values for seg_pinsert and seg_pinsert_check functions.
 */
#define	SEGP_SUCCESS		0	/* seg_pinsert() succeeded */
#define	SEGP_FAIL		1	/* seg_pinsert() failed */

/* Page status bits for segop_incore */
#define	SEG_PAGE_INCORE		0x01	/* VA has a page backing it */
#define	SEG_PAGE_LOCKED		0x02	/* VA has a page that is locked */
#define	SEG_PAGE_HASCOW		0x04	/* VA has a page with a copy-on-write */
#define	SEG_PAGE_SOFTLOCK	0x08	/* VA has a page with softlock held */
#define	SEG_PAGE_VNODEBACKED	0x10	/* Segment is backed by a vnode */
#define	SEG_PAGE_ANON		0x20	/* VA has an anonymous page */
#define	SEG_PAGE_VNODE		0x40	/* VA has a vnode page backing it */

#define	SEGOP_DUP(s, n)		    (*(s)->s_ops->dup)((s), (n))
#define	SEGOP_UNMAP(s, a, l)	    (*(s)->s_ops->unmap)((s), (a), (l))
#define	SEGOP_FREE(s)		    (*(s)->s_ops->free)((s))
#define	SEGOP_FAULT(h, s, a, l, t, rw) \
		(*(s)->s_ops->fault)((h), (s), (a), (l), (t), (rw))
#define	SEGOP_FAULTA(s, a)	    (*(s)->s_ops->faulta)((s), (a))
#define	SEGOP_SETPROT(s, a, l, p)   (*(s)->s_ops->setprot)((s), (a), (l), (p))
#define	SEGOP_CHECKPROT(s, a, l, p) (*(s)->s_ops->checkprot)((s), (a), (l), (p))
#define	SEGOP_KLUSTER(s, a, d)	    (*(s)->s_ops->kluster)((s), (a), (d))
#define	SEGOP_SWAPOUT(s)	    (*(s)->s_ops->swapout)((s))
#define	SEGOP_SYNC(s, a, l, atr, f) \
		(*(s)->s_ops->sync)((s), (a), (l), (atr), (f))
#define	SEGOP_INCORE(s, a, l, v)    (*(s)->s_ops->incore)((s), (a), (l), (v))
#define	SEGOP_LOCKOP(s, a, l, atr, op, b, p) \
		(*(s)->s_ops->lockop)((s), (a), (l), (atr), (op), (b), (p))
#define	SEGOP_GETPROT(s, a, l, p)   (*(s)->s_ops->getprot)((s), (a), (l), (p))
#define	SEGOP_GETOFFSET(s, a)	    (*(s)->s_ops->getoffset)((s), (a))
#define	SEGOP_GETTYPE(s, a)	    (*(s)->s_ops->gettype)((s), (a))
#define	SEGOP_GETVP(s, a, vpp)	    (*(s)->s_ops->getvp)((s), (a), (vpp))
#define	SEGOP_ADVISE(s, a, l, b)    (*(s)->s_ops->advise)((s), (a), (l), (b))
#define	SEGOP_DUMP(s)		    (*(s)->s_ops->dump)((s))
#define	SEGOP_PAGELOCK(s, a, l, p, t, rw) \
		(*(s)->s_ops->pagelock)((s), (a), (l), (p), (t), (rw))
#define	SEGOP_SETPAGESIZE(s, a, l, szc) \
		(*(s)->s_ops->setpagesize)((s), (a), (l), (szc))
#define	SEGOP_GETMEMID(s, a, mp)    (*(s)->s_ops->getmemid)((s), (a), (mp))
#define	SEGOP_GETPOLICY(s, a)	    (*(s)->s_ops->getpolicy)((s), (a))

#define	seg_page(seg, addr) \
	(((uintptr_t)((addr) - (seg)->s_base)) >> PAGESHIFT)

#define	seg_pages(seg) \
	(((uintptr_t)((seg)->s_size + PAGEOFFSET)) >> PAGESHIFT)

#define	IE_NOMEM	-1	/* internal to seg layer */
#define	IE_RETRY	-2	/* internal to seg layer */
#define	IE_REATTACH	-3	/* internal to seg layer */

/* Delay/retry factors for seg_p_mem_config_pre_del */
#define	SEGP_PREDEL_DELAY_FACTOR	4
/*
 * As a workaround to being unable to purge the pagelock
 * cache during a DR delete memory operation, we use
 * a stall threshold that is twice the maximum seen
 * during testing.  This workaround will be removed
 * when a suitable fix is found.
 */
#define	SEGP_STALL_SECONDS	25
#define	SEGP_STALL_THRESHOLD \
	(SEGP_STALL_SECONDS * SEGP_PREDEL_DELAY_FACTOR)

#ifdef VMDEBUG

uint_t	seg_page(struct seg *, caddr_t);
uint_t	seg_pages(struct seg *);

#endif	/* VMDEBUG */

#endif	/* _KERNEL */

#ifdef	__cplusplus
}
#endif

#endif	/* _VM_SEG_H */