[PATCH v12 7/8] netfs: Remove the rolling_buffer implementation

From: David Howells

Date: Mon Oct 05 2026 - 03:22:12 EST


Remove the rolling_buffer implementation as it has been replaced with the
use of bvecq_pos.

Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
cc: Paulo Alcantara <pc@xxxxxxxxxxxxx>
cc: Matthew Wilcox <willy@xxxxxxxxxxxxx>
cc: netfs@xxxxxxxxxxxxxxx
cc: linux-fsdevel@xxxxxxxxxxxxxxx
---
fs/netfs/rolling_buffer.c | 182 ---------------------------------
include/linux/rolling_buffer.h | 47 ---------
2 files changed, 229 deletions(-)
delete mode 100644 fs/netfs/rolling_buffer.c
delete mode 100644 include/linux/rolling_buffer.h

diff --git a/fs/netfs/rolling_buffer.c b/fs/netfs/rolling_buffer.c
deleted file mode 100644
index 66ce9add4012..000000000000
--- a/fs/netfs/rolling_buffer.c
+++ /dev/null
@@ -1,182 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/* Rolling buffer helpers
- *
- * Copyright (C) 2024 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@xxxxxxxxxx)
- */
-
-#include <linux/bitops.h>
-#include <linux/mempool.h>
-#include <linux/pagemap.h>
-#include <linux/rolling_buffer.h>
-#include <linux/slab.h>
-#include "internal.h"
-
-/*
- * Initialise a rolling buffer. We allocate an empty folio queue struct to so
- * that the pointers can be independently driven by the producer and the
- * consumer.
- */
-int rolling_buffer_init(struct rolling_buffer *roll, unsigned int direction,
- gfp_t gfp, bool for_writeback)
-{
- struct bvecq *bq;
-
- roll->for_writeback = for_writeback;
-
- bq = bvecq_alloc_one(BVECQ_POOL_SLOTS, gfp, for_writeback);
- if (!bq)
- return -ENOMEM;
-
- roll->head = bq;
- roll->tail = bq;
- iov_iter_bvec_queue(&roll->iter, direction, bq, 0, 0, 0);
- return 0;
-}
-
-/*
- * Add another bvecq to a rolling buffer if there's no space left.
- */
-int rolling_buffer_make_space(struct rolling_buffer *roll, gfp_t gfp)
-{
- struct bvecq *bq, *head = roll->head;
-
- if (!bvecq_is_full(head))
- return 0;
-
- bq = bvecq_alloc_one(BVECQ_POOL_SLOTS, gfp, roll->for_writeback);
- if (!bq)
- return -ENOMEM;
-
- roll->head = bq;
- if (bvecq_is_full(head)) {
- /* Make sure we don't leave the master iterator pointing to a
- * block that might get immediately consumed.
- */
- if (roll->iter.bvecq == head &&
- roll->iter.bvecq_slot == head->nr_slots) {
- roll->iter.bvecq = bq;
- roll->iter.bvecq_slot = 0;
- }
- }
-
- /* Make sure the initialisation is stored before the next pointer.
- *
- * [!] NOTE: After we set head->next, the consumer is at liberty to
- * immediately delete the old head.
- */
- bvecq_append(head, bq);
- return 0;
-}
-
-/*
- * Decant the entire list of folios to read into a rolling buffer.
- */
-ssize_t rolling_buffer_bulk_load_from_ra(struct rolling_buffer *roll,
- struct readahead_control *ractl,
- gfp_t gfp)
-{
- struct bvecq *bq;
- size_t loaded = 0;
-
- while (ractl->_nr_pages - ractl->_batch_count > 0) {
- struct page **pages;
- unsigned int nr;
-
- /* Allocate a bvecq to put some folios into and attach it to
- * the rolling buffer.
- */
- bq = bvecq_alloc_one(BVECQ_POOL_SLOTS, gfp, false);
- if (!bq)
- goto nomem_unlock;
- bq->mem_type = BVECQ_MEM_EXTERNAL; /* Folio cleanup handled separately. */
-
- if (!roll->tail)
- roll->tail = bq;
- else
- bvecq_append(roll->head, bq);
- roll->head = bq;
-
- /* Get a bunch of folios and note their sizes. */
- pages = (struct page **)(bq->bv + bq->max_slots);
- pages -= bq->max_slots;
- nr = __readahead_batch(ractl, pages, bq->max_slots);
- if (WARN_ON_ONCE(!nr))
- break;
-
- for (int slot = 0; slot < nr; slot++) {
- struct folio *folio = page_folio(pages[slot]);
- size_t len = folio_size(folio);
-
- bvec_set_folio(&bq->bv[slot], folio, len, 0);
- loaded += len;
- trace_netfs_folio(folio, netfs_folio_trace_read);
- }
-
- bvecq_filled_to(bq, nr);
- }
-
- WRITE_ONCE(roll->iter.count, loaded);
- iov_iter_bvec_queue(&roll->iter, ITER_DEST, roll->tail, 0, 0, loaded);
- return loaded;
-
-nomem_unlock:
- for (bq = roll->tail; bq; bq = bq->next) {
- for (int slot = 0; slot < bq->nr_slots; slot++) {
- struct folio *folio = bvec_folio(&bq->bv[slot]);
-
- folio_unlock(folio);
- folio_put(folio);
- }
- }
- rolling_buffer_clear(roll);
- roll->head = NULL;
- roll->tail = NULL;
- return -ENOMEM;
-}
-
-/*
- * Append a folio to the rolling buffer.
- */
-ssize_t rolling_buffer_append(struct rolling_buffer *roll, struct folio *folio,
- gfp_t gfp)
-{
- ssize_t size = folio_size(folio);
- int slot;
-
- if (rolling_buffer_make_space(roll, gfp) < 0)
- return -ENOMEM;
-
- slot = roll->head->nr_slots;
- bvec_set_folio(&roll->head->bv[slot], folio, size, 0);
- bvecq_filled_to(roll->head, slot + 1);
-
- WRITE_ONCE(roll->iter.count, roll->iter.count + size);
- return size;
-}
-
-/*
- * Delete a spent buffer from a rolling queue and return the next in line. We
- * don't return the last buffer to keep the pointers independent, but return
- * NULL instead.
- */
-struct bvecq *rolling_buffer_delete_spent(struct rolling_buffer *roll)
-{
- struct bvecq *spent = roll->tail, *next = bvecq_next(spent);
-
- if (!next)
- return NULL;
- next->prev = NULL;
- roll->tail = next;
- spent->next = NULL;
- bvecq_put(spent);
- return next;
-}
-
-/*
- * Clear out a rolling queue.
- */
-void rolling_buffer_clear(struct rolling_buffer *roll)
-{
- bvecq_put(roll->tail);
-}
diff --git a/include/linux/rolling_buffer.h b/include/linux/rolling_buffer.h
deleted file mode 100644
index 5c0bc4221f01..000000000000
--- a/include/linux/rolling_buffer.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* 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@xxxxxxxxxx)
- */
-
-#ifndef _ROLLING_BUFFER_H
-#define _ROLLING_BUFFER_H
-
-#include <linux/bvecq.h>
-#include <linux/uio.h>
-
-/*
- * Rolling buffer. Whilst the buffer is live and in use, folios and bvecq
- * 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 bvecq 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 bvecq *head; /* Producer's insertion point */
- struct bvecq *tail; /* Consumer's removal point */
- struct iov_iter iter; /* Iterator tracking what's left in the buffer */
- u8 first_tail_slot; /* First slot in ->tail */
- bool for_writeback; /* T if being used for writeback */
-};
-
-int rolling_buffer_init(struct rolling_buffer *roll, unsigned int direction,
- gfp_t gfp, bool for_writeback);
-int rolling_buffer_make_space(struct rolling_buffer *roll, gfp_t gfp);
-ssize_t rolling_buffer_bulk_load_from_ra(struct rolling_buffer *roll,
- struct readahead_control *ractl,
- gfp_t gfp);
-ssize_t rolling_buffer_append(struct rolling_buffer *roll, struct folio *folio, gfp_t gfp);
-struct bvecq *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 */