xfs: use xfs_sync_inodes() for device flushing

Currently xfs_device_flush calls sync_blockdev() which is
a no-op for XFS as all it's metadata is held in a different
address to the one sync_blockdev() works on.

Call xfs_sync_inodes() instead to flush all the delayed
allocation blocks out. To do this as efficiently as possible,
do it via two passes - one to do an async flush of all the
dirty blocks and a second to wait for all the IO to complete.
This requires some modification to the xfs-sync_inodes_ag()
flush code to do efficiently.

Signed-off-by: Dave Chinner <david@fromorbit.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>

authored by

Dave Chinner and committed by
Christoph Hellwig
a8d770d9 9d7fef74

+38 -30
+7 -7
fs/xfs/linux-2.6/xfs_fs_subr.c
··· 74 74 75 75 if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { 76 76 xfs_iflags_clear(ip, XFS_ITRUNCATED); 77 - ret = filemap_fdatawrite(mapping); 78 - if (flags & XFS_B_ASYNC) 79 - return -ret; 80 - ret2 = filemap_fdatawait(mapping); 81 - if (!ret) 82 - ret = ret2; 77 + ret = -filemap_fdatawrite(mapping); 83 78 } 84 - return -ret; 79 + if (flags & XFS_B_ASYNC) 80 + return ret; 81 + ret2 = xfs_wait_on_pages(ip, first, last); 82 + if (!ret) 83 + ret = ret2; 84 + return ret; 85 85 } 86 86 87 87 int
+25 -18
fs/xfs/linux-2.6/xfs_sync.c
··· 62 62 uint32_t first_index = 0; 63 63 int error = 0; 64 64 int last_error = 0; 65 - int fflag = XFS_B_ASYNC; 66 - 67 - if (flags & SYNC_DELWRI) 68 - fflag = XFS_B_DELWRI; 69 - if (flags & SYNC_WAIT) 70 - fflag = 0; /* synchronous overrides all */ 71 65 72 66 do { 73 67 struct inode *inode; ··· 122 128 * If we have to flush data or wait for I/O completion 123 129 * we need to hold the iolock. 124 130 */ 125 - if ((flags & SYNC_DELWRI) && VN_DIRTY(inode)) { 126 - xfs_ilock(ip, XFS_IOLOCK_SHARED); 127 - lock_flags |= XFS_IOLOCK_SHARED; 128 - error = xfs_flush_pages(ip, 0, -1, fflag, FI_NONE); 129 - if (flags & SYNC_IOWAIT) 131 + if (flags & SYNC_DELWRI) { 132 + if (VN_DIRTY(inode)) { 133 + if (flags & SYNC_TRYLOCK) { 134 + if (xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED)) 135 + lock_flags |= XFS_IOLOCK_SHARED; 136 + } else { 137 + xfs_ilock(ip, XFS_IOLOCK_SHARED); 138 + lock_flags |= XFS_IOLOCK_SHARED; 139 + } 140 + if (lock_flags & XFS_IOLOCK_SHARED) { 141 + error = xfs_flush_pages(ip, 0, -1, 142 + (flags & SYNC_WAIT) ? 0 143 + : XFS_B_ASYNC, 144 + FI_NONE); 145 + } 146 + } 147 + if (VN_CACHED(inode) && (flags & SYNC_IOWAIT)) 130 148 xfs_ioend_wait(ip); 131 149 } 132 150 xfs_ilock(ip, XFS_ILOCK_SHARED); ··· 406 400 void *data, 407 401 void (*syncer)(struct xfs_mount *, void *)) 408 402 { 409 - struct bhv_vfs_sync_work *work; 403 + struct xfs_sync_work *work; 410 404 411 - work = kmem_alloc(sizeof(struct bhv_vfs_sync_work), KM_SLEEP); 405 + work = kmem_alloc(sizeof(struct xfs_sync_work), KM_SLEEP); 412 406 INIT_LIST_HEAD(&work->w_list); 413 407 work->w_syncer = syncer; 414 408 work->w_data = data; ··· 451 445 * (IOW, "If at first you don't succeed, use a Bigger Hammer"). 452 446 */ 453 447 STATIC void 454 - xfs_flush_device_work( 448 + xfs_flush_inodes_work( 455 449 struct xfs_mount *mp, 456 450 void *arg) 457 451 { 458 452 struct inode *inode = arg; 459 - sync_blockdev(mp->m_super->s_bdev); 453 + xfs_sync_inodes(mp, SYNC_DELWRI | SYNC_TRYLOCK); 454 + xfs_sync_inodes(mp, SYNC_DELWRI | SYNC_TRYLOCK | SYNC_IOWAIT); 460 455 iput(inode); 461 456 } 462 457 463 458 void 464 - xfs_flush_device( 459 + xfs_flush_inodes( 465 460 xfs_inode_t *ip) 466 461 { 467 462 struct inode *inode = VFS_I(ip); 468 463 469 464 igrab(inode); 470 - xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_device_work); 465 + xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_inodes_work); 471 466 delay(msecs_to_jiffies(500)); 472 467 xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC); 473 468 } ··· 504 497 { 505 498 struct xfs_mount *mp = arg; 506 499 long timeleft; 507 - bhv_vfs_sync_work_t *work, *n; 500 + xfs_sync_work_t *work, *n; 508 501 LIST_HEAD (tmp); 509 502 510 503 set_freezable();
+4 -3
fs/xfs/linux-2.6/xfs_sync.h
··· 21 21 struct xfs_mount; 22 22 struct xfs_perag; 23 23 24 - typedef struct bhv_vfs_sync_work { 24 + typedef struct xfs_sync_work { 25 25 struct list_head w_list; 26 26 struct xfs_mount *w_mount; 27 27 void *w_data; /* syncer routine argument */ 28 28 void (*w_syncer)(struct xfs_mount *, void *); 29 - } bhv_vfs_sync_work_t; 29 + } xfs_sync_work_t; 30 30 31 31 #define SYNC_ATTR 0x0001 /* sync attributes */ 32 32 #define SYNC_DELWRI 0x0002 /* look at delayed writes */ 33 33 #define SYNC_WAIT 0x0004 /* wait for i/o to complete */ 34 34 #define SYNC_BDFLUSH 0x0008 /* BDFLUSH is calling -- don't block */ 35 35 #define SYNC_IOWAIT 0x0010 /* wait for all I/O to complete */ 36 + #define SYNC_TRYLOCK 0x0020 /* only try to lock inodes */ 36 37 37 38 int xfs_syncd_init(struct xfs_mount *mp); 38 39 void xfs_syncd_stop(struct xfs_mount *mp); ··· 45 44 void xfs_quiesce_attr(struct xfs_mount *mp); 46 45 47 46 void xfs_flush_inode(struct xfs_inode *ip); 48 - void xfs_flush_device(struct xfs_inode *ip); 47 + void xfs_flush_inodes(struct xfs_inode *ip); 49 48 50 49 int xfs_reclaim_inode(struct xfs_inode *ip, int locked, int sync_mode); 51 50 int xfs_reclaim_inodes(struct xfs_mount *mp, int noblock, int mode);
+1 -1
fs/xfs/xfs_iomap.c
··· 361 361 return 0; 362 362 case 2: 363 363 xfs_iunlock(ip, XFS_ILOCK_EXCL); 364 - xfs_flush_device(ip); 364 + xfs_flush_inodes(ip); 365 365 xfs_ilock(ip, XFS_ILOCK_EXCL); 366 366 *fsynced = 3; 367 367 return 0;
+1 -1
fs/xfs/xfs_mount.h
··· 313 313 #endif 314 314 struct xfs_mru_cache *m_filestream; /* per-mount filestream data */ 315 315 struct task_struct *m_sync_task; /* generalised sync thread */ 316 - bhv_vfs_sync_work_t m_sync_work; /* work item for VFS_SYNC */ 316 + xfs_sync_work_t m_sync_work; /* work item for VFS_SYNC */ 317 317 struct list_head m_sync_list; /* sync thread work item list */ 318 318 spinlock_t m_sync_lock; /* work item list lock */ 319 319 int m_sync_seq; /* sync thread generation no. */