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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
  2.  * vim:expandtab:shiftwidth=8:tabstop=8:
  3.  *
  4.  *  Original version: Copyright (C) 1996 P. Braam and M. Callahan
  5.  *  Rewritten for Linux 2.1. Copyright (C) 1997 Carnegie Mellon University
  6.  *  d_fsdata and NFS compatiblity fixes Copyright (C) 2001 Tacit Networks, 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.  * Directory operations for InterMezzo filesystem
  24.  */
  25. /* inode dentry alias list walking code adapted from linux/fs/dcache.c
  26.  *
  27.  * fs/dcache.c
  28.  *
  29.  * (C) 1997 Thomas Schoebel-Theuer,
  30.  * with heavy changes by Linus Torvalds
  31.  */
  32. #define __NO_VERSION__
  33. #include <linux/types.h>
  34. #include <linux/kernel.h>
  35. #include <linux/sched.h>
  36. #include <linux/fs.h>
  37. #include <linux/stat.h>
  38. #include <linux/errno.h>
  39. #include <linux/locks.h>
  40. #include <linux/slab.h>
  41. #include <asm/segment.h>
  42. #include <asm/uaccess.h>
  43. #include <linux/string.h>
  44. #include <linux/smp_lock.h>
  45. #include <linux/vmalloc.h>
  46. #include <linux/intermezzo_fs.h>
  47. kmem_cache_t * presto_dentry_slab;
  48. /* called when a cache lookup succeeds */
  49. static int presto_d_revalidate(struct dentry *de, int flag)
  50. {
  51.         struct inode *inode = de->d_inode;
  52.         struct presto_file_set * root_fset;
  53.         ENTRY;
  54.         if (!inode) {
  55.                 EXIT;
  56.                 return 0;
  57.         }
  58.         if (is_bad_inode(inode)) {
  59.                 EXIT;
  60.                 return 0;
  61.         }
  62.         if (!presto_d2d(de)) {
  63.                 presto_set_dd(de);
  64.         }
  65.         if (!presto_d2d(de)) {
  66.                 EXIT;
  67.                 return 0;
  68.         }
  69.         root_fset = presto_d2d(de->d_inode->i_sb->s_root)->dd_fset;
  70.         if (root_fset->fset_flags & FSET_FLAT_BRANCH && 
  71.             (presto_d2d(de)->dd_fset != root_fset )) {
  72.                 presto_d2d(de)->dd_fset = root_fset;
  73.         }
  74.         EXIT;
  75.         return 1;
  76. #if 0
  77.         /* The following is needed for metadata on demand. */
  78.         if ( S_ISDIR(inode->i_mode) ) {
  79.                 EXIT;
  80.                 return (presto_chk(de, PRESTO_DATA) &&
  81.                         (presto_chk(de, PRESTO_ATTR)));
  82.         } else {
  83.                 EXIT;
  84.                 return presto_chk(de, PRESTO_ATTR);
  85.         }
  86. #endif
  87. }
  88. static void presto_d_release(struct dentry *dentry)
  89. {
  90.         if (!presto_d2d(dentry)) {
  91.                 /* This can happen for dentries from NFSd */
  92.                 return;
  93.         }
  94.         presto_d2d(dentry)->dd_count--;
  95.         if (!presto_d2d(dentry)->dd_count) {
  96.                 kmem_cache_free(presto_dentry_slab, presto_d2d(dentry));
  97.                 dentry->d_fsdata = NULL;
  98.         }
  99. }
  100. struct dentry_operations presto_dentry_ops = 
  101. {
  102.         .d_revalidate =  presto_d_revalidate,
  103.         .d_release = presto_d_release
  104. };
  105. static inline int presto_is_dentry_ROOT (struct dentry *dentry)
  106. {
  107.         return(dentry_name_cmp(dentry,"ROOT") &&
  108.                !dentry_name_cmp(dentry->d_parent,".intermezzo"));
  109. }
  110. static struct presto_file_set* presto_try_find_fset(struct dentry* dentry,
  111.                 int *is_under_d_intermezzo)
  112. {
  113.         struct dentry* temp_dentry;
  114.         struct presto_dentry_data *d_data;
  115.         int found_root=0;
  116.         ENTRY;
  117.         CDEBUG(D_FSDATA, "finding fileset for %p:%sn", dentry, 
  118.                         dentry->d_name.name);
  119.         *is_under_d_intermezzo = 0;
  120.         /* walk up through the branch to get the fileset */
  121.         /* The dentry we are passed presumably does not have the correct
  122.          * fset information. However, we still want to start walking up
  123.          * the branch from this dentry to get our found_root and 
  124.          * is_under_d_intermezzo decisions correct
  125.          */
  126.         for (temp_dentry = dentry ; ; temp_dentry = temp_dentry->d_parent) {
  127.                 CDEBUG(D_FSDATA, "--->dentry %p:%*sn", temp_dentry, 
  128.                         temp_dentry->d_name.len,temp_dentry->d_name.name);
  129.                 if (presto_is_dentry_ROOT(temp_dentry))
  130.                         found_root = 1;
  131.                 if (!found_root &&
  132.                     dentry_name_cmp(temp_dentry, ".intermezzo")) {
  133.                         *is_under_d_intermezzo = 1;
  134.                 }
  135.                 d_data = presto_d2d(temp_dentry);
  136.                 if (d_data) {
  137.                         /* If we found a "ROOT" dentry while walking up the
  138.                          * branch, we will journal regardless of whether
  139.                          * we are under .intermezzo or not.
  140.                          * If we are already under d_intermezzo don't reverse
  141.                          * the decision here...even if we found a "ROOT"
  142.                          * dentry above .intermezzo (if we were ever to
  143.                          * modify the directory structure).
  144.                          */
  145.                         if (!*is_under_d_intermezzo)  
  146.                                 *is_under_d_intermezzo = !found_root &&
  147.                                   (d_data->dd_flags & PRESTO_DONT_JOURNAL);
  148.                         EXIT;
  149.                         return d_data->dd_fset;
  150.                 }
  151.                 if (temp_dentry->d_parent == temp_dentry) {
  152.                         break;
  153.                 }
  154.         }
  155.         EXIT;
  156.         return NULL;
  157. }
  158. /* Only call this function on positive dentries */
  159. static struct presto_dentry_data* presto_try_find_alias_with_dd (
  160.                   struct dentry* dentry)
  161. {
  162.         struct inode *inode=dentry->d_inode;
  163.         struct list_head *head, *next, *tmp;
  164.         struct dentry *tmp_dentry;
  165.         /* Search through the alias list for dentries with d_fsdata */
  166.         spin_lock(&dcache_lock);
  167.         head = &inode->i_dentry;
  168.         next = inode->i_dentry.next;
  169.         while (next != head) {
  170.                 tmp = next;
  171.                 next = tmp->next;
  172.                 tmp_dentry = list_entry(tmp, struct dentry, d_alias);
  173.                 if (!presto_d2d(tmp_dentry)) {
  174.                         spin_unlock(&dcache_lock);
  175.                         return presto_d2d(tmp_dentry);
  176.                 }
  177.         }
  178.         spin_unlock(&dcache_lock);
  179.         return NULL;
  180. }
  181. /* Only call this function on positive dentries */
  182. static void presto_set_alias_dd (struct dentry *dentry, 
  183.                 struct presto_dentry_data* dd)
  184. {
  185.         struct inode *inode=dentry->d_inode;
  186.         struct list_head *head, *next, *tmp;
  187.         struct dentry *tmp_dentry;
  188.         /* Set d_fsdata for this dentry */
  189.         dd->dd_count++;
  190.         dentry->d_fsdata = dd;
  191.         /* Now set d_fsdata for all dentries in the alias list. */
  192.         spin_lock(&dcache_lock);
  193.         head = &inode->i_dentry;
  194.         next = inode->i_dentry.next;
  195.         while (next != head) {
  196.                 tmp = next;
  197.                 next = tmp->next;
  198.                 tmp_dentry = list_entry(tmp, struct dentry, d_alias);
  199.                 if (!presto_d2d(tmp_dentry)) {
  200.                         dd->dd_count++;
  201.                         tmp_dentry->d_fsdata = dd;
  202.                 }
  203.         }
  204.         spin_unlock(&dcache_lock);
  205.         return;
  206. }
  207. inline struct presto_dentry_data *izo_alloc_ddata(void)
  208. {
  209.         struct presto_dentry_data *dd;
  210.         dd = kmem_cache_alloc(presto_dentry_slab, SLAB_KERNEL);
  211.         if (dd == NULL) {
  212.                 CERROR("IZO: out of memory trying to allocate presto_dentry_datan");
  213.                 return NULL;
  214.         }
  215.         memset(dd, 0, sizeof(*dd));
  216.         dd->dd_count = 1;
  217.         return dd;
  218. }
  219. /* This uses the BKL! */
  220. int presto_set_dd(struct dentry * dentry)
  221. {
  222.         struct presto_file_set *fset;
  223.         struct presto_dentry_data *dd;
  224.         int is_under_d_izo;
  225.         int error=0;
  226.         ENTRY;
  227.         if (!dentry)
  228.                 BUG();
  229.         lock_kernel();
  230.         /* Did we lose a race? */
  231.         if (dentry->d_fsdata) {
  232.                 CERROR("dentry %p already has d_fsdata setn", dentry);
  233.                 if (dentry->d_inode)
  234.                         CERROR("    inode: %ldn", dentry->d_inode->i_ino);
  235.                 EXIT;
  236.                 goto out_unlock;
  237.         }
  238.         if (dentry->d_inode != NULL) {
  239.                 /* NFSd runs find_fh_dentry which instantiates disconnected
  240.                  * dentries which are then connected without a lookup(). 
  241.                  * So it is possible to have connected dentries that do not 
  242.                  * have d_fsdata set. So we walk the list trying to find 
  243.                  * an alias which has its d_fsdata set and then use that 
  244.                  * for all the other dentries  as well. 
  245.                  * - SHP,Vinny. 
  246.                  */
  247.                 /* If there is an alias with d_fsdata use it. */
  248.                 if ((dd = presto_try_find_alias_with_dd (dentry))) {
  249.                         presto_set_alias_dd (dentry, dd);
  250.                         EXIT;
  251.                         goto out_unlock;
  252.                 }
  253.         } else {
  254.                 /* Negative dentry */
  255.                 CDEBUG(D_FSDATA,"negative dentry %p: %*sn", dentry, 
  256.                                 dentry->d_name.len, dentry->d_name.name);
  257.         }
  258.         /* No pre-existing d_fsdata, we need to construct one.
  259.          * First, we must walk up the tree to find the fileset 
  260.          * If a fileset can't be found, we leave a null fsdata
  261.          * and return EROFS to indicate that we can't journal
  262.          * updates. 
  263.          */
  264.         fset = presto_try_find_fset (dentry, &is_under_d_izo);
  265.         if (!fset) { 
  266. #ifdef PRESTO_NO_NFS
  267.                 CERROR("No fileset for dentry %p: %*sn", dentry,
  268.                                 dentry->d_name.len, dentry->d_name.name);
  269. #endif
  270.                 error = -EROFS;
  271.                 EXIT;
  272.                 goto out_unlock;
  273.         }
  274.         dentry->d_fsdata = izo_alloc_ddata();
  275.         if (!presto_d2d(dentry)) {
  276.                 CERROR ("InterMezzo: out of memory allocating d_fsdatan");
  277.                 error = -ENOMEM;
  278.                 goto out_unlock;
  279.         }
  280.         presto_d2d(dentry)->dd_fset = fset;
  281.         if (is_under_d_izo)
  282.                 presto_d2d(dentry)->dd_flags |= PRESTO_DONT_JOURNAL;
  283.         EXIT;
  284. out_unlock:    
  285.         CDEBUG(D_FSDATA,"presto_set_dd dentry %p: %*s, d_fsdata %pn", 
  286.                         dentry, dentry->d_name.len, dentry->d_name.name, 
  287.                         dentry->d_fsdata);
  288.         unlock_kernel();
  289.         return error; 
  290. }
  291. int presto_init_ddata_cache(void)
  292. {
  293.         ENTRY;
  294.         presto_dentry_slab =
  295.                 kmem_cache_create("presto_cache",
  296.                                   sizeof(struct presto_dentry_data), 0,
  297.                                   SLAB_HWCACHE_ALIGN, NULL,
  298.                                   NULL);
  299.         EXIT;
  300.         return (presto_dentry_slab != NULL);
  301. }
  302. void presto_cleanup_ddata_cache(void)
  303. {
  304.         kmem_cache_destroy(presto_dentry_slab);
  305. }