Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
[linux-2.6] / fs / filesystems.c
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->next)
73                 return -EBUSY;
74         INIT_LIST_HEAD(&fs->fs_supers);
75         write_lock(&file_systems_lock);
76         p = find_filesystem(fs->name);
77         if (*p)
78                 res = -EBUSY;
79         else
80                 *p = fs;
81         write_unlock(&file_systems_lock);
82         return res;
83 }
84
85 EXPORT_SYMBOL(register_filesystem);
86
87 /**
88  *      unregister_filesystem - unregister a file system
89  *      @fs: filesystem to unregister
90  *
91  *      Remove a file system that was previously successfully registered
92  *      with the kernel. An error is returned if the file system is not found.
93  *      Zero is returned on a success.
94  *      
95  *      Once this function has returned the &struct file_system_type structure
96  *      may be freed or reused.
97  */
98  
99 int unregister_filesystem(struct file_system_type * fs)
100 {
101         struct file_system_type ** tmp;
102
103         write_lock(&file_systems_lock);
104         tmp = &file_systems;
105         while (*tmp) {
106                 if (fs == *tmp) {
107                         *tmp = fs->next;
108                         fs->next = NULL;
109                         write_unlock(&file_systems_lock);
110                         return 0;
111                 }
112                 tmp = &(*tmp)->next;
113         }
114         write_unlock(&file_systems_lock);
115         return -EINVAL;
116 }
117
118 EXPORT_SYMBOL(unregister_filesystem);
119
120 static int fs_index(const char __user * __name)
121 {
122         struct file_system_type * tmp;
123         char * name;
124         int err, index;
125
126         name = getname(__name);
127         err = PTR_ERR(name);
128         if (IS_ERR(name))
129                 return err;
130
131         err = -EINVAL;
132         read_lock(&file_systems_lock);
133         for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) {
134                 if (strcmp(tmp->name,name) == 0) {
135                         err = index;
136                         break;
137                 }
138         }
139         read_unlock(&file_systems_lock);
140         putname(name);
141         return err;
142 }
143
144 static int fs_name(unsigned int index, char __user * buf)
145 {
146         struct file_system_type * tmp;
147         int len, res;
148
149         read_lock(&file_systems_lock);
150         for (tmp = file_systems; tmp; tmp = tmp->next, index--)
151                 if (index <= 0 && try_module_get(tmp->owner))
152                         break;
153         read_unlock(&file_systems_lock);
154         if (!tmp)
155                 return -EINVAL;
156
157         /* OK, we got the reference, so we can safely block */
158         len = strlen(tmp->name) + 1;
159         res = copy_to_user(buf, tmp->name, len) ? -EFAULT : 0;
160         put_filesystem(tmp);
161         return res;
162 }
163
164 static int fs_maxindex(void)
165 {
166         struct file_system_type * tmp;
167         int index;
168
169         read_lock(&file_systems_lock);
170         for (tmp = file_systems, index = 0 ; tmp ; tmp = tmp->next, index++)
171                 ;
172         read_unlock(&file_systems_lock);
173         return index;
174 }
175
176 /*
177  * Whee.. Weird sysv syscall. 
178  */
179 asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2)
180 {
181         int retval = -EINVAL;
182
183         switch (option) {
184                 case 1:
185                         retval = fs_index((const char __user *) arg1);
186                         break;
187
188                 case 2:
189                         retval = fs_name(arg1, (char __user *) arg2);
190                         break;
191
192                 case 3:
193                         retval = fs_maxindex();
194                         break;
195         }
196         return retval;
197 }
198
199 int get_filesystem_list(char * buf)
200 {
201         int len = 0;
202         struct file_system_type * tmp;
203
204         read_lock(&file_systems_lock);
205         tmp = file_systems;
206         while (tmp && len < PAGE_SIZE - 80) {
207                 len += sprintf(buf+len, "%s\t%s\n",
208                         (tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev",
209                         tmp->name);
210                 tmp = tmp->next;
211         }
212         read_unlock(&file_systems_lock);
213         return len;
214 }
215
216 struct file_system_type *get_fs_type(const char *name)
217 {
218         struct file_system_type *fs;
219
220         read_lock(&file_systems_lock);
221         fs = *(find_filesystem(name));
222         if (fs && !try_module_get(fs->owner))
223                 fs = NULL;
224         read_unlock(&file_systems_lock);
225         if (!fs && (request_module("%s", name) == 0)) {
226                 read_lock(&file_systems_lock);
227                 fs = *(find_filesystem(name));
228                 if (fs && !try_module_get(fs->owner))
229                         fs = NULL;
230                 read_unlock(&file_systems_lock);
231         }
232         return fs;
233 }
234
235 EXPORT_SYMBOL(get_fs_type);