From d0d37bdfd170587307c6f64678b739e69341dd69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Fri, 16 Dec 2005 16:11:36 +0000 Subject: [PATCH] * vfs_init() is now called later in the startup sequence - since no core kernel service depends on it, it doesn't make any sense to call it that early in the game. * The VFS now has a low memory handler for vnodes as well. If there is enough memory left, it won't free any vnodes anymore. * Potential crashing bug fix: some functions did not check if the FD passed in belonged to the right type; they just assumed it had a valid vnode, but it could have had a mount structure associated as well. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15566 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/fs/fd.h | 1 + src/system/kernel/fs/fd.c | 15 ++++++ src/system/kernel/fs/vfs.cpp | 87 +++++++++++++++++++++++++++------- src/system/kernel/main.c | 4 +- 4 files changed, 87 insertions(+), 20 deletions(-) diff --git a/headers/private/kernel/fs/fd.h b/headers/private/kernel/fs/fd.h index f42af651d9..faa5ddfb69 100644 --- a/headers/private/kernel/fs/fd.h +++ b/headers/private/kernel/fs/fd.h @@ -73,6 +73,7 @@ extern void put_fd(struct file_descriptor *descriptor); extern status_t select_fd(int fd, uint8 event, uint32 ref, struct select_sync *sync, bool kernel); extern status_t deselect_fd(int fd, uint8 event, struct select_sync *sync, bool kernel); extern bool fd_is_valid(int fd, bool kernel); +extern struct vnode *fd_vnode(struct file_descriptor *descriptor); extern bool fd_close_on_exec(struct io_context *context, int fd); extern void fd_set_close_on_exec(struct io_context *context, int fd, bool closeFD); diff --git a/src/system/kernel/fs/fd.c b/src/system/kernel/fs/fd.c index dd77f44468..b28eb2c366 100644 --- a/src/system/kernel/fs/fd.c +++ b/src/system/kernel/fs/fd.c @@ -355,6 +355,21 @@ fd_is_valid(int fd, bool kernel) } +struct vnode * +fd_vnode(struct file_descriptor *descriptor) +{ + switch (descriptor->type) { + case FDTYPE_FILE: + case FDTYPE_DIR: + case FDTYPE_ATTR_DIR: + case FDTYPE_ATTR: + return descriptor->u.vnode; + } + + return NULL; +} + + static status_t common_close(int fd, bool kernel) { diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index e9a2cd91a4..2b51ff6a11 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -14,21 +14,23 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include #include #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include @@ -714,7 +716,8 @@ dec_vnode_ref_count(struct vnode *vnode, bool reenter) freeNode = true; } else { list_add_item(&sUnusedVnodeList, vnode); - if (++sUnusedVnodes > kMaxUnusedVnodes) { + if (++sUnusedVnodes > kMaxUnusedVnodes + && vm_low_memory_state() != B_NO_LOW_MEMORY) { // there are too many unused vnodes so we free the oldest one // ToDo: evaluate this mechanism vnode = (struct vnode *)list_remove_head_item(&sUnusedVnodeList); @@ -875,15 +878,58 @@ put_vnode(struct vnode *vnode) } +static void +vnode_low_memory_handler(void */*data*/, int32 level) +{ + PRINT(("vnode_low_memory_handler(level = %ld)\n", level)); + + int32 count = 1; + switch (level) { + case B_NO_LOW_MEMORY: + return; + case B_LOW_MEMORY_NOTE: + count = sUnusedVnodes / 100; + break; + case B_LOW_MEMORY_WARNING: + count = sUnusedVnodes / 10; + break; + case B_LOW_MEMORY_CRITICAL: + count = sUnusedVnodes; + break; + } + + for (int32 i = 0; i < count; i++) { + mutex_lock(&sVnodeMutex); + + struct vnode *vnode = (struct vnode *)list_remove_head_item(&sUnusedVnodeList); + if (vnode == NULL) { + mutex_unlock(&sVnodeMutex); + break; + } + PRINT((" free vnode %ld:%Ld (%p)\n", vnode->device, vnode->id, vnode)); + + vnode->busy = true; + sUnusedVnodes--; + + mutex_unlock(&sVnodeMutex); + + free_vnode(vnode, false); + } +} + + static status_t create_advisory_locking(struct vnode *vnode) { - status_t status; + if (vnode == NULL) + return B_FILE_ERROR; struct advisory_locking *locking = (struct advisory_locking *)malloc(sizeof(struct advisory_locking)); if (locking == NULL) return B_NO_MEMORY; + status_t status; + locking->wait_sem = create_sem(0, "advisory lock"); if (locking->wait_sem < B_OK) { status = locking->wait_sem; @@ -1849,7 +1895,7 @@ get_fd_and_vnode(int fd, struct vnode **_vnode, bool kernel) if (descriptor == NULL) return NULL; - if (descriptor->u.vnode == NULL) { + if (fd_vnode(descriptor) == NULL) { put_fd(descriptor); return NULL; } @@ -1872,7 +1918,7 @@ get_vnode_from_fd(int fd, bool kernel) if (descriptor == NULL) return NULL; - vnode = descriptor->u.vnode; + vnode = fd_vnode(descriptor); if (vnode != NULL) inc_vnode_ref_count(vnode); @@ -1938,6 +1984,7 @@ get_new_fd(int type, struct fs_mount *mount, struct vnode *vnode, descriptor->cookie = cookie; switch (type) { + // vnode types case FDTYPE_FILE: descriptor->ops = &sFileOps; break; @@ -1950,12 +1997,15 @@ get_new_fd(int type, struct fs_mount *mount, struct vnode *vnode, case FDTYPE_ATTR_DIR: descriptor->ops = &sAttributeDirectoryOps; break; + + // mount types case FDTYPE_INDEX_DIR: descriptor->ops = &sIndexDirectoryOps; break; case FDTYPE_QUERY: descriptor->ops = &sQueryOps; break; + default: panic("get_new_fd() called with unknown type %d\n", type); break; @@ -2235,8 +2285,7 @@ dump_io_context(int argc, char **argv) #endif // ADD_DEBUGGER_COMMANDS -// #pragma mark - -// Public VFS API +// #pragma mark - public VFS API extern "C" status_t @@ -2384,7 +2433,7 @@ unremove_vnode(mount_id mountID, vnode_id vnodeID) } -// #pragma mark - +// #pragma mark - private VFS API // Functions the VFS exports for other parts of the kernel @@ -3107,6 +3156,8 @@ vfs_init(kernel_args *args) add_debugger_command("io_context", &dump_io_context, "info about the I/O context"); #endif + register_low_memory_handler(&vnode_low_memory_handler, NULL, 0); + return file_cache_init(); } diff --git a/src/system/kernel/main.c b/src/system/kernel/main.c index 3a1a979253..b6438e1225 100644 --- a/src/system/kernel/main.c +++ b/src/system/kernel/main.c @@ -128,8 +128,6 @@ _start(kernel_args *bootKernelArgs, int currentCPU) generic_syscall_init(); TRACE(("init cbuf\n")); cbuf_init(); - TRACE(("init VFS\n")); - vfs_init(&sKernelArgs); TRACE(("init teams\n")); team_init(&sKernelArgs); TRACE(("init threads\n")); @@ -145,6 +143,8 @@ _start(kernel_args *bootKernelArgs, int currentCPU) elf_init(&sKernelArgs); TRACE(("init scheduler\n")); scheduler_init(); + TRACE(("init VFS\n")); + vfs_init(&sKernelArgs); // start a thread to finish initializing the rest of the system thread = spawn_kernel_thread(&main2, "main2", B_NORMAL_PRIORITY, NULL);