File: file_table.c

package info (click to toggle)
kernel-source-2.0.32 2.0.32-5
  • links: PTS
  • area: main
  • in suites: hamm
  • size: 29,648 kB
  • ctags: 86,850
  • sloc: ansic: 542,141; asm: 26,201; makefile: 3,423; sh: 1,195; perl: 727; tcl: 408; cpp: 277; lisp: 211; awk: 134
file content (178 lines) | stat: -rw-r--r-- 3,936 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*
 *  linux/fs/file_table.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 */

#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/mm.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;
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;

	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)
{
	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;
}

/*
 * Insert a file structure at the end of the list of available ones.
 */
static inline void put_last_free(struct file *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;
}

/*
 * 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;

	/*
	 * 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--;

	for (; i ; i--)
		insert_file_free(file++);

	return 1;
}

unsigned long file_table_init(unsigned long start, unsigned long end)
{
	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;

	/*
	 * 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) {
				/* The f_next pointer is followed by the f_prev pointer */
				memset(f, 0, offsetof(struct file, f_next));
				memset(&f->f_prev + 1, 0, sizeof(*f) - sizeof(f->f_prev) - offsetof(struct file, f_prev));
				f->f_count = 1;
				f->f_version = ++event;
				first_file = f->f_next;
				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;
		}
	}
}

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