Initial attempt at suspend/snapshot support for userspace file

servers.  This is still pretty much on the level "if it breaks ...".
It should work for single-threaded servers which handle one operation
from start to finish in one go.  Also, it does not yet totally
correctly synchronize metadata and data in some cases.  So needless
to say, it needs improvement, but it is possible that will have to
wait for some lock revampage.
This commit is contained in:
pooka 2007-01-26 22:59:49 +00:00
parent 4ee02bdcac
commit d2595d03c5
7 changed files with 337 additions and 40 deletions

View File

@ -1,7 +1,7 @@
/* $NetBSD: puffs_msgif.c,v 1.15 2007/01/19 13:01:15 pooka Exp $ */
/* $NetBSD: puffs_msgif.c,v 1.16 2007/01/26 22:59:49 pooka Exp $ */
/*
* Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
* Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved.
*
* Development of this software was supported by the
* Google Summer of Code program and the Ulla Tuominen Foundation.
@ -33,9 +33,10 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: puffs_msgif.c,v 1.15 2007/01/19 13:01:15 pooka Exp $");
__KERNEL_RCSID(0, "$NetBSD: puffs_msgif.c,v 1.16 2007/01/26 22:59:49 pooka Exp $");
#include <sys/param.h>
#include <sys/fstrans.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/vnode.h>
@ -80,6 +81,28 @@ puffs_vfstouser(struct puffs_mount *pmp, int optype, void *kbuf, size_t buflen)
return touser(pmp, &park, puffs_getreqid(pmp), NULL, NULL);
}
void
puffs_suspendtouser(struct puffs_mount *pmp, int status)
{
struct puffs_vfsreq_suspend *pvfsr_susp;
struct puffs_park *ppark;
pvfsr_susp = malloc(sizeof(struct puffs_vfsreq_suspend),
M_PUFFS, M_WAITOK | M_ZERO);
ppark = malloc(sizeof(struct puffs_park), M_PUFFS, M_WAITOK | M_ZERO);
pvfsr_susp->pvfsr_status = status;
ppark->park_preq = (struct puffs_req *)pvfsr_susp;
ppark->park_preq->preq_opclass = PUFFSOP_VFS | PUFFSOPFLAG_FAF;
ppark->park_preq->preq_optype = PUFFS_VFS_SUSPEND;
ppark->park_maxlen = ppark->park_copylen
= sizeof(struct puffs_vfsreq_suspend);
(void)touser(pmp, ppark, 0, NULL, NULL);
}
/*
* vnode level request
*/
@ -193,9 +216,34 @@ static int
touser(struct puffs_mount *pmp, struct puffs_park *ppark, uint64_t reqid,
struct vnode *vp1, struct vnode *vp2)
{
struct mount *mp;
struct puffs_req *preq;
mp = PMPTOMP(pmp);
/*
* test for suspension lock.
*
* Note that we *DO NOT* keep the lock, since that might block
* lock acquiring PLUS it would give userlandia control over
* the lock. The operation queue enforces a strict ordering:
* when the fs server gets in the op stream, it knows things
* are in order. The kernel locks can't guarantee that for
* userspace, in any case.
*
* BUT: this presents a problem for ops which have a consistency
* clause based on more than one operation. Unfortunately such
* operations (read, write) do not reliably work yet.
*
* Ya, Ya, it's wrong wong wrong, me be fixink this someday.
*/
if (fstrans_is_owner(mp))
fstrans_start(mp, fstrans_lazy);
else
fstrans_start(mp, fstrans_normal);
simple_lock(&pmp->pmp_lock);
fstrans_done(mp);
if (pmp->pmp_status != PUFFSTAT_RUNNING) {
simple_unlock(&pmp->pmp_lock);
return ENXIO;
@ -239,9 +287,24 @@ touser(struct puffs_mount *pmp, struct puffs_park *ppark, uint64_t reqid,
wakeup(&pmp->pmp_req_touser);
selnotify(pmp->pmp_sel, 0);
if (PUFFSOP_WANTREPLY(ppark->park_preq->preq_opclass))
if (PUFFSOP_WANTREPLY(ppark->park_preq->preq_opclass)) {
ltsleep(ppark, PUSER, "puffs1", 0, NULL);
/*
* retake the lock and release. This makes sure (haha,
* I'm humorous) that we don't process the same vnode in
* multiple threads due to the locks hacks we have in
* puffs_lock(). In reality this is well protected by
* the biglock, but once that's gone, well, hopefully
* this will be fixed for real. (and when you read this
* comment in 2017 and subsequently barf, my condolences ;).
*/
if (!fstrans_is_owner(mp)) {
fstrans_start(mp, fstrans_normal);
fstrans_done(mp);
}
}
#if 0
/* relock */
if (vp1)
@ -250,6 +313,11 @@ touser(struct puffs_mount *pmp, struct puffs_park *ppark, uint64_t reqid,
KASSERT(vn_lock(vp2, LK_EXCLUSIVE | LK_RETRY) == 0);
#endif
simple_lock(&pmp->pmp_lock);
if (--pmp->pmp_req_touser_waiters == 0)
wakeup(&pmp->pmp_req_touser_waiters);
simple_unlock(&pmp->pmp_lock);
return ppark->park_preq->preq_rv;
}
@ -335,8 +403,6 @@ puffs_getop(struct puffs_mount *pmp, struct puffs_reqh_get *phg, int nonblock)
donesome++;
simple_lock(&pmp->pmp_lock);
pmp->pmp_req_touser_waiters--;
if (PUFFSOP_WANTREPLY(preq->preq_opclass)) {
TAILQ_INSERT_TAIL(&pmp->pmp_req_replywait, park,
park_entries);

View File

@ -1,4 +1,4 @@
/* $NetBSD: puffs_msgif.h,v 1.18 2007/01/16 22:38:19 pooka Exp $ */
/* $NetBSD: puffs_msgif.h,v 1.19 2007/01/26 22:59:49 pooka Exp $ */
/*
* Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
@ -59,7 +59,7 @@ enum {
PUFFS_VFS_ROOT, PUFFS_VFS_STATVFS, PUFFS_VFS_SYNC,
PUFFS_VFS_VGET, PUFFS_VFS_FHTOVP, PUFFS_VFS_VPTOFH,
PUFFS_VFS_INIT, PUFFS_VFS_DONE, PUFFS_VFS_SNAPSHOT,
PUFFS_VFS_EXTATTCTL
PUFFS_VFS_EXTATTCTL, PUFFS_VFS_SUSPEND
};
#define PUFFS_VFS_MAX PUFFS_VFS_EXTATTCTL
@ -85,7 +85,7 @@ enum {
#define PUFFS_VN_MAX PUFFS_VN_SETEXTATTR
#define PUFFSDEVELVERS 0x80000000
#define PUFFSVERSION 2
#define PUFFSVERSION 3
#define PUFFSNAMESIZE 32
struct puffs_args {
unsigned int pa_vers;
@ -270,6 +270,7 @@ struct puffs_flush {
#if 0
#define PUFFSFLUSHMULTIOP _IOW ('p', 6, struct puffs_flushmulti)
#endif
#define PUFFSSUSPENDOP _IO ('p', 7)
/*
@ -365,6 +366,16 @@ struct puffs_vfsreq_sync {
int pvfsr_waitfor;
};
struct puffs_vfsreq_suspend {
struct puffs_req pvfsr_pr;
int pvfsr_status;
};
#define PUFFS_SUSPEND_START 0
#define PUFFS_SUSPEND_SUSPENDED 1
#define PUFFS_SUSPEND_RESUME 2
#define PUFFS_SUSPEND_ERROR 3
/*
* aux structures for vnode operations.
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: puffs_subr.c,v 1.17 2007/01/25 17:43:56 pooka Exp $ */
/* $NetBSD: puffs_subr.c,v 1.18 2007/01/26 22:59:49 pooka Exp $ */
/*
* Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: puffs_subr.c,v 1.17 2007/01/25 17:43:56 pooka Exp $");
__KERNEL_RCSID(0, "$NetBSD: puffs_subr.c,v 1.18 2007/01/26 22:59:49 pooka Exp $");
#include <sys/param.h>
#include <sys/conf.h>
@ -446,14 +446,14 @@ puffs_updatevpsize(struct vnode *vp)
* We're dead, kaput, RIP, slightly more than merely pining for the
* fjords, belly-up, fallen, lifeless, finished, expired, gone to meet
* our maker, ceased to be, etcetc. YASD. It's a dead FS!
*
* Caller must hold puffs spinlock.
*/
void
puffs_userdead(struct puffs_mount *pmp)
{
struct puffs_park *park;
simple_lock(&pmp->pmp_lock);
/*
* Mark filesystem status as dying so that operations don't
* attempt to march to userspace any longer.
@ -473,6 +473,4 @@ puffs_userdead(struct puffs_mount *pmp)
TAILQ_REMOVE(&pmp->pmp_req_touser, park, park_entries);
wakeup(park);
}
simple_unlock(&pmp->pmp_lock);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: puffs_sys.h,v 1.21 2007/01/21 16:29:31 pooka Exp $ */
/* $NetBSD: puffs_sys.h,v 1.22 2007/01/26 22:59:49 pooka Exp $ */
/*
* Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
@ -145,6 +145,7 @@ struct puffs_mount {
uint64_t pmp_nextreq;
uint8_t pmp_status;
uint8_t pmp_unmounting;
uint8_t pmp_suspend;
};
#define PUFFSTAT_BEFOREINIT 0
@ -152,7 +153,8 @@ struct puffs_mount {
#define PUFFSTAT_RUNNING 2
#define PUFFSTAT_DYING 3 /* Do you want your possessions identified? */
#define PNODE_NOREFS 0x01 /* vnode invalidated, no backend references */
#define PNODE_NOREFS 0x01 /* vnode inactive, no backend reference */
#define PNODE_SUSPEND 0x02 /* issue all operations as FAF */
#if 0
#define PNODE_LOCKED 0x0
#define PNODE_WANTED 0x0
@ -170,6 +172,7 @@ struct puffs_node {
int puffs_start2(struct puffs_mount *, struct puffs_startreq *);
int puffs_vfstouser(struct puffs_mount *, int, void *, size_t);
void puffs_suspendtouser(struct puffs_mount *, int);
int puffs_vntouser(struct puffs_mount *, int, void *, size_t, void *,
struct vnode *, struct vnode *);
void puffs_vntouser_faf(struct puffs_mount *, int, void *, size_t, void *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: puffs_transport.c,v 1.4 2007/01/09 18:14:31 pooka Exp $ */
/* $NetBSD: puffs_transport.c,v 1.5 2007/01/26 22:59:49 pooka Exp $ */
/*
* Copyright (c) 2006 Antti Kantee. All Rights Reserved.
@ -32,12 +32,14 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: puffs_transport.c,v 1.4 2007/01/09 18:14:31 pooka Exp $");
__KERNEL_RCSID(0, "$NetBSD: puffs_transport.c,v 1.5 2007/01/26 22:59:49 pooka Exp $");
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/fstrans.h>
#include <sys/kthread.h>
#include <sys/malloc.h>
#include <sys/namei.h>
#include <sys/poll.h>
@ -200,6 +202,7 @@ puffs_fop_close(struct file *fp, struct lwp *l)
*/
mp = PMPTOMP(pmp);
simple_unlock(&pi_lock);
simple_lock(&pmp->pmp_lock);
/*
* Free the waiting callers before proceeding any further.
@ -223,7 +226,6 @@ puffs_fop_close(struct file *fp, struct lwp *l)
* since pmp isn't locked. We might end up with PMP_DEAD after
* restart and exit from there.
*/
simple_lock(&pmp->pmp_lock);
if (pmp->pmp_unmounting) {
ltsleep(&pmp->pmp_unmounting, PNORELOCK | PVFS, "puffsum",
0, &pmp->pmp_lock);
@ -233,6 +235,27 @@ puffs_fop_close(struct file *fp, struct lwp *l)
}
simple_unlock(&pmp->pmp_lock);
/*
* Check that suspend isn't running. Issues here:
* + we cannot nuke the mountpoint while suspend is running
* because we risk nuking it from under us (as usual... does
* anyone see a pattern forming?)
* + we must have userdead or the suspend thread might deadlock.
* this has been done above
* + this DOES NOT solve the problem with the regular unmount path.
* however, it is way way way way less likely a problem.
* perhaps vfs_busy() in vfs_suspend() would help?
*/
simple_lock(&pmp->pmp_lock);
if (pmp->pmp_suspend) {
ltsleep(&pmp->pmp_suspend, PNORELOCK | PVFS, "puffsusum",
0, &pmp->pmp_lock);
DPRINTF(("puffs_fop_close: suspend was in progress for pmp %p, "
"restart\n", pmp));
goto restart;
}
simple_unlock(&pmp->pmp_lock);
/*
* Detach from VFS. First do necessary XXX-dance (from
* sys_unmount() & other callers of dounmount()
@ -350,12 +373,51 @@ puffs_flush(struct puffs_mount *pmp, struct puffs_flush *pf)
return rv;
}
#ifdef NEWVNGATE
static void
dosuspendresume(void *arg)
{
struct puffs_mount *pmp = arg;
struct mount *mp;
int rv;
mp = PMPTOMP(pmp);
/*
* XXX? does this really do any good or is it just
* paranoid stupidity? or stupid paranoia?
*/
if (mp->mnt_iflag & IMNT_UNMOUNT) {
printf("puffs dosuspendresume(): detected suspend on "
"unmounting fs\n");
goto out;
}
/* do the dance */
rv = vfs_suspend(PMPTOMP(pmp), 0);
if (rv == 0)
vfs_resume(PMPTOMP(pmp));
simple_lock(&pmp->pmp_lock);
KASSERT(pmp->pmp_suspend);
pmp->pmp_suspend = 0;
wakeup(&pmp->pmp_suspend);
simple_unlock(&pmp->pmp_lock);
out:
kthread_exit(0);
}
#endif
static int
puffs_fop_ioctl(struct file *fp, u_long cmd, void *data, struct lwp *l)
{
struct puffs_mount *pmp = FPTOPMP(fp);
struct puffs_mount *pmp;
int rv;
simple_lock(&pi_lock);
pmp = FPTOPMP(fp);
simple_unlock(&pi_lock);
if (pmp == PMP_EMBRYO || pmp == PMP_DEAD) {
printf("puffs_fop_ioctl: puffs %p, not mounted\n", pmp);
return ENOENT;
@ -384,6 +446,23 @@ puffs_fop_ioctl(struct file *fp, u_long cmd, void *data, struct lwp *l)
rv = puffs_flush(pmp, data);
break;
case PUFFSSUSPENDOP:
#ifdef NEWVNGATE
rv = 0;
simple_lock(&pmp->pmp_lock);
if (pmp->pmp_suspend || pmp->pmp_status != PUFFSTAT_RUNNING)
rv = EBUSY;
else
pmp->pmp_suspend = 1;
simple_unlock(&pmp->pmp_lock);
if (rv)
break;
rv = kthread_create1(dosuspendresume, pmp, NULL, "puffsusp");
#else
rv = EOPNOTSUPP;
#endif
break;
/* already done in sys_ioctl() */
case FIONBIO:
rv = 0;

View File

@ -1,4 +1,4 @@
/* $NetBSD: puffs_vfsops.c,v 1.25 2007/01/25 17:43:56 pooka Exp $ */
/* $NetBSD: puffs_vfsops.c,v 1.26 2007/01/26 22:59:49 pooka Exp $ */
/*
* Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: puffs_vfsops.c,v 1.25 2007/01/25 17:43:56 pooka Exp $");
__KERNEL_RCSID(0, "$NetBSD: puffs_vfsops.c,v 1.26 2007/01/26 22:59:49 pooka Exp $");
#include <sys/param.h>
#include <sys/mount.h>
@ -43,6 +43,7 @@ __KERNEL_RCSID(0, "$NetBSD: puffs_vfsops.c,v 1.25 2007/01/25 17:43:56 pooka Exp
#include <sys/vnode.h>
#include <sys/dirent.h>
#include <sys/kauth.h>
#include <sys/fstrans.h>
#include <lib/libkern/libkern.h>
@ -130,6 +131,9 @@ puffs_mount(struct mount *mp, const char *path, void *data,
mp->mnt_dev_bshift = DEV_BSHIFT;
mp->mnt_flag &= ~MNT_LOCAL; /* we don't really know, so ... */
mp->mnt_data = pmp;
#ifdef NEWVNGATE
mp->mnt_iflag |= IMNT_HAS_TRANS;
#endif
pmp->pmp_status = PUFFSTAT_MOUNTING;
pmp->pmp_nextreq = 0;
@ -284,9 +288,24 @@ puffs_unmount(struct mount *mp, int mntflags, struct lwp *l)
* screw what userland thinks and just die.
*/
if (error == 0 || force) {
pmp->pmp_status = PUFFSTAT_DYING;
/* tell waiters & other resources to go unwait themselves */
puffs_userdead(pmp);
puffs_nukebypmp(pmp);
/*
* Sink waiters. This is still not perfect, since the
* draining is done after userret, not when they really
* exit the file system. It will probably work as almost
* no call will block and therefore cause a context switch
* and therefore will protected by the biglock after
* exiting userspace. But ... it's an imperfect world.
*/
while (pmp->pmp_req_touser_waiters != 0)
ltsleep(&pmp->pmp_req_touser_waiters, PVFS,
"puffsink", 0, &pmp->pmp_lock);
simple_unlock(&pmp->pmp_lock);
/* free resources now that we hopefully have no waiters left */
free(pmp->pmp_pnodehash, M_PUFFS);
FREE(pmp, M_PUFFS);
error = 0;
@ -415,15 +434,17 @@ puffs_statvfs(struct mount *mp, struct statvfs *sbp, struct lwp *l)
return error;
}
int
puffs_sync(struct mount *mp, int waitfor, struct kauth_cred *cred,
struct lwp *l)
static int
pageflush(struct mount *mp, int waitfor, int suspending)
{
struct puffs_node *pn;
struct vnode *vp, *nvp;
int error, rv;
int ppflags;
int error, rv, ppflags;
PUFFS_VFSREQ(sync);
KASSERT(((waitfor == MNT_WAIT) && suspending) == 0);
KASSERT((suspending == 0)
|| (fstrans_is_owner(mp)
&& fstrans_getstate(mp) == fstrans_suspending));
error = 0;
ppflags = PGO_CLEANIT | PGO_ALLPAGES;
@ -444,6 +465,7 @@ puffs_sync(struct mount *mp, int waitfor, struct kauth_cred *cred,
goto loop;
simple_lock(&vp->v_interlock);
pn = VPTOPP(vp);
nvp = TAILQ_NEXT(vp, v_mntvnodes);
if (vp->v_type != VREG || UVM_OBJ_IS_CLEAN(&vp->v_uobj)) {
@ -467,6 +489,9 @@ puffs_sync(struct mount *mp, int waitfor, struct kauth_cred *cred,
* dounmount(), when we are wait-flushing all the dirty
* vnodes through other routes in any case. So there,
* sync() doesn't actually sync. Happy now?
*
* NOTE: if we're suspending, vget() does NOT lock.
* See puffs_lock() for details.
*/
rv = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK);
if (rv) {
@ -476,8 +501,36 @@ puffs_sync(struct mount *mp, int waitfor, struct kauth_cred *cred,
continue;
}
/*
* Thread information to puffs_strategy() through the
* pnode flags: we want to issue the putpages operations
* as FAF if we're suspending, since it's very probable
* that our execution context is that of the userspace
* daemon. We can do this because:
* + we send the "going to suspend" prior to this part
* + if any of the writes fails in userspace, it's the
* file system server's problem to decide if this was a
* failed snapshot when it gets the "snapshot complete"
* notification.
* + if any of the writes fail in the kernel already, we
* immediately fail *and* notify the user server of
* failure.
*
* We also do FAFs if we're called from the syncer. This
* is just general optimization for trickle sync: no need
* to really guarantee that the stuff ended on backing
* storage.
* TODO: Maybe also hint the user server of this twist?
*/
simple_lock(&vp->v_interlock);
if (suspending || waitfor == MNT_LAZY)
pn->pn_stat |= PNODE_SUSPEND;
rv = VOP_PUTPAGES(vp, 0, 0, ppflags);
if (suspending || waitfor == MNT_LAZY) {
simple_lock(&vp->v_interlock);
pn->pn_stat &= ~PNODE_SUSPEND;
simple_unlock(&vp->v_interlock);
}
if (rv)
error = rv;
vput(vp);
@ -485,6 +538,19 @@ puffs_sync(struct mount *mp, int waitfor, struct kauth_cred *cred,
}
simple_unlock(&mntvnode_slock);
return error;
}
int
puffs_sync(struct mount *mp, int waitfor, struct kauth_cred *cred,
struct lwp *l)
{
int error, rv;
PUFFS_VFSREQ(sync);
error = pageflush(mp, waitfor, 0);
/* sync fs */
sync_arg.pvfsr_waitfor = waitfor;
puffs_credcvt(&sync_arg.pvfsr_cred, cred);
@ -555,6 +621,50 @@ puffs_snapshot(struct mount *mp, struct vnode *vp, struct timespec *ts)
return EOPNOTSUPP;
}
int
puffs_suspendctl(struct mount *mp, int cmd)
{
struct puffs_mount *pmp;
int error;
pmp = MPTOPUFFSMP(mp);
switch (cmd) {
case SUSPEND_SUSPEND:
DPRINTF(("puffs_suspendctl: suspending\n"));
if ((error = fstrans_setstate(mp, fstrans_suspending)) != 0)
break;
puffs_suspendtouser(pmp, PUFFS_SUSPEND_START);
error = pageflush(mp, 0, 1);
if (error == 0)
error = fstrans_setstate(mp, fstrans_suspended);
if (error != 0) {
puffs_suspendtouser(pmp, PUFFS_SUSPEND_ERROR);
(void) fstrans_setstate(mp, fstrans_normal);
break;
}
puffs_suspendtouser(pmp, PUFFS_SUSPEND_SUSPENDED);
break;
case SUSPEND_RESUME:
DPRINTF(("puffs_suspendctl: resume\n"));
error = 0;
(void) fstrans_setstate(mp, fstrans_normal);
puffs_suspendtouser(pmp, PUFFS_SUSPEND_RESUME);
break;
default:
error = EINVAL;
break;
}
DPRINTF(("puffs_suspendctl: return %d\n", error));
return error;
}
const struct vnodeopv_desc * const puffs_vnodeopv_descs[] = {
&puffs_vnodeop_opv_desc,
&puffs_specop_opv_desc,
@ -581,7 +691,7 @@ struct vfsops puffs_vfsops = {
NULL, /* mountroot */
puffs_snapshot, /* snapshot */
vfs_stdextattrctl, /* extattrctl */
vfs_stdsuspendctl, /* suspendctl */
puffs_suspendctl, /* suspendctl */
puffs_vnodeopv_descs, /* vnodeops */
0, /* refcount */
{ NULL, NULL }

View File

@ -1,4 +1,4 @@
/* $NetBSD: puffs_vnops.c,v 1.40 2007/01/25 23:43:57 pooka Exp $ */
/* $NetBSD: puffs_vnops.c,v 1.41 2007/01/26 22:59:49 pooka Exp $ */
/*
* Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
@ -33,13 +33,14 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: puffs_vnops.c,v 1.40 2007/01/25 23:43:57 pooka Exp $");
__KERNEL_RCSID(0, "$NetBSD: puffs_vnops.c,v 1.41 2007/01/26 22:59:49 pooka Exp $");
#include <sys/param.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/fstrans.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/namei.h>
#include <sys/vnode.h>
#include <fs/puffs/puffs_msgif.h>
#include <fs/puffs/puffs_sys.h>
@ -948,7 +949,7 @@ puffs_fsync(void *v)
if (!EXISTSOP(pmp, FSYNC) || (pn->pn_stat & PNODE_NOREFS))
return 0;
dofaf = (ap->a_flags & FSYNC_WAIT) == 0;
dofaf = (ap->a_flags & FSYNC_WAIT) == 0 || ap->a_flags == FSYNC_LAZY;
/*
* We abuse VXLOCK to mean "vnode is going to die", so we issue
* only FAFs for those. Otherwise there's a danger of deadlock,
@ -1722,7 +1723,10 @@ puffs_strategy(void *v)
#endif
/*
* See explanation for the necessity of a FAF in puffs_fsync
* See explanation for the necessity of a FAF in puffs_fsync.
*
* Also, do FAF in case we're suspending.
* See puffs_vfsops.c:pageflush()
*
* XXgoddamnX: B_WRITE is a "pseudo flag"
*/
@ -1730,6 +1734,8 @@ puffs_strategy(void *v)
simple_lock(&vp->v_interlock);
if (vp->v_flag & VXLOCK)
dowritefaf = 1;
if (pn->pn_stat & PNODE_SUSPEND)
dowritefaf = 1;
simple_unlock(&vp->v_interlock);
}
@ -1893,9 +1899,7 @@ puffs_bmap(void *v)
return 0;
}
/*
* moreXXX: yes, todo
*/
int
puffs_lock(void *v)
{
@ -1904,11 +1908,29 @@ puffs_lock(void *v)
int a_flags;
} */ *ap = v;
struct vnode *vp = ap->a_vp;
struct mount *mp = vp->v_mount;
#if 0
DPRINTF(("puffs_lock: lock %p, args 0x%x\n", vp, ap->a_flags));
#endif
/*
* XXX: this avoids deadlocking when we're suspending.
* e.g. some ops holding the vnode lock might be blocked for
* the vfs transaction lock so we'd deadlock.
*
* Now once again this is skating on the thin ice of modern life,
* since we are breaking the consistency guarantee provided
* _to the user server_ by vnode locking. Hopefully this will
* get fixed soon enough by getting rid of the dependency on
* vnode locks alltogether.
*/
if (fstrans_is_owner(mp) && fstrans_getstate(mp) == fstrans_suspending){
if (ap->a_flags & LK_INTERLOCK)
simple_unlock(&vp->v_interlock);
return 0;
}
return lockmgr(&vp->v_lock, ap->a_flags, &vp->v_interlock);
}
@ -1920,11 +1942,19 @@ puffs_unlock(void *v)
int a_flags;
} */ *ap = v;
struct vnode *vp = ap->a_vp;
struct mount *mp = vp->v_mount;
#if 0
DPRINTF(("puffs_unlock: lock %p, args 0x%x\n", vp, ap->a_flags));
#endif
/* XXX: see puffs_lock() */
if (fstrans_is_owner(mp) && fstrans_getstate(mp) == fstrans_suspending){
if (ap->a_flags & LK_INTERLOCK)
simple_unlock(&vp->v_interlock);
return 0;
}
return lockmgr(&vp->v_lock, ap->a_flags | LK_RELEASE, &vp->v_interlock);
}