@@ -60,6 +60,52 @@ static int nfs_update_inode(struct inode
static struct kmem_cache * nfs_inode_cachep;
+/*
+ * FSCFC:
+ *
+ * Implementations of FNV-1 hash function:
+ * http://isthe.com/chongo/tech/comp/fnv
+ * http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash#Notes
+ */
+static inline uint32_t
+nfs_fh_hash32(struct nfs_fh *fh)
+{
+ static const uint32_t seed = 2166136261U,
+ prime = 16777619U;
+ uint32_t hash = seed, i = 0;
+
+ while (i < fh->size) {
+ hash = (hash * prime) ^ fh->data[i];
+ ++i;
+ }
+
+ return hash;
+}
+
+static inline uint64_t
+nfs_fh_hash64(struct nfs_fh *fh)
+{
+ static const uint64_t seed = 14695981039346656037U,
+ prime = 1099511628211U;
+ uint64_t hash = seed, i = 0;
+
+ while (i < fh->size) {
+ hash = (hash * prime) ^ fh->data[i];
+ ++i;
+ }
+
+ return hash;
+}
+
+static inline unsigned long
+nfs_fh_hash(struct nfs_fh *fh)
+{
+ if (sizeof(unsigned long) == 4)
+ return nfs_fh_hash32(fh);
+
+ return nfs_fh_hash64(fh);
+}
+
static inline unsigned long
nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
{
@@ -268,7 +314,28 @@ nfs_fhget(struct super_block *sb, struct
if ((fattr->valid & NFS_ATTR_FATTR_TYPE) == 0)
goto out_no_inode;
- hash = nfs_fattr_to_ino_t(fattr);
+ /*
+ * FSCFC:
+ *
+ * This patch exists solely to work around the Bluearc duplicate inode/NFS
+ * fileid bug. On Bluearc filesystems a distinct, non-hardlinked file or
+ * directory appears to share the same fsid + fileid with other completely
+ * unrelated files elsewhere in the hierarchy. This becomes a problem for
+ * any system dependent on the commonly accpepted notion of the NFSv3 fsid
+ * and fileid uniquely identifying a single file/directory within an NFS
+ * filesystem. Thankfully, the NFS file handle for any duplications are
+ * still unique :)
+ *
+ * We must update *both* the hash value (was the i_ino/fileid as returned
+ * by nfs_fattr_to_ino_t() above) and fileid here as it is used as the key
+ * in the inode cache maintained within iget5_locked() below.
+ *
+ * We set fattr->fileid to 'hash' to because NFS_FILEID and set_nfs_fileid()
+ * just copy/return 'fileid' from this structure which the server has
+ * already sent as the inode on it's filesystem as you'd expect. This is
+ * what we overwrite - client side only.
+ */
+ fattr->fileid = hash = nfs_fh_hash(fh); // JV alternate code
inode = iget5_locked(sb, hash, nfs_find_actor, nfs_init_locked, &desc);
if (inode == NULL) {
@@ -907,7 +974,6 @@ static int nfs_check_inode_attributes(st
loff_t cur_size, new_isize;
unsigned long invalid = 0;
-
/* Has the inode gone and changed behind our back? */
if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
return -EIO;
@@ -1036,6 +1102,12 @@ int nfs_refresh_inode(struct inode *inod
if ((fattr->valid & NFS_ATTR_FATTR) == 0)
return 0;
+
+ /*
+ * FSCFC: Compare against the hashed file handle, not the fileid
+ */
+ fattr->fileid = nfs_fh_hash(NFS_FH(inode)); // JV alternate code
+
spin_lock(&inode->i_lock);
status = nfs_refresh_inode_locked(inode, fattr);
spin_unlock(&inode->i_lock);