super.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:13k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  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. static char rcsid[] __attribute ((unused)) = "$Id: super.c,v 1.41 2002/10/03 03:50:49 rread Exp $";
  26. #define INTERMEZZO_VERSION "$Revision: 1.41 $"
  27. #include <stdarg.h>
  28. #include <asm/bitops.h>
  29. #include <asm/uaccess.h>
  30. #include <asm/system.h>
  31. #include <linux/errno.h>
  32. #include <linux/fs.h>
  33. #include <linux/ext2_fs.h>
  34. #include <linux/slab.h>
  35. #include <linux/vmalloc.h>
  36. #include <linux/sched.h>
  37. #include <linux/stat.h>
  38. #include <linux/string.h>
  39. #include <linux/locks.h>
  40. #include <linux/blkdev.h>
  41. #include <linux/init.h>
  42. #include <linux/devfs_fs_kernel.h>
  43. #define __NO_VERSION__
  44. #include <linux/module.h>
  45. #include <linux/intermezzo_fs.h>
  46. #include <linux/intermezzo_psdev.h>
  47. #ifdef PRESTO_DEBUG
  48. long presto_vmemory = 0;
  49. long presto_kmemory = 0;
  50. #endif
  51. /* returns an allocated string, copied out from data if opt is found */
  52. static char *opt_read(const char *opt, char *data)
  53. {
  54.         char *value;
  55.         char *retval;
  56.         CDEBUG(D_SUPER, "option: %s, data %sn", opt, data);
  57.         if ( strncmp(opt, data, strlen(opt)) )
  58.                 return NULL;
  59.         if ( (value = strchr(data, '=')) == NULL )
  60.                 return NULL;
  61.         value++;
  62.         PRESTO_ALLOC(retval, strlen(value) + 1);
  63.         if ( !retval ) {
  64.                 CERROR("InterMezzo: Out of memory!n");
  65.                 return NULL;
  66.         }
  67.         strcpy(retval, value);
  68.         CDEBUG(D_SUPER, "Assigned option: %s, value %sn", opt, retval);
  69.         return retval;
  70. }
  71. static void opt_store(char **dst, char *opt)
  72. {
  73.         if (!dst) 
  74.                 CERROR("intermezzo: store_opt, error dst == NULLn"); 
  75.         if (*dst)
  76.                 PRESTO_FREE(*dst, strlen(*dst) + 1);
  77.         *dst = opt;
  78. }
  79. static void opt_set_default(char **dst, char *defval)
  80. {
  81.         if (!dst) 
  82.                 CERROR("intermezzo: store_opt, error dst == NULLn"); 
  83.         if (*dst)
  84.                 PRESTO_FREE(*dst, strlen(*dst) + 1);
  85.         if (defval) {
  86.                 char *def_alloced; 
  87.                 PRESTO_ALLOC(def_alloced, strlen(defval)+1);
  88.                 if (!def_alloced) {
  89.                         CERROR("InterMezzo: Out of memory!n");
  90.                         return ;
  91.                 }
  92.                 strcpy(def_alloced, defval);
  93.                 *dst = def_alloced; 
  94.         }
  95. }
  96. /* Find the options for InterMezzo in "options", saving them into the
  97.  * passed pointers.  If the pointer is null, the option is discarded.
  98.  * Copy out all non-InterMezzo options into cache_data (to be passed
  99.  * to the read_super operation of the cache).  The return value will
  100.  * be a pointer to the end of the cache_data.
  101.  */
  102. static char *presto_options(struct super_block *sb, 
  103.                             char *options, char *cache_data,
  104.                             char **cache_type, char **fileset,
  105.                             char **channel)
  106. {
  107.         char *this_char;
  108.         char *cache_data_end = cache_data;
  109.         /* set the defaults */ 
  110.         if (strcmp(sb->s_type->name, "intermezzo") == 0)
  111.             opt_set_default(cache_type, "ext3"); 
  112.         else 
  113.             opt_set_default(cache_type, "tmpfs"); 
  114.             
  115.         if (!options || !cache_data)
  116.                 return cache_data_end;
  117.         CDEBUG(D_SUPER, "parsing optionsn");
  118.         for (this_char = strtok (options, ",");
  119.              this_char != NULL;
  120.              this_char = strtok (NULL, ",")) {
  121.                 char *opt;
  122.                 CDEBUG(D_SUPER, "this_char %sn", this_char);
  123.                 if ( (opt = opt_read("fileset", this_char)) ) {
  124.                         opt_store(fileset, opt);
  125.                         continue;
  126.                 }
  127.                 if ( (opt = opt_read("cache_type", this_char)) ) {
  128.                         opt_store(cache_type, opt);
  129.                         continue;
  130.                 }
  131.                 if ( (opt = opt_read("channel", this_char)) ) {
  132.                         opt_store(channel, opt);
  133.                         continue;
  134.                 }
  135.                 cache_data_end += 
  136.                         sprintf(cache_data_end, "%s%s",
  137.                                 cache_data_end != cache_data ? ",":"", 
  138.                                 this_char);
  139.         }
  140.         return cache_data_end;
  141. }
  142. static int presto_set_channel(struct presto_cache *cache, char *channel)
  143. {
  144.         int minor; 
  145.         ENTRY;
  146.         if (!channel) {
  147.                 minor = izo_psdev_get_free_channel();
  148.         } else {
  149.                 minor = simple_strtoul(channel, NULL, 0); 
  150.         }
  151.         if (minor < 0 || minor >= MAX_CHANNEL) { 
  152.                 CERROR("all channels in use or channel too large %dn", 
  153.                        minor);
  154.                 return -EINVAL;
  155.         }
  156.         
  157.         cache->cache_psdev = &(izo_channels[minor]);
  158.         list_add(&cache->cache_channel_list, 
  159.                  &cache->cache_psdev->uc_cache_list); 
  160.         EXIT;
  161.         return minor;
  162. }
  163. /* We always need to remove the presto options before passing 
  164.    mount options to cache FS */
  165. struct super_block * presto_read_super(struct super_block * sb,
  166.                                        void * data, int silent)
  167. {
  168.         struct file_system_type *fstype;
  169.         struct presto_cache *cache = NULL;
  170.         char *cache_data = NULL;
  171.         char *cache_data_end;
  172.         char *cache_type = NULL;
  173.         char *fileset = NULL;
  174.         char *channel = NULL;
  175.         int err; 
  176.         unsigned int minor;
  177.         ENTRY;
  178.         /* reserve space for the cache's data */
  179.         PRESTO_ALLOC(cache_data, PAGE_SIZE);
  180.         if ( !cache_data ) {
  181.                 CERROR("presto_read_super: Cannot allocate data page.n");
  182.                 EXIT;
  183.                 goto out_err;
  184.         }
  185.         /* read and validate options */
  186.         cache_data_end = presto_options(sb, data, cache_data, &cache_type, 
  187.                                         &fileset, &channel);
  188.         /* was there anything for the cache filesystem in the data? */
  189.         if (cache_data_end == cache_data) {
  190.                 PRESTO_FREE(cache_data, PAGE_SIZE);
  191.                 cache_data = NULL;
  192.         } else {
  193.                 CDEBUG(D_SUPER, "cache_data at %p is: %sn", cache_data,
  194.                        cache_data);
  195.         }
  196.         /* set up the cache */
  197.         cache = presto_cache_init();
  198.         if ( !cache ) {
  199.                 CERROR("presto_read_super: failure allocating cache.n");
  200.                 EXIT;
  201.                 goto out_err;
  202.         }
  203.         cache->cache_type = cache_type;
  204.         /* link cache to channel */ 
  205.         minor = presto_set_channel(cache, channel);
  206.         if (minor < 0) { 
  207.                 EXIT;
  208.                 goto out_err;
  209.         }
  210.         CDEBUG(D_SUPER, "Presto: type=%s, fset=%s, dev= %d, flags %xn",
  211.                cache_type, fileset?fileset:"NULL", minor, cache->cache_flags);
  212.         MOD_INC_USE_COUNT;
  213.         /* get the filter for the cache */
  214.         fstype = get_fs_type(cache_type);
  215.         cache->cache_filter = filter_get_filter_fs((const char *)cache_type); 
  216.         if ( !fstype || !cache->cache_filter) {
  217.                 CERROR("Presto: unrecognized fs type or cache typen");
  218.                 MOD_DEC_USE_COUNT;
  219.                 EXIT;
  220.                 goto out_err;
  221.         }
  222.         /* can we in fact mount the cache */ 
  223.         if ((fstype->fs_flags & FS_REQUIRES_DEV) && !sb->s_bdev) {
  224.                 CERROR("filesystem "%s" requires a valid block devicen",
  225.                                 cache_type);
  226.                 MOD_DEC_USE_COUNT;
  227.                 EXIT;
  228.                 goto out_err;
  229.         }
  230.         sb = fstype->read_super(sb, cache_data, silent);
  231.         /* this might have been freed above */
  232.         if (cache_data) {
  233.                 PRESTO_FREE(cache_data, PAGE_SIZE);
  234.                 cache_data = NULL;
  235.         }
  236.         if ( !sb ) {
  237.                 CERROR("InterMezzo: cache mount failure.n");
  238.                 MOD_DEC_USE_COUNT;
  239.                 EXIT;
  240.                 goto out_err;
  241.         }
  242.         cache->cache_sb = sb;
  243.         cache->cache_root = dget(sb->s_root);
  244.         /* we now know the dev of the cache: hash the cache */
  245.         presto_cache_add(cache, sb->s_dev);
  246.         err = izo_prepare_fileset(sb->s_root, fileset); 
  247.         filter_setup_journal_ops(cache->cache_filter, cache->cache_type); 
  248.         /* make sure we have our own super operations: sb
  249.            still contains the cache operations */
  250.         filter_setup_super_ops(cache->cache_filter, sb->s_op, 
  251.                                &presto_super_ops);
  252.         sb->s_op = filter_c2usops(cache->cache_filter);
  253.         /* get izo directory operations: sb->s_root->d_inode exists now */
  254.         filter_setup_dir_ops(cache->cache_filter, sb->s_root->d_inode,
  255.                              &presto_dir_iops, &presto_dir_fops);
  256.         filter_setup_dentry_ops(cache->cache_filter, sb->s_root->d_op, 
  257.                                 &presto_dentry_ops);
  258.         sb->s_root->d_inode->i_op = filter_c2udiops(cache->cache_filter);
  259.         sb->s_root->d_inode->i_fop = filter_c2udfops(cache->cache_filter);
  260.         sb->s_root->d_op = filter_c2udops(cache->cache_filter);
  261.         EXIT;
  262.         return sb;
  263.  out_err:
  264.         CDEBUG(D_SUPER, "out_err calledn");
  265.         if (cache)
  266.                 PRESTO_FREE(cache, sizeof(struct presto_cache));
  267.         if (cache_data)
  268.                 PRESTO_FREE(cache_data, PAGE_SIZE);
  269.         if (fileset)
  270.                 PRESTO_FREE(fileset, strlen(fileset) + 1);
  271.         if (channel)
  272.                 PRESTO_FREE(channel, strlen(channel) + 1);
  273.         if (cache_type)
  274.                 PRESTO_FREE(cache_type, strlen(cache_type) + 1);
  275.         CDEBUG(D_MALLOC, "mount error exit: kmem %ld, vmem %ldn",
  276.                presto_kmemory, presto_vmemory);
  277.         return NULL;
  278. }
  279. #ifdef PRESTO_DEVEL
  280. static DECLARE_FSTYPE(presto_fs_type, "izo", presto_read_super, FS_REQUIRES_DEV);
  281. static DECLARE_FSTYPE(vpresto_fs_type, "vintermezzo", presto_read_super, FS_LITTER);
  282. #else 
  283. static DECLARE_FSTYPE(vpresto_fs_type, "vintermezzo", presto_read_super, FS_LITTER);
  284. static DECLARE_FSTYPE(presto_fs_type, "intermezzo", presto_read_super, FS_REQUIRES_DEV);
  285. #endif
  286. int __init init_intermezzo_fs(void)
  287. {
  288.         int status;
  289.         printk(KERN_INFO "InterMezzo Kernel/Intersync communications " INTERMEZZO_VERSION
  290.                " info@clusterfs.comn");
  291.         status = presto_psdev_init();
  292.         if ( status ) {
  293.                 CERROR("Problem (%d) in init_intermezzo_psdevn", status);
  294.                 return status;
  295.         }
  296.         status = init_intermezzo_sysctl();
  297.         if (status) {
  298.                 CERROR("presto: failed in init_intermezzo_sysctl!n");
  299.         }
  300.         presto_cache_init_hash();
  301.         if (!presto_init_ddata_cache()) {
  302.                 CERROR("presto out of memory!n");
  303.                 return -ENOMEM;
  304.         }
  305.         status = register_filesystem(&presto_fs_type);
  306.         if (status) {
  307.                 CERROR("presto: failed in register_filesystem!n");
  308.         }
  309.         status = register_filesystem(&vpresto_fs_type);
  310.         if (status) {
  311.                 CERROR("vpresto: failed in register_filesystem!n");
  312.         }
  313.         return status;
  314. }
  315. void __exit exit_intermezzo_fs(void)
  316. {
  317.         int err;
  318.         ENTRY;
  319.         if ( (err = unregister_filesystem(&presto_fs_type)) != 0 ) {
  320.                 CERROR("presto: failed to unregister filesystemn");
  321.         }
  322.         if ( (err = unregister_filesystem(&vpresto_fs_type)) != 0 ) {
  323.                 CERROR("vpresto: failed to unregister filesystemn");
  324.         }
  325.         presto_psdev_cleanup();
  326.         cleanup_intermezzo_sysctl();
  327.         presto_cleanup_ddata_cache();
  328.         CERROR("after cleanup: kmem %ld, vmem %ldn",
  329.                presto_kmemory, presto_vmemory);
  330. }
  331. MODULE_AUTHOR("Cluster Filesystems Inc. <info@clusterfs.com>");
  332. MODULE_DESCRIPTION("InterMezzo Kernel/Intersync communications " INTERMEZZO_VERSION);
  333. MODULE_LICENSE("GPL");
  334. module_init(init_intermezzo_fs)
  335. module_exit(exit_intermezzo_fs)