Fscow_run() may recurse into itself.
Take care by adding a per-lwp recursion counter.
This commit is contained in:
parent
e369394198
commit
961a5d4bcb
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: vfs_trans.c,v 1.19 2008/04/28 20:24:05 martin Exp $ */
|
||||
/* $NetBSD: vfs_trans.c,v 1.20 2008/05/16 09:01:56 hannken Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
|
@ -30,7 +30,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: vfs_trans.c,v 1.19 2008/04/28 20:24:05 martin Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: vfs_trans.c,v 1.20 2008/05/16 09:01:56 hannken Exp $");
|
||||
|
||||
/*
|
||||
* File system transaction operations.
|
||||
|
@ -63,7 +63,8 @@ struct fscow_handler {
|
|||
struct fstrans_lwp_info {
|
||||
struct fstrans_lwp_info *fli_succ;
|
||||
struct mount *fli_mount;
|
||||
int fli_count;
|
||||
int fli_trans_cnt;
|
||||
int fli_cow_cnt;
|
||||
enum fstrans_lock_type fli_lock_type;
|
||||
};
|
||||
struct fstrans_mount_info {
|
||||
|
@ -81,6 +82,7 @@ POOL_INIT(fstrans_pl, sizeof(struct fstrans_lwp_info), 0, 0, 0,
|
|||
"fstrans", NULL, IPL_NONE);
|
||||
|
||||
static void fstrans_lwp_dtor(void *);
|
||||
static struct fstrans_lwp_info *fstrans_get_lwp_info(struct mount *);
|
||||
|
||||
/*
|
||||
* Initialize
|
||||
|
@ -105,8 +107,8 @@ fstrans_lwp_dtor(void *arg)
|
|||
struct fstrans_lwp_info *fli, *fli_next;
|
||||
|
||||
for (fli = arg; fli; fli = fli_next) {
|
||||
KASSERT(fli->fli_mount == NULL);
|
||||
KASSERT(fli->fli_count == 0);
|
||||
KASSERT(fli->fli_trans_cnt == 0);
|
||||
KASSERT(fli->fli_cow_cnt == 0);
|
||||
fli_next = fli->fli_succ;
|
||||
pool_put(&fstrans_pl, fli);
|
||||
}
|
||||
|
@ -155,6 +157,39 @@ fstrans_unmount(struct mount *mp)
|
|||
mp->mnt_transinfo = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve the per lwp info for this mount
|
||||
*/
|
||||
static struct fstrans_lwp_info *
|
||||
fstrans_get_lwp_info(struct mount *mp)
|
||||
{
|
||||
struct fstrans_lwp_info *fli, *new_fli;
|
||||
|
||||
new_fli = NULL;
|
||||
for (fli = lwp_getspecific(lwp_data_key); fli; fli = fli->fli_succ) {
|
||||
if (fli->fli_mount == mp)
|
||||
return fli;
|
||||
else if (fli->fli_trans_cnt == 0 && fli->fli_cow_cnt == 0 &&
|
||||
new_fli == NULL)
|
||||
new_fli = fli;
|
||||
}
|
||||
|
||||
if (new_fli == NULL) {
|
||||
new_fli = pool_get(&fstrans_pl, PR_WAITOK);
|
||||
new_fli->fli_trans_cnt = 0;
|
||||
new_fli->fli_cow_cnt = 0;
|
||||
new_fli->fli_succ = lwp_getspecific(lwp_data_key);
|
||||
lwp_setspecific(lwp_data_key, new_fli);
|
||||
}
|
||||
|
||||
KASSERT(new_fli->fli_trans_cnt == 0);
|
||||
KASSERT(new_fli->fli_cow_cnt == 0);
|
||||
|
||||
new_fli->fli_mount = mp;
|
||||
|
||||
return new_fli;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start a transaction. If this thread already has a transaction on this
|
||||
* file system increment the reference counter.
|
||||
|
@ -167,7 +202,7 @@ _fstrans_start(struct mount *mp, enum fstrans_lock_type lock_type, int wait)
|
|||
{
|
||||
krwlock_t *lock_p;
|
||||
krw_t lock_op;
|
||||
struct fstrans_lwp_info *fli, *new_fli;
|
||||
struct fstrans_lwp_info *fli;
|
||||
struct fstrans_mount_info *fmi;
|
||||
|
||||
ASSERT_SLEEPABLE();
|
||||
|
@ -175,31 +210,16 @@ _fstrans_start(struct mount *mp, enum fstrans_lock_type lock_type, int wait)
|
|||
if (mp == NULL || (mp->mnt_iflag & IMNT_HAS_TRANS) == 0)
|
||||
return 0;
|
||||
|
||||
new_fli = NULL;
|
||||
for (fli = lwp_getspecific(lwp_data_key); fli; fli = fli->fli_succ) {
|
||||
if (fli->fli_mount == NULL && new_fli == NULL)
|
||||
new_fli = fli;
|
||||
if (fli->fli_mount == mp) {
|
||||
KASSERT(fli->fli_count > 0);
|
||||
if (fli->fli_lock_type != FSTRANS_EXCL &&
|
||||
lock_type == FSTRANS_EXCL)
|
||||
panic("fstrans_start: cannot upgrade lock");
|
||||
fli->fli_count += 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
fli = fstrans_get_lwp_info(mp);
|
||||
|
||||
if (new_fli == NULL) {
|
||||
new_fli = pool_get(&fstrans_pl, PR_WAITOK);
|
||||
new_fli->fli_mount = NULL;
|
||||
new_fli->fli_count = 0;
|
||||
new_fli->fli_succ = lwp_getspecific(lwp_data_key);
|
||||
lwp_setspecific(lwp_data_key, new_fli);
|
||||
if (fli->fli_trans_cnt > 0) {
|
||||
if (fli->fli_lock_type != FSTRANS_EXCL &&
|
||||
lock_type == FSTRANS_EXCL)
|
||||
panic("fstrans_start: cannot upgrade lock");
|
||||
fli->fli_trans_cnt += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
KASSERT(new_fli->fli_mount == NULL);
|
||||
KASSERT(new_fli->fli_count == 0);
|
||||
|
||||
fmi = mp->mnt_transinfo;
|
||||
|
||||
if (lock_type == FSTRANS_LAZY)
|
||||
|
@ -213,9 +233,8 @@ _fstrans_start(struct mount *mp, enum fstrans_lock_type lock_type, int wait)
|
|||
else if (rw_tryenter(lock_p, lock_op) == 0)
|
||||
return EBUSY;
|
||||
|
||||
new_fli->fli_mount = mp;
|
||||
new_fli->fli_count = 1;
|
||||
new_fli->fli_lock_type = lock_type;
|
||||
fli->fli_trans_cnt = 1;
|
||||
fli->fli_lock_type = lock_type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -234,8 +253,8 @@ fstrans_done(struct mount *mp)
|
|||
|
||||
for (fli = lwp_getspecific(lwp_data_key); fli; fli = fli->fli_succ) {
|
||||
if (fli->fli_mount == mp) {
|
||||
fli->fli_count -= 1;
|
||||
if (fli->fli_count > 0)
|
||||
fli->fli_trans_cnt -= 1;
|
||||
if (fli->fli_trans_cnt > 0)
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
@ -243,8 +262,8 @@ fstrans_done(struct mount *mp)
|
|||
|
||||
KASSERT(fli != NULL);
|
||||
KASSERT(fli->fli_mount == mp);
|
||||
KASSERT(fli->fli_count == 0);
|
||||
fli->fli_mount = NULL;
|
||||
KASSERT(fli->fli_trans_cnt == 0);
|
||||
|
||||
fmi = mp->mnt_transinfo;
|
||||
KASSERT(fmi != NULL);
|
||||
if (fli->fli_lock_type == FSTRANS_LAZY)
|
||||
|
@ -270,11 +289,11 @@ fstrans_is_owner(struct mount *mp)
|
|||
if (fli->fli_mount == mp)
|
||||
break;
|
||||
|
||||
if (fli == NULL)
|
||||
if (fli == NULL || fli->fli_trans_cnt == 0)
|
||||
return 0;
|
||||
|
||||
KASSERT(fli->fli_mount == mp);
|
||||
KASSERT(fli->fli_count > 0);
|
||||
KASSERT(fli->fli_trans_cnt > 0);
|
||||
return (fli->fli_lock_type == FSTRANS_EXCL);
|
||||
}
|
||||
|
||||
|
@ -387,7 +406,7 @@ fstrans_print_lwp(struct proc *p, struct lwp *l, int verbose)
|
|||
for (fli = _lwp_getspecific_by_lwp(l, lwp_data_key);
|
||||
fli;
|
||||
fli = fli->fli_succ) {
|
||||
if (!verbose && fli->fli_count == 0)
|
||||
if (!verbose && fli->fli_trans_cnt == 0)
|
||||
continue;
|
||||
printf("%-8s", prefix);
|
||||
if (verbose)
|
||||
|
@ -410,7 +429,7 @@ fstrans_print_lwp(struct proc *p, struct lwp *l, int verbose)
|
|||
printf(" %#x", fli->fli_lock_type);
|
||||
break;
|
||||
}
|
||||
printf(" %d\n", fli->fli_count);
|
||||
printf(" %d\n", fli->fli_trans_cnt);
|
||||
prefix[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
@ -524,9 +543,12 @@ fscow_run(struct buf *bp, bool data_valid)
|
|||
{
|
||||
int error = 0;
|
||||
struct mount *mp;
|
||||
struct fstrans_lwp_info *fli;
|
||||
struct fstrans_mount_info *fmi;
|
||||
struct fscow_handler *hp;
|
||||
|
||||
KASSERT(ISSET(bp->b_cflags, BC_BUSY));
|
||||
|
||||
if ((bp->b_flags & B_COWDONE))
|
||||
goto done;
|
||||
if (bp->b_vp == NULL)
|
||||
|
@ -538,13 +560,18 @@ fscow_run(struct buf *bp, bool data_valid)
|
|||
if (mp == NULL || (mp->mnt_iflag & IMNT_HAS_TRANS) == 0)
|
||||
goto done;
|
||||
|
||||
fli = fstrans_get_lwp_info(mp);
|
||||
fmi = mp->mnt_transinfo;
|
||||
|
||||
rw_enter(&fmi->fmi_cow_lock, RW_READER);
|
||||
if (fli->fli_cow_cnt++ == 0)
|
||||
rw_enter(&fmi->fmi_cow_lock, RW_READER);
|
||||
|
||||
SLIST_FOREACH(hp, &fmi->fmi_cow_handler, ch_list)
|
||||
if ((error = (*hp->ch_func)(hp->ch_arg, bp, data_valid)) != 0)
|
||||
break;
|
||||
rw_exit(&fmi->fmi_cow_lock);
|
||||
|
||||
if (--fli->fli_cow_cnt == 0)
|
||||
rw_exit(&fmi->fmi_cow_lock);
|
||||
|
||||
done:
|
||||
if (error == 0)
|
||||
|
|
Loading…
Reference in New Issue