diff options
author | Dave Chinner <david@fromorbit.com> | 2009-04-06 12:44:54 -0400 |
---|---|---|
committer | Christoph Hellwig <hch@brick.lst.de> | 2009-04-06 12:44:54 -0400 |
commit | a8d770d987ee20b59fba6c37d7f0f2a351913c4b (patch) | |
tree | 3da37edba537ca5860eae97f47fb1204bc5a55b3 | |
parent | 9d7fef74b23fe57803c5f71fab11630d9ec2cb4b (diff) |
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>
-rw-r--r-- | fs/xfs/linux-2.6/xfs_fs_subr.c | 14 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_sync.c | 43 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_sync.h | 7 | ||||
-rw-r--r-- | fs/xfs/xfs_iomap.c | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.h | 2 |
5 files changed, 38 insertions, 30 deletions
diff --git a/fs/xfs/linux-2.6/xfs_fs_subr.c b/fs/xfs/linux-2.6/xfs_fs_subr.c index 5aeb77776961..08be36d7326c 100644 --- a/fs/xfs/linux-2.6/xfs_fs_subr.c +++ b/fs/xfs/linux-2.6/xfs_fs_subr.c | |||
@@ -74,14 +74,14 @@ xfs_flush_pages( | |||
74 | 74 | ||
75 | if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { | 75 | if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { |
76 | xfs_iflags_clear(ip, XFS_ITRUNCATED); | 76 | xfs_iflags_clear(ip, XFS_ITRUNCATED); |
77 | ret = filemap_fdatawrite(mapping); | 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; | ||
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 | int | 87 | int |
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index a608e72fa405..88caafc8ef1b 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c | |||
@@ -62,12 +62,6 @@ xfs_sync_inodes_ag( | |||
62 | uint32_t first_index = 0; | 62 | uint32_t first_index = 0; |
63 | int error = 0; | 63 | int error = 0; |
64 | int last_error = 0; | 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 | do { | 66 | do { |
73 | struct inode *inode; | 67 | struct inode *inode; |
@@ -128,11 +122,23 @@ xfs_sync_inodes_ag( | |||
128 | * If we have to flush data or wait for I/O completion | 122 | * If we have to flush data or wait for I/O completion |
129 | * we need to hold the iolock. | 123 | * we need to hold the iolock. |
130 | */ | 124 | */ |
131 | if ((flags & SYNC_DELWRI) && VN_DIRTY(inode)) { | 125 | if (flags & SYNC_DELWRI) { |
132 | xfs_ilock(ip, XFS_IOLOCK_SHARED); | 126 | if (VN_DIRTY(inode)) { |
133 | lock_flags |= XFS_IOLOCK_SHARED; | 127 | if (flags & SYNC_TRYLOCK) { |
134 | error = xfs_flush_pages(ip, 0, -1, fflag, FI_NONE); | 128 | if (xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED)) |
135 | if (flags & SYNC_IOWAIT) | 129 | lock_flags |= XFS_IOLOCK_SHARED; |
130 | } else { | ||
131 | xfs_ilock(ip, XFS_IOLOCK_SHARED); | ||
132 | lock_flags |= XFS_IOLOCK_SHARED; | ||
133 | } | ||
134 | if (lock_flags & XFS_IOLOCK_SHARED) { | ||
135 | error = xfs_flush_pages(ip, 0, -1, | ||
136 | (flags & SYNC_WAIT) ? 0 | ||
137 | : XFS_B_ASYNC, | ||
138 | FI_NONE); | ||
139 | } | ||
140 | } | ||
141 | if (VN_CACHED(inode) && (flags & SYNC_IOWAIT)) | ||
136 | xfs_ioend_wait(ip); | 142 | xfs_ioend_wait(ip); |
137 | } | 143 | } |
138 | xfs_ilock(ip, XFS_ILOCK_SHARED); | 144 | xfs_ilock(ip, XFS_ILOCK_SHARED); |
@@ -400,9 +406,9 @@ xfs_syncd_queue_work( | |||
400 | void *data, | 406 | void *data, |
401 | void (*syncer)(struct xfs_mount *, void *)) | 407 | void (*syncer)(struct xfs_mount *, void *)) |
402 | { | 408 | { |
403 | struct bhv_vfs_sync_work *work; | 409 | struct xfs_sync_work *work; |
404 | 410 | ||
405 | work = kmem_alloc(sizeof(struct bhv_vfs_sync_work), KM_SLEEP); | 411 | work = kmem_alloc(sizeof(struct xfs_sync_work), KM_SLEEP); |
406 | INIT_LIST_HEAD(&work->w_list); | 412 | INIT_LIST_HEAD(&work->w_list); |
407 | work->w_syncer = syncer; | 413 | work->w_syncer = syncer; |
408 | work->w_data = data; | 414 | work->w_data = data; |
@@ -445,23 +451,24 @@ xfs_flush_inode( | |||
445 | * (IOW, "If at first you don't succeed, use a Bigger Hammer"). | 451 | * (IOW, "If at first you don't succeed, use a Bigger Hammer"). |
446 | */ | 452 | */ |
447 | STATIC void | 453 | STATIC void |
448 | xfs_flush_device_work( | 454 | xfs_flush_inodes_work( |
449 | struct xfs_mount *mp, | 455 | struct xfs_mount *mp, |
450 | void *arg) | 456 | void *arg) |
451 | { | 457 | { |
452 | struct inode *inode = arg; | 458 | struct inode *inode = arg; |
453 | sync_blockdev(mp->m_super->s_bdev); | 459 | xfs_sync_inodes(mp, SYNC_DELWRI | SYNC_TRYLOCK); |
460 | xfs_sync_inodes(mp, SYNC_DELWRI | SYNC_TRYLOCK | SYNC_IOWAIT); | ||
454 | iput(inode); | 461 | iput(inode); |
455 | } | 462 | } |
456 | 463 | ||
457 | void | 464 | void |
458 | xfs_flush_device( | 465 | xfs_flush_inodes( |
459 | xfs_inode_t *ip) | 466 | xfs_inode_t *ip) |
460 | { | 467 | { |
461 | struct inode *inode = VFS_I(ip); | 468 | struct inode *inode = VFS_I(ip); |
462 | 469 | ||
463 | igrab(inode); | 470 | igrab(inode); |
464 | xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_device_work); | 471 | xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_inodes_work); |
465 | delay(msecs_to_jiffies(500)); | 472 | delay(msecs_to_jiffies(500)); |
466 | xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC); | 473 | xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC); |
467 | } | 474 | } |
@@ -497,7 +504,7 @@ xfssyncd( | |||
497 | { | 504 | { |
498 | struct xfs_mount *mp = arg; | 505 | struct xfs_mount *mp = arg; |
499 | long timeleft; | 506 | long timeleft; |
500 | bhv_vfs_sync_work_t *work, *n; | 507 | xfs_sync_work_t *work, *n; |
501 | LIST_HEAD (tmp); | 508 | LIST_HEAD (tmp); |
502 | 509 | ||
503 | set_freezable(); | 510 | set_freezable(); |
diff --git a/fs/xfs/linux-2.6/xfs_sync.h b/fs/xfs/linux-2.6/xfs_sync.h index 04f058c848ae..ec95e264805b 100644 --- a/fs/xfs/linux-2.6/xfs_sync.h +++ b/fs/xfs/linux-2.6/xfs_sync.h | |||
@@ -21,18 +21,19 @@ | |||
21 | struct xfs_mount; | 21 | struct xfs_mount; |
22 | struct xfs_perag; | 22 | struct xfs_perag; |
23 | 23 | ||
24 | typedef struct bhv_vfs_sync_work { | 24 | typedef struct xfs_sync_work { |
25 | struct list_head w_list; | 25 | struct list_head w_list; |
26 | struct xfs_mount *w_mount; | 26 | struct xfs_mount *w_mount; |
27 | void *w_data; /* syncer routine argument */ | 27 | void *w_data; /* syncer routine argument */ |
28 | void (*w_syncer)(struct xfs_mount *, void *); | 28 | void (*w_syncer)(struct xfs_mount *, void *); |
29 | } bhv_vfs_sync_work_t; | 29 | } xfs_sync_work_t; |
30 | 30 | ||
31 | #define SYNC_ATTR 0x0001 /* sync attributes */ | 31 | #define SYNC_ATTR 0x0001 /* sync attributes */ |
32 | #define SYNC_DELWRI 0x0002 /* look at delayed writes */ | 32 | #define SYNC_DELWRI 0x0002 /* look at delayed writes */ |
33 | #define SYNC_WAIT 0x0004 /* wait for i/o to complete */ | 33 | #define SYNC_WAIT 0x0004 /* wait for i/o to complete */ |
34 | #define SYNC_BDFLUSH 0x0008 /* BDFLUSH is calling -- don't block */ | 34 | #define SYNC_BDFLUSH 0x0008 /* BDFLUSH is calling -- don't block */ |
35 | #define SYNC_IOWAIT 0x0010 /* wait for all I/O to complete */ | 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 | int xfs_syncd_init(struct xfs_mount *mp); | 38 | int xfs_syncd_init(struct xfs_mount *mp); |
38 | void xfs_syncd_stop(struct xfs_mount *mp); | 39 | void xfs_syncd_stop(struct xfs_mount *mp); |
@@ -44,7 +45,7 @@ int xfs_quiesce_data(struct xfs_mount *mp); | |||
44 | void xfs_quiesce_attr(struct xfs_mount *mp); | 45 | void xfs_quiesce_attr(struct xfs_mount *mp); |
45 | 46 | ||
46 | void xfs_flush_inode(struct xfs_inode *ip); | 47 | void xfs_flush_inode(struct xfs_inode *ip); |
47 | void xfs_flush_device(struct xfs_inode *ip); | 48 | void xfs_flush_inodes(struct xfs_inode *ip); |
48 | 49 | ||
49 | int xfs_reclaim_inode(struct xfs_inode *ip, int locked, int sync_mode); | 50 | int xfs_reclaim_inode(struct xfs_inode *ip, int locked, int sync_mode); |
50 | int xfs_reclaim_inodes(struct xfs_mount *mp, int noblock, int mode); | 51 | int xfs_reclaim_inodes(struct xfs_mount *mp, int noblock, int mode); |
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 08ce72316bfe..8b97d82d7a88 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c | |||
@@ -361,7 +361,7 @@ xfs_flush_space( | |||
361 | return 0; | 361 | return 0; |
362 | case 2: | 362 | case 2: |
363 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 363 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
364 | xfs_flush_device(ip); | 364 | xfs_flush_inodes(ip); |
365 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 365 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
366 | *fsynced = 3; | 366 | *fsynced = 3; |
367 | return 0; | 367 | return 0; |
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 7af44adffc8f..d6a64392f983 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h | |||
@@ -313,7 +313,7 @@ typedef struct xfs_mount { | |||
313 | #endif | 313 | #endif |
314 | struct xfs_mru_cache *m_filestream; /* per-mount filestream data */ | 314 | struct xfs_mru_cache *m_filestream; /* per-mount filestream data */ |
315 | struct task_struct *m_sync_task; /* generalised sync thread */ | 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 | struct list_head m_sync_list; /* sync thread work item list */ | 317 | struct list_head m_sync_list; /* sync thread work item list */ |
318 | spinlock_t m_sync_lock; /* work item list lock */ | 318 | spinlock_t m_sync_lock; /* work item list lock */ |
319 | int m_sync_seq; /* sync thread generation no. */ | 319 | int m_sync_seq; /* sync thread generation no. */ |