Whamcloud - gitweb
Fix locking with filter. This changes the way objects are looked up in
authoradilger <adilger>
Thu, 23 May 2002 21:14:19 +0000 (21:14 +0000)
committeradilger <adilger>
Thu, 23 May 2002 21:14:19 +0000 (21:14 +0000)
the filter to always use lookup_one_len() from the parent (which is gotten
at filter_setup time) instead of doing a file open each time.

There appears to be some sort of leak which prevents the loop device from
being cleaned up, but e.g. bonnie runs just fine and all of the modules
can be unloaded.  Will look at it again later once I've gotten some more
urgent things out of the way.

lustre/include/linux/lustre_lib.h
lustre/include/linux/lustre_mds.h
lustre/include/linux/obd.h
lustre/lib/simple.c
lustre/mds/handler.c
lustre/obdfilter/filter.c

index da941fa..29232ba 100644 (file)
@@ -42,27 +42,18 @@ int lustre_commit_page(struct page *page, unsigned from, unsigned to);
 struct obd_run_ctxt;
 void push_ctxt(struct obd_run_ctxt *save, struct obd_run_ctxt *new);
 void pop_ctxt(struct obd_run_ctxt *saved);
-int simple_mkdir(struct dentry *dir, char *name, int mode);
+struct dentry *simple_mkdir(struct dentry *dir, char *name, int mode);
 int lustre_fread(struct file *file, char *str, int len, loff_t *off);
 int lustre_fwrite(struct file *file, const char *str, int len, loff_t *off);
 int lustre_fsync(struct file *file);
 
-#define ASSERT_MAX_SIZE_MB 50000ULL
-#define ASSERT_PAGE_INDEX(index, OP)                                    \
-do { if (index > ASSERT_MAX_SIZE_MB << (20 - PAGE_SHIFT)) {             \
-        CERROR("bad page index %lu > %Lu\n", index,                     \
-               ASSERT_MAX_SIZE_MB << (20 - PAGE_SHIFT));                \
-        portal_debug = ~0UL;                                            \
-        OP;                                                             \
-}} while(0)
-
-#define ASSERT_FILE_OFFSET(offset, OP)                                  \
-do { if (offset > ASSERT_MAX_SIZE_MB << 20) {                           \
-        CERROR("bad file offset %Lu > %Lu\n", offset,                   \
-               ASSERT_MAX_SIZE_MB << 20);                               \
-        portal_debug = ~0UL;                                            \
-        OP;                                                             \
-}} while(0)
+static inline void l_dput(struct dentry *de)
+{
+        if (!de || IS_ERR(de))
+                return;
+        shrink_dcache_parent(de);
+        dput(de);
+}
 
 static inline void ll_sleep(int t)
 {
index c1b3b55..e7f942b 100644 (file)
 #include <linux/lustre_idl.h>
 #include <linux/lustre_net.h>
 
-static inline void l_dput(struct dentry *de) 
-{
-        if (!de || IS_ERR(de)) 
-                return; 
-        shrink_dcache_parent(de); 
-        dput(de); 
-}
-
 #define LUSTRE_MDS_NAME "mds"
 
 struct mds_update_record { 
index 8640d95..4ce3791 100644 (file)
@@ -57,6 +57,8 @@ struct filter_obd {
         struct super_block *fo_sb;
         struct vfsmount *fo_vfsmnt;
         struct obd_run_ctxt fo_ctxt;
+        struct dentry *fo_dentry_O;
+        struct dentry *fo_dentry_O_mode[16];
         spinlock_t fo_lock;
         __u64 fo_lastino;
         struct file_operations *fo_fop;
index baeff93..dee3013 100644 (file)
@@ -1,4 +1,6 @@
-/*
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
  *  lib/simple.c
  *
  * Copyright (C) 2002  Cluster File Systems, Inc.
@@ -25,7 +27,7 @@
 
 /* push / pop to root of obd store */
 void push_ctxt(struct obd_run_ctxt *save, struct obd_run_ctxt *new)
-{ 
+{
         save->fs = get_fs();
         save->pwd = dget(current->fs->pwd);
         save->pwdmnt = mntget(current->fs->pwdmnt);
@@ -44,28 +46,33 @@ void pop_ctxt(struct obd_run_ctxt *saved)
 }
 
 /* utility to make a directory */
-int simple_mkdir(struct dentry *dir, char *name, int mode)
+struct dentry *simple_mkdir(struct dentry *dir, char *name, int mode)
 {
         struct dentry *dchild;
         int err;
         ENTRY;
 
+       CDEBUG(D_INODE, "creating directory %*s\n", strlen(name), name);
         dchild = lookup_one_len(name, dir, strlen(name));
         if (IS_ERR(dchild))
-                RETURN(PTR_ERR(dchild));
+                RETURN(dchild);
 
         if (dchild->d_inode) {
                if (!S_ISDIR(dchild->d_inode->i_mode))
                        GOTO(out, err = -ENOTDIR);
 
-                GOTO(out, err = -EEXIST);
+                RETURN(dchild);
        }
 
         err = vfs_mkdir(dir->d_inode, dchild, mode);
+        EXIT;
 out:
-        l_dput(dchild);
+        if (err) {
+                dput(dchild);
+                RETURN(ERR_PTR(err));
+        }
 
-        RETURN(err);
+        RETURN(dchild);
 }
 
 int lustre_fread(struct file *file, char *str, int len, loff_t *off)
index 0ce5167..95c897c 100644 (file)
@@ -85,11 +85,11 @@ struct dentry *mds_fid2dentry(struct mds_obd *mds, struct ll_fid *fid,
         struct dentry *result;
 
         if (ino == 0)
-                return ERR_PTR(-ESTALE);
+                RETURN(ERR_PTR(-ESTALE));
 
         inode = iget(sb, ino);
         if (inode == NULL)
-                return ERR_PTR(-ENOMEM);
+                RETURN(ERR_PTR(-ENOMEM));
 
         CDEBUG(D_DENTRY, "--> mds_fid2dentry: sb %p\n", inode->i_sb);
 
@@ -102,7 +102,7 @@ struct dentry *mds_fid2dentry(struct mds_obd *mds, struct ll_fid *fid,
                        generation);
                 LBUG();
                 iput(inode);
-                return ERR_PTR(-ESTALE);
+                RETURN(ERR_PTR(-ESTALE));
         }
 
         /* now to find a dentry.
@@ -727,15 +727,19 @@ static int mds_prep(struct obd_device *obddev)
         struct obd_run_ctxt saved;
         struct mds_obd *mds = &obddev->u.mds;
         struct super_operations *s_ops;
+        struct dentry *dentry;
         struct file *f;
         int rc;
 
         push_ctxt(&saved, &mds->mds_ctxt);
-        rc = simple_mkdir(current->fs->pwd, "ROOT", 0700);
-        if (rc && rc != -EEXIST) {
+        dentry = simple_mkdir(current->fs->pwd, "ROOT", 0700);
+        if (IS_ERR(dentry)) {
+                rc = PTR_ERR(dentry);
                 CERROR("cannot create ROOT directory: rc = %d\n", rc);
                 GOTO(err_pop, rc);
         }
+        /* XXX probably want to hold on to this later... */
+        dput(dentry);
         f = filp_open("ROOT", O_RDONLY, 0);
         if (IS_ERR(f)) {
                 rc = PTR_ERR(f);
@@ -754,11 +758,14 @@ static int mds_prep(struct obd_device *obddev)
                 LBUG();
         }
 
-        rc = simple_mkdir(current->fs->pwd, "FH", 0700);
-        if (rc && rc != -EEXIST) {
+        dentry = simple_mkdir(current->fs->pwd, "FH", 0700);
+        if (IS_ERR(dentry)) {
+                rc = PTR_ERR(dentry);
                 CERROR("cannot create FH directory: rc = %d\n", rc);
                 GOTO(err_pop, rc);
         }
+        /* XXX probably want to hold on to this later... */
+        dput(dentry);
 
         rc = mds_init_client_data(mds);
         if (rc)
index 74b81f4..bb7a56b 100644 (file)
@@ -1,7 +1,7 @@
 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
  * vim:expandtab:shiftwidth=8:tabstop=8:
  *
- *  linux/fs/ext2_obd/ext2_obd.c
+ *  linux/fs/filter/filter.c
  *
  * Copyright (C) 2001  Cluster File Systems, Inc.
  *
@@ -15,7 +15,6 @@
 #define DEBUG_SUBSYSTEM S_FILTER
 
 #include <linux/module.h>
-#include <linux/obd_ext2.h>
 #include <linux/obd_filter.h>
 
 extern struct obd_device obd_dev[MAX_OBD_DEVICES];
@@ -24,8 +23,8 @@ long filter_memory;
 #define FILTER_ROOTINO 2
 
 #define S_SHIFT 12
-static char * obd_type_by_mode[S_IFMT >> S_SHIFT] = {
-        [0]                     "",
+static char *obd_type_by_mode[S_IFMT >> S_SHIFT] = {
+        [0]                     NULL,
         [S_IFREG >> S_SHIFT]    "R",
         [S_IFDIR >> S_SHIFT]    "D",
         [S_IFCHR >> S_SHIFT]    "C",
@@ -35,82 +34,124 @@ static char * obd_type_by_mode[S_IFMT >> S_SHIFT] = {
         [S_IFLNK >> S_SHIFT]    "L"
 };
 
+static inline const char *obd_mode_to_type(int mode)
+{
+        return obd_type_by_mode[(mode & S_IFMT) >> S_SHIFT];
+}
 
 /* write the pathname into the string */
-static void filter_id(char *buf, obd_id id, obd_mode mode)
+static int filter_id(char *buf, obd_id id, obd_mode mode)
 {
-        sprintf(buf, "O/%s/%Ld", obd_type_by_mode[(mode & S_IFMT) >> S_SHIFT],
-                (unsigned long long)id);
+        return sprintf(buf, "O/%s/%Ld", obd_mode_to_type(mode),
+                       (unsigned long long)id);
 }
 
 /* setup the object store with correct subdirectories */
 static int filter_prep(struct obd_device *obddev)
 {
         struct obd_run_ctxt saved;
+        struct filter_obd *filter = &obddev->u.filter;
+        struct dentry *dentry;
         struct file *file;
         struct inode *inode;
         loff_t off;
         int rc = 0;
         char rootid[128];
         __u64 lastino = 2;
-
-        push_ctxt(&saved, &obddev->u.filter.fo_ctxt);
-        rc = simple_mkdir(current->fs->pwd, "O", 0700);
-        rc = simple_mkdir(current->fs->pwd, "P", 0700);
-        rc = simple_mkdir(current->fs->pwd, "D", 0700);
-        file = filp_open("O", O_RDONLY, 0);
-        if (IS_ERR(file)) {
-                CERROR("cannot open O\n");
-                GOTO(out, rc = PTR_ERR(file));
-        }
-        rc = simple_mkdir(file->f_dentry, "R", 0700);  /* regular */
-        rc = simple_mkdir(file->f_dentry, "D", 0700);  /* directory */
-        rc = simple_mkdir(file->f_dentry, "L", 0700);  /* symbolic links */
-        rc = simple_mkdir(file->f_dentry, "C", 0700);  /* character devices */
-        rc = simple_mkdir(file->f_dentry, "B", 0700);  /* block devices */
-        rc = simple_mkdir(file->f_dentry, "F", 0700);  /* fifo's */
-        rc = simple_mkdir(file->f_dentry, "S", 0700);  /* sockets */
-        filp_close(file, NULL);
+        int mode = 0;
+
+        push_ctxt(&saved, &filter->fo_ctxt);
+        dentry = simple_mkdir(current->fs->pwd, "O", 0700);
+        CDEBUG(D_INODE, "got/created O: %p\n", dentry);
+        if (IS_ERR(dentry)) {
+                rc = PTR_ERR(dentry);
+                CERROR("cannot open/create O: rc = %d\n", rc);
+                GOTO(out, rc);
+        }
+        filter->fo_dentry_O = dentry;
+        dentry = simple_mkdir(current->fs->pwd, "P", 0700);
+        CDEBUG(D_INODE, "got/created P: %p\n", dentry);
+        if (IS_ERR(dentry)) {
+                rc = PTR_ERR(dentry);
+                CERROR("cannot open/create P: rc = %d\n", rc);
+                GOTO(out_O, rc);
+        }
+        CDEBUG(D_INODE, "putting P: %p, count = %d\n", dentry,dentry->d_count.counter-1);
+        l_dput(dentry);
+        dentry = simple_mkdir(current->fs->pwd, "D", 0700);
+        CDEBUG(D_INODE, "got/created D: %p\n", dentry);
+        if (IS_ERR(dentry)) {
+                rc = PTR_ERR(dentry);
+                CERROR("cannot open/create D: rc = %d\n", rc);
+                GOTO(out_O, rc);
+        }
+        CDEBUG(D_INODE, "putting D: %p, count = %d\n", dentry,dentry->d_count.counter-1);
+        l_dput(dentry);
+
+        /*
+         * Create directories and/or get dentries for each object type.
+         * This saves us from having to do multiple lookups for each one.
+         */
+        for (mode = 0; mode < (S_IFMT >> S_SHIFT); mode++) {
+                char *type = obd_type_by_mode[mode];
+
+                if (!type) {
+                        filter->fo_dentry_O_mode[mode] = NULL;
+                        continue;
+                }
+                dentry = simple_mkdir(filter->fo_dentry_O, type, 0700);
+                CDEBUG(D_INODE, "got/created O/%s: %p\n", type, dentry);
+                if (IS_ERR(dentry)) {
+                        rc = PTR_ERR(dentry);
+                        CERROR("cannot create O/%s: rc = %d\n", type, rc);
+                        GOTO(out_O_mode, rc);
+                }
+                filter->fo_dentry_O_mode[mode] = dentry;
+        }
 
         filter_id(rootid, FILTER_ROOTINO, S_IFDIR);
-        file = filp_open(rootid, O_RDWR | O_CREAT, 00755);
+        file = filp_open(rootid, O_RDWR | O_CREAT, 0755);
         if (IS_ERR(file)) {
-                CERROR("OBD filter: cannot make root directory");
-                GOTO(out, rc = PTR_ERR(file));
+                rc = PTR_ERR(file);
+                CERROR("OBD filter: cannot open/create root %s: rc = %d\n",
+                       rootid, rc);
+                GOTO(out_O_mode, rc);
         }
         filp_close(file, 0);
-        /* FIXME: this is the same as the _file_ we just created? */
-        rc = simple_mkdir(current->fs->pwd, rootid, 0755);
 
         file = filp_open("D/status", O_RDWR | O_CREAT, 0700);
         if ( !file || IS_ERR(file) ) {
-                CERROR("OBD filter: cannot open/create status file\n");
-                GOTO(out, rc = PTR_ERR(file));
+                rc = PTR_ERR(file);
+                CERROR("OBD filter: cannot open/create status %s: rc = %d\n",
+                       "D/status", rc);
+                GOTO(out_O_mode, rc);
         }
 
         /* steal operations */
         inode = file->f_dentry->d_inode;
-        obddev->u.filter.fo_fop = file->f_op;
-        obddev->u.filter.fo_iop = inode->i_op;
-        obddev->u.filter.fo_aops = inode->i_mapping->a_ops;
+        filter->fo_fop = file->f_op;
+        filter->fo_iop = inode->i_op;
+        filter->fo_aops = inode->i_mapping->a_ops;
 
         off = 0;
         if (inode->i_size == 0) {
                 ssize_t retval = file->f_op->write(file, (char *)&lastino,
                                                    sizeof(lastino), &off);
                 if (retval != sizeof(lastino)) {
-                        CERROR("OBD filter: error writing lastino\n");
-                        GOTO(out, rc = -EIO);
+                        CDEBUG(D_INODE, "OBD filter: error writing lastino\n");
+                        filp_close(file, 0);
+                        GOTO(out_O_mode, rc = -EIO);
                 }
         } else {
                 ssize_t retval = file->f_op->read(file, (char *)&lastino,
                                                   sizeof(lastino), &off);
                 if (retval != sizeof(lastino)) {
-                        CERROR("OBD filter: error reading lastino\n");
-                        GOTO(out, rc = -EIO);
+                        CDEBUG(D_INODE, "OBD filter: error reading lastino\n");
+                        filp_close(file, 0);
+                        GOTO(out_O_mode, rc = -EIO);
                 }
         }
-        obddev->u.filter.fo_lastino = lastino;
+        filter->fo_lastino = lastino;
         filp_close(file, 0);
 
         rc = 0;
@@ -118,33 +159,65 @@ static int filter_prep(struct obd_device *obddev)
         pop_ctxt(&saved);
 
         return(rc);
+
+out_O_mode:
+        while (--mode >= 0) {
+                if (filter->fo_dentry_O_mode[mode]) {
+                        CDEBUG(D_INODE, "putting O/%s: %p, count = %d\n",
+                               obd_type_by_mode[mode],
+                               filter->fo_dentry_O_mode[mode],
+                               filter->fo_dentry_O_mode[mode]->d_count.counter-1);
+                        l_dput(filter->fo_dentry_O_mode[mode]);
+                        filter->fo_dentry_O_mode[mode] = NULL;
+                }
+        }
+out_O:
+        CDEBUG(D_INODE, "putting O: %p, count = %d\n", filter->fo_dentry_O,
+               filter->fo_dentry_O->d_count.counter);
+        l_dput(filter->fo_dentry_O);
+        filter->fo_dentry_O = NULL;
+        goto out;
 }
 
 /* cleanup the filter: write last used object id to status file */
 static void filter_post(struct obd_device *obddev)
 {
         struct obd_run_ctxt saved;
+        struct filter_obd *filter = &obddev->u.filter;
         long rc;
         struct file *file;
         loff_t off = 0;
+        int mode;
 
-        push_ctxt(&saved, &obddev->u.filter.fo_ctxt);
+        push_ctxt(&saved, &filter->fo_ctxt);
         file = filp_open("D/status", O_RDWR | O_CREAT, 0700);
-        if ( !file || IS_ERR(file)) {
+        if (IS_ERR(file)) {
                 CERROR("OBD filter: cannot create status file\n");
                 goto out;
         }
-        rc = file->f_op->write(file, (char *)&obddev->u.filter.fo_lastino,
-                       sizeof(obddev->u.filter.fo_lastino), &off);
-        if (rc != sizeof(obddev->u.filter.fo_lastino) ) {
-                CERROR("OBD filter: error writing lastino\n");
-        }
+        rc = file->f_op->write(file, (char *)&filter->fo_lastino,
+                       sizeof(filter->fo_lastino), &off);
+        if (rc != sizeof(filter->fo_lastino))
+                CERROR("OBD filter: error writing lastino: rc = %ld\n", rc);
 
         rc = filp_close(file, NULL);
-        if (rc) {
-                CERROR("OBD filter: cannot close status file\n");
+        if (rc)
+                CERROR("OBD filter: cannot close status file: rc = %ld\n", rc);
+
+        for (mode = 0; mode < (S_IFMT >> S_SHIFT); mode++) {
+                if (filter->fo_dentry_O_mode[mode]) {
+                        CDEBUG(D_INODE, "putting O/%s: %p, count = %d\n",
+                               obd_type_by_mode[mode],
+                               filter->fo_dentry_O_mode[mode],
+                               filter->fo_dentry_O_mode[mode]->d_count.counter-1);
+                        l_dput(filter->fo_dentry_O_mode[mode]);
+                        filter->fo_dentry_O_mode[mode] = NULL;
+                }
         }
- out:
+        CDEBUG(D_INODE, "putting O: %p, count = %d\n", filter->fo_dentry_O,
+               filter->fo_dentry_O->d_count.counter);
+        l_dput(filter->fo_dentry_O);
+out:
         pop_ctxt(&saved);
 }
 
@@ -160,69 +233,114 @@ static __u64 filter_next_id(struct obd_device *obddev)
 }
 
 /* how to get files, dentries, inodes from object id's */
+/* parent i_sem is already held if needed for exclusivity */
+static struct dentry *filter_fid2dentry(struct obd_device *obddev,
+                                        struct dentry *dparent,
+                                        __u64 id, __u32 type)
+{
+        struct super_block *sb = obddev->u.filter.fo_sb;
+        struct dentry *dchild;
+        char name[32];
+        int len;
+        ENTRY;
+
+        if (!sb || !sb->s_dev) {
+                CERROR("fatal: device not initialized.\n");
+                RETURN(ERR_PTR(-ENXIO));
+        }
+
+        if (id == 0) {
+                CERROR("fatal: invalid object #0\n");
+                RETURN(ERR_PTR(-ESTALE));
+        }
+
+        if (!(type & S_IFMT)) {
+                CERROR("OBD %s, object %Lu has bad type: %o\n", __FUNCTION__,
+                       (unsigned long long)id, type);
+                RETURN(ERR_PTR(-EINVAL));
+        }
+
+        len = sprintf(name, "%Ld", id);
+        CDEBUG(D_INODE, "opening object O/%s/%s\n", obd_mode_to_type(type),
+               name);
+        dchild = lookup_one_len(name, dparent, len);
+        CDEBUG(D_INODE, "got child obj O/%s/%s: %p, count = %d\n",
+               obd_mode_to_type(type), name, dchild, dchild->d_count.counter);
+
+        if (IS_ERR(dchild)) {
+                CERROR("child lookup error %ld\n", PTR_ERR(dchild));
+                RETURN(dchild);
+        }
+
+        RETURN(dchild);
+}
+
 static struct file *filter_obj_open(struct obd_device *obddev,
-                                   __u64 id, __u32 type)
+                                    __u64 id, __u32 type)
 {
+        struct super_block *sb = obddev->u.filter.fo_sb;
         struct obd_run_ctxt saved;
         char name[24];
-        struct super_block *sb;
         struct file *file;
         ENTRY;
 
-        sb = obddev->u.filter.fo_sb;
         if (!sb || !sb->s_dev) {
-                CDEBUG(D_SUPER, "fatal: device not initialized.\n");
-                RETURN(NULL);
+                CERROR("fatal: device not initialized.\n");
+                RETURN(ERR_PTR(-ENXIO));
         }
 
-        if ( !id ) {
-                CDEBUG(D_INODE, "fatal: invalid obdo %Lu\n",
-                       (unsigned long long)id);
-                RETURN(NULL);
+        if (!id) {
+                CERROR("fatal: invalid obdo %Lu\n", (unsigned long long)id);
+                RETURN(ERR_PTR(-ESTALE));
         }
 
-        if ( ! (type & S_IFMT) ) {
-                CERROR("OBD filter_obj_open, no type (%Ld), mode %o!\n",
+        if (!(type & S_IFMT)) {
+                CERROR("OBD %s, no type (%Ld), mode %o!\n", __FUNCTION__,
                        (unsigned long long)id, type);
+                RETURN(ERR_PTR(-EINVAL));
         }
 
         filter_id(name, id, type);
         push_ctxt(&saved, &obddev->u.filter.fo_ctxt);
-        file = filp_open(name, O_RDONLY | O_LARGEFILE, 0);
+        file = filp_open(name, O_RDONLY | O_LARGEFILE, 0 /* type? */);
         pop_ctxt(&saved);
 
-        CDEBUG(D_INODE, "opening obdo %s\n", name);
+        CDEBUG(D_INODE, "opening obdo %s: rc = %p\n", name, file);
 
+        if (IS_ERR(file))
+                file = NULL;
         RETURN(file);
 }
 
-static struct file *filter_parent(obd_id id, obd_mode mode)
+static struct dentry *filter_parent(struct obd_device *obddev, obd_mode mode)
 {
-        char path[64];
-        struct file *file;
-
-        sprintf(path, "O/%s", obd_type_by_mode[(mode & S_IFMT) >> S_SHIFT]);
+        struct filter_obd *filter = &obddev->u.filter;
 
-        file = filp_open(path, O_RDONLY, 0);
-        return file;
+        return filter->fo_dentry_O_mode[(mode & S_IFMT) >> S_SHIFT];
 }
 
 
 static struct inode *filter_inode_from_obj(struct obd_device *obddev,
-                                     __u64 id, __u32 type)
+                                           __u64 id, __u32 type)
 {
-        struct file *file;
+        struct dentry *dentry;
         struct inode *inode;
 
-        file = filter_obj_open(obddev, id, type);
-        if ( !file ) {
-                CERROR("filter_inode_from_obdo failed\n");
-                return NULL;
+        dentry = filter_fid2dentry(obddev, filter_parent(obddev, type),
+                                   id, type);
+        if (IS_ERR(dentry)) {
+                CERROR("%s: lookup failed: rc = %ld\n", __FUNCTION__,
+                       PTR_ERR(dentry));
+                RETURN(NULL);
         }
 
-        inode = iget(file->f_dentry->d_inode->i_sb,
-                     file->f_dentry->d_inode->i_ino);
-        filp_close(file, 0);
+        lock_kernel();
+        inode = iget(dentry->d_inode->i_sb, dentry->d_inode->i_ino);
+        unlock_kernel();
+        CDEBUG(D_INODE, "put child %p, count = %d\n", dentry, dentry->d_count.counter-1);
+        l_dput(dentry);
+        CDEBUG(D_INODE, "got inode %p (%ld), count = %d\n", inode, inode->i_ino,
+               inode->i_count.counter);
         return inode;
 }
 
@@ -256,6 +374,7 @@ static int filter_disconnect(struct obd_conn *conn)
 static int filter_setup(struct obd_device *obddev, obd_count len, void *buf)
 {
         struct obd_ioctl_data* data = buf;
+        struct filter_obd *filter;
         struct vfsmount *mnt;
         int err = 0;
         ENTRY;
@@ -269,31 +388,32 @@ static int filter_setup(struct obd_device *obddev, obd_count len, void *buf)
         if (IS_ERR(mnt))
                 GOTO(err_dec, err);
 
+        filter = &obddev->u.filter;;
+        filter->fo_sb = mnt->mnt_root->d_inode->i_sb;
         /* XXX is this even possible if do_kern_mount succeeded? */
-        obddev->u.filter.fo_sb = mnt->mnt_root->d_inode->i_sb;
-        if (!obddev->u.filter.fo_sb)
+        if (!filter->fo_sb)
                 GOTO(err_put, err = -ENODEV);
 
-        obddev->u.filter.fo_vfsmnt = mnt;
-        obddev->u.filter.fo_fstype = strdup(data->ioc_inlbuf2);
+        filter->fo_vfsmnt = mnt;
+        filter->fo_fstype = strdup(data->ioc_inlbuf2);
 
-        obddev->u.filter.fo_ctxt.pwdmnt = mnt;
-        obddev->u.filter.fo_ctxt.pwd = mnt->mnt_root;
-        obddev->u.filter.fo_ctxt.fs = KERNEL_DS;
+        filter->fo_ctxt.pwdmnt = mnt;
+        filter->fo_ctxt.pwd = mnt->mnt_root;
+        filter->fo_ctxt.fs = KERNEL_DS;
 
         err = filter_prep(obddev);
         if (err)
                 GOTO(err_kfree, err);
-        spin_lock_init(&obddev->u.filter.fo_lock);
+        spin_lock_init(&filter->fo_lock);
 
         RETURN(0);
 
 err_kfree:
-        kfree(obddev->u.filter.fo_fstype);
+        kfree(filter->fo_fstype);
 err_put:
         unlock_kernel();
-        mntput(obddev->u.filter.fo_vfsmnt);
-        obddev->u.filter.fo_sb = 0;
+        mntput(filter->fo_vfsmnt);
+        filter->fo_sb = 0;
         lock_kernel();
 
 err_dec:
@@ -305,10 +425,12 @@ err_dec:
 static int filter_cleanup(struct obd_device * obddev)
 {
         struct super_block *sb;
-
         ENTRY;
 
-        if ( !list_empty(&obddev->obd_gen_clients) ) {
+        if (!(obddev->obd_flags & OBD_SET_UP))
+                RETURN(0);
+
+        if (!list_empty(&obddev->obd_gen_clients)) {
                 CERROR("still has clients!\n");
                 RETURN(-EBUSY);
         }
@@ -319,7 +441,10 @@ static int filter_cleanup(struct obd_device * obddev)
 
         filter_post(obddev);
 
+        shrink_dcache_parent(sb->s_root);
         unlock_kernel();
+        CDEBUG(D_INODE, "putting sb->s_root: count = %d\n",
+               sb->s_root->d_count.counter-1);
         mntput(obddev->u.filter.fo_vfsmnt);
         obddev->u.filter.fo_sb = 0;
         kfree(obddev->u.filter.fo_fstype);
@@ -377,24 +502,27 @@ static int filter_getattr(struct obd_conn *conn, struct obdo *oa)
         struct inode *inode;
         ENTRY;
 
-        if ( !gen_client(conn) ) {
+        if (!gen_client(conn)) {
                 CDEBUG(D_IOCTL, "fatal: invalid client %u\n", conn->oc_id);
                 RETURN(-EINVAL);
         }
 
         inode = filter_inode_from_obj(conn->oc_dev, oa->o_id, oa->o_mode);
-        if (inode == NULL)
+        if (!inode)
                 RETURN(-ENOENT);
 
         oa->o_valid &= ~OBD_MD_FLID;
         filter_from_inode(oa, inode);
 
+        CDEBUG(D_INODE, "put inode %p (%ld), count = %d, nlink = %d\n", inode,
+               inode->i_ino, inode->i_count.counter - 1, inode->i_nlink);
         iput(inode);
         RETURN(0);
 }
 
 static int filter_setattr(struct obd_conn *conn, struct obdo *oa)
 {
+        struct obd_run_ctxt saved;
         struct inode *inode;
         struct iattr iattr;
         int rc;
@@ -407,18 +535,28 @@ static int filter_setattr(struct obd_conn *conn, struct obdo *oa)
         }
 
         inode = filter_inode_from_obj(conn->oc_dev, oa->o_id, oa->o_mode);
-        if ( !inode )
+        if (!inode)
                 RETURN(-ENOENT);
 
         iattr_from_obdo(&iattr, oa);
         iattr.ia_mode &= ~S_IFMT;
         iattr.ia_mode |= S_IFREG;
         de.d_inode = inode;
-        if ( inode->i_op->setattr )
+        lock_kernel();
+        if (iattr.ia_mode & ATTR_SIZE)
+                down(&inode->i_sem);
+        push_ctxt(&saved, &conn->oc_dev->u.filter.fo_ctxt);
+        if (inode->i_op->setattr)
                 rc = inode->i_op->setattr(&de, &iattr);
         else
                 rc = inode_setattr(inode, &iattr);
+        pop_ctxt(&saved);
+        if (iattr.ia_mode & ATTR_SIZE)
+                up(&inode->i_sem);
+        unlock_kernel();
 
+        CDEBUG(D_INODE, "put inode %p (%ld), count = %d, nlink = %d\n", inode,
+               inode->i_ino, inode->i_count.counter - 1, inode->i_nlink);
         iput(inode);
         RETURN(rc);
 }
@@ -428,11 +566,13 @@ static int filter_open(struct obd_conn *conn, struct obdo *oa)
         struct inode *inode;
         /* ENTRY; */
 
-        if (!gen_client(conn))
+        if (!gen_client(conn)) {
+                CDEBUG(D_IOCTL, "fatal: invalid client %u\n", conn->oc_id);
                 RETURN(-EINVAL);
+        }
 
-        if ( !(inode = filter_inode_from_obj(conn->oc_dev,
-                                             oa->o_id, oa->o_mode)) )
+        inode = filter_inode_from_obj(conn->oc_dev, oa->o_id, oa->o_mode);
+        if (!inode)
                 RETURN(-ENOENT);
 
         return 0;
@@ -443,19 +583,27 @@ static int filter_close(struct obd_conn *conn, struct obdo *oa)
         struct inode *inode;
         /* ENTRY; */
 
-        if (!gen_client(conn))
+        if (!gen_client(conn)) {
+                CDEBUG(D_IOCTL, "fatal: invalid client %u\n", conn->oc_id);
                 RETURN(-EINVAL);
+        }
 
-        if ( !(inode = filter_inode_from_obj(conn->oc_dev,
-                                             oa->o_id, oa->o_mode)) )
+        inode = filter_inode_from_obj(conn->oc_dev, oa->o_id, oa->o_mode);
+        if (!inode)
                 RETURN(-ENOENT);
 
+        CDEBUG(D_INODE, "put inode %p (%ld), count = %d, nlink = %d\n", inode,
+               inode->i_ino, inode->i_count.counter - 1, inode->i_nlink);
         iput(inode);  /* for the close */
+        CDEBUG(D_INODE, "objid #%ld has %d links, %d count after close\n",
+               inode->i_ino, inode->i_nlink, inode->i_count.counter - 1);
+        CDEBUG(D_INODE, "put inode %p (%ld), count = %d, nlink = %d\n", inode,
+               inode->i_ino, inode->i_count.counter - 1, inode->i_nlink);
         iput(inode);  /* for this call */
         return 0;
 } /* filter_close */
 
-static int filter_create (struct obd_conn* conn, struct obdo *oa)
+static int filter_create(struct obd_conn* conn, struct obdo *oa)
 {
         char name[64];
         struct obd_run_ctxt saved;
@@ -471,16 +619,14 @@ static int filter_create (struct obd_conn* conn, struct obdo *oa)
         }
 
         oa->o_id = filter_next_id(conn->oc_dev);
-        if ( !(oa->o_mode && S_IFMT) ) {
+        if (!(oa->o_mode && S_IFMT)) {
                 CERROR("filter obd: no type!\n");
                 return -ENOENT;
         }
 
         filter_id(name, oa->o_id, oa->o_mode);
+        mode = (oa->o_mode & ~S_IFMT) | S_IFREG;
         push_ctxt(&saved, &obddev->u.filter.fo_ctxt);
-        mode = oa->o_mode;
-        mode &= ~S_IFMT;
-        mode |= S_IFREG;
         file = filp_open(name, O_RDONLY | O_CREAT, mode);
         pop_ctxt(&saved);
         if (IS_ERR(file)) {
@@ -489,22 +635,23 @@ static int filter_create (struct obd_conn* conn, struct obdo *oa)
         }
         filp_close(file, 0);
 
-        /* Set flags for fields we have set in ext2_new_inode */
+        /* Set flags for fields we have set in the inode struct */
         oa->o_valid |= OBD_MD_FLID | OBD_MD_FLBLKSZ | OBD_MD_FLBLOCKS |
                  OBD_MD_FLMTIME | OBD_MD_FLATIME | OBD_MD_FLCTIME |
                  OBD_MD_FLUID | OBD_MD_FLGID;
+
+        /* XXX Hmm, shouldn't we copy the fields into the obdo here? */
         return 0;
 }
 
 static int filter_destroy(struct obd_conn *conn, struct obdo *oa)
 {
-        struct obd_device * obddev;
-        struct obd_client * cli;
-        struct file *dir;
-        struct file *object;
+        struct obd_run_ctxt saved;
+        struct obd_device *obddev;
+        struct obd_client *cli;
+        struct inode *inode;
         struct dentry *dir_dentry, *object_dentry;
         int rc;
-        struct obd_run_ctxt saved;
         ENTRY;
 
         if (!(cli = gen_client(conn))) {
@@ -512,35 +659,48 @@ static int filter_destroy(struct obd_conn *conn, struct obdo *oa)
                 RETURN(-EINVAL);
         }
 
+        CDEBUG(D_INODE, "destroying object %Ld\n",oa->o_id);
         obddev = conn->oc_dev;
-        object = filter_obj_open(obddev, oa->o_id, oa->o_mode);
-        if (!object || IS_ERR(object))
-                RETURN(-ENOENT);
 
         push_ctxt(&saved, &obddev->u.filter.fo_ctxt);
-        dir = filter_parent(oa->o_id, oa->o_mode);
-        if (IS_ERR(dir))
-                GOTO(out, rc = PTR_ERR(dir));
-        dir_dentry = dget(dir->f_dentry);
-        object_dentry = dget(object->f_dentry);
-        filp_close(dir, 0);
-        filp_close(object, 0);
+        dir_dentry = filter_parent(obddev, oa->o_mode);
+        down(&dir_dentry->d_inode->i_sem);
+
+        object_dentry = filter_fid2dentry(obddev, dir_dentry, oa->o_id,
+                                          oa->o_mode);
+        if (IS_ERR(object_dentry))
+                GOTO(out, rc = -ENOENT);
+
+        inode = object_dentry->d_inode;
+        if (inode->i_nlink != 1) {
+                CERROR("destroying inode with nlink = %d\n", inode->i_nlink);
+                inode->i_nlink = 1;
+        }
+        inode->i_mode = 010000;
+
+        CDEBUG(D_INODE, "calling vfs_unlink for object #%ld\n", inode->i_ino);
+        push_ctxt(&saved, &obddev->u.filter.fo_ctxt);
         rc = vfs_unlink(dir_dentry->d_inode, object_dentry);
+        pop_ctxt(&saved);
+        CDEBUG(D_INODE, "put child %p, count = %d\n", object_dentry,
+               object_dentry->d_count.counter-1);
+        l_dput(object_dentry);
 
-        dput(dir_dentry);
-        dput(object_dentry);
         EXIT;
 out:
-        pop_ctxt(&saved);
+        up(&dir_dentry->d_inode->i_sem);
         return rc;
 }
 
+/* NB count and offset are used for punch, but not truncate */
 static int filter_truncate(struct obd_conn *conn, struct obdo *oa,
                            obd_size count, obd_off offset)
 {
         int error;
         ENTRY;
 
+        CDEBUG(D_INODE, "calling truncate for object #%Ld, valid = %x, "
+               "o_size = %Ld\n", oa->o_id, oa->o_valid, oa->o_size);
         error = filter_setattr(conn, oa);
         oa->o_valid = OBD_MD_FLBLOCKS | OBD_MD_FLCTIME | OBD_MD_FLMTIME;
 
@@ -562,8 +722,8 @@ static int filter_read(struct obd_conn *conn, struct obdo *oa, char *buf,
         }
 
         file = filter_obj_open(conn->oc_dev, oa->o_id, oa->o_mode);
-        if (!file || IS_ERR(file))
-                RETURN(-PTR_ERR(file));
+        if (IS_ERR(file))
+                RETURN(PTR_ERR(file));
 
         /* count doubles as retval */
         retval = file->f_op->read(file, buf, *count, (loff_t *)&offset);
@@ -585,6 +745,7 @@ static int filter_read(struct obd_conn *conn, struct obdo *oa, char *buf,
 static int filter_write(struct obd_conn *conn, struct obdo *oa, char *buf,
                          obd_size *count, obd_off offset)
 {
+        struct obd_run_ctxt saved;
         int err;
         struct file * file;
         unsigned long retval;
@@ -596,11 +757,13 @@ static int filter_write(struct obd_conn *conn, struct obdo *oa, char *buf,
         }
 
         file = filter_obj_open(conn->oc_dev, oa->o_id, oa->o_mode);
-        if (!file || IS_ERR(file))
-                RETURN(-PTR_ERR(file));
+        if (IS_ERR(file))
+                RETURN(PTR_ERR(file));
 
         /* count doubles as retval */
+        push_ctxt(&saved, &conn->oc_dev->u.filter.fo_ctxt);
         retval = file->f_op->write(file, buf, *count, (loff_t *)&offset);
+        pop_ctxt(&saved);
         filp_close(file, 0);
 
         if ( retval >= 0 ) {
@@ -616,22 +779,18 @@ static int filter_write(struct obd_conn *conn, struct obdo *oa, char *buf,
         return err;
 } /* filter_write */
 
-static int filter_pgcache_brw(int rw, struct obd_conn *conn,
-                               obd_count num_oa,
-                               struct obdo **oa,
-                               obd_count *oa_bufs,
-                               struct page **pages,
-                               obd_size *count,
-                               obd_off *offset,
-                               obd_flag *flags)
+static int filter_pgcache_brw(int rw, struct obd_conn *conn, obd_count num_oa,
+                               struct obdo **oa, obd_count *oa_bufs,
+                               struct page **pages, obd_size *count,
+                               obd_off *offset, obd_flag *flags)
 {
+        struct obd_run_ctxt      saved;
         struct super_block      *sb;
-        mm_segment_t oldfs;
         int                      onum;          /* index to oas */
         int                      pnum;          /* index to pages (bufs) */
         unsigned long            retval;
         int                      error;
-        struct file *file;
+        struct file             *file;
         ENTRY;
 
         if (!gen_client(conn)) {
@@ -640,17 +799,16 @@ static int filter_pgcache_brw(int rw, struct obd_conn *conn,
         }
 
         sb = conn->oc_dev->u.filter.fo_sb;
-        oldfs = get_fs();
-        set_fs(KERNEL_DS);
-
+        // if (rw == WRITE)
+        push_ctxt(&saved, &conn->oc_dev->u.filter.fo_ctxt);
         pnum = 0; /* pnum indexes buf 0..num_pages */
         for (onum = 0; onum < num_oa; onum++) {
                 int pg;
 
                 file = filter_obj_open(conn->oc_dev, oa[onum]->o_id,
                                        oa[onum]->o_mode);
-                if (!file || IS_ERR(file))
-                        GOTO(ERROR, error = -ENOENT);
+                if (IS_ERR(file))
+                        GOTO(out, retval = PTR_ERR(file));
 
                 /* count doubles as retval */
                 for (pg = 0; pg < oa_bufs[onum]; pg++) {
@@ -680,9 +838,9 @@ static int filter_pgcache_brw(int rw, struct obd_conn *conn,
                                 }
                                 kunmap(pages[pnum]);
 
-                                if ( retval != count[pnum] ) {
+                                if (retval != count[pnum]) {
                                         filp_close(file, 0);
-                                        GOTO(ERROR, retval = -EIO);
+                                        GOTO(out, retval = -EIO);
                                 }
                                 CDEBUG(D_INODE, "retval %ld\n", retval);
                         }
@@ -694,8 +852,9 @@ static int filter_pgcache_brw(int rw, struct obd_conn *conn,
         }
 
         EXIT;
- ERROR:
-        set_fs(oldfs);
+out:
+        // if (rw == WRITE)
+        pop_ctxt(&saved);
         error = (retval >= 0) ? 0 : retval;
         return error;
 }
@@ -703,8 +862,8 @@ static int filter_pgcache_brw(int rw, struct obd_conn *conn,
 
 struct inode *ioobj_to_inode(struct obd_conn *conn, struct obd_ioobj *o)
 {
+        struct super_block *sb = conn->oc_dev->u.filter.fo_sb;
         struct inode *inode = NULL;
-        struct super_block *sb = conn->oc_dev->u.ext2.e2_sb;
         ENTRY;
 
         if (!sb || !sb->s_dev) {
@@ -722,8 +881,7 @@ struct inode *ioobj_to_inode(struct obd_conn *conn, struct obd_ioobj *o)
                 CERROR("from obdo - fatal: invalid inode %ld (%s).\n",
                        (long)o->ioo_id, inode ? inode->i_nlink ? "bad inode" :
                        "no links" : "NULL");
-                if (inode)
-                        iput(inode);
+                iput(inode);
                 RETURN(NULL);
         }
 
@@ -735,6 +893,7 @@ static int filter_preprw(int cmd, struct obd_conn *conn,
                          int niocount, struct niobuf_remote *nb,
                          struct niobuf_local *res)
 {
+        struct obd_run_ctxt saved;
         struct obd_ioobj *o = obj;
         struct niobuf_remote *b = nb;
         struct niobuf_local *r = res;
@@ -743,6 +902,8 @@ static int filter_preprw(int cmd, struct obd_conn *conn,
 
         memset(res, 0, sizeof(*res) * niocount);
 
+        // if (cmd == OBD_BRW_WRITE)
+        push_ctxt(&saved, &conn->oc_dev->u.filter.fo_ctxt);
         for (i = 0; i < objcount; i++, o++) {
                 int j;
                 for (j = 0; j < o->ioo_bufcnt; j++, b++, r++) {
@@ -767,18 +928,23 @@ static int filter_preprw(int cmd, struct obd_conn *conn,
                         r->len = PAGE_SIZE;
                 }
         }
-        return 0;
+        // if (cmd == OBD_BRW_WRITE)
+        pop_ctxt(&saved);
+        return(0);
 }
 
 static int filter_commitrw(int cmd, struct obd_conn *conn,
                            int objcount, struct obd_ioobj *obj,
                            int niocount, struct niobuf_local *res)
 {
+        struct obd_run_ctxt saved;
         struct obd_ioobj *o = obj;
         struct niobuf_local *r = res;
         int i;
         ENTRY;
 
+        // if (cmd == OBD_BRW_WRITE)
+        push_ctxt(&saved, &conn->oc_dev->u.filter.fo_ctxt);
         for (i = 0; i < objcount; i++, obj++) {
                 int j;
                 for (j = 0 ; j < o->ioo_bufcnt ; j++, r++) {
@@ -796,13 +962,20 @@ static int filter_commitrw(int cmd, struct obd_conn *conn,
                         } else
                                 lustre_put_page(page);
 
+                        CDEBUG(D_INODE, "put inode %p (%ld), count = %d, nlink = %d\n",
+                               page->mapping->host,
+                               page->mapping->host->i_ino,
+                               page->mapping->host->i_count.counter - 1,
+                               page->mapping->host->i_nlink);
                         iput(page->mapping->host);
                 }
         }
+        // if (cmd == OBD_BRW_WRITE)
+        pop_ctxt(&saved);
         RETURN(0);
 }
 
-static int filter_statfs (struct obd_conn *conn, struct statfs * statfs)
+static int filter_statfs(struct obd_conn *conn, struct statfs * statfs)
 {
         struct super_block *sb;
         int err;
@@ -820,8 +993,8 @@ static int filter_statfs (struct obd_conn *conn, struct statfs * statfs)
 } /* filter_statfs */
 
 
-static int  filter_get_info(struct obd_conn *conn, obd_count keylen,
-                             void *key, obd_count *vallen, void **val)
+static int filter_get_info(struct obd_conn *conn, obd_count keylen,
+                           void *key, obd_count *vallen, void **val)
 {
         struct obd_device *obddev;
         struct obd_client * cli;