summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/compression.c41
-rw-r--r--fs/btrfs/compression.h2
-rw-r--r--fs/btrfs/inode.c2
-rw-r--r--fs/btrfs/lzo.c6
-rw-r--r--fs/btrfs/zlib.c6
-rw-r--r--fs/btrfs/zstd.c6
6 files changed, 45 insertions, 18 deletions
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
index e897342bece1..c5783ac1b646 100644
--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -180,7 +180,7 @@ static unsigned long btrfs_compr_pool_scan(struct shrinker *sh, struct shrink_co
/*
* Common wrappers for page allocation from compression wrappers
*/
-struct folio *btrfs_alloc_compr_folio(struct btrfs_fs_info *fs_info)
+struct folio *btrfs_alloc_compr_folio(struct btrfs_fs_info *fs_info, gfp_t gfp)
{
struct folio *folio = NULL;
@@ -200,7 +200,7 @@ struct folio *btrfs_alloc_compr_folio(struct btrfs_fs_info *fs_info)
return folio;
alloc:
- return folio_alloc(GFP_NOFS, fs_info->block_min_order);
+ return folio_alloc(gfp, fs_info->block_min_order);
}
void btrfs_free_compr_folio(struct folio *folio)
@@ -368,7 +368,8 @@ struct compressed_bio *btrfs_alloc_compressed_write(struct btrfs_inode *inode,
static noinline int add_ra_bio_pages(struct inode *inode,
u64 compressed_end,
struct compressed_bio *cb,
- int *memstall, unsigned long *pflags)
+ int *memstall, unsigned long *pflags,
+ bool direct_reclaim)
{
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
pgoff_t end_index;
@@ -376,6 +377,7 @@ static noinline int add_ra_bio_pages(struct inode *inode,
u64 cur = cb->orig_bbio->file_offset + orig_bio->bi_iter.bi_size;
u64 isize = i_size_read(inode);
int ret;
+ gfp_t constraint_gfp, cache_gfp;
struct folio *folio;
struct extent_map *em;
struct address_space *mapping = inode->i_mapping;
@@ -405,6 +407,19 @@ static noinline int add_ra_bio_pages(struct inode *inode,
end_index = (i_size_read(inode) - 1) >> PAGE_SHIFT;
+ /*
+ * Avoid direct reclaim when the caller does not allow it. Since
+ * add_ra_bio_pages() is always speculative, suppress allocation warnings
+ * in either case.
+ */
+ if (!direct_reclaim) {
+ constraint_gfp = ~(__GFP_FS | __GFP_DIRECT_RECLAIM) | __GFP_NOWARN;
+ cache_gfp = (GFP_NOFS & ~__GFP_DIRECT_RECLAIM) | __GFP_NOWARN;
+ } else {
+ constraint_gfp = (~__GFP_FS) | __GFP_NOWARN;
+ cache_gfp = GFP_NOFS | __GFP_NOWARN;
+ }
+
while (cur < compressed_end) {
pgoff_t page_end;
pgoff_t pg_index = cur >> PAGE_SHIFT;
@@ -434,12 +449,12 @@ static noinline int add_ra_bio_pages(struct inode *inode,
continue;
}
- folio = filemap_alloc_folio(mapping_gfp_constraint(mapping, ~__GFP_FS),
+ folio = filemap_alloc_folio(mapping_gfp_constraint(mapping, constraint_gfp),
0, NULL);
if (!folio)
break;
- if (filemap_add_folio(mapping, folio, pg_index, GFP_NOFS)) {
+ if (filemap_add_folio(mapping, folio, pg_index, cache_gfp)) {
/* There is already a page, skip to page end */
cur += folio_size(folio);
folio_put(folio);
@@ -532,6 +547,7 @@ void btrfs_submit_compressed_read(struct btrfs_bio *bbio)
unsigned int compressed_len;
const u32 min_folio_size = btrfs_min_folio_size(fs_info);
u64 file_offset = bbio->file_offset;
+ gfp_t gfp;
u64 em_len;
u64 em_start;
struct extent_map *em;
@@ -539,6 +555,17 @@ void btrfs_submit_compressed_read(struct btrfs_bio *bbio)
int memstall = 0;
int ret;
+ /*
+ * If this is a readahead bio, prevent direct reclaim. This is done to
+ * avoid stalling on speculative allocations when memory pressure is
+ * high. The demand fault will retry with GFP_NOFS and enter direct
+ * reclaim if needed.
+ */
+ if (bbio->bio.bi_opf & REQ_RAHEAD)
+ gfp = (GFP_NOFS & ~__GFP_DIRECT_RECLAIM) | __GFP_NOWARN;
+ else
+ gfp = GFP_NOFS;
+
/* we need the actual starting offset of this extent in the file */
read_lock(&em_tree->lock);
em = btrfs_lookup_extent_mapping(em_tree, file_offset, fs_info->sectorsize);
@@ -569,7 +596,7 @@ void btrfs_submit_compressed_read(struct btrfs_bio *bbio)
struct folio *folio;
u32 cur_len = min(compressed_len - i * min_folio_size, min_folio_size);
- folio = btrfs_alloc_compr_folio(fs_info);
+ folio = btrfs_alloc_compr_folio(fs_info, gfp);
if (!folio) {
ret = -ENOMEM;
goto out_free_bio;
@@ -585,7 +612,7 @@ void btrfs_submit_compressed_read(struct btrfs_bio *bbio)
ASSERT(cb->bbio.bio.bi_iter.bi_size == compressed_len);
add_ra_bio_pages(&inode->vfs_inode, em_start + em_len, cb, &memstall,
- &pflags);
+ &pflags, !(bbio->bio.bi_opf & REQ_RAHEAD));
cb->len = bbio->bio.bi_iter.bi_size;
cb->bbio.bio.bi_iter.bi_sector = bbio->bio.bi_iter.bi_sector;
diff --git a/fs/btrfs/compression.h b/fs/btrfs/compression.h
index 973530e9ce6c..1022dc53ec51 100644
--- a/fs/btrfs/compression.h
+++ b/fs/btrfs/compression.h
@@ -98,7 +98,7 @@ void btrfs_submit_compressed_read(struct btrfs_bio *bbio);
int btrfs_compress_str2level(unsigned int type, const char *str, int *level_ret);
-struct folio *btrfs_alloc_compr_folio(struct btrfs_fs_info *fs_info);
+struct folio *btrfs_alloc_compr_folio(struct btrfs_fs_info *fs_info, gfp_t gfp);
void btrfs_free_compr_folio(struct folio *folio);
struct workspace_manager {
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 1a4e6a9239ae..769e96dbe639 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -9980,7 +9980,7 @@ ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from,
size_t bytes = min(min_folio_size, iov_iter_count(from));
char *kaddr;
- folio = btrfs_alloc_compr_folio(fs_info);
+ folio = btrfs_alloc_compr_folio(fs_info, GFP_NOFS);
if (!folio) {
ret = -ENOMEM;
goto out_cb;
diff --git a/fs/btrfs/lzo.c b/fs/btrfs/lzo.c
index 3e62e3e64907..2de18c7b563a 100644
--- a/fs/btrfs/lzo.c
+++ b/fs/btrfs/lzo.c
@@ -202,7 +202,7 @@ static int copy_compressed_data_to_bio(struct btrfs_fs_info *fs_info,
ASSERT((old_size >> sectorsize_bits) == (old_size + LZO_LEN - 1) >> sectorsize_bits);
if (!*out_folio) {
- *out_folio = btrfs_alloc_compr_folio(fs_info);
+ *out_folio = btrfs_alloc_compr_folio(fs_info, GFP_NOFS);
if (!*out_folio)
return -ENOMEM;
}
@@ -229,7 +229,7 @@ static int copy_compressed_data_to_bio(struct btrfs_fs_info *fs_info,
return -E2BIG;
if (!*out_folio) {
- *out_folio = btrfs_alloc_compr_folio(fs_info);
+ *out_folio = btrfs_alloc_compr_folio(fs_info, GFP_NOFS);
if (!*out_folio)
return -ENOMEM;
}
@@ -280,7 +280,7 @@ int lzo_compress_bio(struct list_head *ws, struct compressed_bio *cb)
ASSERT(bio->bi_iter.bi_size == 0);
ASSERT(len);
- folio_out = btrfs_alloc_compr_folio(fs_info);
+ folio_out = btrfs_alloc_compr_folio(fs_info, GFP_NOFS);
if (!folio_out)
return -ENOMEM;
diff --git a/fs/btrfs/zlib.c b/fs/btrfs/zlib.c
index 9ebc90267e26..486b52db583e 100644
--- a/fs/btrfs/zlib.c
+++ b/fs/btrfs/zlib.c
@@ -172,7 +172,7 @@ int zlib_compress_bio(struct list_head *ws, struct compressed_bio *cb)
workspace->strm.total_in = 0;
workspace->strm.total_out = 0;
- out_folio = btrfs_alloc_compr_folio(fs_info);
+ out_folio = btrfs_alloc_compr_folio(fs_info, GFP_NOFS);
if (out_folio == NULL) {
ret = -ENOMEM;
goto out;
@@ -254,7 +254,7 @@ int zlib_compress_bio(struct list_head *ws, struct compressed_bio *cb)
goto out;
}
- out_folio = btrfs_alloc_compr_folio(fs_info);
+ out_folio = btrfs_alloc_compr_folio(fs_info, GFP_NOFS);
if (out_folio == NULL) {
ret = -ENOMEM;
goto out;
@@ -291,7 +291,7 @@ int zlib_compress_bio(struct list_head *ws, struct compressed_bio *cb)
goto out;
}
/* Get another folio for the stream end. */
- out_folio = btrfs_alloc_compr_folio(fs_info);
+ out_folio = btrfs_alloc_compr_folio(fs_info, GFP_NOFS);
if (out_folio == NULL) {
ret = -ENOMEM;
goto out;
diff --git a/fs/btrfs/zstd.c b/fs/btrfs/zstd.c
index 128646521ea8..86919293fd54 100644
--- a/fs/btrfs/zstd.c
+++ b/fs/btrfs/zstd.c
@@ -437,7 +437,7 @@ int zstd_compress_bio(struct list_head *ws, struct compressed_bio *cb)
workspace->in_buf.size = btrfs_calc_input_length(in_folio, end, start);
/* Allocate and map in the output buffer. */
- out_folio = btrfs_alloc_compr_folio(fs_info);
+ out_folio = btrfs_alloc_compr_folio(fs_info, GFP_NOFS);
if (out_folio == NULL) {
ret = -ENOMEM;
goto out;
@@ -480,7 +480,7 @@ int zstd_compress_bio(struct list_head *ws, struct compressed_bio *cb)
goto out;
}
- out_folio = btrfs_alloc_compr_folio(fs_info);
+ out_folio = btrfs_alloc_compr_folio(fs_info, GFP_NOFS);
if (out_folio == NULL) {
ret = -ENOMEM;
goto out;
@@ -553,7 +553,7 @@ int zstd_compress_bio(struct list_head *ws, struct compressed_bio *cb)
ret = -E2BIG;
goto out;
}
- out_folio = btrfs_alloc_compr_folio(fs_info);
+ out_folio = btrfs_alloc_compr_folio(fs_info, GFP_NOFS);
if (out_folio == NULL) {
ret = -ENOMEM;
goto out;