Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/kern Replace the rwlock based implementation with passiv...
details: https://anonhg.NetBSD.org/src/rev/7f8f3f55cca1
branches: trunk
changeset: 784182:7f8f3f55cca1
user: hannken <hannken%NetBSD.org@localhost>
date: Mon Jan 21 09:14:01 2013 +0000
description:
Replace the rwlock based implementation with passive serialization
from pserialize(9) and mutex / condvar.
The fast paths (fstrans_start/fstrans_done on a file system not
suspended or suspending and fscow_run with no change pending) now
run without locks or other atomic operations. Suspension and cow
handler insertion and removal is done with mutex / condvars.
The API remains unchanged.
diffstat:
sys/kern/vfs_trans.c | 722 +++++++++++++++++++++++++++++++++-----------------
1 files changed, 477 insertions(+), 245 deletions(-)
diffs (truncated from 964 to 300 lines):
diff -r 68b23e791aac -r 7f8f3f55cca1 sys/kern/vfs_trans.c
--- a/sys/kern/vfs_trans.c Mon Jan 21 08:02:01 2013 +0000
+++ b/sys/kern/vfs_trans.c Mon Jan 21 09:14:01 2013 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: vfs_trans.c,v 1.25 2009/05/12 11:42:12 yamt Exp $ */
+/* $NetBSD: vfs_trans.c,v 1.26 2013/01/21 09:14:01 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.25 2009/05/12 11:42:12 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_trans.c,v 1.26 2013/01/21 09:14:01 hannken Exp $");
/*
* File system transaction operations.
@@ -38,16 +38,13 @@
#include "opt_ddb.h"
-#if defined(DDB)
-#define _LWP_API_PRIVATE /* Need _lwp_getspecific_by_lwp() */
-#endif
-
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/atomic.h>
#include <sys/buf.h>
#include <sys/kmem.h>
#include <sys/mount.h>
-#include <sys/rwlock.h>
+#include <sys/pserialize.h>
#include <sys/vnode.h>
#define _FSTRANS_API_PRIVATE
#include <sys/fstrans.h>
@@ -57,34 +54,47 @@
#include <miscfs/syncfs/syncfs.h>
struct fscow_handler {
- SLIST_ENTRY(fscow_handler) ch_list;
+ LIST_ENTRY(fscow_handler) ch_list;
int (*ch_func)(void *, struct buf *, bool);
void *ch_arg;
};
struct fstrans_lwp_info {
struct fstrans_lwp_info *fli_succ;
+ struct lwp *fli_self;
struct mount *fli_mount;
int fli_trans_cnt;
int fli_cow_cnt;
enum fstrans_lock_type fli_lock_type;
+ LIST_ENTRY(fstrans_lwp_info) fli_list;
};
struct fstrans_mount_info {
enum fstrans_state fmi_state;
- krwlock_t fmi_shared_lock;
- krwlock_t fmi_lazy_lock;
- krwlock_t fmi_cow_lock;
- SLIST_HEAD(, fscow_handler) fmi_cow_handler;
+ unsigned int fmi_ref_cnt;
+ bool fmi_cow_change;
+ LIST_HEAD(, fscow_handler) fmi_cow_handler;
};
-static specificdata_key_t lwp_data_key;
+static specificdata_key_t lwp_data_key; /* Our specific data key. */
static kmutex_t vfs_suspend_lock; /* Serialize suspensions. */
-static pool_cache_t fstrans_cache;
+static kmutex_t fstrans_lock; /* Fstrans big lock. */
+static kcondvar_t fstrans_state_cv; /* Fstrans or cow state changed. */
+static kcondvar_t fstrans_count_cv; /* Fstrans or cow count changed. */
+static pserialize_t fstrans_psz; /* Pserialize state. */
+static LIST_HEAD(fstrans_lwp_head, fstrans_lwp_info) fstrans_fli_head;
+ /* List of all fstrans_lwp_info. */
+static pool_cache_t fstrans_cache; /* Pool of struct fstrans_lwp_info. */
static void fstrans_lwp_dtor(void *);
-static struct fstrans_lwp_info *fstrans_get_lwp_info(struct mount *);
+static void fstrans_mount_dtor(struct mount *);
+static struct fstrans_lwp_info *fstrans_get_lwp_info(struct mount *, bool);
+static bool grant_lock(const enum fstrans_state, const enum fstrans_lock_type);
+static bool state_change_done(const struct mount *);
+static bool cow_state_change_done(const struct mount *);
+static void cow_change_enter(const struct mount *);
+static void cow_change_done(const struct mount *);
/*
- * Initialize
+ * Initialize.
*/
void
fstrans_init(void)
@@ -95,120 +105,183 @@
KASSERT(error == 0);
mutex_init(&vfs_suspend_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&fstrans_lock, MUTEX_DEFAULT, IPL_NONE);
+ cv_init(&fstrans_state_cv, "fstchg");
+ cv_init(&fstrans_count_cv, "fstcnt");
+ fstrans_psz = pserialize_create();
+ LIST_INIT(&fstrans_fli_head);
fstrans_cache = pool_cache_init(sizeof(struct fstrans_lwp_info), 0, 0,
0, "fstrans", NULL, IPL_NONE, NULL, NULL, NULL);
}
/*
- * Deallocate lwp state
+ * Deallocate lwp state.
*/
static void
fstrans_lwp_dtor(void *arg)
{
struct fstrans_lwp_info *fli, *fli_next;
+ mutex_enter(&fstrans_lock);
for (fli = arg; fli; fli = fli_next) {
KASSERT(fli->fli_trans_cnt == 0);
KASSERT(fli->fli_cow_cnt == 0);
+ if (fli->fli_mount != NULL)
+ fstrans_mount_dtor(fli->fli_mount);
fli_next = fli->fli_succ;
+ LIST_REMOVE(fli, fli_list);
pool_cache_put(fstrans_cache, fli);
}
+ mutex_exit(&fstrans_lock);
}
/*
- * Allocate mount state
+ * Dereference mount state.
+ */
+static void
+fstrans_mount_dtor(struct mount *mp)
+{
+ struct fstrans_mount_info *fmi;
+
+ fmi = mp->mnt_transinfo;
+ if (atomic_dec_uint_nv(&fmi->fmi_ref_cnt) > 0)
+ return;
+
+ KASSERT(fmi->fmi_state == FSTRANS_NORMAL);
+ KASSERT(LIST_FIRST(&fmi->fmi_cow_handler) == NULL);
+
+ kmem_free(fmi, sizeof(*fmi));
+ mp->mnt_iflag &= ~IMNT_HAS_TRANS;
+ mp->mnt_transinfo = NULL;
+
+ vfs_destroy(mp);
+}
+
+/*
+ * Allocate mount state.
*/
int
fstrans_mount(struct mount *mp)
{
+ int error;
struct fstrans_mount_info *new;
+ error = vfs_busy(mp, NULL);
+ if (error)
+ return error;
if ((new = kmem_alloc(sizeof(*new), KM_SLEEP)) == NULL)
return ENOMEM;
new->fmi_state = FSTRANS_NORMAL;
- rw_init(&new->fmi_lazy_lock);
- rw_init(&new->fmi_shared_lock);
- SLIST_INIT(&new->fmi_cow_handler);
- rw_init(&new->fmi_cow_lock);
+ new->fmi_ref_cnt = 1;
+ LIST_INIT(&new->fmi_cow_handler);
+ new->fmi_cow_change = false;
mp->mnt_transinfo = new;
mp->mnt_iflag |= IMNT_HAS_TRANS;
+ vfs_unbusy(mp, true, NULL);
+
return 0;
}
/*
- * Deallocate mount state
+ * Deallocate mount state.
*/
void
fstrans_unmount(struct mount *mp)
{
- struct fstrans_mount_info *fmi;
- struct fscow_handler *hp;
-
- if ((fmi = mp->mnt_transinfo) == NULL)
- return;
- KASSERT(fmi->fmi_state == FSTRANS_NORMAL);
- rw_destroy(&fmi->fmi_lazy_lock);
- rw_destroy(&fmi->fmi_shared_lock);
- rw_enter(&fmi->fmi_cow_lock, RW_WRITER);
- while ((hp = SLIST_FIRST(&fmi->fmi_cow_handler)) != NULL) {
- SLIST_REMOVE(&fmi->fmi_cow_handler, hp, fscow_handler, ch_list);
- kmem_free(hp, sizeof(*hp));
- }
- rw_exit(&fmi->fmi_cow_lock);
- rw_destroy(&fmi->fmi_cow_lock);
- kmem_free(fmi, sizeof(*fmi));
- mp->mnt_iflag &= ~IMNT_HAS_TRANS;
- mp->mnt_transinfo = NULL;
+ KASSERT(mp->mnt_transinfo != NULL);
+
+ fstrans_mount_dtor(mp);
}
/*
- * Retrieve the per lwp info for this mount
+ * Retrieve the per lwp info for this mount allocating if necessary.
*/
static struct fstrans_lwp_info *
-fstrans_get_lwp_info(struct mount *mp)
+fstrans_get_lwp_info(struct mount *mp, bool do_alloc)
{
- struct fstrans_lwp_info *fli, *new_fli;
+ struct fstrans_lwp_info *fli, *res;
+ struct fstrans_mount_info *fmi;
- new_fli = NULL;
+ /*
+ * Scan our list for a match clearing entries whose mount is gone.
+ */
+ res = 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 (fli->fli_mount == mp) {
+ KASSERT(res == NULL);
+ res = fli;
+ } else if (fli->fli_mount != NULL &&
+ (fli->fli_mount->mnt_iflag & IMNT_GONE) != 0 &&
+ fli->fli_trans_cnt == 0 && fli->fli_cow_cnt == 0) {
+ fstrans_mount_dtor(fli->fli_mount);
+ fli->fli_mount = NULL;
+ }
+ }
+ if (__predict_true(res != NULL))
+ return res;
+
+ if (! do_alloc)
+ return NULL;
+
+ /*
+ * Try to reuse a cleared entry or allocate a new one.
+ */
+ for (fli = lwp_getspecific(lwp_data_key); fli; fli = fli->fli_succ) {
+ if (fli->fli_mount == NULL) {
+ KASSERT(fli->fli_trans_cnt == 0);
+ KASSERT(fli->fli_cow_cnt == 0);
+ break;
+ }
+ }
+ if (fli == NULL) {
+ fli = pool_cache_get(fstrans_cache, PR_WAITOK);
+ mutex_enter(&fstrans_lock);
+ memset(fli, 0, sizeof(*fli));
+ fli->fli_self = curlwp;
+ LIST_INSERT_HEAD(&fstrans_fli_head, fli, fli_list);
+ mutex_exit(&fstrans_lock);
+ fli->fli_succ = lwp_getspecific(lwp_data_key);
+ lwp_setspecific(lwp_data_key, fli);
}
- if (new_fli == NULL) {
- new_fli = pool_cache_get(fstrans_cache, 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);
- }
+ /*
+ * Attach the entry to the mount.
+ */
+ fmi = mp->mnt_transinfo;
+ fli->fli_mount = mp;
+ atomic_inc_uint(&fmi->fmi_ref_cnt);
+
+ return fli;
+}
- KASSERT(new_fli->fli_trans_cnt == 0);
- KASSERT(new_fli->fli_cow_cnt == 0);
+/*
+ * Check if this lock type is granted at this state.
+ */
+static bool
+grant_lock(const enum fstrans_state state, const enum fstrans_lock_type type)
+{
Home |
Main Index |
Thread Index |
Old Index