diff options
Diffstat (limited to 'fs/xfs/xfs_dquot_item.c')
-rw-r--r-- | fs/xfs/xfs_dquot_item.c | 162 |
1 files changed, 44 insertions, 118 deletions
diff --git a/fs/xfs/xfs_dquot_item.c b/fs/xfs/xfs_dquot_item.c index 34baeae4526..57aa4b03720 100644 --- a/fs/xfs/xfs_dquot_item.c +++ b/fs/xfs/xfs_dquot_item.c | |||
@@ -17,9 +17,7 @@ | |||
17 | */ | 17 | */ |
18 | #include "xfs.h" | 18 | #include "xfs.h" |
19 | #include "xfs_fs.h" | 19 | #include "xfs_fs.h" |
20 | #include "xfs_bit.h" | ||
21 | #include "xfs_log.h" | 20 | #include "xfs_log.h" |
22 | #include "xfs_inum.h" | ||
23 | #include "xfs_trans.h" | 21 | #include "xfs_trans.h" |
24 | #include "xfs_sb.h" | 22 | #include "xfs_sb.h" |
25 | #include "xfs_ag.h" | 23 | #include "xfs_ag.h" |
@@ -108,38 +106,6 @@ xfs_qm_dquot_logitem_unpin( | |||
108 | wake_up(&dqp->q_pinwait); | 106 | wake_up(&dqp->q_pinwait); |
109 | } | 107 | } |
110 | 108 | ||
111 | /* | ||
112 | * Given the logitem, this writes the corresponding dquot entry to disk | ||
113 | * asynchronously. This is called with the dquot entry securely locked; | ||
114 | * we simply get xfs_qm_dqflush() to do the work, and unlock the dquot | ||
115 | * at the end. | ||
116 | */ | ||
117 | STATIC void | ||
118 | xfs_qm_dquot_logitem_push( | ||
119 | struct xfs_log_item *lip) | ||
120 | { | ||
121 | struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; | ||
122 | int error; | ||
123 | |||
124 | ASSERT(XFS_DQ_IS_LOCKED(dqp)); | ||
125 | ASSERT(!completion_done(&dqp->q_flush)); | ||
126 | |||
127 | /* | ||
128 | * Since we were able to lock the dquot's flush lock and | ||
129 | * we found it on the AIL, the dquot must be dirty. This | ||
130 | * is because the dquot is removed from the AIL while still | ||
131 | * holding the flush lock in xfs_dqflush_done(). Thus, if | ||
132 | * we found it in the AIL and were able to obtain the flush | ||
133 | * lock without sleeping, then there must not have been | ||
134 | * anyone in the process of flushing the dquot. | ||
135 | */ | ||
136 | error = xfs_qm_dqflush(dqp, SYNC_TRYLOCK); | ||
137 | if (error) | ||
138 | xfs_warn(dqp->q_mount, "%s: push error %d on dqp %p", | ||
139 | __func__, error, dqp); | ||
140 | xfs_dqunlock(dqp); | ||
141 | } | ||
142 | |||
143 | STATIC xfs_lsn_t | 109 | STATIC xfs_lsn_t |
144 | xfs_qm_dquot_logitem_committed( | 110 | xfs_qm_dquot_logitem_committed( |
145 | struct xfs_log_item *lip, | 111 | struct xfs_log_item *lip, |
@@ -171,67 +137,15 @@ xfs_qm_dqunpin_wait( | |||
171 | wait_event(dqp->q_pinwait, (atomic_read(&dqp->q_pincount) == 0)); | 137 | wait_event(dqp->q_pinwait, (atomic_read(&dqp->q_pincount) == 0)); |
172 | } | 138 | } |
173 | 139 | ||
174 | /* | ||
175 | * This is called when IOP_TRYLOCK returns XFS_ITEM_PUSHBUF to indicate that | ||
176 | * the dquot is locked by us, but the flush lock isn't. So, here we are | ||
177 | * going to see if the relevant dquot buffer is incore, waiting on DELWRI. | ||
178 | * If so, we want to push it out to help us take this item off the AIL as soon | ||
179 | * as possible. | ||
180 | * | ||
181 | * We must not be holding the AIL lock at this point. Calling incore() to | ||
182 | * search the buffer cache can be a time consuming thing, and AIL lock is a | ||
183 | * spinlock. | ||
184 | */ | ||
185 | STATIC bool | ||
186 | xfs_qm_dquot_logitem_pushbuf( | ||
187 | struct xfs_log_item *lip) | ||
188 | { | ||
189 | struct xfs_dq_logitem *qlip = DQUOT_ITEM(lip); | ||
190 | struct xfs_dquot *dqp = qlip->qli_dquot; | ||
191 | struct xfs_buf *bp; | ||
192 | bool ret = true; | ||
193 | |||
194 | ASSERT(XFS_DQ_IS_LOCKED(dqp)); | ||
195 | |||
196 | /* | ||
197 | * If flushlock isn't locked anymore, chances are that the | ||
198 | * inode flush completed and the inode was taken off the AIL. | ||
199 | * So, just get out. | ||
200 | */ | ||
201 | if (completion_done(&dqp->q_flush) || | ||
202 | !(lip->li_flags & XFS_LI_IN_AIL)) { | ||
203 | xfs_dqunlock(dqp); | ||
204 | return true; | ||
205 | } | ||
206 | |||
207 | bp = xfs_incore(dqp->q_mount->m_ddev_targp, qlip->qli_format.qlf_blkno, | ||
208 | dqp->q_mount->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK); | ||
209 | xfs_dqunlock(dqp); | ||
210 | if (!bp) | ||
211 | return true; | ||
212 | if (XFS_BUF_ISDELAYWRITE(bp)) | ||
213 | xfs_buf_delwri_promote(bp); | ||
214 | if (xfs_buf_ispinned(bp)) | ||
215 | ret = false; | ||
216 | xfs_buf_relse(bp); | ||
217 | return ret; | ||
218 | } | ||
219 | |||
220 | /* | ||
221 | * This is called to attempt to lock the dquot associated with this | ||
222 | * dquot log item. Don't sleep on the dquot lock or the flush lock. | ||
223 | * If the flush lock is already held, indicating that the dquot has | ||
224 | * been or is in the process of being flushed, then see if we can | ||
225 | * find the dquot's buffer in the buffer cache without sleeping. If | ||
226 | * we can and it is marked delayed write, then we want to send it out. | ||
227 | * We delay doing so until the push routine, though, to avoid sleeping | ||
228 | * in any device strategy routines. | ||
229 | */ | ||
230 | STATIC uint | 140 | STATIC uint |
231 | xfs_qm_dquot_logitem_trylock( | 141 | xfs_qm_dquot_logitem_push( |
232 | struct xfs_log_item *lip) | 142 | struct xfs_log_item *lip, |
143 | struct list_head *buffer_list) | ||
233 | { | 144 | { |
234 | struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; | 145 | struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; |
146 | struct xfs_buf *bp = NULL; | ||
147 | uint rval = XFS_ITEM_SUCCESS; | ||
148 | int error; | ||
235 | 149 | ||
236 | if (atomic_read(&dqp->q_pincount) > 0) | 150 | if (atomic_read(&dqp->q_pincount) > 0) |
237 | return XFS_ITEM_PINNED; | 151 | return XFS_ITEM_PINNED; |
@@ -239,16 +153,41 @@ xfs_qm_dquot_logitem_trylock( | |||
239 | if (!xfs_dqlock_nowait(dqp)) | 153 | if (!xfs_dqlock_nowait(dqp)) |
240 | return XFS_ITEM_LOCKED; | 154 | return XFS_ITEM_LOCKED; |
241 | 155 | ||
156 | /* | ||
157 | * Re-check the pincount now that we stabilized the value by | ||
158 | * taking the quota lock. | ||
159 | */ | ||
160 | if (atomic_read(&dqp->q_pincount) > 0) { | ||
161 | rval = XFS_ITEM_PINNED; | ||
162 | goto out_unlock; | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * Someone else is already flushing the dquot. Nothing we can do | ||
167 | * here but wait for the flush to finish and remove the item from | ||
168 | * the AIL. | ||
169 | */ | ||
242 | if (!xfs_dqflock_nowait(dqp)) { | 170 | if (!xfs_dqflock_nowait(dqp)) { |
243 | /* | 171 | rval = XFS_ITEM_FLUSHING; |
244 | * dquot has already been flushed to the backing buffer, | 172 | goto out_unlock; |
245 | * leave it locked, pushbuf routine will unlock it. | ||
246 | */ | ||
247 | return XFS_ITEM_PUSHBUF; | ||
248 | } | 173 | } |
249 | 174 | ||
250 | ASSERT(lip->li_flags & XFS_LI_IN_AIL); | 175 | spin_unlock(&lip->li_ailp->xa_lock); |
251 | return XFS_ITEM_SUCCESS; | 176 | |
177 | error = xfs_qm_dqflush(dqp, &bp); | ||
178 | if (error) { | ||
179 | xfs_warn(dqp->q_mount, "%s: push error %d on dqp %p", | ||
180 | __func__, error, dqp); | ||
181 | } else { | ||
182 | if (!xfs_buf_delwri_queue(bp, buffer_list)) | ||
183 | rval = XFS_ITEM_FLUSHING; | ||
184 | xfs_buf_relse(bp); | ||
185 | } | ||
186 | |||
187 | spin_lock(&lip->li_ailp->xa_lock); | ||
188 | out_unlock: | ||
189 | xfs_dqunlock(dqp); | ||
190 | return rval; | ||
252 | } | 191 | } |
253 | 192 | ||
254 | /* | 193 | /* |
@@ -299,11 +238,9 @@ static const struct xfs_item_ops xfs_dquot_item_ops = { | |||
299 | .iop_format = xfs_qm_dquot_logitem_format, | 238 | .iop_format = xfs_qm_dquot_logitem_format, |
300 | .iop_pin = xfs_qm_dquot_logitem_pin, | 239 | .iop_pin = xfs_qm_dquot_logitem_pin, |
301 | .iop_unpin = xfs_qm_dquot_logitem_unpin, | 240 | .iop_unpin = xfs_qm_dquot_logitem_unpin, |
302 | .iop_trylock = xfs_qm_dquot_logitem_trylock, | ||
303 | .iop_unlock = xfs_qm_dquot_logitem_unlock, | 241 | .iop_unlock = xfs_qm_dquot_logitem_unlock, |
304 | .iop_committed = xfs_qm_dquot_logitem_committed, | 242 | .iop_committed = xfs_qm_dquot_logitem_committed, |
305 | .iop_push = xfs_qm_dquot_logitem_push, | 243 | .iop_push = xfs_qm_dquot_logitem_push, |
306 | .iop_pushbuf = xfs_qm_dquot_logitem_pushbuf, | ||
307 | .iop_committing = xfs_qm_dquot_logitem_committing | 244 | .iop_committing = xfs_qm_dquot_logitem_committing |
308 | }; | 245 | }; |
309 | 246 | ||
@@ -398,11 +335,13 @@ xfs_qm_qoff_logitem_unpin( | |||
398 | } | 335 | } |
399 | 336 | ||
400 | /* | 337 | /* |
401 | * Quotaoff items have no locking, so just return success. | 338 | * There isn't much you can do to push a quotaoff item. It is simply |
339 | * stuck waiting for the log to be flushed to disk. | ||
402 | */ | 340 | */ |
403 | STATIC uint | 341 | STATIC uint |
404 | xfs_qm_qoff_logitem_trylock( | 342 | xfs_qm_qoff_logitem_push( |
405 | struct xfs_log_item *lip) | 343 | struct xfs_log_item *lip, |
344 | struct list_head *buffer_list) | ||
406 | { | 345 | { |
407 | return XFS_ITEM_LOCKED; | 346 | return XFS_ITEM_LOCKED; |
408 | } | 347 | } |
@@ -429,17 +368,6 @@ xfs_qm_qoff_logitem_committed( | |||
429 | return lsn; | 368 | return lsn; |
430 | } | 369 | } |
431 | 370 | ||
432 | /* | ||
433 | * There isn't much you can do to push on an quotaoff item. It is simply | ||
434 | * stuck waiting for the log to be flushed to disk. | ||
435 | */ | ||
436 | STATIC void | ||
437 | xfs_qm_qoff_logitem_push( | ||
438 | struct xfs_log_item *lip) | ||
439 | { | ||
440 | } | ||
441 | |||
442 | |||
443 | STATIC xfs_lsn_t | 371 | STATIC xfs_lsn_t |
444 | xfs_qm_qoffend_logitem_committed( | 372 | xfs_qm_qoffend_logitem_committed( |
445 | struct xfs_log_item *lip, | 373 | struct xfs_log_item *lip, |
@@ -454,7 +382,7 @@ xfs_qm_qoffend_logitem_committed( | |||
454 | * xfs_trans_ail_delete() drops the AIL lock. | 382 | * xfs_trans_ail_delete() drops the AIL lock. |
455 | */ | 383 | */ |
456 | spin_lock(&ailp->xa_lock); | 384 | spin_lock(&ailp->xa_lock); |
457 | xfs_trans_ail_delete(ailp, (xfs_log_item_t *)qfs); | 385 | xfs_trans_ail_delete(ailp, &qfs->qql_item, SHUTDOWN_LOG_IO_ERROR); |
458 | 386 | ||
459 | kmem_free(qfs); | 387 | kmem_free(qfs); |
460 | kmem_free(qfe); | 388 | kmem_free(qfe); |
@@ -487,7 +415,6 @@ static const struct xfs_item_ops xfs_qm_qoffend_logitem_ops = { | |||
487 | .iop_format = xfs_qm_qoff_logitem_format, | 415 | .iop_format = xfs_qm_qoff_logitem_format, |
488 | .iop_pin = xfs_qm_qoff_logitem_pin, | 416 | .iop_pin = xfs_qm_qoff_logitem_pin, |
489 | .iop_unpin = xfs_qm_qoff_logitem_unpin, | 417 | .iop_unpin = xfs_qm_qoff_logitem_unpin, |
490 | .iop_trylock = xfs_qm_qoff_logitem_trylock, | ||
491 | .iop_unlock = xfs_qm_qoff_logitem_unlock, | 418 | .iop_unlock = xfs_qm_qoff_logitem_unlock, |
492 | .iop_committed = xfs_qm_qoffend_logitem_committed, | 419 | .iop_committed = xfs_qm_qoffend_logitem_committed, |
493 | .iop_push = xfs_qm_qoff_logitem_push, | 420 | .iop_push = xfs_qm_qoff_logitem_push, |
@@ -502,7 +429,6 @@ static const struct xfs_item_ops xfs_qm_qoff_logitem_ops = { | |||
502 | .iop_format = xfs_qm_qoff_logitem_format, | 429 | .iop_format = xfs_qm_qoff_logitem_format, |
503 | .iop_pin = xfs_qm_qoff_logitem_pin, | 430 | .iop_pin = xfs_qm_qoff_logitem_pin, |
504 | .iop_unpin = xfs_qm_qoff_logitem_unpin, | 431 | .iop_unpin = xfs_qm_qoff_logitem_unpin, |
505 | .iop_trylock = xfs_qm_qoff_logitem_trylock, | ||
506 | .iop_unlock = xfs_qm_qoff_logitem_unlock, | 432 | .iop_unlock = xfs_qm_qoff_logitem_unlock, |
507 | .iop_committed = xfs_qm_qoff_logitem_committed, | 433 | .iop_committed = xfs_qm_qoff_logitem_committed, |
508 | .iop_push = xfs_qm_qoff_logitem_push, | 434 | .iop_push = xfs_qm_qoff_logitem_push, |