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 $"
29 #include <asm/bitops.h>
30 #include <asm/uaccess.h>
31 #include <asm/system.h>
33 #include <linux/errno.h>
35 #include <linux/ext2_fs.h>
36 #include <linux/slab.h>
37 #include <linux/vmalloc.h>
38 #include <linux/sched.h>
39 #include <linux/stat.h>
40 #include <linux/string.h>
41 #include <linux/blkdev.h>
42 #include <linux/init.h>
43 #include <linux/devfs_fs_kernel.h>
44 #include <linux/module.h>
46 #include "intermezzo_fs.h"
47 #include "intermezzo_psdev.h"
50 long presto_vmemory = 0;
51 long presto_kmemory = 0;
54 /* returns an allocated string, copied out from data if opt is found */
55 static char *opt_read(const char *opt, char *data)
60 CDEBUG(D_SUPER, "option: %s, data %s\n", opt, data);
61 if ( strncmp(opt, data, strlen(opt)) )
64 if ( (value = strchr(data, '=')) == NULL )
68 PRESTO_ALLOC(retval, strlen(value) + 1);
70 CERROR("InterMezzo: Out of memory!\n");
74 strcpy(retval, value);
75 CDEBUG(D_SUPER, "Assigned option: %s, value %s\n", opt, retval);
79 static void opt_store(char **dst, char *opt)
82 CERROR("intermezzo: store_opt, error dst == NULL\n");
85 PRESTO_FREE(*dst, strlen(*dst) + 1);
89 static void opt_set_default(char **dst, char *defval)
92 CERROR("intermezzo: store_opt, error dst == NULL\n");
95 PRESTO_FREE(*dst, strlen(*dst) + 1);
98 PRESTO_ALLOC(def_alloced, strlen(defval)+1);
100 CERROR("InterMezzo: Out of memory!\n");
103 strcpy(def_alloced, defval);
109 /* Find the options for InterMezzo in "options", saving them into the
110 * passed pointers. If the pointer is null, the option is discarded.
111 * Copy out all non-InterMezzo options into cache_data (to be passed
112 * to the read_super operation of the cache). The return value will
113 * be a pointer to the end of the cache_data.
115 static char *presto_options(struct file_system_type *fstype,
116 char *options, char *cache_data,
117 char **cache_type, char **fileset,
121 char *opt_ptr = options;
122 char *cache_data_end = cache_data;
124 /* set the defaults */
125 if (strcmp(fstype->name, "intermezzo") == 0)
126 opt_set_default(cache_type, "ext3");
128 opt_set_default(cache_type, "tmpfs");
130 if (!options || !cache_data)
131 return cache_data_end;
134 CDEBUG(D_SUPER, "parsing options\n");
135 while ((this_char = strsep (&opt_ptr, ",")) != NULL) {
139 CDEBUG(D_SUPER, "this_char %s\n", this_char);
141 if ( (opt = opt_read("fileset", this_char)) ) {
142 opt_store(fileset, opt);
145 if ( (opt = opt_read("cache_type", this_char)) ) {
146 opt_store(cache_type, opt);
149 if ( (opt = opt_read("channel", this_char)) ) {
150 opt_store(channel, opt);
155 sprintf(cache_data_end, "%s%s",
156 cache_data_end != cache_data ? ",":"",
160 return cache_data_end;
163 static int presto_set_channel(struct presto_cache *cache, char *channel)
169 minor = izo_psdev_get_free_channel();
171 minor = simple_strtoul(channel, NULL, 0);
173 if (minor < 0 || minor >= MAX_CHANNEL) {
174 CERROR("all channels in use or channel too large %d\n",
179 cache->cache_psdev = &(izo_channels[minor]);
180 list_add(&cache->cache_channel_list,
181 &cache->cache_psdev->uc_cache_list);
187 /* We always need to remove the presto options before passing
188 mount options to cache FS */
190 presto_get_sb(struct file_system_type *izo_type, int flags,
191 const char *devname, void *data)
193 struct file_system_type *fstype;
194 struct presto_cache *cache = NULL;
195 char *cache_data = NULL;
196 char *cache_data_end;
197 char *cache_type = NULL;
198 char *fileset = NULL;
199 char *channel = NULL;
200 struct super_block *sb;
206 /* reserve space for the cache's data */
207 PRESTO_ALLOC(cache_data, PAGE_SIZE);
209 CERROR("presto_read_super: Cannot allocate data page.\n");
214 /* read and validate options */
215 cache_data_end = presto_options(izo_type, data, cache_data, &cache_type,
218 /* was there anything for the cache filesystem in the data? */
219 if (cache_data_end == cache_data) {
220 PRESTO_FREE(cache_data, PAGE_SIZE);
221 cache_data_end = cache_data = NULL;
223 CDEBUG(D_SUPER, "cache_data at %p is: %s\n", cache_data,
227 /* set up the cache */
228 cache = presto_cache_init();
230 CERROR("presto_read_super: failure allocating cache.\n");
234 cache->cache_type = cache_type;
236 /* link cache to channel */
237 minor = presto_set_channel(cache, channel);
243 CDEBUG(D_SUPER, "Presto: type=%s, fset=%s, dev= %d, flags %x\n",
244 cache_type, fileset?fileset:"NULL", minor, cache->cache_flags);
246 /* get the filter for the cache */
247 fstype = get_fs_type(cache_type);
248 cache->cache_filter = filter_get_filter_fs((const char *)cache_type);
249 if ( !fstype || !cache->cache_filter) {
250 CERROR("Presto: unrecognized fs type or cache type\n");
255 sb = fstype->get_sb(fstype, flags, devname, cache_data);
257 if ( !sb || IS_ERR(sb)) {
258 CERROR("InterMezzo: cache mount failure.\n");
263 /* can we in fact mount the cache */
264 if (sb->s_bdev && (strcmp(fstype->name, "vintermezzo") == 0)) {
265 CERROR("vintermezzo must not be used with a block device\n");
270 /* this might have been freed above */
272 PRESTO_FREE(cache_data, PAGE_SIZE);
276 cache->cache_sb = sb;
277 cache->cache_root = dget(sb->s_root);
279 /* we now know the dev of the cache: hash the cache */
280 presto_cache_add(cache);
281 err = izo_prepare_fileset(sb->s_root, fileset);
283 filter_setup_journal_ops(cache->cache_filter, cache->cache_type);
285 /* make sure we have our own super operations: sb
286 still contains the cache operations */
287 filter_setup_super_ops(cache->cache_filter, sb->s_op,
289 sb->s_op = filter_c2usops(cache->cache_filter);
291 /* get izo directory operations: sb->s_root->d_inode exists now */
292 filter_setup_dir_ops(cache->cache_filter, sb->s_root->d_inode,
293 &presto_dir_iops, &presto_dir_fops);
294 filter_setup_dentry_ops(cache->cache_filter, sb->s_root->d_op,
296 sb->s_root->d_inode->i_op = filter_c2udiops(cache->cache_filter);
297 sb->s_root->d_inode->i_fop = filter_c2udfops(cache->cache_filter);
298 sb->s_root->d_op = filter_c2udops(cache->cache_filter);
304 CDEBUG(D_SUPER, "out_err called\n");
306 PRESTO_FREE(cache, sizeof(struct presto_cache));
308 PRESTO_FREE(cache_data, PAGE_SIZE);
310 PRESTO_FREE(fileset, strlen(fileset) + 1);
312 PRESTO_FREE(channel, strlen(channel) + 1);
314 PRESTO_FREE(cache_type, strlen(cache_type) + 1);
316 CDEBUG(D_MALLOC, "mount error exit: kmem %ld, vmem %ld\n",
317 presto_kmemory, presto_vmemory);
318 return ERR_PTR(-EINVAL);
325 static DECLARE_FSTYPE(presto_fs_type, "izo", presto_read_super, FS_REQUIRES_DEV);
326 static DECLARE_FSTYPE(vpresto_fs_type, "vintermezzo", presto_read_super, FS_LITTER);
328 static struct file_system_type vpresto_fs_type = {
329 .owner = THIS_MODULE,
330 .name = "vintermezzo",
331 .get_sb = presto_get_sb,
332 .kill_sb = kill_litter_super,
334 static struct file_system_type presto_fs_type = {
335 .owner = THIS_MODULE,
336 .name = "intermezzo",
337 .get_sb = presto_get_sb,
338 .kill_sb = kill_block_super,
339 .fs_flags = FS_REQUIRES_DEV,
345 int __init init_intermezzo_fs(void)
349 printk(KERN_INFO "InterMezzo Kernel/Intersync communications " INTERMEZZO_VERSION
350 " info@clusterfs.com\n");
352 status = presto_psdev_init();
354 CERROR("Problem (%d) in init_intermezzo_psdev\n", status);
358 status = init_intermezzo_sysctl();
360 CERROR("presto: failed in init_intermezzo_sysctl!\n");
363 presto_cache_init_hash();
365 if (!presto_init_ddata_cache()) {
366 CERROR("presto out of memory!\n");
370 status = register_filesystem(&presto_fs_type);
372 CERROR("presto: failed in register_filesystem!\n");
374 status = register_filesystem(&vpresto_fs_type);
376 CERROR("vpresto: failed in register_filesystem!\n");
381 void __exit exit_intermezzo_fs(void)
387 if ( (err = unregister_filesystem(&presto_fs_type)) != 0 ) {
388 CERROR("presto: failed to unregister filesystem\n");
390 if ( (err = unregister_filesystem(&vpresto_fs_type)) != 0 ) {
391 CERROR("vpresto: failed to unregister filesystem\n");
394 presto_psdev_cleanup();
395 cleanup_intermezzo_sysctl();
396 presto_cleanup_ddata_cache();
397 CERROR("after cleanup: kmem %ld, vmem %ld\n",
398 presto_kmemory, presto_vmemory);
402 MODULE_AUTHOR("Cluster Filesystems Inc. <info@clusterfs.com>");
403 MODULE_DESCRIPTION("InterMezzo Kernel/Intersync communications " INTERMEZZO_VERSION);
404 MODULE_LICENSE("GPL");
406 module_init(init_intermezzo_fs)
407 module_exit(exit_intermezzo_fs)