aboutsummaryrefslogtreecommitdiffstats
path: root/fs/buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/buffer.c')
-rw-r--r--fs/buffer.c114
1 files changed, 0 insertions, 114 deletions
diff --git a/fs/buffer.c b/fs/buffer.c
index 249b83fafe48..cabc045f483d 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -3427,120 +3427,6 @@ int bh_submit_read(struct buffer_head *bh)
3427} 3427}
3428EXPORT_SYMBOL(bh_submit_read); 3428EXPORT_SYMBOL(bh_submit_read);
3429 3429
3430/*
3431 * Seek for SEEK_DATA / SEEK_HOLE within @page, starting at @lastoff.
3432 *
3433 * Returns the offset within the file on success, and -ENOENT otherwise.
3434 */
3435static loff_t
3436page_seek_hole_data(struct page *page, loff_t lastoff, int whence)
3437{
3438 loff_t offset = page_offset(page);
3439 struct buffer_head *bh, *head;
3440 bool seek_data = whence == SEEK_DATA;
3441
3442 if (lastoff < offset)
3443 lastoff = offset;
3444
3445 bh = head = page_buffers(page);
3446 do {
3447 offset += bh->b_size;
3448 if (lastoff >= offset)
3449 continue;
3450
3451 /*
3452 * Unwritten extents that have data in the page cache covering
3453 * them can be identified by the BH_Unwritten state flag.
3454 * Pages with multiple buffers might have a mix of holes, data
3455 * and unwritten extents - any buffer with valid data in it
3456 * should have BH_Uptodate flag set on it.
3457 */
3458
3459 if ((buffer_unwritten(bh) || buffer_uptodate(bh)) == seek_data)
3460 return lastoff;
3461
3462 lastoff = offset;
3463 } while ((bh = bh->b_this_page) != head);
3464 return -ENOENT;
3465}
3466
3467/*
3468 * Seek for SEEK_DATA / SEEK_HOLE in the page cache.
3469 *
3470 * Within unwritten extents, the page cache determines which parts are holes
3471 * and which are data: unwritten and uptodate buffer heads count as data;
3472 * everything else counts as a hole.
3473 *
3474 * Returns the resulting offset on successs, and -ENOENT otherwise.
3475 */
3476loff_t
3477page_cache_seek_hole_data(struct inode *inode, loff_t offset, loff_t length,
3478 int whence)
3479{
3480 pgoff_t index = offset >> PAGE_SHIFT;
3481 pgoff_t end = DIV_ROUND_UP(offset + length, PAGE_SIZE);
3482 loff_t lastoff = offset;
3483 struct pagevec pvec;
3484
3485 if (length <= 0)
3486 return -ENOENT;
3487
3488 pagevec_init(&pvec);
3489
3490 do {
3491 unsigned nr_pages, i;
3492
3493 nr_pages = pagevec_lookup_range(&pvec, inode->i_mapping, &index,
3494 end - 1);
3495 if (nr_pages == 0)
3496 break;
3497
3498 for (i = 0; i < nr_pages; i++) {
3499 struct page *page = pvec.pages[i];
3500
3501 /*
3502 * At this point, the page may be truncated or
3503 * invalidated (changing page->mapping to NULL), or
3504 * even swizzled back from swapper_space to tmpfs file
3505 * mapping. However, page->index will not change
3506 * because we have a reference on the page.
3507 *
3508 * If current page offset is beyond where we've ended,
3509 * we've found a hole.
3510 */
3511 if (whence == SEEK_HOLE &&
3512 lastoff < page_offset(page))
3513 goto check_range;
3514
3515 lock_page(page);
3516 if (likely(page->mapping == inode->i_mapping) &&
3517 page_has_buffers(page)) {
3518 lastoff = page_seek_hole_data(page, lastoff, whence);
3519 if (lastoff >= 0) {
3520 unlock_page(page);
3521 goto check_range;
3522 }
3523 }
3524 unlock_page(page);
3525 lastoff = page_offset(page) + PAGE_SIZE;
3526 }
3527 pagevec_release(&pvec);
3528 } while (index < end);
3529
3530 /* When no page at lastoff and we are not done, we found a hole. */
3531 if (whence != SEEK_HOLE)
3532 goto not_found;
3533
3534check_range:
3535 if (lastoff < offset + length)
3536 goto out;
3537not_found:
3538 lastoff = -ENOENT;
3539out:
3540 pagevec_release(&pvec);
3541 return lastoff;
3542}
3543
3544void __init buffer_init(void) 3430void __init buffer_init(void)
3545{ 3431{
3546 unsigned long nrpages; 3432 unsigned long nrpages;