use pools for allocating most softdep datastructures. since we want to

allocate memory from kernel_map but some of the objects are freed from
interrupt context, we put objects on a queue instead of freeing them
immediately.  then in softdep_process_worklist() (which is called at
least once per second from the syncer), we process that queue and
free all the objects.  allocating from kernel_map instead of from kmem_map
allows us to have a much larger number of softdeps pending even in
configurations where kmem_map is relatively small.
This commit is contained in:
chs 2001-09-15 16:33:53 +00:00
parent daa2a3c1a7
commit 5d3eefe245

View File

@ -1,4 +1,4 @@
/* $NetBSD: ffs_softdep.c,v 1.15 2001/09/15 16:13:04 chs Exp $ */
/* $NetBSD: ffs_softdep.c,v 1.16 2001/09/15 16:33:53 chs Exp $ */
/*
* Copyright 1998 Marshall Kirk McKusick. All Rights Reserved.
@ -74,25 +74,40 @@ int softdep_lockedbufs;
/*
* Mapping of dependency structure types to malloc types.
*/
#define D_PAGEDEP M_PAGEDEP
#define D_INODEDEP M_INODEDEP
#define D_NEWBLK M_NEWBLK
#define D_BMSAFEMAP M_BMSAFEMAP
#define D_ALLOCDIRECT M_ALLOCDIRECT
#define D_INDIRDEP M_INDIRDEP
#define D_ALLOCINDIR M_ALLOCINDIR
#define D_FREEFRAG M_FREEFRAG
#define D_FREEBLKS M_FREEBLKS
#define D_FREEFILE M_FREEFILE
#define D_DIRADD M_DIRADD
#define D_MKDIR M_MKDIR
#define D_DIRREM M_DIRREM
#define D_PAGEDEP 1
#define D_INODEDEP 2
#define D_NEWBLK 3
#define D_BMSAFEMAP 4
#define D_ALLOCDIRECT 5
#define D_INDIRDEP 6
#define D_ALLOCINDIR 7
#define D_FREEFRAG 8
#define D_FREEBLKS 9
#define D_FREEFILE 10
#define D_DIRADD 11
#define D_MKDIR 12
#define D_DIRREM 13
#define D_LAST 13
/*
* Names of malloc types.
* Names of softdep types.
*/
extern char *memname[];
#define TYPENAME(type) ((unsigned)(type) < M_LAST ? memname[type] : "???")
#define DtoM(type) (type)
const char *softdep_typenames[] = {
"invalid",
"pagedep",
"inodedep",
"newblk",
"bmsafemap",
"allocdirect",
"indirdep",
"allocindir",
"freefrag",
"freeblks",
"diradd",
"mkdir",
"dirrem",
};
#define TYPENAME(type) \
((unsigned)(type) < D_LAST ? softdep_typenames[type] : "???")
/*
* Finding the current process.
*/
@ -352,6 +367,94 @@ sema_release(semap)
semap->holder = -1;
}
/*
* Memory management.
*/
static struct pool pagedep_pool;
static struct pool inodedep_pool;
static struct pool newblk_pool;
static struct pool bmsafemap_pool;
static struct pool allocdirect_pool;
static struct pool indirdep_pool;
static struct pool allocindir_pool;
static struct pool freefrag_pool;
static struct pool freeblks_pool;
static struct pool freefile_pool;
static struct pool diradd_pool;
static struct pool mkdir_pool;
static struct pool dirrem_pool;
static __inline void
softdep_free(struct worklist *item, int type)
{
switch (type) {
case D_PAGEDEP:
pool_put(&pagedep_pool, item);
return;
case D_INODEDEP:
pool_put(&inodedep_pool, item);
return;
case D_BMSAFEMAP:
pool_put(&bmsafemap_pool, item);
return;
case D_ALLOCDIRECT:
pool_put(&allocdirect_pool, item);
return;
case D_INDIRDEP:
pool_put(&indirdep_pool, item);
return;
case D_ALLOCINDIR:
pool_put(&allocindir_pool, item);
return;
case D_FREEFRAG:
pool_put(&freefrag_pool, item);
return;
case D_FREEBLKS:
pool_put(&freeblks_pool, item);
return;
case D_FREEFILE:
pool_put(&freefile_pool, item);
return;
case D_DIRADD:
pool_put(&diradd_pool, item);
return;
case D_MKDIR:
pool_put(&mkdir_pool, item);
return;
case D_DIRREM:
pool_put(&dirrem_pool, item);
return;
}
panic("softdep_free: unknown type %d", type);
}
struct workhead softdep_tofree;
static __inline void
softdep_queuefree(struct worklist *item)
{
int s;
s = splbio();
LIST_INSERT_HEAD(&softdep_tofree, item , wk_list);
splx(s);
}
/*
* Worklist queue management.
* These routines require that the lock be held.
@ -365,7 +468,7 @@ sema_release(semap)
(item)->wk_state &= ~ONWORKLIST; \
LIST_REMOVE(item, wk_list); \
} while (0)
#define WORKITEM_FREE(item, type) FREE(item, DtoM(type))
#define WORKITEM_FREE(item, type) softdep_queuefree(item, type)
#else /* DEBUG */
static void worklist_insert __P((struct workhead *, struct worklist *));
@ -411,9 +514,7 @@ workitem_free(item, type)
if (item->wk_state & ONWORKLIST)
panic("workitem_free: still on list");
if (item->wk_type != type)
panic("workitem_free: type mismatch");
FREE(item, DtoM(type));
softdep_queuefree(item);
}
#endif /* DEBUG */
@ -497,6 +598,18 @@ softdep_process_worklist(matchmnt)
struct worklist *wk;
struct fs *matchfs;
int matchcnt;
int s;
/*
* First process any items on the delay-free queue.
*/
s = splbio();
while ((wk = LIST_FIRST(&softdep_tofree)) != NULL) {
LIST_REMOVE(wk, wk_list);
softdep_free(wk, wk->wk_type);
}
splx(s);
/*
* Record the process identifier of our caller so that we can give
* this process preferential treatment in request_cleanup below.
@ -752,8 +865,7 @@ top:
ACQUIRE_LOCK(&lk);
goto top;
}
MALLOC(pagedep, struct pagedep *, sizeof(struct pagedep), M_PAGEDEP,
M_WAITOK);
pagedep = pool_get(&pagedep_pool, PR_WAITOK);
bzero(pagedep, sizeof(struct pagedep));
pagedep->pd_list.wk_type = D_PAGEDEP;
pagedep->pd_mnt = mp;
@ -829,8 +941,7 @@ top:
goto top;
}
num_inodedep += 1;
MALLOC(inodedep, struct inodedep *, sizeof(struct inodedep),
M_INODEDEP, M_WAITOK);
inodedep = pool_get(&inodedep_pool, PR_WAITOK);
inodedep->id_list.wk_type = D_INODEDEP;
inodedep->id_fs = fs;
inodedep->id_ino = inum;
@ -891,8 +1002,7 @@ top:
}
if (sema_get(&newblk_in_progress, 0) == 0)
goto top;
MALLOC(newblk, struct newblk *, sizeof(struct newblk),
M_NEWBLK, M_WAITOK);
newblk = pool_get(&newblk_pool, PR_WAITOK);
newblk->nb_state = 0;
newblk->nb_fs = fs;
newblk->nb_newblkno = newblkno;
@ -928,6 +1038,46 @@ softdep_initialize()
for (i = 0; i < PCBPHASHSIZE; i++) {
LIST_INIT(&pcbphashhead[i]);
}
pool_init(&pagedep_pool, sizeof(struct pagedep), 0, 0, 0,
"pagedeppl", 0, pool_page_alloc_nointr, pool_page_free_nointr,
M_PAGEDEP);
pool_init(&inodedep_pool, sizeof(struct inodedep), 0, 0, 0,
"inodedeppl", 0, pool_page_alloc_nointr, pool_page_free_nointr,
M_INODEDEP);
pool_init(&newblk_pool, sizeof(struct newblk), 0, 0, 0,
"newblkpl", 0, pool_page_alloc_nointr, pool_page_free_nointr,
M_NEWBLK);
pool_init(&bmsafemap_pool, sizeof(struct bmsafemap), 0, 0, 0,
"bmsafemappl", 0, pool_page_alloc_nointr, pool_page_free_nointr,
M_BMSAFEMAP);
pool_init(&allocdirect_pool, sizeof(struct allocdirect), 0, 0, 0,
"allocdirectpl", 0, pool_page_alloc_nointr, pool_page_free_nointr,
M_ALLOCDIRECT);
pool_init(&indirdep_pool, sizeof(struct indirdep), 0, 0, 0,
"indirdeppl", 0, pool_page_alloc_nointr, pool_page_free_nointr,
M_INDIRDEP);
pool_init(&allocindir_pool, sizeof(struct allocindir), 0, 0, 0,
"allocindirpl", 0, pool_page_alloc_nointr, pool_page_free_nointr,
M_ALLOCINDIR);
pool_init(&freefrag_pool, sizeof(struct freefrag), 0, 0, 0,
"freefragpl", 0, pool_page_alloc_nointr, pool_page_free_nointr,
M_FREEFRAG);
pool_init(&freeblks_pool, sizeof(struct freeblks), 0, 0, 0,
"freeblkspl", 0, pool_page_alloc_nointr, pool_page_free_nointr,
M_FREEBLKS);
pool_init(&freefile_pool, sizeof(struct freefile), 0, 0, 0,
"freefilepl", 0, pool_page_alloc_nointr, pool_page_free_nointr,
M_FREEFILE);
pool_init(&diradd_pool, sizeof(struct diradd), 0, 0, 0,
"diraddpl", 0, pool_page_alloc_nointr, pool_page_free_nointr,
M_DIRADD);
pool_init(&mkdir_pool, sizeof(struct mkdir), 0, 0, 0,
"mkdirpl", 0, pool_page_alloc_nointr, pool_page_free_nointr,
M_MKDIR);
pool_init(&dirrem_pool, sizeof(struct dirrem), 0, 0, 0,
"dirrempl", 0, pool_page_alloc_nointr, pool_page_free_nointr,
M_DIRREM);
}
/*
@ -1142,8 +1292,7 @@ bmsafemap_lookup(bp)
if (wk->wk_type == D_BMSAFEMAP)
return (WK_BMSAFEMAP(wk));
FREE_LOCK(&lk);
MALLOC(bmsafemap, struct bmsafemap *, sizeof(struct bmsafemap),
M_BMSAFEMAP, M_WAITOK);
bmsafemap = pool_get(&bmsafemap_pool, PR_WAITOK);
bmsafemap->sm_list.wk_type = D_BMSAFEMAP;
bmsafemap->sm_list.wk_state = 0;
bmsafemap->sm_buf = bp;
@ -1202,8 +1351,7 @@ softdep_setup_allocdirect(ip, lbn, newblkno, oldblkno, newsize, oldsize, bp)
struct pagedep *pagedep;
struct newblk *newblk;
MALLOC(adp, struct allocdirect *, sizeof(struct allocdirect),
M_ALLOCDIRECT, M_WAITOK);
adp = pool_get(&allocdirect_pool, PR_WAITOK);
bzero(adp, sizeof(struct allocdirect));
adp->ad_list.wk_type = D_ALLOCDIRECT;
adp->ad_lbn = lbn;
@ -1234,7 +1382,7 @@ softdep_setup_allocdirect(ip, lbn, newblkno, oldblkno, newsize, oldsize, bp)
LIST_INSERT_HEAD(&bmsafemap->sm_allocdirecthd, adp, ad_deps);
}
LIST_REMOVE(newblk, nb_hash);
FREE(newblk, M_NEWBLK);
pool_put(&newblk_pool, newblk);
/*
* If we were not passed a bp to attach the dep to,
@ -1366,8 +1514,7 @@ newfreefrag(ip, blkno, size)
fs = ip->i_fs;
if (fragnum(fs, blkno) + numfrags(fs, size) > fs->fs_frag)
panic("newfreefrag: frag size");
MALLOC(freefrag, struct freefrag *, sizeof(struct freefrag),
M_FREEFRAG, M_WAITOK);
freefrag = pool_get(&freefrag_pool, PR_WAITOK);
freefrag->ff_list.wk_type = D_FREEFRAG;
freefrag->ff_state = ip->i_ffs_uid & ~ONWORKLIST; /* XXX - used below */
freefrag->ff_inum = ip->i_number;
@ -1401,7 +1548,7 @@ handle_workitem_freefrag(freefrag)
lockmgr(&vp.v_glock, LK_EXCLUSIVE, NULL);
ffs_blkfree(&tip, freefrag->ff_blkno, freefrag->ff_fragsize);
lockmgr(&vp.v_glock, LK_RELEASE, NULL);
FREE(freefrag, M_FREEFRAG);
pool_put(&freefrag_pool, freefrag);
}
/*
@ -1441,8 +1588,7 @@ newallocindir(ip, ptrno, newblkno, oldblkno)
{
struct allocindir *aip;
MALLOC(aip, struct allocindir *, sizeof(struct allocindir),
M_ALLOCINDIR, M_WAITOK);
aip = pool_get(&allocindir_pool, PR_WAITOK);
bzero(aip, sizeof(struct allocindir));
aip->ai_list.wk_type = D_ALLOCINDIR;
aip->ai_state = ATTACHED;
@ -1571,7 +1717,7 @@ setup_allocindir_phase2(bp, ip, aip)
aip, ai_deps);
}
LIST_REMOVE(newblk, nb_hash);
FREE(newblk, M_NEWBLK);
pool_put(&newblk_pool, newblk);
aip->ai_indirdep = indirdep;
/*
* Check to see if there is an existing dependency
@ -1604,12 +1750,11 @@ setup_allocindir_phase2(bp, ip, aip)
brelse(newindirdep->ir_savebp);
softdep_lockedbufs--;
}
WORKITEM_FREE((caddr_t)newindirdep, D_INDIRDEP);
WORKITEM_FREE(newindirdep, D_INDIRDEP);
}
if (indirdep)
break;
MALLOC(newindirdep, struct indirdep *, sizeof(struct indirdep),
M_INDIRDEP, M_WAITOK);
newindirdep = pool_get(&indirdep_pool, PR_WAITOK);
newindirdep->ir_list.wk_type = D_INDIRDEP;
newindirdep->ir_state = ATTACHED;
LIST_INIT(&newindirdep->ir_deplisthd);
@ -1673,8 +1818,7 @@ softdep_setup_freeblocks(ip, length)
if (length != 0)
panic("softdep_setup_freeblocks: non-zero length");
MALLOC(freeblks, struct freeblks *, sizeof(struct freeblks),
M_FREEBLKS, M_WAITOK);
freeblks = pool_get(&freeblks_pool, PR_WAITOK);
bzero(freeblks, sizeof(struct freeblks));
freeblks->fb_list.wk_type = D_FREEBLKS;
freeblks->fb_uid = ip->i_ffs_uid;
@ -1932,8 +2076,7 @@ softdep_freefile(v)
/*
* This sets up the inode de-allocation dependency.
*/
MALLOC(freefile, struct freefile *, sizeof(struct freefile),
M_FREEFILE, M_WAITOK);
freefile = pool_get(&freefile_pool, PR_WAITOK);
freefile->fx_list.wk_type = D_FREEFILE;
freefile->fx_list.wk_state = 0;
freefile->fx_mode = ap->a_mode;
@ -2261,7 +2404,7 @@ softdep_setup_directory_add(bp, dp, diroffset, newinum, newdirbp)
fs = dp->i_fs;
lbn = lblkno(fs, diroffset);
offset = blkoff(fs, diroffset);
MALLOC(dap, struct diradd *, sizeof(struct diradd), M_DIRADD, M_WAITOK);
dap = pool_get(&diradd_pool, PR_WAITOK);
bzero(dap, sizeof(struct diradd));
dap->da_list.wk_type = D_DIRADD;
dap->da_state = ATTACHED;
@ -2272,13 +2415,11 @@ softdep_setup_directory_add(bp, dp, diroffset, newinum, newdirbp)
ACQUIRE_LOCK(&lk);
} else {
dap->da_state |= MKDIR_BODY | MKDIR_PARENT;
MALLOC(mkdir1, struct mkdir *, sizeof(struct mkdir), M_MKDIR,
M_WAITOK);
mkdir1 = pool_get(&mkdir_pool, PR_WAITOK);
mkdir1->md_list.wk_type = D_MKDIR;
mkdir1->md_state = MKDIR_BODY;
mkdir1->md_diradd = dap;
MALLOC(mkdir2, struct mkdir *, sizeof(struct mkdir), M_MKDIR,
M_WAITOK);
mkdir2 = pool_get(&mkdir_pool, PR_WAITOK);
mkdir2->md_list.wk_type = D_MKDIR;
mkdir2->md_state = MKDIR_PARENT;
mkdir2->md_diradd = dap;
@ -2521,8 +2662,7 @@ newdirrem(bp, dp, ip, isrmdir, prevdirremp)
(void) request_cleanup(FLUSH_REMOVE, 0);
num_dirrem += 1;
MALLOC(dirrem, struct dirrem *, sizeof(struct dirrem),
M_DIRREM, M_WAITOK);
dirrem = pool_get(&dirrem_pool, PR_WAITOK);
bzero(dirrem, sizeof(struct dirrem));
dirrem->dm_list.wk_type = D_DIRREM;
dirrem->dm_state = isrmdir ? RMDIR : 0;
@ -2618,8 +2758,7 @@ softdep_setup_directory_change(bp, dp, ip, newinum, isrmdir)
* Whiteouts do not need diradd dependencies.
*/
if (newinum != WINO) {
MALLOC(dap, struct diradd *, sizeof(struct diradd),
M_DIRADD, M_WAITOK);
dap = pool_get(&diradd_pool, PR_WAITOK);
bzero(dap, sizeof(struct diradd));
dap->da_list.wk_type = D_DIRADD;
dap->da_state = DIRCHG | ATTACHED | DEPCOMPLETE;
@ -3908,12 +4047,8 @@ softdep_fsync(vp)
if (error != 0)
return (error);
if (flushparent) {
#ifdef __FreeBSD__
error = UFS_UPDATE(pvp, 1);
#else
VTOI(pvp)->i_flag |= IN_MODIFIED;
error = VOP_UPDATE(pvp, NULL, NULL, UPDATE_WAIT);
#endif
if (error) {
vput(pvp);
return (error);
@ -4401,12 +4536,8 @@ flush_pagedep_deps(pvp, mp, diraddhdp)
*/
if (dap->da_state & MKDIR_PARENT) {
FREE_LOCK(&lk);
#ifdef __FreeBSD__
error = UFS_UPDATE(pvp, 1);
#else
VTOI(pvp)->i_flag |= IN_MODIFIED;
error = VOP_UPDATE(pvp, NULL, NULL, UPDATE_WAIT);
#endif
if (error)
break;
ACQUIRE_LOCK(&lk);