Author: kib
Date: Wed Mar 13 10:01:05 2013
New Revision: 248233
URL: http://svnweb.freebsd.org/changeset/base/248233

Log:
  MFC r247388:
  Work around the hold of references to the struct dquot by the freeblk
  workitems for some time at unmount.

Modified:
  stable/9/sys/sys/vnode.h
  stable/9/sys/ufs/ffs/ffs_softdep.c
  stable/9/sys/ufs/ffs/ffs_vfsops.c
  stable/9/sys/ufs/ufs/ufs_quota.c
Directory Properties:
  stable/9/sys/   (props changed)

Modified: stable/9/sys/sys/vnode.h
==============================================================================
--- stable/9/sys/sys/vnode.h    Wed Mar 13 09:54:11 2013        (r248232)
+++ stable/9/sys/sys/vnode.h    Wed Mar 13 10:01:05 2013        (r248233)
@@ -383,6 +383,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 */

Modified: stable/9/sys/ufs/ffs/ffs_softdep.c
==============================================================================
--- stable/9/sys/ufs/ffs/ffs_softdep.c  Wed Mar 13 09:54:11 2013        
(r248232)
+++ stable/9/sys/ufs/ffs/ffs_softdep.c  Wed Mar 13 10:01:05 2013        
(r248233)
@@ -1914,7 +1914,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;
@@ -1932,7 +1937,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)
@@ -1956,7 +1963,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;

Modified: stable/9/sys/ufs/ffs/ffs_vfsops.c
==============================================================================
--- stable/9/sys/ufs/ffs/ffs_vfsops.c   Wed Mar 13 09:54:11 2013        
(r248232)
+++ stable/9/sys/ufs/ffs/ffs_vfsops.c   Wed Mar 13 10:01:05 2013        
(r248233)
@@ -1355,9 +1355,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;
@@ -1365,11 +1366,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
@@ -1384,11 +1393,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.
         */

Modified: stable/9/sys/ufs/ufs/ufs_quota.c
==============================================================================
--- stable/9/sys/ufs/ufs/ufs_quota.c    Wed Mar 13 09:54:11 2013        
(r248232)
+++ stable/9/sys/ufs/ufs/ufs_quota.c    Wed Mar 13 10:01:05 2013        
(r248233)
@@ -80,7 +80,7 @@ static int dqopen(struct vnode *, struct
 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);
 
@@ -680,8 +680,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);
@@ -1615,17 +1619,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) {
@@ -1633,12 +1639,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);
 }
 
 /*
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to