diff options
-rw-r--r-- | fs/xfs/xfs_mount.c | 56 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.h | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_sync.c | 96 | ||||
-rw-r--r-- | fs/xfs/xfs_trans_ail.c | 36 | ||||
-rw-r--r-- | fs/xfs/xfs_trans_priv.h | 2 |
5 files changed, 56 insertions, 135 deletions
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 1ffead4b2296..385a3b11d3dd 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include "xfs_log.h" | 22 | #include "xfs_log.h" |
23 | #include "xfs_inum.h" | 23 | #include "xfs_inum.h" |
24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
25 | #include "xfs_trans_priv.h" | ||
25 | #include "xfs_sb.h" | 26 | #include "xfs_sb.h" |
26 | #include "xfs_ag.h" | 27 | #include "xfs_ag.h" |
27 | #include "xfs_dir2.h" | 28 | #include "xfs_dir2.h" |
@@ -1475,15 +1476,15 @@ xfs_unmountfs( | |||
1475 | xfs_log_force(mp, XFS_LOG_SYNC); | 1476 | xfs_log_force(mp, XFS_LOG_SYNC); |
1476 | 1477 | ||
1477 | /* | 1478 | /* |
1478 | * Do a delwri reclaim pass first so that as many dirty inodes are | 1479 | * Flush all pending changes from the AIL. |
1479 | * queued up for IO as possible. Then flush the buffers before making | 1480 | */ |
1480 | * a synchronous path to catch all the remaining inodes are reclaimed. | 1481 | xfs_ail_push_all_sync(mp->m_ail); |
1481 | * This makes the reclaim process as quick as possible by avoiding | 1482 | |
1482 | * synchronous writeout and blocking on inodes already in the delwri | 1483 | /* |
1483 | * state as much as possible. | 1484 | * And reclaim all inodes. At this point there should be no dirty |
1485 | * inode, and none should be pinned or locked, but use synchronous | ||
1486 | * reclaim just to be sure. | ||
1484 | */ | 1487 | */ |
1485 | xfs_reclaim_inodes(mp, 0); | ||
1486 | xfs_flush_buftarg(mp->m_ddev_targp, 1); | ||
1487 | xfs_reclaim_inodes(mp, SYNC_WAIT); | 1488 | xfs_reclaim_inodes(mp, SYNC_WAIT); |
1488 | 1489 | ||
1489 | xfs_qm_unmount(mp); | 1490 | xfs_qm_unmount(mp); |
@@ -1519,15 +1520,12 @@ xfs_unmountfs( | |||
1519 | if (error) | 1520 | if (error) |
1520 | xfs_warn(mp, "Unable to update superblock counters. " | 1521 | xfs_warn(mp, "Unable to update superblock counters. " |
1521 | "Freespace may not be correct on next mount."); | 1522 | "Freespace may not be correct on next mount."); |
1522 | xfs_unmountfs_writesb(mp); | ||
1523 | 1523 | ||
1524 | /* | 1524 | /* |
1525 | * Make sure all buffers have been flushed and completed before | 1525 | * At this point we might have modified the superblock again and thus |
1526 | * unmounting the log. | 1526 | * added an item to the AIL, thus flush it again. |
1527 | */ | 1527 | */ |
1528 | error = xfs_flush_buftarg(mp->m_ddev_targp, 1); | 1528 | xfs_ail_push_all_sync(mp->m_ail); |
1529 | if (error) | ||
1530 | xfs_warn(mp, "%d busy buffers during unmount.", error); | ||
1531 | xfs_wait_buftarg(mp->m_ddev_targp); | 1529 | xfs_wait_buftarg(mp->m_ddev_targp); |
1532 | 1530 | ||
1533 | xfs_log_unmount_write(mp); | 1531 | xfs_log_unmount_write(mp); |
@@ -1588,36 +1586,6 @@ xfs_log_sbcount(xfs_mount_t *mp) | |||
1588 | return error; | 1586 | return error; |
1589 | } | 1587 | } |
1590 | 1588 | ||
1591 | int | ||
1592 | xfs_unmountfs_writesb(xfs_mount_t *mp) | ||
1593 | { | ||
1594 | xfs_buf_t *sbp; | ||
1595 | int error = 0; | ||
1596 | |||
1597 | /* | ||
1598 | * skip superblock write if fs is read-only, or | ||
1599 | * if we are doing a forced umount. | ||
1600 | */ | ||
1601 | if (!((mp->m_flags & XFS_MOUNT_RDONLY) || | ||
1602 | XFS_FORCED_SHUTDOWN(mp))) { | ||
1603 | |||
1604 | sbp = xfs_getsb(mp, 0); | ||
1605 | |||
1606 | XFS_BUF_UNDONE(sbp); | ||
1607 | XFS_BUF_UNREAD(sbp); | ||
1608 | xfs_buf_delwri_dequeue(sbp); | ||
1609 | XFS_BUF_WRITE(sbp); | ||
1610 | XFS_BUF_UNASYNC(sbp); | ||
1611 | ASSERT(sbp->b_target == mp->m_ddev_targp); | ||
1612 | xfsbdstrat(mp, sbp); | ||
1613 | error = xfs_buf_iowait(sbp); | ||
1614 | if (error) | ||
1615 | xfs_buf_ioerror_alert(sbp, __func__); | ||
1616 | xfs_buf_relse(sbp); | ||
1617 | } | ||
1618 | return error; | ||
1619 | } | ||
1620 | |||
1621 | /* | 1589 | /* |
1622 | * xfs_mod_sb() can be used to copy arbitrary changes to the | 1590 | * xfs_mod_sb() can be used to copy arbitrary changes to the |
1623 | * in-core superblock into the superblock buffer to be logged. | 1591 | * in-core superblock into the superblock buffer to be logged. |
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 9eba73887829..19fd5eda92b8 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h | |||
@@ -378,7 +378,6 @@ extern __uint64_t xfs_default_resblks(xfs_mount_t *mp); | |||
378 | extern int xfs_mountfs(xfs_mount_t *mp); | 378 | extern int xfs_mountfs(xfs_mount_t *mp); |
379 | 379 | ||
380 | extern void xfs_unmountfs(xfs_mount_t *); | 380 | extern void xfs_unmountfs(xfs_mount_t *); |
381 | extern int xfs_unmountfs_writesb(xfs_mount_t *); | ||
382 | extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int64_t, int); | 381 | extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int64_t, int); |
383 | extern int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *, | 382 | extern int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *, |
384 | uint, int); | 383 | uint, int); |
diff --git a/fs/xfs/xfs_sync.c b/fs/xfs/xfs_sync.c index 7648776e0a9e..85d03e6a2677 100644 --- a/fs/xfs/xfs_sync.c +++ b/fs/xfs/xfs_sync.c | |||
@@ -241,45 +241,6 @@ xfs_sync_inode_data( | |||
241 | return error; | 241 | return error; |
242 | } | 242 | } |
243 | 243 | ||
244 | STATIC int | ||
245 | xfs_sync_inode_attr( | ||
246 | struct xfs_inode *ip, | ||
247 | struct xfs_perag *pag, | ||
248 | int flags) | ||
249 | { | ||
250 | int error = 0; | ||
251 | |||
252 | xfs_ilock(ip, XFS_ILOCK_SHARED); | ||
253 | if (xfs_inode_clean(ip)) | ||
254 | goto out_unlock; | ||
255 | if (!xfs_iflock_nowait(ip)) { | ||
256 | if (!(flags & SYNC_WAIT)) | ||
257 | goto out_unlock; | ||
258 | xfs_iflock(ip); | ||
259 | } | ||
260 | |||
261 | if (xfs_inode_clean(ip)) { | ||
262 | xfs_ifunlock(ip); | ||
263 | goto out_unlock; | ||
264 | } | ||
265 | |||
266 | error = xfs_iflush(ip, flags); | ||
267 | |||
268 | /* | ||
269 | * We don't want to try again on non-blocking flushes that can't run | ||
270 | * again immediately. If an inode really must be written, then that's | ||
271 | * what the SYNC_WAIT flag is for. | ||
272 | */ | ||
273 | if (error == EAGAIN) { | ||
274 | ASSERT(!(flags & SYNC_WAIT)); | ||
275 | error = 0; | ||
276 | } | ||
277 | |||
278 | out_unlock: | ||
279 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | ||
280 | return error; | ||
281 | } | ||
282 | |||
283 | /* | 244 | /* |
284 | * Write out pagecache data for the whole filesystem. | 245 | * Write out pagecache data for the whole filesystem. |
285 | */ | 246 | */ |
@@ -300,19 +261,6 @@ xfs_sync_data( | |||
300 | return 0; | 261 | return 0; |
301 | } | 262 | } |
302 | 263 | ||
303 | /* | ||
304 | * Write out inode metadata (attributes) for the whole filesystem. | ||
305 | */ | ||
306 | STATIC int | ||
307 | xfs_sync_attr( | ||
308 | struct xfs_mount *mp, | ||
309 | int flags) | ||
310 | { | ||
311 | ASSERT((flags & ~SYNC_WAIT) == 0); | ||
312 | |||
313 | return xfs_inode_ag_iterator(mp, xfs_sync_inode_attr, flags); | ||
314 | } | ||
315 | |||
316 | STATIC int | 264 | STATIC int |
317 | xfs_sync_fsdata( | 265 | xfs_sync_fsdata( |
318 | struct xfs_mount *mp) | 266 | struct xfs_mount *mp) |
@@ -350,7 +298,7 @@ xfs_sync_fsdata( | |||
350 | * First stage of freeze - no writers will make progress now we are here, | 298 | * First stage of freeze - no writers will make progress now we are here, |
351 | * so we flush delwri and delalloc buffers here, then wait for all I/O to | 299 | * so we flush delwri and delalloc buffers here, then wait for all I/O to |
352 | * complete. Data is frozen at that point. Metadata is not frozen, | 300 | * complete. Data is frozen at that point. Metadata is not frozen, |
353 | * transactions can still occur here so don't bother flushing the buftarg | 301 | * transactions can still occur here so don't bother emptying the AIL |
354 | * because it'll just get dirty again. | 302 | * because it'll just get dirty again. |
355 | */ | 303 | */ |
356 | int | 304 | int |
@@ -379,33 +327,6 @@ xfs_quiesce_data( | |||
379 | return error ? error : error2; | 327 | return error ? error : error2; |
380 | } | 328 | } |
381 | 329 | ||
382 | STATIC void | ||
383 | xfs_quiesce_fs( | ||
384 | struct xfs_mount *mp) | ||
385 | { | ||
386 | int count = 0, pincount; | ||
387 | |||
388 | xfs_reclaim_inodes(mp, 0); | ||
389 | xfs_flush_buftarg(mp->m_ddev_targp, 0); | ||
390 | |||
391 | /* | ||
392 | * This loop must run at least twice. The first instance of the loop | ||
393 | * will flush most meta data but that will generate more meta data | ||
394 | * (typically directory updates). Which then must be flushed and | ||
395 | * logged before we can write the unmount record. We also so sync | ||
396 | * reclaim of inodes to catch any that the above delwri flush skipped. | ||
397 | */ | ||
398 | do { | ||
399 | xfs_reclaim_inodes(mp, SYNC_WAIT); | ||
400 | xfs_sync_attr(mp, SYNC_WAIT); | ||
401 | pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1); | ||
402 | if (!pincount) { | ||
403 | delay(50); | ||
404 | count++; | ||
405 | } | ||
406 | } while (count < 2); | ||
407 | } | ||
408 | |||
409 | /* | 330 | /* |
410 | * Second stage of a quiesce. The data is already synced, now we have to take | 331 | * Second stage of a quiesce. The data is already synced, now we have to take |
411 | * care of the metadata. New transactions are already blocked, so we need to | 332 | * care of the metadata. New transactions are already blocked, so we need to |
@@ -421,8 +342,12 @@ xfs_quiesce_attr( | |||
421 | while (atomic_read(&mp->m_active_trans) > 0) | 342 | while (atomic_read(&mp->m_active_trans) > 0) |
422 | delay(100); | 343 | delay(100); |
423 | 344 | ||
424 | /* flush inodes and push all remaining buffers out to disk */ | 345 | /* reclaim inodes to do any IO before the freeze completes */ |
425 | xfs_quiesce_fs(mp); | 346 | xfs_reclaim_inodes(mp, 0); |
347 | xfs_reclaim_inodes(mp, SYNC_WAIT); | ||
348 | |||
349 | /* flush all pending changes from the AIL */ | ||
350 | xfs_ail_push_all_sync(mp->m_ail); | ||
426 | 351 | ||
427 | /* | 352 | /* |
428 | * Just warn here till VFS can correctly support | 353 | * Just warn here till VFS can correctly support |
@@ -436,7 +361,12 @@ xfs_quiesce_attr( | |||
436 | xfs_warn(mp, "xfs_attr_quiesce: failed to log sb changes. " | 361 | xfs_warn(mp, "xfs_attr_quiesce: failed to log sb changes. " |
437 | "Frozen image may not be consistent."); | 362 | "Frozen image may not be consistent."); |
438 | xfs_log_unmount_write(mp); | 363 | xfs_log_unmount_write(mp); |
439 | xfs_unmountfs_writesb(mp); | 364 | |
365 | /* | ||
366 | * At this point we might have modified the superblock again and thus | ||
367 | * added an item to the AIL, thus flush it again. | ||
368 | */ | ||
369 | xfs_ail_push_all_sync(mp->m_ail); | ||
440 | } | 370 | } |
441 | 371 | ||
442 | static void | 372 | static void |
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index 77acc53f2f31..0425ca16738b 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c | |||
@@ -383,9 +383,8 @@ xfsaild_push( | |||
383 | spin_lock(&ailp->xa_lock); | 383 | spin_lock(&ailp->xa_lock); |
384 | } | 384 | } |
385 | 385 | ||
386 | target = ailp->xa_target; | ||
387 | lip = xfs_trans_ail_cursor_first(ailp, &cur, ailp->xa_last_pushed_lsn); | 386 | lip = xfs_trans_ail_cursor_first(ailp, &cur, ailp->xa_last_pushed_lsn); |
388 | if (!lip || XFS_FORCED_SHUTDOWN(mp)) { | 387 | if (!lip) { |
389 | /* | 388 | /* |
390 | * AIL is empty or our push has reached the end. | 389 | * AIL is empty or our push has reached the end. |
391 | */ | 390 | */ |
@@ -408,6 +407,7 @@ xfsaild_push( | |||
408 | * lots of contention on the AIL lists. | 407 | * lots of contention on the AIL lists. |
409 | */ | 408 | */ |
410 | lsn = lip->li_lsn; | 409 | lsn = lip->li_lsn; |
410 | target = ailp->xa_target; | ||
411 | while ((XFS_LSN_CMP(lip->li_lsn, target) <= 0)) { | 411 | while ((XFS_LSN_CMP(lip->li_lsn, target) <= 0)) { |
412 | int lock_result; | 412 | int lock_result; |
413 | /* | 413 | /* |
@@ -466,11 +466,6 @@ xfsaild_push( | |||
466 | } | 466 | } |
467 | 467 | ||
468 | spin_lock(&ailp->xa_lock); | 468 | spin_lock(&ailp->xa_lock); |
469 | /* should we bother continuing? */ | ||
470 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
471 | break; | ||
472 | ASSERT(mp->m_log); | ||
473 | |||
474 | count++; | 469 | count++; |
475 | 470 | ||
476 | /* | 471 | /* |
@@ -611,6 +606,30 @@ xfs_ail_push_all( | |||
611 | } | 606 | } |
612 | 607 | ||
613 | /* | 608 | /* |
609 | * Push out all items in the AIL immediately and wait until the AIL is empty. | ||
610 | */ | ||
611 | void | ||
612 | xfs_ail_push_all_sync( | ||
613 | struct xfs_ail *ailp) | ||
614 | { | ||
615 | struct xfs_log_item *lip; | ||
616 | DEFINE_WAIT(wait); | ||
617 | |||
618 | spin_lock(&ailp->xa_lock); | ||
619 | while ((lip = xfs_ail_max(ailp)) != NULL) { | ||
620 | prepare_to_wait(&ailp->xa_empty, &wait, TASK_UNINTERRUPTIBLE); | ||
621 | ailp->xa_target = lip->li_lsn; | ||
622 | wake_up_process(ailp->xa_task); | ||
623 | spin_unlock(&ailp->xa_lock); | ||
624 | schedule(); | ||
625 | spin_lock(&ailp->xa_lock); | ||
626 | } | ||
627 | spin_unlock(&ailp->xa_lock); | ||
628 | |||
629 | finish_wait(&ailp->xa_empty, &wait); | ||
630 | } | ||
631 | |||
632 | /* | ||
614 | * xfs_trans_ail_update - bulk AIL insertion operation. | 633 | * xfs_trans_ail_update - bulk AIL insertion operation. |
615 | * | 634 | * |
616 | * @xfs_trans_ail_update takes an array of log items that all need to be | 635 | * @xfs_trans_ail_update takes an array of log items that all need to be |
@@ -737,6 +756,8 @@ xfs_trans_ail_delete_bulk( | |||
737 | if (mlip_changed) { | 756 | if (mlip_changed) { |
738 | if (!XFS_FORCED_SHUTDOWN(ailp->xa_mount)) | 757 | if (!XFS_FORCED_SHUTDOWN(ailp->xa_mount)) |
739 | xlog_assign_tail_lsn_locked(ailp->xa_mount); | 758 | xlog_assign_tail_lsn_locked(ailp->xa_mount); |
759 | if (list_empty(&ailp->xa_ail)) | ||
760 | wake_up_all(&ailp->xa_empty); | ||
740 | spin_unlock(&ailp->xa_lock); | 761 | spin_unlock(&ailp->xa_lock); |
741 | 762 | ||
742 | xfs_log_space_wake(ailp->xa_mount); | 763 | xfs_log_space_wake(ailp->xa_mount); |
@@ -773,6 +794,7 @@ xfs_trans_ail_init( | |||
773 | INIT_LIST_HEAD(&ailp->xa_ail); | 794 | INIT_LIST_HEAD(&ailp->xa_ail); |
774 | INIT_LIST_HEAD(&ailp->xa_cursors); | 795 | INIT_LIST_HEAD(&ailp->xa_cursors); |
775 | spin_lock_init(&ailp->xa_lock); | 796 | spin_lock_init(&ailp->xa_lock); |
797 | init_waitqueue_head(&ailp->xa_empty); | ||
776 | 798 | ||
777 | ailp->xa_task = kthread_run(xfsaild, ailp, "xfsaild/%s", | 799 | ailp->xa_task = kthread_run(xfsaild, ailp, "xfsaild/%s", |
778 | ailp->xa_mount->m_fsname); | 800 | ailp->xa_mount->m_fsname); |
diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h index 46a1ebd4a7a2..218304a8cdc7 100644 --- a/fs/xfs/xfs_trans_priv.h +++ b/fs/xfs/xfs_trans_priv.h | |||
@@ -71,6 +71,7 @@ struct xfs_ail { | |||
71 | spinlock_t xa_lock; | 71 | spinlock_t xa_lock; |
72 | xfs_lsn_t xa_last_pushed_lsn; | 72 | xfs_lsn_t xa_last_pushed_lsn; |
73 | int xa_log_flush; | 73 | int xa_log_flush; |
74 | wait_queue_head_t xa_empty; | ||
74 | }; | 75 | }; |
75 | 76 | ||
76 | /* | 77 | /* |
@@ -102,6 +103,7 @@ xfs_trans_ail_delete( | |||
102 | 103 | ||
103 | void xfs_ail_push(struct xfs_ail *, xfs_lsn_t); | 104 | void xfs_ail_push(struct xfs_ail *, xfs_lsn_t); |
104 | void xfs_ail_push_all(struct xfs_ail *); | 105 | void xfs_ail_push_all(struct xfs_ail *); |
106 | void xfs_ail_push_all_sync(struct xfs_ail *); | ||
105 | struct xfs_log_item *xfs_ail_min(struct xfs_ail *ailp); | 107 | struct xfs_log_item *xfs_ail_min(struct xfs_ail *ailp); |
106 | xfs_lsn_t xfs_ail_min_lsn(struct xfs_ail *ailp); | 108 | xfs_lsn_t xfs_ail_min_lsn(struct xfs_ail *ailp); |
107 | 109 | ||