patch-2.4.20 linux-2.4.20/fs/intermezzo/dcache.c
Next file: linux-2.4.20/fs/intermezzo/dir.c
Previous file: linux-2.4.20/fs/intermezzo/cache.c
Back to the patch index
Back to the overall index
- Lines: 375
- Date:
Thu Nov 28 15:53:15 2002
- Orig file:
linux-2.4.19/fs/intermezzo/dcache.c
- Orig date:
Mon Feb 25 11:38:08 2002
diff -urN linux-2.4.19/fs/intermezzo/dcache.c linux-2.4.20/fs/intermezzo/dcache.c
@@ -1,10 +1,34 @@
-/*
+/* -*- 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
- * Original version: (C) 1996 P. Braam and M. Callahan
- * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University
+ */
+
+/* inode dentry alias list walking code adapted from linux/fs/dcache.c
*
- * Stelias encourages users to contribute improvements to
- * the InterMezzo project. Contact Peter Braam (coda@stelias.com).
+ * fs/dcache.c
+ *
+ * (C) 1997 Thomas Schoebel-Theuer,
+ * with heavy changes by Linus Torvalds
*/
#define __NO_VERSION__
@@ -15,48 +39,307 @@
#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>
-static int presto_dentry_revalidate(struct dentry *de, int );
-
+kmem_cache_t * presto_dentry_slab;
/* called when a cache lookup succeeds */
-static int presto_dentry_revalidate(struct dentry *de, int flag)
+static int presto_d_revalidate(struct dentry *de, int flag)
{
- struct inode *inode = de->d_inode;
- ENTRY;
- if (!inode) {
- EXIT;
- return 1;
- }
- if (is_bad_inode(inode)) {
- EXIT;
- return 0;
- }
-
- 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);
- }
+ 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_dentry_iput(struct dentry *dentry, struct inode *inode)
+static void presto_d_release(struct dentry *dentry)
{
- dentry->d_time = 0;
- iput(inode);
+ 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_dentry_revalidate,
- d_iput: presto_dentry_iput
+ .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:%s\n", 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:%*s\n", 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_data\n");
+ 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 set\n", dentry);
+ if (dentry->d_inode)
+ CERROR(" inode: %ld\n", 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: %*s\n", 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: %*s\n", 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_fsdata\n");
+ 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 %p\n",
+ 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);
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)