fs: inode and open-file tables that grow, with a hash for iget
The inode table was NINODE (200) entries, searched end to end on every
iget(), and a panic -- "iget: no inodes" -- when all of them were held.
Held means open, a cwd, a running binary or a directory mid-walk, so a
few busy processes reached it. iget() now finds an inode through a hash
on (dev, inum), takes a free one from a list, and makes more from a
slab cache once the NINODE in the image are all in use.
The open-file table had the same shape, NFILE (512) and then ENFILE,
and gets the same treatment: a free list, and the slab past NFILE.
/proc/fsstat's peaks now read against how many exist.
getrlimit(RLIMIT_NOFILE) said unlimited, which musl turns into
sysconf(_SC_OPEN_MAX) == -1, after which zsh believed it had no
descriptors and `exec {fd}<file` failed on the first one. It reports
NOFILE now. And a comment in sys_fs.c held a "*/" that ended it early.
Checked under QEMU: six processes holding 115 files each, 713 open
descriptions and 341 inodes at once, all back to the baseline after.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
parent
62d2a85ac8
commit
09e07423e8
6 changed files with 161 additions and 40 deletions
|
|
@ -21,6 +21,7 @@ struct file {
|
|||
// invite somebody to keep one.
|
||||
int memfd_seg;
|
||||
uint64 off;
|
||||
struct file *fnext; // file.c's free list, while ref is 0
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
@ -105,6 +106,8 @@ struct inode {
|
|||
struct sleeplock lock;
|
||||
int valid;
|
||||
const struct fs_ops *ops; // chosen by iget from dev; never null once held
|
||||
struct inode *hnext; // fs.c: hash chain while held, free list after
|
||||
struct inode *anext; // fs.c: every inode there is, never reordered
|
||||
|
||||
short type;
|
||||
short major;
|
||||
|
|
@ -191,6 +194,10 @@ int sysfs_mount(const char *target);
|
|||
int iheld(uint dev, uint64 inum);
|
||||
// 1 if any inode on dev but `except` is referenced (0: no exception). In fs.c.
|
||||
int ibusy(uint dev, uint64 except);
|
||||
// How many in-memory inodes exist; the table grows past NINODE. In fs.c.
|
||||
uint inode_slots(void);
|
||||
// How many open file descriptions exist; the table grows past NFILE. file.c.
|
||||
uint file_slots(void);
|
||||
// Path lookup that follows a final symlink too; 0 with *err set on failure.
|
||||
// `start` 0 means the cwd. In fs.c.
|
||||
struct inode *nameifollow(struct inode *start, char *path, int *err);
|
||||
|
|
|
|||
Loading…
Reference in a new issue