Add an owner field to fstrans mount info and use it to hold

the thread currently suspending this mount.

Remove now unneeded state FSTRANS_EXCL.

It is now possible to suspend a file system from a thread
already holding fstrans locks.  Use with care ...
This commit is contained in:
hannken 2019-06-17 08:07:27 +00:00
parent a390011a60
commit 7eef6f5745

View File

@ -1,4 +1,4 @@
/* $NetBSD: vfs_trans.c,v 1.60 2019/05/13 08:16:56 hannken Exp $ */
/* $NetBSD: vfs_trans.c,v 1.61 2019/06/17 08:07:27 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.60 2019/05/13 08:16:56 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: vfs_trans.c,v 1.61 2019/06/17 08:07:27 hannken Exp $");
/*
* File system transaction operations.
@ -55,8 +55,7 @@ __KERNEL_RCSID(0, "$NetBSD: vfs_trans.c,v 1.60 2019/05/13 08:16:56 hannken Exp $
enum fstrans_lock_type {
FSTRANS_LAZY, /* Granted while not suspended */
FSTRANS_SHARED, /* Granted while not suspending */
FSTRANS_EXCL /* Internal: exclusive lock */
FSTRANS_SHARED /* Granted while not suspending */
};
struct fscow_handler {
@ -83,6 +82,7 @@ struct fstrans_mount_info {
bool fmi_cow_change;
LIST_HEAD(, fscow_handler) fmi_cow_handler;
struct mount *fmi_mount;
struct lwp *fmi_owner;
};
static kmutex_t vfs_suspend_lock; /* Serialize suspensions. */
@ -101,7 +101,8 @@ static inline struct fstrans_lwp_info *
fstrans_get_lwp_info(struct mount *, bool);
static struct fstrans_lwp_info *fstrans_alloc_lwp_info(struct mount *);
static inline int _fstrans_start(struct mount *, enum fstrans_lock_type, int);
static bool grant_lock(const enum fstrans_state, const enum fstrans_lock_type);
static bool grant_lock(const struct fstrans_mount_info *,
const enum fstrans_lock_type);
static bool state_change_done(const struct fstrans_mount_info *);
static bool cow_state_change_done(const struct fstrans_mount_info *);
static void cow_change_enter(struct fstrans_mount_info *);
@ -233,6 +234,7 @@ fstrans_mount_dtor(struct fstrans_mount_info *fmi)
KASSERT(fmi->fmi_state == FSTRANS_NORMAL);
KASSERT(LIST_FIRST(&fmi->fmi_cow_handler) == NULL);
KASSERT(fmi->fmi_owner == NULL);
KASSERT(fstrans_gone_count > 0);
fstrans_gone_count -= 1;
@ -258,6 +260,7 @@ fstrans_mount(struct mount *mp)
LIST_INIT(&newfmi->fmi_cow_handler);
newfmi->fmi_cow_change = false;
newfmi->fmi_mount = mp;
newfmi->fmi_owner = NULL;
mutex_enter(&fstrans_mount_lock);
mp->mnt_transinfo = newfmi;
@ -433,14 +436,15 @@ fstrans_get_lwp_info(struct mount *mp, bool do_alloc)
* 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)
grant_lock(const struct fstrans_mount_info *fmi,
const enum fstrans_lock_type type)
{
if (__predict_true(state == FSTRANS_NORMAL))
if (__predict_true(fmi->fmi_state == FSTRANS_NORMAL))
return true;
if (type == FSTRANS_EXCL)
if (fmi->fmi_owner == curlwp)
return true;
if (state == FSTRANS_SUSPENDING && type == FSTRANS_LAZY)
if (fmi->fmi_state == FSTRANS_SUSPENDING && type == FSTRANS_LAZY)
return true;
return false;
@ -468,14 +472,13 @@ _fstrans_start(struct mount *mp, enum fstrans_lock_type lock_type, int wait)
fmi = fli->fli_mountinfo;
if (fli->fli_trans_cnt > 0) {
KASSERT(lock_type != FSTRANS_EXCL);
fli->fli_trans_cnt += 1;
return 0;
}
s = pserialize_read_enter();
if (__predict_true(grant_lock(fmi->fmi_state, lock_type))) {
if (__predict_true(grant_lock(fmi, lock_type))) {
fli->fli_trans_cnt = 1;
fli->fli_lock_type = lock_type;
pserialize_read_exit(s);
@ -488,7 +491,7 @@ _fstrans_start(struct mount *mp, enum fstrans_lock_type lock_type, int wait)
return EBUSY;
mutex_enter(&fstrans_lock);
while (! grant_lock(fmi->fmi_state, lock_type))
while (! grant_lock(fmi, lock_type))
cv_wait(&fstrans_state_cv, &fstrans_lock);
fli->fli_trans_cnt = 1;
fli->fli_lock_type = lock_type;
@ -572,15 +575,14 @@ int
fstrans_is_owner(struct mount *mp)
{
struct fstrans_lwp_info *fli;
struct fstrans_mount_info *fmi;
KASSERT(mp != dead_rootmount);
fli = fstrans_get_lwp_info(mp, true);
fmi = fli->fli_mountinfo;
if (fli->fli_trans_cnt == 0)
return 0;
return (fli->fli_lock_type == FSTRANS_EXCL);
return (fmi->fmi_owner == curlwp);
}
/*
@ -598,7 +600,9 @@ state_change_done(const struct fstrans_mount_info *fmi)
continue;
if (fli->fli_trans_cnt == 0)
continue;
if (grant_lock(fmi->fmi_state, fli->fli_lock_type))
if (fli->fli_self == curlwp)
continue;
if (grant_lock(fmi, fli->fli_lock_type))
continue;
return false;
@ -642,16 +646,19 @@ fstrans_setstate(struct mount *mp, enum fstrans_state new_state)
break;
}
}
if (old_state != new_state) {
if (old_state == FSTRANS_NORMAL) {
KASSERT(fmi->fmi_owner == NULL);
fmi->fmi_owner = curlwp;
}
if (new_state == FSTRANS_NORMAL) {
KASSERT(fmi->fmi_owner == curlwp);
fmi->fmi_owner = NULL;
}
}
cv_broadcast(&fstrans_state_cv);
mutex_exit(&fstrans_lock);
if (old_state != new_state) {
if (old_state == FSTRANS_NORMAL)
_fstrans_start(mp, FSTRANS_EXCL, 1);
if (new_state == FSTRANS_NORMAL)
fstrans_done(mp);
}
return error;
}
@ -976,9 +983,6 @@ fstrans_print_lwp(struct proc *p, struct lwp *l, int verbose)
case FSTRANS_SHARED:
printf(" shared");
break;
case FSTRANS_EXCL:
printf(" excl");
break;
default:
printf(" %#x", fli->fli_lock_type);
break;
@ -1004,6 +1008,7 @@ fstrans_print_mount(struct mount *mp, int verbose)
printf("(null)\n");
return;
}
printf("owner %p ", fmi->fmi_owner);
switch (fmi->fmi_state) {
case FSTRANS_NORMAL:
printf("state normal\n");