1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
5 * Copyright (C) 2000 Stelias Computing, Inc.
6 * Copyright (C) 2000 Red Hat, Inc.
8 * This file is part of InterMezzo, http://www.inter-mezzo.org.
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.
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.
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.
26 static char rcsid
[] __attribute ((unused
)) = "$Id: super.c,v 1.4 2002/10/12 02:16:19 rread Exp $";
27 #define INTERMEZZO_VERSION "$Revision: 1.4 $"
31 #include <asm/bitops.h>
32 #include <asm/uaccess.h>
33 #include <asm/system.h>
35 #include <linux/errno.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/smp_lock.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>
50 #include <linux/intermezzo_fs.h>
51 #include <linux/intermezzo_psdev.h>
54 long presto_vmemory
= 0;
55 long presto_kmemory
= 0;
58 /* returns an allocated string, copied out from data if opt is found */
59 static char *opt_read(const char *opt
, char *data
)
64 CDEBUG(D_SUPER
, "option: %s, data %s\n", opt
, data
);
65 if ( strncmp(opt
, data
, strlen(opt
)) )
68 if ( (value
= strchr(data
, '=')) == NULL
)
72 PRESTO_ALLOC(retval
, strlen(value
) + 1);
74 CERROR("InterMezzo: Out of memory!\n");
78 strcpy(retval
, value
);
79 CDEBUG(D_SUPER
, "Assigned option: %s, value %s\n", opt
, retval
);
83 static void opt_store(char **dst
, char *opt
)
86 CERROR("intermezzo: store_opt, error dst == NULL\n");
89 PRESTO_FREE(*dst
, strlen(*dst
) + 1);
93 static void opt_set_default(char **dst
, char *defval
)
96 CERROR("intermezzo: store_opt, error dst == NULL\n");
99 PRESTO_FREE(*dst
, strlen(*dst
) + 1);
102 PRESTO_ALLOC(def_alloced
, strlen(defval
)+1);
104 CERROR("InterMezzo: Out of memory!\n");
107 strcpy(def_alloced
, defval
);
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.
119 static char *presto_options(struct file_system_type
*fstype
,
120 char *options
, char *cache_data
,
121 char **cache_type
, char **fileset
,
125 char *opt_ptr
= options
;
126 char *cache_data_end
= cache_data
;
128 /* set the defaults */
129 if (strcmp(fstype
->name
, "intermezzo") == 0)
130 opt_set_default(cache_type
, "ext3");
132 opt_set_default(cache_type
, "tmpfs");
134 if (!options
|| !cache_data
)
135 return cache_data_end
;
138 CDEBUG(D_SUPER
, "parsing options\n");
139 while ((this_char
= strsep (&opt_ptr
, ",")) != NULL
) {
143 CDEBUG(D_SUPER
, "this_char %s\n", this_char
);
145 if ( (opt
= opt_read("fileset", this_char
)) ) {
146 opt_store(fileset
, opt
);
149 if ( (opt
= opt_read("cache_type", this_char
)) ) {
150 opt_store(cache_type
, opt
);
153 if ( (opt
= opt_read("channel", this_char
)) ) {
154 opt_store(channel
, opt
);
159 sprintf(cache_data_end
, "%s%s",
160 cache_data_end
!= cache_data
? ",":"",
164 return cache_data_end
;
167 static int presto_set_channel(struct presto_cache
*cache
, char *channel
)
173 minor
= izo_psdev_get_free_channel();
175 minor
= simple_strtoul(channel
, NULL
, 0);
177 if (minor
< 0 || minor
>= MAX_CHANNEL
) {
178 CERROR("all channels in use or channel too large %d\n",
183 cache
->cache_psdev
= &(izo_channels
[minor
]);
184 list_add(&cache
->cache_channel_list
,
185 &cache
->cache_psdev
->uc_cache_list
);
191 /* We always need to remove the presto options before passing
192 mount options to cache FS */
193 struct super_block
* presto_get_sb(struct file_system_type
*izo_type
,
194 int flags
, char *devname
, void * data
)
196 struct file_system_type
*fstype
;
197 struct presto_cache
*cache
= NULL
;
198 char *cache_data
= NULL
;
199 char *cache_data_end
;
200 char *cache_type
= NULL
;
201 char *fileset
= NULL
;
202 char *channel
= NULL
;
203 struct super_block
*sb
;
209 /* reserve space for the cache's data */
210 PRESTO_ALLOC(cache_data
, PAGE_SIZE
);
212 CERROR("presto_read_super: Cannot allocate data page.\n");
217 /* read and validate options */
218 cache_data_end
= presto_options(izo_type
, data
, cache_data
, &cache_type
,
221 /* was there anything for the cache filesystem in the data? */
222 if (cache_data_end
== cache_data
) {
223 PRESTO_FREE(cache_data
, PAGE_SIZE
);
224 cache_data_end
= cache_data
= NULL
;
226 CDEBUG(D_SUPER
, "cache_data at %p is: %s\n", cache_data
,
230 /* set up the cache */
231 cache
= presto_cache_init();
233 CERROR("presto_read_super: failure allocating cache.\n");
237 cache
->cache_type
= cache_type
;
239 /* link cache to channel */
240 minor
= presto_set_channel(cache
, channel
);
246 CDEBUG(D_SUPER
, "Presto: type=%s, fset=%s, dev= %d, flags %x\n",
247 cache_type
, fileset
?fileset
:"NULL", minor
, cache
->cache_flags
);
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");
258 sb
= fstype
->get_sb(fstype
, flags
, devname
, cache_data
);
260 if ( !sb
|| IS_ERR(sb
)) {
261 CERROR("InterMezzo: cache mount failure.\n");
266 /* can we in fact mount the cache */
267 if (sb
->s_bdev
&& (strcmp(fstype
->name
, "vintermezzo") == 0)) {
268 CERROR("vintermezzo must not be used with a block device\n");
273 /* this might have been freed above */
275 PRESTO_FREE(cache_data
, PAGE_SIZE
);
279 cache
->cache_sb
= sb
;
280 cache
->cache_root
= dget(sb
->s_root
);
282 /* we now know the dev of the cache: hash the cache */
283 presto_cache_add(cache
);
284 err
= izo_prepare_fileset(sb
->s_root
, fileset
);
286 filter_setup_journal_ops(cache
->cache_filter
, cache
->cache_type
);
288 /* make sure we have our own super operations: sb
289 still contains the cache operations */
290 filter_setup_super_ops(cache
->cache_filter
, sb
->s_op
,
292 sb
->s_op
= filter_c2usops(cache
->cache_filter
);
294 /* get izo directory operations: sb->s_root->d_inode exists now */
295 filter_setup_dir_ops(cache
->cache_filter
, sb
->s_root
->d_inode
,
296 &presto_dir_iops
, &presto_dir_fops
);
297 filter_setup_dentry_ops(cache
->cache_filter
, sb
->s_root
->d_op
,
299 sb
->s_root
->d_inode
->i_op
= filter_c2udiops(cache
->cache_filter
);
300 sb
->s_root
->d_inode
->i_fop
= filter_c2udfops(cache
->cache_filter
);
301 sb
->s_root
->d_op
= filter_c2udops(cache
->cache_filter
);
307 CDEBUG(D_SUPER
, "out_err called\n");
309 PRESTO_FREE(cache
, sizeof(struct presto_cache
));
311 PRESTO_FREE(cache_data
, PAGE_SIZE
);
313 PRESTO_FREE(fileset
, strlen(fileset
) + 1);
315 PRESTO_FREE(channel
, strlen(channel
) + 1);
317 PRESTO_FREE(cache_type
, strlen(cache_type
) + 1);
319 CDEBUG(D_MALLOC
, "mount error exit: kmem %ld, vmem %ld\n",
320 presto_kmemory
, presto_vmemory
);
328 static DECLARE_FSTYPE(presto_fs_type
, "izo", presto_read_super
, FS_REQUIRES_DEV
);
329 static DECLARE_FSTYPE(vpresto_fs_type
, "vintermezzo", presto_read_super
, FS_LITTER
);
331 static struct file_system_type vpresto_fs_type
= {
332 .owner
= THIS_MODULE
,
333 .name
= "vintermezzo",
334 .get_sb
= presto_get_sb
,
335 .kill_sb
= kill_litter_super
,
337 static struct file_system_type presto_fs_type
= {
338 .owner
= THIS_MODULE
,
339 .name
= "intermezzo",
340 .get_sb
= presto_get_sb
,
341 .kill_sb
= kill_block_super
,
342 .fs_flags
= FS_REQUIRES_DEV
,
348 int __init
init_intermezzo_fs(void)
352 printk(KERN_INFO
"InterMezzo Kernel/Intersync communications " INTERMEZZO_VERSION
353 " info@clusterfs.com\n");
355 status
= presto_psdev_init();
357 CERROR("Problem (%d) in init_intermezzo_psdev\n", status
);
361 status
= init_intermezzo_sysctl();
363 CERROR("presto: failed in init_intermezzo_sysctl!\n");
366 presto_cache_init_hash();
368 if (!presto_init_ddata_cache()) {
369 CERROR("presto out of memory!\n");
373 status
= register_filesystem(&presto_fs_type
);
375 CERROR("presto: failed in register_filesystem!\n");
377 status
= register_filesystem(&vpresto_fs_type
);
379 CERROR("vpresto: failed in register_filesystem!\n");
384 void __exit
exit_intermezzo_fs(void)
390 if ( (err
= unregister_filesystem(&presto_fs_type
)) != 0 ) {
391 CERROR("presto: failed to unregister filesystem\n");
393 if ( (err
= unregister_filesystem(&vpresto_fs_type
)) != 0 ) {
394 CERROR("vpresto: failed to unregister filesystem\n");
397 presto_psdev_cleanup();
398 cleanup_intermezzo_sysctl();
399 presto_cleanup_ddata_cache();
400 CERROR("after cleanup: kmem %ld, vmem %ld\n",
401 presto_kmemory
, presto_vmemory
);
405 MODULE_AUTHOR("Cluster Filesystems Inc. <info@clusterfs.com>");
406 MODULE_DESCRIPTION("InterMezzo Kernel/Intersync communications " INTERMEZZO_VERSION
);
407 MODULE_LICENSE("GPL");
409 module_init(init_intermezzo_fs
)
410 module_exit(exit_intermezzo_fs
)