xref: /openbmc/linux/fs/filesystems.c (revision 643d1f7f)
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, unsigned len)
45 {
46 	struct file_system_type **p;
47 	for (p=&file_systems; *p; p=&(*p)->next)
48 		if (strlen((*p)->name) == len &&
49 		    strncmp((*p)->name, name, len) == 0)
50 			break;
51 	return p;
52 }
53 
54 /**
55  *	register_filesystem - register a new filesystem
56  *	@fs: the file system structure
57  *
58  *	Adds the file system passed to the list of file systems the kernel
59  *	is aware of for mount and other syscalls. Returns 0 on success,
60  *	or a negative errno code on an error.
61  *
62  *	The &struct file_system_type that is passed is linked into the kernel
63  *	structures and must not be freed until the file system has been
64  *	unregistered.
65  */
66 
67 int register_filesystem(struct file_system_type * fs)
68 {
69 	int res = 0;
70 	struct file_system_type ** p;
71 
72 	BUG_ON(strchr(fs->name, '.'));
73 	if (fs->next)
74 		return -EBUSY;
75 	INIT_LIST_HEAD(&fs->fs_supers);
76 	write_lock(&file_systems_lock);
77 	p = find_filesystem(fs->name, strlen(fs->name));
78 	if (*p)
79 		res = -EBUSY;
80 	else
81 		*p = fs;
82 	write_unlock(&file_systems_lock);
83 	return res;
84 }
85 
86 EXPORT_SYMBOL(register_filesystem);
87 
88 /**
89  *	unregister_filesystem - unregister a file system
90  *	@fs: filesystem to unregister
91  *
92  *	Remove a file system that was previously successfully registered
93  *	with the kernel. An error is returned if the file system is not found.
94  *	Zero is returned on a success.
95  *
96  *	Once this function has returned the &struct file_system_type structure
97  *	may be freed or reused.
98  */
99 
100 int unregister_filesystem(struct file_system_type * fs)
101 {
102 	struct file_system_type ** tmp;
103 
104 	write_lock(&file_systems_lock);
105 	tmp = &file_systems;
106 	while (*tmp) {
107 		if (fs == *tmp) {
108 			*tmp = fs->next;
109 			fs->next = NULL;
110 			write_unlock(&file_systems_lock);
111 			return 0;
112 		}
113 		tmp = &(*tmp)->next;
114 	}
115 	write_unlock(&file_systems_lock);
116 	return -EINVAL;
117 }
118 
119 EXPORT_SYMBOL(unregister_filesystem);
120 
121 static int fs_index(const char __user * __name)
122 {
123 	struct file_system_type * tmp;
124 	char * name;
125 	int err, index;
126 
127 	name = getname(__name);
128 	err = PTR_ERR(name);
129 	if (IS_ERR(name))
130 		return err;
131 
132 	err = -EINVAL;
133 	read_lock(&file_systems_lock);
134 	for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) {
135 		if (strcmp(tmp->name,name) == 0) {
136 			err = index;
137 			break;
138 		}
139 	}
140 	read_unlock(&file_systems_lock);
141 	putname(name);
142 	return err;
143 }
144 
145 static int fs_name(unsigned int index, char __user * buf)
146 {
147 	struct file_system_type * tmp;
148 	int len, res;
149 
150 	read_lock(&file_systems_lock);
151 	for (tmp = file_systems; tmp; tmp = tmp->next, index--)
152 		if (index <= 0 && try_module_get(tmp->owner))
153 			break;
154 	read_unlock(&file_systems_lock);
155 	if (!tmp)
156 		return -EINVAL;
157 
158 	/* OK, we got the reference, so we can safely block */
159 	len = strlen(tmp->name) + 1;
160 	res = copy_to_user(buf, tmp->name, len) ? -EFAULT : 0;
161 	put_filesystem(tmp);
162 	return res;
163 }
164 
165 static int fs_maxindex(void)
166 {
167 	struct file_system_type * tmp;
168 	int index;
169 
170 	read_lock(&file_systems_lock);
171 	for (tmp = file_systems, index = 0 ; tmp ; tmp = tmp->next, index++)
172 		;
173 	read_unlock(&file_systems_lock);
174 	return index;
175 }
176 
177 /*
178  * Whee.. Weird sysv syscall.
179  */
180 asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2)
181 {
182 	int retval = -EINVAL;
183 
184 	switch (option) {
185 		case 1:
186 			retval = fs_index((const char __user *) arg1);
187 			break;
188 
189 		case 2:
190 			retval = fs_name(arg1, (char __user *) arg2);
191 			break;
192 
193 		case 3:
194 			retval = fs_maxindex();
195 			break;
196 	}
197 	return retval;
198 }
199 
200 int get_filesystem_list(char * buf)
201 {
202 	int len = 0;
203 	struct file_system_type * tmp;
204 
205 	read_lock(&file_systems_lock);
206 	tmp = file_systems;
207 	while (tmp && len < PAGE_SIZE - 80) {
208 		len += sprintf(buf+len, "%s\t%s\n",
209 			(tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev",
210 			tmp->name);
211 		tmp = tmp->next;
212 	}
213 	read_unlock(&file_systems_lock);
214 	return len;
215 }
216 
217 struct file_system_type *get_fs_type(const char *name)
218 {
219 	struct file_system_type *fs;
220 	const char *dot = strchr(name, '.');
221 	unsigned len = dot ? dot - name : strlen(name);
222 
223 	read_lock(&file_systems_lock);
224 	fs = *(find_filesystem(name, len));
225 	if (fs && !try_module_get(fs->owner))
226 		fs = NULL;
227 	read_unlock(&file_systems_lock);
228 	if (!fs && (request_module("%.*s", len, name) == 0)) {
229 		read_lock(&file_systems_lock);
230 		fs = *(find_filesystem(name, len));
231 		if (fs && !try_module_get(fs->owner))
232 			fs = NULL;
233 		read_unlock(&file_systems_lock);
234 	}
235 
236 	if (dot && fs && !(fs->fs_flags & FS_HAS_SUBTYPE)) {
237 		put_filesystem(fs);
238 		fs = NULL;
239 	}
240 	return fs;
241 }
242 
243 EXPORT_SYMBOL(get_fs_type);
244