Skip to content

Commit e5f8892

Browse files
committed
os/bluestore/bluefs: Fix race condition between truncate() and unlink()
It was possible for unlink() to interrupt ongoing truncate(). As the result, unlink() finishes properly, but truncate() is not aware of it and does: 1) updates file that is already removed 2) releases same allocations again Now fixed by checking if file is deleted under FILE lock. https://tracker.ceph.com/issues/70747 Signed-off-by: Adam Kupczyk <[email protected]>
1 parent d7f0b6a commit e5f8892

File tree

2 files changed

+19
-16
lines changed

2 files changed

+19
-16
lines changed

src/os/bluestore/BlueFS.cc

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2221,7 +2221,7 @@ std::ostream& operator<<(std::ostream& out, const lock_fnode_print& to_lock) {
22212221
return out;
22222222
}
22232223

2224-
void BlueFS::_drop_link_D(FileRef file)
2224+
void BlueFS::_drop_link_DF(FileRef file)
22252225
{
22262226
dout(20) << __func__ << " had refs " << file->refs
22272227
<< " on " << lock_fnode_print(file) << dendl;
@@ -2237,9 +2237,11 @@ void BlueFS::_drop_link_D(FileRef file)
22372237
log.t.op_file_remove(file->fnode.ino);
22382238
nodes.file_map.erase(file->fnode.ino);
22392239
logger->set(l_bluefs_num_files, nodes.file_map.size());
2240-
file->deleted = true;
2241-
22422240
std::lock_guard dl(dirty.lock);
2241+
std::lock_guard fl(file->lock);
2242+
// setting `deleted` is under log+nodes+dirty+file locks
2243+
// so it is enough to held one of those locks to make sure it does not change
2244+
file->deleted = true;
22432245
for (auto& r : file->fnode.extents) {
22442246
dirty.pending_release[r.bdev].insert(r.offset, r.length);
22452247
}
@@ -3563,10 +3565,6 @@ int BlueFS::_flush_range_F(FileWriter *h, uint64_t offset, uint64_t length)
35633565
<< " to " << h->file->fnode
35643566
<< " hint " << h->file->vselector_hint
35653567
<< dendl;
3566-
if (h->file->deleted) {
3567-
dout(10) << __func__ << " deleted, no-op" << dendl;
3568-
return 0;
3569-
}
35703568

35713569
bool buffered = cct->_conf->bluefs_buffered_io;
35723570

@@ -3580,6 +3578,10 @@ int BlueFS::_flush_range_F(FileWriter *h, uint64_t offset, uint64_t length)
35803578
<< dendl;
35813579
}
35823580
std::lock_guard file_lock(h->file->lock);
3581+
if (h->file->deleted) {
3582+
dout(10) << __func__ << " deleted, no-op" << dendl;
3583+
return 0;
3584+
}
35833585
ceph_assert(offset <= h->file->fnode.size);
35843586

35853587
uint64_t allocated = h->file->fnode.get_allocated();
@@ -3836,16 +3838,13 @@ int BlueFS::truncate(FileWriter *h, uint64_t offset)/*_WF_L*/
38363838
auto t0 = mono_clock::now();
38373839
std::lock_guard hl(h->lock);
38383840
auto& fnode = h->file->fnode;
3839-
dout(10) << __func__ << " 0x" << std::hex << offset << std::dec
3840-
<< " file " << fnode << dendl;
3841-
if (h->file->deleted) {
3842-
dout(10) << __func__ << " deleted, no-op" << dendl;
3843-
return 0;
3844-
}
38453841

38463842
// we never truncate internal log files
38473843
ceph_assert(fnode.ino > 1);
38483844

3845+
dout(10) << __func__ << " 0x" << std::hex << offset << std::dec
3846+
<< " file " << fnode << dendl;
3847+
38493848
// truncate off unflushed data?
38503849
if (h->pos < offset &&
38513850
h->pos + h->get_buffer_length() > offset) {
@@ -3866,6 +3865,10 @@ int BlueFS::truncate(FileWriter *h, uint64_t offset)/*_WF_L*/
38663865
{
38673866
std::lock_guard ll(log.lock);
38683867
std::lock_guard dl(dirty.lock);
3868+
if (h->file->deleted) {
3869+
dout(10) << __func__ << " deleted, no-op" << dendl;
3870+
return 0;
3871+
}
38693872
bool changed_extents = false;
38703873
vselector->sub_usage(h->file->vselector_hint, fnode);
38713874
uint64_t x_off = 0;
@@ -4456,7 +4459,7 @@ int BlueFS::rename(
44564459
<< " already exists, unlinking" << dendl;
44574460
ceph_assert(q->second != file);
44584461
log.t.op_dir_unlink(new_dirname, new_filename);
4459-
_drop_link_D(q->second);
4462+
_drop_link_DF(q->second);
44604463
}
44614464

44624465
dout(10) << __func__ << " " << new_dirname << "/" << new_filename << " "
@@ -4651,7 +4654,7 @@ int BlueFS::unlink(std::string_view dirname, std::string_view filename)/*_LND*/
46514654
}
46524655
dir->file_map.erase(q);
46534656
log.t.op_dir_unlink(dirname, filename);
4654-
_drop_link_D(file);
4657+
_drop_link_DF(file);
46554658
logger->tinc(l_bluefs_unlink_lat, mono_clock::now() - t0);
46564659

46574660
return 0;

src/os/bluestore/BlueFS.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ class BlueFS {
563563
uint64_t _get_minimal_reserved(unsigned id) const;
564564

565565
FileRef _get_file(uint64_t ino);
566-
void _drop_link_D(FileRef f);
566+
void _drop_link_DF(FileRef f);
567567

568568
unsigned _get_slow_device_id() {
569569
return bdev[BDEV_SLOW] ? BDEV_SLOW : BDEV_DB;

0 commit comments

Comments
 (0)