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