diff options
Diffstat (limited to 'fs/xfs/linux-2.6/xfs_buf.c')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_buf.c | 91 |
1 files changed, 86 insertions, 5 deletions
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index d71dc44e21ed..aa1016bb9134 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c | |||
@@ -34,6 +34,12 @@ | |||
34 | #include <linux/backing-dev.h> | 34 | #include <linux/backing-dev.h> |
35 | #include <linux/freezer.h> | 35 | #include <linux/freezer.h> |
36 | 36 | ||
37 | #include "xfs_sb.h" | ||
38 | #include "xfs_inum.h" | ||
39 | #include "xfs_ag.h" | ||
40 | #include "xfs_dmapi.h" | ||
41 | #include "xfs_mount.h" | ||
42 | |||
37 | static kmem_zone_t *xfs_buf_zone; | 43 | static kmem_zone_t *xfs_buf_zone; |
38 | STATIC int xfsbufd(void *); | 44 | STATIC int xfsbufd(void *); |
39 | STATIC int xfsbufd_wakeup(int, gfp_t); | 45 | STATIC int xfsbufd_wakeup(int, gfp_t); |
@@ -166,6 +172,75 @@ test_page_region( | |||
166 | } | 172 | } |
167 | 173 | ||
168 | /* | 174 | /* |
175 | * Mapping of multi-page buffers into contiguous virtual space | ||
176 | */ | ||
177 | |||
178 | typedef struct a_list { | ||
179 | void *vm_addr; | ||
180 | struct a_list *next; | ||
181 | } a_list_t; | ||
182 | |||
183 | static a_list_t *as_free_head; | ||
184 | static int as_list_len; | ||
185 | static DEFINE_SPINLOCK(as_lock); | ||
186 | |||
187 | /* | ||
188 | * Try to batch vunmaps because they are costly. | ||
189 | */ | ||
190 | STATIC void | ||
191 | free_address( | ||
192 | void *addr) | ||
193 | { | ||
194 | a_list_t *aentry; | ||
195 | |||
196 | #ifdef CONFIG_XEN | ||
197 | /* | ||
198 | * Xen needs to be able to make sure it can get an exclusive | ||
199 | * RO mapping of pages it wants to turn into a pagetable. If | ||
200 | * a newly allocated page is also still being vmap()ed by xfs, | ||
201 | * it will cause pagetable construction to fail. This is a | ||
202 | * quick workaround to always eagerly unmap pages so that Xen | ||
203 | * is happy. | ||
204 | */ | ||
205 | vunmap(addr); | ||
206 | return; | ||
207 | #endif | ||
208 | |||
209 | aentry = kmalloc(sizeof(a_list_t), GFP_NOWAIT); | ||
210 | if (likely(aentry)) { | ||
211 | spin_lock(&as_lock); | ||
212 | aentry->next = as_free_head; | ||
213 | aentry->vm_addr = addr; | ||
214 | as_free_head = aentry; | ||
215 | as_list_len++; | ||
216 | spin_unlock(&as_lock); | ||
217 | } else { | ||
218 | vunmap(addr); | ||
219 | } | ||
220 | } | ||
221 | |||
222 | STATIC void | ||
223 | purge_addresses(void) | ||
224 | { | ||
225 | a_list_t *aentry, *old; | ||
226 | |||
227 | if (as_free_head == NULL) | ||
228 | return; | ||
229 | |||
230 | spin_lock(&as_lock); | ||
231 | aentry = as_free_head; | ||
232 | as_free_head = NULL; | ||
233 | as_list_len = 0; | ||
234 | spin_unlock(&as_lock); | ||
235 | |||
236 | while ((old = aentry) != NULL) { | ||
237 | vunmap(aentry->vm_addr); | ||
238 | aentry = aentry->next; | ||
239 | kfree(old); | ||
240 | } | ||
241 | } | ||
242 | |||
243 | /* | ||
169 | * Internal xfs_buf_t object manipulation | 244 | * Internal xfs_buf_t object manipulation |
170 | */ | 245 | */ |
171 | 246 | ||
@@ -264,7 +339,7 @@ xfs_buf_free( | |||
264 | uint i; | 339 | uint i; |
265 | 340 | ||
266 | if ((bp->b_flags & XBF_MAPPED) && (bp->b_page_count > 1)) | 341 | if ((bp->b_flags & XBF_MAPPED) && (bp->b_page_count > 1)) |
267 | vm_unmap_ram(bp->b_addr - bp->b_offset, bp->b_page_count); | 342 | free_address(bp->b_addr - bp->b_offset); |
268 | 343 | ||
269 | for (i = 0; i < bp->b_page_count; i++) { | 344 | for (i = 0; i < bp->b_page_count; i++) { |
270 | struct page *page = bp->b_pages[i]; | 345 | struct page *page = bp->b_pages[i]; |
@@ -386,8 +461,10 @@ _xfs_buf_map_pages( | |||
386 | bp->b_addr = page_address(bp->b_pages[0]) + bp->b_offset; | 461 | bp->b_addr = page_address(bp->b_pages[0]) + bp->b_offset; |
387 | bp->b_flags |= XBF_MAPPED; | 462 | bp->b_flags |= XBF_MAPPED; |
388 | } else if (flags & XBF_MAPPED) { | 463 | } else if (flags & XBF_MAPPED) { |
389 | bp->b_addr = vm_map_ram(bp->b_pages, bp->b_page_count, | 464 | if (as_list_len > 64) |
390 | -1, PAGE_KERNEL); | 465 | purge_addresses(); |
466 | bp->b_addr = vmap(bp->b_pages, bp->b_page_count, | ||
467 | VM_MAP, PAGE_KERNEL); | ||
391 | if (unlikely(bp->b_addr == NULL)) | 468 | if (unlikely(bp->b_addr == NULL)) |
392 | return -ENOMEM; | 469 | return -ENOMEM; |
393 | bp->b_addr += bp->b_offset; | 470 | bp->b_addr += bp->b_offset; |
@@ -1364,10 +1441,12 @@ xfs_unregister_buftarg( | |||
1364 | 1441 | ||
1365 | void | 1442 | void |
1366 | xfs_free_buftarg( | 1443 | xfs_free_buftarg( |
1367 | xfs_buftarg_t *btp) | 1444 | struct xfs_mount *mp, |
1445 | struct xfs_buftarg *btp) | ||
1368 | { | 1446 | { |
1369 | xfs_flush_buftarg(btp, 1); | 1447 | xfs_flush_buftarg(btp, 1); |
1370 | xfs_blkdev_issue_flush(btp); | 1448 | if (mp->m_flags & XFS_MOUNT_BARRIER) |
1449 | xfs_blkdev_issue_flush(btp); | ||
1371 | xfs_free_bufhash(btp); | 1450 | xfs_free_bufhash(btp); |
1372 | iput(btp->bt_mapping->host); | 1451 | iput(btp->bt_mapping->host); |
1373 | 1452 | ||
@@ -1672,6 +1751,8 @@ xfsbufd( | |||
1672 | count++; | 1751 | count++; |
1673 | } | 1752 | } |
1674 | 1753 | ||
1754 | if (as_list_len > 0) | ||
1755 | purge_addresses(); | ||
1675 | if (count) | 1756 | if (count) |
1676 | blk_run_address_space(target->bt_mapping); | 1757 | blk_run_address_space(target->bt_mapping); |
1677 | 1758 | ||