Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(native): BLKFLSBUF + drop_caches to release nvme after lazy unmount

The install-to-HD was failing because MNT_DETACH (lazy unmount) removes
the mount from the namespace but the kernel VFS holds block device
references via cached dentries/inodes/superblock. BLKRRPART and mkfs
both fail with EBUSY because the block layer still considers the device
exclusively held.

Fix: after unmounting, flush the block device buffer cache via BLKFLSBUF
ioctl on both the partition and whole disk, then drop all page/dentry/
inode caches before attempting sfdisk or mkfs. Also increase mkfs retry
count to 5 with BLKFLSBUF flush between each attempt.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+56 -9
+56 -9
fedac/native/src/ac-native.c
··· 1255 1255 ac_log("[install] force_unmount_disk(%s) released %d mounts\n", 1256 1256 parent_blk, n_unmounted); 1257 1257 sync(); 1258 - usleep(500000); 1258 + 1259 + // CRITICAL: After MNT_DETACH (lazy unmount), the kernel 1260 + // VFS still holds block device references from cached 1261 + // dentries/inodes/superblock. We MUST flush buffer cache 1262 + // on both the partition and whole disk via BLKFLSBUF, 1263 + // then drop page caches, before the block layer will 1264 + // release its exclusive hold. Without this, BLKRRPART 1265 + // and mkfs both fail with EBUSY. 1266 + { 1267 + // Flush buffer cache on partition 1268 + int pfd = open(devpath, O_RDONLY | O_CLOEXEC); 1269 + if (pfd >= 0) { 1270 + ioctl(pfd, BLKFLSBUF); 1271 + close(pfd); 1272 + ac_log("[install] BLKFLSBUF on %s: ok\n", devpath); 1273 + } 1274 + // Flush buffer cache on whole disk 1275 + char disk_dev[64]; 1276 + snprintf(disk_dev, sizeof(disk_dev), "/dev/%s", parent_blk); 1277 + int dfd = open(disk_dev, O_RDONLY | O_CLOEXEC); 1278 + if (dfd >= 0) { 1279 + ioctl(dfd, BLKFLSBUF); 1280 + close(dfd); 1281 + ac_log("[install] BLKFLSBUF on %s: ok\n", disk_dev); 1282 + } 1283 + // Drop all page/dentry/inode caches 1284 + system("echo 3 > /proc/sys/vm/drop_caches 2>/dev/null || true"); 1285 + sync(); 1286 + ac_log("[install] caches flushed + dropped\n"); 1287 + } 1288 + usleep(1000000); // 1s settle after cache flush 1259 1289 1260 1290 // Nuke the old filesystem signatures BEFORE sfdisk. This 1261 1291 // is critical: the old Fedora ESP's FAT boot sector and ··· 1344 1374 "fi", 1345 1375 DLOG, devpath, DLOG, DLOG, devpath, DLOG); 1346 1376 system(rcmd); 1347 - // Drop the kernel page cache so any lingering references 1348 - // to the old filesystem's cached pages are released. 1377 + // Aggressively flush block device buffer cache + page cache 1378 + // to release the kernel's exclusive hold on the partition. 1379 + { 1380 + int pfd = open(devpath, O_RDONLY | O_CLOEXEC); 1381 + if (pfd >= 0) { ioctl(pfd, BLKFLSBUF); close(pfd); } 1382 + char disk_dev2[64]; 1383 + snprintf(disk_dev2, sizeof(disk_dev2), "/dev/%s", parent_blk); 1384 + int dfd = open(disk_dev2, O_RDONLY | O_CLOEXEC); 1385 + if (dfd >= 0) { ioctl(dfd, BLKFLSBUF); close(dfd); } 1386 + } 1349 1387 system("echo 3 > /proc/sys/vm/drop_caches 2>/dev/null || true"); 1350 1388 sync(); 1389 + ac_log("[install] pre-mkfs cache flush done\n"); 1351 1390 // Long settle — let the kernel + nvme driver fully release 1352 - // the device. 3 seconds gives enough margin for the block 1353 - // layer to quiesce after partx + wipefs. 1354 - usleep(3000000); 1391 + // the device. 5 seconds to be safe. 1392 + usleep(5000000); 1355 1393 1356 1394 // Reformat. Retry up to 3 times if mkfs fails — the 1357 1395 // kernel sometimes needs multiple passes after a fresh ··· 1390 1428 fclose(mf); 1391 1429 } 1392 1430 } 1393 - // Attempt 2 + 3 if needed 1394 - for (int mkfs_try = 2; mkfs_try <= 3 && mkfs_exit != 0; mkfs_try++) { 1431 + // Attempt 2–5 if needed (more retries with aggressive flush) 1432 + for (int mkfs_try = 2; mkfs_try <= 5 && mkfs_exit != 0; mkfs_try++) { 1433 + // Flush block device buffer cache before each retry 1434 + { 1435 + int pfd = open(devpath, O_RDONLY | O_CLOEXEC); 1436 + if (pfd >= 0) { ioctl(pfd, BLKFLSBUF); close(pfd); } 1437 + char dd2[64]; 1438 + snprintf(dd2, sizeof(dd2), "/dev/%s", parent_blk); 1439 + int dfd = open(dd2, O_RDONLY | O_CLOEXEC); 1440 + if (dfd >= 0) { ioctl(dfd, BLKFLSBUF); close(dfd); } 1441 + } 1395 1442 sync(); 1396 1443 system("echo 3 > /proc/sys/vm/drop_caches 2>/dev/null || true"); 1397 - usleep(2000000); // 2s settle between retries 1444 + usleep(3000000); // 3s settle between retries 1398 1445 snprintf(rcmd, sizeof(rcmd), 1399 1446 "echo '--- mkfs attempt %d ---' >> %s; " 1400 1447 "(mkfs.vfat -F 32 -n AC-NATIVE %s > %s 2>&1; rc=$?; "