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