| From: Ryan Roberts <ryan.roberts@arm.com> |
| Subject: mm/readahead: do not allow order-1 folio |
| Date: Fri, 1 Dec 2023 16:10:45 +0000 |
| |
| The THP machinery does not support order-1 folios because it requires meta |
| data spanning the first 3 `struct page`s. So order-2 is the smallest |
| large folio that we can safely create. |
| |
| There was a theoretical bug whereby if ra->size was 2 or 3 pages (due to |
| the device-specific bdi->ra_pages being set that way), we could end up |
| with order = 1. Fix this by unconditionally checking if the preferred |
| order is 1 and if so, set it to 0. Previously this was done in a few |
| specific places, but with this refactoring it is done just once, |
| unconditionally, at the end of the calculation. |
| |
| This is a theoretical bug found during review of the code; I have no |
| evidence to suggest this manifests in the real world (I expect all |
| device-specific ra_pages values are much bigger than 3). |
| |
| Link: https://lkml.kernel.org/r/20231201161045.3962614-1-ryan.roberts@arm.com |
| Signed-off-by: Ryan Roberts <ryan.roberts@arm.com> |
| Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| --- |
| |
| mm/readahead.c | 14 ++++++-------- |
| 1 file changed, 6 insertions(+), 8 deletions(-) |
| |
| --- a/mm/readahead.c~mm-readahead-do-not-allow-order-1-folio |
| +++ a/mm/readahead.c |
| @@ -511,16 +511,14 @@ void page_cache_ra_order(struct readahea |
| unsigned int order = new_order; |
| |
| /* Align with smaller pages if needed */ |
| - if (index & ((1UL << order) - 1)) { |
| + if (index & ((1UL << order) - 1)) |
| order = __ffs(index); |
| - if (order == 1) |
| - order = 0; |
| - } |
| /* Don't allocate pages past EOF */ |
| - while (index + (1UL << order) - 1 > limit) { |
| - if (--order == 1) |
| - order = 0; |
| - } |
| + while (index + (1UL << order) - 1 > limit) |
| + order--; |
| + /* THP machinery does not support order-1 */ |
| + if (order == 1) |
| + order = 0; |
| err = ra_alloc_folio(ractl, index, mark, order, gfp); |
| if (err) |
| break; |
| _ |