Files
Paulo Alcantara c43d323362 netfs: Fix folio_queue ENOMEM in writeback by adding a mempool
JIRA: https://issues.redhat.com/browse/RHEL-235460
Conflicts:
	- Code difference due to missing upstream commit
	69050f8d6d075dc01af7a5f2f550a8067510366f.

commit 1d78d56c43ef3768183e8370e7367b162700e049
Author: David Howells <dhowells@redhat.com>
Date:   Mon Jul 27 14:07:15 2026 +0100

    netfs: Fix folio_queue ENOMEM in writeback by adding a mempool

    Fix the handling of folio_queue allocation failure in writeback by adding a
    mempool and passing in gfp_t flags to the rolling buffer functions that
    allocate memory, using the mempool if gfp != GFP_KERNEL.

    This is then extended upwards and the gfp to be used for a request is stored
    in the netfs_io_request struct and is then used for both requests and
    subrequests, eliminating the sleeping loops there.

    The failure caused:

        folio != NULL
        WARNING: fs/netfs/write_issue.c:603 at netfs_writepages+0x883/0xa10 fs/netfs/write_issue.c:603, CPU#3: syz.0.17/5919

    Fixes: cd0277ed0c ("netfs: Use new folio_queue data type and iterator instead of xarray iter")
    Reported-by: syzbot+0da43efa72f88bd3a8af@syzkaller.appspotmail.com
    Closes: https://syzkaller.appspot.com/bug?extid=0da43efa72f88bd3a8af
    Signed-off-by: David Howells <dhowells@redhat.com>
    Link: https://patch.msgid.link/20260727130716.1099906-5-dhowells@redhat.com
    Tested-by: syzbot+0da43efa72f88bd3a8af@syzkaller.appspotmail.com
    cc: Paulo Alcantara <pc@manguebit.org>
    cc: Yun Zhou <yun.zhou@windriver.com>
    cc: Matthew Wilcox <willy@infradead.org>
    cc: Christoph Hellwig <hch@infradead.org>
    cc: netfs@lists.linux.dev
    cc: linux-fsdevel@vger.kernel.org
    Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>

Signed-off-by: Paulo Alcantara <paalcant@redhat.com>
2026-08-12 15:06:52 -03:00

62 lines
2.2 KiB
C

/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Rolling buffer of folios
*
* Copyright (C) 2024 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*/
#ifndef _ROLLING_BUFFER_H
#define _ROLLING_BUFFER_H
#include <linux/folio_queue.h>
#include <linux/uio.h>
/*
* Rolling buffer. Whilst the buffer is live and in use, folios and folio
* queue segments can be added to one end by one thread and removed from the
* other end by another thread. The buffer isn't allowed to be empty; it must
* always have at least one folio_queue in it so that neither side has to
* modify both queue pointers.
*
* The iterator in the buffer is extended as buffers are inserted. It can be
* snapshotted to use a segment of the buffer.
*/
struct rolling_buffer {
struct folio_queue *head; /* Producer's insertion point */
struct folio_queue *tail; /* Consumer's removal point */
struct iov_iter iter; /* Iterator tracking what's left in the buffer */
u8 next_head_slot; /* Next slot in ->head */
u8 first_tail_slot; /* First slot in ->tail */
};
/*
* Snapshot of a rolling buffer.
*/
struct rolling_buffer_snapshot {
struct folio_queue *curr_folioq; /* Queue segment in which current folio resides */
unsigned char curr_slot; /* Folio currently being read */
unsigned char curr_order; /* Order of folio */
};
/* Marks to store per-folio in the internal folio_queue structs. */
#define ROLLBUF_MARK_1 BIT(0)
#define ROLLBUF_MARK_2 BIT(1)
int rolling_buffer_init(struct rolling_buffer *roll, unsigned int rreq_id,
unsigned int direction, gfp_t gfp);
int rolling_buffer_make_space(struct rolling_buffer *roll, gfp_t gfp);
ssize_t rolling_buffer_load_from_ra(struct rolling_buffer *roll,
struct readahead_control *ractl,
struct folio_batch *put_batch);
ssize_t rolling_buffer_append(struct rolling_buffer *roll, struct folio *folio,
unsigned int flags, gfp_t gfp);
struct folio_queue *rolling_buffer_delete_spent(struct rolling_buffer *roll);
void rolling_buffer_clear(struct rolling_buffer *roll);
static inline void rolling_buffer_advance(struct rolling_buffer *roll, size_t amount)
{
iov_iter_advance(&roll->iter, amount);
}
#endif /* _ROLLING_BUFFER_H */