diff options
-rw-r--r-- | fs/xfs/linux-2.6/xfs_sync.c | 66 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_sync.h | 2 |
2 files changed, 45 insertions, 23 deletions
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index 37fc2c0a4d25..0ed3d0ae3c28 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c | |||
@@ -39,6 +39,14 @@ | |||
39 | #include <linux/kthread.h> | 39 | #include <linux/kthread.h> |
40 | #include <linux/freezer.h> | 40 | #include <linux/freezer.h> |
41 | 41 | ||
42 | /* | ||
43 | * The inode lookup is done in batches to keep the amount of lock traffic and | ||
44 | * radix tree lookups to a minimum. The batch size is a trade off between | ||
45 | * lookup reduction and stack usage. This is in the reclaim path, so we can't | ||
46 | * be too greedy. | ||
47 | */ | ||
48 | #define XFS_LOOKUP_BATCH 32 | ||
49 | |||
42 | STATIC int | 50 | STATIC int |
43 | xfs_inode_ag_walk_grab( | 51 | xfs_inode_ag_walk_grab( |
44 | struct xfs_inode *ip) | 52 | struct xfs_inode *ip) |
@@ -66,7 +74,6 @@ xfs_inode_ag_walk_grab( | |||
66 | return 0; | 74 | return 0; |
67 | } | 75 | } |
68 | 76 | ||
69 | |||
70 | STATIC int | 77 | STATIC int |
71 | xfs_inode_ag_walk( | 78 | xfs_inode_ag_walk( |
72 | struct xfs_mount *mp, | 79 | struct xfs_mount *mp, |
@@ -79,54 +86,69 @@ xfs_inode_ag_walk( | |||
79 | int last_error = 0; | 86 | int last_error = 0; |
80 | int skipped; | 87 | int skipped; |
81 | int done; | 88 | int done; |
89 | int nr_found; | ||
82 | 90 | ||
83 | restart: | 91 | restart: |
84 | done = 0; | 92 | done = 0; |
85 | skipped = 0; | 93 | skipped = 0; |
86 | first_index = 0; | 94 | first_index = 0; |
95 | nr_found = 0; | ||
87 | do { | 96 | do { |
97 | struct xfs_inode *batch[XFS_LOOKUP_BATCH]; | ||
88 | int error = 0; | 98 | int error = 0; |
89 | int nr_found; | 99 | int i; |
90 | xfs_inode_t *ip; | ||
91 | 100 | ||
92 | read_lock(&pag->pag_ici_lock); | 101 | read_lock(&pag->pag_ici_lock); |
93 | nr_found = radix_tree_gang_lookup(&pag->pag_ici_root, | 102 | nr_found = radix_tree_gang_lookup(&pag->pag_ici_root, |
94 | (void **)&ip, first_index, 1); | 103 | (void **)batch, first_index, |
104 | XFS_LOOKUP_BATCH); | ||
95 | if (!nr_found) { | 105 | if (!nr_found) { |
96 | read_unlock(&pag->pag_ici_lock); | 106 | read_unlock(&pag->pag_ici_lock); |
97 | break; | 107 | break; |
98 | } | 108 | } |
99 | 109 | ||
100 | /* | 110 | /* |
101 | * Update the index for the next lookup. Catch overflows | 111 | * Grab the inodes before we drop the lock. if we found |
102 | * into the next AG range which can occur if we have inodes | 112 | * nothing, nr == 0 and the loop will be skipped. |
103 | * in the last block of the AG and we are currently | ||
104 | * pointing to the last inode. | ||
105 | */ | 113 | */ |
106 | first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1); | 114 | for (i = 0; i < nr_found; i++) { |
107 | if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino)) | 115 | struct xfs_inode *ip = batch[i]; |
108 | done = 1; | ||
109 | 116 | ||
110 | if (xfs_inode_ag_walk_grab(ip)) { | 117 | if (done || xfs_inode_ag_walk_grab(ip)) |
111 | read_unlock(&pag->pag_ici_lock); | 118 | batch[i] = NULL; |
112 | continue; | 119 | |
120 | /* | ||
121 | * Update the index for the next lookup. Catch overflows | ||
122 | * into the next AG range which can occur if we have inodes | ||
123 | * in the last block of the AG and we are currently | ||
124 | * pointing to the last inode. | ||
125 | */ | ||
126 | first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1); | ||
127 | if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino)) | ||
128 | done = 1; | ||
113 | } | 129 | } |
130 | |||
131 | /* unlock now we've grabbed the inodes. */ | ||
114 | read_unlock(&pag->pag_ici_lock); | 132 | read_unlock(&pag->pag_ici_lock); |
115 | 133 | ||
116 | error = execute(ip, pag, flags); | 134 | for (i = 0; i < nr_found; i++) { |
117 | IRELE(ip); | 135 | if (!batch[i]) |
118 | if (error == EAGAIN) { | 136 | continue; |
119 | skipped++; | 137 | error = execute(batch[i], pag, flags); |
120 | continue; | 138 | IRELE(batch[i]); |
139 | if (error == EAGAIN) { | ||
140 | skipped++; | ||
141 | continue; | ||
142 | } | ||
143 | if (error && last_error != EFSCORRUPTED) | ||
144 | last_error = error; | ||
121 | } | 145 | } |
122 | if (error) | ||
123 | last_error = error; | ||
124 | 146 | ||
125 | /* bail out if the filesystem is corrupted. */ | 147 | /* bail out if the filesystem is corrupted. */ |
126 | if (error == EFSCORRUPTED) | 148 | if (error == EFSCORRUPTED) |
127 | break; | 149 | break; |
128 | 150 | ||
129 | } while (!done); | 151 | } while (nr_found && !done); |
130 | 152 | ||
131 | if (skipped) { | 153 | if (skipped) { |
132 | delay(1); | 154 | delay(1); |
diff --git a/fs/xfs/linux-2.6/xfs_sync.h b/fs/xfs/linux-2.6/xfs_sync.h index e8a352896d20..32ba6628290c 100644 --- a/fs/xfs/linux-2.6/xfs_sync.h +++ b/fs/xfs/linux-2.6/xfs_sync.h | |||
@@ -47,7 +47,7 @@ void __xfs_inode_set_reclaim_tag(struct xfs_perag *pag, struct xfs_inode *ip); | |||
47 | void __xfs_inode_clear_reclaim_tag(struct xfs_mount *mp, struct xfs_perag *pag, | 47 | void __xfs_inode_clear_reclaim_tag(struct xfs_mount *mp, struct xfs_perag *pag, |
48 | struct xfs_inode *ip); | 48 | struct xfs_inode *ip); |
49 | 49 | ||
50 | int xfs_sync_inode_valid(struct xfs_inode *ip, struct xfs_perag *pag); | 50 | int xfs_sync_inode_grab(struct xfs_inode *ip); |
51 | int xfs_inode_ag_iterator(struct xfs_mount *mp, | 51 | int xfs_inode_ag_iterator(struct xfs_mount *mp, |
52 | int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag, int flags), | 52 | int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag, int flags), |
53 | int flags); | 53 | int flags); |