Merge branch 'fs-current' of linux-next

This commit is contained in:
Mark Brown
2026-07-31 13:58:39 +01:00
23 changed files with 772 additions and 73 deletions
+4 -1
View File
@@ -477,6 +477,9 @@ void afs_fs_fetch_data(struct afs_operation *op)
if (!call)
return afs_op_nomem(op);
if (op->flags & AFS_OPERATION_ASYNC)
call->async = true;
/* marshall the parameters */
bp = call->request;
bp[0] = htonl(FSFETCHDATA);
@@ -484,7 +487,7 @@ void afs_fs_fetch_data(struct afs_operation *op)
bp[2] = htonl(vp->fid.vnode);
bp[3] = htonl(vp->fid.unique);
bp[4] = htonl(lower_32_bits(subreq->start + subreq->transferred));
bp[5] = htonl(lower_32_bits(subreq->len + subreq->transferred));
bp[5] = htonl(lower_32_bits(subreq->len - subreq->transferred));
call->fid = vp->fid;
trace_afs_make_fs_call(call, &vp->fid);
+2 -1
View File
@@ -1421,7 +1421,7 @@ static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *c
{
struct afs_addr_list *alist = op->estate->addresses;
op->call = call;
op->call = afs_get_call(call, afs_call_trace_get);
op->type = call->type;
call->op = op;
call->key = op->key;
@@ -1429,6 +1429,7 @@ static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *c
call->peer = rxrpc_kernel_get_peer(alist->addrs[op->addr_index].peer);
call->service_id = op->server->service_id;
afs_make_call(call, gfp);
afs_put_call(call);
}
static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size)
+1 -1
View File
@@ -176,7 +176,7 @@ int setattr_prepare(struct mnt_idmap *idmap, struct dentry *dentry,
* covered by the open-time check because sys_truncate() takes a
* path, not an open file.
*/
if (IS_ENABLED(CONFIG_FS_VERITY) && IS_VERITY(inode))
if (IS_VERITY(inode))
return -EPERM;
error = inode_newsize_ok(inode, attr->ia_size);
+34 -20
View File
@@ -162,8 +162,10 @@ static Node *get_binfmt_handler(struct binfmt_misc *misc,
static void put_binfmt_handler(Node *e)
{
if (refcount_dec_and_test(&e->users)) {
if (e->flags & MISC_FMT_OPEN_FILE)
if (e->flags & MISC_FMT_OPEN_FILE) {
exe_file_allow_write_access(e->interp_file);
filp_close(e->interp_file, NULL);
}
kfree(e);
}
}
@@ -247,8 +249,14 @@ static int load_misc_binary(struct linux_binprm *bprm)
if (fmt->flags & MISC_FMT_OPEN_FILE) {
interp_file = file_clone_open(fmt->interp_file);
if (!IS_ERR(interp_file))
deny_write_access(interp_file);
if (!IS_ERR(interp_file)) {
int err = exe_file_deny_write_access(interp_file);
if (err) {
fput(interp_file);
interp_file = ERR_PTR(err);
}
}
} else {
interp_file = open_exec(fmt->interpreter);
}
@@ -376,6 +384,10 @@ static Node *create_entry(const char __user *buffer, size_t count)
pr_debug("register: delim: %#x {%c}\n", del, del);
/* A flag-char delimiter runs the flag scan off the buffer. */
if (del == 'P' || del == 'O' || del == 'C' || del == 'F')
goto einval;
/* Pad the buffer with the delim to simplify parsing below. */
memset(buf + count, del, 8);
@@ -909,18 +921,9 @@ static const struct file_operations bm_status_operations = {
/* Superblock handling */
static void bm_put_super(struct super_block *sb)
{
struct user_namespace *user_ns = sb->s_fs_info;
sb->s_fs_info = NULL;
put_user_ns(user_ns);
}
static const struct super_operations s_ops = {
.statfs = simple_statfs,
.evict_inode = bm_evict_inode,
.put_super = bm_put_super,
};
static int bm_fill_super(struct super_block *sb, struct fs_context *fc)
@@ -937,6 +940,10 @@ static int bm_fill_super(struct super_block *sb, struct fs_context *fc)
if (WARN_ON(user_ns != current_user_ns()))
return -EINVAL;
/* Never exec off this instance and never let anything stack on it. */
sb->s_iflags |= SB_I_NOEXEC | SB_I_NODEV;
sb->s_stack_depth = FILESYSTEM_MAX_STACK_DEPTH;
/*
* Lazily allocate a new binfmt_misc instance for this namespace, i.e.
* do it here during the first mount of binfmt_misc. We don't need to
@@ -974,13 +981,12 @@ static int bm_fill_super(struct super_block *sb, struct fs_context *fc)
/*
* When the binfmt_misc superblock for this userns is shutdown
* ->enabled might have been set to false and we don't reinitialize
* ->enabled again in put_super() as someone might already be mounting
* binfmt_misc again. It also would be pointless since by the time
* ->put_super() is called we know that the binary type list for this
* bintfmt_misc mount is empty making load_misc_binary() return
* -ENOEXEC independent of whether ->enabled is true. Instead, if
* someone mounts binfmt_misc for the first time or again we simply
* reset ->enabled to true.
* ->enabled again during shutdown as someone might already be mounting
* binfmt_misc again. It also would be pointless since by then we know
* that the binary type list for this binfmt_misc mount is empty making
* load_misc_binary() return -ENOEXEC independent of whether ->enabled
* is true. Instead, if someone mounts binfmt_misc for the first time or
* again we simply reset ->enabled to true.
*/
misc->enabled = true;
@@ -1006,6 +1012,14 @@ static const struct fs_context_operations bm_context_ops = {
.get_tree = bm_get_tree,
};
static void bm_kill_sb(struct super_block *sb)
{
struct user_namespace *user_ns = sb->s_fs_info;
kill_anon_super(sb);
put_user_ns(user_ns);
}
static int bm_init_fs_context(struct fs_context *fc)
{
fc->ops = &bm_context_ops;
@@ -1022,7 +1036,7 @@ static struct file_system_type bm_fs_type = {
.name = "binfmt_misc",
.init_fs_context = bm_init_fs_context,
.fs_flags = FS_USERNS_MOUNT,
.kill_sb = kill_anon_super,
.kill_sb = bm_kill_sb,
};
MODULE_ALIAS_FS("binfmt_misc");
+1
View File
@@ -600,6 +600,7 @@ int btrfs_prealloc_file_range_trans(struct inode *inode,
loff_t actual_len, u64 *alloc_hint);
int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct folio *locked_folio,
u64 start, u64 end, struct writeback_control *wbc);
void btrfs_queue_writepage_fixup(struct btrfs_inode *inode, struct folio *folio);
int btrfs_encoded_io_compression_from_extent(struct btrfs_fs_info *fs_info,
int compress_type);
int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode,
+27 -1
View File
@@ -1760,6 +1760,8 @@ static int read_backup_root(struct btrfs_fs_info *fs_info, u8 priority)
/* helper to cleanup workers */
static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info)
{
if (fs_info->fixup_workers)
destroy_workqueue(fs_info->fixup_workers);
btrfs_destroy_workqueue(fs_info->delalloc_workers);
btrfs_destroy_workqueue(fs_info->workers);
if (fs_info->endio_workers)
@@ -1967,6 +1969,9 @@ static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info)
fs_info->caching_workers =
btrfs_alloc_workqueue(fs_info, "cache", flags, max_active, 0);
fs_info->fixup_workers =
alloc_ordered_workqueue("btrfs-fixup", ordered_flags);
fs_info->endio_workers =
alloc_workqueue("btrfs-endio", flags, max_active);
fs_info->endio_meta_workers =
@@ -1992,7 +1997,7 @@ static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info)
fs_info->endio_workers && fs_info->endio_meta_workers &&
fs_info->endio_write_workers &&
fs_info->endio_freespace_worker && fs_info->rmw_workers &&
fs_info->caching_workers &&
fs_info->caching_workers && fs_info->fixup_workers &&
fs_info->delayed_workers && fs_info->qgroup_rescan_workers &&
fs_info->discard_ctl.discard_workers)) {
return -ENOMEM;
@@ -4356,6 +4361,18 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
/* clear out the rbtree of defraggable inodes */
btrfs_cleanup_defrag_inodes(fs_info);
/*
* Before the unmount, we sync down all the writeback which can
* generate fixup work. We are about to run delalloc for autodefrag so
* piggy back on that by also flushing the fixup work which can also
* generate delalloc we would like to get run.
*
* After this, it is still possible that some thread doing writeback is
* in btrfs_queue_writepage_fixup() and might finish queueing some final
* work, racing the btrfs_fs_closing() check there.
*/
flush_workqueue(fs_info->fixup_workers);
/*
* Handle the error fs first, as it will flush and wait for all ordered
* extents. This will generate delayed iputs, thus we want to handle
@@ -4433,6 +4450,15 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
cancel_work_sync(&fs_info->preempt_reclaim_work);
cancel_work_sync(&fs_info->em_shrinker_work);
/*
* Reclaim workers can run writeback which can queue fixup.
* After the above cancel_work_sync() calls, any such queueing attempts are
* guaranteed to see btrfs_fs_closing(), so at this point we can genuinely fully
* flush the fixup workqueue. This relies on the belief that *now* no thread can
* still be sitting in btrfs_queue_writepage_fixup().
*/
flush_workqueue(fs_info->fixup_workers);
/*
* Run delayed iputs again because an async reclaim worker may have
* added new ones if it was flushing delalloc:
+113
View File
@@ -1440,6 +1440,115 @@ static bool find_next_delalloc_bitmap(struct folio *folio,
return true;
}
/*
* Debug checks for fixup selection logic to help ensure the invariants
* we expect for fixup marking hold in practice.
*
* - A dirty block without a fixup bit is covered by delalloc or a running
* ordered extent (it was dirtied by a reserving write path).
* - A block with a fixup bit is never covered by delalloc: every delalloc
* setter holds the folio lock and cancels the fixup state of the blocks
* it covers (btrfs_folio_set_dirty()) before releasing it.
*/
static void debug_check_writepage_fixup(struct btrfs_inode *inode, u64 start,
u32 len, bool needs_fixup)
{
struct btrfs_ordered_extent *ordered;
bool delalloc;
if (!IS_ENABLED(CONFIG_BTRFS_DEBUG))
return;
delalloc = btrfs_test_range_bit_exists(&inode->io_tree, start,
start + len - 1, EXTENT_DELALLOC);
if (needs_fixup) {
if (unlikely(delalloc))
DEBUG_WARN("writeback: delalloc and fixup conflict. ino %llu start %llu",
btrfs_ino(inode), start);
} else {
if (delalloc)
return;
ordered = btrfs_lookup_ordered_range(inode, start, len);
if (unlikely(!ordered))
DEBUG_WARN("dirty block, no delalloc, fixup, ordered. ino %llu start %llu",
btrfs_ino(inode), start);
else
btrfs_put_ordered_extent(ordered);
}
}
/*
* Handle folios dirtied without a delalloc reservation, e.g.
* O_DIRECT read into a MAP_SHARED mapping dirtying via set_page_dirty_lock().
*
* btrfs_data_dirty_folio() records the affected blocks in the fixup bitmap
* and the folio fixup flag and we check them here in writeback.
*
* Don't submit such blocks and queue work for the fixup worker to reserve
* space for them so that they can be submitted properly by writeback.
*
* Return 1 if the folio needed fixup, 0 if not, and a negative error code
* on error.
*/
static noinline_for_stack int writepage_fixup(struct btrfs_inode *inode,
struct folio *folio,
struct btrfs_bio_ctrl *bio_ctrl)
{
struct btrfs_fs_info *fs_info = inode_to_fs_info(&inode->vfs_inode);
const unsigned int blocks_per_folio = btrfs_blocks_per_folio(fs_info, folio);
const u32 sectorsize = fs_info->sectorsize;
const u64 page_start = folio_pos(folio);
bool found_fixup = false;
unsigned int bit;
/*
* A folio was dirtied without calling aops->dirty_folio() which we
* explicitly assert is not allowed.
*/
if (unlikely(bitmap_empty(bio_ctrl->submit_bitmap, blocks_per_folio))) {
DEBUG_WARN();
btrfs_err_rl(fs_info,
"root %lld ino %llu folio %llu is dirty with an empty dirty bitmap",
btrfs_root_id(inode->root), btrfs_ino(inode),
folio_pos(folio));
return -EUCLEAN;
}
/* Cheap check on the folio flag. Set iff the fixup bitmap is non-empty. */
if (likely(!folio_test_fixup_pending(folio)))
return 0;
for_each_set_bit(bit, bio_ctrl->submit_bitmap, blocks_per_folio) {
const u64 start = page_start + (bit << fs_info->sectorsize_bits);
const bool needs_fixup = btrfs_folio_test_fixup(fs_info, folio,
start, sectorsize);
debug_check_writepage_fixup(inode, start, sectorsize, needs_fixup);
if (needs_fixup) {
bitmap_clear(bio_ctrl->submit_bitmap, bit, 1);
found_fixup = true;
}
}
if (likely(found_fixup)) {
btrfs_queue_writepage_fixup(inode, folio);
folio_redirty_for_writepage(bio_ctrl->wbc, folio);
if (bitmap_empty(bio_ctrl->submit_bitmap, blocks_per_folio)) {
folio_unlock(folio);
return 1;
}
return 0;
}
/* We should always find fixup if the folio fixup flag was set. */
DEBUG_WARN();
btrfs_err_rl(fs_info,
"root %lld ino %llu folio %llu is fixup with an empty fixup bitmap",
btrfs_root_id(inode->root), btrfs_ino(inode),
folio_pos(folio));
return -EUCLEAN;
}
/*
* Do all of the delayed allocation setup.
*
@@ -1492,6 +1601,10 @@ static noinline_for_stack int writepage_delalloc(struct btrfs_inode *inode,
/* Save the dirty bitmap as our submission bitmap will be a subset of it. */
btrfs_copy_subpage_dirty_bitmap(fs_info, folio, bio_ctrl->submit_bitmap);
ret = writepage_fixup(inode, folio, bio_ctrl);
if (ret)
return ret;
for_each_set_bitrange(start_bit, end_bit, bio_ctrl->submit_bitmap,
blocks_per_folio) {
u64 start = page_start + (start_bit << fs_info->sectorsize_bits);
+12
View File
@@ -713,6 +713,8 @@ struct btrfs_fs_info {
struct btrfs_workqueue *endio_write_workers;
struct btrfs_workqueue *endio_freespace_worker;
struct btrfs_workqueue *caching_workers;
struct workqueue_struct *fixup_workers;
struct btrfs_workqueue *delayed_workers;
struct task_struct *transaction_kthread;
@@ -1200,6 +1202,16 @@ static inline void btrfs_wake_unfinished_drop(struct btrfs_fs_info *fs_info)
clear_and_wake_up_bit(BTRFS_FS_UNFINISHED_DROPS, &fs_info->flags);
}
/*
* We use the folio owner_2 flag to indicate the folio has blocks that were
* dirtied without a space reservation and need the writepage fixup before
* writeback. For bs < folio_size the fixup bitmap tracks the affected
* blocks.
*/
#define folio_test_fixup_pending(folio) folio_test_owner_2(folio)
#define folio_set_fixup_pending(folio) folio_set_owner_2(folio)
#define folio_clear_fixup_pending(folio) folio_clear_owner_2(folio)
#define BTRFS_FS_ERROR(fs_info) (READ_ONCE((fs_info)->fs_error))
#define BTRFS_FS_LOG_CLEANUP_ERROR(fs_info) \
+216 -1
View File
@@ -2812,6 +2812,180 @@ int btrfs_set_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
EXTENT_DELALLOC | extra_bits, cached_state);
}
struct btrfs_writepage_fixup {
struct folio *folio;
struct btrfs_inode *inode;
struct work_struct work;
};
/*
* Do the real fixup work of reserving space for the blocks a folio's fixup
* state records. Queued by writepage_fixup() when writeback found the bits set.
*
* Since the fixup can be cancelled by a task dirtying with a reservation, we must
* re-check the state of fixup under the folio lock.
*/
static void btrfs_writepage_fixup_worker(struct work_struct *work)
{
struct btrfs_writepage_fixup *fixup =
container_of(work, struct btrfs_writepage_fixup, work);
struct extent_state *cached_state = NULL;
struct extent_changeset *data_reserved = NULL;
unsigned long delalloc_bitmap[BITS_TO_LONGS(BTRFS_MAX_BLOCKS_PER_FOLIO)] = { 0 };
struct folio *folio = fixup->folio;
struct btrfs_inode *inode = fixup->inode;
struct btrfs_fs_info *fs_info = inode->root->fs_info;
const unsigned int blocks_per_folio = btrfs_blocks_per_folio(fs_info, folio);
const u32 sectorsize = fs_info->sectorsize;
const u64 page_start = folio_pos(folio);
const u64 page_end = folio_next_pos(folio) - 1;
unsigned int start_bit;
unsigned int end_bit;
unsigned int bit;
bool reserved;
int ret;
/*
* We would prefer to reserve under the folio lock when we know exactly
* which blocks need a reservation. Unfortunately, since the reservation
* can go into flushers which can go into writeback, which takes folio
* locks, that is not possible. Therefore, we have to reserve for the
* whole folio here, then release what we didn't end up needing once we
* figure it out.
*
* Also note the slightly strange error checking. If fixup is actually
* not set, we don't need to mark an error on the mapping. So hang on to
* ret until after we lock and find out if we actually care.
*/
ret = btrfs_delalloc_reserve_space(inode, &data_reserved, page_start,
folio_size(folio));
reserved = (ret == 0);
again:
folio_lock(folio);
if (!folio->mapping || !folio_test_fixup_pending(folio)) {
ret = 0;
goto out;
}
if (ret)
goto out;
btrfs_lock_extent(&inode->io_tree, page_start, page_end, &cached_state);
for (bit = 0; bit < blocks_per_folio; bit++) {
struct btrfs_ordered_extent *ordered;
const u64 start = page_start + (bit << fs_info->sectorsize_bits);
if (test_bit(bit, delalloc_bitmap))
continue;
if (!btrfs_folio_test_fixup(fs_info, folio, start, sectorsize))
continue;
/*
* Any task that sets EXTENT_DELALLOC clears the fixup bits
* under the folio lock, so it should be impossible to observe
* both under the lock. Setting delalloc twice would wrongly
* double account the space.
*/
if (IS_ENABLED(CONFIG_BTRFS_DEBUG) &&
unlikely(btrfs_test_range_bit_exists(&inode->io_tree, start,
start + sectorsize - 1,
EXTENT_DELALLOC))) {
DEBUG_WARN("fixup worker: delalloc and fixup conflict. ino %llu start %llu",
btrfs_ino(inode), start);
btrfs_folio_clear_fixup(fs_info, folio, start, sectorsize);
continue;
}
ordered = btrfs_lookup_ordered_range(inode, start, sectorsize);
if (ordered) {
trace_btrfs_writepage_fixup_defer(inode, ordered);
btrfs_unlock_extent(&inode->io_tree, page_start,
page_end, &cached_state);
folio_unlock(folio);
btrfs_start_ordered_extent(ordered);
btrfs_put_ordered_extent(ordered);
goto again;
}
ret = btrfs_set_extent_delalloc(inode, start,
start + sectorsize - 1, 0,
&cached_state);
if (ret)
break;
trace_btrfs_writepage_fixup_reserve(inode, start, sectorsize);
btrfs_folio_clear_fixup(fs_info, folio, start, sectorsize);
set_bit(bit, delalloc_bitmap);
}
btrfs_unlock_extent(&inode->io_tree, page_start, page_end, &cached_state);
out:
if (ret < 0) {
/* Failure here is analogous to failure in writeback. */
mapping_set_error(folio->mapping, ret);
btrfs_folio_clear_fixup_dirty(fs_info, folio, page_start,
folio_size(folio));
}
if (reserved) {
btrfs_delalloc_release_extents(inode, folio_size(folio));
for_each_clear_bitrange(start_bit, end_bit, delalloc_bitmap,
blocks_per_folio)
btrfs_delalloc_release_space(inode, data_reserved,
page_start + (start_bit << fs_info->sectorsize_bits),
(end_bit - start_bit) << fs_info->sectorsize_bits,
true);
}
folio_unlock(folio);
folio_put(folio);
kfree(fixup);
extent_changeset_free(data_reserved);
btrfs_add_delayed_iput(inode);
}
/*
* Queue space reservation fixup work for blocks dirtied without a space reservation.
*
* Should be used by writeback while holding the folio locked.
*
* If we fail to queue fixup, then the folio state is unchanged and a future
* writeback pass will still see it.
*/
void btrfs_queue_writepage_fixup(struct btrfs_inode *inode, struct folio *folio)
{
struct btrfs_fs_info *fs_info = inode->root->fs_info;
struct btrfs_writepage_fixup *fixup;
/*
* Disallow queueing more fixup during unmount to break the cycle
* of writeback queuing fixup queuing writeback etc.
*
* If it actually hit, then something which was fixup wasn't written
* which we should warn about.
*/
if (btrfs_fs_closing(fs_info)) {
btrfs_warn_rl(fs_info,
"dropping unqueued fixup blocks at unmount. root %lld ino %llu folio %llu",
btrfs_root_id(inode->root), btrfs_ino(inode),
folio_pos(folio));
btrfs_folio_clear_fixup_dirty(fs_info, folio,
folio_pos(folio), folio_size(folio));
return;
}
fixup = kzalloc_obj(*fixup, GFP_NOFS);
if (!fixup)
return;
/*
* This is called from within extent_write_cache_pages() which
* has successfully done an igrab(). But that will be released at the
* end of the writeback pass. We need to extend it for the worker as well.
*/
ihold(&inode->vfs_inode);
folio_get(folio);
INIT_WORK(&fixup->work, btrfs_writepage_fixup_worker);
fixup->folio = folio;
fixup->inode = inode;
queue_work(fs_info->fixup_workers, &fixup->work);
}
/*
* Clear the old accounting flags and set EXTENT_DELALLOC for the range.
*
@@ -7507,6 +7681,12 @@ static void btrfs_invalidate_folio(struct folio *folio, size_t offset,
folio_wait_writeback(folio);
wait_subpage_spinlock(folio);
/*
* The invalidated blocks are going away; drop any fixup blocks among
* them, data included, as they have no space reservation.
*/
btrfs_folio_clear_fixup_dirty(fs_info, folio, page_start + offset, length);
/*
* For subpage case, we have call sites like
* btrfs_punch_hole_lock_range() which passes range not aligned to
@@ -10548,6 +10728,41 @@ static const struct file_operations btrfs_dir_file_operations = {
.setlease = generic_setlease,
};
/*
* The folio is going dirty without a btrfs delalloc space reservation.
* This requires a fixup before writeback which we might sleep so cannot
* run in this context, so we merely set state on the folio indicating it
* needs fixup before writeback.
*
* Note that there is no range in the input, so the whole folio is marked
* dirty and fixup.
*
* We believe that all callers of dirty_folio either:
* - take the folio lock (e.g. pinned folio release notification).
* - take the pte lock but must be running on a dirty pte which means
* page_mkwrite() ran on it and reserved the space. zap_pte_range() cannot
* race with writeback cleaning the folio because writeback runs
* folio_mkclean() which also uses the pte lock and revokes outstanding
* writable mappings.
* Therefore, an additional folio private lock (a la bfs->lock for all cases,
* not just subpage) is not necessary.
*/
static bool btrfs_data_dirty_folio(struct address_space *mapping,
struct folio *folio)
{
struct btrfs_inode *inode = BTRFS_I(mapping->host);
struct btrfs_fs_info *fs_info = inode->root->fs_info;
const u64 page_start = folio_pos(folio);
const u64 range_end = min_t(u64, folio_next_pos(folio),
round_up(i_size_read(&inode->vfs_inode),
fs_info->sectorsize));
if (range_end > page_start)
btrfs_folio_set_fixup_dirty(fs_info, folio, page_start,
range_end - page_start);
return filemap_dirty_folio(mapping, folio);
}
/*
* btrfs doesn't support the bmap operation because swapfiles
* use bmap to make a mapping of extents in the file. They assume
@@ -10568,7 +10783,7 @@ static const struct address_space_operations btrfs_aops = {
.launder_folio = btrfs_launder_folio,
.release_folio = btrfs_release_folio,
.migrate_folio = btrfs_migrate_folio,
.dirty_folio = filemap_dirty_folio,
.dirty_folio = btrfs_data_dirty_folio,
.error_remove_folio = generic_error_remove_folio,
.swap_activate = btrfs_swap_activate,
.swap_deactivate = btrfs_swap_deactivate,
+211 -5
View File
@@ -345,18 +345,57 @@ void btrfs_subpage_clear_uptodate(const struct btrfs_fs_info *fs_info,
spin_unlock_irqrestore(&bfs->lock, flags);
}
/*
* folio_mark_dirty() for a folio we are dirtying with a space reservation.
*
* Dirtiers without a reservation use btrfs_data_dirty_folio().
*/
static void btrfs_folio_mark_dirty(struct folio *folio)
{
struct address_space *mapping = folio_mapping(folio);
if (!mapping || !mapping->host || !is_data_inode(BTRFS_I(mapping->host))) {
folio_mark_dirty(folio);
return;
}
if (folio_test_reclaim(folio))
folio_clear_reclaim(folio);
filemap_dirty_folio(mapping, folio);
}
/*
* The set helper of the dirty ops, so it only runs for folios without a
* fixup bitmap: for those the folio flag is the whole fixup state, and this
* reserving write covers the block, so retire it. Metadata never has the
* flag set and only pays the test.
*/
static void btrfs_folio_mark_dirty_reserved(struct folio *folio)
{
if (folio_test_fixup_pending(folio))
folio_clear_fixup_pending(folio);
btrfs_folio_mark_dirty(folio);
}
void btrfs_subpage_set_dirty(const struct btrfs_fs_info *fs_info,
struct folio *folio, u64 start, u32 len)
{
struct btrfs_folio_state *bfs = folio_get_private(folio);
unsigned int start_bit = subpage_calc_start_bit(fs_info, folio,
unsigned int dirty_bit = subpage_calc_start_bit(fs_info, folio,
dirty, start, len);
unsigned int fixup_bit = subpage_calc_start_bit(fs_info, folio,
fixup, start, len);
const unsigned int nbits = len >> fs_info->sectorsize_bits;
unsigned long flags;
spin_lock_irqsave(&bfs->lock, flags);
bitmap_set(bfs->bitmaps, start_bit, len >> fs_info->sectorsize_bits);
bitmap_set(bfs->bitmaps, dirty_bit, nbits);
/* Proper dirtying obviates the need for fixup. */
bitmap_clear(bfs->bitmaps, fixup_bit, nbits);
if (folio_test_fixup_pending(folio) &&
subpage_test_bitmap_all_zero(fs_info, folio, fixup))
folio_clear_fixup_pending(folio);
spin_unlock_irqrestore(&bfs->lock, flags);
folio_mark_dirty(folio);
btrfs_folio_mark_dirty(folio);
}
static void folio_clear_tags(struct folio *folio)
@@ -457,6 +496,172 @@ void btrfs_subpage_clear_writeback(const struct btrfs_fs_info *fs_info,
spin_unlock_irqrestore(&bfs->lock, flags);
}
void btrfs_subpage_clear_fixup(const struct btrfs_fs_info *fs_info,
struct folio *folio, u64 start, u32 len)
{
struct btrfs_folio_state *bfs = folio_get_private(folio);
unsigned int start_bit = subpage_calc_start_bit(fs_info, folio,
fixup, start, len);
unsigned long flags;
spin_lock_irqsave(&bfs->lock, flags);
bitmap_clear(bfs->bitmaps, start_bit, len >> fs_info->sectorsize_bits);
if (subpage_test_bitmap_all_zero(fs_info, folio, fixup))
folio_clear_fixup_pending(folio);
spin_unlock_irqrestore(&bfs->lock, flags);
}
/*
* In one pass under bfs->lock, mark every block with a clear dirty bit in the
* range both dirty and needing fixup.
*
* Only called from the dirty_folio callback, which owns the folio-level
* dirty flag; calling folio_mark_dirty() here would recurse.
*
* The folio fixup flag and bits are both set under bfs->lock so that a
* writeback pass observing the new bits also observes the flag.
*/
static void btrfs_subpage_set_fixup_dirty(const struct btrfs_fs_info *fs_info,
struct folio *folio, u64 start, u32 len)
{
struct btrfs_folio_state *bfs = folio_get_private(folio);
unsigned int dirty_bit = subpage_calc_start_bit(fs_info, folio,
dirty, start, len);
unsigned int fixup_bit = subpage_calc_start_bit(fs_info, folio,
fixup, start, len);
const unsigned int nbits = len >> fs_info->sectorsize_bits;
unsigned long flags;
bool marked = false;
spin_lock_irqsave(&bfs->lock, flags);
for (unsigned int i = 0; i < nbits; i++) {
if (test_bit(dirty_bit + i, bfs->bitmaps))
continue;
set_bit(dirty_bit + i, bfs->bitmaps);
set_bit(fixup_bit + i, bfs->bitmaps);
marked = true;
}
if (marked)
folio_set_fixup_pending(folio);
spin_unlock_irqrestore(&bfs->lock, flags);
}
/*
* Mark the still-clean blocks of a folio dirty and needing fixup, for
* btrfs_data_dirty_folio().
*
* A subpage block size folio that is not uptodate is left alone: its clean
* blocks may hold content that was never read in, which must not be marked
* dirty.
*/
void btrfs_folio_set_fixup_dirty(const struct btrfs_fs_info *fs_info,
struct folio *folio, u64 start, u32 len)
{
if (!btrfs_is_subpage(fs_info, folio)) {
if (!folio_test_dirty(folio))
folio_set_fixup_pending(folio);
return;
}
if (!folio_test_uptodate(folio))
return;
btrfs_subpage_set_fixup_dirty(fs_info, folio, start, len);
}
/*
* Drop the fixup blocks inside the range: clear both their fixup and dirty
* bits.
*
* Fixup blocks carry no space reservation, so their fixup and dirty bits
* must be dropped together. Clearing only the fixup bit would leave a
* dirty block without a reservation which is not a valid state.
*
* Returns true if the folio has no dirty blocks left.
*/
static bool btrfs_subpage_clear_fixup_dirty(const struct btrfs_fs_info *fs_info,
struct folio *folio, u64 start, u32 len)
{
struct btrfs_folio_state *bfs = folio_get_private(folio);
unsigned int dirty_bit = subpage_calc_start_bit(fs_info, folio,
dirty, start, len);
unsigned int fixup_bit = subpage_calc_start_bit(fs_info, folio,
fixup, start, len);
const unsigned int nbits = len >> fs_info->sectorsize_bits;
unsigned long flags;
bool last;
spin_lock_irqsave(&bfs->lock, flags);
for (unsigned int i = 0; i < nbits; i++) {
if (!test_bit(fixup_bit + i, bfs->bitmaps))
continue;
clear_bit(fixup_bit + i, bfs->bitmaps);
clear_bit(dirty_bit + i, bfs->bitmaps);
}
if (subpage_test_bitmap_all_zero(fs_info, folio, fixup))
folio_clear_fixup_pending(folio);
last = subpage_test_bitmap_all_zero(fs_info, folio, dirty);
spin_unlock_irqrestore(&bfs->lock, flags);
return last;
}
/*
* Drop the fixup blocks inside the range, for callers discarding their data:
* btrfs_invalidate_folio() and the writepage fixup worker's error path.
*
* Callers that have just reserved space for a block want
* btrfs_folio_clear_fixup() instead - there the block stays dirty and gets
* written.
*
* The range can be byte-granular (an unaligned truncate through
* btrfs_invalidate_folio()); only blocks fully inside it are dropped, as a
* partially covered block still holds live data outside the range. For
* single-block folios the folio flag is the fixup state, so it is dropped
* only when the range covers the whole folio.
*/
void btrfs_folio_clear_fixup_dirty(const struct btrfs_fs_info *fs_info,
struct folio *folio, u64 start, u32 len)
{
u64 aligned_start;
u64 aligned_end;
/* The folio flag is set whenever any fixup bitmap bit is. */
if (!folio_test_fixup_pending(folio))
return;
if (!btrfs_is_subpage(fs_info, folio)) {
if (start <= folio_pos(folio) &&
start + len >= folio_next_pos(folio)) {
folio_clear_fixup_pending(folio);
folio_clear_dirty_for_io(folio);
}
return;
}
btrfs_subpage_clamp_range(folio, &start, &len);
aligned_start = round_up(start, fs_info->sectorsize);
aligned_end = round_down(start + len, fs_info->sectorsize);
if (aligned_end <= aligned_start)
return;
if (btrfs_subpage_clear_fixup_dirty(fs_info, folio, aligned_start,
aligned_end - aligned_start))
folio_clear_dirty_for_io(folio);
}
bool btrfs_folio_test_fixup(const struct btrfs_fs_info *fs_info,
struct folio *folio, u64 start, u32 len)
{
if (!btrfs_is_subpage(fs_info, folio))
return folio_test_fixup_pending(folio);
return btrfs_subpage_test_fixup(fs_info, folio, start, len);
}
void btrfs_folio_clear_fixup(const struct btrfs_fs_info *fs_info,
struct folio *folio, u64 start, u32 len)
{
if (!btrfs_is_subpage(fs_info, folio)) {
folio_clear_fixup_pending(folio);
return;
}
btrfs_subpage_clear_fixup(fs_info, folio, start, len);
}
/*
* Unlike set/clear which is dependent on each page status, for test all bits
* are tested in the same way.
@@ -480,6 +685,7 @@ bool btrfs_subpage_test_##name(const struct btrfs_fs_info *fs_info, \
IMPLEMENT_BTRFS_SUBPAGE_TEST_OP(uptodate);
IMPLEMENT_BTRFS_SUBPAGE_TEST_OP(dirty);
IMPLEMENT_BTRFS_SUBPAGE_TEST_OP(writeback);
IMPLEMENT_BTRFS_SUBPAGE_TEST_OP(fixup);
/*
* Note that, in selftests (extent-io-tests), we can have empty fs_info passed
@@ -571,8 +777,8 @@ bool btrfs_meta_folio_test_##name(struct folio *folio, const struct extent_buffe
}
IMPLEMENT_BTRFS_PAGE_OPS(uptodate, folio_mark_uptodate, folio_clear_uptodate,
folio_test_uptodate);
IMPLEMENT_BTRFS_PAGE_OPS(dirty, folio_mark_dirty, folio_clear_dirty_for_io,
folio_test_dirty);
IMPLEMENT_BTRFS_PAGE_OPS(dirty, btrfs_folio_mark_dirty_reserved,
folio_clear_dirty_for_io, folio_test_dirty);
IMPLEMENT_BTRFS_PAGE_OPS(writeback, folio_start_writeback, folio_end_writeback,
folio_test_writeback);
+36 -5
View File
@@ -14,15 +14,15 @@ struct folio;
/*
* Extra info for subpage bitmap.
*
* For subpage we pack all uptodate/dirty/writeback bitmaps into
* For subpage we pack all uptodate/dirty/writeback/fixup bitmaps into
* one larger bitmap.
*
* This structure records how they are organized in the bitmap:
*
* /- uptodate /- dirty /- writeback
* | | |
* v v v
* |u|u|u|u|........|u|u|d|d|.......|d|d|w|w|.......|w|w|
* /- uptodate /- dirty /- writeback /- fixup
* | | | |
* v v v v
* |u|u|u|u|........|u|u|d|d|.......|d|d|w|w|.....|w|w|f|f|.....|f|f|
* |< sectors_per_page >|
*
* Unlike regular macro-like enums, here we do not go upper-case names, as
@@ -40,6 +40,14 @@ enum {
*/
btrfs_bitmap_nr_writeback,
/*
* Blocks dirtied by the dirty_folio callback instead of a reserving
* write path (e.g. set_page_dirty_lock() on a GUP pin). They have
* no space reservation and need the writepage fixup before they can
* be submitted.
*/
btrfs_bitmap_nr_fixup,
btrfs_bitmap_nr_max
};
@@ -165,6 +173,29 @@ DECLARE_BTRFS_SUBPAGE_OPS(uptodate);
DECLARE_BTRFS_SUBPAGE_OPS(dirty);
DECLARE_BTRFS_SUBPAGE_OPS(writeback);
/*
* Fixup bit helpers.
*
* The fixup bit is data-only and has no plain set helper (setting happens
* together with dirtying in btrfs_subpage_set_fixup_dirty()), so it does not
* go through DECLARE_BTRFS_SUBPAGE_OPS(). For single-block folios the
* folio_*_fixup_pending() flag takes the place of the bitmap.
*/
void btrfs_subpage_clear_fixup(const struct btrfs_fs_info *fs_info,
struct folio *folio, u64 start, u32 len);
bool btrfs_subpage_test_fixup(const struct btrfs_fs_info *fs_info,
struct folio *folio, u64 start, u32 len);
bool btrfs_folio_test_fixup(const struct btrfs_fs_info *fs_info,
struct folio *folio, u64 start, u32 len);
void btrfs_folio_set_fixup_dirty(const struct btrfs_fs_info *fs_info,
struct folio *folio, u64 start, u32 len);
/* For a block that just got its space reserved; it stays dirty. */
void btrfs_folio_clear_fixup(const struct btrfs_fs_info *fs_info,
struct folio *folio, u64 start, u32 len);
/* For callers discarding the data; clears the dirty bits too. */
void btrfs_folio_clear_fixup_dirty(const struct btrfs_fs_info *fs_info,
struct folio *folio, u64 start, u32 len);
/*
* Helper for error cleanup, where a folio will have its dirty flag cleared,
* with writeback started and finished.
+1 -1
View File
@@ -534,7 +534,7 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg)
return -EFAULT;
policy.version = version;
if (!inode_owner_or_capable(&nop_mnt_idmap, inode))
if (!inode_owner_or_capable(file_mnt_idmap(filp), inode))
return -EACCES;
ret = mnt_want_write_file(filp);
+19 -2
View File
@@ -13,6 +13,7 @@
struct bio_set iomap_ioend_bioset;
EXPORT_SYMBOL_GPL(iomap_ioend_bioset);
static struct bio_set iomap_ioend_split_bioset;
struct iomap_ioend *iomap_init_ioend(struct inode *inode,
struct bio *bio, loff_t file_offset, u16 ioend_flags)
@@ -488,7 +489,8 @@ struct iomap_ioend *iomap_split_ioend(struct iomap_ioend *ioend,
sector_offset = ALIGN_DOWN(sector_offset << SECTOR_SHIFT,
i_blocksize(ioend->io_inode)) >> SECTOR_SHIFT;
split = bio_split(bio, sector_offset, GFP_NOFS, &iomap_ioend_bioset);
split = bio_split(bio, sector_offset, GFP_NOFS,
&iomap_ioend_split_bioset);
if (IS_ERR(split))
return ERR_CAST(split);
split->bi_private = bio->bi_private;
@@ -511,8 +513,23 @@ EXPORT_SYMBOL_GPL(iomap_split_ioend);
static int __init iomap_ioend_init(void)
{
return bioset_init(&iomap_ioend_bioset, 4 * (PAGE_SIZE / SECTOR_SIZE),
const unsigned int nr_mempool_entries = 4 * (PAGE_SIZE / SECTOR_SIZE);
int error;
error = bioset_init(&iomap_ioend_bioset, nr_mempool_entries,
offsetof(struct iomap_ioend, io_bio),
BIOSET_NEED_BVECS);
if (error)
return error;
error = bioset_init(&iomap_ioend_split_bioset, nr_mempool_entries,
offsetof(struct iomap_ioend, io_bio),
BIOSET_NEED_BVECS);
if (error)
goto out_exit_ioend_bioset;
return 0;
out_exit_ioend_bioset:
bioset_exit(&iomap_ioend_bioset);
return error;
}
fs_initcall(iomap_ioend_init);
+6 -4
View File
@@ -102,8 +102,10 @@ static ssize_t netfs_prepare_read_iterator(struct netfs_io_subrequest *subreq,
added = rolling_buffer_load_from_ra(&rreq->buffer, ractl,
&put_batch);
if (added < 0)
if (added < 0) {
folio_batch_release(&put_batch);
return added;
}
rreq->submitted += added;
}
folio_batch_release(&put_batch);
@@ -359,7 +361,7 @@ void netfs_readahead(struct readahead_control *ractl)
netfs_rreq_expand(rreq, ractl);
rreq->submitted = rreq->start;
if (rolling_buffer_init(&rreq->buffer, rreq->debug_id, ITER_DEST) < 0)
if (rolling_buffer_init(&rreq->buffer, rreq->debug_id, ITER_DEST, rreq->gfp) < 0)
goto cleanup_free;
netfs_read_to_pagecache(rreq, ractl);
@@ -378,10 +380,10 @@ static int netfs_create_singular_buffer(struct netfs_io_request *rreq, struct fo
{
ssize_t added;
if (rolling_buffer_init(&rreq->buffer, rreq->debug_id, ITER_DEST) < 0)
if (rolling_buffer_init(&rreq->buffer, rreq->debug_id, ITER_DEST, rreq->gfp) < 0)
return -ENOMEM;
added = rolling_buffer_append(&rreq->buffer, folio, rollbuf_flags);
added = rolling_buffer_append(&rreq->buffer, folio, rollbuf_flags, rreq->gfp);
if (added < 0)
return added;
rreq->submitted = rreq->start + added;
+1
View File
@@ -43,6 +43,7 @@ extern struct list_head netfs_io_requests;
extern spinlock_t netfs_proc_lock;
extern mempool_t netfs_request_pool;
extern mempool_t netfs_subrequest_pool;
extern mempool_t netfs_folioq_pool;
#ifdef CONFIG_PROC_FS
static inline void netfs_proc_add_rreq(struct netfs_io_request *rreq)
+7
View File
@@ -28,6 +28,7 @@ static struct kmem_cache *netfs_request_slab;
static struct kmem_cache *netfs_subrequest_slab;
mempool_t netfs_request_pool;
mempool_t netfs_subrequest_pool;
mempool_t netfs_folioq_pool;
#ifdef CONFIG_PROC_FS
LIST_HEAD(netfs_io_requests);
@@ -108,6 +109,9 @@ static int __init netfs_init(void)
{
int ret = -ENOMEM;
if (mempool_init_kmalloc_pool(&netfs_folioq_pool, 100, sizeof(struct folio_queue)) < 0)
goto error_folioq_pool;
netfs_request_slab = kmem_cache_create("netfs_request",
sizeof(struct netfs_io_request), 0,
SLAB_HWCACHE_ALIGN | SLAB_ACCOUNT,
@@ -160,6 +164,8 @@ error_subreq:
error_reqpool:
kmem_cache_destroy(netfs_request_slab);
error_req:
mempool_exit(&netfs_folioq_pool);
error_folioq_pool:
return ret;
}
fs_initcall(netfs_init);
@@ -172,5 +178,6 @@ static void __exit netfs_exit(void)
kmem_cache_destroy(netfs_subrequest_slab);
mempool_exit(&netfs_request_pool);
kmem_cache_destroy(netfs_request_slab);
mempool_exit(&netfs_folioq_pool);
}
module_exit(netfs_exit);
+17 -13
View File
@@ -7,7 +7,6 @@
#include <linux/slab.h>
#include <linux/mempool.h>
#include <linux/delay.h>
#include "internal.h"
static void netfs_free_request(struct work_struct *work);
@@ -26,17 +25,23 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping,
struct netfs_io_request *rreq;
mempool_t *mempool = ctx->ops->request_pool ?: &netfs_request_pool;
struct kmem_cache *cache = mempool->pool_data;
gfp_t gfp = GFP_KERNEL;
int ret;
for (;;) {
rreq = mempool_alloc(mempool, GFP_KERNEL);
if (rreq)
break;
msleep(10);
/* Writeback is part of memory reclaim and must not fail due to ENOMEM. */
if (origin == NETFS_WRITEBACK || origin == NETFS_WRITEBACK_SINGLE) {
gfp = GFP_NOFS; /* Allows use of mempools. */
rreq = mempool_alloc(mempool, gfp);
} else {
rreq = mempool->alloc(gfp, mempool->pool_data);
if (!rreq)
return ERR_PTR(-ENOMEM);
}
memset(rreq, 0, kmem_cache_size(cache));
INIT_WORK(&rreq->cleanup_work, netfs_free_request);
rreq->gfp = gfp;
rreq->start = start;
rreq->len = len;
rreq->origin = origin;
@@ -200,13 +205,12 @@ struct netfs_io_subrequest *netfs_alloc_subrequest(struct netfs_io_request *rreq
mempool_t *mempool = rreq->netfs_ops->subrequest_pool ?: &netfs_subrequest_pool;
struct kmem_cache *cache = mempool->pool_data;
for (;;) {
subreq = mempool_alloc(rreq->netfs_ops->subrequest_pool ?: &netfs_subrequest_pool,
GFP_KERNEL);
if (subreq)
break;
msleep(10);
}
if (rreq->gfp == GFP_KERNEL)
subreq = mempool->alloc(rreq->gfp, mempool->pool_data);
else
subreq = mempool_alloc(mempool, rreq->gfp);
if (!subreq)
return NULL;
memset(subreq, 0, kmem_cache_size(cache));
INIT_WORK(&subreq->work, NULL);
+2 -1
View File
@@ -53,7 +53,8 @@ static void netfs_pgpriv2_copy_folio(struct netfs_io_request *creq, struct folio
trace_netfs_folio(folio, netfs_folio_trace_store_copy);
/* Attach the folio to the rolling buffer. */
if (rolling_buffer_append(&creq->buffer, folio, 0) < 0) {
if (rolling_buffer_append(&creq->buffer, folio, 0, creq->gfp) < 0) {
folio_end_private_2(folio);
clear_bit(NETFS_RREQ_FOLIO_COPY_TO_CACHE, &creq->flags);
return;
}
+13 -9
View File
@@ -6,6 +6,7 @@
*/
#include <linux/bitops.h>
#include <linux/mempool.h>
#include <linux/pagemap.h>
#include <linux/rolling_buffer.h>
#include <linux/slab.h>
@@ -27,7 +28,10 @@ struct folio_queue *netfs_folioq_alloc(unsigned int rreq_id, gfp_t gfp,
{
struct folio_queue *fq;
fq = kmalloc_obj(*fq, gfp);
if (gfp == GFP_KERNEL)
fq = netfs_folioq_pool.alloc(gfp, netfs_folioq_pool.pool_data);
else
fq = mempool_alloc(&netfs_folioq_pool, gfp);
if (fq) {
netfs_stat(&netfs_n_folioq);
folioq_init(fq, rreq_id);
@@ -50,7 +54,7 @@ void netfs_folioq_free(struct folio_queue *folioq,
{
trace_netfs_folioq(folioq, trace);
netfs_stat_d(&netfs_n_folioq);
kfree(folioq);
mempool_free(folioq, &netfs_folioq_pool);
}
EXPORT_SYMBOL(netfs_folioq_free);
@@ -60,11 +64,11 @@ EXPORT_SYMBOL(netfs_folioq_free);
* consumer.
*/
int rolling_buffer_init(struct rolling_buffer *roll, unsigned int rreq_id,
unsigned int direction)
unsigned int direction, gfp_t gfp)
{
struct folio_queue *fq;
fq = netfs_folioq_alloc(rreq_id, GFP_NOFS, netfs_trace_folioq_rollbuf_init);
fq = netfs_folioq_alloc(rreq_id, gfp, netfs_trace_folioq_rollbuf_init);
if (!fq)
return -ENOMEM;
@@ -77,14 +81,14 @@ int rolling_buffer_init(struct rolling_buffer *roll, unsigned int rreq_id,
/*
* Add another folio_queue to a rolling buffer if there's no space left.
*/
int rolling_buffer_make_space(struct rolling_buffer *roll)
int rolling_buffer_make_space(struct rolling_buffer *roll, gfp_t gfp)
{
struct folio_queue *fq, *head = roll->head;
if (!folioq_full(head))
return 0;
fq = netfs_folioq_alloc(head->rreq_id, GFP_NOFS, netfs_trace_folioq_make_space);
fq = netfs_folioq_alloc(head->rreq_id, gfp, netfs_trace_folioq_make_space);
if (!fq)
return -ENOMEM;
fq->prev = head;
@@ -122,7 +126,7 @@ ssize_t rolling_buffer_load_from_ra(struct rolling_buffer *roll,
int nr, ix, to;
ssize_t size = 0;
if (rolling_buffer_make_space(roll) < 0)
if (rolling_buffer_make_space(roll, GFP_KERNEL) < 0)
return -ENOMEM;
fq = roll->head;
@@ -153,12 +157,12 @@ ssize_t rolling_buffer_load_from_ra(struct rolling_buffer *roll,
* Append a folio to the rolling buffer.
*/
ssize_t rolling_buffer_append(struct rolling_buffer *roll, struct folio *folio,
unsigned int flags)
unsigned int flags, gfp_t gfp)
{
ssize_t size = folio_size(folio);
int slot;
if (rolling_buffer_make_space(roll) < 0)
if (rolling_buffer_make_space(roll, gfp) < 0)
return -ENOMEM;
slot = folioq_append(roll->head, folio);
+10 -5
View File
@@ -108,7 +108,7 @@ struct netfs_io_request *netfs_create_write_req(struct address_space *mapping,
ictx = netfs_inode(wreq->inode);
if (is_cacheable)
fscache_begin_write_operation(&wreq->cache_resources, netfs_i_cookie(ictx));
if (rolling_buffer_init(&wreq->buffer, wreq->debug_id, ITER_SOURCE) < 0)
if (rolling_buffer_init(&wreq->buffer, wreq->debug_id, ITER_SOURCE, wreq->gfp) < 0)
goto nomem;
wreq->cleaned_to = wreq->start;
@@ -167,7 +167,7 @@ void netfs_prepare_write(struct netfs_io_request *wreq,
*/
if (iov_iter_is_folioq(wreq_iter) &&
wreq_iter->folioq_slot >= folioq_nr_slots(wreq_iter->folioq))
rolling_buffer_make_space(&wreq->buffer);
rolling_buffer_make_space(&wreq->buffer, wreq->gfp);
subreq = netfs_alloc_subrequest(wreq);
subreq->source = stream->source;
@@ -334,7 +334,7 @@ static int netfs_write_folio(struct netfs_io_request *wreq,
_enter("");
if (rolling_buffer_make_space(&wreq->buffer) < 0)
if (rolling_buffer_make_space(&wreq->buffer, wreq->gfp) < 0)
return -ENOMEM;
/* netfs_perform_write() may shift i_size around the page or from out
@@ -436,7 +436,7 @@ static int netfs_write_folio(struct netfs_io_request *wreq,
}
/* Attach the folio to the rolling buffer. */
rolling_buffer_append(&wreq->buffer, folio, 0);
rolling_buffer_append(&wreq->buffer, folio, 0, wreq->gfp);
/* Move the submission point forward to allow for write-streaming data
* not starting at the front of the page. We don't do write-streaming
@@ -720,6 +720,7 @@ static int netfs_write_folio_single(struct netfs_io_request *wreq,
size_t iter_off = 0;
size_t fsize = folio_size(folio), flen;
loff_t fpos = folio_pos(folio);
ssize_t ret;
bool to_eof = false;
bool no_debug = false;
@@ -748,7 +749,11 @@ static int netfs_write_folio_single(struct netfs_io_request *wreq,
/* Attach the folio to the rolling buffer. */
folio_get(folio);
rolling_buffer_append(&wreq->buffer, folio, NETFS_ROLLBUF_PUT_MARK);
ret = rolling_buffer_append(&wreq->buffer, folio, NETFS_ROLLBUF_PUT_MARK, wreq->gfp);
if (ret < 0) {
folio_put(folio);
return ret;
}
/* Move the submission point forward to allow for write-streaming data
* not starting at the front of the page. We don't do write-streaming

Some files were not shown because too many files have changed in this diff Show More