xref: /linux/fs/filesystems.c (revision a7edd0e676d51145ae634a2acf7a447e319200fa)
1 /*
2  *  linux/fs/filesystems.c
3  *
4  *  Copyright (C) 1991, 1992  Linus Torvalds
5  *
6  *  table of configured filesystems
7  */
8 
9 #include <linux/syscalls.h>
10 #include <linux/fs.h>
11 #include <linux/slab.h>
12 #include <linux/kmod.h>
13 #include <linux/init.h>
14 #include <linux/module.h>
15 #include <asm/uaccess.h>
16 
17 /*
18  * Handling of filesystem drivers list.
19  * Rules:
20  *	Inclusion to/removals from/scanning of list are protected by spinlock.
21  *	During the unload module must call unregister_filesystem().
22  *	We can access the fields of list element if:
23  *		1) spinlock is held or
24  *		2) we hold the reference to the module.
25  *	The latter can be guaranteed by call of try_module_get(); if it
26  *	returned 0 we must skip the element, otherwise we got the reference.
27  *	Once the reference is obtained we can drop the spinlock.
28  */
29 
30 static struct file_system_type *file_systems;
31 static DEFINE_RWLOCK(file_systems_lock);
32 
33 /* WARNING: This can be used only if we _already_ own a reference */
34 void get_filesystem(struct file_system_type *fs)
35 {
36 	__module_get(fs->owner);
37 }
38 
39 void put_filesystem(struct file_system_type *fs)
40 {
41 	module_put(fs->owner);
42 }
43 
44 static struct file_system_type **find_filesystem(const char *name)
45 {
46 	struct file_system_type **p;
47 	for (p=&file_systems; *p; p=&(*p)->next)
48 		if (strcmp((*p)->name,name) == 0)
49 			break;
50 	return p;
51 }
52 
53 /**
54  *	register_filesystem - register a new filesystem
55  *	@fs: the file system structure
56  *
57  *	Adds the file system passed to the list of file systems the kernel
58  *	is aware of for mount and other syscalls. Returns 0 on success,
59  *	or a negative errno code on an error.
60  *
61  *	The &struct file_system_type that is passed is linked into the kernel
62  *	structures and must not be freed until the file system has been
63  *	unregistered.
64  */
65 
66 int register_filesystem(struct file_system_type * fs)
67 {
68 	int res = 0;
69 	struct file_system_type ** p;
70 
71 	if (fs->next)
72 		return -EBUSY;
73 	INIT_LIST_HEAD(&fs->fs_supers);
74 	write_lock(&file_systems_lock);
75 	p = find_filesystem(fs->name);
76 	if (*p)
77 		res = -EBUSY;
78 	else
79 		*p = fs;
80 	write_unlock(&file_systems_lock);
81 	return res;
82 }
83 
84 EXPORT_SYMBOL(register_filesystem);
85 
86 /**
87  *	unregister_filesystem - unregister a file system
88  *	@fs: filesystem to unregister
89  *
90  *	Remove a file system that was previously successfully registered
91  *	with the kernel. An error is returned if the file system is not found.
92  *	Zero is returned on a success.
93  *
94  *	Once this function has returned the &struct file_system_type structure
95  *	may be freed or reused.
96  */
97 
98 int unregister_filesystem(struct file_system_type * fs)
99 {
100 	struct file_system_type ** tmp;
101 
102 	write_lock(&file_systems_lock);
103 	tmp = &file_systems;
104 	while (*tmp) {
105 		if (fs == *tmp) {
106 			*tmp = fs->next;
107 			fs->next = NULL;
108 			write_unlock(&file_systems_lock);
109 			return 0;
110 		}
111 		tmp = &(*tmp)->next;
112 	}
113 	write_unlock(&file_systems_lock);
114 	return -EINVAL;
115 }
116 
117 EXPORT_SYMBOL(unregister_filesystem);
118 
119 static int fs_index(const char __user * __name)
120 {
121 	struct file_system_type * tmp;
122 	char * name;
123 	int err, index;
124 
125 	name = getname(__name);
126 	err = PTR_ERR(name);
127 	if (IS_ERR(name))
128 		return err;
129 
130 	err = -EINVAL;
131 	read_lock(&file_systems_lock);
132 	for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) {
133 		if (strcmp(tmp->name,name) == 0) {
134 			err = index;
135 			break;
136 		}
137 	}
138 	read_unlock(&file_systems_lock);
139 	putname(name);
140 	return err;
141 }
142 
143 static int fs_name(unsigned int index, char __user * buf)
144 {
145 	struct file_system_type * tmp;
146 	int len, res;
147 
148 	read_lock(&file_systems_lock);
149 	for (tmp = file_systems; tmp; tmp = tmp->next, index--)
150 		if (index <= 0 && try_module_get(tmp->owner))
151 			break;
152 	read_unlock(&file_systems_lock);
153 	if (!tmp)
154 		return -EINVAL;
155 
156 	/* OK, we got the reference, so we can safely block */
157 	len = strlen(tmp->name) + 1;
158 	res = copy_to_user(buf, tmp->name, len) ? -EFAULT : 0;
159 	put_filesystem(tmp);
160 	return res;
161 }
162 
163 static int fs_maxindex(void)
164 {
165 	struct file_system_type * tmp;
166 	int index;
167 
168 	read_lock(&file_systems_lock);
169 	for (tmp = file_systems, index = 0 ; tmp ; tmp = tmp->next, index++)
170 		;
171 	read_unlock(&file_systems_lock);
172 	return index;
173 }
174 
175 /*
176  * Whee.. Weird sysv syscall.
177  */
178 asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2)
179 {
180 	int retval = -EINVAL;
181 
182 	switch (option) {
183 		case 1:
184 			retval = fs_index((const char __user *) arg1);
185 			break;
186 
187 		case 2:
188 			retval = fs_name(arg1, (char __user *) arg2);
189 			break;
190 
191 		case 3:
192 			retval = fs_maxindex();
193 			break;
194 	}
195 	return retval;
196 }
197 
198 int get_filesystem_list(char * buf)
199 {
200 	int len = 0;
201 	struct file_system_type * tmp;
202 
203 	read_lock(&file_systems_lock);
204 	tmp = file_systems;
205 	while (tmp && len < PAGE_SIZE - 80) {
206 		len += sprintf(buf+len, "%s\t%s\n",
207 			(tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev",
208 			tmp->name);
209 		tmp = tmp->next;
210 	}
211 	read_unlock(&file_systems_lock);
212 	return len;
213 }
214 
215 struct file_system_type *get_fs_type(const char *name)
216 {
217 	struct file_system_type *fs;
218 
219 	read_lock(&file_systems_lock);
220 	fs = *(find_filesystem(name));
221 	if (fs && !try_module_get(fs->owner))
222 		fs = NULL;
223 	read_unlock(&file_systems_lock);
224 	if (!fs && (request_module("%s", name) == 0)) {
225 		read_lock(&file_systems_lock);
226 		fs = *(find_filesystem(name));
227 		if (fs && !try_module_get(fs->owner))
228 			fs = NULL;
229 		read_unlock(&file_systems_lock);
230 	}
231 	return fs;
232 }
233 
234 EXPORT_SYMBOL(get_fs_type);
235