diff options
author | Dave Chinner <david@fromorbit.com> | 2010-02-01 18:13:42 -0500 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2010-02-01 18:13:42 -0500 |
commit | d808f617ad00a413585b806de340feda5ad9a2da (patch) | |
tree | ed03d4d019a9d8b566ffd454e112e9fbce70bad8 /fs/xfs/quota | |
parent | c854363e80b49dd04a4de18ebc379eb8c8806674 (diff) |
xfs: Don't issue buffer IO direct from AIL push V2
All buffers logged into the AIL are marked as delayed write.
When the AIL needs to push the buffer out, it issues an async write of the
buffer. This means that IO patterns are dependent on the order of
buffers in the AIL.
Instead of flushing the buffer, promote the buffer in the delayed
write list so that the next time the xfsbufd is run the buffer will
be flushed by the xfsbufd. Return the state to the xfsaild that the
buffer was promoted so that the xfsaild knows that it needs to cause
the xfsbufd to run to flush the buffers that were promoted.
Using the xfsbufd for issuing the IO allows us to dispatch all
buffer IO from the one queue. This means that we can make much more
enlightened decisions on what order to flush buffers to disk as
we don't have multiple places issuing IO. Optimisations to xfsbufd
will be in a future patch.
Version 2
- kill XFS_ITEM_FLUSHING as it is now unused.
Signed-off-by: Dave Chinner <david@fromorbit.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'fs/xfs/quota')
-rw-r--r-- | fs/xfs/quota/xfs_dquot_item.c | 85 | ||||
-rw-r--r-- | fs/xfs/quota/xfs_dquot_item.h | 4 |
2 files changed, 12 insertions, 77 deletions
diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c index 1b564376d50c..dda0fb045c8a 100644 --- a/fs/xfs/quota/xfs_dquot_item.c +++ b/fs/xfs/quota/xfs_dquot_item.c | |||
@@ -212,66 +212,31 @@ xfs_qm_dquot_logitem_pushbuf( | |||
212 | xfs_dquot_t *dqp; | 212 | xfs_dquot_t *dqp; |
213 | xfs_mount_t *mp; | 213 | xfs_mount_t *mp; |
214 | xfs_buf_t *bp; | 214 | xfs_buf_t *bp; |
215 | uint dopush; | ||
216 | 215 | ||
217 | dqp = qip->qli_dquot; | 216 | dqp = qip->qli_dquot; |
218 | ASSERT(XFS_DQ_IS_LOCKED(dqp)); | 217 | ASSERT(XFS_DQ_IS_LOCKED(dqp)); |
219 | 218 | ||
220 | /* | 219 | /* |
221 | * The qli_pushbuf_flag keeps others from | ||
222 | * trying to duplicate our effort. | ||
223 | */ | ||
224 | ASSERT(qip->qli_pushbuf_flag != 0); | ||
225 | ASSERT(qip->qli_push_owner == current_pid()); | ||
226 | |||
227 | /* | ||
228 | * If flushlock isn't locked anymore, chances are that the | 220 | * If flushlock isn't locked anymore, chances are that the |
229 | * inode flush completed and the inode was taken off the AIL. | 221 | * inode flush completed and the inode was taken off the AIL. |
230 | * So, just get out. | 222 | * So, just get out. |
231 | */ | 223 | */ |
232 | if (completion_done(&dqp->q_flush) || | 224 | if (completion_done(&dqp->q_flush) || |
233 | ((qip->qli_item.li_flags & XFS_LI_IN_AIL) == 0)) { | 225 | ((qip->qli_item.li_flags & XFS_LI_IN_AIL) == 0)) { |
234 | qip->qli_pushbuf_flag = 0; | ||
235 | xfs_dqunlock(dqp); | 226 | xfs_dqunlock(dqp); |
236 | return; | 227 | return; |
237 | } | 228 | } |
238 | mp = dqp->q_mount; | 229 | mp = dqp->q_mount; |
239 | bp = xfs_incore(mp->m_ddev_targp, qip->qli_format.qlf_blkno, | 230 | bp = xfs_incore(mp->m_ddev_targp, qip->qli_format.qlf_blkno, |
240 | XFS_QI_DQCHUNKLEN(mp), XBF_TRYLOCK); | 231 | XFS_QI_DQCHUNKLEN(mp), XBF_TRYLOCK); |
241 | if (bp != NULL) { | 232 | xfs_dqunlock(dqp); |
242 | if (XFS_BUF_ISDELAYWRITE(bp)) { | 233 | if (!bp) |
243 | dopush = ((qip->qli_item.li_flags & XFS_LI_IN_AIL) && | ||
244 | !completion_done(&dqp->q_flush)); | ||
245 | qip->qli_pushbuf_flag = 0; | ||
246 | xfs_dqunlock(dqp); | ||
247 | |||
248 | if (XFS_BUF_ISPINNED(bp)) | ||
249 | xfs_log_force(mp, 0); | ||
250 | |||
251 | if (dopush) { | ||
252 | int error; | ||
253 | #ifdef XFSRACEDEBUG | ||
254 | delay_for_intr(); | ||
255 | delay(300); | ||
256 | #endif | ||
257 | error = xfs_bawrite(mp, bp); | ||
258 | if (error) | ||
259 | xfs_fs_cmn_err(CE_WARN, mp, | ||
260 | "xfs_qm_dquot_logitem_pushbuf: pushbuf error %d on qip %p, bp %p", | ||
261 | error, qip, bp); | ||
262 | } else { | ||
263 | xfs_buf_relse(bp); | ||
264 | } | ||
265 | } else { | ||
266 | qip->qli_pushbuf_flag = 0; | ||
267 | xfs_dqunlock(dqp); | ||
268 | xfs_buf_relse(bp); | ||
269 | } | ||
270 | return; | 234 | return; |
271 | } | 235 | if (XFS_BUF_ISDELAYWRITE(bp)) |
236 | xfs_buf_delwri_promote(bp); | ||
237 | xfs_buf_relse(bp); | ||
238 | return; | ||
272 | 239 | ||
273 | qip->qli_pushbuf_flag = 0; | ||
274 | xfs_dqunlock(dqp); | ||
275 | } | 240 | } |
276 | 241 | ||
277 | /* | 242 | /* |
@@ -289,50 +254,24 @@ xfs_qm_dquot_logitem_trylock( | |||
289 | xfs_dq_logitem_t *qip) | 254 | xfs_dq_logitem_t *qip) |
290 | { | 255 | { |
291 | xfs_dquot_t *dqp; | 256 | xfs_dquot_t *dqp; |
292 | uint retval; | ||
293 | 257 | ||
294 | dqp = qip->qli_dquot; | 258 | dqp = qip->qli_dquot; |
295 | if (atomic_read(&dqp->q_pincount) > 0) | 259 | if (atomic_read(&dqp->q_pincount) > 0) |
296 | return (XFS_ITEM_PINNED); | 260 | return XFS_ITEM_PINNED; |
297 | 261 | ||
298 | if (! xfs_qm_dqlock_nowait(dqp)) | 262 | if (! xfs_qm_dqlock_nowait(dqp)) |
299 | return (XFS_ITEM_LOCKED); | 263 | return XFS_ITEM_LOCKED; |
300 | 264 | ||
301 | retval = XFS_ITEM_SUCCESS; | ||
302 | if (!xfs_dqflock_nowait(dqp)) { | 265 | if (!xfs_dqflock_nowait(dqp)) { |
303 | /* | 266 | /* |
304 | * The dquot is already being flushed. It may have been | 267 | * dquot has already been flushed to the backing buffer, |
305 | * flushed delayed write, however, and we don't want to | 268 | * leave it locked, pushbuf routine will unlock it. |
306 | * get stuck waiting for that to complete. So, we want to check | ||
307 | * to see if we can lock the dquot's buffer without sleeping. | ||
308 | * If we can and it is marked for delayed write, then we | ||
309 | * hold it and send it out from the push routine. We don't | ||
310 | * want to do that now since we might sleep in the device | ||
311 | * strategy routine. We also don't want to grab the buffer lock | ||
312 | * here because we'd like not to call into the buffer cache | ||
313 | * while holding the AIL lock. | ||
314 | * Make sure to only return PUSHBUF if we set pushbuf_flag | ||
315 | * ourselves. If someone else is doing it then we don't | ||
316 | * want to go to the push routine and duplicate their efforts. | ||
317 | */ | 269 | */ |
318 | if (qip->qli_pushbuf_flag == 0) { | 270 | return XFS_ITEM_PUSHBUF; |
319 | qip->qli_pushbuf_flag = 1; | ||
320 | ASSERT(qip->qli_format.qlf_blkno == dqp->q_blkno); | ||
321 | #ifdef DEBUG | ||
322 | qip->qli_push_owner = current_pid(); | ||
323 | #endif | ||
324 | /* | ||
325 | * The dquot is left locked. | ||
326 | */ | ||
327 | retval = XFS_ITEM_PUSHBUF; | ||
328 | } else { | ||
329 | retval = XFS_ITEM_FLUSHING; | ||
330 | xfs_dqunlock_nonotify(dqp); | ||
331 | } | ||
332 | } | 271 | } |
333 | 272 | ||
334 | ASSERT(qip->qli_item.li_flags & XFS_LI_IN_AIL); | 273 | ASSERT(qip->qli_item.li_flags & XFS_LI_IN_AIL); |
335 | return (retval); | 274 | return XFS_ITEM_SUCCESS; |
336 | } | 275 | } |
337 | 276 | ||
338 | 277 | ||
diff --git a/fs/xfs/quota/xfs_dquot_item.h b/fs/xfs/quota/xfs_dquot_item.h index 5a632531f843..5acae2ada70b 100644 --- a/fs/xfs/quota/xfs_dquot_item.h +++ b/fs/xfs/quota/xfs_dquot_item.h | |||
@@ -27,10 +27,6 @@ typedef struct xfs_dq_logitem { | |||
27 | xfs_log_item_t qli_item; /* common portion */ | 27 | xfs_log_item_t qli_item; /* common portion */ |
28 | struct xfs_dquot *qli_dquot; /* dquot ptr */ | 28 | struct xfs_dquot *qli_dquot; /* dquot ptr */ |
29 | xfs_lsn_t qli_flush_lsn; /* lsn at last flush */ | 29 | xfs_lsn_t qli_flush_lsn; /* lsn at last flush */ |
30 | unsigned short qli_pushbuf_flag; /* 1 bit used in push_ail */ | ||
31 | #ifdef DEBUG | ||
32 | uint64_t qli_push_owner; | ||
33 | #endif | ||
34 | xfs_dq_logformat_t qli_format; /* logged structure */ | 30 | xfs_dq_logformat_t qli_format; /* logged structure */ |
35 | } xfs_dq_logitem_t; | 31 | } xfs_dq_logitem_t; |
36 | 32 | ||