diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-09-28 22:25:29 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-09-28 22:25:29 +0000 |
commit | 0ae8dceaebe3659ee0c3352c08125f403e77ebca (patch) | |
tree | 5085c389f09da78182b899d19fe1068b619a69dd /fs/file_table.c | |
parent | 273767781288c35c9d679e908672b9996cda4c34 (diff) |
Merge with 2.3.10.
Diffstat (limited to 'fs/file_table.c')
-rw-r--r-- | fs/file_table.c | 132 |
1 files changed, 87 insertions, 45 deletions
diff --git a/fs/file_table.c b/fs/file_table.c index 80c3a08ba..cb9ef16e9 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -9,6 +9,7 @@ #include <linux/slab.h> #include <linux/file.h> #include <linux/init.h> +#include <linux/smp_lock.h> /* SLAB cache for filp's. */ static kmem_cache_t *filp_cache; @@ -18,37 +19,12 @@ int nr_files = 0; /* read only */ int nr_free_files = 0; /* read only */ int max_files = NR_FILE;/* tunable */ -/* Free list management, if you are here you must have f_count == 0 */ -static struct file * free_filps = NULL; - -static void insert_file_free(struct file *file) -{ - if((file->f_next = free_filps) != NULL) - free_filps->f_pprev = &file->f_next; - free_filps = file; - file->f_pprev = &free_filps; - nr_free_files++; -} - -/* The list of in-use filp's must be exported (ugh...) */ -struct file *inuse_filps = NULL; - -static inline void put_inuse(struct file *file) -{ - if((file->f_next = inuse_filps) != NULL) - inuse_filps->f_pprev = &file->f_next; - inuse_filps = file; - file->f_pprev = &inuse_filps; -} - -/* It does not matter which list it is on. */ -static inline void remove_filp(struct file *file) -{ - if(file->f_next) - file->f_next->f_pprev = file->f_pprev; - *file->f_pprev = file->f_next; -} - +/* Here the new files go */ +static LIST_HEAD(anon_list); +/* And here the free ones sit */ +static LIST_HEAD(free_list); +/* public *and* exported. Not pretty! */ +spinlock_t files_lock = SPIN_LOCK_UNLOCKED; void __init file_table_init(void) { @@ -67,24 +43,30 @@ void __init file_table_init(void) /* 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. + * + * SMP-safe. */ struct file * get_empty_filp(void) { static int old_max = 0; struct file * f; + file_list_lock(); if (nr_free_files > NR_RESERVED_FILES) { used_one: - f = free_filps; - remove_filp(f); + f = list_entry(free_list.next, struct file, f_list); + list_del(&f->f_list); nr_free_files--; new_one: + file_list_unlock(); memset(f, 0, sizeof(*f)); - atomic_set(&f->f_count, 1); + atomic_set(&f->f_count,1); f->f_version = ++event; f->f_uid = current->fsuid; f->f_gid = current->fsgid; - put_inuse(f); + file_list_lock(); + list_add(&f->f_list, &anon_list); + file_list_unlock(); return f; } /* @@ -96,7 +78,9 @@ struct file * get_empty_filp(void) * Allocate a new one if we're below the limit. */ if (nr_files < max_files) { + file_list_unlock(); f = kmem_cache_alloc(filp_cache, SLAB_KERNEL); + file_list_lock(); if (f) { nr_files++; goto new_one; @@ -108,6 +92,7 @@ struct file * get_empty_filp(void) printk("VFS: file-max limit %d reached\n", max_files); old_max = max_files; } + file_list_unlock(); return NULL; } @@ -131,20 +116,77 @@ int init_private_file(struct file *filp, struct dentry *dentry, int mode) return 0; } -void fput(struct file *file) +void _fput(struct file *file) { - if (atomic_dec_and_test(&file->f_count)) { - locks_remove_flock(file); - __fput(file); - remove_filp(file); - insert_file_free(file); - } + atomic_inc(&file->f_count); + + lock_kernel(); + locks_remove_flock(file); /* Still need the */ + __fput(file); /* big lock here. */ + unlock_kernel(); + + atomic_set(&file->f_count, 0); + file_list_lock(); + list_del(&file->f_list); + list_add(&file->f_list, &free_list); + nr_free_files++; + file_list_unlock(); } +/* Here. put_filp() is SMP-safe now. */ + void put_filp(struct file *file) { - if (atomic_dec_and_test(&file->f_count)) { - remove_filp(file); - insert_file_free(file); + if(atomic_dec_and_test(&file->f_count)) { + file_list_lock(); + list_del(&file->f_list); + list_add(&file->f_list, &free_list); + nr_free_files++; + file_list_unlock(); + } +} + +void file_move(struct file *file, struct list_head *list) +{ + if (!list) + return; + file_list_lock(); + list_del(&file->f_list); + list_add(&file->f_list, list); + file_list_unlock(); +} + +void file_moveto(struct file *new, struct file *old) +{ + file_list_lock(); + list_del(&new->f_list); + list_add(&new->f_list, &old->f_list); + file_list_unlock(); +} + +int fs_may_remount_ro(struct super_block *sb) +{ + struct list_head *p; + + /* Check that no files are currently opened for writing. */ + file_list_lock(); + for (p = sb->s_files.next; p != &sb->s_files; p = p->next) { + struct file *file = list_entry(p, struct file, f_list); + struct inode *inode = file->f_dentry->d_inode; + if (!inode) + continue; + + /* File with pending delete? */ + if (inode->i_nlink == 0) + goto too_bad; + + /* Writable file? */ + if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE)) + return 0; } + file_list_unlock(); + return 1; /* Tis' cool bro. */ +too_bad: + file_list_unlock(); + return 0; } |