diff options
-rw-r--r-- | fs/nfs/fscache-index.c | 34 | ||||
-rw-r--r-- | fs/nfs/fscache.c | 116 | ||||
-rw-r--r-- | fs/nfs/fscache.h | 49 | ||||
-rw-r--r-- | fs/nfs/internal.h | 3 | ||||
-rw-r--r-- | fs/nfs/super.c | 9 | ||||
-rw-r--r-- | include/linux/nfs_fs_sb.h | 5 |
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 | */ | ||
119 | static 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 | */ | ||
144 | const 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 | ||
26 | static struct rb_root nfs_fscache_keys = RB_ROOT; | ||
27 | static 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 | */ | ||
61 | void 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 | |||
139 | non_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 | */ | ||
151 | void 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 | */ | ||
25 | struct 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 | */ |
25 | extern struct fscache_netfs nfs_fscache_netfs; | 62 | extern struct fscache_netfs nfs_fscache_netfs; |
26 | extern const struct fscache_cookie_def nfs_fscache_server_index_def; | 63 | extern const struct fscache_cookie_def nfs_fscache_server_index_def; |
64 | extern const struct fscache_cookie_def nfs_fscache_super_index_def; | ||
27 | 65 | ||
28 | extern int nfs_fscache_register(void); | 66 | extern int nfs_fscache_register(void); |
29 | extern void nfs_fscache_unregister(void); | 67 | extern void nfs_fscache_unregister(void); |
@@ -34,6 +72,10 @@ extern void nfs_fscache_unregister(void); | |||
34 | extern void nfs_fscache_get_client_cookie(struct nfs_client *); | 72 | extern void nfs_fscache_get_client_cookie(struct nfs_client *); |
35 | extern void nfs_fscache_release_client_cookie(struct nfs_client *); | 73 | extern void nfs_fscache_release_client_cookie(struct nfs_client *); |
36 | 74 | ||
75 | extern void nfs_fscache_get_super_cookie(struct super_block *, | ||
76 | struct nfs_parsed_mount_data *); | ||
77 | extern void nfs_fscache_release_super_cookie(struct super_block *); | ||
78 | |||
37 | #else /* CONFIG_NFS_FSCACHE */ | 79 | #else /* CONFIG_NFS_FSCACHE */ |
38 | static inline int nfs_fscache_register(void) { return 0; } | 80 | static inline int nfs_fscache_register(void) { return 0; } |
39 | static inline void nfs_fscache_unregister(void) {} | 81 | static inline void nfs_fscache_unregister(void) {} |
@@ -41,5 +83,12 @@ static inline void nfs_fscache_unregister(void) {} | |||
41 | static inline void nfs_fscache_get_client_cookie(struct nfs_client *clp) {} | 83 | static inline void nfs_fscache_get_client_cookie(struct nfs_client *clp) {} |
42 | static inline void nfs_fscache_release_client_cookie(struct nfs_client *clp) {} | 84 | static inline void nfs_fscache_release_client_cookie(struct nfs_client *clp) {} |
43 | 85 | ||
86 | static inline void nfs_fscache_get_super_cookie( | ||
87 | struct super_block *sb, | ||
88 | struct nfs_parsed_mount_data *data) | ||
89 | { | ||
90 | } | ||
91 | static 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 | |||
8 | struct nfs_string; | 10 | struct 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 | |||
1875 | static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags) | 1874 | static 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, | |||
2056 | out: | 2056 | out: |
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); |
2060 | out_free_fh: | 2061 | out_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); |
2415 | out_free_fh: | 2419 | out_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 |