dcache.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:11k
- /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
- * vim:expandtab:shiftwidth=8:tabstop=8:
- *
- * Original version: Copyright (C) 1996 P. Braam and M. Callahan
- * Rewritten for Linux 2.1. Copyright (C) 1997 Carnegie Mellon University
- * d_fsdata and NFS compatiblity fixes Copyright (C) 2001 Tacit Networks, Inc.
- *
- * This file is part of InterMezzo, http://www.inter-mezzo.org.
- *
- * InterMezzo is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * InterMezzo is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with InterMezzo; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Directory operations for InterMezzo filesystem
- */
- /* inode dentry alias list walking code adapted from linux/fs/dcache.c
- *
- * fs/dcache.c
- *
- * (C) 1997 Thomas Schoebel-Theuer,
- * with heavy changes by Linus Torvalds
- */
- #define __NO_VERSION__
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/sched.h>
- #include <linux/fs.h>
- #include <linux/stat.h>
- #include <linux/errno.h>
- #include <linux/locks.h>
- #include <linux/slab.h>
- #include <asm/segment.h>
- #include <asm/uaccess.h>
- #include <linux/string.h>
- #include <linux/smp_lock.h>
- #include <linux/vmalloc.h>
- #include <linux/intermezzo_fs.h>
- kmem_cache_t * presto_dentry_slab;
- /* called when a cache lookup succeeds */
- static int presto_d_revalidate(struct dentry *de, int flag)
- {
- struct inode *inode = de->d_inode;
- struct presto_file_set * root_fset;
- ENTRY;
- if (!inode) {
- EXIT;
- return 0;
- }
- if (is_bad_inode(inode)) {
- EXIT;
- return 0;
- }
- if (!presto_d2d(de)) {
- presto_set_dd(de);
- }
- if (!presto_d2d(de)) {
- EXIT;
- return 0;
- }
- root_fset = presto_d2d(de->d_inode->i_sb->s_root)->dd_fset;
- if (root_fset->fset_flags & FSET_FLAT_BRANCH &&
- (presto_d2d(de)->dd_fset != root_fset )) {
- presto_d2d(de)->dd_fset = root_fset;
- }
- EXIT;
- return 1;
- #if 0
- /* The following is needed for metadata on demand. */
- if ( S_ISDIR(inode->i_mode) ) {
- EXIT;
- return (presto_chk(de, PRESTO_DATA) &&
- (presto_chk(de, PRESTO_ATTR)));
- } else {
- EXIT;
- return presto_chk(de, PRESTO_ATTR);
- }
- #endif
- }
- static void presto_d_release(struct dentry *dentry)
- {
- if (!presto_d2d(dentry)) {
- /* This can happen for dentries from NFSd */
- return;
- }
- presto_d2d(dentry)->dd_count--;
- if (!presto_d2d(dentry)->dd_count) {
- kmem_cache_free(presto_dentry_slab, presto_d2d(dentry));
- dentry->d_fsdata = NULL;
- }
- }
- struct dentry_operations presto_dentry_ops =
- {
- .d_revalidate = presto_d_revalidate,
- .d_release = presto_d_release
- };
- static inline int presto_is_dentry_ROOT (struct dentry *dentry)
- {
- return(dentry_name_cmp(dentry,"ROOT") &&
- !dentry_name_cmp(dentry->d_parent,".intermezzo"));
- }
- static struct presto_file_set* presto_try_find_fset(struct dentry* dentry,
- int *is_under_d_intermezzo)
- {
- struct dentry* temp_dentry;
- struct presto_dentry_data *d_data;
- int found_root=0;
- ENTRY;
- CDEBUG(D_FSDATA, "finding fileset for %p:%sn", dentry,
- dentry->d_name.name);
- *is_under_d_intermezzo = 0;
- /* walk up through the branch to get the fileset */
- /* The dentry we are passed presumably does not have the correct
- * fset information. However, we still want to start walking up
- * the branch from this dentry to get our found_root and
- * is_under_d_intermezzo decisions correct
- */
- for (temp_dentry = dentry ; ; temp_dentry = temp_dentry->d_parent) {
- CDEBUG(D_FSDATA, "--->dentry %p:%*sn", temp_dentry,
- temp_dentry->d_name.len,temp_dentry->d_name.name);
- if (presto_is_dentry_ROOT(temp_dentry))
- found_root = 1;
- if (!found_root &&
- dentry_name_cmp(temp_dentry, ".intermezzo")) {
- *is_under_d_intermezzo = 1;
- }
- d_data = presto_d2d(temp_dentry);
- if (d_data) {
- /* If we found a "ROOT" dentry while walking up the
- * branch, we will journal regardless of whether
- * we are under .intermezzo or not.
- * If we are already under d_intermezzo don't reverse
- * the decision here...even if we found a "ROOT"
- * dentry above .intermezzo (if we were ever to
- * modify the directory structure).
- */
- if (!*is_under_d_intermezzo)
- *is_under_d_intermezzo = !found_root &&
- (d_data->dd_flags & PRESTO_DONT_JOURNAL);
- EXIT;
- return d_data->dd_fset;
- }
- if (temp_dentry->d_parent == temp_dentry) {
- break;
- }
- }
- EXIT;
- return NULL;
- }
- /* Only call this function on positive dentries */
- static struct presto_dentry_data* presto_try_find_alias_with_dd (
- struct dentry* dentry)
- {
- struct inode *inode=dentry->d_inode;
- struct list_head *head, *next, *tmp;
- struct dentry *tmp_dentry;
- /* Search through the alias list for dentries with d_fsdata */
- spin_lock(&dcache_lock);
- head = &inode->i_dentry;
- next = inode->i_dentry.next;
- while (next != head) {
- tmp = next;
- next = tmp->next;
- tmp_dentry = list_entry(tmp, struct dentry, d_alias);
- if (!presto_d2d(tmp_dentry)) {
- spin_unlock(&dcache_lock);
- return presto_d2d(tmp_dentry);
- }
- }
- spin_unlock(&dcache_lock);
- return NULL;
- }
- /* Only call this function on positive dentries */
- static void presto_set_alias_dd (struct dentry *dentry,
- struct presto_dentry_data* dd)
- {
- struct inode *inode=dentry->d_inode;
- struct list_head *head, *next, *tmp;
- struct dentry *tmp_dentry;
- /* Set d_fsdata for this dentry */
- dd->dd_count++;
- dentry->d_fsdata = dd;
- /* Now set d_fsdata for all dentries in the alias list. */
- spin_lock(&dcache_lock);
- head = &inode->i_dentry;
- next = inode->i_dentry.next;
- while (next != head) {
- tmp = next;
- next = tmp->next;
- tmp_dentry = list_entry(tmp, struct dentry, d_alias);
- if (!presto_d2d(tmp_dentry)) {
- dd->dd_count++;
- tmp_dentry->d_fsdata = dd;
- }
- }
- spin_unlock(&dcache_lock);
- return;
- }
- inline struct presto_dentry_data *izo_alloc_ddata(void)
- {
- struct presto_dentry_data *dd;
- dd = kmem_cache_alloc(presto_dentry_slab, SLAB_KERNEL);
- if (dd == NULL) {
- CERROR("IZO: out of memory trying to allocate presto_dentry_datan");
- return NULL;
- }
- memset(dd, 0, sizeof(*dd));
- dd->dd_count = 1;
- return dd;
- }
- /* This uses the BKL! */
- int presto_set_dd(struct dentry * dentry)
- {
- struct presto_file_set *fset;
- struct presto_dentry_data *dd;
- int is_under_d_izo;
- int error=0;
- ENTRY;
- if (!dentry)
- BUG();
- lock_kernel();
- /* Did we lose a race? */
- if (dentry->d_fsdata) {
- CERROR("dentry %p already has d_fsdata setn", dentry);
- if (dentry->d_inode)
- CERROR(" inode: %ldn", dentry->d_inode->i_ino);
- EXIT;
- goto out_unlock;
- }
- if (dentry->d_inode != NULL) {
- /* NFSd runs find_fh_dentry which instantiates disconnected
- * dentries which are then connected without a lookup().
- * So it is possible to have connected dentries that do not
- * have d_fsdata set. So we walk the list trying to find
- * an alias which has its d_fsdata set and then use that
- * for all the other dentries as well.
- * - SHP,Vinny.
- */
- /* If there is an alias with d_fsdata use it. */
- if ((dd = presto_try_find_alias_with_dd (dentry))) {
- presto_set_alias_dd (dentry, dd);
- EXIT;
- goto out_unlock;
- }
- } else {
- /* Negative dentry */
- CDEBUG(D_FSDATA,"negative dentry %p: %*sn", dentry,
- dentry->d_name.len, dentry->d_name.name);
- }
- /* No pre-existing d_fsdata, we need to construct one.
- * First, we must walk up the tree to find the fileset
- * If a fileset can't be found, we leave a null fsdata
- * and return EROFS to indicate that we can't journal
- * updates.
- */
- fset = presto_try_find_fset (dentry, &is_under_d_izo);
- if (!fset) {
- #ifdef PRESTO_NO_NFS
- CERROR("No fileset for dentry %p: %*sn", dentry,
- dentry->d_name.len, dentry->d_name.name);
- #endif
- error = -EROFS;
- EXIT;
- goto out_unlock;
- }
- dentry->d_fsdata = izo_alloc_ddata();
- if (!presto_d2d(dentry)) {
- CERROR ("InterMezzo: out of memory allocating d_fsdatan");
- error = -ENOMEM;
- goto out_unlock;
- }
- presto_d2d(dentry)->dd_fset = fset;
- if (is_under_d_izo)
- presto_d2d(dentry)->dd_flags |= PRESTO_DONT_JOURNAL;
- EXIT;
- out_unlock:
- CDEBUG(D_FSDATA,"presto_set_dd dentry %p: %*s, d_fsdata %pn",
- dentry, dentry->d_name.len, dentry->d_name.name,
- dentry->d_fsdata);
- unlock_kernel();
- return error;
- }
- int presto_init_ddata_cache(void)
- {
- ENTRY;
- presto_dentry_slab =
- kmem_cache_create("presto_cache",
- sizeof(struct presto_dentry_data), 0,
- SLAB_HWCACHE_ALIGN, NULL,
- NULL);
- EXIT;
- return (presto_dentry_slab != NULL);
- }
- void presto_cleanup_ddata_cache(void)
- {
- kmem_cache_destroy(presto_dentry_slab);
- }