Allow vfs_write_suspend() to wait if the file system is already
suspending. Move vfs_write_suspend() and vfs_write_resume() from kern/vfs_vnops.c to kern/vfs_subr.c. Change vnode write gating in ufs/ffs/ffs_softdep.c (from FreeBSD). When vnodes are throttled in softdep_trackbufs() check for file system suspension every 10 msecs to avoid a deadlock.
This commit is contained in:
parent
6297e36a60
commit
ed68c4e34c
|
@ -1,4 +1,4 @@
|
|||
.\" $NetBSD: vfssubr.9,v 1.7 2003/12/04 23:57:44 wiz Exp $
|
||||
.\" $NetBSD: vfssubr.9,v 1.8 2004/01/10 17:16:38 hannken Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2003 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
|
@ -34,7 +34,7 @@
|
|||
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd December 5, 2003
|
||||
.Dd January 10, 2004
|
||||
.Dt VFSSUBR 9
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -103,7 +103,7 @@
|
|||
.Ft struct vfsops *
|
||||
.Fn vfs_getopsbyname "const char *name"
|
||||
.Ft int
|
||||
.Fn vfs_write_suspend "struct mount *mp"
|
||||
.Fn vfs_write_suspend "struct mount *mp" "int slpflag" "int slptimeo"
|
||||
.Ft void
|
||||
.Fn vfs_write_resume "struct mount *mp"
|
||||
.Sh DESCRIPTION
|
||||
|
@ -189,11 +189,25 @@ look up the vfs operations for that file system (see
|
|||
or return
|
||||
.Dv NULL
|
||||
if file system isn't present in the kernel.
|
||||
.It Fn vfs_write_suspend "mp"
|
||||
.It Fn vfs_write_suspend "mp" "slpflag" "slptimeo"
|
||||
Request a mounted file system to suspend write operations.
|
||||
All new write operations to the file system are stopped.
|
||||
After all write operations in progress have completed, the
|
||||
file system is synced to disk and the function returns.
|
||||
If the file system is currently suspended the
|
||||
.Xr sleep 9
|
||||
flag and timeout are specified by the arguments
|
||||
.Fa slpflag
|
||||
and
|
||||
.Fa slptimeo
|
||||
respectively.
|
||||
If
|
||||
.Fa slptimeo
|
||||
is less than zero
|
||||
.Er EWOULDBLOCK
|
||||
is returned.
|
||||
If the operation is successful zero is returned, otherwise an
|
||||
appropriate error code is returned.
|
||||
.It Fn vfs_write_resume "mp"
|
||||
Request a mounted file system to resume write operations.
|
||||
.El
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: fss.c,v 1.2 2003/12/13 18:59:29 hannken Exp $ */
|
||||
/* $NetBSD: fss.c,v 1.3 2004/01/10 17:16:38 hannken Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2003 The NetBSD Foundation, Inc.
|
||||
|
@ -43,7 +43,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: fss.c,v 1.2 2003/12/13 18:59:29 hannken Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: fss.c,v 1.3 2004/01/10 17:16:38 hannken Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
@ -632,7 +632,7 @@ fss_create_snapshot(struct fss_softc *sc, struct fss_set *fss, struct proc *p)
|
|||
* Activate the snapshot.
|
||||
*/
|
||||
|
||||
if ((error = vfs_write_suspend(sc->sc_mount)) != 0)
|
||||
if ((error = vfs_write_suspend(sc->sc_mount, PUSER|PCATCH, 0)) != 0)
|
||||
goto bad;
|
||||
|
||||
microtime(&sc->sc_time);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: vfs_subr.c,v 1.213 2003/12/30 12:33:24 pk Exp $ */
|
||||
/* $NetBSD: vfs_subr.c,v 1.214 2004/01/10 17:16:38 hannken Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
|
||||
|
@ -78,7 +78,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.213 2003/12/30 12:33:24 pk Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.214 2004/01/10 17:16:38 hannken Exp $");
|
||||
|
||||
#include "opt_inet.h"
|
||||
#include "opt_ddb.h"
|
||||
|
@ -2828,6 +2828,54 @@ vfs_reinit(void)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Request a filesystem to suspend write operations.
|
||||
*/
|
||||
int
|
||||
vfs_write_suspend(struct mount *mp, int slpflag, int slptimeo)
|
||||
{
|
||||
struct proc *p = curproc; /* XXX */
|
||||
int error;
|
||||
|
||||
while ((mp->mnt_iflag & IMNT_SUSPEND)) {
|
||||
if (slptimeo < 0)
|
||||
return EWOULDBLOCK;
|
||||
error = tsleep(&mp->mnt_flag, slpflag, "suspwt1", slptimeo);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
mp->mnt_iflag |= IMNT_SUSPEND;
|
||||
|
||||
if (mp->mnt_writeopcountupper > 0)
|
||||
tsleep(&mp->mnt_writeopcountupper, PUSER - 1, "suspwt", 0);
|
||||
|
||||
error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p);
|
||||
if (error) {
|
||||
vfs_write_resume(mp);
|
||||
return error;
|
||||
}
|
||||
mp->mnt_iflag |= IMNT_SUSPENDLOW;
|
||||
|
||||
if (mp->mnt_writeopcountlower > 0)
|
||||
tsleep(&mp->mnt_writeopcountlower, PUSER - 1, "suspwt", 0);
|
||||
mp->mnt_iflag |= IMNT_SUSPENDED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Request a filesystem to resume write operations.
|
||||
*/
|
||||
void
|
||||
vfs_write_resume(struct mount *mp)
|
||||
{
|
||||
|
||||
if ((mp->mnt_iflag & IMNT_SUSPEND) == 0)
|
||||
return;
|
||||
mp->mnt_iflag &= ~(IMNT_SUSPEND | IMNT_SUSPENDLOW | IMNT_SUSPENDED);
|
||||
wakeup(&mp->mnt_flag);
|
||||
}
|
||||
|
||||
void
|
||||
copy_statfs_info(struct statfs *sbp, const struct mount *mp)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: vfs_vnops.c,v 1.75 2003/10/15 11:29:01 hannken Exp $ */
|
||||
/* $NetBSD: vfs_vnops.c,v 1.76 2004/01/10 17:16:38 hannken Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1982, 1986, 1989, 1993
|
||||
|
@ -37,7 +37,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.75 2003/10/15 11:29:01 hannken Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.76 2004/01/10 17:16:38 hannken Exp $");
|
||||
|
||||
#include "fs_union.h"
|
||||
|
||||
|
@ -825,41 +825,3 @@ vn_restorerecurse(vp, flags)
|
|||
lkp->lk_flags &= ~LK_CANRECURSE;
|
||||
lkp->lk_flags |= flags;
|
||||
}
|
||||
|
||||
/*
|
||||
* Request a filesystem to suspend write operations.
|
||||
*/
|
||||
int
|
||||
vfs_write_suspend(struct mount *mp)
|
||||
{
|
||||
struct proc *p = curproc; /* XXX */
|
||||
int error;
|
||||
|
||||
if (mp->mnt_iflag & IMNT_SUSPEND)
|
||||
return (0);
|
||||
mp->mnt_iflag |= IMNT_SUSPEND;
|
||||
if (mp->mnt_writeopcountupper > 0)
|
||||
tsleep(&mp->mnt_writeopcountupper, PUSER - 1, "suspwt", 0);
|
||||
if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) != 0) {
|
||||
vfs_write_resume(mp);
|
||||
return (error);
|
||||
}
|
||||
mp->mnt_iflag |= IMNT_SUSPENDLOW;
|
||||
if (mp->mnt_writeopcountlower > 0)
|
||||
tsleep(&mp->mnt_writeopcountlower, PUSER - 1, "suspwt", 0);
|
||||
mp->mnt_iflag |= IMNT_SUSPENDED;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Request a filesystem to resume write operations.
|
||||
*/
|
||||
void
|
||||
vfs_write_resume(struct mount *mp)
|
||||
{
|
||||
|
||||
if ((mp->mnt_iflag & IMNT_SUSPEND) == 0)
|
||||
return;
|
||||
mp->mnt_iflag &= ~(IMNT_SUSPEND | IMNT_SUSPENDLOW | IMNT_SUSPENDED);
|
||||
wakeup(&mp->mnt_flag);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: vnode.h,v 1.118 2003/11/18 18:26:18 dbj Exp $ */
|
||||
/* $NetBSD: vnode.h,v 1.119 2004/01/10 17:16:38 hannken Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
|
@ -678,12 +678,12 @@ int getvnode(struct filedesc *fdp, int fd, struct file **fpp);
|
|||
/* see vfssubr(9) */
|
||||
void vfs_getnewfsid(struct mount *);
|
||||
int vfs_drainvnodes(long target, struct proc *);
|
||||
void vfs_write_resume(struct mount *);
|
||||
int vfs_write_suspend(struct mount *, int, int);
|
||||
#ifdef DDB
|
||||
void vfs_vnode_print(struct vnode *, int, void (*)(const char *, ...));
|
||||
void vfs_mount_print(struct mount *, int, void (*)(const char *, ...));
|
||||
#endif /* DDB */
|
||||
void vfs_write_resume(struct mount *);
|
||||
int vfs_write_suspend(struct mount *);
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* !_SYS_VNODE_H_ */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: ffs_softdep.c,v 1.54 2004/01/10 16:23:36 hannken Exp $ */
|
||||
/* $NetBSD: ffs_softdep.c,v 1.55 2004/01/10 17:16:38 hannken Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 1998 Marshall Kirk McKusick. All Rights Reserved.
|
||||
|
@ -33,7 +33,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ffs_softdep.c,v 1.54 2004/01/10 16:23:36 hannken Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: ffs_softdep.c,v 1.55 2004/01/10 17:16:38 hannken Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/buf.h>
|
||||
|
@ -193,7 +193,7 @@ void softdep_pageiodone1 __P((struct buf *));
|
|||
#endif
|
||||
void softdep_pageiodone __P((struct buf *));
|
||||
void softdep_flush_vnode __P((struct vnode *, daddr_t));
|
||||
static void softdep_trackbufs(int, boolean_t);
|
||||
static void softdep_trackbufs(struct inode *, int, boolean_t);
|
||||
|
||||
/*
|
||||
* Exported softdep operations.
|
||||
|
@ -692,9 +692,9 @@ softdep_process_worklist(matchmnt)
|
|||
mp = WK_DIRREM(wk)->dm_mnt;
|
||||
if (mp == matchmnt)
|
||||
matchcnt += 1;
|
||||
vn_start_write(NULL, &mp, V_WAIT);
|
||||
vn_start_write(NULL, &mp, V_WAIT|V_LOWER);
|
||||
handle_workitem_remove(WK_DIRREM(wk));
|
||||
vn_finished_write(mp, 0);
|
||||
vn_finished_write(mp, V_LOWER);
|
||||
break;
|
||||
|
||||
case D_FREEBLKS:
|
||||
|
@ -702,9 +702,9 @@ softdep_process_worklist(matchmnt)
|
|||
mp = WK_FREEBLKS(wk)->fb_ump->um_mountp;
|
||||
if (mp == matchmnt)
|
||||
matchcnt += 1;
|
||||
vn_start_write(NULL, &mp, V_WAIT);
|
||||
vn_start_write(NULL, &mp, V_WAIT|V_LOWER);
|
||||
handle_workitem_freeblocks(WK_FREEBLKS(wk));
|
||||
vn_finished_write(mp, 0);
|
||||
vn_finished_write(mp, V_LOWER);
|
||||
break;
|
||||
|
||||
case D_FREEFRAG:
|
||||
|
@ -712,9 +712,9 @@ softdep_process_worklist(matchmnt)
|
|||
mp = WK_FREEFRAG(wk)->ff_mnt;
|
||||
if (mp == matchmnt)
|
||||
matchcnt += 1;
|
||||
vn_start_write(NULL, &mp, V_WAIT);
|
||||
vn_start_write(NULL, &mp, V_WAIT|V_LOWER);
|
||||
handle_workitem_freefrag(WK_FREEFRAG(wk));
|
||||
vn_finished_write(mp, 0);
|
||||
vn_finished_write(mp, V_LOWER);
|
||||
break;
|
||||
|
||||
case D_FREEFILE:
|
||||
|
@ -722,9 +722,9 @@ softdep_process_worklist(matchmnt)
|
|||
mp = WK_FREEFILE(wk)->fx_mnt;
|
||||
if (mp == matchmnt)
|
||||
matchcnt += 1;
|
||||
vn_start_write(NULL, &mp, V_WAIT);
|
||||
vn_start_write(NULL, &mp, V_WAIT|V_LOWER);
|
||||
handle_workitem_freefile(WK_FREEFILE(wk));
|
||||
vn_finished_write(mp, 0);
|
||||
vn_finished_write(mp, V_LOWER);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1852,7 +1852,7 @@ setup_allocindir_phase2(bp, ip, aip)
|
|||
if (newindirdep) {
|
||||
if (indirdep->ir_savebp != NULL) {
|
||||
brelse(newindirdep->ir_savebp);
|
||||
softdep_trackbufs(-1, FALSE);
|
||||
softdep_trackbufs(ip, -1, FALSE);
|
||||
}
|
||||
WORKITEM_FREE(newindirdep, D_INDIRDEP);
|
||||
}
|
||||
|
@ -1869,7 +1869,7 @@ setup_allocindir_phase2(bp, ip, aip)
|
|||
VOP_BMAP(bp->b_vp, bp->b_lblkno, NULL, &bp->b_blkno,
|
||||
NULL);
|
||||
}
|
||||
softdep_trackbufs(1, TRUE);
|
||||
softdep_trackbufs(ip, 1, TRUE);
|
||||
newindirdep->ir_savebp =
|
||||
getblk(ip->i_devvp, bp->b_blkno, bp->b_bcount, 0, 0);
|
||||
newindirdep->ir_savebp->b_flags |= B_ASYNC;
|
||||
|
@ -2523,7 +2523,7 @@ indir_trunc(ip, dbn, level, lbn, countp)
|
|||
FREE_LOCK(&lk);
|
||||
} else {
|
||||
FREE_LOCK(&lk);
|
||||
softdep_trackbufs(1, FALSE);
|
||||
softdep_trackbufs(ip, 1, FALSE);
|
||||
error = bread(ip->i_devvp, dbn, (int)fs->fs_bsize, NOCRED, &bp);
|
||||
if (error)
|
||||
return (error);
|
||||
|
@ -2559,7 +2559,7 @@ indir_trunc(ip, dbn, level, lbn, countp)
|
|||
}
|
||||
bp->b_flags |= B_INVAL | B_NOCACHE;
|
||||
brelse(bp);
|
||||
softdep_trackbufs(-1, FALSE);
|
||||
softdep_trackbufs(ip, -1, FALSE);
|
||||
return (allerror);
|
||||
}
|
||||
|
||||
|
@ -3400,7 +3400,7 @@ softdep_disk_io_initiation(bp)
|
|||
if (LIST_FIRST(&indirdep->ir_deplisthd) == NULL) {
|
||||
indirdep->ir_savebp->b_flags |= B_INVAL | B_NOCACHE;
|
||||
brelse(indirdep->ir_savebp);
|
||||
softdep_trackbufs(-1, FALSE);
|
||||
softdep_trackbufs(NULL, -1, FALSE);
|
||||
|
||||
/* inline expand WORKLIST_REMOVE(wk); */
|
||||
wk->wk_state &= ~ONWORKLIST;
|
||||
|
@ -5428,9 +5428,9 @@ clear_remove(p)
|
|||
continue;
|
||||
mp = pagedep->pd_mnt;
|
||||
ino = pagedep->pd_ino;
|
||||
if (vn_start_write(NULL, &mp, V_NOWAIT) != 0)
|
||||
continue;
|
||||
FREE_LOCK(&lk);
|
||||
if (vn_start_write(NULL, &mp, V_WAIT | V_PCATCH) != 0)
|
||||
return;
|
||||
if ((error = VFS_VGET(mp, ino, &vp)) != 0) {
|
||||
softdep_error("clear_remove: vget", error);
|
||||
vn_finished_write(mp, 0);
|
||||
|
@ -5501,9 +5501,9 @@ clear_inodedeps(p)
|
|||
for (ino = firstino; ino <= lastino; ino++) {
|
||||
if (inodedep_lookup(fs, ino, 0, &inodedep) == 0)
|
||||
continue;
|
||||
if (vn_start_write(NULL, &mp, V_NOWAIT) != 0)
|
||||
continue;
|
||||
FREE_LOCK(&lk);
|
||||
if (vn_start_write(NULL, &mp, V_WAIT | V_PCATCH) != 0)
|
||||
return;
|
||||
if ((error = VFS_VGET(mp, ino, &vp)) != 0) {
|
||||
softdep_error("clear_inodedeps: vget", error);
|
||||
vn_finished_write(mp, 0);
|
||||
|
@ -5797,8 +5797,9 @@ softdep_lookupvp(fs, ino)
|
|||
}
|
||||
|
||||
static void
|
||||
softdep_trackbufs(int delta, boolean_t throttle)
|
||||
softdep_trackbufs(struct inode *ip, int delta, boolean_t throttle)
|
||||
{
|
||||
struct proc *p = curproc;
|
||||
|
||||
if (delta < 0) {
|
||||
if (softdep_lockedbufs < nbuf >> 2) {
|
||||
|
@ -5809,9 +5810,18 @@ softdep_trackbufs(int delta, boolean_t throttle)
|
|||
return;
|
||||
}
|
||||
|
||||
KASSERT(ip != NULL);
|
||||
/*
|
||||
* Kernel threads never get blocked.
|
||||
* User processes check for file system suspension every 10 msecs.
|
||||
*/
|
||||
while (throttle && softdep_lockedbufs >= nbuf >> 2) {
|
||||
speedup_syncer();
|
||||
tsleep(&softdep_lockedbufs, PRIBIO, "softdbufs", 0);
|
||||
if (p && (p->p_flag & P_SYSTEM))
|
||||
break;
|
||||
tsleep(&softdep_lockedbufs, PRIBIO, "softdbufs", mstohz(10));
|
||||
if ((ITOV(ip)->v_mount->mnt_iflag & IMNT_SUSPEND))
|
||||
break;
|
||||
}
|
||||
softdep_lockedbufs += delta;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue