Use vn_start_secondary_write() and vn_finished_secondary_write() as a

replacement for vn_write_suspend_wait() to better account for secondary write
processing.

Close race where secondary writes could be started after ffs_sync() returned
but before the file system was marked as suspended.

Detect if secondary writes or softdep processing occurred during vnode sync
loop in ffs_sync() and retry the loop if needed.
This commit is contained in:
Tor Egge 2006-03-08 23:43:39 +00:00
parent be957ba522
commit 791dd2fade
11 changed files with 344 additions and 18 deletions

View file

@ -498,6 +498,16 @@ vfs_mount_destroy(struct mount *mp, struct thread *td)
}
printf("mount point write ops completed\n");
}
if (mp->mnt_secondary_writes > 0) {
printf("Waiting for mount point secondary write ops\n");
while (mp->mnt_secondary_writes > 0) {
mp->mnt_kern_flag |= MNTK_SUSPEND;
msleep(&mp->mnt_secondary_writes,
MNT_MTX(mp),
PZERO, "mntdestroy3", 0);
}
printf("mount point secondary write ops completed\n");
}
MNT_IUNLOCK(mp);
mp->mnt_vfc->vfc_refcount--;
if (!TAILQ_EMPTY(&mp->mnt_nvnodelist))
@ -508,10 +518,13 @@ vfs_mount_destroy(struct mount *mp, struct thread *td)
wakeup(mp);
if (mp->mnt_writeopcount != 0)
panic("vfs_mount_destroy: nonzero writeopcount");
if (mp->mnt_secondary_writes != 0)
panic("vfs_mount_destroy: nonzero secondary_writes");
if (mp->mnt_nvnodelistsize != 0)
panic("vfs_mount_destroy: nonzero nvnodelistsize");
mp->mnt_writeopcount = -1000;
mp->mnt_nvnodelistsize = -1000;
mp->mnt_secondary_writes = -1000;
MNT_IUNLOCK(mp);
mtx_destroy(&mp->mnt_mtx);
#ifdef MAC

View file

@ -2052,12 +2052,19 @@ vrele(struct vnode *vp)
* We must call VOP_INACTIVE with the node locked. Mark
* as VI_DOINGINACT to avoid recursion.
*/
vp->v_iflag |= VI_OWEINACT;
if (vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK, td) == 0) {
VI_LOCK(vp);
vinactive(vp, td);
if (vp->v_usecount > 0)
vp->v_iflag &= ~VI_OWEINACT;
if (vp->v_iflag & VI_OWEINACT)
vinactive(vp, td);
VOP_UNLOCK(vp, 0, td);
} else
} else {
VI_LOCK(vp);
if (vp->v_usecount > 0)
vp->v_iflag &= ~VI_OWEINACT;
}
vdropl(vp);
}
@ -2104,9 +2111,14 @@ vput(struct vnode *vp)
if (VOP_ISLOCKED(vp, NULL) != LK_EXCLUSIVE) {
error = VOP_LOCK(vp, LK_EXCLUPGRADE|LK_INTERLOCK|LK_NOWAIT, td);
VI_LOCK(vp);
if (error)
if (error) {
if (vp->v_usecount > 0)
vp->v_iflag &= ~VI_OWEINACT;
goto done;
}
}
if (vp->v_usecount > 0)
vp->v_iflag &= ~VI_OWEINACT;
if (vp->v_iflag & VI_OWEINACT)
vinactive(vp, td);
VOP_UNLOCK(vp, 0, td);
@ -2368,6 +2380,7 @@ vgonel(struct vnode *vp)
struct thread *td;
int oweinact;
int active;
struct mount *mp;
CTR1(KTR_VFS, "vgonel: vp %p", vp);
ASSERT_VOP_LOCKED(vp, "vgonel");
@ -2396,8 +2409,9 @@ vgonel(struct vnode *vp)
* Clean out any buffers associated with the vnode.
* If the flush fails, just toss the buffers.
*/
mp = NULL;
if (!TAILQ_EMPTY(&vp->v_bufobj.bo_dirty.bv_hd))
(void) vn_write_suspend_wait(vp, NULL, V_WAIT);
(void) vn_start_secondary_write(vp, &mp, V_WAIT);
if (vinvalbuf(vp, V_SAVE, td, 0, 0) != 0)
vinvalbuf(vp, 0, td, 0, 0);
@ -2418,6 +2432,8 @@ vgonel(struct vnode *vp)
*/
if (VOP_RECLAIM(vp, td))
panic("vgone: cannot reclaim");
if (mp != NULL)
vn_finished_secondary_write(mp);
VNASSERT(vp->v_object == NULL, vp,
("vop_reclaim left v_object vp=%p, tag=%s", vp, vp->v_tag));
/*

View file

@ -950,6 +950,58 @@ vn_write_suspend_wait(vp, mp, flags)
(PUSER - 1) | (flags & PCATCH) | PDROP, "suspfs", 0));
}
/*
* Secondary suspension. Used by operations such as vop_inactive
* routines that are needed by the higher level functions. These
* are allowed to proceed until all the higher level functions have
* completed (indicated by mnt_writeopcount dropping to zero). At that
* time, these operations are halted until the suspension is over.
*/
int
vn_start_secondary_write(vp, mpp, flags)
struct vnode *vp;
struct mount **mpp;
int flags;
{
struct mount *mp;
int error;
retry:
if (vp != NULL) {
if ((error = VOP_GETWRITEMOUNT(vp, mpp)) != 0) {
*mpp = NULL;
if (error != EOPNOTSUPP)
return (error);
return (0);
}
}
/*
* If we are not suspended or have not yet reached suspended
* mode, then let the operation proceed.
*/
if ((mp = *mpp) == NULL)
return (0);
MNT_ILOCK(mp);
if ((mp->mnt_kern_flag & MNTK_SUSPENDED) == 0) {
mp->mnt_secondary_writes++;
mp->mnt_secondary_accwrites++;
MNT_IUNLOCK(mp);
return (0);
}
if (flags & V_NOWAIT) {
MNT_IUNLOCK(mp);
return (EWOULDBLOCK);
}
/*
* Wait for the suspension to finish.
*/
error = msleep(&mp->mnt_flag, MNT_MTX(mp),
(PUSER - 1) | (flags & PCATCH) | PDROP, "suspfs", 0);
if (error == 0)
goto retry;
return (error);
}
/*
* Filesystem write operation has completed. If we are suspending and this
* operation is the last one, notify the suspender that the suspension is
@ -971,6 +1023,30 @@ vn_finished_write(mp)
MNT_IUNLOCK(mp);
}
/*
* Filesystem secondary write operation has completed. If we are
* suspending and this operation is the last one, notify the suspender
* that the suspension is now in effect.
*/
void
vn_finished_secondary_write(mp)
struct mount *mp;
{
if (mp == NULL)
return;
MNT_ILOCK(mp);
mp->mnt_secondary_writes--;
if (mp->mnt_secondary_writes < 0)
panic("vn_finished_secondary_write: neg cnt");
if ((mp->mnt_kern_flag & MNTK_SUSPEND) != 0 &&
mp->mnt_secondary_writes <= 0)
wakeup(&mp->mnt_secondary_writes);
MNT_IUNLOCK(mp);
}
/*
* Request a filesystem to suspend write operations.
*/
@ -991,12 +1067,11 @@ vfs_write_suspend(mp)
MNT_MTX(mp), (PUSER - 1)|PDROP, "suspwt", 0);
else
MNT_IUNLOCK(mp);
if ((error = VFS_SYNC(mp, MNT_WAIT, td)) != 0) {
if ((error = VFS_SYNC(mp, MNT_SUSPEND, td)) != 0) {
vfs_write_resume(mp);
return (error);
}
MNT_ILOCK(mp);
mp->mnt_kern_flag |= MNTK_SUSPENDED;
unlock:
MNT_IUNLOCK(mp);
return (error);

View file

@ -171,6 +171,8 @@ struct mount {
int mnt_markercnt; /* marker vnodes in use */
int mnt_holdcnt; /* hold count */
int mnt_holdcntwaiters; /* waits on hold count */
int mnt_secondary_writes; /* (i) # of secondary writes */
int mnt_secondary_accwrites;/* (i) secondary wr. starts */
};
struct vnode *__mnt_vnode_next(struct vnode **mvp, struct mount *mp);
@ -192,6 +194,7 @@ void __mnt_vnode_markerfree(struct vnode **mvp, struct mount *mp);
} while (0)
#define MNT_ILOCK(mp) mtx_lock(&(mp)->mnt_mtx)
#define MNT_ITRYLOCK(mp) mtx_trylock(&(mp)->mnt_mtx)
#define MNT_IUNLOCK(mp) mtx_unlock(&(mp)->mnt_mtx)
#define MNT_MTX(mp) (&(mp)->mnt_mtx)
#define MNT_REF(mp) (mp)->mnt_ref++
@ -331,6 +334,7 @@ void __mnt_vnode_markerfree(struct vnode **mvp, struct mount *mp);
#define MNT_WAIT 1 /* synchronously wait for I/O to complete */
#define MNT_NOWAIT 2 /* start all I/O, but do not wait for it */
#define MNT_LAZY 3 /* push data not written by filesystem syncer */
#define MNT_SUSPEND 4 /* Suspend file system after sync */
/*
* Generic file handle

View file

@ -603,6 +603,7 @@ int vrecycle(struct vnode *vp, struct thread *td);
int vn_close(struct vnode *vp,
int flags, struct ucred *file_cred, struct thread *td);
void vn_finished_write(struct mount *mp);
void vn_finished_secondary_write(struct mount *mp);
int vn_isdisk(struct vnode *vp, int *errp);
int vn_lock(struct vnode *vp, int flags, struct thread *td);
int vn_open(struct nameidata *ndp, int *flagp, int cmode, int fdidx);
@ -620,6 +621,8 @@ int vn_rdwr_inchunks(enum uio_rw rw, struct vnode *vp, void *base,
int vn_stat(struct vnode *vp, struct stat *sb, struct ucred *active_cred,
struct ucred *file_cred, struct thread *td);
int vn_start_write(struct vnode *vp, struct mount **mpp, int flags);
int vn_start_secondary_write(struct vnode *vp, struct mount **mpp,
int flags);
int vn_write_suspend_wait(struct vnode *vp, struct mount *mp,
int flags);
int vn_writechk(struct vnode *vp);

View file

@ -94,6 +94,10 @@ extern struct vop_vector ffs_fifoops2;
/*
* Soft update function prototypes.
*/
int softdep_check_suspend(struct mount *, struct vnode *,
int, int, int, int);
void softdep_get_depcounts(struct mount *, int *, int *);
void softdep_initialize(void);
void softdep_uninitialize(void);
int softdep_mount(struct vnode *, struct mount *, struct fs *,

View file

@ -346,6 +346,68 @@ softdep_request_cleanup(fs, vp)
return (0);
}
int
softdep_check_suspend(struct mount *mp,
struct vnode *devvp,
int softdep_deps,
int softdep_accdeps,
int secondary_writes,
int secondary_accwrites)
{
struct bufobj *bo;
int error;
(void) softdep_deps,
(void) softdep_accdeps;
ASSERT_VI_LOCKED(devvp, "softdep_check_suspend");
bo = &devvp->v_bufobj;
for (;;) {
if (!MNT_ITRYLOCK(mp)) {
VI_UNLOCK(devvp);
MNT_ILOCK(mp);
MNT_IUNLOCK(mp);
VI_LOCK(devvp);
continue;
}
if (mp->mnt_secondary_writes != 0) {
VI_UNLOCK(devvp);
msleep(&mp->mnt_secondary_writes,
MNT_MTX(mp),
(PUSER - 1) | PDROP, "secwr", 0);
VI_LOCK(devvp);
continue;
}
break;
}
/*
* Reasons for needing more work before suspend:
* - Dirty buffers on devvp.
* - Secondary writes occurred after start of vnode sync loop
*/
error = 0;
if (bo->bo_numoutput > 0 ||
bo->bo_dirty.bv_cnt > 0 ||
secondary_writes != 0 ||
mp->mnt_secondary_writes != 0 ||
secondary_accwrites != mp->mnt_secondary_accwrites)
error = EAGAIN;
VI_UNLOCK(devvp);
return (error);
}
void
softdep_get_depcounts(struct mount *mp,
int *softdepactivep,
int *softdepactiveaccp)
{
(void) mp;
*softdepactivep = 0;
*softdepactiveaccp = 0;
}
#else
/*
* These definitions need to be adapted to the system to which
@ -500,6 +562,7 @@ static int softdep_count_dependencies(struct buf *bp, int);
static struct mtx lk;
MTX_SYSINIT(softdep_lock, &lk, "Softdep Lock", MTX_DEF);
#define TRY_ACQUIRE_LOCK(lk) mtx_trylock(lk)
#define ACQUIRE_LOCK(lk) mtx_lock(lk)
#define FREE_LOCK(lk) mtx_unlock(lk)
@ -588,6 +651,7 @@ workitem_alloc(item, type, mp)
item->wk_state = 0;
ACQUIRE_LOCK(&lk);
VFSTOUFS(mp)->softdep_deps++;
VFSTOUFS(mp)->softdep_accdeps++;
FREE_LOCK(&lk);
}
@ -873,7 +937,7 @@ process_worklist_item(mp, flags)
}
ump->softdep_on_worklist -= 1;
FREE_LOCK(&lk);
if (vn_write_suspend_wait(NULL, mp, V_NOWAIT))
if (vn_start_secondary_write(NULL, &mp, V_NOWAIT))
panic("process_worklist_item: suspended filesystem");
matchcnt++;
switch (wk->wk_type) {
@ -903,6 +967,7 @@ process_worklist_item(mp, flags)
"softdep", TYPENAME(wk->wk_type));
/* NOTREACHED */
}
vn_finished_secondary_write(mp);
ACQUIRE_LOCK(&lk);
return (matchcnt);
}
@ -6000,6 +6065,98 @@ getdirtybuf(bp, mtx, waitfor)
return (bp);
}
/*
* Check if it is safe to suspend the file system now. On entry,
* the vnode interlock for devvp should be held. Return 0 with
* the mount interlock held if the file system can be suspended now,
* otherwise return EAGAIN with the mount interlock held.
*/
int
softdep_check_suspend(struct mount *mp,
struct vnode *devvp,
int softdep_deps,
int softdep_accdeps,
int secondary_writes,
int secondary_accwrites)
{
struct bufobj *bo;
struct ufsmount *ump;
int error;
ASSERT_VI_LOCKED(devvp, "softdep_check_suspend");
ump = VFSTOUFS(mp);
bo = &devvp->v_bufobj;
for (;;) {
if (!TRY_ACQUIRE_LOCK(&lk)) {
VI_UNLOCK(devvp);
ACQUIRE_LOCK(&lk);
FREE_LOCK(&lk);
VI_LOCK(devvp);
continue;
}
if (!MNT_ITRYLOCK(mp)) {
FREE_LOCK(&lk);
VI_UNLOCK(devvp);
MNT_ILOCK(mp);
MNT_IUNLOCK(mp);
VI_LOCK(devvp);
continue;
}
if (mp->mnt_secondary_writes != 0) {
FREE_LOCK(&lk);
VI_UNLOCK(devvp);
msleep(&mp->mnt_secondary_writes,
MNT_MTX(mp),
(PUSER - 1) | PDROP, "secwr", 0);
VI_LOCK(devvp);
continue;
}
break;
}
/*
* Reasons for needing more work before suspend:
* - Dirty buffers on devvp.
* - Softdep activity occurred after start of vnode sync loop
* - Secondary writes occurred after start of vnode sync loop
*/
error = 0;
if (bo->bo_numoutput > 0 ||
bo->bo_dirty.bv_cnt > 0 ||
softdep_deps != 0 ||
ump->softdep_deps != 0 ||
softdep_accdeps != ump->softdep_accdeps ||
secondary_writes != 0 ||
mp->mnt_secondary_writes != 0 ||
secondary_accwrites != mp->mnt_secondary_accwrites)
error = EAGAIN;
FREE_LOCK(&lk);
VI_UNLOCK(devvp);
return (error);
}
/*
* Get the number of dependency structures for the file system, both
* the current number and the total number allocated. These will
* later be used to detect that softdep processing has occurred.
*/
void
softdep_get_depcounts(struct mount *mp,
int *softdep_depsp,
int *softdep_accdepsp)
{
struct ufsmount *ump;
ump = VFSTOUFS(mp);
ACQUIRE_LOCK(&lk);
*softdep_depsp = ump->softdep_deps;
*softdep_accdepsp = ump->softdep_accdeps;
FREE_LOCK(&lk);
}
/*
* Wait for pending output on a vnode to complete.
* Must be called with vnode lock and interlock locked.

View file

@ -70,7 +70,7 @@ __FBSDID("$FreeBSD$");
static uma_zone_t uma_inode, uma_ufs1, uma_ufs2;
static int ffs_sbupdate(struct ufsmount *, int);
static int ffs_sbupdate(struct ufsmount *, int, int);
static int ffs_reload(struct mount *, struct thread *);
static int ffs_mountfs(struct vnode *, struct mount *, struct thread *);
static void ffs_oldfscompat_read(struct fs *, struct ufsmount *,
@ -234,7 +234,7 @@ ffs_mount(struct mount *mp, struct thread *td)
}
if ((fs->fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0)
fs->fs_clean = 1;
if ((error = ffs_sbupdate(ump, MNT_WAIT)) != 0) {
if ((error = ffs_sbupdate(ump, MNT_WAIT, 0)) != 0) {
fs->fs_ronly = 0;
fs->fs_clean = 0;
vn_finished_write(mp);
@ -301,7 +301,7 @@ ffs_mount(struct mount *mp, struct thread *td)
fs->fs_ronly = 0;
mp->mnt_flag &= ~MNT_RDONLY;
fs->fs_clean = 0;
if ((error = ffs_sbupdate(ump, MNT_WAIT)) != 0) {
if ((error = ffs_sbupdate(ump, MNT_WAIT, 0)) != 0) {
vn_finished_write(mp);
return (error);
}
@ -806,7 +806,7 @@ ffs_mountfs(devvp, mp, td)
ffs_snapshot_mount(mp);
fs->fs_fmod = 1;
fs->fs_clean = 0;
(void) ffs_sbupdate(ump, MNT_WAIT);
(void) ffs_sbupdate(ump, MNT_WAIT, 0);
}
/*
* Initialize filesystem stat information in mount struct.
@ -988,7 +988,7 @@ ffs_unmount(mp, mntflags, td)
UFS_UNLOCK(ump);
if (fs->fs_ronly == 0) {
fs->fs_clean = fs->fs_flags & (FS_UNCLEAN|FS_NEEDSFSCK) ? 0 : 1;
error = ffs_sbupdate(ump, MNT_WAIT);
error = ffs_sbupdate(ump, MNT_WAIT, 0);
if (error) {
fs->fs_clean = 0;
return (error);
@ -1113,6 +1113,12 @@ ffs_sync(mp, waitfor, td)
struct ufsmount *ump = VFSTOUFS(mp);
struct fs *fs;
int error, count, wait, lockreq, allerror = 0;
int suspend;
int suspended;
int secondary_writes;
int secondary_accwrites;
int softdep_deps;
int softdep_accdeps;
struct bufobj *bo;
fs = ump->um_fs;
@ -1124,14 +1130,30 @@ ffs_sync(mp, waitfor, td)
* Write back each (modified) inode.
*/
wait = 0;
suspend = 0;
suspended = 0;
lockreq = LK_EXCLUSIVE | LK_NOWAIT;
if (waitfor == MNT_SUSPEND) {
suspend = 1;
waitfor = MNT_WAIT;
}
if (waitfor == MNT_WAIT) {
wait = 1;
lockreq = LK_EXCLUSIVE;
}
lockreq |= LK_INTERLOCK | LK_SLEEPFAIL;
MNT_ILOCK(mp);
MNT_REF(mp);
loop:
/* Grab snapshot of secondary write counts */
secondary_writes = mp->mnt_secondary_writes;
secondary_accwrites = mp->mnt_secondary_accwrites;
/* Grab snapshot of softdep dependency counts */
MNT_IUNLOCK(mp);
softdep_get_depcounts(mp, &softdep_deps, &softdep_accdeps);
MNT_ILOCK(mp);
MNT_VNODE_FOREACH(vp, mp, mvp) {
/*
* Depend on the mntvnode_slock to keep things stable enough
@ -1165,6 +1187,7 @@ loop:
vput(vp);
MNT_ILOCK(mp);
}
MNT_REL(mp);
MNT_IUNLOCK(mp);
/*
* Force stale filesystem control information to be flushed.
@ -1194,12 +1217,25 @@ loop:
MNT_ILOCK(mp);
goto loop;
}
} else if (suspend != 0) {
if (softdep_check_suspend(mp,
devvp,
softdep_deps,
softdep_accdeps,
secondary_writes,
secondary_accwrites) != 0)
goto loop; /* More work needed */
mtx_assert(MNT_MTX(mp), MA_OWNED);
mp->mnt_kern_flag |= MNTK_SUSPENDED;
MNT_IUNLOCK(mp);
suspended = 1;
} else
VI_UNLOCK(devvp);
/*
* Write back modified superblock.
*/
if (fs->fs_fmod != 0 && (error = ffs_sbupdate(ump, waitfor)) != 0)
if (fs->fs_fmod != 0 &&
(error = ffs_sbupdate(ump, waitfor, suspended)) != 0)
allerror = error;
return (allerror);
}
@ -1449,9 +1485,10 @@ ffs_uninit(vfsp)
* Write a superblock and associated information back to disk.
*/
static int
ffs_sbupdate(mp, waitfor)
ffs_sbupdate(mp, waitfor, suspended)
struct ufsmount *mp;
int waitfor;
int suspended;
{
struct fs *fs = mp->um_fs;
struct buf *sbbp;
@ -1482,6 +1519,8 @@ ffs_sbupdate(mp, waitfor)
size, 0, 0, 0);
bcopy(space, bp->b_data, (u_int)size);
space = (char *)space + size;
if (suspended)
bp->b_flags |= B_VALIDSUSPWRT;
if (waitfor != MNT_WAIT)
bawrite(bp);
else if ((error = bwrite(bp)) != 0)
@ -1513,6 +1552,8 @@ ffs_sbupdate(mp, waitfor)
fs->fs_time = time_second;
bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize);
ffs_oldfscompat_write((struct fs *)bp->b_data, mp);
if (suspended)
bp->b_flags |= B_VALIDSUSPWRT;
if (waitfor != MNT_WAIT)
bawrite(bp);
else if ((error = bwrite(bp)) != 0)

View file

@ -73,7 +73,9 @@ ufs_inactive(ap)
struct thread *td = ap->a_td;
mode_t mode;
int error = 0;
struct mount *mp;
mp = NULL;
if (prtactive && vp->v_usecount != 0)
vprint("ufs_inactive: pushing active", vp);
/*
@ -84,7 +86,7 @@ ufs_inactive(ap)
if (ip->i_effnlink == 0 && DOINGSOFTDEP(vp))
softdep_releasefile(ip);
if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
(void) vn_write_suspend_wait(vp, NULL, V_WAIT);
(void) vn_start_secondary_write(vp, &mp, V_WAIT);
#ifdef QUOTA
if (!getinoquota(ip))
(void)chkiq(ip, -1, NOCRED, FORCE);
@ -111,10 +113,14 @@ ufs_inactive(ap)
}
if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) {
if ((ip->i_flag & (IN_CHANGE | IN_UPDATE | IN_MODIFIED)) == 0 &&
vn_write_suspend_wait(vp, NULL, V_NOWAIT)) {
mp == NULL &&
vn_start_secondary_write(vp, &mp, V_NOWAIT)) {
mp = NULL;
ip->i_flag &= ~IN_ACCESS;
} else {
(void) vn_write_suspend_wait(vp, NULL, V_WAIT);
if (mp == NULL)
(void) vn_start_secondary_write(vp, &mp,
V_WAIT);
UFS_UPDATE(vp, 0);
}
}
@ -125,6 +131,8 @@ out:
*/
if (ip->i_mode == 0)
vrecycle(vp, td);
if (mp != NULL)
vn_finished_secondary_write(mp);
return (error);
}

View file

@ -980,14 +980,16 @@ dqsync(vp, dq)
struct iovec aiov;
struct uio auio;
int error;
struct mount *mp;
mp = NULL;
if (dq == NODQUOT)
panic("dqsync: dquot");
if ((dq->dq_flags & DQ_MOD) == 0)
return (0);
if ((dqvp = dq->dq_ump->um_quotas[dq->dq_type]) == NULLVP)
panic("dqsync: file");
(void) vn_write_suspend_wait(dqvp, NULL, V_WAIT);
(void) vn_start_secondary_write(dqvp, &mp, V_WAIT);
if (vp != dqvp)
vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY, td);
while (dq->dq_flags & DQ_LOCK) {
@ -996,6 +998,7 @@ dqsync(vp, dq)
if ((dq->dq_flags & DQ_MOD) == 0) {
if (vp != dqvp)
VOP_UNLOCK(dqvp, 0, td);
vn_finished_secondary_write(mp);
return (0);
}
}
@ -1017,6 +1020,7 @@ dqsync(vp, dq)
dq->dq_flags &= ~(DQ_MOD|DQ_LOCK|DQ_WANT);
if (vp != dqvp)
VOP_UNLOCK(dqvp, 0, td);
vn_finished_secondary_write(mp);
return (error);
}

View file

@ -77,6 +77,7 @@ struct ufsmount {
struct worklist *softdep_worklist_tail; /* Tail pointer for above */
int softdep_on_worklist; /* Items on the worklist */
int softdep_deps; /* Total dependency count */
int softdep_accdeps; /* accumulated dep count */
int softdep_req; /* Wakeup when deps hits 0. */
struct vnode *um_quotas[MAXQUOTAS]; /* pointer to quota files */
struct ucred *um_cred[MAXQUOTAS]; /* quota file access cred */