1
- /* $NetBSD: vm_swap.c,v 1.44 1997/10/10 13:16:24 mrg Exp $ */
1
+ /* $NetBSD: vm_swap.c,v 1.45 1997/10/13 19:15:19 pk Exp $ */
2
2
3
3
/*
4
4
* Copyright (c) 1995, 1996, 1997 Matthew R. Green
38
38
#include <sys/errno.h>
39
39
#include <sys/kernel.h>
40
40
#include <sys/malloc.h>
41
+ #include <sys/lock.h>
41
42
#include <sys/vnode.h>
42
43
#include <sys/map.h>
43
44
#include <sys/file.h>
@@ -131,38 +132,174 @@ struct swappri {
131
132
};
132
133
133
134
135
+
136
+
137
+ /*
138
+ * Pool resource management helpers for vndxfer & vndbuf below.
139
+ */
140
+ struct pool_item {
141
+ struct pool_item * pi_next ;
142
+ };
143
+
144
+ struct pool {
145
+ struct pool_item * pr_freelist ; /* Free items in pool */
146
+ int pr_size ; /* Size of item */
147
+ int pr_freecount ; /* # of free items */
148
+ int pr_hiwat ; /* max # of pooled items */
149
+ char * pr_wchan ; /* tsleep(9) identifier */
150
+ int pr_flags ;
151
+ #define PR_WANTED 1
152
+ struct simplelock pr_lock ;
153
+ };
154
+
155
+ static void * get_pooled_resource __P ((struct pool * ) );
156
+ static void put_pooled_resource __P ((struct pool * , void * ) );
157
+ static int prime_pooled_resource __P ((struct pool * , int ) );
158
+
159
+
160
+ /* Grab an item from the pool; must be called at splbio */
161
+ static __inline void *
162
+ get_pooled_resource (pp )
163
+ struct pool * pp ;
164
+ {
165
+ void * v ;
166
+ struct pool_item * pi ;
167
+
168
+ again :
169
+ simple_lock (& pp -> pr_lock );
170
+ if (pp -> pr_freelist == NULL ) {
171
+ /* if (pp->pr_flags & PR_MALLOC) */
172
+ v = (void * )malloc (pp -> pr_size , M_DEVBUF , M_NOWAIT );
173
+ if (v == NULL ) {
174
+ pp -> pr_flags |= PR_WANTED ;
175
+ simple_unlock (& pp -> pr_lock );
176
+ tsleep ((caddr_t )pp , PSWP , pp -> pr_wchan , 0 );
177
+ goto again ;
178
+ }
179
+ } else {
180
+ v = pi = pp -> pr_freelist ;
181
+ pp -> pr_freelist = pi -> pi_next ;
182
+ pp -> pr_freecount -- ;
183
+ }
184
+ simple_unlock (& pp -> pr_lock );
185
+ return (v );
186
+ }
187
+
188
+ /* Return resource to the pool; must be called at splbio */
189
+ static __inline void
190
+ put_pooled_resource (pp , v )
191
+ struct pool * pp ;
192
+ void * v ;
193
+ {
194
+ struct pool_item * pi = v ;
195
+
196
+ simple_lock (& pp -> pr_lock );
197
+ if ((pp -> pr_flags & PR_WANTED ) || pp -> pr_freecount < pp -> pr_hiwat ) {
198
+ /* Return to pool */
199
+ pi -> pi_next = pp -> pr_freelist ;
200
+ pp -> pr_freelist = pi ;
201
+ pp -> pr_freecount ++ ;
202
+ if (pp -> pr_flags & PR_WANTED ) {
203
+ pp -> pr_flags &= ~PR_WANTED ;
204
+ wakeup ((caddr_t )pp );
205
+ }
206
+ } else {
207
+ /* Return to system */
208
+ free (v , M_DEVBUF );
209
+
210
+ /*
211
+ * Return any excess items allocated during periods of
212
+ * contention.
213
+ */
214
+ while (pp -> pr_freecount > pp -> pr_hiwat ) {
215
+ pi = pp -> pr_freelist ;
216
+ pp -> pr_freelist = pi -> pi_next ;
217
+ pp -> pr_freecount -- ;
218
+ free (pi , M_DEVBUF );
219
+ }
220
+ }
221
+ simple_unlock (& pp -> pr_lock );
222
+ }
223
+
224
+ /* Add N items to the pool */
225
+ static int
226
+ prime_pooled_resource (pp , n )
227
+ struct pool * pp ;
228
+ int n ;
229
+ {
230
+ struct pool_item * pi ;
231
+
232
+ simple_lock (& pp -> pr_lock );
233
+ pp -> pr_hiwat += n ;
234
+ while (n -- ) {
235
+ pi = malloc (pp -> pr_size , M_DEVBUF , M_NOWAIT );
236
+ if (pi == NULL ) {
237
+ simple_unlock (& pp -> pr_lock );
238
+ return (ENOMEM );
239
+ }
240
+
241
+ pi -> pi_next = pp -> pr_freelist ;
242
+ pp -> pr_freelist = pi ;
243
+ pp -> pr_freecount ++ ;
244
+ }
245
+ simple_unlock (& pp -> pr_lock );
246
+ return (0 );
247
+ }
248
+
249
+
134
250
/*
135
251
* The following two structures are used to keep track of data transfers
136
252
* on swap devices associated with regular files.
137
253
* NOTE: this code is more or less a copy of vnd.c; we use the same
138
254
* structure names here to ease porting..
139
255
*/
256
+
257
+
140
258
struct vndxfer {
141
- struct buf * vx_bp ; /* Pointer to parent buffer */
259
+ struct pool_item vx_pool ; /* MUST be first */
260
+ struct buf * vx_bp ; /* Pointer to parent buffer */
142
261
struct swapdev * vx_sdp ;
143
262
int vx_error ;
144
- int vx_pending ; /* # of pending aux buffers */
263
+ int vx_pending ; /* # of pending aux buffers */
145
264
};
146
265
266
+
147
267
struct vndbuf {
268
+ struct pool_item vb_pool ; /* MUST be first */
148
269
struct buf vb_buf ;
149
270
struct vndxfer * vb_xfer ;
150
271
};
151
272
273
+ /* To get from a buffer to the encapsulating vndbuf */
274
+ #define BUF_TO_VNDBUF (bp ) \
275
+ ((struct vndbuf *)((int)bp - ((int)&((struct vndbuf *)0)->vb_buf)))
276
+
152
277
/*
153
- * XXX: Not a very good idea in a swap strategy module!
278
+ * We keep a pool vndbuf's and vndxfer structures.
154
279
*/
155
- #define getvndxfer () \
156
- ((struct vndxfer *)malloc(sizeof(struct vndxfer), M_DEVBUF, M_WAITOK))
280
+ struct pool vndxfer_head = { NULL , sizeof (struct vndxfer ), 0 , 0 , "sw vnx" , 0 };
281
+ struct pool vndbuf_head = { NULL , sizeof (struct vndbuf ), 0 , 0 , "sw vnd" , 0 };
282
+
283
+ #define getvndxfer (vnx ) do { \
284
+ int s = splbio(); \
285
+ (vnx) = (struct vndxfer *)get_pooled_resource(&vndxfer_head); \
286
+ splx(s); \
287
+ } while (0)
288
+
289
+ #define putvndxfer (vnx ) \
290
+ put_pooled_resource(&vndxfer_head, (void *)(vnx));
291
+
292
+ #define getvndbuf (vbp ) do { \
293
+ int s = splbio(); \
294
+ (vbp) = (struct vndbuf *)get_pooled_resource(&vndbuf_head); \
295
+ splx(s); \
296
+ } while (0)
297
+
298
+ #define putvndbuf (vbp ) \
299
+ put_pooled_resource(&vndbuf_head, (void *)(vbp));
157
300
158
- #define putvndxfer (vnx ) \
159
- free((caddr_t)(vnx), M_DEVBUF)
160
301
161
- #define getvndbuf () \
162
- ((struct vndbuf *)malloc(sizeof(struct vndbuf), M_DEVBUF, M_WAITOK))
163
302
164
- #define putvndbuf (vbp ) \
165
- free((caddr_t)(vbp), M_DEVBUF)
166
303
167
304
int nswapdev ;
168
305
int swflags ;
@@ -619,6 +756,25 @@ swap_on(p, sdp)
619
756
rootblks , dtoc (size - rootblks ));
620
757
}
621
758
759
+ if (vp -> v_type == VREG ) {
760
+ /* Allocate additional vnx and vnd buffers */
761
+ int n , s ;
762
+ /*
763
+ * Allocation Policy:
764
+ * (8 * swd_maxactive) vnx headers per swap dev
765
+ * (16 * swd_maxactive) vnd buffers per swap dev
766
+ */
767
+
768
+ s = splbio ();
769
+ n = 8 * sdp -> swd_maxactive ;
770
+ (void )prime_pooled_resource (& vndxfer_head , n );
771
+
772
+ n = 16 * sdp -> swd_maxactive ;
773
+ (void )prime_pooled_resource (& vndbuf_head , n );
774
+ splx (s );
775
+
776
+ }
777
+
622
778
swap_addmap (sdp , size );
623
779
nswapdev ++ ;
624
780
sdp -> swd_flags |= SWF_ENABLE ;
@@ -880,7 +1036,6 @@ swstrategy(bp)
880
1036
}
881
1037
882
1038
#ifdef SWAP_TO_FILES
883
- int doswvnlock = 0 ;
884
1039
885
1040
static void
886
1041
sw_reg_strategy (sdp , bp , bn )
@@ -904,18 +1059,16 @@ sw_reg_strategy(sdp, bp, bn)
904
1059
bn = dbtob (bn );
905
1060
906
1061
/* Allocate a header for this transfer and link it to the buffer */
907
- vnx = getvndxfer ();
1062
+ getvndxfer (vnx );
908
1063
vnx -> vx_error = 0 ;
909
1064
vnx -> vx_pending = 0 ;
910
1065
vnx -> vx_bp = bp ;
911
1066
vnx -> vx_sdp = sdp ;
912
1067
913
1068
for (resid = bp -> b_resid ; resid ; resid -= sz ) {
914
- if (doswvnlock ) VOP_LOCK (sdp -> swd_vp );
915
1069
nra = 0 ;
916
1070
error = VOP_BMAP (sdp -> swd_vp , bn / sdp -> swd_bsize ,
917
1071
& vp , & nbn , & nra );
918
- if (doswvnlock ) VOP_UNLOCK (sdp -> swd_vp );
919
1072
920
1073
if (error == 0 && (long )nbn == -1 )
921
1074
error = EIO ;
@@ -956,7 +1109,7 @@ sw_reg_strategy(sdp, bp, bn)
956
1109
" sz 0x%x\n" , sdp -> swd_vp , vp , bn , nbn , sz );
957
1110
#endif /* SWAPDEBUG */
958
1111
959
- nbp = getvndbuf ();
1112
+ getvndbuf (nbp );
960
1113
nbp -> vb_buf .b_flags = bp -> b_flags | B_CALL ;
961
1114
nbp -> vb_buf .b_bcount = sz ;
962
1115
nbp -> vb_buf .b_bufsize = bp -> b_bufsize ;
@@ -1041,7 +1194,7 @@ static void
1041
1194
sw_reg_iodone (bp )
1042
1195
struct buf * bp ;
1043
1196
{
1044
- register struct vndbuf * vbp = ( struct vndbuf * ) bp ;
1197
+ register struct vndbuf * vbp = BUF_TO_VNDBUF ( bp ) ;
1045
1198
register struct vndxfer * vnx = (struct vndxfer * )vbp -> vb_xfer ;
1046
1199
register struct buf * pbp = vnx -> vx_bp ;
1047
1200
struct swapdev * sdp = vnx -> vx_sdp ;
0 commit comments