diff options
| -rw-r--r-- | fs/xfs/xfs_qm.c | 71 |
1 files changed, 50 insertions, 21 deletions
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index 588e4909c589..dd88f0e27bd8 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c | |||
| @@ -134,8 +134,6 @@ xfs_qm_dqpurge( | |||
| 134 | { | 134 | { |
| 135 | struct xfs_mount *mp = dqp->q_mount; | 135 | struct xfs_mount *mp = dqp->q_mount; |
| 136 | struct xfs_quotainfo *qi = mp->m_quotainfo; | 136 | struct xfs_quotainfo *qi = mp->m_quotainfo; |
| 137 | struct xfs_dquot *gdqp = NULL; | ||
| 138 | struct xfs_dquot *pdqp = NULL; | ||
| 139 | 137 | ||
| 140 | xfs_dqlock(dqp); | 138 | xfs_dqlock(dqp); |
| 141 | if ((dqp->dq_flags & XFS_DQ_FREEING) || dqp->q_nrefs != 0) { | 139 | if ((dqp->dq_flags & XFS_DQ_FREEING) || dqp->q_nrefs != 0) { |
| @@ -143,21 +141,6 @@ xfs_qm_dqpurge( | |||
| 143 | return EAGAIN; | 141 | return EAGAIN; |
| 144 | } | 142 | } |
| 145 | 143 | ||
| 146 | /* | ||
| 147 | * If this quota has a hint attached, prepare for releasing it now. | ||
| 148 | */ | ||
| 149 | gdqp = dqp->q_gdquot; | ||
| 150 | if (gdqp) { | ||
| 151 | xfs_dqlock(gdqp); | ||
| 152 | dqp->q_gdquot = NULL; | ||
| 153 | } | ||
| 154 | |||
| 155 | pdqp = dqp->q_pdquot; | ||
| 156 | if (pdqp) { | ||
| 157 | xfs_dqlock(pdqp); | ||
| 158 | dqp->q_pdquot = NULL; | ||
| 159 | } | ||
| 160 | |||
| 161 | dqp->dq_flags |= XFS_DQ_FREEING; | 144 | dqp->dq_flags |= XFS_DQ_FREEING; |
| 162 | 145 | ||
| 163 | xfs_dqflock(dqp); | 146 | xfs_dqflock(dqp); |
| @@ -206,11 +189,47 @@ xfs_qm_dqpurge( | |||
| 206 | XFS_STATS_DEC(xs_qm_dquot_unused); | 189 | XFS_STATS_DEC(xs_qm_dquot_unused); |
| 207 | 190 | ||
| 208 | xfs_qm_dqdestroy(dqp); | 191 | xfs_qm_dqdestroy(dqp); |
| 192 | return 0; | ||
| 193 | } | ||
| 194 | |||
| 195 | /* | ||
| 196 | * Release the group or project dquot pointers the user dquots maybe carrying | ||
| 197 | * around as a hint, and proceed to purge the user dquot cache if requested. | ||
| 198 | */ | ||
| 199 | STATIC int | ||
| 200 | xfs_qm_dqpurge_hints( | ||
| 201 | struct xfs_dquot *dqp, | ||
| 202 | void *data) | ||
| 203 | { | ||
| 204 | struct xfs_dquot *gdqp = NULL; | ||
| 205 | struct xfs_dquot *pdqp = NULL; | ||
| 206 | uint flags = *((uint *)data); | ||
| 207 | |||
| 208 | xfs_dqlock(dqp); | ||
| 209 | if (dqp->dq_flags & XFS_DQ_FREEING) { | ||
| 210 | xfs_dqunlock(dqp); | ||
| 211 | return EAGAIN; | ||
| 212 | } | ||
| 213 | |||
| 214 | /* If this quota has a hint attached, prepare for releasing it now */ | ||
| 215 | gdqp = dqp->q_gdquot; | ||
| 216 | if (gdqp) | ||
| 217 | dqp->q_gdquot = NULL; | ||
| 218 | |||
| 219 | pdqp = dqp->q_pdquot; | ||
| 220 | if (pdqp) | ||
| 221 | dqp->q_pdquot = NULL; | ||
| 222 | |||
| 223 | xfs_dqunlock(dqp); | ||
| 209 | 224 | ||
| 210 | if (gdqp) | 225 | if (gdqp) |
| 211 | xfs_qm_dqput(gdqp); | 226 | xfs_qm_dqrele(gdqp); |
| 212 | if (pdqp) | 227 | if (pdqp) |
| 213 | xfs_qm_dqput(pdqp); | 228 | xfs_qm_dqrele(pdqp); |
| 229 | |||
| 230 | if (flags & XFS_QMOPT_UQUOTA) | ||
| 231 | return xfs_qm_dqpurge(dqp, NULL); | ||
| 232 | |||
| 214 | return 0; | 233 | return 0; |
| 215 | } | 234 | } |
| 216 | 235 | ||
| @@ -222,8 +241,18 @@ xfs_qm_dqpurge_all( | |||
| 222 | struct xfs_mount *mp, | 241 | struct xfs_mount *mp, |
| 223 | uint flags) | 242 | uint flags) |
| 224 | { | 243 | { |
| 225 | if (flags & XFS_QMOPT_UQUOTA) | 244 | /* |
| 226 | xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_dqpurge, NULL); | 245 | * We have to release group/project dquot hint(s) from the user dquot |
| 246 | * at first if they are there, otherwise we would run into an infinite | ||
| 247 | * loop while walking through radix tree to purge other type of dquots | ||
| 248 | * since their refcount is not zero if the user dquot refers to them | ||
| 249 | * as hint. | ||
| 250 | * | ||
| 251 | * Call the special xfs_qm_dqpurge_hints() will end up go through the | ||
| 252 | * general xfs_qm_dqpurge() against user dquot cache if requested. | ||
| 253 | */ | ||
| 254 | xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_dqpurge_hints, &flags); | ||
| 255 | |||
| 227 | if (flags & XFS_QMOPT_GQUOTA) | 256 | if (flags & XFS_QMOPT_GQUOTA) |
| 228 | xfs_qm_dquot_walk(mp, XFS_DQ_GROUP, xfs_qm_dqpurge, NULL); | 257 | xfs_qm_dquot_walk(mp, XFS_DQ_GROUP, xfs_qm_dqpurge, NULL); |
| 229 | if (flags & XFS_QMOPT_PQUOTA) | 258 | if (flags & XFS_QMOPT_PQUOTA) |
