| /* |
| * 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; |
| return f; |
| } |
| if (nr_files < NR_FILE) { |
| grow_files(); |
| goto repeat; |
| } |
| return NULL; |
| } |