aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'fs/squashfs/file.c')
-rw-r--r--fs/squashfs/file.c140
1 files changed, 105 insertions, 35 deletions
diff --git a/fs/squashfs/file.c b/fs/squashfs/file.c
index e5c9689062ba..6f5ef8d7e55a 100644
--- a/fs/squashfs/file.c
+++ b/fs/squashfs/file.c
@@ -47,12 +47,16 @@
47#include <linux/string.h> 47#include <linux/string.h>
48#include <linux/pagemap.h> 48#include <linux/pagemap.h>
49#include <linux/mutex.h> 49#include <linux/mutex.h>
50#include <linux/mm_inline.h>
50 51
51#include "squashfs_fs.h" 52#include "squashfs_fs.h"
52#include "squashfs_fs_sb.h" 53#include "squashfs_fs_sb.h"
53#include "squashfs_fs_i.h" 54#include "squashfs_fs_i.h"
54#include "squashfs.h" 55#include "squashfs.h"
55 56
57// Backported from 4.5
58#define lru_to_page(head) (list_entry((head)->prev, struct page, lru))
59
56/* 60/*
57 * Locate cache slot in range [offset, index] for specified inode. If 61 * Locate cache slot in range [offset, index] for specified inode. If
58 * there's more than one return the slot closest to index. 62 * there's more than one return the slot closest to index.
@@ -438,6 +442,21 @@ static int squashfs_readpage_fragment(struct page *page)
438 return res; 442 return res;
439} 443}
440 444
445static int squashfs_readpages_fragment(struct page *page,
446 struct list_head *readahead_pages, struct address_space *mapping)
447{
448 if (!page) {
449 page = lru_to_page(readahead_pages);
450 list_del(&page->lru);
451 if (add_to_page_cache_lru(page, mapping, page->index,
452 mapping_gfp_constraint(mapping, GFP_KERNEL))) {
453 put_page(page);
454 return 0;
455 }
456 }
457 return squashfs_readpage_fragment(page);
458}
459
441static int squashfs_readpage_sparse(struct page *page, int index, int file_end) 460static int squashfs_readpage_sparse(struct page *page, int index, int file_end)
442{ 461{
443 struct inode *inode = page->mapping->host; 462 struct inode *inode = page->mapping->host;
@@ -450,54 +469,105 @@ static int squashfs_readpage_sparse(struct page *page, int index, int file_end)
450 return 0; 469 return 0;
451} 470}
452 471
453static int squashfs_readpage(struct file *file, struct page *page) 472static int squashfs_readpages_sparse(struct page *page,
473 struct list_head *readahead_pages, int index, int file_end,
474 struct address_space *mapping)
454{ 475{
455 struct inode *inode = page->mapping->host; 476 if (!page) {
477 page = lru_to_page(readahead_pages);
478 list_del(&page->lru);
479 if (add_to_page_cache_lru(page, mapping, page->index,
480 mapping_gfp_constraint(mapping, GFP_KERNEL))) {
481 put_page(page);
482 return 0;
483 }
484 }
485 return squashfs_readpage_sparse(page, index, file_end);
486}
487
488static int __squashfs_readpages(struct file *file, struct page *page,
489 struct list_head *readahead_pages, unsigned int nr_pages,
490 struct address_space *mapping)
491{
492 struct inode *inode = mapping->host;
456 struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; 493 struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
457 int index = page->index >> (msblk->block_log - PAGE_CACHE_SHIFT);
458 int file_end = i_size_read(inode) >> msblk->block_log; 494 int file_end = i_size_read(inode) >> msblk->block_log;
459 int res; 495 int res;
460 void *pageaddr;
461 496
462 TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n", 497 do {
463 page->index, squashfs_i(inode)->start); 498 struct page *cur_page = page ? page
499 : lru_to_page(readahead_pages);
500 int page_index = cur_page->index;
501 int index = page_index >> (msblk->block_log - PAGE_CACHE_SHIFT);
502
503 if (page_index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
504 PAGE_CACHE_SHIFT))
505 return 1;
506
507 if (index < file_end || squashfs_i(inode)->fragment_block ==
508 SQUASHFS_INVALID_BLK) {
509 u64 block = 0;
510 int bsize = read_blocklist(inode, index, &block);
511
512 if (bsize < 0)
513 return -1;
514
515 if (bsize == 0) {
516 res = squashfs_readpages_sparse(page,
517 readahead_pages, index, file_end,
518 mapping);
519 } else {
520 res = squashfs_readpages_block(page,
521 readahead_pages, &nr_pages, mapping,
522 page_index, block, bsize);
523 }
524 } else {
525 res = squashfs_readpages_fragment(page,
526 readahead_pages, mapping);
527 }
528 if (res)
529 return 0;
530 page = NULL;
531 } while (readahead_pages && !list_empty(readahead_pages));
464 532
465 if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> 533 return 0;
466 PAGE_CACHE_SHIFT)) 534}
467 goto out;
468 535
469 if (index < file_end || squashfs_i(inode)->fragment_block == 536static int squashfs_readpage(struct file *file, struct page *page)
470 SQUASHFS_INVALID_BLK) { 537{
471 u64 block = 0; 538 int ret;
472 int bsize = read_blocklist(inode, index, &block);
473 if (bsize < 0)
474 goto error_out;
475 539
476 if (bsize == 0) 540 TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
477 res = squashfs_readpage_sparse(page, index, file_end); 541 page->index, squashfs_i(page->mapping->host)->start);
542
543 get_page(page);
544
545 ret = __squashfs_readpages(file, page, NULL, 1, page->mapping);
546 if (ret) {
547 flush_dcache_page(page);
548 if (ret < 0)
549 SetPageError(page);
478 else 550 else
479 res = squashfs_readpage_block(page, block, bsize); 551 SetPageUptodate(page);
480 } else 552 zero_user_segment(page, 0, PAGE_CACHE_SIZE);
481 res = squashfs_readpage_fragment(page); 553 unlock_page(page);
482 554 put_page(page);
483 if (!res) 555 }
484 return 0;
485
486error_out:
487 SetPageError(page);
488out:
489 pageaddr = kmap_atomic(page);
490 memset(pageaddr, 0, PAGE_CACHE_SIZE);
491 kunmap_atomic(pageaddr);
492 flush_dcache_page(page);
493 if (!PageError(page))
494 SetPageUptodate(page);
495 unlock_page(page);
496 556
497 return 0; 557 return 0;
498} 558}
499 559
560static int squashfs_readpages(struct file *file, struct address_space *mapping,
561 struct list_head *pages, unsigned int nr_pages)
562{
563 TRACE("Entered squashfs_readpages, %u pages, first page index %lx\n",
564 nr_pages, lru_to_page(pages)->index);
565 __squashfs_readpages(file, NULL, pages, nr_pages, mapping);
566 return 0;
567}
568
500 569
501const struct address_space_operations squashfs_aops = { 570const struct address_space_operations squashfs_aops = {
502 .readpage = squashfs_readpage 571 .readpage = squashfs_readpage,
572 .readpages = squashfs_readpages,
503}; 573};