Skip to content

Commit 92842c0

Browse files
committed
feat: US-014 - Kernel cleanup: remove old fast paths and inode table
1 parent c450043 commit 92842c0

7 files changed

Lines changed: 92 additions & 631 deletions

File tree

packages/core/src/kernel/index.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,6 @@ export type { LineDisciplineConfig } from "./pty.js";
7474
export { CommandRegistry } from "./command-registry.js";
7575
export { FileLockManager, LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB } from "./file-lock.js";
7676
export { WaitHandle, WaitQueue } from "./wait.js";
77-
export { InodeTable } from "./inode-table.js";
78-
export type { Inode } from "./inode-table.js";
7977
export { TimerTable } from "./timer-table.js";
8078
export type { KernelTimer, TimerTableOptions } from "./timer-table.js";
8179
export { DnsCache } from "./dns-cache.js";

packages/core/src/kernel/inode-table.ts

Lines changed: 0 additions & 110 deletions
This file was deleted.

packages/core/src/kernel/kernel.ts

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ import { wrapFileSystem, checkChildProcess } from "./permissions.js";
3838
import { UserManager } from "./user.js";
3939
import { SocketTable } from "./socket-table.js";
4040
import { TimerTable } from "./timer-table.js";
41-
import { InodeTable } from "./inode-table.js";
42-
import { InMemoryFileSystem } from "../shared/in-memory-fs.js";
4341
import {
4442
FILETYPE_REGULAR_FILE,
4543
FILETYPE_DIRECTORY,
@@ -72,7 +70,6 @@ export function createKernel(options: KernelOptions): Kernel {
7270
class KernelImpl implements Kernel {
7371
private vfs: VirtualFileSystem;
7472
private mountTable: MountTable;
75-
private rawInMemoryFs?: InMemoryFileSystem;
7673
private fdTableManager = new FDTableManager();
7774
private processTable!: ProcessTable;
7875
private pipeManager = new PipeManager();
@@ -81,7 +78,6 @@ class KernelImpl implements Kernel {
8178
private commandRegistry = new CommandRegistry();
8279
readonly socketTable: SocketTable;
8380
readonly timerTable: TimerTable;
84-
readonly inodeTable: InodeTable;
8581
private userManager: UserManager;
8682
private drivers: RuntimeDriver[] = [];
8783
private driverPids = new Map<string, Set<number>>();
@@ -109,12 +105,6 @@ class KernelImpl implements Kernel {
109105
},
110106
this.log.child({ component: "pty" }),
111107
);
112-
this.inodeTable = new InodeTable();
113-
if (options.filesystem instanceof InMemoryFileSystem) {
114-
options.filesystem.setInodeTable(this.inodeTable);
115-
this.rawInMemoryFs = options.filesystem;
116-
}
117-
118108
// Build mount table: root FS → /dev → /proc → user mounts.
119109
const mt = new MountTable(options.filesystem);
120110
mt.mount("/dev", createDeviceBackend());
@@ -834,9 +824,6 @@ class KernelImpl implements Kernel {
834824
const filetype = FILETYPE_REGULAR_FILE;
835825
const fd = table.open(path, flags, filetype);
836826
const fdEntry = table.get(fd);
837-
if (fdEntry) {
838-
this.trackDescriptionInode(fdEntry.description);
839-
}
840827

841828
// Stash the effective mode for the first write that materializes a new file.
842829
if (created && (flags & O_CREAT)) {
@@ -1471,7 +1458,7 @@ class KernelImpl implements Kernel {
14711458
// Close all FDs and remove the table
14721459
this.fdTableManager.remove(pid);
14731460

1474-
// Release inode-backed file data after the last shared reference closes.
1461+
// Flush buffered writes when the last shared reference closes.
14751462
for (const description of descriptions.values()) {
14761463
if (description.refCount <= 0) {
14771464
this.releaseDescriptionInode(description);
@@ -1516,48 +1503,24 @@ class KernelImpl implements Kernel {
15161503
return data.length;
15171504
}
15181505

1519-
private trackDescriptionInode(description: import("./types.js").FileDescription): void {
1520-
if (!this.rawInMemoryFs || description.inode !== undefined) return;
1521-
const ino = this.rawInMemoryFs.getInodeForPath(description.path);
1522-
if (ino === null) return;
1523-
description.inode = ino;
1524-
this.inodeTable.incrementOpenRefs(ino);
1525-
}
1526-
15271506
private releaseDescriptionInode(
15281507
description: import("./types.js").FileDescription,
15291508
): void {
15301509
// Flush buffered writes to durable storage when the last FD is closed.
15311510
void this.vfs.fsync?.(description.path);
1532-
1533-
if (description.inode === undefined) return;
1534-
this.inodeTable.decrementOpenRefs(description.inode);
1535-
if (this.inodeTable.shouldDelete(description.inode)) {
1536-
this.rawInMemoryFs?.deleteInodeData(description.inode);
1537-
this.inodeTable.delete(description.inode);
1538-
}
1539-
description.inode = undefined;
15401511
}
15411512

15421513
private async readDescriptionFile(
15431514
description: import("./types.js").FileDescription,
15441515
): Promise<Uint8Array> {
1545-
if (description.inode !== undefined && this.rawInMemoryFs) {
1546-
return this.rawInMemoryFs.readFileByInode(description.inode);
1547-
}
15481516
return this.vfs.readFile(description.path);
15491517
}
15501518

15511519
private async writeDescriptionFile(
15521520
description: import("./types.js").FileDescription,
15531521
content: Uint8Array,
15541522
): Promise<void> {
1555-
if (description.inode !== undefined && this.rawInMemoryFs) {
1556-
this.rawInMemoryFs.writeFileByInode(description.inode, content);
1557-
return;
1558-
}
15591523
await this.vfs.writeFile(description.path, content);
1560-
this.trackDescriptionInode(description);
15611524
}
15621525

15631526
private prepareOpenSync(path: string, flags: number): boolean {
@@ -1572,9 +1535,6 @@ class KernelImpl implements Kernel {
15721535
offset: number,
15731536
length: number,
15741537
): Promise<Uint8Array> {
1575-
if (description.inode !== undefined && this.rawInMemoryFs) {
1576-
return this.rawInMemoryFs.preadByInode(description.inode, offset, length);
1577-
}
15781538
return this.vfs.pread(description.path, offset, length);
15791539
}
15801540

@@ -1583,12 +1543,7 @@ class KernelImpl implements Kernel {
15831543
offset: number,
15841544
data: Uint8Array,
15851545
): Promise<void> {
1586-
if (description.inode !== undefined && this.rawInMemoryFs) {
1587-
this.rawInMemoryFs.pwriteByInode(description.inode, offset, data);
1588-
return;
1589-
}
15901546
await this.vfs.pwrite(description.path, offset, data);
1591-
this.trackDescriptionInode(description);
15921547
}
15931548

15941549
private async getDescriptionSize(
@@ -1600,9 +1555,6 @@ class KernelImpl implements Kernel {
16001555
private async statDescription(
16011556
description: import("./types.js").FileDescription,
16021557
): Promise<VirtualStat> {
1603-
if (description.inode !== undefined && this.rawInMemoryFs) {
1604-
return this.rawInMemoryFs.statByInode(description.inode);
1605-
}
16061558
return this.vfs.stat(description.path);
16071559
}
16081560

packages/core/src/kernel/types.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ export interface Kernel {
125125
// Socket table
126126
readonly socketTable: import("./socket-table.js").SocketTable;
127127
readonly timerTable: import("./timer-table.js").TimerTable;
128-
readonly inodeTable: import("./inode-table.js").InodeTable;
129128

130129
// Introspection
131130
readonly commands: ReadonlyMap<string, string>;
@@ -426,8 +425,6 @@ export interface FDStat {
426425
export interface FileDescription {
427426
id: number;
428427
path: string;
429-
/** Stable inode identity for FD I/O after the pathname is unlinked. */
430-
inode?: number;
431428
cursor: bigint;
432429
flags: number;
433430
refCount: number;

packages/core/src/shared/in-memory-fs.ts

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,94 @@
1-
import { InodeTable, type Inode } from "../kernel/inode-table.js";
1+
interface Inode {
2+
readonly ino: number;
3+
nlink: number;
4+
openRefCount: number;
5+
mode: number;
6+
uid: number;
7+
gid: number;
8+
size: number;
9+
atime: Date;
10+
mtime: Date;
11+
ctime: Date;
12+
birthtime: Date;
13+
}
14+
15+
class InodeTable {
16+
private inodes: Map<number, Inode> = new Map();
17+
private nextIno = 1;
18+
19+
allocate(mode: number, uid: number, gid: number): Inode {
20+
const now = new Date();
21+
const inode: Inode = {
22+
ino: this.nextIno++,
23+
nlink: 1,
24+
openRefCount: 0,
25+
mode,
26+
uid,
27+
gid,
28+
size: 0,
29+
atime: now,
30+
mtime: now,
31+
ctime: now,
32+
birthtime: now,
33+
};
34+
this.inodes.set(inode.ino, inode);
35+
return inode;
36+
}
37+
38+
get(ino: number): Inode | null {
39+
return this.inodes.get(ino) ?? null;
40+
}
41+
42+
incrementLinks(ino: number): void {
43+
const inode = this.requireInode(ino);
44+
inode.nlink++;
45+
inode.ctime = new Date();
46+
}
47+
48+
decrementLinks(ino: number): void {
49+
const inode = this.requireInode(ino);
50+
if (inode.nlink <= 0) {
51+
throw new KernelError("EINVAL", `inode ${ino} nlink already 0`);
52+
}
53+
inode.nlink--;
54+
inode.ctime = new Date();
55+
}
56+
57+
incrementOpenRefs(ino: number): void {
58+
const inode = this.requireInode(ino);
59+
inode.openRefCount++;
60+
}
61+
62+
decrementOpenRefs(ino: number): void {
63+
const inode = this.requireInode(ino);
64+
if (inode.openRefCount <= 0) {
65+
throw new KernelError("EINVAL", `inode ${ino} openRefCount already 0`);
66+
}
67+
inode.openRefCount--;
68+
}
69+
70+
shouldDelete(ino: number): boolean {
71+
const inode = this.inodes.get(ino);
72+
if (!inode) return false;
73+
return inode.nlink === 0 && inode.openRefCount === 0;
74+
}
75+
76+
delete(ino: number): void {
77+
this.inodes.delete(ino);
78+
}
79+
80+
get size(): number {
81+
return this.inodes.size;
82+
}
83+
84+
private requireInode(ino: number): Inode {
85+
const inode = this.inodes.get(ino);
86+
if (!inode) {
87+
throw new KernelError("ENOENT", `inode ${ino} not found`);
88+
}
89+
return inode;
90+
}
91+
}
292
import type {
393
VirtualDirEntry,
494
VirtualFileSystem,

0 commit comments

Comments
 (0)