The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/intermezzo/super.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.