diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
commit | beb116954b9b7f3bb56412b2494b562f02b864b1 (patch) | |
tree | 120e997879884e1b9d93b265221b939d2ef1ade1 /fs/file_table.c | |
parent | 908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff) |
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'fs/file_table.c')
-rw-r--r-- | fs/file_table.c | 166 |
1 files changed, 126 insertions, 40 deletions
diff --git a/fs/file_table.c b/fs/file_table.c index 6438162a0..17a670f59 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -4,87 +4,173 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ +#include <linux/config.h> #include <linux/fs.h> #include <linux/string.h> #include <linux/mm.h> -struct file * first_file; +/* + * first_file points to a doubly linked list of all file structures in + * the system. + * nr_files holds the length of this list. + */ +struct file * first_file = NULL; int nr_files = 0; +int max_files = NR_FILE; -static void insert_file_free(struct file *file) +/* + * Insert a new file structure at the head of the list of available ones. + */ +static inline 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; + struct file *next, *prev; + + next = first_file; first_file = file; + file->f_count = 0; + prev = next->f_prev; + file->f_next = next; + next->f_prev = file; + file->f_prev = prev; + prev->f_next = file; } -static void remove_file_free(struct file *file) +/* + * Remove a file structure from the list of available ones. + */ +static inline 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; + struct file *next, *prev; + + next = file->f_next; + prev = file->f_prev; file->f_next = file->f_prev = NULL; + if (first_file == file) + first_file = next; + next->f_prev = prev; + prev->f_next = next; } -static void put_last_free(struct file *file) +/* + * Insert a file structure at the end of the list of available ones. + */ +static inline 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; + struct file *next, *prev; + + next = first_file; + file->f_next = next; + prev = next->f_prev; + next->f_prev = file; + file->f_prev = prev; + prev->f_next = file; } -void grow_files(void) +/* + * Allocate a new memory page for file structures and + * insert the new structures into the global list. + * Returns 0, if there is no more memory, 1 otherwise. + */ +static int grow_files(void) { struct file * file; int i; - file = (struct file *) get_free_page(GFP_KERNEL); + /* + * We don't have to clear the page because we only look into + * f_count, f_prev and f_next and they get initialized in + * insert_file_free. The rest of the file structure is cleared + * by get_empty_filp before it is returned. + */ + file = (struct file *) __get_free_page(GFP_KERNEL); if (!file) - return; + return 0; - nr_files+=i= PAGE_SIZE/sizeof(struct file); + nr_files += i = PAGE_SIZE/sizeof(struct file); if (!first_file) - file->f_next = file->f_prev = first_file = file++, i--; + file->f_count = 0, + file->f_next = file->f_prev = first_file = file++, + i--; for (; i ; i--) insert_file_free(file++); + + return 1; } unsigned long file_table_init(unsigned long start, unsigned long end) { - first_file = NULL; return start; } +/* + * Find an unused file structure and return a pointer to it. + * Returns NULL, if there are no more free file structures or + * we run out of memory. + */ struct file * get_empty_filp(void) { int i; + int max = max_files; 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; + /* + * Reserve a few files for the super-user.. + */ + if (current->euid) + max -= 10; + + /* if the return is taken, we are in deep trouble */ + if (!first_file && !grow_files()) + return NULL; + + do { + 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; + } + } while (nr_files < max && grow_files()); + + return NULL; +} + +#ifdef CONFIG_QUOTA + +void add_dquot_ref(kdev_t dev, short type) +{ + struct file *filp; + int cnt; + + for (filp = first_file, cnt = 0; cnt < nr_files; cnt++, filp = filp->f_next) { + if (!filp->f_count || !filp->f_inode || filp->f_inode->i_dev != dev) + continue; + if (filp->f_mode & FMODE_WRITE && filp->f_inode->i_sb->dq_op) { + filp->f_inode->i_sb->dq_op->initialize(filp->f_inode, type); + filp->f_inode->i_flags |= S_WRITE; } - if (nr_files < NR_FILE) { - grow_files(); - goto repeat; } - return NULL; } + +void reset_dquot_ptrs(kdev_t dev, short type) +{ + struct file *filp; + int cnt; + + for (filp = first_file, cnt = 0; cnt < nr_files; cnt++, filp = filp->f_next) { + if (!filp->f_count || !filp->f_inode || filp->f_inode->i_dev != dev) + continue; + if (IS_WRITABLE(filp->f_inode)) { + filp->f_inode->i_dquot[type] = NODQUOT; + filp->f_inode->i_flags &= ~S_WRITE; + } + } +} + +#endif |