diff options
-rw-r--r-- | fs/cifs/cifsproto.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 67 | ||||
-rw-r--r-- | fs/cifs/file.c | 68 |
3 files changed, 74 insertions, 63 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index d57cdf4e2033..f309b43848fb 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -472,6 +472,8 @@ struct cifs_readdata { | |||
472 | int result; | 472 | int result; |
473 | struct list_head pages; | 473 | struct list_head pages; |
474 | struct work_struct work; | 474 | struct work_struct work; |
475 | int (*marshal_iov) (struct cifs_readdata *rdata, | ||
476 | unsigned int remaining); | ||
475 | unsigned int nr_iov; | 477 | unsigned int nr_iov; |
476 | struct kvec iov[1]; | 478 | struct kvec iov[1]; |
477 | }; | 479 | }; |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index d263f98aab91..3aa1fcc15156 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -1436,13 +1436,10 @@ static int | |||
1436 | cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | 1436 | cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) |
1437 | { | 1437 | { |
1438 | int length, len; | 1438 | int length, len; |
1439 | unsigned int data_offset, remaining, data_len; | 1439 | unsigned int data_offset, data_len; |
1440 | struct cifs_readdata *rdata = mid->callback_data; | 1440 | struct cifs_readdata *rdata = mid->callback_data; |
1441 | char *buf = server->smallbuf; | 1441 | char *buf = server->smallbuf; |
1442 | unsigned int buflen = get_rfc1002_length(buf) + 4; | 1442 | unsigned int buflen = get_rfc1002_length(buf) + 4; |
1443 | u64 eof; | ||
1444 | pgoff_t eof_index; | ||
1445 | struct page *page, *tpage; | ||
1446 | 1443 | ||
1447 | cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__, | 1444 | cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__, |
1448 | mid->mid, rdata->offset, rdata->bytes); | 1445 | mid->mid, rdata->offset, rdata->bytes); |
@@ -1525,64 +1522,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1525 | } | 1522 | } |
1526 | 1523 | ||
1527 | /* marshal up the page array */ | 1524 | /* marshal up the page array */ |
1528 | len = 0; | 1525 | len = rdata->marshal_iov(rdata, data_len); |
1529 | remaining = data_len; | 1526 | data_len -= len; |
1530 | rdata->nr_iov = 1; | ||
1531 | |||
1532 | /* determine the eof that the server (probably) has */ | ||
1533 | eof = CIFS_I(rdata->mapping->host)->server_eof; | ||
1534 | eof_index = eof ? (eof - 1) >> PAGE_CACHE_SHIFT : 0; | ||
1535 | cFYI(1, "eof=%llu eof_index=%lu", eof, eof_index); | ||
1536 | |||
1537 | list_for_each_entry_safe(page, tpage, &rdata->pages, lru) { | ||
1538 | if (remaining >= PAGE_CACHE_SIZE) { | ||
1539 | /* enough data to fill the page */ | ||
1540 | rdata->iov[rdata->nr_iov].iov_base = kmap(page); | ||
1541 | rdata->iov[rdata->nr_iov].iov_len = PAGE_CACHE_SIZE; | ||
1542 | cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu", | ||
1543 | rdata->nr_iov, page->index, | ||
1544 | rdata->iov[rdata->nr_iov].iov_base, | ||
1545 | rdata->iov[rdata->nr_iov].iov_len); | ||
1546 | ++rdata->nr_iov; | ||
1547 | len += PAGE_CACHE_SIZE; | ||
1548 | remaining -= PAGE_CACHE_SIZE; | ||
1549 | } else if (remaining > 0) { | ||
1550 | /* enough for partial page, fill and zero the rest */ | ||
1551 | rdata->iov[rdata->nr_iov].iov_base = kmap(page); | ||
1552 | rdata->iov[rdata->nr_iov].iov_len = remaining; | ||
1553 | cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu", | ||
1554 | rdata->nr_iov, page->index, | ||
1555 | rdata->iov[rdata->nr_iov].iov_base, | ||
1556 | rdata->iov[rdata->nr_iov].iov_len); | ||
1557 | memset(rdata->iov[rdata->nr_iov].iov_base + remaining, | ||
1558 | '\0', PAGE_CACHE_SIZE - remaining); | ||
1559 | ++rdata->nr_iov; | ||
1560 | len += remaining; | ||
1561 | remaining = 0; | ||
1562 | } else if (page->index > eof_index) { | ||
1563 | /* | ||
1564 | * The VFS will not try to do readahead past the | ||
1565 | * i_size, but it's possible that we have outstanding | ||
1566 | * writes with gaps in the middle and the i_size hasn't | ||
1567 | * caught up yet. Populate those with zeroed out pages | ||
1568 | * to prevent the VFS from repeatedly attempting to | ||
1569 | * fill them until the writes are flushed. | ||
1570 | */ | ||
1571 | zero_user(page, 0, PAGE_CACHE_SIZE); | ||
1572 | list_del(&page->lru); | ||
1573 | lru_cache_add_file(page); | ||
1574 | flush_dcache_page(page); | ||
1575 | SetPageUptodate(page); | ||
1576 | unlock_page(page); | ||
1577 | page_cache_release(page); | ||
1578 | } else { | ||
1579 | /* no need to hold page hostage */ | ||
1580 | list_del(&page->lru); | ||
1581 | lru_cache_add_file(page); | ||
1582 | unlock_page(page); | ||
1583 | page_cache_release(page); | ||
1584 | } | ||
1585 | } | ||
1586 | 1527 | ||
1587 | /* issue the read if we have any iovecs left to fill */ | 1528 | /* issue the read if we have any iovecs left to fill */ |
1588 | if (rdata->nr_iov > 1) { | 1529 | if (rdata->nr_iov > 1) { |
@@ -1598,7 +1539,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1598 | rdata->bytes = length; | 1539 | rdata->bytes = length; |
1599 | 1540 | ||
1600 | cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read, | 1541 | cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read, |
1601 | buflen, remaining); | 1542 | buflen, data_len); |
1602 | 1543 | ||
1603 | /* discard anything left over */ | 1544 | /* discard anything left over */ |
1604 | if (server->total_read < buflen) | 1545 | if (server->total_read < buflen) |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index d210288e4a47..183381d9c4c1 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -2654,6 +2654,73 @@ cifs_readv_complete(struct work_struct *work) | |||
2654 | cifs_readdata_free(rdata); | 2654 | cifs_readdata_free(rdata); |
2655 | } | 2655 | } |
2656 | 2656 | ||
2657 | static int | ||
2658 | cifs_readpages_marshal_iov(struct cifs_readdata *rdata, unsigned int remaining) | ||
2659 | { | ||
2660 | int len = 0; | ||
2661 | struct page *page, *tpage; | ||
2662 | u64 eof; | ||
2663 | pgoff_t eof_index; | ||
2664 | |||
2665 | /* determine the eof that the server (probably) has */ | ||
2666 | eof = CIFS_I(rdata->mapping->host)->server_eof; | ||
2667 | eof_index = eof ? (eof - 1) >> PAGE_CACHE_SHIFT : 0; | ||
2668 | cFYI(1, "eof=%llu eof_index=%lu", eof, eof_index); | ||
2669 | |||
2670 | rdata->nr_iov = 1; | ||
2671 | list_for_each_entry_safe(page, tpage, &rdata->pages, lru) { | ||
2672 | if (remaining >= PAGE_CACHE_SIZE) { | ||
2673 | /* enough data to fill the page */ | ||
2674 | rdata->iov[rdata->nr_iov].iov_base = kmap(page); | ||
2675 | rdata->iov[rdata->nr_iov].iov_len = PAGE_CACHE_SIZE; | ||
2676 | cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu", | ||
2677 | rdata->nr_iov, page->index, | ||
2678 | rdata->iov[rdata->nr_iov].iov_base, | ||
2679 | rdata->iov[rdata->nr_iov].iov_len); | ||
2680 | ++rdata->nr_iov; | ||
2681 | len += PAGE_CACHE_SIZE; | ||
2682 | remaining -= PAGE_CACHE_SIZE; | ||
2683 | } else if (remaining > 0) { | ||
2684 | /* enough for partial page, fill and zero the rest */ | ||
2685 | rdata->iov[rdata->nr_iov].iov_base = kmap(page); | ||
2686 | rdata->iov[rdata->nr_iov].iov_len = remaining; | ||
2687 | cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu", | ||
2688 | rdata->nr_iov, page->index, | ||
2689 | rdata->iov[rdata->nr_iov].iov_base, | ||
2690 | rdata->iov[rdata->nr_iov].iov_len); | ||
2691 | memset(rdata->iov[rdata->nr_iov].iov_base + remaining, | ||
2692 | '\0', PAGE_CACHE_SIZE - remaining); | ||
2693 | ++rdata->nr_iov; | ||
2694 | len += remaining; | ||
2695 | remaining = 0; | ||
2696 | } else if (page->index > eof_index) { | ||
2697 | /* | ||
2698 | * The VFS will not try to do readahead past the | ||
2699 | * i_size, but it's possible that we have outstanding | ||
2700 | * writes with gaps in the middle and the i_size hasn't | ||
2701 | * caught up yet. Populate those with zeroed out pages | ||
2702 | * to prevent the VFS from repeatedly attempting to | ||
2703 | * fill them until the writes are flushed. | ||
2704 | */ | ||
2705 | zero_user(page, 0, PAGE_CACHE_SIZE); | ||
2706 | list_del(&page->lru); | ||
2707 | lru_cache_add_file(page); | ||
2708 | flush_dcache_page(page); | ||
2709 | SetPageUptodate(page); | ||
2710 | unlock_page(page); | ||
2711 | page_cache_release(page); | ||
2712 | } else { | ||
2713 | /* no need to hold page hostage */ | ||
2714 | list_del(&page->lru); | ||
2715 | lru_cache_add_file(page); | ||
2716 | unlock_page(page); | ||
2717 | page_cache_release(page); | ||
2718 | } | ||
2719 | } | ||
2720 | |||
2721 | return len; | ||
2722 | } | ||
2723 | |||
2657 | static int cifs_readpages(struct file *file, struct address_space *mapping, | 2724 | static int cifs_readpages(struct file *file, struct address_space *mapping, |
2658 | struct list_head *page_list, unsigned num_pages) | 2725 | struct list_head *page_list, unsigned num_pages) |
2659 | { | 2726 | { |
@@ -2777,6 +2844,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
2777 | rdata->offset = offset; | 2844 | rdata->offset = offset; |
2778 | rdata->bytes = bytes; | 2845 | rdata->bytes = bytes; |
2779 | rdata->pid = pid; | 2846 | rdata->pid = pid; |
2847 | rdata->marshal_iov = cifs_readpages_marshal_iov; | ||
2780 | list_splice_init(&tmplist, &rdata->pages); | 2848 | list_splice_init(&tmplist, &rdata->pages); |
2781 | 2849 | ||
2782 | do { | 2850 | do { |