* 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
This commit is contained in:
Axel Dörfler
2005-12-16 16:11:36 +00:00
parent 4c0f46e2a3
commit d0d37bdfd1
4 changed files with 87 additions and 20 deletions
+1
View File
@@ -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 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 status_t deselect_fd(int fd, uint8 event, struct select_sync *sync, bool kernel);
extern bool fd_is_valid(int fd, 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 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); extern void fd_set_close_on_exec(struct io_context *context, int fd, bool closeFD);
+15
View File
@@ -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 static status_t
common_close(int fd, bool kernel) common_close(int fd, bool kernel)
{ {
+69 -18
View File
@@ -14,21 +14,23 @@
#include <fs_interface.h> #include <fs_interface.h>
#include <fs_volume.h> #include <fs_volume.h>
#include <block_cache.h>
#include <fd.h>
#include <file_cache.h>
#include <khash.h>
#include <KPath.h>
#include <lock.h>
#include <syscalls.h>
#include <vfs.h>
#include <vm.h>
#include <vm_cache.h>
#include <vm_low_memory.h>
#include <boot/kernel_args.h>
#include <disk_device_manager/KDiskDevice.h> #include <disk_device_manager/KDiskDevice.h>
#include <disk_device_manager/KDiskDeviceManager.h> #include <disk_device_manager/KDiskDeviceManager.h>
#include <disk_device_manager/KDiskDeviceUtils.h> #include <disk_device_manager/KDiskDeviceUtils.h>
#include <disk_device_manager/KDiskSystem.h> #include <disk_device_manager/KDiskSystem.h>
#include <KPath.h>
#include <syscalls.h>
#include <boot/kernel_args.h>
#include <vfs.h>
#include <vm.h>
#include <vm_cache.h>
#include <file_cache.h>
#include <block_cache.h>
#include <khash.h>
#include <lock.h>
#include <fd.h>
#include <fs/node_monitor.h> #include <fs/node_monitor.h>
#include <util/kernel_cpp.h> #include <util/kernel_cpp.h>
@@ -714,7 +716,8 @@ dec_vnode_ref_count(struct vnode *vnode, bool reenter)
freeNode = true; freeNode = true;
} else { } else {
list_add_item(&sUnusedVnodeList, vnode); 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 // there are too many unused vnodes so we free the oldest one
// ToDo: evaluate this mechanism // ToDo: evaluate this mechanism
vnode = (struct vnode *)list_remove_head_item(&sUnusedVnodeList); 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 static status_t
create_advisory_locking(struct vnode *vnode) 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)); struct advisory_locking *locking = (struct advisory_locking *)malloc(sizeof(struct advisory_locking));
if (locking == NULL) if (locking == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
status_t status;
locking->wait_sem = create_sem(0, "advisory lock"); locking->wait_sem = create_sem(0, "advisory lock");
if (locking->wait_sem < B_OK) { if (locking->wait_sem < B_OK) {
status = locking->wait_sem; status = locking->wait_sem;
@@ -1849,7 +1895,7 @@ get_fd_and_vnode(int fd, struct vnode **_vnode, bool kernel)
if (descriptor == NULL) if (descriptor == NULL)
return NULL; return NULL;
if (descriptor->u.vnode == NULL) { if (fd_vnode(descriptor) == NULL) {
put_fd(descriptor); put_fd(descriptor);
return NULL; return NULL;
} }
@@ -1872,7 +1918,7 @@ get_vnode_from_fd(int fd, bool kernel)
if (descriptor == NULL) if (descriptor == NULL)
return NULL; return NULL;
vnode = descriptor->u.vnode; vnode = fd_vnode(descriptor);
if (vnode != NULL) if (vnode != NULL)
inc_vnode_ref_count(vnode); inc_vnode_ref_count(vnode);
@@ -1938,6 +1984,7 @@ get_new_fd(int type, struct fs_mount *mount, struct vnode *vnode,
descriptor->cookie = cookie; descriptor->cookie = cookie;
switch (type) { switch (type) {
// vnode types
case FDTYPE_FILE: case FDTYPE_FILE:
descriptor->ops = &sFileOps; descriptor->ops = &sFileOps;
break; break;
@@ -1950,12 +1997,15 @@ get_new_fd(int type, struct fs_mount *mount, struct vnode *vnode,
case FDTYPE_ATTR_DIR: case FDTYPE_ATTR_DIR:
descriptor->ops = &sAttributeDirectoryOps; descriptor->ops = &sAttributeDirectoryOps;
break; break;
// mount types
case FDTYPE_INDEX_DIR: case FDTYPE_INDEX_DIR:
descriptor->ops = &sIndexDirectoryOps; descriptor->ops = &sIndexDirectoryOps;
break; break;
case FDTYPE_QUERY: case FDTYPE_QUERY:
descriptor->ops = &sQueryOps; descriptor->ops = &sQueryOps;
break; break;
default: default:
panic("get_new_fd() called with unknown type %d\n", type); panic("get_new_fd() called with unknown type %d\n", type);
break; break;
@@ -2235,8 +2285,7 @@ dump_io_context(int argc, char **argv)
#endif // ADD_DEBUGGER_COMMANDS #endif // ADD_DEBUGGER_COMMANDS
// #pragma mark - // #pragma mark - public VFS API
// Public VFS API
extern "C" status_t 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 // 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"); add_debugger_command("io_context", &dump_io_context, "info about the I/O context");
#endif #endif
register_low_memory_handler(&vnode_low_memory_handler, NULL, 0);
return file_cache_init(); return file_cache_init();
} }
+2 -2
View File
@@ -128,8 +128,6 @@ _start(kernel_args *bootKernelArgs, int currentCPU)
generic_syscall_init(); generic_syscall_init();
TRACE(("init cbuf\n")); TRACE(("init cbuf\n"));
cbuf_init(); cbuf_init();
TRACE(("init VFS\n"));
vfs_init(&sKernelArgs);
TRACE(("init teams\n")); TRACE(("init teams\n"));
team_init(&sKernelArgs); team_init(&sKernelArgs);
TRACE(("init threads\n")); TRACE(("init threads\n"));
@@ -145,6 +143,8 @@ _start(kernel_args *bootKernelArgs, int currentCPU)
elf_init(&sKernelArgs); elf_init(&sKernelArgs);
TRACE(("init scheduler\n")); TRACE(("init scheduler\n"));
scheduler_init(); scheduler_init();
TRACE(("init VFS\n"));
vfs_init(&sKernelArgs);
// start a thread to finish initializing the rest of the system // start a thread to finish initializing the rest of the system
thread = spawn_kernel_thread(&main2, "main2", B_NORMAL_PRIORITY, NULL); thread = spawn_kernel_thread(&main2, "main2", B_NORMAL_PRIORITY, NULL);