* [PATCH pve-ceph] backport fix for BlueFS space leak on close
@ 2026-09-20 6:28 Kefu Chai
0 siblings, 0 replies; only message in thread
From: Kefu Chai @ 2026-09-20 6:28 UTC (permalink / raw)
To: pve-devel
BlueFS reserves space for each RocksDB file. Since 20.1.0, a tentacle
RC, it does not free the reserved but unused part when the file is
closed (PR #62224). That space stays in use until compaction deletes
the file.
For the user this means an OSD uses more space than its data needs. In
bad cases a 70MB file holds only a few kB of data. Clusters without
RocksDB sharding are affected most. If DB and block are on the same
device, the free space of a pool goes up and down, while the stored
data does not change (https://tracker.ceph.com/issues/76256).
The fix is merged for main (https://github.com/ceph/ceph/pull/71479),
but its tentacle backport (https://github.com/ceph/ceph/pull/71855) is
still open, so no point release has it yet. Pick up its three commits
(most recent last):
* 8e68cb4b9bf0941fe3a2f20678844a0721de9904
* 21c357d88278eceb0beb9c69c837ad68517e2df4
* efe2e8d1bf0be327118da6e9e62f6132e6335c9e
They are the fix, a small cleanup asked for in review, and a missing
file lock in BlueFS::truncate()
(https://tracker.ceph.com/issues/80188). They drop out on the next
rebase.
Signed-off-by: Kefu Chai <k.chai@proxmox.com>
---
...-truncate-unused-allocation-on-close.patch | 395 ++++++++++++++++++
...16-bluefs-fix-use_direct_io-override.patch | 30 ++
...bluefs-acquire-file-lock-in-truncate.patch | 42 ++
patches/series | 3 +
4 files changed, 470 insertions(+)
create mode 100644 patches/0015-bluefs-truncate-unused-allocation-on-close.patch
create mode 100644 patches/0016-bluefs-fix-use_direct_io-override.patch
create mode 100644 patches/0017-bluefs-acquire-file-lock-in-truncate.patch
diff --git a/patches/0015-bluefs-truncate-unused-allocation-on-close.patch b/patches/0015-bluefs-truncate-unused-allocation-on-close.patch
new file mode 100644
index 0000000000..d17347e8ee
--- /dev/null
+++ b/patches/0015-bluefs-truncate-unused-allocation-on-close.patch
@@ -0,0 +1,395 @@
+From 8e68cb4b9bf0941fe3a2f20678844a0721de9904 Mon Sep 17 00:00:00 2001
+From: Viliam Durina <viliam.durina@gmail.com>
+Date: Tue, 1 Sep 2026 10:58:18 +0200
+Subject: [PATCH] os/bluestore: Re-introduce truncation in
+ `BlueRocksWritableFile.Close()`
+
+`rocksdb::WritableFile` assumes that whatever was allocated using `Allocate()`, and was not actually written to, is released when the file is closed (cf. `PosixWritableFile::Close()`). This used to work up to PR #62224 (released in 20.1.0, a tentacle RC), which removed the truncation from `close` and it assumed that `truncate` is called.
+
+This PR adds the truncation back to `BlueRocksWritableFile::Close()`. We cannot bring back the exact pre-62224 code, as it relies on `h->pos`. Instead we flush the file and use `fnode.size`, which contains the on-disk size, including the envelope.
+
+This should fix https://tracker.ceph.com/issues/76256.
+
+I'm not sure why this issue excessively affected clusters with no sharding. From the logs attached to the issue, in the non-sharded case there are many files with only a few kB payload in a 70MB file; in the sharded case the unreleased file tails still exist, but are much smaller.
+
+The new test case unit-tests the new `truncate_unused_allocations()` method, overall correctness of BlueFS operation is covered by other tests already. We also delete `BlueStoreWritableFile::UseDirectIO()`, as it is unused (it doesn't override superclass method).
+
+Fixes: https://tracker.ceph.com/issues/76256
+Signed-off-by: Viliam Durina <viliam.durina@gmail.com>
+(cherry picked from commit 88dca29d2dd99443826311723db375df96ddca5e)
+---
+ src/os/bluestore/BlueFS.cc | 31 ++++-
+ src/os/bluestore/BlueFS.h | 8 ++
+ src/os/bluestore/BlueRocksEnv.cc | 13 +-
+ src/test/objectstore/CMakeLists.txt | 7 +
+ src/test/objectstore/test_bluefs.cc | 65 +++++++++
+ src/test/objectstore/test_bluerocksenv.cc | 159 ++++++++++++++++++++++
+ 6 files changed, 275 insertions(+), 8 deletions(-)
+ create mode 100644 src/test/objectstore/test_bluerocksenv.cc
+
+diff --git a/src/os/bluestore/BlueFS.cc b/src/os/bluestore/BlueFS.cc
+index a30f3580a50a..54d49a368775 100644
+--- a/src/os/bluestore/BlueFS.cc
++++ b/src/os/bluestore/BlueFS.cc
+@@ -4313,9 +4313,8 @@ uint64_t BlueFS::_flush_special(FileWriter *h)
+ return new_data;
+ }
+
+-int BlueFS::truncate(FileWriter *h, uint64_t offset)/*_WF_L*/
++int BlueFS::truncate(FileWriter *h, uint64_t offset) /*_WF_L*/
+ {
+- auto t0 = mono_clock::now();
+ std::lock_guard hl(h->lock);
+ auto& fnode = h->file->fnode;
+
+@@ -4345,6 +4344,34 @@ int BlueFS::truncate(FileWriter *h, uint64_t offset)/*_WF_L*/
+ offset = h->file->fnode.size;
+ }
+ }
++ return _truncate_LDF(h, offset);
++}
++
++int BlueFS::truncate_unused(FileWriter *h) /*_WF_L*/
++{
++ std::lock_guard hl(h->lock);
++
++ // we never truncate internal log files
++ ceph_assert(h->file->fnode.ino > 1);
++
++ if (h->get_buffer_length()) {
++ int r = _flush_F(h, true);
++ if (r < 0)
++ return r;
++ }
++ // Everything this file will ever hold has been flushed by now, so truncating
++ // it to its current size gives back exactly the tail that preallocate() has
++ // reserved and that was never written to. This works for envelope mode files
++ // too, as fnode.size is the on-disk size there as well.
++ dout(10) << __func__ << " file " << h->file->fnode << dendl;
++ return _truncate_LDF(h, h->file->fnode.size);
++}
++
++int BlueFS::_truncate_LDF(FileWriter *h, uint64_t offset) /*_WF_WLDF*/
++{
++ auto t0 = mono_clock::now();
++ ceph_assert(ceph_mutex_is_locked(h->lock));
++ auto& fnode = h->file->fnode;
+ if (offset > fnode.size) {
+ ceph_abort_msg("truncate up not supported");
+ }
+diff --git a/src/os/bluestore/BlueFS.h b/src/os/bluestore/BlueFS.h
+index b320d57a951b..19e7d5178bd7 100644
+--- a/src/os/bluestore/BlueFS.h
++++ b/src/os/bluestore/BlueFS.h
+@@ -666,6 +666,11 @@ class BlueFS {
+ int _flush_data(FileWriter *h, uint64_t offset, uint64_t length, bool buffered);
+ int _flush_F(FileWriter *h, bool force, bool *flushed = nullptr);
+ int _flush_envelope_F(FileWriter *h);
++ // Truncates file to 'offset', which must be expressed in on-disk units
++ // (that is, envelopes included for envelope mode files) and must not be
++ // larger than the amount of data already flushed. Releases the allocations
++ // that fall past the new end of file.
++ int _truncate_LDF(FileWriter *h, uint64_t offset);
+ int _fsync(FileWriter *h, bool force_dirty);
+ uint64_t _flush_special(FileWriter *h);
+
+@@ -915,6 +920,9 @@ class BlueFS {
+ void invalidate_cache(FileRef f, uint64_t offset, uint64_t len);
+ int preallocate(FileRef f, uint64_t offset, uint64_t len);
+ int truncate(FileWriter *h, uint64_t offset);
++ // Releases the space that preallocate() has reserved for the file but that
++ // has not been written to. To be called when the file is done growing.
++ int truncate_unused(FileWriter *h);
+
+ size_t probe_alloc_avail(int dev, uint64_t alloc_size);
+
+diff --git a/src/os/bluestore/BlueRocksEnv.cc b/src/os/bluestore/BlueRocksEnv.cc
+index fc4f60e1fc9e..991a92c58d25 100644
+--- a/src/os/bluestore/BlueRocksEnv.cc
++++ b/src/os/bluestore/BlueRocksEnv.cc
+@@ -221,6 +221,13 @@ class BlueRocksWritableFile : public rocksdb::WritableFile {
+ }
+
+ rocksdb::Status Close() override {
++ // RocksDB assumes that when the file is closed, unused allocated
++ // space is truncated. It's not explicitly documented, but compare
++ // PosixWritableFile::Close().
++ int r = fs->truncate_unused(h);
++ if (r < 0) {
++ return err_to_status(r);
++ }
+ fs->fsync(h);
+ return rocksdb::Status::OK();
+ }
+@@ -241,12 +248,6 @@ class BlueRocksWritableFile : public rocksdb::WritableFile {
+ return true;
+ }
+
+- // Indicates the upper layers if the current WritableFile implementation
+- // uses direct IO.
+- bool UseDirectIO() const {
+- return false;
+- }
+-
+ void SetWriteLifeTimeHint(rocksdb::Env::WriteLifeTimeHint hint) override {
+ h->write_hint = (const int)hint;
+ }
+diff --git a/src/test/objectstore/CMakeLists.txt b/src/test/objectstore/CMakeLists.txt
+index d72d99ec37cc..f0960c2eb3bf 100644
+--- a/src/test/objectstore/CMakeLists.txt
++++ b/src/test/objectstore/CMakeLists.txt
+@@ -126,6 +126,13 @@ if(WITH_BLUESTORE)
+ add_ceph_unittest(unittest_bluefs)
+ target_link_libraries(unittest_bluefs os global)
+
++ # unittest_bluerocksenv
++ add_executable(unittest_bluerocksenv
++ test_bluerocksenv.cc
++ )
++ add_ceph_unittest(unittest_bluerocksenv)
++ target_link_libraries(unittest_bluerocksenv os global RocksDB::RocksDB)
++
+ # unittest_bluefs_ex
+ add_executable(unittest_bluefs_ex
+ test_bluefs_ex.cc
+diff --git a/src/test/objectstore/test_bluefs.cc b/src/test/objectstore/test_bluefs.cc
+index ab0501cd8c24..0bc926a7236a 100644
+--- a/src/test/objectstore/test_bluefs.cc
++++ b/src/test/objectstore/test_bluefs.cc
+@@ -2244,6 +2244,71 @@ TEST(BlueFS, truncate_drops_allocations) {
+
+
+
++// Space reserved by preallocate() but never written to has to be given back
++// when truncate_unused_allocations() is called.
++TEST(BlueFS, truncate_unused_allocations) {
++ constexpr uint64_t K = 1024;
++ constexpr uint64_t M = 1024 * K;
++ uuid_d fsid;
++ const char* DIR_NAME = "dir";
++ const char* FILE_NAME = "file1";
++ constexpr uint64_t alloc_unit = 64 * K;
++ constexpr uint64_t db_size = 128 * M;
++ struct {
++ uint64_t preallocated_size;
++ uint64_t write_size;
++ uint64_t allocated_after_drop;
++ } scenarios [] = {
++ // preallocate 8M, write a single byte, a single AU is to remain
++ { 8*M, 1, 64*K },
++ // preallocate 8M, write 1M + 1, 1M + one AU is to remain
++ { 8*M, 1*M + 1, 1*M + 64*K },
++ // preallocated space fully used, nothing to give back
++ { 1*M, 1*M, 1*M },
++ // nothing preallocated, nothing to give back either
++ { 0, 123*K, 128*K },
++ };
++ for (auto& s : scenarios) {
++ ConfSaver conf(g_ceph_context->_conf);
++ conf.SetVal("bluefs_shared_alloc_size", stringify(alloc_unit).c_str());
++ conf.SetVal("bluefs_alloc_size", stringify(1*M).c_str());
++
++ TempBdev bdev_db{db_size};
++
++ bluefs_shared_alloc_context_t shared_alloc;
++ shared_alloc.set(
++ Allocator::create(g_ceph_context, g_ceph_context->_conf->bluefs_allocator,
++ db_size, alloc_unit, "test shared allocator"),
++ alloc_unit);
++ shared_alloc.a->init_add_free(0, db_size);
++
++ BlueFS fs(g_ceph_context);
++ ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, bdev_db.path, false,
++ &shared_alloc));
++ ASSERT_EQ(0, fs.mkfs(fsid, {BlueFS::BDEV_DB, false, false}));
++ ASSERT_EQ(0, fs.mount());
++ ASSERT_EQ(0, fs.maybe_verify_layout({BlueFS::BDEV_DB, false, false}));
++ BlueFS::FileWriter *h;
++ ASSERT_EQ(0, fs.mkdir(DIR_NAME));
++ ASSERT_EQ(0, fs.open_for_write(DIR_NAME, FILE_NAME, &h, false));
++ uint64_t pre = fs.get_used();
++ ASSERT_EQ(0, fs.preallocate(h->file, 0, s.preallocated_size));
++ const std::string content(s.write_size, 'x');
++ h->append(content.c_str(), content.length());
++ fs.fsync(h);
++ ASSERT_EQ(0, fs.truncate_unused(h));
++ fs.fsync(h);
++ uint64_t post = fs.get_used();
++ // no data may be lost by giving the unused tail back
++ EXPECT_EQ(s.write_size, h->file->fnode.size);
++ fs.close_writer(h);
++ EXPECT_EQ(pre, post - s.allocated_after_drop);
++
++ fs.umount();
++ delete shared_alloc.a;
++ }
++}
++
+ TEST(BlueFS, test_log_runway) {
+ uint64_t max_log_runway = 65536;
+ ConfSaver conf(g_ceph_context->_conf);
+diff --git a/src/test/objectstore/test_bluerocksenv.cc b/src/test/objectstore/test_bluerocksenv.cc
+new file mode 100644
+index 000000000000..201de7696d10
+--- /dev/null
++++ b/src/test/objectstore/test_bluerocksenv.cc
+@@ -0,0 +1,159 @@
++// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
++// vim: ts=8 sw=2 sts=2 expandtab
++
++#include <stdio.h>
++#include <string.h>
++#include <fcntl.h>
++#include <unistd.h>
++#include <stack>
++#include <string>
++#include <vector>
++#include <gtest/gtest.h>
++
++#include "common/ceph_argparse.h"
++#include "global/global_init.h"
++#include "include/intarith.h"
++#include "include/stringify.h"
++
++#include "os/bluestore/BlueFS.h"
++#include "os/bluestore/BlueRocksEnv.h"
++
++#include "rocksdb/db.h"
++#include "rocksdb/options.h"
++
++using namespace std;
++
++class TempBdev {
++public:
++ TempBdev(uint64_t size)
++ : path{get_temp_bdev(size)}
++ {}
++ ~TempBdev() {
++ rm_temp_bdev(path);
++ }
++ const std::string path;
++private:
++ static string get_temp_bdev(uint64_t size)
++ {
++ static int n = 0;
++ string fn = "ceph_test_bluerocksenv.tmp.block." + stringify(getpid())
++ + "." + stringify(++n);
++ int fd = ::open(fn.c_str(), O_CREAT|O_RDWR|O_TRUNC, 0644);
++ ceph_assert(fd >= 0);
++ int r = ::ftruncate(fd, size);
++ ceph_assert(r >= 0);
++ ::close(fd);
++ return fn;
++ }
++ static void rm_temp_bdev(string f)
++ {
++ ::unlink(f.c_str());
++ }
++};
++
++class ConfSaver {
++ std::stack<std::pair<std::string, std::string>> saved_settings;
++ ConfigProxy& conf;
++public:
++ ConfSaver(ConfigProxy& conf) : conf(conf) {
++ conf._clear_safe_to_start_threads();
++ };
++ ~ConfSaver() {
++ conf._clear_safe_to_start_threads();
++ while(saved_settings.size() > 0) {
++ auto& e = saved_settings.top();
++ conf.set_val_or_die(e.first, e.second);
++ saved_settings.pop();
++ }
++ conf.set_safe_to_start_threads();
++ conf.apply_changes(nullptr);
++ }
++ void SetVal(const char* key, const char* val) {
++ std::string skey(key);
++ std::string prev_val;
++ conf.get_val(skey, &prev_val);
++ conf.set_val_or_die(skey, val);
++ saved_settings.emplace(skey, prev_val);
++ }
++};
++
++// End-to-end regression test for https://tracker.ceph.com/issues/76256.
++//
++// RocksDB preallocates space for the files it writes via
++// WritableFile::Allocate(), and expects the unused tail to be released when
++// the file is closed. It doesn't call Truncate() for that.
++TEST(BlueRocksEnv, close_releases_preallocated_tail) {
++ constexpr uint64_t alloc_unit = 4 << 10;
++ const char* DB_DIR = "db";
++
++ ConfSaver conf(g_ceph_context->_conf);
++ conf.SetVal("bluefs_shared_alloc_size", stringify(alloc_unit).c_str());
++ conf.SetVal("bluefs_alloc_size", stringify(alloc_unit).c_str());
++
++ uuid_d fsid;
++ TempBdev bdev_db{(64 << 20)};
++
++ BlueFS fs(g_ceph_context);
++ ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, bdev_db.path, false));
++ ASSERT_EQ(0, fs.mkfs(fsid, {BlueFS::BDEV_DB, false, false}));
++ ASSERT_EQ(0, fs.mount());
++ ASSERT_EQ(0, fs.maybe_verify_layout({BlueFS::BDEV_DB, false, false}));
++ ASSERT_EQ(0, fs.mkdir(DB_DIR));
++
++ auto make_options = [&](BlueRocksEnv* env) {
++ rocksdb::Options options;
++ options.env = env;
++ options.create_if_missing = true;
++ // use smallest possible sizes to speed up the test
++ options.write_buffer_size = 64 << 10;
++ options.manifest_preallocation_size = 64 << 10;
++ return options;
++ };
++
++ // create a database
++ {
++ BlueRocksEnv env(&fs);
++ rocksdb::DB* db = nullptr;
++ ASSERT_TRUE(rocksdb::DB::Open(make_options(&env), DB_DIR, &db).ok());
++ ASSERT_TRUE(db->Put(rocksdb::WriteOptions(), "key", "v").ok());
++ // Close the db without flushing the memtable, so that the WAL and the MANIFEST are
++ // closed but stay alive -- the state in which the preallocated tails were leaked.
++ ASSERT_TRUE(db->Close().ok());
++ delete db;
++ }
++
++ std::vector<std::string> ls;
++ ASSERT_EQ(0, fs.readdir(DB_DIR, &ls));
++ ASSERT_LT(3, ls.size());
++ for (std::string& fname : ls) {
++ if (fname == "." || fname == "..") {
++ continue;
++ }
++ BlueFS::FileReader* r;
++ ASSERT_EQ(0, fs.open_for_read(DB_DIR, fname, &r));
++ auto& fnode = r->file->fnode;
++ // This is what was fixed in the issue - the file held allocated more than necessary
++ EXPECT_EQ(p2roundup(fnode.size, alloc_unit), fnode.get_allocated())
++ << DB_DIR << "/" << fname << " holds " << fnode.get_allocated()
++ << " bytes for " << fnode.size << " bytes of data";
++ delete r;
++ }
++
++ fs.umount();
++}
++
++int main(int argc, char **argv) {
++ auto args = argv_to_vec(argc, argv);
++ map<string,string> defaults = {
++ { "debug_bluefs", "1/20" },
++ { "debug_bdev", "1/20" }
++ };
++
++ auto cct = global_init(&defaults, args, CEPH_ENTITY_TYPE_CLIENT,
++ CODE_ENVIRONMENT_UTILITY,
++ CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
++ common_init_finish(g_ceph_context);
++
++ ::testing::InitGoogleTest(&argc, argv);
++ return RUN_ALL_TESTS();
++}
diff --git a/patches/0016-bluefs-fix-use_direct_io-override.patch b/patches/0016-bluefs-fix-use_direct_io-override.patch
new file mode 100644
index 0000000000..9ed610747a
--- /dev/null
+++ b/patches/0016-bluefs-fix-use_direct_io-override.patch
@@ -0,0 +1,30 @@
+From 21c357d88278eceb0beb9c69c837ad68517e2df4 Mon Sep 17 00:00:00 2001
+From: Viliam Durina <viliam.durina@gmail.com>
+Date: Wed, 2 Sep 2026 15:35:19 +0200
+Subject: [PATCH] os/bluestore: Fix `use_direct_io()` override
+
+Requested here: https://github.com/ceph/ceph/pull/71479#discussion_r3914283440
+
+Signed-off-by: Viliam Durina <viliam.durina@gmail.com>
+(cherry picked from commit aa054f89c99dbac553b0e12b9670ee46b99758b8)
+---
+ src/os/bluestore/BlueRocksEnv.cc | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/src/os/bluestore/BlueRocksEnv.cc b/src/os/bluestore/BlueRocksEnv.cc
+index 991a92c58d25..673af2d729ae 100644
+--- a/src/os/bluestore/BlueRocksEnv.cc
++++ b/src/os/bluestore/BlueRocksEnv.cc
+@@ -248,6 +248,12 @@ class BlueRocksWritableFile : public rocksdb::WritableFile {
+ return true;
+ }
+
++ // Indicates the upper layers if the current WritableFile implementation
++ // uses direct IO.
++ bool use_direct_io() const override {
++ return false;
++ }
++
+ void SetWriteLifeTimeHint(rocksdb::Env::WriteLifeTimeHint hint) override {
+ h->write_hint = (const int)hint;
+ }
diff --git a/patches/0017-bluefs-acquire-file-lock-in-truncate.patch b/patches/0017-bluefs-acquire-file-lock-in-truncate.patch
new file mode 100644
index 0000000000..98a1aacf77
--- /dev/null
+++ b/patches/0017-bluefs-acquire-file-lock-in-truncate.patch
@@ -0,0 +1,42 @@
+From efe2e8d1bf0be327118da6e9e62f6132e6335c9e Mon Sep 17 00:00:00 2001
+From: Igor Fedotov <igor.fedotov@croit.io>
+Date: Wed, 2 Sep 2026 12:24:57 +0300
+Subject: [PATCH] os/bluestore: do acquire file lock in BlueFS::truncate
+
+Fixes: https://tracker.ceph.com/issues/80188
+Signed-off-by: Igor Fedotov <igor.fedotov@croit.io>
+(cherry picked from commit 481ebbd14cd36ae55f2aea305d5ac8bcf5ae4ef0)
+---
+ src/os/bluestore/BlueFS.cc | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/src/os/bluestore/BlueFS.cc b/src/os/bluestore/BlueFS.cc
+index 54d49a368775..ed848dd876a6 100644
+--- a/src/os/bluestore/BlueFS.cc
++++ b/src/os/bluestore/BlueFS.cc
+@@ -4313,7 +4313,7 @@ uint64_t BlueFS::_flush_special(FileWriter *h)
+ return new_data;
+ }
+
+-int BlueFS::truncate(FileWriter *h, uint64_t offset) /*_WF_L*/
++int BlueFS::truncate(FileWriter *h, uint64_t offset) /*_WF_WLDF*/
+ {
+ std::lock_guard hl(h->lock);
+ auto& fnode = h->file->fnode;
+@@ -4347,7 +4347,7 @@ int BlueFS::truncate(FileWriter *h, uint64_t offset) /*_WF_L*/
+ return _truncate_LDF(h, offset);
+ }
+
+-int BlueFS::truncate_unused(FileWriter *h) /*_WF_L*/
++int BlueFS::truncate_unused(FileWriter *h) /*_WF_WLDF*/
+ {
+ std::lock_guard hl(h->lock);
+
+@@ -4380,6 +4380,7 @@ int BlueFS::_truncate_LDF(FileWriter *h, uint64_t offset) /*_WF_WLDF*/
+ {
+ std::lock_guard ll(log.lock);
+ std::lock_guard dl(dirty.lock);
++ std::lock_guard fl(h->file->lock);
+ if (h->file->deleted) {
+ dout(10) << __func__ << " deleted, no-op" << dendl;
+ return 0;
diff --git a/patches/series b/patches/series
index 0a22ad5bba..99ac6daf8a 100644
--- a/patches/series
+++ b/patches/series
@@ -12,3 +12,6 @@
0012-mgr-fix-module-import-by-making-NOTIFY_TYPES-in-py-m.patch
0013-pybind-rbd-disable-on_progress-callbacks-to-prevent-.patch
0014-restore-the-auth_supported-config-option.patch
+0015-bluefs-truncate-unused-allocation-on-close.patch
+0016-bluefs-fix-use_direct_io-override.patch
+0017-bluefs-acquire-file-lock-in-truncate.patch
--
2.47.3
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-09-20 6:28 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-20 6:28 [PATCH pve-ceph] backport fix for BlueFS space leak on close Kefu Chai
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox