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.
|
* Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#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.
|
* File system transaction operations.
|
||||||
|
@ -63,7 +63,8 @@ struct fscow_handler {
|
||||||
struct fstrans_lwp_info {
|
struct fstrans_lwp_info {
|
||||||
struct fstrans_lwp_info *fli_succ;
|
struct fstrans_lwp_info *fli_succ;
|
||||||
struct mount *fli_mount;
|
struct mount *fli_mount;
|
||||||
int fli_count;
|
int fli_trans_cnt;
|
||||||
|
int fli_cow_cnt;
|
||||||
enum fstrans_lock_type fli_lock_type;
|
enum fstrans_lock_type fli_lock_type;
|
||||||
};
|
};
|
||||||
struct fstrans_mount_info {
|
struct fstrans_mount_info {
|
||||||
|
@ -81,6 +82,7 @@ POOL_INIT(fstrans_pl, sizeof(struct fstrans_lwp_info), 0, 0, 0,
|
||||||
"fstrans", NULL, IPL_NONE);
|
"fstrans", NULL, IPL_NONE);
|
||||||
|
|
||||||
static void fstrans_lwp_dtor(void *);
|
static void fstrans_lwp_dtor(void *);
|
||||||
|
static struct fstrans_lwp_info *fstrans_get_lwp_info(struct mount *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize
|
* Initialize
|
||||||
|
@ -105,8 +107,8 @@ fstrans_lwp_dtor(void *arg)
|
||||||
struct fstrans_lwp_info *fli, *fli_next;
|
struct fstrans_lwp_info *fli, *fli_next;
|
||||||
|
|
||||||
for (fli = arg; fli; fli = fli_next) {
|
for (fli = arg; fli; fli = fli_next) {
|
||||||
KASSERT(fli->fli_mount == NULL);
|
KASSERT(fli->fli_trans_cnt == 0);
|
||||||
KASSERT(fli->fli_count == 0);
|
KASSERT(fli->fli_cow_cnt == 0);
|
||||||
fli_next = fli->fli_succ;
|
fli_next = fli->fli_succ;
|
||||||
pool_put(&fstrans_pl, fli);
|
pool_put(&fstrans_pl, fli);
|
||||||
}
|
}
|
||||||
|
@ -155,6 +157,39 @@ fstrans_unmount(struct mount *mp)
|
||||||
mp->mnt_transinfo = NULL;
|
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
|
* Start a transaction. If this thread already has a transaction on this
|
||||||
* file system increment the reference counter.
|
* 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;
|
krwlock_t *lock_p;
|
||||||
krw_t lock_op;
|
krw_t lock_op;
|
||||||
struct fstrans_lwp_info *fli, *new_fli;
|
struct fstrans_lwp_info *fli;
|
||||||
struct fstrans_mount_info *fmi;
|
struct fstrans_mount_info *fmi;
|
||||||
|
|
||||||
ASSERT_SLEEPABLE();
|
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)
|
if (mp == NULL || (mp->mnt_iflag & IMNT_HAS_TRANS) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
new_fli = NULL;
|
fli = fstrans_get_lwp_info(mp);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_fli == NULL) {
|
if (fli->fli_trans_cnt > 0) {
|
||||||
new_fli = pool_get(&fstrans_pl, PR_WAITOK);
|
if (fli->fli_lock_type != FSTRANS_EXCL &&
|
||||||
new_fli->fli_mount = NULL;
|
lock_type == FSTRANS_EXCL)
|
||||||
new_fli->fli_count = 0;
|
panic("fstrans_start: cannot upgrade lock");
|
||||||
new_fli->fli_succ = lwp_getspecific(lwp_data_key);
|
fli->fli_trans_cnt += 1;
|
||||||
lwp_setspecific(lwp_data_key, new_fli);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
KASSERT(new_fli->fli_mount == NULL);
|
|
||||||
KASSERT(new_fli->fli_count == 0);
|
|
||||||
|
|
||||||
fmi = mp->mnt_transinfo;
|
fmi = mp->mnt_transinfo;
|
||||||
|
|
||||||
if (lock_type == FSTRANS_LAZY)
|
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)
|
else if (rw_tryenter(lock_p, lock_op) == 0)
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
|
|
||||||
new_fli->fli_mount = mp;
|
fli->fli_trans_cnt = 1;
|
||||||
new_fli->fli_count = 1;
|
fli->fli_lock_type = lock_type;
|
||||||
new_fli->fli_lock_type = lock_type;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -234,8 +253,8 @@ fstrans_done(struct mount *mp)
|
||||||
|
|
||||||
for (fli = lwp_getspecific(lwp_data_key); fli; fli = fli->fli_succ) {
|
for (fli = lwp_getspecific(lwp_data_key); fli; fli = fli->fli_succ) {
|
||||||
if (fli->fli_mount == mp) {
|
if (fli->fli_mount == mp) {
|
||||||
fli->fli_count -= 1;
|
fli->fli_trans_cnt -= 1;
|
||||||
if (fli->fli_count > 0)
|
if (fli->fli_trans_cnt > 0)
|
||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -243,8 +262,8 @@ fstrans_done(struct mount *mp)
|
||||||
|
|
||||||
KASSERT(fli != NULL);
|
KASSERT(fli != NULL);
|
||||||
KASSERT(fli->fli_mount == mp);
|
KASSERT(fli->fli_mount == mp);
|
||||||
KASSERT(fli->fli_count == 0);
|
KASSERT(fli->fli_trans_cnt == 0);
|
||||||
fli->fli_mount = NULL;
|
|
||||||
fmi = mp->mnt_transinfo;
|
fmi = mp->mnt_transinfo;
|
||||||
KASSERT(fmi != NULL);
|
KASSERT(fmi != NULL);
|
||||||
if (fli->fli_lock_type == FSTRANS_LAZY)
|
if (fli->fli_lock_type == FSTRANS_LAZY)
|
||||||
|
@ -270,11 +289,11 @@ fstrans_is_owner(struct mount *mp)
|
||||||
if (fli->fli_mount == mp)
|
if (fli->fli_mount == mp)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (fli == NULL)
|
if (fli == NULL || fli->fli_trans_cnt == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
KASSERT(fli->fli_mount == mp);
|
KASSERT(fli->fli_mount == mp);
|
||||||
KASSERT(fli->fli_count > 0);
|
KASSERT(fli->fli_trans_cnt > 0);
|
||||||
return (fli->fli_lock_type == FSTRANS_EXCL);
|
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);
|
for (fli = _lwp_getspecific_by_lwp(l, lwp_data_key);
|
||||||
fli;
|
fli;
|
||||||
fli = fli->fli_succ) {
|
fli = fli->fli_succ) {
|
||||||
if (!verbose && fli->fli_count == 0)
|
if (!verbose && fli->fli_trans_cnt == 0)
|
||||||
continue;
|
continue;
|
||||||
printf("%-8s", prefix);
|
printf("%-8s", prefix);
|
||||||
if (verbose)
|
if (verbose)
|
||||||
|
@ -410,7 +429,7 @@ fstrans_print_lwp(struct proc *p, struct lwp *l, int verbose)
|
||||||
printf(" %#x", fli->fli_lock_type);
|
printf(" %#x", fli->fli_lock_type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
printf(" %d\n", fli->fli_count);
|
printf(" %d\n", fli->fli_trans_cnt);
|
||||||
prefix[0] = '\0';
|
prefix[0] = '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -524,9 +543,12 @@ fscow_run(struct buf *bp, bool data_valid)
|
||||||
{
|
{
|
||||||
int error = 0;
|
int error = 0;
|
||||||
struct mount *mp;
|
struct mount *mp;
|
||||||
|
struct fstrans_lwp_info *fli;
|
||||||
struct fstrans_mount_info *fmi;
|
struct fstrans_mount_info *fmi;
|
||||||
struct fscow_handler *hp;
|
struct fscow_handler *hp;
|
||||||
|
|
||||||
|
KASSERT(ISSET(bp->b_cflags, BC_BUSY));
|
||||||
|
|
||||||
if ((bp->b_flags & B_COWDONE))
|
if ((bp->b_flags & B_COWDONE))
|
||||||
goto done;
|
goto done;
|
||||||
if (bp->b_vp == NULL)
|
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)
|
if (mp == NULL || (mp->mnt_iflag & IMNT_HAS_TRANS) == 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
fli = fstrans_get_lwp_info(mp);
|
||||||
fmi = mp->mnt_transinfo;
|
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)
|
SLIST_FOREACH(hp, &fmi->fmi_cow_handler, ch_list)
|
||||||
if ((error = (*hp->ch_func)(hp->ch_arg, bp, data_valid)) != 0)
|
if ((error = (*hp->ch_func)(hp->ch_arg, bp, data_valid)) != 0)
|
||||||
break;
|
break;
|
||||||
rw_exit(&fmi->fmi_cow_lock);
|
|
||||||
|
if (--fli->fli_cow_cnt == 0)
|
||||||
|
rw_exit(&fmi->fmi_cow_lock);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
|
|
Loading…
Reference in New Issue