]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/ceph/dir.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / fs / ceph / dir.c
index d902948a90d88622e9af8bbfc505a779fe735d99..ebafa65a29b6580619c75256195547a5107cb86d 100644 (file)
@@ -42,11 +42,11 @@ int ceph_init_dentry(struct dentry *dentry)
 
        if (dentry->d_parent == NULL ||   /* nfs fh_to_dentry */
            ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP)
-               dentry->d_op = &ceph_dentry_ops;
+               d_set_d_op(dentry, &ceph_dentry_ops);
        else if (ceph_snap(dentry->d_parent->d_inode) == CEPH_SNAPDIR)
-               dentry->d_op = &ceph_snapdir_dentry_ops;
+               d_set_d_op(dentry, &ceph_snapdir_dentry_ops);
        else
-               dentry->d_op = &ceph_snap_dentry_ops;
+               d_set_d_op(dentry, &ceph_snap_dentry_ops);
 
        di = kmem_cache_alloc(ceph_dentry_cachep, GFP_NOFS | __GFP_ZERO);
        if (!di)
@@ -112,7 +112,7 @@ static int __dcache_readdir(struct file *filp,
        dout("__dcache_readdir %p at %llu (last %p)\n", dir, filp->f_pos,
             last);
 
-       spin_lock(&dcache_lock);
+       spin_lock(&parent->d_lock);
 
        /* start at beginning? */
        if (filp->f_pos == 2 || last == NULL ||
@@ -136,6 +136,7 @@ more:
                        fi->at_end = 1;
                        goto out_unlock;
                }
+               spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
                if (!d_unhashed(dentry) && dentry->d_inode &&
                    ceph_snap(dentry->d_inode) != CEPH_SNAPDIR &&
                    ceph_ino(dentry->d_inode) != CEPH_INO_CEPH &&
@@ -145,13 +146,15 @@ more:
                     dentry->d_name.len, dentry->d_name.name, di->offset,
                     filp->f_pos, d_unhashed(dentry) ? " unhashed" : "",
                     !dentry->d_inode ? " null" : "");
+               spin_unlock(&dentry->d_lock);
                p = p->prev;
                dentry = list_entry(p, struct dentry, d_u.d_child);
                di = ceph_dentry(dentry);
        }
 
-       atomic_inc(&dentry->d_count);
-       spin_unlock(&dcache_lock);
+       dget_dlock(dentry);
+       spin_unlock(&dentry->d_lock);
+       spin_unlock(&parent->d_lock);
 
        dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, filp->f_pos,
             dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
@@ -177,19 +180,19 @@ more:
 
        filp->f_pos++;
 
-       /* make sure a dentry wasn't dropped while we didn't have dcache_lock */
+       /* make sure a dentry wasn't dropped while we didn't have parent lock */
        if (!ceph_i_test(dir, CEPH_I_COMPLETE)) {
                dout(" lost I_COMPLETE on %p; falling back to mds\n", dir);
                err = -EAGAIN;
                goto out;
        }
 
-       spin_lock(&dcache_lock);
+       spin_lock(&parent->d_lock);
        p = p->prev;    /* advance to next dentry */
        goto more;
 
 out_unlock:
-       spin_unlock(&dcache_lock);
+       spin_unlock(&parent->d_lock);
 out:
        if (last)
                dput(last);
@@ -406,7 +409,7 @@ more:
        spin_lock(&inode->i_lock);
        if (ci->i_release_count == fi->dir_release_count) {
                dout(" marking %p complete\n", inode);
-               ci->i_ceph_flags |= CEPH_I_COMPLETE;
+               /* ci->i_ceph_flags |= CEPH_I_COMPLETE; */
                ci->i_max_offset = filp->f_pos;
        }
        spin_unlock(&inode->i_lock);
@@ -493,6 +496,7 @@ struct dentry *ceph_finish_lookup(struct ceph_mds_request *req,
 
        /* .snap dir? */
        if (err == -ENOENT &&
+           ceph_snap(parent) == CEPH_NOSNAP &&
            strcmp(dentry->d_name.name,
                   fsc->mount_options->snapdir_name) == 0) {
                struct inode *inode = ceph_get_snapdir(parent);
@@ -987,7 +991,12 @@ static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry)
  */
 static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
-       struct inode *dir = dentry->d_parent->d_inode;
+       struct inode *dir;
+
+       if (nd && nd->flags & LOOKUP_RCU)
+               return -ECHILD;
+
+       dir = dentry->d_parent->d_inode;
 
        dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry,
             dentry->d_name.len, dentry->d_name.name, dentry->d_inode,
@@ -1021,28 +1030,8 @@ out_touch:
 static void ceph_dentry_release(struct dentry *dentry)
 {
        struct ceph_dentry_info *di = ceph_dentry(dentry);
-       struct inode *parent_inode = NULL;
-       u64 snapid = CEPH_NOSNAP;
 
-       if (!IS_ROOT(dentry)) {
-               parent_inode = dentry->d_parent->d_inode;
-               if (parent_inode)
-                       snapid = ceph_snap(parent_inode);
-       }
-       dout("dentry_release %p parent %p\n", dentry, parent_inode);
-       if (parent_inode && snapid != CEPH_SNAPDIR) {
-               struct ceph_inode_info *ci = ceph_inode(parent_inode);
-
-               spin_lock(&parent_inode->i_lock);
-               if (ci->i_shared_gen == di->lease_shared_gen ||
-                   snapid <= CEPH_MAXSNAP) {
-                       dout(" clearing %p complete (d_release)\n",
-                            parent_inode);
-                       ci->i_ceph_flags &= ~CEPH_I_COMPLETE;
-                       ci->i_release_count++;
-               }
-               spin_unlock(&parent_inode->i_lock);
-       }
+       dout("dentry_release %p\n", dentry);
        if (di) {
                ceph_dentry_lru_del(dentry);
                if (di->lease_session)
@@ -1216,6 +1205,26 @@ void ceph_dentry_lru_del(struct dentry *dn)
        }
 }
 
+/*
+ * Return name hash for a given dentry.  This is dependent on
+ * the parent directory's hash function.
+ */
+unsigned ceph_dentry_hash(struct dentry *dn)
+{
+       struct inode *dir = dn->d_parent->d_inode;
+       struct ceph_inode_info *dci = ceph_inode(dir);
+
+       switch (dci->i_dir_layout.dl_dir_hash) {
+       case 0: /* for backward compat */
+       case CEPH_STR_HASH_LINUX:
+               return dn->d_name.hash;
+
+       default:
+               return ceph_str_hash(dci->i_dir_layout.dl_dir_hash,
+                                    dn->d_name.name, dn->d_name.len);
+       }
+}
+
 const struct file_operations ceph_dir_fops = {
        .read = ceph_read_dir,
        .readdir = ceph_readdir,