super.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:16k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  presto's super.c
  3.  *
  4.  *  Copyright (C) 1998 Peter J. Braam
  5.  *  Copyright (C) 2000 Stelias Computing, Inc.
  6.  *  Copyright (C) 2000 Red Hat, Inc.
  7.  *
  8.  *
  9.  */
  10. #include <stdarg.h>
  11. #include <asm/bitops.h>
  12. #include <asm/uaccess.h>
  13. #include <asm/system.h>
  14. #include <linux/errno.h>
  15. #include <linux/fs.h>
  16. #include <linux/ext2_fs.h>
  17. #include <linux/slab.h>
  18. #include <linux/vmalloc.h>
  19. #include <linux/sched.h>
  20. #include <linux/stat.h>
  21. #include <linux/string.h>
  22. #include <linux/locks.h>
  23. #include <linux/blkdev.h>
  24. #include <linux/init.h>
  25. #define __NO_VERSION__
  26. #include <linux/module.h>
  27. #include <linux/intermezzo_fs.h>
  28. #include <linux/intermezzo_upcall.h>
  29. #include <linux/intermezzo_psdev.h>
  30. #ifdef PRESTO_DEBUG
  31. long presto_vmemory = 0;
  32. long presto_kmemory = 0;
  33. #endif
  34. extern struct presto_cache *presto_init_cache(void);
  35. extern inline void presto_cache_add(struct presto_cache *cache, kdev_t dev);
  36. extern inline void presto_init_cache_hash(void);
  37. int presto_remount(struct super_block *, int *, char *);
  38. extern ssize_t presto_file_write(struct file *file, const char *buf, 
  39.                                  size_t size, loff_t *off);
  40. /*
  41.  *  Reading the super block.
  42.  *
  43.  *
  44.  *
  45.  */
  46. /* returns an allocated string, copied out from data if opt is found */
  47. static char *read_opt(const char *opt, char *data)
  48. {
  49.         char *value;
  50.         char *retval;
  51.         CDEBUG(D_SUPER, "option: %s, data %sn", opt, data);
  52.         if ( strncmp(opt, data, strlen(opt)) )
  53.                 return NULL;
  54.         if ( (value = strchr(data, '=')) == NULL )
  55.                 return NULL;
  56.         value++;
  57.         PRESTO_ALLOC(retval, char *, strlen(value) + 1);
  58.         if ( !retval ) {
  59.                 printk("InterMezzo: Out of memory!n");
  60.                 return NULL;
  61.         }
  62.         strcpy(retval, value);
  63.         CDEBUG(D_SUPER, "Assigned option: %s, value %sn", opt, retval);
  64.         return retval;
  65. }
  66. static void store_opt(char **dst, char *opt, char *defval)
  67. {
  68.         if (dst) {
  69.                 if (*dst) { 
  70.                         PRESTO_FREE(*dst, strlen(*dst) + 1);
  71.                 }
  72.                 *dst = opt;
  73.         } else {
  74.                 printk("presto: store_opt, error dst == NULLn"); 
  75.         }
  76.         if (!opt && defval) {
  77.                 char *def_alloced; 
  78.                 PRESTO_ALLOC(def_alloced, char *, strlen(defval)+1);
  79.                 strcpy(def_alloced, defval);
  80.                 *dst = def_alloced; 
  81.         }
  82. }
  83. /* Find the options for InterMezzo in "options", saving them into the
  84.  * passed pointers.  If the pointer is null, the option is discarded.
  85.  * Copy out all non-InterMezzo options into cache_data (to be passed
  86.  * to the read_super operation of the cache).  The return value will
  87.  * be a pointer to the end of the cache_data.
  88.  */
  89. static char *presto_options(char *options, char *cache_data,
  90.                             char **cache_type, char **fileset,
  91.                             char **prestodev,  char **mtpt)
  92. {
  93.         char *this_char;
  94.         char *cache_data_end = cache_data;
  95.         if (!options || !cache_data)
  96.                 return cache_data_end;
  97.         /* set the defaults */ 
  98.         store_opt(cache_type, NULL, "ext3"); 
  99.         store_opt(prestodev, NULL, PRESTO_PSDEV_NAME "0"); 
  100.         CDEBUG(D_SUPER, "parsing optionsn");
  101.         for (this_char = strtok (options, ",");
  102.              this_char != NULL;
  103.              this_char = strtok (NULL, ",")) {
  104.                 char *opt;
  105.                 CDEBUG(D_SUPER, "this_char %sn", this_char);
  106.                 if ( (opt = read_opt("fileset", this_char)) ) {
  107.                         store_opt(fileset, opt, NULL);
  108.                         continue;
  109.                 }
  110.                 if ( (opt = read_opt("cache_type", this_char)) ) {
  111.                         store_opt(cache_type, opt, "ext3");
  112.                         continue;
  113.                 }
  114.                 if ( (opt = read_opt("mtpt", this_char)) ) {
  115.                         store_opt(mtpt, opt, NULL);
  116.                         continue;
  117.                 }
  118.                 if ( (opt = read_opt("prestodev", this_char)) ) {
  119.                         store_opt(prestodev, opt, PRESTO_PSDEV_NAME);
  120.                         continue;
  121.                 }
  122.                 cache_data_end += sprintf(cache_data_end, "%s%s",
  123.                                           cache_data_end != cache_data ? ",":"",
  124.                                           this_char);
  125.         }
  126.         return cache_data_end;
  127. }
  128. /*
  129.     map a /dev/intermezzoX path to a minor:
  130.     used to validate mount options passed to InterMezzo
  131.  */
  132. static int presto_get_minor(char *dev_path, int *minor)
  133. {
  134.         struct nameidata nd;
  135.         struct dentry *dentry;
  136.         kdev_t devno = 0;
  137.         int error; 
  138.         ENTRY;
  139.         /* Special case for root filesystem - use minor 0 always. */
  140.         if ( current->pid == 1 ) {
  141.                 *minor = 0;
  142.                 return 0;
  143.         }
  144.         error = presto_walk(dev_path, &nd);
  145.         if (error) {
  146. EXIT;
  147.                 return error;
  148. }
  149.         dentry = nd.dentry;
  150. error = -ENODEV;
  151.         if (!dentry->d_inode) { 
  152. EXIT;
  153. goto out;
  154. }
  155.         if (!S_ISCHR(dentry->d_inode->i_mode)) {
  156. EXIT;
  157. goto out;
  158. }
  159.         devno = dentry->d_inode->i_rdev;
  160.         if ( MAJOR(devno) != PRESTO_PSDEV_MAJOR ) { 
  161. EXIT;
  162. goto out;
  163. }
  164.         if ( MINOR(devno) >= MAX_PRESTODEV ) {
  165. EXIT;
  166. goto out;
  167. }
  168. EXIT;
  169.  out:
  170.         *minor = MINOR(devno);
  171.         path_release(&nd);
  172.         return 0;
  173. }
  174. /* We always need to remove the presto options before passing to bottom FS */
  175. struct super_block * presto_read_super(struct super_block * presto_sb,
  176.                                        void * data, int silent)
  177. {
  178.         struct super_block *mysb = NULL;
  179.         struct file_system_type *fstype;
  180.         struct presto_cache *cache = NULL;
  181.         char *cache_data = NULL;
  182.         char *cache_data_end;
  183.         char *cache_type = NULL;
  184.         char *fileset = NULL;
  185.         char *presto_mtpt = NULL;
  186.         char *prestodev = NULL;
  187.         struct filter_fs *ops;
  188.         int minor;
  189.         struct upc_comm *psdev;
  190.         ENTRY;
  191.         CDEBUG(D_MALLOC, "before parsing: kmem %ld, vmem %ldn",
  192.                presto_kmemory, presto_vmemory);
  193.         /* reserve space for the cache's data */
  194.         PRESTO_ALLOC(cache_data, void *, PAGE_SIZE);
  195.         if ( !cache_data ) {
  196.                 printk("presto_read_super: Cannot allocate data page.n");
  197.                 EXIT;
  198.                 goto out_err;
  199.         }
  200.         CDEBUG(D_SUPER, "mount opts: %sn", data ? (char *)data : "(none)");
  201.         /* read and validate options */
  202.         cache_data_end = presto_options(data, cache_data, &cache_type, &fileset,
  203.                                         &prestodev, &presto_mtpt);
  204.         /* was there anything for the cache filesystem in the data? */
  205.         if (cache_data_end == cache_data) {
  206.                 PRESTO_FREE(cache_data, PAGE_SIZE);
  207.                 cache_data = NULL;
  208.         } else {
  209.                 CDEBUG(D_SUPER, "cache_data at %p is: %sn", cache_data,
  210.                        cache_data);
  211.         }
  212.         /* prepare the communication channel */
  213.         if ( presto_get_minor(prestodev, &minor) ) {
  214.                 /* if (!silent) */
  215.                 printk("InterMezzo: %s not a valid presto devn", prestodev);
  216.                 EXIT;
  217.                 goto out_err;
  218.         }
  219.         psdev = &upc_comms[minor];
  220.         CDEBUG(D_SUPER, "n");
  221.         psdev->uc_no_filter = 1;
  222.         CDEBUG(D_SUPER, "presto minor is %dn", minor);
  223.         /* set up the cache */
  224.         cache = presto_init_cache();
  225.         if ( !cache ) {
  226.                 printk("presto_read_super: failure allocating cache.n");
  227.                 EXIT;
  228.                 goto out_err;
  229.         }
  230.         /* no options were passed: likely we are "/" readonly */
  231.         if ( !presto_mtpt || !fileset ) {
  232.                 cache->cache_flags |= CACHE_LENTO_RO | CACHE_CLIENT_RO;
  233.         }
  234.         cache->cache_psdev = psdev;
  235.         /* no options were passed: likely we are "/" readonly */
  236.         /* before the journaling infrastructure can work, these
  237.            need to be set; that happens in presto_remount */
  238.         if ( !presto_mtpt || !fileset ) {
  239.                 if (!presto_mtpt) 
  240.                         printk("No mountpoint marking cache ROn");
  241.                 if (!fileset) 
  242.                         printk("No fileset marking cache ROn");
  243.                 cache->cache_flags |= CACHE_LENTO_RO | CACHE_CLIENT_RO;
  244.         }
  245.         cache->cache_mtpt = presto_mtpt;
  246.         cache->cache_root_fileset = fileset;
  247.         cache->cache_type = cache_type;
  248.         printk("Presto: type=%s, vol=%s, dev=%s (minor %d), mtpt %s, flags %xn",
  249.                cache_type, fileset ? fileset : "NULL", prestodev, minor,
  250.                presto_mtpt ? presto_mtpt : "NULL", cache->cache_flags);
  251.         MOD_INC_USE_COUNT;
  252.         fstype = get_fs_type(cache_type);
  253.         cache->cache_filter = filter_get_filter_fs((const char *)cache_type); 
  254.         if ( !fstype || !cache->cache_filter) {
  255.                 printk("Presto: unrecognized fs type or cache typen");
  256.                 MOD_DEC_USE_COUNT;
  257.                 EXIT;
  258.                 goto out_err;
  259.         }
  260.         mysb = fstype->read_super(presto_sb, cache_data, silent);
  261.         /* this might have been freed above */
  262.         if (cache_data) {
  263.                 PRESTO_FREE(cache_data, PAGE_SIZE);
  264.                 cache_data = NULL;
  265.         }
  266.         if ( !mysb ) {
  267.                 /* if (!silent) */
  268.                 printk("InterMezzo: cache mount failure.n");
  269.                 MOD_DEC_USE_COUNT;
  270.                 EXIT;
  271.                 goto out_err;
  272.         }
  273. cache->cache_sb = mysb;
  274.         ops = filter_get_filter_fs(cache_type);
  275.         filter_setup_journal_ops(cache->cache_filter, cache->cache_type); 
  276.         /* we now know the dev of the cache: hash the cache */
  277.         presto_cache_add(cache, mysb->s_dev);
  278.         /* make sure we have our own super operations: mysb
  279.            still contains the cache operations */
  280.         filter_setup_super_ops(cache->cache_filter, mysb->s_op, 
  281.                                &presto_super_ops);
  282.         mysb->s_op = filter_c2usops(cache->cache_filter);
  283.         /* now get our own directory operations */
  284.         if ( mysb->s_root && mysb->s_root->d_inode ) {
  285.                 CDEBUG(D_SUPER, "n");
  286.                 filter_setup_dir_ops(cache->cache_filter, 
  287.                                      mysb->s_root->d_inode,
  288.                                      &presto_dir_iops, &presto_dir_fops);
  289.                 mysb->s_root->d_inode->i_op = filter_c2udiops(cache->cache_filter);
  290.                 CDEBUG(D_SUPER, "lookup at %pn", 
  291.                        mysb->s_root->d_inode->i_op->lookup);
  292.                 filter_setup_dentry_ops(cache->cache_filter, 
  293.                                         mysb->s_root->d_op, 
  294.                                         &presto_dentry_ops);
  295.                 presto_sb->s_root->d_op = filter_c2udops(cache->cache_filter);
  296.                 cache->cache_mtde = mysb->s_root;
  297.         }
  298.         CDEBUG(D_MALLOC, "after mounting: kmem %ld, vmem %ldn",
  299.                presto_kmemory, presto_vmemory);
  300.         EXIT;
  301.         return mysb;
  302.  out_err:
  303.         CDEBUG(D_SUPER, "out_err calledn");
  304.         if (cache)
  305.                 PRESTO_FREE(cache, sizeof(struct presto_cache));
  306.         if (cache_data)
  307.                 PRESTO_FREE(cache_data, PAGE_SIZE);
  308.         if (fileset)
  309.                 PRESTO_FREE(fileset, strlen(fileset) + 1);
  310.         if (presto_mtpt)
  311.                 PRESTO_FREE(presto_mtpt, strlen(presto_mtpt) + 1);
  312.         if (prestodev)
  313.                 PRESTO_FREE(prestodev, strlen(prestodev) + 1);
  314.         if (cache_type)
  315.                 PRESTO_FREE(cache_type, strlen(cache_type) + 1);
  316.         CDEBUG(D_MALLOC, "mount error exit: kmem %ld, vmem %ldn",
  317.                presto_kmemory, presto_vmemory);
  318.         return NULL;
  319. }
  320. int presto_remount(struct super_block * sb, int *flags, char *data)
  321. {
  322.         char *cache_data = NULL;
  323.         char *cache_data_end;
  324.         char **type;
  325.         char **fileset;
  326.         char **mtpt;
  327.         char **prestodev;
  328.         struct super_operations *sops;
  329.         struct presto_cache *cache = NULL;
  330.         int err = 0;
  331.         ENTRY;
  332.         CDEBUG(D_MALLOC, "before remount: kmem %ld, vmem %ldn",
  333.                presto_kmemory, presto_vmemory);
  334.         CDEBUG(D_SUPER, "remount opts: %sn", data ? (char *)data : "(none)");
  335.         if (data) {
  336.                 /* reserve space for the cache's data */
  337.                 PRESTO_ALLOC(cache_data, void *, PAGE_SIZE);
  338.                 if ( !cache_data ) {
  339.                         err = -ENOMEM;
  340.                         EXIT;
  341.                         goto out_err;
  342.                 }
  343.         }
  344.         cache = presto_find_cache(sb->s_dev);
  345.         if (!cache) {
  346.                 printk(__FUNCTION__ ": cannot find cache on remountn");
  347.                 err = -ENODEV;
  348.                 EXIT;
  349.                 goto out_err;
  350.         }
  351.         /* If an option has not yet been set, we allow it to be set on
  352.          * remount.  If an option already has a value, we pass NULL for
  353.          * the option pointer, which means that the InterMezzo option
  354.          * will be parsed but discarded.
  355.          */
  356.         type = cache->cache_type ? NULL : &cache->cache_type;
  357.         fileset = cache->cache_root_fileset ? NULL : &cache->cache_root_fileset;
  358.         prestodev = cache->cache_psdev ? NULL : &cache->cache_psdev->uc_devname;
  359.         mtpt = cache->cache_mtpt ? NULL : &cache->cache_mtpt;
  360.         cache_data_end = presto_options(data, cache_data, type, fileset,
  361.                                         prestodev, mtpt);
  362.         if (cache_data) {
  363.                 if (cache_data_end == cache_data) {
  364.                         PRESTO_FREE(cache_data, PAGE_SIZE);
  365.                         cache_data = NULL;
  366.                 } else {
  367.                         CDEBUG(D_SUPER, "cache_data at %p is: %sn", cache_data,
  368.                                cache_data);
  369.                 }
  370.         }
  371.         if (cache->cache_root_fileset && cache->cache_mtpt) {
  372.                 cache->cache_flags &= ~(CACHE_LENTO_RO|CACHE_CLIENT_RO);
  373.         }
  374.         sops = filter_c2csops(cache->cache_filter);
  375.         if (sops->remount_fs) {
  376.                 err = sops->remount_fs(sb, flags, cache_data);
  377.         }
  378.         CDEBUG(D_MALLOC, "after remount: kmem %ld, vmem %ldn",
  379.                presto_kmemory, presto_vmemory);
  380.         EXIT;
  381. out_err:
  382.         if (cache_data)
  383.                 PRESTO_FREE(cache_data, PAGE_SIZE);
  384.         return err;
  385. }
  386. struct file_system_type presto_fs_type = {
  387. #ifdef PRESTO_DEVEL
  388.         "izofs",
  389. #else 
  390.         "intermezzo",
  391. #endif
  392.         FS_REQUIRES_DEV, /* can use Ibaskets when ext2 does */
  393.         presto_read_super,
  394.         NULL
  395. };
  396. int /* __init */ init_intermezzo_fs(void)
  397. {
  398.         int status;
  399.         printk(KERN_INFO "InterMezzo Kernel/Lento communications, "
  400.                "v1.04, braam@inter-mezzo.orgn");
  401.         status = presto_psdev_init();
  402.         if ( status ) {
  403.                 printk("Problem (%d) in init_intermezzo_psdevn", status);
  404.                 return status;
  405.         }
  406.         status = init_intermezzo_sysctl();
  407.         if (status) {
  408.                 printk("presto: failed in init_intermezzo_sysctl!n");
  409.         }
  410.         presto_init_cache_hash();
  411.         status = register_filesystem(&presto_fs_type);
  412.         if (status) {
  413.                 printk("presto: failed in register_filesystem!n");
  414.         }
  415.         return status;
  416. }
  417. #ifdef MODULE
  418. MODULE_AUTHOR("Peter J. Braam <braam@inter-mezzo.org>");
  419. MODULE_DESCRIPTION("InterMezzo Kernel/Lento communications, v1.0.5.1");
  420. int init_module(void)
  421. {
  422.         return init_intermezzo_fs();
  423. }
  424. void cleanup_module(void)
  425. {
  426.         int err;
  427.         ENTRY;
  428.         if ( (err = unregister_filesystem(&presto_fs_type)) != 0 ) {
  429.                 printk("presto: failed to unregister filesystemn");
  430.         }
  431.         presto_psdev_cleanup();
  432.         cleanup_intermezzo_sysctl();
  433. #ifdef PRESTO_DEVEL
  434.         unregister_chrdev(PRESTO_PSDEV_MAJOR, "intermezzo_psdev_devel");
  435. #else 
  436.         unregister_chrdev(PRESTO_PSDEV_MAJOR, "intermezzo_psdev");
  437. #endif
  438.         CDEBUG(D_MALLOC, "after cleanup: kmem %ld, vmem %ldn",
  439.                presto_kmemory, presto_vmemory);
  440. }
  441. #endif