1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
3 *
4 * Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
5 * Copyright (C) 2000 Stelias Computing, Inc.
6 * Copyright (C) 2000 Red Hat, Inc.
7 *
8 * This file is part of InterMezzo, http://www.inter-mezzo.org.
9 *
10 * InterMezzo is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU General Public
12 * License as published by the Free Software Foundation.
13 *
14 * InterMezzo is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with InterMezzo; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 * presto's super.c
24 */
25
26 static char rcsid[] __attribute ((unused)) = "$Id: super.c,v 1.41 2002/10/03 03:50:49 rread Exp $";
27 #define INTERMEZZO_VERSION "$Revision: 1.41 $"
28
29 #include <stdarg.h>
30
31 #include <asm/bitops.h>
32 #include <asm/uaccess.h>
33 #include <asm/system.h>
34
35 #include <linux/errno.h>
36 #include <linux/fs.h>
37 #include <linux/ext2_fs.h>
38 #include <linux/slab.h>
39 #include <linux/vmalloc.h>
40 #include <linux/sched.h>
41 #include <linux/stat.h>
42 #include <linux/string.h>
43 #include <linux/locks.h>
44 #include <linux/blkdev.h>
45 #include <linux/init.h>
46 #include <linux/devfs_fs_kernel.h>
47 #define __NO_VERSION__
48 #include <linux/module.h>
49
50 #include <linux/intermezzo_fs.h>
51 #include <linux/intermezzo_psdev.h>
52
53 #ifdef PRESTO_DEBUG
54 long presto_vmemory = 0;
55 long presto_kmemory = 0;
56 #endif
57
58 /* returns an allocated string, copied out from data if opt is found */
59 static char *opt_read(const char *opt, char *data)
60 {
61 char *value;
62 char *retval;
63
64 CDEBUG(D_SUPER, "option: %s, data %s\n", opt, data);
65 if ( strncmp(opt, data, strlen(opt)) )
66 return NULL;
67
68 if ( (value = strchr(data, '=')) == NULL )
69 return NULL;
70
71 value++;
72 PRESTO_ALLOC(retval, strlen(value) + 1);
73 if ( !retval ) {
74 CERROR("InterMezzo: Out of memory!\n");
75 return NULL;
76 }
77
78 strcpy(retval, value);
79 CDEBUG(D_SUPER, "Assigned option: %s, value %s\n", opt, retval);
80 return retval;
81 }
82
83 static void opt_store(char **dst, char *opt)
84 {
85 if (!dst)
86 CERROR("intermezzo: store_opt, error dst == NULL\n");
87
88 if (*dst)
89 PRESTO_FREE(*dst, strlen(*dst) + 1);
90 *dst = opt;
91 }
92
93 static void opt_set_default(char **dst, char *defval)
94 {
95 if (!dst)
96 CERROR("intermezzo: store_opt, error dst == NULL\n");
97
98 if (*dst)
99 PRESTO_FREE(*dst, strlen(*dst) + 1);
100 if (defval) {
101 char *def_alloced;
102 PRESTO_ALLOC(def_alloced, strlen(defval)+1);
103 if (!def_alloced) {
104 CERROR("InterMezzo: Out of memory!\n");
105 return ;
106 }
107 strcpy(def_alloced, defval);
108 *dst = def_alloced;
109 }
110 }
111
112
113 /* Find the options for InterMezzo in "options", saving them into the
114 * passed pointers. If the pointer is null, the option is discarded.
115 * Copy out all non-InterMezzo options into cache_data (to be passed
116 * to the read_super operation of the cache). The return value will
117 * be a pointer to the end of the cache_data.
118 */
119 static char *presto_options(struct super_block *sb,
120 char *options, char *cache_data,
121 char **cache_type, char **fileset,
122 char **channel)
123 {
124 char *this_char;
125 char *cache_data_end = cache_data;
126
127 /* set the defaults */
128 if (strcmp(sb->s_type->name, "intermezzo") == 0)
129 opt_set_default(cache_type, "ext3");
130 else
131 opt_set_default(cache_type, "tmpfs");
132
133 if (!options || !cache_data)
134 return cache_data_end;
135
136
137 CDEBUG(D_SUPER, "parsing options\n");
138 for (this_char = strtok (options, ",");
139 this_char != NULL;
140 this_char = strtok (NULL, ",")) {
141 char *opt;
142 CDEBUG(D_SUPER, "this_char %s\n", this_char);
143
144 if ( (opt = opt_read("fileset", this_char)) ) {
145 opt_store(fileset, opt);
146 continue;
147 }
148 if ( (opt = opt_read("cache_type", this_char)) ) {
149 opt_store(cache_type, opt);
150 continue;
151 }
152 if ( (opt = opt_read("channel", this_char)) ) {
153 opt_store(channel, opt);
154 continue;
155 }
156
157 cache_data_end +=
158 sprintf(cache_data_end, "%s%s",
159 cache_data_end != cache_data ? ",":"",
160 this_char);
161 }
162
163 return cache_data_end;
164 }
165
166 static int presto_set_channel(struct presto_cache *cache, char *channel)
167 {
168 int minor;
169
170 ENTRY;
171 if (!channel) {
172 minor = izo_psdev_get_free_channel();
173 } else {
174 minor = simple_strtoul(channel, NULL, 0);
175 }
176 if (minor < 0 || minor >= MAX_CHANNEL) {
177 CERROR("all channels in use or channel too large %d\n",
178 minor);
179 return -EINVAL;
180 }
181
182 cache->cache_psdev = &(izo_channels[minor]);
183 list_add(&cache->cache_channel_list,
184 &cache->cache_psdev->uc_cache_list);
185
186 EXIT;
187 return minor;
188 }
189
190 /* We always need to remove the presto options before passing
191 mount options to cache FS */
192 struct super_block * presto_read_super(struct super_block * sb,
193 void * data, int silent)
194 {
195 struct file_system_type *fstype;
196 struct presto_cache *cache = NULL;
197 char *cache_data = NULL;
198 char *cache_data_end;
199 char *cache_type = NULL;
200 char *fileset = NULL;
201 char *channel = NULL;
202 int err;
203 unsigned int minor;
204
205 ENTRY;
206
207 /* reserve space for the cache's data */
208 PRESTO_ALLOC(cache_data, PAGE_SIZE);
209 if ( !cache_data ) {
210 CERROR("presto_read_super: Cannot allocate data page.\n");
211 EXIT;
212 goto out_err;
213 }
214
215 /* read and validate options */
216 cache_data_end = presto_options(sb, data, cache_data, &cache_type,
217 &fileset, &channel);
218
219 /* was there anything for the cache filesystem in the data? */
220 if (cache_data_end == cache_data) {
221 PRESTO_FREE(cache_data, PAGE_SIZE);
222 cache_data = NULL;
223 } else {
224 CDEBUG(D_SUPER, "cache_data at %p is: %s\n", cache_data,
225 cache_data);
226 }
227
228 /* set up the cache */
229 cache = presto_cache_init();
230 if ( !cache ) {
231 CERROR("presto_read_super: failure allocating cache.\n");
232 EXIT;
233 goto out_err;
234 }
235 cache->cache_type = cache_type;
236
237 /* link cache to channel */
238 minor = presto_set_channel(cache, channel);
239 if (minor < 0) {
240 EXIT;
241 goto out_err;
242 }
243
244 CDEBUG(D_SUPER, "Presto: type=%s, fset=%s, dev= %d, flags %x\n",
245 cache_type, fileset?fileset:"NULL", minor, cache->cache_flags);
246
247 MOD_INC_USE_COUNT;
248
249 /* get the filter for the cache */
250 fstype = get_fs_type(cache_type);
251 cache->cache_filter = filter_get_filter_fs((const char *)cache_type);
252 if ( !fstype || !cache->cache_filter) {
253 CERROR("Presto: unrecognized fs type or cache type\n");
254 MOD_DEC_USE_COUNT;
255 EXIT;
256 goto out_err;
257 }
258
259 /* can we in fact mount the cache */
260 if ((fstype->fs_flags & FS_REQUIRES_DEV) && !sb->s_bdev) {
261 CERROR("filesystem \"%s\" requires a valid block device\n",
262 cache_type);
263 MOD_DEC_USE_COUNT;
264 EXIT;
265 goto out_err;
266 }
267
268 sb = fstype->read_super(sb, cache_data, silent);
269
270 /* this might have been freed above */
271 if (cache_data) {
272 PRESTO_FREE(cache_data, PAGE_SIZE);
273 cache_data = NULL;
274 }
275
276 if ( !sb ) {
277 CERROR("InterMezzo: cache mount failure.\n");
278 MOD_DEC_USE_COUNT;
279 EXIT;
280 goto out_err;
281 }
282
283 cache->cache_sb = sb;
284 cache->cache_root = dget(sb->s_root);
285
286 /* we now know the dev of the cache: hash the cache */
287 presto_cache_add(cache, sb->s_dev);
288 err = izo_prepare_fileset(sb->s_root, fileset);
289
290 filter_setup_journal_ops(cache->cache_filter, cache->cache_type);
291
292 /* make sure we have our own super operations: sb
293 still contains the cache operations */
294 filter_setup_super_ops(cache->cache_filter, sb->s_op,
295 &presto_super_ops);
296 sb->s_op = filter_c2usops(cache->cache_filter);
297
298 /* get izo directory operations: sb->s_root->d_inode exists now */
299 filter_setup_dir_ops(cache->cache_filter, sb->s_root->d_inode,
300 &presto_dir_iops, &presto_dir_fops);
301 filter_setup_dentry_ops(cache->cache_filter, sb->s_root->d_op,
302 &presto_dentry_ops);
303 sb->s_root->d_inode->i_op = filter_c2udiops(cache->cache_filter);
304 sb->s_root->d_inode->i_fop = filter_c2udfops(cache->cache_filter);
305 sb->s_root->d_op = filter_c2udops(cache->cache_filter);
306
307 EXIT;
308 return sb;
309
310 out_err:
311 CDEBUG(D_SUPER, "out_err called\n");
312 if (cache)
313 PRESTO_FREE(cache, sizeof(struct presto_cache));
314 if (cache_data)
315 PRESTO_FREE(cache_data, PAGE_SIZE);
316 if (fileset)
317 PRESTO_FREE(fileset, strlen(fileset) + 1);
318 if (channel)
319 PRESTO_FREE(channel, strlen(channel) + 1);
320 if (cache_type)
321 PRESTO_FREE(cache_type, strlen(cache_type) + 1);
322
323 CDEBUG(D_MALLOC, "mount error exit: kmem %ld, vmem %ld\n",
324 presto_kmemory, presto_vmemory);
325 return NULL;
326 }
327
328
329
330 #ifdef PRESTO_DEVEL
331 static DECLARE_FSTYPE(presto_fs_type, "izo", presto_read_super, FS_REQUIRES_DEV);
332 static DECLARE_FSTYPE(vpresto_fs_type, "vintermezzo", presto_read_super, FS_LITTER);
333 #else
334 static DECLARE_FSTYPE(vpresto_fs_type, "vintermezzo", presto_read_super, FS_LITTER);
335 static DECLARE_FSTYPE(presto_fs_type, "intermezzo", presto_read_super, FS_REQUIRES_DEV);
336 #endif
337
338
339
340 int __init init_intermezzo_fs(void)
341 {
342 int status;
343
344 printk(KERN_INFO "InterMezzo Kernel/Intersync communications " INTERMEZZO_VERSION
345 " info@clusterfs.com\n");
346
347 status = presto_psdev_init();
348 if ( status ) {
349 CERROR("Problem (%d) in init_intermezzo_psdev\n", status);
350 return status;
351 }
352
353 status = init_intermezzo_sysctl();
354 if (status) {
355 CERROR("presto: failed in init_intermezzo_sysctl!\n");
356 }
357
358 presto_cache_init_hash();
359
360 if (!presto_init_ddata_cache()) {
361 CERROR("presto out of memory!\n");
362 return -ENOMEM;
363 }
364
365 status = register_filesystem(&presto_fs_type);
366 if (status) {
367 CERROR("presto: failed in register_filesystem!\n");
368 }
369 status = register_filesystem(&vpresto_fs_type);
370 if (status) {
371 CERROR("vpresto: failed in register_filesystem!\n");
372 }
373 return status;
374 }
375
376 void __exit exit_intermezzo_fs(void)
377 {
378 int err;
379
380 ENTRY;
381
382 if ( (err = unregister_filesystem(&presto_fs_type)) != 0 ) {
383 CERROR("presto: failed to unregister filesystem\n");
384 }
385 if ( (err = unregister_filesystem(&vpresto_fs_type)) != 0 ) {
386 CERROR("vpresto: failed to unregister filesystem\n");
387 }
388
389 presto_psdev_cleanup();
390 cleanup_intermezzo_sysctl();
391 presto_cleanup_ddata_cache();
392 CERROR("after cleanup: kmem %ld, vmem %ld\n",
393 presto_kmemory, presto_vmemory);
394 }
395
396
397 MODULE_AUTHOR("Cluster Filesystems Inc. <info@clusterfs.com>");
398 MODULE_DESCRIPTION("InterMezzo Kernel/Intersync communications " INTERMEZZO_VERSION);
399 MODULE_LICENSE("GPL");
400
401 module_init(init_intermezzo_fs)
402 module_exit(exit_intermezzo_fs)
Cache object: 6162494771123da7cbccbee96293f8a3
|