[PATCH v2 19/79] ssdfs: introduce segment block bitmap
From: Viacheslav Dubeyko
Date: Sun Mar 15 2026 - 22:23:09 EST
Complete patchset is available here:
https://github.com/dubeyko/ssdfs-driver/tree/master/patchset/linux-kernel-6.18.0
SSDFS splits a partition/volume on sequence of fixed-sized
segments. Every segment can include one or several Logical
Erase Blocks (LEB). LEB can be mapped into "Physical" Erase
Block (PEB). PEB block bitmap object represents the aggregation
of source PEB's block bitmap and destination PEB's block bitmap.
Finally, segment block bitmap implements an array of PEB block
bitmaps. Segment block bitmap has API:
(1) create - create segment block bitmap
(2) destroy - destroy segment block bitmap
(3) partial_init - initialize by state of one PEB block bitmap
(4) get_free_pages - get free pages in segment block bitmap
(5) get_used_pages - get used pages in segment block bitmap
(6) get_invalid_pages - get invalid pages in segment block bitmap
(7) reserve_block - reserve a free block
(8) reserved_extent - reserve some number of free blocks
(9) pre_allocate - pre_allocate page/range in segment block bitmap
(10) allocate - allocate page/range in segment block bitmap
(11) update_range - change the state of range in segment block bitmap
Signed-off-by: Viacheslav Dubeyko <slava@xxxxxxxxxxx>
---
fs/ssdfs/segment_block_bitmap.h | 240 ++++++++++++++++++++++++++++++++
1 file changed, 240 insertions(+)
create mode 100644 fs/ssdfs/segment_block_bitmap.h
diff --git a/fs/ssdfs/segment_block_bitmap.h b/fs/ssdfs/segment_block_bitmap.h
new file mode 100644
index 000000000000..7ee7e39972ef
--- /dev/null
+++ b/fs/ssdfs/segment_block_bitmap.h
@@ -0,0 +1,240 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause-Clear
+ *
+ * SSDFS -- SSD-oriented File System.
+ *
+ * fs/ssdfs/segment_block_bitmap.h - segment's block bitmap declarations.
+ *
+ * Copyright (c) 2014-2019 HGST, a Western Digital Company.
+ * http://www.hgst.com/
+ * Copyright (c) 2014-2026 Viacheslav Dubeyko <slava@xxxxxxxxxxx>
+ * http://www.ssdfs.org/
+ *
+ * (C) Copyright 2014-2019, HGST, Inc., All rights reserved.
+ *
+ * Created by HGST, San Jose Research Center, Storage Architecture Group
+ *
+ * Authors: Viacheslav Dubeyko <slava@xxxxxxxxxxx>
+ *
+ * Acknowledgement: Cyril Guyot
+ * Zvonimir Bandic
+ */
+
+#ifndef _SSDFS_SEGMENT_BLOCK_BITMAP_H
+#define _SSDFS_SEGMENT_BLOCK_BITMAP_H
+
+#include "peb_block_bitmap.h"
+
+/*
+ * struct ssdfs_segment_blk_bmap - segment block bitmap object
+ * @state: segment block bitmap's state
+ * @pages_per_peb: pages per physical erase block
+ * @pages_per_seg: pages per segment
+ * @modification_lock: lock for modification operations
+ * @seg_valid_blks: segment's valid logical blocks count
+ * @seg_invalid_blks: segment's invalid logical blocks count
+ * @seg_free_blks: segment's free logical blocks count
+ * @seg_reserved_metapages: number of reserved metapages
+ * @peb: array of PEB block bitmap objects
+ * @pebs_count: PEBs count in segment
+ * @parent_si: pointer on parent segment object
+ */
+struct ssdfs_segment_blk_bmap {
+ atomic_t state;
+
+ u32 pages_per_peb;
+ u32 pages_per_seg;
+
+ struct rw_semaphore modification_lock;
+ atomic_t seg_valid_blks;
+ atomic_t seg_invalid_blks;
+ atomic_t seg_free_blks;
+ atomic_t seg_reserved_metapages;
+
+ struct ssdfs_peb_blk_bmap *peb;
+ u16 pebs_count;
+
+ struct ssdfs_segment_info *parent_si;
+};
+
+/* Segment block bitmap's possible states */
+enum {
+ SSDFS_SEG_BLK_BMAP_STATE_UNKNOWN,
+ SSDFS_SEG_BLK_BMAP_CREATED,
+ SSDFS_SEG_BLK_BMAP_STATE_MAX,
+};
+
+/*
+ * Segment block bitmap API
+ */
+int ssdfs_segment_blk_bmap_create(struct ssdfs_segment_info *si,
+ int init_flag, int init_state);
+void ssdfs_segment_blk_bmap_destroy(struct ssdfs_segment_blk_bmap *ptr);
+int ssdfs_segment_blk_bmap_partial_init(struct ssdfs_segment_blk_bmap *bmap,
+ u16 peb_index,
+ struct ssdfs_folio_vector *source,
+ struct ssdfs_block_bitmap_fragment *hdr,
+ u32 peb_free_pages, u64 cno);
+int ssdfs_segment_blk_bmap_partial_inflate(struct ssdfs_segment_blk_bmap *bmap,
+ u16 peb_index, u32 free_items);
+int
+ssdfs_segment_blk_bmap_partial_clean_init(struct ssdfs_segment_blk_bmap *bmap,
+ u16 peb_index);
+void ssdfs_segment_blk_bmap_init_failed(struct ssdfs_segment_blk_bmap *bmap,
+ u16 peb_index);
+
+bool is_ssdfs_segment_blk_bmap_dirty(struct ssdfs_segment_blk_bmap *bmap,
+ u16 peb_index);
+
+bool has_ssdfs_segment_blk_bmap_initialized(struct ssdfs_segment_blk_bmap *ptr,
+ struct ssdfs_peb_container *pebc);
+int ssdfs_segment_blk_bmap_wait_init_end(struct ssdfs_segment_blk_bmap *ptr,
+ struct ssdfs_peb_container *pebc);
+
+int ssdfs_segment_blk_bmap_get_block_state(struct ssdfs_segment_blk_bmap *ptr,
+ struct ssdfs_peb_info *pebi,
+ u32 blk);
+int ssdfs_segment_blk_bmap_reserve_metapages(struct ssdfs_segment_blk_bmap *ptr,
+ struct ssdfs_peb_info *pebi,
+ u32 count);
+int ssdfs_segment_blk_bmap_free_metapages(struct ssdfs_segment_blk_bmap *ptr,
+ struct ssdfs_peb_info *pebi,
+ u32 count);
+int ssdfs_segment_blk_bmap_reserve_block(struct ssdfs_segment_blk_bmap *ptr);
+int ssdfs_segment_blk_bmap_reserve_extent(struct ssdfs_segment_blk_bmap *ptr,
+ u32 count, u32 *reserved_blks);
+int ssdfs_segment_blk_bmap_release_extent(struct ssdfs_segment_blk_bmap *ptr,
+ u32 count);
+int ssdfs_segment_blk_bmap_pre_allocate(struct ssdfs_segment_blk_bmap *ptr,
+ struct ssdfs_peb_info *pebi,
+ struct ssdfs_block_bmap_range *range);
+int ssdfs_segment_blk_bmap_allocate(struct ssdfs_segment_blk_bmap *ptr,
+ struct ssdfs_peb_info *pebi,
+ struct ssdfs_block_bmap_range *range);
+int ssdfs_segment_blk_bmap_update_range(struct ssdfs_segment_blk_bmap *ptr,
+ struct ssdfs_peb_info *pebi,
+ u8 peb_migration_id,
+ int range_state,
+ struct ssdfs_block_bmap_range *range);
+
+/* Inline methods */
+
+static inline
+int __ssdfs_segment_blk_bmap_get_capacity(struct ssdfs_segment_blk_bmap *ptr)
+{
+ int capacity = 0;
+ int i;
+
+ for (i = 0; i < ptr->pebs_count; i++) {
+ capacity += atomic_read(&ptr->peb[i].peb_blks_capacity);
+ }
+
+ return capacity;
+}
+
+static inline
+int ssdfs_segment_blk_bmap_get_capacity(struct ssdfs_segment_blk_bmap *ptr)
+{
+ int capacity;
+
+ down_read(&ptr->modification_lock);
+ capacity = __ssdfs_segment_blk_bmap_get_capacity(ptr);
+ up_read(&ptr->modification_lock);
+
+ return capacity;
+}
+
+static inline
+bool is_pages_balance_correct(struct ssdfs_segment_blk_bmap *ptr)
+{
+#ifdef CONFIG_SSDFS_DEBUG
+ int free_blks;
+ int valid_blks;
+ int invalid_blks;
+ int capacity;
+ int calculated;
+
+ BUG_ON(!ptr);
+
+ down_read(&ptr->modification_lock);
+ free_blks = atomic_read(&ptr->seg_free_blks);
+ valid_blks = atomic_read(&ptr->seg_valid_blks);
+ invalid_blks = atomic_read(&ptr->seg_invalid_blks);
+ calculated = free_blks + valid_blks + invalid_blks;
+ capacity = __ssdfs_segment_blk_bmap_get_capacity(ptr);
+ up_read(&ptr->modification_lock);
+
+ BUG_ON(free_blks < 0);
+ BUG_ON(valid_blks < 0);
+ BUG_ON(invalid_blks < 0);
+ BUG_ON(capacity < 0);
+
+ SSDFS_DBG("free_logical_blks %d, valid_logical_blks %d, "
+ "invalid_logical_blks %d, capacity %d\n",
+ free_blks, valid_blks, invalid_blks,
+ capacity);
+
+ if (calculated > capacity) {
+ SSDFS_ERR("free_logical_blks %d, valid_logical_blks %d, "
+ "invalid_logical_blks %d, calculated %d, "
+ "capacity %d\n",
+ free_blks, valid_blks, invalid_blks,
+ calculated, capacity);
+ return false;
+ }
+
+ return true;
+#else
+ return true;
+#endif /* CONFIG_SSDFS_DEBUG */
+}
+
+static inline
+int ssdfs_segment_blk_bmap_get_free_pages(struct ssdfs_segment_blk_bmap *ptr)
+{
+ int free_blks;
+
+#ifdef CONFIG_SSDFS_DEBUG
+ WARN_ON(!is_pages_balance_correct(ptr));
+#endif /* CONFIG_SSDFS_DEBUG */
+
+ down_read(&ptr->modification_lock);
+ free_blks = atomic_read(&ptr->seg_free_blks);
+ up_read(&ptr->modification_lock);
+
+ return free_blks;
+}
+
+static inline
+int ssdfs_segment_blk_bmap_get_used_pages(struct ssdfs_segment_blk_bmap *ptr)
+{
+ int valid_blks;
+
+#ifdef CONFIG_SSDFS_DEBUG
+ WARN_ON(!is_pages_balance_correct(ptr));
+#endif /* CONFIG_SSDFS_DEBUG */
+
+ down_read(&ptr->modification_lock);
+ valid_blks = atomic_read(&ptr->seg_valid_blks);
+ up_read(&ptr->modification_lock);
+
+ return valid_blks;
+}
+
+static inline
+int ssdfs_segment_blk_bmap_get_invalid_pages(struct ssdfs_segment_blk_bmap *ptr)
+{
+ int invalid_blks;
+
+#ifdef CONFIG_SSDFS_DEBUG
+ WARN_ON(!is_pages_balance_correct(ptr));
+#endif /* CONFIG_SSDFS_DEBUG */
+
+ down_read(&ptr->modification_lock);
+ invalid_blks = atomic_read(&ptr->seg_invalid_blks);
+ up_read(&ptr->modification_lock);
+
+ return invalid_blks;
+}
+
+#endif /* _SSDFS_SEGMENT_BLOCK_BITMAP_H */
--
2.34.1