patch-1.3.16 linux/fs/file_table.c

Next file: linux/fs/minix/truncate.c
Previous file: linux/fs/ext2/truncate.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.15/linux/fs/file_table.c linux/fs/file_table.c
@@ -8,11 +8,20 @@
 #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;
 
+/*
+ * Insert a new file structure at the head of the list of available ones.
+ */
 static void insert_file_free(struct file *file)
 {
+	file->f_count = 0;
 	file->f_next = first_file;
 	file->f_prev = first_file->f_prev;
 	file->f_next->f_prev = file;
@@ -20,71 +29,93 @@
 	first_file = file;
 }
 
+/*
+ * Remove a file structure from the list of available ones.
+ */
 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->f_prev = file->f_prev;
+	file->f_prev->f_next = file->f_next;
 	file->f_next = file->f_prev = NULL;
 }
 
+/*
+ * Insert a file structure at the end of the list of available ones.
+ */
 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)
+/*
+ * 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;
 	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;
-	}
+	/* 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 < NR_FILE && grow_files());
+
 	return NULL;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this