diff options
Diffstat (limited to 'fs/file_table.c')
-rw-r--r-- | fs/file_table.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/fs/file_table.c b/fs/file_table.c new file mode 100644 index 000000000..6438162a0 --- /dev/null +++ b/fs/file_table.c @@ -0,0 +1,90 @@ +/* + * linux/fs/file_table.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/mm.h> + +struct file * first_file; +int nr_files = 0; + +static void insert_file_free(struct file *file) +{ + file->f_next = first_file; + file->f_prev = first_file->f_prev; + file->f_next->f_prev = file; + file->f_prev->f_next = file; + first_file = file; +} + +static void remove_file_free(struct file *file) +{ + if (first_file == file) + first_file = first_file->f_next; + if (file->f_next) + file->f_next->f_prev = file->f_prev; + if (file->f_prev) + file->f_prev->f_next = file->f_next; + file->f_next = file->f_prev = NULL; +} + +static void put_last_free(struct file *file) +{ + remove_file_free(file); + file->f_prev = first_file->f_prev; + file->f_prev->f_next = file; + file->f_next = first_file; + file->f_next->f_prev = file; +} + +void grow_files(void) +{ + struct file * file; + int i; + + file = (struct file *) get_free_page(GFP_KERNEL); + + if (!file) + return; + + nr_files+=i= PAGE_SIZE/sizeof(struct file); + + if (!first_file) + file->f_next = file->f_prev = first_file = file++, i--; + + for (; i ; i--) + insert_file_free(file++); +} + +unsigned long file_table_init(unsigned long start, unsigned long end) +{ + first_file = NULL; + return start; +} + +struct file * get_empty_filp(void) +{ + int i; + struct file * f; + + if (!first_file) + grow_files(); +repeat: + for (f = first_file, i=0; i < nr_files; i++, f = f->f_next) + if (!f->f_count) { + remove_file_free(f); + memset(f,0,sizeof(*f)); + put_last_free(f); + f->f_count = 1; + f->f_version = ++event; + return f; + } + if (nr_files < NR_FILE) { + grow_files(); + goto repeat; + } + return NULL; +} |