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

Cache object: 5d47981939fd9226062c355951a60bbd


[ 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.