diff options
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_buf.c | 341 | ||||
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_buf.h | 40 |
2 files changed, 84 insertions, 297 deletions
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index a5a260fab824..d45b2cdee6c4 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c | |||
| @@ -94,75 +94,6 @@ xfs_buf_vmap_len( | |||
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | /* | 96 | /* |
| 97 | * Page Region interfaces. | ||
| 98 | * | ||
| 99 | * For pages in filesystems where the blocksize is smaller than the | ||
| 100 | * pagesize, we use the page->private field (long) to hold a bitmap | ||
| 101 | * of uptodate regions within the page. | ||
| 102 | * | ||
| 103 | * Each such region is "bytes per page / bits per long" bytes long. | ||
| 104 | * | ||
| 105 | * NBPPR == number-of-bytes-per-page-region | ||
| 106 | * BTOPR == bytes-to-page-region (rounded up) | ||
| 107 | * BTOPRT == bytes-to-page-region-truncated (rounded down) | ||
| 108 | */ | ||
| 109 | #if (BITS_PER_LONG == 32) | ||
| 110 | #define PRSHIFT (PAGE_CACHE_SHIFT - 5) /* (32 == 1<<5) */ | ||
| 111 | #elif (BITS_PER_LONG == 64) | ||
| 112 | #define PRSHIFT (PAGE_CACHE_SHIFT - 6) /* (64 == 1<<6) */ | ||
| 113 | #else | ||
| 114 | #error BITS_PER_LONG must be 32 or 64 | ||
| 115 | #endif | ||
| 116 | #define NBPPR (PAGE_CACHE_SIZE/BITS_PER_LONG) | ||
| 117 | #define BTOPR(b) (((unsigned int)(b) + (NBPPR - 1)) >> PRSHIFT) | ||
| 118 | #define BTOPRT(b) (((unsigned int)(b) >> PRSHIFT)) | ||
| 119 | |||
| 120 | STATIC unsigned long | ||
| 121 | page_region_mask( | ||
| 122 | size_t offset, | ||
| 123 | size_t length) | ||
| 124 | { | ||
| 125 | unsigned long mask; | ||
| 126 | int first, final; | ||
| 127 | |||
| 128 | first = BTOPR(offset); | ||
| 129 | final = BTOPRT(offset + length - 1); | ||
| 130 | first = min(first, final); | ||
| 131 | |||
| 132 | mask = ~0UL; | ||
| 133 | mask <<= BITS_PER_LONG - (final - first); | ||
| 134 | mask >>= BITS_PER_LONG - (final); | ||
| 135 | |||
| 136 | ASSERT(offset + length <= PAGE_CACHE_SIZE); | ||
| 137 | ASSERT((final - first) < BITS_PER_LONG && (final - first) >= 0); | ||
| 138 | |||
| 139 | return mask; | ||
| 140 | } | ||
| 141 | |||
| 142 | STATIC void | ||
| 143 | set_page_region( | ||
| 144 | struct page *page, | ||
| 145 | size_t offset, | ||
| 146 | size_t length) | ||
| 147 | { | ||
| 148 | set_page_private(page, | ||
| 149 | page_private(page) | page_region_mask(offset, length)); | ||
| 150 | if (page_private(page) == ~0UL) | ||
| 151 | SetPageUptodate(page); | ||
| 152 | } | ||
| 153 | |||
| 154 | STATIC int | ||
| 155 | test_page_region( | ||
| 156 | struct page *page, | ||
| 157 | size_t offset, | ||
| 158 | size_t length) | ||
| 159 | { | ||
| 160 | unsigned long mask = page_region_mask(offset, length); | ||
| 161 | |||
| 162 | return (mask && (page_private(page) & mask) == mask); | ||
| 163 | } | ||
| 164 | |||
| 165 | /* | ||
| 166 | * xfs_buf_lru_add - add a buffer to the LRU. | 97 | * xfs_buf_lru_add - add a buffer to the LRU. |
| 167 | * | 98 | * |
| 168 | * The LRU takes a new reference to the buffer so that it will only be freed | 99 | * The LRU takes a new reference to the buffer so that it will only be freed |
| @@ -332,7 +263,7 @@ xfs_buf_free( | |||
| 332 | 263 | ||
| 333 | ASSERT(list_empty(&bp->b_lru)); | 264 | ASSERT(list_empty(&bp->b_lru)); |
| 334 | 265 | ||
| 335 | if (bp->b_flags & (_XBF_PAGE_CACHE|_XBF_PAGES)) { | 266 | if (bp->b_flags & _XBF_PAGES) { |
| 336 | uint i; | 267 | uint i; |
| 337 | 268 | ||
| 338 | if (xfs_buf_is_vmapped(bp)) | 269 | if (xfs_buf_is_vmapped(bp)) |
| @@ -342,25 +273,22 @@ xfs_buf_free( | |||
| 342 | for (i = 0; i < bp->b_page_count; i++) { | 273 | for (i = 0; i < bp->b_page_count; i++) { |
| 343 | struct page *page = bp->b_pages[i]; | 274 | struct page *page = bp->b_pages[i]; |
| 344 | 275 | ||
| 345 | if (bp->b_flags & _XBF_PAGE_CACHE) | 276 | __free_page(page); |
| 346 | ASSERT(!PagePrivate(page)); | ||
| 347 | page_cache_release(page); | ||
| 348 | } | 277 | } |
| 349 | } | 278 | } else if (bp->b_flags & _XBF_KMEM) |
| 279 | kmem_free(bp->b_addr); | ||
| 350 | _xfs_buf_free_pages(bp); | 280 | _xfs_buf_free_pages(bp); |
| 351 | xfs_buf_deallocate(bp); | 281 | xfs_buf_deallocate(bp); |
| 352 | } | 282 | } |
| 353 | 283 | ||
| 354 | /* | 284 | /* |
| 355 | * Finds all pages for buffer in question and builds it's page list. | 285 | * Allocates all the pages for buffer in question and builds it's page list. |
| 356 | */ | 286 | */ |
| 357 | STATIC int | 287 | STATIC int |
| 358 | _xfs_buf_lookup_pages( | 288 | xfs_buf_allocate_memory( |
| 359 | xfs_buf_t *bp, | 289 | xfs_buf_t *bp, |
| 360 | uint flags) | 290 | uint flags) |
| 361 | { | 291 | { |
| 362 | struct address_space *mapping = bp->b_target->bt_mapping; | ||
| 363 | size_t blocksize = bp->b_target->bt_bsize; | ||
| 364 | size_t size = bp->b_count_desired; | 292 | size_t size = bp->b_count_desired; |
| 365 | size_t nbytes, offset; | 293 | size_t nbytes, offset; |
| 366 | gfp_t gfp_mask = xb_to_gfp(flags); | 294 | gfp_t gfp_mask = xb_to_gfp(flags); |
| @@ -369,29 +297,55 @@ _xfs_buf_lookup_pages( | |||
| 369 | xfs_off_t end; | 297 | xfs_off_t end; |
| 370 | int error; | 298 | int error; |
| 371 | 299 | ||
| 300 | /* | ||
| 301 | * for buffers that are contained within a single page, just allocate | ||
| 302 | * the memory from the heap - there's no need for the complexity of | ||
| 303 | * page arrays to keep allocation down to order 0. | ||
| 304 | */ | ||
| 305 | if (bp->b_buffer_length < PAGE_SIZE) { | ||
| 306 | bp->b_addr = kmem_alloc(bp->b_buffer_length, xb_to_km(flags)); | ||
| 307 | if (!bp->b_addr) { | ||
| 308 | /* low memory - use alloc_page loop instead */ | ||
| 309 | goto use_alloc_page; | ||
| 310 | } | ||
| 311 | |||
| 312 | if (((unsigned long)(bp->b_addr + bp->b_buffer_length - 1) & | ||
| 313 | PAGE_MASK) != | ||
| 314 | ((unsigned long)bp->b_addr & PAGE_MASK)) { | ||
| 315 | /* b_addr spans two pages - use alloc_page instead */ | ||
| 316 | kmem_free(bp->b_addr); | ||
| 317 | bp->b_addr = NULL; | ||
| 318 | goto use_alloc_page; | ||
| 319 | } | ||
| 320 | bp->b_offset = offset_in_page(bp->b_addr); | ||
| 321 | bp->b_pages = bp->b_page_array; | ||
| 322 | bp->b_pages[0] = virt_to_page(bp->b_addr); | ||
| 323 | bp->b_page_count = 1; | ||
| 324 | bp->b_flags |= XBF_MAPPED | _XBF_KMEM; | ||
| 325 | return 0; | ||
| 326 | } | ||
| 327 | |||
| 328 | use_alloc_page: | ||
| 372 | end = bp->b_file_offset + bp->b_buffer_length; | 329 | end = bp->b_file_offset + bp->b_buffer_length; |
| 373 | page_count = xfs_buf_btoc(end) - xfs_buf_btoct(bp->b_file_offset); | 330 | page_count = xfs_buf_btoc(end) - xfs_buf_btoct(bp->b_file_offset); |
| 374 | |||
| 375 | error = _xfs_buf_get_pages(bp, page_count, flags); | 331 | error = _xfs_buf_get_pages(bp, page_count, flags); |
| 376 | if (unlikely(error)) | 332 | if (unlikely(error)) |
| 377 | return error; | 333 | return error; |
| 378 | bp->b_flags |= _XBF_PAGE_CACHE; | ||
| 379 | 334 | ||
| 380 | offset = bp->b_offset; | 335 | offset = bp->b_offset; |
| 381 | first = bp->b_file_offset >> PAGE_CACHE_SHIFT; | 336 | first = bp->b_file_offset >> PAGE_SHIFT; |
| 337 | bp->b_flags |= _XBF_PAGES; | ||
| 382 | 338 | ||
| 383 | for (i = 0; i < bp->b_page_count; i++) { | 339 | for (i = 0; i < bp->b_page_count; i++) { |
| 384 | struct page *page; | 340 | struct page *page; |
| 385 | uint retries = 0; | 341 | uint retries = 0; |
| 386 | 342 | retry: | |
| 387 | retry: | 343 | page = alloc_page(gfp_mask); |
| 388 | page = find_or_create_page(mapping, first + i, gfp_mask); | ||
| 389 | if (unlikely(page == NULL)) { | 344 | if (unlikely(page == NULL)) { |
| 390 | if (flags & XBF_READ_AHEAD) { | 345 | if (flags & XBF_READ_AHEAD) { |
| 391 | bp->b_page_count = i; | 346 | bp->b_page_count = i; |
| 392 | for (i = 0; i < bp->b_page_count; i++) | 347 | error = ENOMEM; |
| 393 | unlock_page(bp->b_pages[i]); | 348 | goto out_free_pages; |
| 394 | return -ENOMEM; | ||
| 395 | } | ||
