Skip to content

Commit 88ad48a

Browse files
committed
Purge root caches after subvolume deletion
- Clear subprocess roots cache on SIGUSR1 signal to force re-resolution of roots after deletion - Add generation checks to skip processing stale NewRootMessage and inode result messages in the main process - Track deleted subvolume IDs during the deletion process - Remove deleted subvolumes from globalRoots after deletion completes This ensures deleted subvolumes are properly purged from all caches and prevents stale root information from being processed after deletion.
1 parent aa3c00e commit 88ad48a

File tree

4 files changed

+33
-2
lines changed

4 files changed

+33
-2
lines changed

source/btdu/sample.d

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,12 +324,15 @@ struct Root
324324
Root[u64] roots;
325325
uint generation;
326326

327-
/// Set up SIGUSR1 handler to increment generation counter.
328-
/// This causes in-flight samples to be discarded by the main process.
327+
/// Set up SIGUSR1 handler to invalidate root cache and increment generation.
328+
/// This causes the subprocess to re-resolve roots and the main process to
329+
/// discard in-flight samples.
329330
void setupCacheInvalidationHandler()
330331
{
331332
sigaction_t sa;
332333
sa.sa_handler = (int) {
334+
// Clear the roots cache - will be repopulated on next access
335+
roots = null;
333336
generation++;
334337
};
335338
sigemptyset(&sa.sa_mask);

source/btdu/subproc.d

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ struct Subprocess
162162

163163
void handleMessage(NewRootMessage m)
164164
{
165+
// Discard root info from before the last deletion
166+
if (m.generation < currentGeneration)
167+
return;
168+
165169
if (m.rootID in globalRoots)
166170
return;
167171

@@ -257,6 +261,10 @@ struct Subprocess
257261

258262
void handleMessage(ResultInodeStartMessage m)
259263
{
264+
// Skip processing if this sample will be discarded anyway
265+
if (result.generation < currentGeneration)
266+
return;
267+
260268
result.haveInode = true;
261269
result.havePath = false;
262270
result.inodeRoot = (m.rootID in globalRoots).enforce("Unknown inode root");
@@ -267,25 +275,33 @@ struct Subprocess
267275

268276
void handleMessage(ResultInodeErrorMessage m)
269277
{
278+
if (result.generation < currentGeneration)
279+
return;
270280
allPaths ~= GlobalPath(result.inodeRoot.path, subPathRoot.appendError(m.error));
271281
result.category = DiskMap.SectorCategory.error;
272282
}
273283

274284
void handleMessage(ResultMessage m)
275285
{
286+
if (result.generation < currentGeneration)
287+
return;
276288
result.havePath = true;
277289
allPaths ~= GlobalPath(result.inodeRoot.path, subPathRoot.appendPath(m.path));
278290
}
279291

280292
void handleMessage(ResultInodeEndMessage m)
281293
{
294+
if (result.generation < currentGeneration)
295+
return;
282296
cast(void) m; // empty message
283297
if (!result.havePath)
284298
allPaths ~= GlobalPath(result.inodeRoot.path, subPathRoot.appendPath("\0NO_PATH"));
285299
}
286300

287301
void handleMessage(ResultErrorMessage m)
288302
{
303+
if (result.generation < currentGeneration)
304+
return;
289305
import core.stdc.errno : ENOENT;
290306
allPaths ~= GlobalPath(null, subPathRoot.appendError(m.error));
291307
result.haveInode = true;

source/btdu/ui/browser.d

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,9 @@ struct Browser
402402
showMessage(format!"Deleted %s."(deleter.items[0].browserPath.humanName));
403403
else
404404
showMessage(format!"Deleted %d item%s."(deleter.items.length, deleter.items.length > 1 ? "s" : ""));
405+
// Purge deleted subvolumes from the root cache
406+
foreach (subvolumeID; deleter.deletedSubvolumeIDs)
407+
globalRoots.remove(subvolumeID);
405408
foreach (item; deleter.items)
406409
item.browserPath.remove(item.obeyMarks);
407410
invalidateMark();

source/btdu/ui/deletion.d

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import core.thread : Thread;
3333
import ae.sys.file : listDir, getMounts;
3434

3535
import btrfs : getSubvolumeID, deleteSubvolume;
36+
import btrfs.c.kerncompat : u64;
3637

3738
import btdu.paths : BrowserPath, Mark;
3839
import btdu.state : toFilesystemPath;
@@ -85,6 +86,9 @@ struct Deleter
8586
}
8687
Item[] items;
8788

89+
/// Subvolume IDs that were deleted (collected during deletion for cache purging)
90+
u64[] deletedSubvolumeIDs;
91+
8892
void prepare(Item[] items)
8993
{
9094
assert(this.state.status == Status.none);
@@ -105,6 +109,7 @@ struct Deleter
105109
assert(this.state.status == Status.ready);
106110
this.state.stopping = false;
107111
this.state.status = Status.progress;
112+
this.deletedSubvolumeIDs = null;
108113
this.subvolumeResume.initialize(false, false);
109114
this.thread = new Thread(&threadFunc);
110115
this.thread.start();
@@ -181,6 +186,10 @@ struct Deleter
181186
auto subvolumeID = getSubvolumeID(fd);
182187
deleteSubvolume(fd, subvolumeID);
183188

189+
// Track deleted subvolume for cache purging
190+
synchronized (this.thread)
191+
this.deletedSubvolumeIDs ~= subvolumeID;
192+
184193
this.state.status = Status.progress;
185194
return; // The ioctl will also unlink the directory entry
186195
}

0 commit comments

Comments
 (0)