Skip to content

Commit e95c79e

Browse files
pkpk
authored andcommitted
Keep a private pool of auxiliary resources (vndxfer & vndbuf structures)
used to setup I/O to regular files. Implemented in a somewhat generic way, for what it's worth.
1 parent c713bc8 commit e95c79e

File tree

1 file changed

+171
-18
lines changed

1 file changed

+171
-18
lines changed

sys/vm/vm_swap.c

Lines changed: 171 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
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 $ */
22

33
/*
44
* Copyright (c) 1995, 1996, 1997 Matthew R. Green
@@ -38,6 +38,7 @@
3838
#include <sys/errno.h>
3939
#include <sys/kernel.h>
4040
#include <sys/malloc.h>
41+
#include <sys/lock.h>
4142
#include <sys/vnode.h>
4243
#include <sys/map.h>
4344
#include <sys/file.h>
@@ -131,38 +132,174 @@ struct swappri {
131132
};
132133

133134

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+
134250
/*
135251
* The following two structures are used to keep track of data transfers
136252
* on swap devices associated with regular files.
137253
* NOTE: this code is more or less a copy of vnd.c; we use the same
138254
* structure names here to ease porting..
139255
*/
256+
257+
140258
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 */
142261
struct swapdev *vx_sdp;
143262
int vx_error;
144-
int vx_pending; /* # of pending aux buffers */
263+
int vx_pending; /* # of pending aux buffers */
145264
};
146265

266+
147267
struct vndbuf {
268+
struct pool_item vb_pool; /* MUST be first */
148269
struct buf vb_buf;
149270
struct vndxfer *vb_xfer;
150271
};
151272

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+
152277
/*
153-
* XXX: Not a very good idea in a swap strategy module!
278+
* We keep a pool vndbuf's and vndxfer structures.
154279
*/
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));
157300

158-
#define putvndxfer(vnx) \
159-
free((caddr_t)(vnx), M_DEVBUF)
160301

161-
#define getvndbuf() \
162-
((struct vndbuf *)malloc(sizeof(struct vndbuf), M_DEVBUF, M_WAITOK))
163302

164-
#define putvndbuf(vbp) \
165-
free((caddr_t)(vbp), M_DEVBUF)
166303

167304
int nswapdev;
168305
int swflags;
@@ -619,6 +756,25 @@ swap_on(p, sdp)
619756
rootblks, dtoc(size - rootblks));
620757
}
621758

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+
622778
swap_addmap(sdp, size);
623779
nswapdev++;
624780
sdp->swd_flags |= SWF_ENABLE;
@@ -880,7 +1036,6 @@ swstrategy(bp)
8801036
}
8811037

8821038
#ifdef SWAP_TO_FILES
883-
int doswvnlock = 0;
8841039

8851040
static void
8861041
sw_reg_strategy(sdp, bp, bn)
@@ -904,18 +1059,16 @@ sw_reg_strategy(sdp, bp, bn)
9041059
bn = dbtob(bn);
9051060

9061061
/* Allocate a header for this transfer and link it to the buffer */
907-
vnx = getvndxfer();
1062+
getvndxfer(vnx);
9081063
vnx->vx_error = 0;
9091064
vnx->vx_pending = 0;
9101065
vnx->vx_bp = bp;
9111066
vnx->vx_sdp = sdp;
9121067

9131068
for (resid = bp->b_resid; resid; resid -= sz) {
914-
if (doswvnlock) VOP_LOCK(sdp->swd_vp);
9151069
nra = 0;
9161070
error = VOP_BMAP(sdp->swd_vp, bn / sdp->swd_bsize,
9171071
&vp, &nbn, &nra);
918-
if (doswvnlock) VOP_UNLOCK(sdp->swd_vp);
9191072

9201073
if (error == 0 && (long)nbn == -1)
9211074
error = EIO;
@@ -956,7 +1109,7 @@ sw_reg_strategy(sdp, bp, bn)
9561109
" sz 0x%x\n", sdp->swd_vp, vp, bn, nbn, sz);
9571110
#endif /* SWAPDEBUG */
9581111

959-
nbp = getvndbuf();
1112+
getvndbuf(nbp);
9601113
nbp->vb_buf.b_flags = bp->b_flags | B_CALL;
9611114
nbp->vb_buf.b_bcount = sz;
9621115
nbp->vb_buf.b_bufsize = bp->b_bufsize;
@@ -1041,7 +1194,7 @@ static void
10411194
sw_reg_iodone(bp)
10421195
struct buf *bp;
10431196
{
1044-
register struct vndbuf *vbp = (struct vndbuf *) bp;
1197+
register struct vndbuf *vbp = BUF_TO_VNDBUF(bp);
10451198
register struct vndxfer *vnx = (struct vndxfer *)vbp->vb_xfer;
10461199
register struct buf *pbp = vnx->vx_bp;
10471200
struct swapdev *sdp = vnx->vx_sdp;

0 commit comments

Comments
 (0)