Author: kib
Date: Wed Sep 26 14:26:29 2018
New Revision: 338943
URL: https://svnweb.freebsd.org/changeset/base/338943

Log:
  MFC r338798:
  Fix state of dquot-less vnodes after failed quotaoff.

Modified:
  stable/11/sys/kern/vfs_syscalls.c
  stable/11/sys/ufs/ufs/ufs_quota.c
  stable/11/sys/ufs/ufs/ufs_vfsops.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/kern/vfs_syscalls.c
==============================================================================
--- stable/11/sys/kern/vfs_syscalls.c   Wed Sep 26 13:16:55 2018        
(r338942)
+++ stable/11/sys/kern/vfs_syscalls.c   Wed Sep 26 14:26:29 2018        
(r338943)
@@ -189,7 +189,8 @@ sys_quotactl(struct thread *td, struct quotactl_args *
         * Require that Q_QUOTAON handles the vfs_busy() reference on
         * its own, always returning with ubusied mount point.
         */
-       if ((uap->cmd >> SUBCMDSHIFT) != Q_QUOTAON)
+       if ((uap->cmd >> SUBCMDSHIFT) != Q_QUOTAON &&
+           (uap->cmd >> SUBCMDSHIFT) != Q_QUOTAOFF)
                vfs_unbusy(mp);
        return (error);
 }

Modified: stable/11/sys/ufs/ufs/ufs_quota.c
==============================================================================
--- stable/11/sys/ufs/ufs/ufs_quota.c   Wed Sep 26 13:16:55 2018        
(r338942)
+++ stable/11/sys/ufs/ufs/ufs_quota.c   Wed Sep 26 14:26:29 2018        
(r338943)
@@ -710,6 +710,34 @@ again:
        return (error);
 }
 
+static int
+quotaoff_inchange1(struct thread *td, struct mount *mp, int type)
+{
+       int error;
+       bool need_resume;
+
+       /*
+        * mp is already suspended on unmount.  If not, suspend it, to
+        * avoid the situation where quotaoff operation eventually
+        * failing due to SU structures still keeping references on
+        * dquots, but vnode's references are already clean.  This
+        * would cause quota accounting leak and asserts otherwise.
+        * Note that the thread has already called vn_start_write().
+        */
+       if (mp->mnt_susp_owner == td) {
+               need_resume = false;
+       } else {
+               error = vfs_write_suspend_umnt(mp);
+               if (error != 0)
+                       return (error);
+               need_resume = true;
+       }
+       error = quotaoff1(td, mp, type);
+       if (need_resume)
+               vfs_write_resume(mp, VR_START_WRITE);
+       return (error);
+}
+
 /*
  * Turns off quotas, assumes that ump->um_qflags are already checked
  * and QTF_CLOSING is set to indicate operation in progress. Fixes
@@ -719,10 +747,9 @@ int
 quotaoff_inchange(struct thread *td, struct mount *mp, int type)
 {
        struct ufsmount *ump;
-       int i;
-       int error;
+       int error, i;
 
-       error = quotaoff1(td, mp, type);
+       error = quotaoff_inchange1(td, mp, type);
 
        ump = VFSTOUFS(mp);
        UFS_LOCK(ump);

Modified: stable/11/sys/ufs/ufs/ufs_vfsops.c
==============================================================================
--- stable/11/sys/ufs/ufs/ufs_vfsops.c  Wed Sep 26 13:16:55 2018        
(r338942)
+++ stable/11/sys/ufs/ufs/ufs_vfsops.c  Wed Sep 26 14:26:29 2018        
(r338943)
@@ -92,7 +92,8 @@ ufs_quotactl(mp, cmds, id, arg)
        void *arg;
 {
 #ifndef QUOTA
-       if ((cmds >> SUBCMDSHIFT) == Q_QUOTAON)
+       if ((cmds >> SUBCMDSHIFT) == Q_QUOTAON ||
+           (cmds >> SUBCMDSHIFT) == Q_QUOTAOFF)
                vfs_unbusy(mp);
 
        return (EOPNOTSUPP);
@@ -115,13 +116,13 @@ ufs_quotactl(mp, cmds, id, arg)
                        break;
 
                default:
-                       if (cmd == Q_QUOTAON)
+                       if (cmd == Q_QUOTAON || cmd == Q_QUOTAOFF)
                                vfs_unbusy(mp);
                        return (EINVAL);
                }
        }
        if ((u_int)type >= MAXQUOTAS) {
-               if (cmd == Q_QUOTAON)
+               if (cmd == Q_QUOTAON || cmd == Q_QUOTAOFF)
                        vfs_unbusy(mp);
                return (EINVAL);
        }
@@ -132,7 +133,11 @@ ufs_quotactl(mp, cmds, id, arg)
                break;
 
        case Q_QUOTAOFF:
+               vfs_ref(mp);
+               vfs_unbusy(mp);
+               vn_start_write(NULL, &mp, V_WAIT | V_MNTREF);
                error = quotaoff(td, mp, type);
+               vn_finished_write(mp);
                break;
 
        case Q_SETQUOTA32:
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to