* 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

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 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);

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
common_close(int fd, bool kernel)
{

View File

@ -14,21 +14,23 @@
#include <fs_interface.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/KDiskDeviceManager.h>
#include <disk_device_manager/KDiskDeviceUtils.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 <util/kernel_cpp.h>
@ -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();
}

View File

@ -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);