patch-2.1.37 linux/fs/file_table.c

Next file: linux/fs/inode.c
Previous file: linux/fs/fcntl.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.36/linux/fs/file_table.c linux/fs/file_table.c
@@ -2,143 +2,104 @@
  *  linux/fs/file_table.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/fs.h>
+#include <linux/file.h>
 #include <linux/string.h>
 #include <linux/mm.h>
+#include <linux/slab.h>
 
-/*
- * 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;
+/* SLAB cache for filp's. */
+static kmem_cache_t *filp_cache;
+
+/* sysctl tunables... */
 int nr_files = 0;
 int max_files = NR_FILE;
 
-/*
- * Insert a new file structure at the head of the list of available ones.
- */
-static inline void insert_file_free(struct file *file)
-{
-	struct file *next, *prev;
+/* Free list management, if you are here you must have f_count == 0 */
+static struct file * free_filps = NULL;
 
-	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;
-}
-
-/*
- * Remove a file structure from the list of available ones.
- */
-static inline void remove_file_free(struct file *file)
+void insert_file_free(struct file *file)
 {
-	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;
+	if((file->f_next = free_filps) != NULL)
+		free_filps->f_pprev = &file->f_next;
+	free_filps = file;
+	file->f_pprev = &free_filps;
 }
 
-/*
- * Insert a file structure at the end of the list of available ones.
- */
-static inline void put_last_free(struct file *file)
+/* The list of in-use filp's must be exported (ugh...) */
+struct file *inuse_filps = NULL;
+
+static inline void put_inuse(struct file *file)
 {
-	struct file *next, *prev;
+	if((file->f_next = inuse_filps) != NULL)
+		inuse_filps->f_pprev = &file->f_next;
+	inuse_filps = file;
+	file->f_pprev = &inuse_filps;
+}
 
-	next = first_file;
-	file->f_next = next;
-	prev = next->f_prev;
-	next->f_prev = file;
-	file->f_prev = prev;
-	prev->f_next = file;
-}
-
-/*
- * 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.
- */
+/* Get more free filp's. */
 static int grow_files(void)
 {
-	struct file * file;
-	int i;
-
-	/*
-	 * 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 0;
-
-	nr_files += i = PAGE_SIZE/sizeof(struct file);
-
-	if (!first_file)
-		file->f_count = 0,
-		file->f_next = file->f_prev = first_file = file++,
-		i--;
+	int i = 16;
 
-	for (; i ; i--)
-		insert_file_free(file++);
+	while(i--) {
+		struct file * file = kmem_cache_alloc(filp_cache, SLAB_KERNEL);
+		if(!file) {
+			if(i == 15)
+				return 0;
+			goto got_some;
+		}
 
+		insert_file_free(file);
+		nr_files++;
+	}
+got_some:
 	return 1;
 }
 
-unsigned long file_table_init(unsigned long start, unsigned long end)
+void file_table_init(void)
 {
-	return start;
+	filp_cache = kmem_cache_create("filp", sizeof(struct file),
+				       sizeof(unsigned long) * 8,
+				       SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if(!filp_cache)
+		panic("VFS: Cannot alloc filp SLAB cache.");
 }
 
-/*
- * Find an unused file structure and return a pointer to it.
+/* 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;
 
-	/*
-	 * 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());
+again:
+	if((f = free_filps) != NULL) {
+		remove_filp(f);
+		memset(f, 0, sizeof(*f));
+		f->f_count = 1;
+		f->f_version = ++event;
+		put_inuse(f);
+	} else {
+		int max = max_files;
+
+		/* Reserve a few files for the super-user.. */
+		if (current->euid)
+			max -= 10;
 
-	return NULL;
+		if (nr_files < max && grow_files())
+			goto again;
+
+		/* Big problems... */
+	}
+	return f;
 }
 
 #ifdef CONFIG_QUOTA
@@ -146,10 +107,9 @@
 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)
+	for (filp = inuse_filps; filp; filp = filp->f_next) {
+		if (!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);
@@ -161,10 +121,9 @@
 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)
+	for (filp = inuse_filps; filp; filp = filp->f_next) {
+		if (!filp->f_inode || filp->f_inode->i_dev != dev)
 			continue;
 		if (IS_WRITABLE(filp->f_inode)) {
 			filp->f_inode->i_dquot[type] = NODQUOT;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov