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.
This commit is contained in:
pk 1997-10-13 19:15:19 +00:00
parent c713bc804e
commit e95c79e586
1 changed files with 171 additions and 18 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: vm_swap.c,v 1.44 1997/10/10 13:16:24 mrg Exp $ */
/* $NetBSD: vm_swap.c,v 1.45 1997/10/13 19:15:19 pk Exp $ */
/*
* Copyright (c) 1995, 1996, 1997 Matthew R. Green
@ -38,6 +38,7 @@
#include <sys/errno.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/lock.h>
#include <sys/vnode.h>
#include <sys/map.h>
#include <sys/file.h>
@ -131,38 +132,174 @@ struct swappri {
};
/*
* Pool resource management helpers for vndxfer & vndbuf below.
*/
struct pool_item {
struct pool_item *pi_next;
};
struct pool {
struct pool_item *pr_freelist; /* Free items in pool */
int pr_size; /* Size of item */
int pr_freecount; /* # of free items */
int pr_hiwat; /* max # of pooled items */
char *pr_wchan; /* tsleep(9) identifier */
int pr_flags;
#define PR_WANTED 1
struct simplelock pr_lock;
};
static void *get_pooled_resource __P((struct pool *));
static void put_pooled_resource __P((struct pool *, void *));
static int prime_pooled_resource __P((struct pool *, int));
/* Grab an item from the pool; must be called at splbio */
static __inline void *
get_pooled_resource(pp)
struct pool *pp;
{
void *v;
struct pool_item *pi;
again:
simple_lock(&pp->pr_lock);
if (pp->pr_freelist == NULL) {
/* if (pp->pr_flags & PR_MALLOC) */
v = (void *)malloc(pp->pr_size, M_DEVBUF, M_NOWAIT);
if (v == NULL) {
pp->pr_flags |= PR_WANTED;
simple_unlock(&pp->pr_lock);
tsleep((caddr_t)pp, PSWP, pp->pr_wchan, 0);
goto again;
}
} else {
v = pi = pp->pr_freelist;
pp->pr_freelist = pi->pi_next;
pp->pr_freecount--;
}
simple_unlock(&pp->pr_lock);
return (v);
}
/* Return resource to the pool; must be called at splbio */
static __inline void
put_pooled_resource(pp, v)
struct pool *pp;
void *v;
{
struct pool_item *pi = v;
simple_lock(&pp->pr_lock);
if ((pp->pr_flags & PR_WANTED) || pp->pr_freecount < pp->pr_hiwat) {
/* Return to pool */
pi->pi_next = pp->pr_freelist;
pp->pr_freelist = pi;
pp->pr_freecount++;
if (pp->pr_flags & PR_WANTED) {
pp->pr_flags &= ~PR_WANTED;
wakeup((caddr_t)pp);
}
} else {
/* Return to system */
free(v, M_DEVBUF);
/*
* Return any excess items allocated during periods of
* contention.
*/
while (pp->pr_freecount > pp->pr_hiwat) {
pi = pp->pr_freelist;
pp->pr_freelist = pi->pi_next;
pp->pr_freecount--;
free(pi, M_DEVBUF);
}
}
simple_unlock(&pp->pr_lock);
}
/* Add N items to the pool */
static int
prime_pooled_resource(pp, n)
struct pool *pp;
int n;
{
struct pool_item *pi;
simple_lock(&pp->pr_lock);
pp->pr_hiwat += n;
while (n--) {
pi = malloc(pp->pr_size, M_DEVBUF, M_NOWAIT);
if (pi == NULL) {
simple_unlock(&pp->pr_lock);
return (ENOMEM);
}
pi->pi_next = pp->pr_freelist;
pp->pr_freelist = pi;
pp->pr_freecount++;
}
simple_unlock(&pp->pr_lock);
return (0);
}
/*
* The following two structures are used to keep track of data transfers
* on swap devices associated with regular files.
* NOTE: this code is more or less a copy of vnd.c; we use the same
* structure names here to ease porting..
*/
struct vndxfer {
struct buf *vx_bp; /* Pointer to parent buffer */
struct pool_item vx_pool; /* MUST be first */
struct buf *vx_bp; /* Pointer to parent buffer */
struct swapdev *vx_sdp;
int vx_error;
int vx_pending; /* # of pending aux buffers */
int vx_pending; /* # of pending aux buffers */
};
struct vndbuf {
struct pool_item vb_pool; /* MUST be first */
struct buf vb_buf;
struct vndxfer *vb_xfer;
};
/* To get from a buffer to the encapsulating vndbuf */
#define BUF_TO_VNDBUF(bp) \
((struct vndbuf *)((int)bp - ((int)&((struct vndbuf *)0)->vb_buf)))
/*
* XXX: Not a very good idea in a swap strategy module!
* We keep a pool vndbuf's and vndxfer structures.
*/
#define getvndxfer() \
((struct vndxfer *)malloc(sizeof(struct vndxfer), M_DEVBUF, M_WAITOK))
struct pool vndxfer_head = { NULL, sizeof(struct vndxfer), 0, 0, "sw vnx", 0 };
struct pool vndbuf_head = { NULL, sizeof(struct vndbuf), 0, 0, "sw vnd", 0 };
#define getvndxfer(vnx) do { \
int s = splbio(); \
(vnx) = (struct vndxfer *)get_pooled_resource(&vndxfer_head); \
splx(s); \
} while (0)
#define putvndxfer(vnx) \
put_pooled_resource(&vndxfer_head, (void *)(vnx));
#define getvndbuf(vbp) do { \
int s = splbio(); \
(vbp) = (struct vndbuf *)get_pooled_resource(&vndbuf_head); \
splx(s); \
} while (0)
#define putvndbuf(vbp) \
put_pooled_resource(&vndbuf_head, (void *)(vbp));
#define putvndxfer(vnx) \
free((caddr_t)(vnx), M_DEVBUF)
#define getvndbuf() \
((struct vndbuf *)malloc(sizeof(struct vndbuf), M_DEVBUF, M_WAITOK))
#define putvndbuf(vbp) \
free((caddr_t)(vbp), M_DEVBUF)
int nswapdev;
int swflags;
@ -619,6 +756,25 @@ swap_on(p, sdp)
rootblks, dtoc(size - rootblks));
}
if (vp->v_type == VREG) {
/* Allocate additional vnx and vnd buffers */
int n, s;
/*
* Allocation Policy:
* (8 * swd_maxactive) vnx headers per swap dev
* (16 * swd_maxactive) vnd buffers per swap dev
*/
s = splbio();
n = 8 * sdp->swd_maxactive;
(void)prime_pooled_resource(&vndxfer_head, n);
n = 16 * sdp->swd_maxactive;
(void)prime_pooled_resource(&vndbuf_head, n);
splx(s);
}
swap_addmap(sdp, size);
nswapdev++;
sdp->swd_flags |= SWF_ENABLE;
@ -880,7 +1036,6 @@ swstrategy(bp)
}
#ifdef SWAP_TO_FILES
int doswvnlock = 0;
static void
sw_reg_strategy(sdp, bp, bn)
@ -904,18 +1059,16 @@ sw_reg_strategy(sdp, bp, bn)
bn = dbtob(bn);
/* Allocate a header for this transfer and link it to the buffer */
vnx = getvndxfer();
getvndxfer(vnx);
vnx->vx_error = 0;
vnx->vx_pending = 0;
vnx->vx_bp = bp;
vnx->vx_sdp = sdp;
for (resid = bp->b_resid; resid; resid -= sz) {
if (doswvnlock) VOP_LOCK(sdp->swd_vp);
nra = 0;
error = VOP_BMAP(sdp->swd_vp, bn / sdp->swd_bsize,
&vp, &nbn, &nra);
if (doswvnlock) VOP_UNLOCK(sdp->swd_vp);
if (error == 0 && (long)nbn == -1)
error = EIO;
@ -956,7 +1109,7 @@ sw_reg_strategy(sdp, bp, bn)
" sz 0x%x\n", sdp->swd_vp, vp, bn, nbn, sz);
#endif /* SWAPDEBUG */
nbp = getvndbuf();
getvndbuf(nbp);
nbp->vb_buf.b_flags = bp->b_flags | B_CALL;
nbp->vb_buf.b_bcount = sz;
nbp->vb_buf.b_bufsize = bp->b_bufsize;
@ -1041,7 +1194,7 @@ static void
sw_reg_iodone(bp)
struct buf *bp;
{
register struct vndbuf *vbp = (struct vndbuf *) bp;
register struct vndbuf *vbp = BUF_TO_VNDBUF(bp);
register struct vndxfer *vnx = (struct vndxfer *)vbp->vb_xfer;
register struct buf *pbp = vnx->vx_bp;
struct swapdev *sdp = vnx->vx_sdp;