diff options
Diffstat (limited to 'fs/xfs/linux-2.6/xfs_buf.c')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_buf.c | 67 |
1 files changed, 30 insertions, 37 deletions
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index fe4f66a5af14..b0f0e58866de 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c | |||
@@ -35,10 +35,13 @@ | |||
35 | #include <linux/freezer.h> | 35 | #include <linux/freezer.h> |
36 | 36 | ||
37 | static kmem_zone_t *xfs_buf_zone; | 37 | static kmem_zone_t *xfs_buf_zone; |
38 | static kmem_shaker_t xfs_buf_shake; | ||
39 | STATIC int xfsbufd(void *); | 38 | STATIC int xfsbufd(void *); |
40 | STATIC int xfsbufd_wakeup(int, gfp_t); | 39 | STATIC int xfsbufd_wakeup(int, gfp_t); |
41 | STATIC void xfs_buf_delwri_queue(xfs_buf_t *, int); | 40 | STATIC void xfs_buf_delwri_queue(xfs_buf_t *, int); |
41 | static struct shrinker xfs_buf_shake = { | ||
42 | .shrink = xfsbufd_wakeup, | ||
43 | .seeks = DEFAULT_SEEKS, | ||
44 | }; | ||
42 | 45 | ||
43 | static struct workqueue_struct *xfslogd_workqueue; | 46 | static struct workqueue_struct *xfslogd_workqueue; |
44 | struct workqueue_struct *xfsdatad_workqueue; | 47 | struct workqueue_struct *xfsdatad_workqueue; |
@@ -314,7 +317,7 @@ xfs_buf_free( | |||
314 | 317 | ||
315 | ASSERT(list_empty(&bp->b_hash_list)); | 318 | ASSERT(list_empty(&bp->b_hash_list)); |
316 | 319 | ||
317 | if (bp->b_flags & _XBF_PAGE_CACHE) { | 320 | if (bp->b_flags & (_XBF_PAGE_CACHE|_XBF_PAGES)) { |
318 | uint i; | 321 | uint i; |
319 | 322 | ||
320 | if ((bp->b_flags & XBF_MAPPED) && (bp->b_page_count > 1)) | 323 | if ((bp->b_flags & XBF_MAPPED) && (bp->b_page_count > 1)) |
@@ -323,18 +326,11 @@ xfs_buf_free( | |||
323 | for (i = 0; i < bp->b_page_count; i++) { | 326 | for (i = 0; i < bp->b_page_count; i++) { |
324 | struct page *page = bp->b_pages[i]; | 327 | struct page *page = bp->b_pages[i]; |
325 | 328 | ||
326 | ASSERT(!PagePrivate(page)); | 329 | if (bp->b_flags & _XBF_PAGE_CACHE) |
330 | ASSERT(!PagePrivate(page)); | ||
327 | page_cache_release(page); | 331 | page_cache_release(page); |
328 | } | 332 | } |
329 | _xfs_buf_free_pages(bp); | 333 | _xfs_buf_free_pages(bp); |
330 | } else if (bp->b_flags & _XBF_KMEM_ALLOC) { | ||
331 | /* | ||
332 | * XXX(hch): bp->b_count_desired might be incorrect (see | ||
333 | * xfs_buf_associate_memory for details), but fortunately | ||
334 | * the Linux version of kmem_free ignores the len argument.. | ||
335 | */ | ||
336 | kmem_free(bp->b_addr, bp->b_count_desired); | ||
337 | _xfs_buf_free_pages(bp); | ||
338 | } | 334 | } |
339 | 335 | ||
340 | xfs_buf_deallocate(bp); | 336 | xfs_buf_deallocate(bp); |
@@ -764,43 +760,44 @@ xfs_buf_get_noaddr( | |||
764 | size_t len, | 760 | size_t len, |
765 | xfs_buftarg_t *target) | 761 | xfs_buftarg_t *target) |
766 | { | 762 | { |
767 | size_t malloc_len = len; | 763 | unsigned long page_count = PAGE_ALIGN(len) >> PAGE_SHIFT; |
764 | int error, i; | ||
768 | xfs_buf_t *bp; | 765 | xfs_buf_t *bp; |
769 | void *data; | ||
770 | int error; | ||
771 | 766 | ||
772 | bp = xfs_buf_allocate(0); | 767 | bp = xfs_buf_allocate(0); |
773 | if (unlikely(bp == NULL)) | 768 | if (unlikely(bp == NULL)) |
774 | goto fail; | 769 | goto fail; |
775 | _xfs_buf_initialize(bp, target, 0, len, 0); | 770 | _xfs_buf_initialize(bp, target, 0, len, 0); |
776 | 771 | ||
777 | try_again: | 772 | error = _xfs_buf_get_pages(bp, page_count, 0); |
778 | data = kmem_alloc(malloc_len, KM_SLEEP | KM_MAYFAIL | KM_LARGE); | 773 | if (error) |
779 | if (unlikely(data == NULL)) | ||
780 | goto fail_free_buf; | 774 | goto fail_free_buf; |
781 | 775 | ||
782 | /* check whether alignment matches.. */ | 776 | for (i = 0; i < page_count; i++) { |
783 | if ((__psunsigned_t)data != | 777 | bp->b_pages[i] = alloc_page(GFP_KERNEL); |
784 | ((__psunsigned_t)data & ~target->bt_smask)) { | 778 | if (!bp->b_pages[i]) |
785 | /* .. else double the size and try again */ | 779 | goto fail_free_mem; |
786 | kmem_free(data, malloc_len); | ||
787 | malloc_len <<= 1; | ||
788 | goto try_again; | ||
789 | } | 780 | } |
781 | bp->b_flags |= _XBF_PAGES; | ||
790 | 782 | ||
791 | error = xfs_buf_associate_memory(bp, data, len); | 783 | error = _xfs_buf_map_pages(bp, XBF_MAPPED); |
792 | if (error) | 784 | if (unlikely(error)) { |
785 | printk(KERN_WARNING "%s: failed to map pages\n", | ||
786 | __FUNCTION__); | ||
793 | goto fail_free_mem; | 787 | goto fail_free_mem; |
794 | bp->b_flags |= _XBF_KMEM_ALLOC; | 788 | } |
795 | 789 | ||
796 | xfs_buf_unlock(bp); | 790 | xfs_buf_unlock(bp); |
797 | 791 | ||
798 | XB_TRACE(bp, "no_daddr", data); | 792 | XB_TRACE(bp, "no_daddr", len); |
799 | return bp; | 793 | return bp; |
794 | |||
800 | fail_free_mem: | 795 | fail_free_mem: |
801 | kmem_free(data, malloc_len); | 796 | while (--i >= 0) |
797 | __free_page(bp->b_pages[i]); | ||
798 | _xfs_buf_free_pages(bp); | ||
802 | fail_free_buf: | 799 | fail_free_buf: |
803 | xfs_buf_free(bp); | 800 | xfs_buf_deallocate(bp); |
804 | fail: | 801 | fail: |
805 | return NULL; | 802 | return NULL; |
806 | } | 803 | } |
@@ -1453,6 +1450,7 @@ xfs_free_buftarg( | |||
1453 | int external) | 1450 | int external) |
1454 | { | 1451 | { |
1455 | xfs_flush_buftarg(btp, 1); | 1452 | xfs_flush_buftarg(btp, 1); |
1453 | xfs_blkdev_issue_flush(btp); | ||
1456 | if (external) | 1454 | if (external) |
1457 | xfs_blkdev_put(btp->bt_bdev); | 1455 | xfs_blkdev_put(btp->bt_bdev); |
1458 | xfs_free_bufhash(btp); | 1456 | xfs_free_bufhash(btp); |
@@ -1837,14 +1835,9 @@ xfs_buf_init(void) | |||
1837 | if (!xfsdatad_workqueue) | 1835 | if (!xfsdatad_workqueue) |
1838 | goto out_destroy_xfslogd_workqueue; | 1836 | goto out_destroy_xfslogd_workqueue; |
1839 | 1837 | ||
1840 | xfs_buf_shake = kmem_shake_register(xfsbufd_wakeup); | 1838 | register_shrinker(&xfs_buf_shake); |
1841 | if (!xfs_buf_shake) | ||
1842 | goto out_destroy_xfsdatad_workqueue; | ||
1843 | |||
1844 | return 0; | 1839 | return 0; |
1845 | 1840 | ||
1846 | out_destroy_xfsdatad_workqueue: | ||
1847 | destroy_workqueue(xfsdatad_workqueue); | ||
1848 | out_destroy_xfslogd_workqueue: | 1841 | out_destroy_xfslogd_workqueue: |
1849 | destroy_workqueue(xfslogd_workqueue); | 1842 | destroy_workqueue(xfslogd_workqueue); |
1850 | out_free_buf_zone: | 1843 | out_free_buf_zone: |
@@ -1859,7 +1852,7 @@ xfs_buf_init(void) | |||
1859 | void | 1852 | void |
1860 | xfs_buf_terminate(void) | 1853 | xfs_buf_terminate(void) |
1861 | { | 1854 | { |
1862 | kmem_shake_deregister(xfs_buf_shake); | 1855 | unregister_shrinker(&xfs_buf_shake); |
1863 | destroy_workqueue(xfsdatad_workqueue); | 1856 | destroy_workqueue(xfsdatad_workqueue); |
1864 | destroy_workqueue(xfslogd_workqueue); | 1857 | destroy_workqueue(xfslogd_workqueue); |
1865 | kmem_zone_destroy(xfs_buf_zone); | 1858 | kmem_zone_destroy(xfs_buf_zone); |