tunnels: fix netns vs proto registration ordering
[safe/jmp/linux-2.6] / fs / ocfs2 / export.c
index fb91089..15713cb 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "ocfs2.h"
 
+#include "alloc.h"
 #include "dir.h"
 #include "dlmglue.h"
 #include "dcache.h"
@@ -38,6 +39,7 @@
 #include "inode.h"
 
 #include "buffer_head_io.h"
+#include "suballoc.h"
 
 struct ocfs2_inode_handle
 {
@@ -45,41 +47,102 @@ struct ocfs2_inode_handle
        u32 ih_generation;
 };
 
-static struct dentry *ocfs2_get_dentry(struct super_block *sb, void *vobjp)
+static struct dentry *ocfs2_get_dentry(struct super_block *sb,
+               struct ocfs2_inode_handle *handle)
 {
-       struct ocfs2_inode_handle *handle = vobjp;
        struct inode *inode;
+       struct ocfs2_super *osb = OCFS2_SB(sb);
+       u64 blkno = handle->ih_blkno;
+       int status, set;
        struct dentry *result;
 
        mlog_entry("(0x%p, 0x%p)\n", sb, handle);
 
-       if (handle->ih_blkno == 0) {
-               mlog_errno(-ESTALE);
-               return ERR_PTR(-ESTALE);
+       if (blkno == 0) {
+               mlog(0, "nfs wants inode with blkno: 0\n");
+               result = ERR_PTR(-ESTALE);
+               goto bail;
+       }
+
+       inode = ocfs2_ilookup(sb, blkno);
+       /*
+        * If the inode exists in memory, we only need to check it's
+        * generation number
+        */
+       if (inode)
+               goto check_gen;
+
+       /*
+        * This will synchronize us against ocfs2_delete_inode() on
+        * all nodes
+        */
+       status = ocfs2_nfs_sync_lock(osb, 1);
+       if (status < 0) {
+               mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n", status);
+               goto check_err;
        }
 
-       inode = ocfs2_iget(OCFS2_SB(sb), handle->ih_blkno, 0);
+       status = ocfs2_test_inode_bit(osb, blkno, &set);
+       if (status < 0) {
+               if (status == -EINVAL) {
+                       /*
+                        * The blkno NFS gave us doesn't even show up
+                        * as an inode, we return -ESTALE to be
+                        * nice
+                        */
+                       mlog(0, "test inode bit failed %d\n", status);
+                       status = -ESTALE;
+               } else {
+                       mlog(ML_ERROR, "test inode bit failed %d\n", status);
+               }
+               goto unlock_nfs_sync;
+       }
+
+       /* If the inode allocator bit is clear, this inode must be stale */
+       if (!set) {
+               mlog(0, "inode %llu suballoc bit is clear\n",
+                    (unsigned long long)blkno);
+               status = -ESTALE;
+               goto unlock_nfs_sync;
+       }
+
+       inode = ocfs2_iget(osb, blkno, 0, 0);
+
+unlock_nfs_sync:
+       ocfs2_nfs_sync_unlock(osb, 1);
+
+check_err:
+       if (status < 0) {
+               if (status == -ESTALE) {
+                       mlog(0, "stale inode ino: %llu generation: %u\n",
+                            (unsigned long long)blkno, handle->ih_generation);
+               }
+               result = ERR_PTR(status);
+               goto bail;
+       }
 
        if (IS_ERR(inode)) {
                mlog_errno(PTR_ERR(inode));
-               return (void *)inode;
+               result = (void *)inode;
+               goto bail;
        }
 
+check_gen:
        if (handle->ih_generation != inode->i_generation) {
                iput(inode);
-               mlog_errno(-ESTALE);
-               return ERR_PTR(-ESTALE);
+               mlog(0, "stale inode ino: %llu generation: %u\n",
+                    (unsigned long long)blkno, handle->ih_generation);
+               result = ERR_PTR(-ESTALE);
+               goto bail;
        }
 
-       result = d_alloc_anon(inode);
-
-       if (!result) {
-               iput(inode);
-               mlog_errno(-ENOMEM);
-               return ERR_PTR(-ENOMEM);
-       }
-       result->d_op = &ocfs2_dentry_ops;
+       result = d_obtain_alias(inode);
+       if (!IS_ERR(result))
+               result->d_op = &ocfs2_dentry_ops;
+       else
+               mlog_errno(PTR_ERR(result));
 
+bail:
        mlog_exit_ptr(result);
        return result;
 }
@@ -89,10 +152,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
        int status;
        u64 blkno;
        struct dentry *parent;
-       struct inode *inode;
        struct inode *dir = child->d_inode;
-       struct buffer_head *dirent_bh = NULL;
-       struct ocfs2_dir_entry *dirent;
 
        mlog_entry("(0x%p, '%.*s')\n", child,
                   child->d_name.len, child->d_name.name);
@@ -100,7 +160,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
        mlog(0, "find parent of directory %llu\n",
             (unsigned long long)OCFS2_I(dir)->ip_blkno);
 
-       status = ocfs2_meta_lock(dir, NULL, NULL, 0);
+       status = ocfs2_inode_lock(dir, NULL, 0);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -108,34 +168,18 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
                goto bail;
        }
 
-       status = ocfs2_find_files_on_disk("..", 2, &blkno, dir, &dirent_bh,
-                                         &dirent);
+       status = ocfs2_lookup_ino_from_name(dir, "..", 2, &blkno);
        if (status < 0) {
                parent = ERR_PTR(-ENOENT);
                goto bail_unlock;
        }
 
-       inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0);
-       if (IS_ERR(inode)) {
-               mlog(ML_ERROR, "Unable to create inode %llu\n",
-                    (unsigned long long)blkno);
-               parent = ERR_PTR(-EACCES);
-               goto bail_unlock;
-       }
-
-       parent = d_alloc_anon(inode);
-       if (!parent) {
-               iput(inode);
-               parent = ERR_PTR(-ENOMEM);
-       }
-
-       parent->d_op = &ocfs2_dentry_ops;
+       parent = d_obtain_alias(ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0));
+       if (!IS_ERR(parent))
+               parent->d_op = &ocfs2_dentry_ops;
 
 bail_unlock:
-       ocfs2_meta_unlock(dir, 0);
-
-       if (dirent_bh)
-               brelse(dirent_bh);
+       ocfs2_inode_unlock(dir, 0);
 
 bail:
        mlog_exit_ptr(parent);
@@ -143,7 +187,7 @@ bail:
        return parent;
 }
 
-static int ocfs2_encode_fh(struct dentry *dentry, __be32 *fh, int *max_len,
+static int ocfs2_encode_fh(struct dentry *dentry, u32 *fh_in, int *max_len,
                           int connectable)
 {
        struct inode *inode = dentry->d_inode;
@@ -151,6 +195,7 @@ static int ocfs2_encode_fh(struct dentry *dentry, __be32 *fh, int *max_len,
        int type = 1;
        u64 blkno;
        u32 generation;
+       __le32 *fh = (__force __le32 *) fh_in;
 
        mlog_entry("(0x%p, '%.*s', 0x%p, %d, %d)\n", dentry,
                   dentry->d_name.len, dentry->d_name.name,
@@ -202,53 +247,37 @@ bail:
        return type;
 }
 
-static struct dentry *ocfs2_decode_fh(struct super_block *sb, __be32 *fh,
-                                     int fh_len, int fileid_type,
-                                     int (*acceptable)(void *context,
-                                                       struct dentry *de),
-                                     void *context)
+static struct dentry *ocfs2_fh_to_dentry(struct super_block *sb,
+               struct fid *fid, int fh_len, int fh_type)
 {
-       struct ocfs2_inode_handle handle, parent;
-       struct dentry *ret = NULL;
+       struct ocfs2_inode_handle handle;
 
-       mlog_entry("(0x%p, 0x%p, %d, %d, 0x%p, 0x%p)\n",
-                  sb, fh, fh_len, fileid_type, acceptable, context);
+       if (fh_len < 3 || fh_type > 2)
+               return NULL;
 
-       if (fh_len < 3 || fileid_type > 2)
-               goto bail;
-
-       if (fileid_type == 2) {
-               if (fh_len < 6)
-                       goto bail;
-
-               parent.ih_blkno = (u64)le32_to_cpu(fh[3]) << 32;
-               parent.ih_blkno |= (u64)le32_to_cpu(fh[4]);
-               parent.ih_generation = le32_to_cpu(fh[5]);
-
-               mlog(0, "Decoding parent: blkno: %llu, generation: %u\n",
-                    (unsigned long long)parent.ih_blkno,
-                    parent.ih_generation);
-       }
-
-       handle.ih_blkno = (u64)le32_to_cpu(fh[0]) << 32;
-       handle.ih_blkno |= (u64)le32_to_cpu(fh[1]);
-       handle.ih_generation = le32_to_cpu(fh[2]);
+       handle.ih_blkno = (u64)le32_to_cpu(fid->raw[0]) << 32;
+       handle.ih_blkno |= (u64)le32_to_cpu(fid->raw[1]);
+       handle.ih_generation = le32_to_cpu(fid->raw[2]);
+       return ocfs2_get_dentry(sb, &handle);
+}
 
-       mlog(0, "Encoding fh: blkno: %llu, generation: %u\n",
-            (unsigned long long)handle.ih_blkno, handle.ih_generation);
+static struct dentry *ocfs2_fh_to_parent(struct super_block *sb,
+               struct fid *fid, int fh_len, int fh_type)
+{
+       struct ocfs2_inode_handle parent;
 
-       ret = ocfs2_export_ops.find_exported_dentry(sb, &handle, &parent,
-                                                   acceptable, context);
+       if (fh_type != 2 || fh_len < 6)
+               return NULL;
 
-bail:
-       mlog_exit_ptr(ret);
-       return ret;
+       parent.ih_blkno = (u64)le32_to_cpu(fid->raw[3]) << 32;
+       parent.ih_blkno |= (u64)le32_to_cpu(fid->raw[4]);
+       parent.ih_generation = le32_to_cpu(fid->raw[5]);
+       return ocfs2_get_dentry(sb, &parent);
 }
 
-struct export_operations ocfs2_export_ops = {
-       .decode_fh      = ocfs2_decode_fh,
+const struct export_operations ocfs2_export_ops = {
        .encode_fh      = ocfs2_encode_fh,
-
+       .fh_to_dentry   = ocfs2_fh_to_dentry,
+       .fh_to_parent   = ocfs2_fh_to_parent,
        .get_parent     = ocfs2_get_parent,
-       .get_dentry     = ocfs2_get_dentry,
 };