aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2009-04-03 11:42:42 -0400
committerDavid Howells <dhowells@redhat.com>2009-04-03 11:42:42 -0400
commit08734048b380103f0412f58b84c2f76a2c8b599f (patch)
tree34a65d40e33b12d36f5c82adb686bcdae6eab0fe
parent147272813e043fb44bd112527951da70c1e663de (diff)
NFS: Define and create superblock-level objects
Define and create superblock-level cache index objects (as managed by nfs_server structs). Each superblock object is created in a server level index object and is itself an index into which inode-level objects are inserted. Ideally there would be one superblock-level object per server, and the former would be folded into the latter; however, since the "nosharecache" option exists this isn't possible. The superblock object key is a sequence consisting of: (1) Certain superblock s_flags. (2) Various connection parameters that serve to distinguish superblocks for sget(). (3) The volume FSID. (4) The security flavour. (5) The uniquifier length. (6) The uniquifier text. This is normally an empty string, unless the fsc=xyz mount option was used to explicitly specify a uniquifier. The key blob is of variable length, depending on the length of (6). The superblock object is given no coherency data to carry in the auxiliary data permitted by the cache. It is assumed that the superblock is always coherent. This patch also adds uniquification handling such that two otherwise identical superblocks, at least one of which is marked "nosharecache", won't end up trying to share the on-disk cache. It will be possible to manually provide a uniquifier through a mount option with a later patch to avoid the error otherwise produced. Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: Steve Dickson <steved@redhat.com> Acked-by: Trond Myklebust <Trond.Myklebust@netapp.com> Acked-by: Al Viro <viro@zeniv.linux.org.uk> Tested-by: Daire Byrne <Daire.Byrne@framestore.com>
-rw-r--r--fs/nfs/fscache-index.c34
-rw-r--r--fs/nfs/fscache.c116
-rw-r--r--fs/nfs/fscache.h49
-rw-r--r--fs/nfs/internal.h3
-rw-r--r--fs/nfs/super.c9
-rw-r--r--include/linux/nfs_fs_sb.h5
6 files changed, 214 insertions, 2 deletions
diff --git a/fs/nfs/fscache-index.c b/fs/nfs/fscache-index.c
index ff14b032459b..a824050be807 100644
--- a/fs/nfs/fscache-index.c
+++ b/fs/nfs/fscache-index.c
@@ -112,3 +112,37 @@ const struct fscache_cookie_def nfs_fscache_server_index_def = {
112 .type = FSCACHE_COOKIE_TYPE_INDEX, 112 .type = FSCACHE_COOKIE_TYPE_INDEX,
113 .get_key = nfs_server_get_key, 113 .get_key = nfs_server_get_key,
114}; 114};
115
116/*
117 * Generate a key to describe a superblock key in the main NFS index
118 */
119static uint16_t nfs_super_get_key(const void *cookie_netfs_data,
120 void *buffer, uint16_t bufmax)
121{
122 const struct nfs_fscache_key *key;
123 const struct nfs_server *nfss = cookie_netfs_data;
124 uint16_t len;
125
126 key = nfss->fscache_key;
127 len = sizeof(key->key) + key->key.uniq_len;
128 if (len > bufmax) {
129 len = 0;
130 } else {
131 memcpy(buffer, &key->key, sizeof(key->key));
132 memcpy(buffer + sizeof(key->key),
133 key->key.uniquifier, key->key.uniq_len);
134 }
135
136 return len;
137}
138
139/*
140 * Define the superblock object for FS-Cache. This is used to describe a
141 * superblock object to fscache_acquire_cookie(). It is keyed by all the NFS
142 * parameters that might cause a separate superblock.
143 */
144const struct fscache_cookie_def nfs_fscache_super_index_def = {
145 .name = "NFS.super",
146 .type = FSCACHE_COOKIE_TYPE_INDEX,
147 .get_key = nfs_super_get_key,
148};
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c
index c3f056f89477..ab2de2c92b21 100644
--- a/fs/nfs/fscache.c
+++ b/fs/nfs/fscache.c
@@ -23,6 +23,9 @@
23 23
24#define NFSDBG_FACILITY NFSDBG_FSCACHE 24#define NFSDBG_FACILITY NFSDBG_FSCACHE
25 25
26static struct rb_root nfs_fscache_keys = RB_ROOT;
27static DEFINE_SPINLOCK(nfs_fscache_keys_lock);
28
26/* 29/*
27 * Get the per-client index cookie for an NFS client if the appropriate mount 30 * Get the per-client index cookie for an NFS client if the appropriate mount
28 * flag was set 31 * flag was set
@@ -50,3 +53,116 @@ void nfs_fscache_release_client_cookie(struct nfs_client *clp)
50 fscache_relinquish_cookie(clp->fscache, 0); 53 fscache_relinquish_cookie(clp->fscache, 0);
51 clp->fscache = NULL; 54 clp->fscache = NULL;
52} 55}
56
57/*
58 * Get the cache cookie for an NFS superblock. We have to handle
59 * uniquification here because the cache doesn't do it for us.
60 */
61void nfs_fscache_get_super_cookie(struct super_block *sb,
62 struct nfs_parsed_mount_data *data)
63{
64 struct nfs_fscache_key *key, *xkey;
65 struct nfs_server *nfss = NFS_SB(sb);
66 struct rb_node **p, *parent;
67 const char *uniq = data->fscache_uniq ?: "";
68 int diff, ulen;
69
70 ulen = strlen(uniq);
71 key = kzalloc(sizeof(*key) + ulen, GFP_KERNEL);
72 if (!key)
73 return;
74
75 key->nfs_client = nfss->nfs_client;
76 key->key.super.s_flags = sb->s_flags & NFS_MS_MASK;
77 key->key.nfs_server.flags = nfss->flags;
78 key->key.nfs_server.rsize = nfss->rsize;
79 key->key.nfs_server.wsize = nfss->wsize;
80 key->key.nfs_server.acregmin = nfss->acregmin;
81 key->key.nfs_server.acregmax = nfss->acregmax;
82 key->key.nfs_server.acdirmin = nfss->acdirmin;
83 key->key.nfs_server.acdirmax = nfss->acdirmax;
84 key->key.nfs_server.fsid = nfss->fsid;
85 key->key.rpc_auth.au_flavor = nfss->client->cl_auth->au_flavor;
86
87 key->key.uniq_len = ulen;
88 memcpy(key->key.uniquifier, uniq, ulen);
89
90 spin_lock(&nfs_fscache_keys_lock);
91 p = &nfs_fscache_keys.rb_node;
92 parent = NULL;
93 while (*p) {
94 parent = *p;
95 xkey = rb_entry(parent, struct nfs_fscache_key, node);
96
97 if (key->nfs_client < xkey->nfs_client)
98 goto go_left;
99 if (key->nfs_client > xkey->nfs_client)
100 goto go_right;
101
102 diff = memcmp(&key->key, &xkey->key, sizeof(key->key));
103 if (diff < 0)
104 goto go_left;
105 if (diff > 0)
106 goto go_right;
107
108 if (key->key.uniq_len == 0)
109 goto non_unique;
110 diff = memcmp(key->key.uniquifier,
111 xkey->key.uniquifier,
112 key->key.uniq_len);
113 if (diff < 0)
114 goto go_left;
115 if (diff > 0)
116 goto go_right;
117 goto non_unique;
118
119 go_left:
120 p = &(*p)->rb_left;
121 continue;
122 go_right:
123 p = &(*p)->rb_right;
124 }
125
126 rb_link_node(&key->node, parent, p);
127 rb_insert_color(&key->node, &nfs_fscache_keys);
128 spin_unlock(&nfs_fscache_keys_lock);
129 nfss->fscache_key = key;
130
131 /* create a cache index for looking up filehandles */
132 nfss->fscache = fscache_acquire_cookie(nfss->nfs_client->fscache,
133 &nfs_fscache_super_index_def,
134 nfss);
135 dfprintk(FSCACHE, "NFS: get superblock cookie (0x%p/0x%p)\n",
136 nfss, nfss->fscache);
137 return;
138
139non_unique:
140 spin_unlock(&nfs_fscache_keys_lock);
141 kfree(key);
142 nfss->fscache_key = NULL;
143 nfss->fscache = NULL;
144 printk(KERN_WARNING "NFS:"
145 " Cache request denied due to non-unique superblock keys\n");
146}
147
148/*
149 * release a per-superblock cookie
150 */
151void nfs_fscache_release_super_cookie(struct super_block *sb)
152{
153 struct nfs_server *nfss = NFS_SB(sb);
154
155 dfprintk(FSCACHE, "NFS: releasing superblock cookie (0x%p/0x%p)\n",
156 nfss, nfss->fscache);
157
158 fscache_relinquish_cookie(nfss->fscache, 0);
159 nfss->fscache = NULL;
160
161 if (nfss->fscache_key) {
162 spin_lock(&nfs_fscache_keys_lock);
163 rb_erase(&nfss->fscache_key->node, &nfs_fscache_keys);
164 spin_unlock(&nfs_fscache_keys_lock);
165 kfree(nfss->fscache_key);
166 nfss->fscache_key = NULL;
167 }
168}
diff --git a/fs/nfs/fscache.h b/fs/nfs/fscache.h
index 1d864bedf154..22b971e8b380 100644
--- a/fs/nfs/fscache.h
+++ b/fs/nfs/fscache.h
@@ -20,10 +20,48 @@
20#ifdef CONFIG_NFS_FSCACHE 20#ifdef CONFIG_NFS_FSCACHE
21 21
22/* 22/*
23 * set of NFS FS-Cache objects that form a superblock key
24 */
25struct nfs_fscache_key {
26 struct rb_node node;
27 struct nfs_client *nfs_client; /* the server */
28
29 /* the elements of the unique key - as used by nfs_compare_super() and
30 * nfs_compare_mount_options() to distinguish superblocks */
31 struct {
32 struct {
33 unsigned long s_flags; /* various flags
34 * (& NFS_MS_MASK) */
35 } super;
36
37 struct {
38 struct nfs_fsid fsid;
39 int flags;
40 unsigned int rsize; /* read size */
41 unsigned int wsize; /* write size */
42 unsigned int acregmin; /* attr cache timeouts */
43 unsigned int acregmax;
44 unsigned int acdirmin;
45 unsigned int acdirmax;
46 } nfs_server;
47
48 struct {
49 rpc_authflavor_t au_flavor;
50 } rpc_auth;
51
52 /* uniquifier - can be used if nfs_server.flags includes
53 * NFS_MOUNT_UNSHARED */
54 u8 uniq_len;
55 char uniquifier[0];
56 } key;
57};
58
59/*
23 * fscache-index.c 60 * fscache-index.c
24 */ 61 */
25extern struct fscache_netfs nfs_fscache_netfs; 62extern struct fscache_netfs nfs_fscache_netfs;
26extern const struct fscache_cookie_def nfs_fscache_server_index_def; 63extern const struct fscache_cookie_def nfs_fscache_server_index_def;
64extern const struct fscache_cookie_def nfs_fscache_super_index_def;
27 65
28extern int nfs_fscache_register(void); 66extern int nfs_fscache_register(void);
29extern void nfs_fscache_unregister(void); 67extern void nfs_fscache_unregister(void);
@@ -34,6 +72,10 @@ extern void nfs_fscache_unregister(void);
34extern void nfs_fscache_get_client_cookie(struct nfs_client *); 72extern void nfs_fscache_get_client_cookie(struct nfs_client *);
35extern void nfs_fscache_release_client_cookie(struct nfs_client *); 73extern void nfs_fscache_release_client_cookie(struct nfs_client *);
36 74
75extern void nfs_fscache_get_super_cookie(struct super_block *,
76 struct nfs_parsed_mount_data *);
77extern void nfs_fscache_release_super_cookie(struct super_block *);
78
37#else /* CONFIG_NFS_FSCACHE */ 79#else /* CONFIG_NFS_FSCACHE */
38static inline int nfs_fscache_register(void) { return 0; } 80static inline int nfs_fscache_register(void) { return 0; }
39static inline void nfs_fscache_unregister(void) {} 81static inline void nfs_fscache_unregister(void) {}
@@ -41,5 +83,12 @@ static inline void nfs_fscache_unregister(void) {}
41static inline void nfs_fscache_get_client_cookie(struct nfs_client *clp) {} 83static inline void nfs_fscache_get_client_cookie(struct nfs_client *clp) {}
42static inline void nfs_fscache_release_client_cookie(struct nfs_client *clp) {} 84static inline void nfs_fscache_release_client_cookie(struct nfs_client *clp) {}
43 85
86static inline void nfs_fscache_get_super_cookie(
87 struct super_block *sb,
88 struct nfs_parsed_mount_data *data)
89{
90}
91static inline void nfs_fscache_release_super_cookie(struct super_block *sb) {}
92
44#endif /* CONFIG_NFS_FSCACHE */ 93#endif /* CONFIG_NFS_FSCACHE */
45#endif /* _NFS_FSCACHE_H */ 94#endif /* _NFS_FSCACHE_H */
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 2041f68ff1cc..013070000c38 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -5,6 +5,8 @@
5#include <linux/mount.h> 5#include <linux/mount.h>
6#include <linux/security.h> 6#include <linux/security.h>
7 7
8#define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS)
9
8struct nfs_string; 10struct nfs_string;
9 11
10/* Maximum number of readahead requests 12/* Maximum number of readahead requests
@@ -41,6 +43,7 @@ struct nfs_parsed_mount_data {
41 unsigned int auth_flavor_len; 43 unsigned int auth_flavor_len;
42 rpc_authflavor_t auth_flavors[1]; 44 rpc_authflavor_t auth_flavors[1];
43 char *client_address; 45 char *client_address;
46 char *fscache_uniq;
44 47
45 struct { 48 struct {
46 struct sockaddr_storage address; 49 struct sockaddr_storage address;
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 0942fcbbad3c..87f65ae07f32 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -60,6 +60,7 @@
60#include "delegation.h" 60#include "delegation.h"
61#include "iostat.h" 61#include "iostat.h"
62#include "internal.h" 62#include "internal.h"
63#include "fscache.h"
63 64
64#define NFSDBG_FACILITY NFSDBG_VFS 65#define NFSDBG_FACILITY NFSDBG_VFS
65 66
@@ -1870,8 +1871,6 @@ static void nfs_clone_super(struct super_block *sb,
1870 nfs_initialise_sb(sb); 1871 nfs_initialise_sb(sb);
1871} 1872}
1872 1873
1873#define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS)
1874
1875static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags) 1874static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags)
1876{ 1875{
1877 const struct nfs_server *a = s->s_fs_info; 1876 const struct nfs_server *a = s->s_fs_info;
@@ -2036,6 +2035,7 @@ static int nfs_get_sb(struct file_system_type *fs_type,
2036 if (!s->s_root) { 2035 if (!s->s_root) {
2037 /* initial superblock/root creation */ 2036 /* initial superblock/root creation */
2038 nfs_fill_super(s, data); 2037 nfs_fill_super(s, data);
2038 nfs_fscache_get_super_cookie(s, data);
2039 } 2039 }
2040 2040
2041 mntroot = nfs_get_root(s, mntfh); 2041 mntroot = nfs_get_root(s, mntfh);
@@ -2056,6 +2056,7 @@ static int nfs_get_sb(struct file_system_type *fs_type,
2056out: 2056out:
2057 kfree(data->nfs_server.hostname); 2057 kfree(data->nfs_server.hostname);
2058 kfree(data->mount_server.hostname); 2058 kfree(data->mount_server.hostname);
2059 kfree(data->fscache_uniq);
2059 security_free_mnt_opts(&data->lsm_opts); 2060 security_free_mnt_opts(&data->lsm_opts);
2060out_free_fh: 2061out_free_fh:
2061 kfree(mntfh); 2062 kfree(mntfh);
@@ -2083,6 +2084,7 @@ static void nfs_kill_super(struct super_block *s)
2083 2084
2084 bdi_unregister(&server->backing_dev_info); 2085 bdi_unregister(&server->backing_dev_info);
2085 kill_anon_super(s); 2086 kill_anon_super(s);
2087 nfs_fscache_release_super_cookie(s);
2086 nfs_free_server(server); 2088 nfs_free_server(server);
2087} 2089}
2088 2090
@@ -2390,6 +2392,7 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
2390 if (!s->s_root) { 2392 if (!s->s_root) {
2391 /* initial superblock/root creation */ 2393 /* initial superblock/root creation */
2392 nfs4_fill_super(s); 2394 nfs4_fill_super(s);
2395 nfs_fscache_get_super_cookie(s, data);
2393 } 2396 }
2394 2397
2395 mntroot = nfs4_get_root(s, mntfh); 2398 mntroot = nfs4_get_root(s, mntfh);
@@ -2411,6 +2414,7 @@ out:
2411 kfree(data->client_address); 2414 kfree(data->client_address);
2412 kfree(data->nfs_server.export_path); 2415 kfree(data->nfs_server.export_path);
2413 kfree(data->nfs_server.hostname); 2416 kfree(data->nfs_server.hostname);
2417 kfree(data->fscache_uniq);
2414 security_free_mnt_opts(&data->lsm_opts); 2418 security_free_mnt_opts(&data->lsm_opts);
2415out_free_fh: 2419out_free_fh:
2416 kfree(mntfh); 2420 kfree(mntfh);
@@ -2437,6 +2441,7 @@ static void nfs4_kill_super(struct super_block *sb)
2437 kill_anon_super(sb); 2441 kill_anon_super(sb);
2438 2442
2439 nfs4_renewd_prepare_shutdown(server); 2443 nfs4_renewd_prepare_shutdown(server);
2444 nfs_fscache_release_super_cookie(sb);
2440 nfs_free_server(server); 2445 nfs_free_server(server);
2441} 2446}
2442 2447
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 0a374b9c5093..6ad75948cbf7 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -108,6 +108,11 @@ struct nfs_server {
108 unsigned long mount_time; /* when this fs was mounted */ 108 unsigned long mount_time; /* when this fs was mounted */
109 dev_t s_dev; /* superblock dev numbers */ 109 dev_t s_dev; /* superblock dev numbers */
110 110
111#ifdef CONFIG_NFS_FSCACHE
112 struct nfs_fscache_key *fscache_key; /* unique key for superblock */
113 struct fscache_cookie *fscache; /* superblock cookie */
114#endif
115
111#ifdef CONFIG_NFS_V4 116#ifdef CONFIG_NFS_V4
112 u32 attr_bitmask[2];/* V4 bitmask representing the set 117 u32 attr_bitmask[2];/* V4 bitmask representing the set
113 of attributes supported on this 118 of attributes supported on this