[PATCH] hfsplus: don't modify journaled volume
[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/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);