Skip to content

Commit 3ca2364

Browse files
committed
mm: Implement readahead_control pageset expansion
Provide a function, readahead_expand(), that expands the set of pages specified by a readahead_control object to encompass a revised area with a proposed size and length. The proposed area must include all of the old area and may be expanded yet more by this function so that the edges align on (transparent huge) page boundaries as allocated. The expansion will be cut short if a page already exists in either of the areas being expanded into. Note that any expansion made in such a case is not rolled back. This will be used by fscache so that reads can be expanded to cache granule boundaries, thereby allowing whole granules to be stored in the cache, but there are other potential users also. Changes: v6: - Fold in a patch from Matthew Wilcox to tell the ondemand readahead algorithm about the expansion so that the next readahead starts at the right place[2]. v4: - Moved the declaration of readahead_expand() to a better place[1]. Suggested-by: Matthew Wilcox (Oracle) <willy@infradead.org> Signed-off-by: David Howells <dhowells@redhat.com> Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org> Tested-by: Jeff Layton <jlayton@kernel.org> Tested-by: Dave Wysochanski <dwysocha@redhat.com> Tested-By: Marc Dionne <marc.dionne@auristor.com> cc: Alexander Viro <viro@zeniv.linux.org.uk> cc: Christoph Hellwig <hch@lst.de> cc: Mike Marshall <hubcap@omnibond.com> cc: linux-mm@kvack.org cc: linux-cachefs@redhat.com cc: linux-afs@lists.infradead.org cc: linux-nfs@vger.kernel.org cc: linux-cifs@vger.kernel.org cc: ceph-devel@vger.kernel.org cc: v9fs-developer@lists.sourceforge.net cc: linux-fsdevel@vger.kernel.org Link: https://lore.kernel.org/r/20210217161358.GM2858050@casper.infradead.org/ [1] Link: https://lore.kernel.org/r/20210407201857.3582797-4-willy@infradead.org/ [2] Link: https://lore.kernel.org/r/159974633888.2094769.8326206446358128373.stgit@warthog.procyon.org.uk/ Link: https://lore.kernel.org/r/160588479816.3465195.553952688795241765.stgit@warthog.procyon.org.uk/ # rfc Link: https://lore.kernel.org/r/161118131787.1232039.4863969952441067985.stgit@warthog.procyon.org.uk/ # rfc Link: https://lore.kernel.org/r/161161028670.2537118.13831420617039766044.stgit@warthog.procyon.org.uk/ # v2 Link: https://lore.kernel.org/r/161340389201.1303470.14353807284546854878.stgit@warthog.procyon.org.uk/ # v3 Link: https://lore.kernel.org/r/161539530488.286939.18085961677838089157.stgit@warthog.procyon.org.uk/ # v4 Link: https://lore.kernel.org/r/161653789422.2770958.2108046612147345000.stgit@warthog.procyon.org.uk/ # v5 Link: https://lore.kernel.org/r/161789069829.6155.4295672417565512161.stgit@warthog.procyon.org.uk/ # v6
1 parent f615bd5 commit 3ca2364

2 files changed

Lines changed: 77 additions & 0 deletions

File tree

include/linux/pagemap.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,8 @@ void page_cache_ra_unbounded(struct readahead_control *,
839839
void page_cache_sync_ra(struct readahead_control *, unsigned long req_count);
840840
void page_cache_async_ra(struct readahead_control *, struct page *,
841841
unsigned long req_count);
842+
void readahead_expand(struct readahead_control *ractl,
843+
loff_t new_start, size_t new_len);
842844

843845
/**
844846
* page_cache_sync_readahead - generic file readahead

mm/readahead.c

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,3 +638,78 @@ SYSCALL_DEFINE3(readahead, int, fd, loff_t, offset, size_t, count)
638638
{
639639
return ksys_readahead(fd, offset, count);
640640
}
641+
642+
/**
643+
* readahead_expand - Expand a readahead request
644+
* @ractl: The request to be expanded
645+
* @new_start: The revised start
646+
* @new_len: The revised size of the request
647+
*
648+
* Attempt to expand a readahead request outwards from the current size to the
649+
* specified size by inserting locked pages before and after the current window
650+
* to increase the size to the new window. This may involve the insertion of
651+
* THPs, in which case the window may get expanded even beyond what was
652+
* requested.
653+
*
654+
* The algorithm will stop if it encounters a conflicting page already in the
655+
* pagecache and leave a smaller expansion than requested.
656+
*
657+
* The caller must check for this by examining the revised @ractl object for a
658+
* different expansion than was requested.
659+
*/
660+
void readahead_expand(struct readahead_control *ractl,
661+
loff_t new_start, size_t new_len)
662+
{
663+
struct address_space *mapping = ractl->mapping;
664+
struct file_ra_state *ra = ractl->ra;
665+
pgoff_t new_index, new_nr_pages;
666+
gfp_t gfp_mask = readahead_gfp_mask(mapping);
667+
668+
new_index = new_start / PAGE_SIZE;
669+
670+
/* Expand the leading edge downwards */
671+
while (ractl->_index > new_index) {
672+
unsigned long index = ractl->_index - 1;
673+
struct page *page = xa_load(&mapping->i_pages, index);
674+
675+
if (page && !xa_is_value(page))
676+
return; /* Page apparently present */
677+
678+
page = __page_cache_alloc(gfp_mask);
679+
if (!page)
680+
return;
681+
if (add_to_page_cache_lru(page, mapping, index, gfp_mask) < 0) {
682+
put_page(page);
683+
return;
684+
}
685+
686+
ractl->_nr_pages++;
687+
ractl->_index = page->index;
688+
}
689+
690+
new_len += new_start - readahead_pos(ractl);
691+
new_nr_pages = DIV_ROUND_UP(new_len, PAGE_SIZE);
692+
693+
/* Expand the trailing edge upwards */
694+
while (ractl->_nr_pages < new_nr_pages) {
695+
unsigned long index = ractl->_index + ractl->_nr_pages;
696+
struct page *page = xa_load(&mapping->i_pages, index);
697+
698+
if (page && !xa_is_value(page))
699+
return; /* Page apparently present */
700+
701+
page = __page_cache_alloc(gfp_mask);
702+
if (!page)
703+
return;
704+
if (add_to_page_cache_lru(page, mapping, index, gfp_mask) < 0) {
705+
put_page(page);
706+
return;
707+
}
708+
ractl->_nr_pages++;
709+
if (ra) {
710+
ra->size++;
711+
ra->async_size++;
712+
}
713+
}
714+
}
715+
EXPORT_SYMBOL(readahead_expand);

0 commit comments

Comments
 (0)