.type           = FSCACHE_COOKIE_TYPE_INDEX,
        .get_key        = nfs_server_get_key,
 };
+
+/*
+ * Generate a key to describe a superblock key in the main NFS index
+ */
+static uint16_t nfs_super_get_key(const void *cookie_netfs_data,
+                                 void *buffer, uint16_t bufmax)
+{
+       const struct nfs_fscache_key *key;
+       const struct nfs_server *nfss = cookie_netfs_data;
+       uint16_t len;
+
+       key = nfss->fscache_key;
+       len = sizeof(key->key) + key->key.uniq_len;
+       if (len > bufmax) {
+               len = 0;
+       } else {
+               memcpy(buffer, &key->key, sizeof(key->key));
+               memcpy(buffer + sizeof(key->key),
+                      key->key.uniquifier, key->key.uniq_len);
+       }
+
+       return len;
+}
+
+/*
+ * Define the superblock object for FS-Cache.  This is used to describe a
+ * superblock object to fscache_acquire_cookie().  It is keyed by all the NFS
+ * parameters that might cause a separate superblock.
+ */
+const struct fscache_cookie_def nfs_fscache_super_index_def = {
+       .name           = "NFS.super",
+       .type           = FSCACHE_COOKIE_TYPE_INDEX,
+       .get_key        = nfs_super_get_key,
+};
 
 
 #define NFSDBG_FACILITY                NFSDBG_FSCACHE
 
+static struct rb_root nfs_fscache_keys = RB_ROOT;
+static DEFINE_SPINLOCK(nfs_fscache_keys_lock);
+
 /*
  * Get the per-client index cookie for an NFS client if the appropriate mount
  * flag was set
        fscache_relinquish_cookie(clp->fscache, 0);
        clp->fscache = NULL;
 }
+
+/*
+ * Get the cache cookie for an NFS superblock.  We have to handle
+ * uniquification here because the cache doesn't do it for us.
+ */
+void nfs_fscache_get_super_cookie(struct super_block *sb,
+                                 struct nfs_parsed_mount_data *data)
+{
+       struct nfs_fscache_key *key, *xkey;
+       struct nfs_server *nfss = NFS_SB(sb);
+       struct rb_node **p, *parent;
+       const char *uniq = data->fscache_uniq ?: "";
+       int diff, ulen;
+
+       ulen = strlen(uniq);
+       key = kzalloc(sizeof(*key) + ulen, GFP_KERNEL);
+       if (!key)
+               return;
+
+       key->nfs_client = nfss->nfs_client;
+       key->key.super.s_flags = sb->s_flags & NFS_MS_MASK;
+       key->key.nfs_server.flags = nfss->flags;
+       key->key.nfs_server.rsize = nfss->rsize;
+       key->key.nfs_server.wsize = nfss->wsize;
+       key->key.nfs_server.acregmin = nfss->acregmin;
+       key->key.nfs_server.acregmax = nfss->acregmax;
+       key->key.nfs_server.acdirmin = nfss->acdirmin;
+       key->key.nfs_server.acdirmax = nfss->acdirmax;
+       key->key.nfs_server.fsid = nfss->fsid;
+       key->key.rpc_auth.au_flavor = nfss->client->cl_auth->au_flavor;
+
+       key->key.uniq_len = ulen;
+       memcpy(key->key.uniquifier, uniq, ulen);
+
+       spin_lock(&nfs_fscache_keys_lock);
+       p = &nfs_fscache_keys.rb_node;
+       parent = NULL;
+       while (*p) {
+               parent = *p;
+               xkey = rb_entry(parent, struct nfs_fscache_key, node);
+
+               if (key->nfs_client < xkey->nfs_client)
+                       goto go_left;
+               if (key->nfs_client > xkey->nfs_client)
+                       goto go_right;
+
+               diff = memcmp(&key->key, &xkey->key, sizeof(key->key));
+               if (diff < 0)
+                       goto go_left;
+               if (diff > 0)
+                       goto go_right;
+
+               if (key->key.uniq_len == 0)
+                       goto non_unique;
+               diff = memcmp(key->key.uniquifier,
+                             xkey->key.uniquifier,
+                             key->key.uniq_len);
+               if (diff < 0)
+                       goto go_left;
+               if (diff > 0)
+                       goto go_right;
+               goto non_unique;
+
+       go_left:
+               p = &(*p)->rb_left;
+               continue;
+       go_right:
+               p = &(*p)->rb_right;
+       }
+
+       rb_link_node(&key->node, parent, p);
+       rb_insert_color(&key->node, &nfs_fscache_keys);
+       spin_unlock(&nfs_fscache_keys_lock);
+       nfss->fscache_key = key;
+
+       /* create a cache index for looking up filehandles */
+       nfss->fscache = fscache_acquire_cookie(nfss->nfs_client->fscache,
+                                              &nfs_fscache_super_index_def,
+                                              nfss);
+       dfprintk(FSCACHE, "NFS: get superblock cookie (0x%p/0x%p)\n",
+                nfss, nfss->fscache);
+       return;
+
+non_unique:
+       spin_unlock(&nfs_fscache_keys_lock);
+       kfree(key);
+       nfss->fscache_key = NULL;
+       nfss->fscache = NULL;
+       printk(KERN_WARNING "NFS:"
+              " Cache request denied due to non-unique superblock keys\n");
+}
+
+/*
+ * release a per-superblock cookie
+ */
+void nfs_fscache_release_super_cookie(struct super_block *sb)
+{
+       struct nfs_server *nfss = NFS_SB(sb);
+
+       dfprintk(FSCACHE, "NFS: releasing superblock cookie (0x%p/0x%p)\n",
+                nfss, nfss->fscache);
+
+       fscache_relinquish_cookie(nfss->fscache, 0);
+       nfss->fscache = NULL;
+
+       if (nfss->fscache_key) {
+               spin_lock(&nfs_fscache_keys_lock);
+               rb_erase(&nfss->fscache_key->node, &nfs_fscache_keys);
+               spin_unlock(&nfs_fscache_keys_lock);
+               kfree(nfss->fscache_key);
+               nfss->fscache_key = NULL;
+       }
+}
 
 
 #ifdef CONFIG_NFS_FSCACHE
 
+/*
+ * set of NFS FS-Cache objects that form a superblock key
+ */
+struct nfs_fscache_key {
+       struct rb_node          node;
+       struct nfs_client       *nfs_client;    /* the server */
+
+       /* the elements of the unique key - as used by nfs_compare_super() and
+        * nfs_compare_mount_options() to distinguish superblocks */
+       struct {
+               struct {
+                       unsigned long   s_flags;        /* various flags
+                                                        * (& NFS_MS_MASK) */
+               } super;
+
+               struct {
+                       struct nfs_fsid fsid;
+                       int             flags;
+                       unsigned int    rsize;          /* read size */
+                       unsigned int    wsize;          /* write size */
+                       unsigned int    acregmin;       /* attr cache timeouts */
+                       unsigned int    acregmax;
+                       unsigned int    acdirmin;
+                       unsigned int    acdirmax;
+               } nfs_server;
+
+               struct {
+                       rpc_authflavor_t au_flavor;
+               } rpc_auth;
+
+               /* uniquifier - can be used if nfs_server.flags includes
+                * NFS_MOUNT_UNSHARED  */
+               u8 uniq_len;
+               char uniquifier[0];
+       } key;
+};
+
 /*
  * fscache-index.c
  */
 extern struct fscache_netfs nfs_fscache_netfs;
 extern const struct fscache_cookie_def nfs_fscache_server_index_def;
+extern const struct fscache_cookie_def nfs_fscache_super_index_def;
 
 extern int nfs_fscache_register(void);
 extern void nfs_fscache_unregister(void);
 extern void nfs_fscache_get_client_cookie(struct nfs_client *);
 extern void nfs_fscache_release_client_cookie(struct nfs_client *);
 
+extern void nfs_fscache_get_super_cookie(struct super_block *,
+                                        struct nfs_parsed_mount_data *);
+extern void nfs_fscache_release_super_cookie(struct super_block *);
+
 #else /* CONFIG_NFS_FSCACHE */
 static inline int nfs_fscache_register(void) { return 0; }
 static inline void nfs_fscache_unregister(void) {}
 static inline void nfs_fscache_get_client_cookie(struct nfs_client *clp) {}
 static inline void nfs_fscache_release_client_cookie(struct nfs_client *clp) {}
 
+static inline void nfs_fscache_get_super_cookie(
+       struct super_block *sb,
+       struct nfs_parsed_mount_data *data)
+{
+}
+static inline void nfs_fscache_release_super_cookie(struct super_block *sb) {}
+
 #endif /* CONFIG_NFS_FSCACHE */
 #endif /* _NFS_FSCACHE_H */
 
 #include <linux/mount.h>
 #include <linux/security.h>
 
+#define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS)
+
 struct nfs_string;
 
 /* Maximum number of readahead requests
        unsigned int            auth_flavor_len;
        rpc_authflavor_t        auth_flavors[1];
        char                    *client_address;
+       char                    *fscache_uniq;
 
        struct {
                struct sockaddr_storage address;
 
 #include "delegation.h"
 #include "iostat.h"
 #include "internal.h"
+#include "fscache.h"
 
 #define NFSDBG_FACILITY                NFSDBG_VFS
 
        nfs_initialise_sb(sb);
 }
 
-#define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS)
-
 static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags)
 {
        const struct nfs_server *a = s->s_fs_info;
        if (!s->s_root) {
                /* initial superblock/root creation */
                nfs_fill_super(s, data);
+               nfs_fscache_get_super_cookie(s, data);
        }
 
        mntroot = nfs_get_root(s, mntfh);
 out:
        kfree(data->nfs_server.hostname);
        kfree(data->mount_server.hostname);
+       kfree(data->fscache_uniq);
        security_free_mnt_opts(&data->lsm_opts);
 out_free_fh:
        kfree(mntfh);
 
        bdi_unregister(&server->backing_dev_info);
        kill_anon_super(s);
+       nfs_fscache_release_super_cookie(s);
        nfs_free_server(server);
 }
 
        if (!s->s_root) {
                /* initial superblock/root creation */
                nfs4_fill_super(s);
+               nfs_fscache_get_super_cookie(s, data);
        }
 
        mntroot = nfs4_get_root(s, mntfh);
        kfree(data->client_address);
        kfree(data->nfs_server.export_path);
        kfree(data->nfs_server.hostname);
+       kfree(data->fscache_uniq);
        security_free_mnt_opts(&data->lsm_opts);
 out_free_fh:
        kfree(mntfh);
        kill_anon_super(sb);
 
        nfs4_renewd_prepare_shutdown(server);
+       nfs_fscache_release_super_cookie(sb);
        nfs_free_server(server);
 }
 
 
        unsigned long           mount_time;     /* when this fs was mounted */
        dev_t                   s_dev;          /* superblock dev numbers */
 
+#ifdef CONFIG_NFS_FSCACHE
+       struct nfs_fscache_key  *fscache_key;   /* unique key for superblock */
+       struct fscache_cookie   *fscache;       /* superblock cookie */
+#endif
+
 #ifdef CONFIG_NFS_V4
        u32                     attr_bitmask[2];/* V4 bitmask representing the set
                                                   of attributes supported on this