diff options
-rw-r--r-- | sys/sys/vnode.h | 1 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_softdep.c | 23 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vfsops.c | 33 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_quota.c | 23 |
4 files changed, 63 insertions, 17 deletions
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index b54dc04..0696edd 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -385,6 +385,7 @@ extern int vttoif_tab[]; #define SKIPSYSTEM 0x0001 /* vflush: skip vnodes marked VSYSTEM */ #define FORCECLOSE 0x0002 /* vflush: force file closure */ #define WRITECLOSE 0x0004 /* vflush: only close writable files */ +#define EARLYFLUSH 0x0008 /* vflush: early call for ffs_flushfiles */ #define V_SAVE 0x0001 /* vinvalbuf: sync file first */ #define V_ALT 0x0002 /* vinvalbuf: invalidate only alternate bufs */ #define V_NORMAL 0x0004 /* vinvalbuf: invalidate only regular bufs */ diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index 16fe134..e39fd46 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -1908,7 +1908,12 @@ softdep_flushfiles(oldmnt, flags, td) int flags; struct thread *td; { - int error, depcount, loopcnt, retry_flush_count, retry; +#ifdef QUOTA + struct ufsmount *ump; + int i; +#endif + int error, early, depcount, loopcnt, retry_flush_count, retry; + int morework; loopcnt = 10; retry_flush_count = 3; @@ -1926,7 +1931,9 @@ retry_flush: * Do another flush in case any vnodes were brought in * as part of the cleanup operations. */ - if ((error = ffs_flushfiles(oldmnt, flags, td)) != 0) + early = retry_flush_count == 1 || (oldmnt->mnt_kern_flag & + MNTK_UNMOUNT) == 0 ? 0 : EARLYFLUSH; + if ((error = ffs_flushfiles(oldmnt, flags | early, td)) != 0) break; if ((error = softdep_flushworklist(oldmnt, &depcount, td)) != 0 || depcount == 0) @@ -1950,7 +1957,17 @@ retry_flush: MNT_ILOCK(oldmnt); KASSERT((oldmnt->mnt_kern_flag & MNTK_NOINSMNTQ) != 0, ("softdep_flushfiles: !MNTK_NOINSMNTQ")); - if (oldmnt->mnt_nvnodelistsize > 0) { + morework = oldmnt->mnt_nvnodelistsize > 0; +#ifdef QUOTA + ump = VFSTOUFS(oldmnt); + UFS_LOCK(ump); + for (i = 0; i < MAXQUOTAS; i++) { + if (ump->um_quotas[i] != NULLVP) + morework = 1; + } + UFS_UNLOCK(ump); +#endif + if (morework) { if (--retry_flush_count > 0) { retry = 1; loopcnt = 3; diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 0204613..b3292d0 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -1351,9 +1351,10 @@ ffs_flushfiles(mp, flags, td) struct thread *td; { struct ufsmount *ump; - int error; + int qerror, error; ump = VFSTOUFS(mp); + qerror = 0; #ifdef QUOTA if (mp->mnt_flag & MNT_QUOTA) { int i; @@ -1361,11 +1362,19 @@ ffs_flushfiles(mp, flags, td) if (error) return (error); for (i = 0; i < MAXQUOTAS; i++) { - quotaoff(td, mp, i); + error = quotaoff(td, mp, i); + if (error != 0) { + if ((flags & EARLYFLUSH) == 0) + return (error); + else + qerror = error; + } } + /* - * Here we fall through to vflush again to ensure - * that we have gotten rid of all the system vnodes. + * Here we fall through to vflush again to ensure that + * we have gotten rid of all the system vnodes, unless + * quotas must not be closed. */ } #endif @@ -1380,11 +1389,21 @@ ffs_flushfiles(mp, flags, td) * that we have gotten rid of all the system vnodes. */ } - /* - * Flush all the files. + + /* + * Do not close system files if quotas were not closed, to be + * able to sync the remaining dquots. The freeblks softupdate + * workitems might hold a reference on a dquot, preventing + * quotaoff() from completing. Next round of + * softdep_flushworklist() iteration should process the + * blockers, allowing the next run of quotaoff() to finally + * flush held dquots. + * + * Otherwise, flush all the files. */ - if ((error = vflush(mp, 0, flags, td)) != 0) + if (qerror == 0 && (error = vflush(mp, 0, flags, td)) != 0) return (error); + /* * Flush filesystem metadata. */ diff --git a/sys/ufs/ufs/ufs_quota.c b/sys/ufs/ufs/ufs_quota.c index 87ac9a1..a949898 100644 --- a/sys/ufs/ufs/ufs_quota.c +++ b/sys/ufs/ufs/ufs_quota.c @@ -80,7 +80,7 @@ static int dqopen(struct vnode *, struct ufsmount *, int); static int dqget(struct vnode *, u_long, struct ufsmount *, int, struct dquot **); static int dqsync(struct vnode *, struct dquot *); -static void dqflush(struct vnode *); +static int dqflush(struct vnode *); static int quotaoff1(struct thread *td, struct mount *mp, int type); static int quotaoff_inchange(struct thread *td, struct mount *mp, int type); @@ -674,8 +674,12 @@ again: vrele(vp); } - dqflush(qvp); - /* Clear um_quotas before closing the quota vnode to prevent + error = dqflush(qvp); + if (error != 0) + return (error); + + /* + * Clear um_quotas before closing the quota vnode to prevent * access to the closed vnode from dqget/dqsync */ UFS_LOCK(ump); @@ -1594,17 +1598,19 @@ out: /* * Flush all entries from the cache for a particular vnode. */ -static void +static int dqflush(struct vnode *vp) { struct dquot *dq, *nextdq; struct dqhash *dqh; + int error; /* * Move all dquot's that used to refer to this quota * file off their hash chains (they will eventually * fall off the head of the free list and be re-used). */ + error = 0; DQH_LOCK(); for (dqh = &dqhashtbl[dqhash]; dqh >= dqhashtbl; dqh--) { for (dq = LIST_FIRST(dqh); dq; dq = nextdq) { @@ -1612,12 +1618,15 @@ dqflush(struct vnode *vp) if (dq->dq_ump->um_quotas[dq->dq_type] != vp) continue; if (dq->dq_cnt) - panic("dqflush: stray dquot"); - LIST_REMOVE(dq, dq_hash); - dq->dq_ump = (struct ufsmount *)0; + error = EBUSY; + else { + LIST_REMOVE(dq, dq_hash); + dq->dq_ump = NULL; + } } } DQH_UNLOCK(); + return (error); } /* |