ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / 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/fs.h>
10 #include <linux/slab.h>
11 #include <linux/kmod.h>
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <asm/uaccess.h>
15
16 /*
17  * Handling of filesystem drivers list.
18  * Rules:
19  *      Inclusion to/removals from/scanning of list are protected by spinlock.
20  *      During the unload module must call unregister_filesystem().
21  *      We can access the fields of list element if:
22  *              1) spinlock is held or
23  *              2) we hold the reference to the module.
24  *      The latter can be guaranteed by call of try_module_get(); if it
25  *      returned 0 we must skip the element, otherwise we got the reference.
26  *      Once the reference is obtained we can drop the spinlock.
27  */
28
29 static struct file_system_type *file_systems;
30 static rwlock_t file_systems_lock = RW_LOCK_UNLOCKED;
31
32 /* WARNING: This can be used only if we _already_ own a reference */
33 void get_filesystem(struct file_system_type *fs)
34 {
35         __module_get(fs->owner);
36 }
37
38 void put_filesystem(struct file_system_type *fs)
39 {
40         module_put(fs->owner);
41 }
42
43 static struct file_system_type **find_filesystem(const char *name)
44 {
45         struct file_system_type **p;
46         for (p=&file_systems; *p; p=&(*p)->next)
47                 if (strcmp((*p)->name,name) == 0)
48                         break;
49         return p;
50 }
51
52 /**
53  *      register_filesystem - register a new filesystem
54  *      @fs: the file system structure
55  *
56  *      Adds the file system passed to the list of file systems the kernel
57  *      is aware of for mount and other syscalls. Returns 0 on success,
58  *      or a negative errno code on an error.
59  *
60  *      The &struct file_system_type that is passed is linked into the kernel 
61  *      structures and must not be freed until the file system has been
62  *      unregistered.
63  */
64  
65 int register_filesystem(struct file_system_type * fs)
66 {
67         int res = 0;
68         struct file_system_type ** p;
69
70         if (!fs)
71                 return -EINVAL;
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);