Merge branch 'core-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[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 <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);