aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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