summaryrefslogtreecommitdiffstats
path: root/fs/nfs/fscache.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2018-04-04 08:41:28 -0400
committerDavid Howells <dhowells@redhat.com>2018-04-04 08:41:28 -0400
commit402cb8dda949d9b8c0df20ad2527d139faad7ca1 (patch)
tree83cdb77f5490a0990eade886aa7f8dd087864996 /fs/nfs/fscache.c
parent08c2e3d087840cd1e7141b62d92f3dc897147984 (diff)
fscache: Attach the index key and aux data to the cookie
Attach copies of the index key and auxiliary data to the fscache cookie so that: (1) The callbacks to the netfs for this stuff can be eliminated. This can simplify things in the cache as the information is still available, even after the cache has relinquished the cookie. (2) Simplifies the locking requirements of accessing the information as we don't have to worry about the netfs object going away on us. (3) The cache can do lazy updating of the coherency information on disk. As long as the cache is flushed before reboot/poweroff, there's no need to update the coherency info on disk every time it changes. (4) Cookies can be hashed or put in a tree as the index key is easily available. This allows: (a) Checks for duplicate cookies can be made at the top fscache layer rather than down in the bowels of the cache backend. (b) Caching can be added to a netfs object that has a cookie if the cache is brought online after the netfs object is allocated. A certain amount of space is made in the cookie for inline copies of the data, but if it won't fit there, extra memory will be allocated for it. The downside of this is that live cache operation requires more memory. Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: Anna Schumaker <anna.schumaker@netapp.com> Tested-by: Steve Dickson <steved@redhat.com>
Diffstat (limited to 'fs/nfs/fscache.c')
-rw-r--r--fs/nfs/fscache.c83
1 files changed, 78 insertions, 5 deletions
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c
index d63bea8bbfbb..c45ba2691cee 100644
--- a/fs/nfs/fscache.c
+++ b/fs/nfs/fscache.c
@@ -18,6 +18,7 @@
18#include <linux/in6.h> 18#include <linux/in6.h>
19#include <linux/seq_file.h> 19#include <linux/seq_file.h>
20#include <linux/slab.h> 20#include <linux/slab.h>
21#include <linux/iversion.h>
21 22
22#include "internal.h" 23#include "internal.h"
23#include "iostat.h" 24#include "iostat.h"
@@ -29,6 +30,21 @@ static struct rb_root nfs_fscache_keys = RB_ROOT;
29static DEFINE_SPINLOCK(nfs_fscache_keys_lock); 30static DEFINE_SPINLOCK(nfs_fscache_keys_lock);
30 31
31/* 32/*
33 * Layout of the key for an NFS server cache object.
34 */
35struct nfs_server_key {
36 struct {
37 uint16_t nfsversion; /* NFS protocol version */
38 uint16_t family; /* address family */
39 __be16 port; /* IP port */
40 } hdr;
41 union {
42 struct in_addr ipv4_addr; /* IPv4 address */
43 struct in6_addr ipv6_addr; /* IPv6 address */
44 };
45} __packed;
46
47/*
32 * Get the per-client index cookie for an NFS client if the appropriate mount 48 * Get the per-client index cookie for an NFS client if the appropriate mount
33 * flag was set 49 * flag was set
34 * - We always try and get an index cookie for the client, but get filehandle 50 * - We always try and get an index cookie for the client, but get filehandle
@@ -36,9 +52,40 @@ static DEFINE_SPINLOCK(nfs_fscache_keys_lock);
36 */ 52 */
37void nfs_fscache_get_client_cookie(struct nfs_client *clp) 53void nfs_fscache_get_client_cookie(struct nfs_client *clp)
38{ 54{
55 const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &clp->cl_addr;
56 const struct sockaddr_in *sin = (struct sockaddr_in *) &clp->cl_addr;
57 struct nfs_server_key key;
58 uint16_t len = sizeof(key.hdr);
59
60 memset(&key, 0, sizeof(key));
61 key.hdr.nfsversion = clp->rpc_ops->version;
62 key.hdr.family = clp->cl_addr.ss_family;
63
64 switch (clp->cl_addr.ss_family) {
65 case AF_INET:
66 key.hdr.port = sin->sin_port;
67 key.ipv4_addr = sin->sin_addr;
68 len += sizeof(key.ipv4_addr);
69 break;
70
71 case AF_INET6:
72 key.hdr.port = sin6->sin6_port;
73 key.ipv6_addr = sin6->sin6_addr;
74 len += sizeof(key.ipv6_addr);
75 break;
76
77 default:
78 printk(KERN_WARNING "NFS: Unknown network family '%d'\n",
79 clp->cl_addr.ss_family);
80 clp->fscache = NULL;
81 return;
82 }
83
39 /* create a cache index for looking up filehandles */ 84 /* create a cache index for looking up filehandles */
40 clp->fscache = fscache_acquire_cookie(nfs_fscache_netfs.primary_index, 85 clp->fscache = fscache_acquire_cookie(nfs_fscache_netfs.primary_index,
41 &nfs_fscache_server_index_def, 86 &nfs_fscache_server_index_def,
87 &key, len,
88 NULL, 0,
42 clp, true); 89 clp, true);
43 dfprintk(FSCACHE, "NFS: get client cookie (0x%p/0x%p)\n", 90 dfprintk(FSCACHE, "NFS: get client cookie (0x%p/0x%p)\n",
44 clp, clp->fscache); 91 clp, clp->fscache);
@@ -52,7 +99,7 @@ void nfs_fscache_release_client_cookie(struct nfs_client *clp)
52 dfprintk(FSCACHE, "NFS: releasing client cookie (0x%p/0x%p)\n", 99 dfprintk(FSCACHE, "NFS: releasing client cookie (0x%p/0x%p)\n",
53 clp, clp->fscache); 100 clp, clp->fscache);
54 101
55 fscache_relinquish_cookie(clp->fscache, 0); 102 fscache_relinquish_cookie(clp->fscache, NULL, false);
56 clp->fscache = NULL; 103 clp->fscache = NULL;
57} 104}
58 105
@@ -139,6 +186,8 @@ void nfs_fscache_get_super_cookie(struct super_block *sb, const char *uniq, int
139 /* create a cache index for looking up filehandles */ 186 /* create a cache index for looking up filehandles */
140 nfss->fscache = fscache_acquire_cookie(nfss->nfs_client->fscache, 187 nfss->fscache = fscache_acquire_cookie(nfss->nfs_client->fscache,
141 &nfs_fscache_super_index_def, 188 &nfs_fscache_super_index_def,
189 key, sizeof(*key) + ulen,
190 NULL, 0,
142 nfss, true); 191 nfss, true);
143 dfprintk(FSCACHE, "NFS: get superblock cookie (0x%p/0x%p)\n", 192 dfprintk(FSCACHE, "NFS: get superblock cookie (0x%p/0x%p)\n",
144 nfss, nfss->fscache); 193 nfss, nfss->fscache);
@@ -163,7 +212,7 @@ void nfs_fscache_release_super_cookie(struct super_block *sb)
163 dfprintk(FSCACHE, "NFS: releasing superblock cookie (0x%p/0x%p)\n", 212 dfprintk(FSCACHE, "NFS: releasing superblock cookie (0x%p/0x%p)\n",
164 nfss, nfss->fscache); 213 nfss, nfss->fscache);
165 214
166 fscache_relinquish_cookie(nfss->fscache, 0); 215 fscache_relinquish_cookie(nfss->fscache, NULL, false);
167 nfss->fscache = NULL; 216 nfss->fscache = NULL;
168 217
169 if (nfss->fscache_key) { 218 if (nfss->fscache_key) {
@@ -180,13 +229,25 @@ void nfs_fscache_release_super_cookie(struct super_block *sb)
180 */ 229 */
181void nfs_fscache_init_inode(struct inode *inode) 230void nfs_fscache_init_inode(struct inode *inode)
182{ 231{
232 struct nfs_fscache_inode_auxdata auxdata;
183 struct nfs_inode *nfsi = NFS_I(inode); 233 struct nfs_inode *nfsi = NFS_I(inode);
184 234
185 nfsi->fscache = NULL; 235 nfsi->fscache = NULL;
186 if (!S_ISREG(inode->i_mode)) 236 if (!S_ISREG(inode->i_mode))
187 return; 237 return;
238
239 memset(&auxdata, 0, sizeof(auxdata));
240 auxdata.size = nfsi->vfs_inode.i_size;
241 auxdata.mtime = nfsi->vfs_inode.i_mtime;
242 auxdata.ctime = nfsi->vfs_inode.i_ctime;
243
244 if (NFS_SERVER(&nfsi->vfs_inode)->nfs_client->rpc_ops->version == 4)
245 auxdata.change_attr = inode_peek_iversion_raw(&nfsi->vfs_inode);
246
188 nfsi->fscache = fscache_acquire_cookie(NFS_SB(inode->i_sb)->fscache, 247 nfsi->fscache = fscache_acquire_cookie(NFS_SB(inode->i_sb)->fscache,
189 &nfs_fscache_inode_object_def, 248 &nfs_fscache_inode_object_def,
249 nfsi->fh.data, nfsi->fh.size,
250 &auxdata, sizeof(auxdata),
190 nfsi, false); 251 nfsi, false);
191} 252}
192 253
@@ -195,12 +256,17 @@ void nfs_fscache_init_inode(struct inode *inode)
195 */ 256 */
196void nfs_fscache_clear_inode(struct inode *inode) 257void nfs_fscache_clear_inode(struct inode *inode)
197{ 258{
259 struct nfs_fscache_inode_auxdata auxdata;
198 struct nfs_inode *nfsi = NFS_I(inode); 260 struct nfs_inode *nfsi = NFS_I(inode);
199 struct fscache_cookie *cookie = nfs_i_fscache(inode); 261 struct fscache_cookie *cookie = nfs_i_fscache(inode);
200 262
201 dfprintk(FSCACHE, "NFS: clear cookie (0x%p/0x%p)\n", nfsi, cookie); 263 dfprintk(FSCACHE, "NFS: clear cookie (0x%p/0x%p)\n", nfsi, cookie);
202 264
203 fscache_relinquish_cookie(cookie, false); 265 memset(&auxdata, 0, sizeof(auxdata));
266 auxdata.size = nfsi->vfs_inode.i_size;
267 auxdata.mtime = nfsi->vfs_inode.i_mtime;
268 auxdata.ctime = nfsi->vfs_inode.i_ctime;
269 fscache_relinquish_cookie(cookie, &auxdata, false);
204 nfsi->fscache = NULL; 270 nfsi->fscache = NULL;
205} 271}
206 272
@@ -232,20 +298,27 @@ static bool nfs_fscache_can_enable(void *data)
232 */ 298 */
233void nfs_fscache_open_file(struct inode *inode, struct file *filp) 299void nfs_fscache_open_file(struct inode *inode, struct file *filp)
234{ 300{
301 struct nfs_fscache_inode_auxdata auxdata;
235 struct nfs_inode *nfsi = NFS_I(inode); 302 struct nfs_inode *nfsi = NFS_I(inode);
236 struct fscache_cookie *cookie = nfs_i_fscache(inode); 303 struct fscache_cookie *cookie = nfs_i_fscache(inode);
237 304
238 if (!fscache_cookie_valid(cookie)) 305 if (!fscache_cookie_valid(cookie))
239 return; 306 return;
240 307
308 memset(&auxdata, 0, sizeof(auxdata));
309 auxdata.size = nfsi->vfs_inode.i_size;
310 auxdata.mtime = nfsi->vfs_inode.i_mtime;
311 auxdata.ctime = nfsi->vfs_inode.i_ctime;
312
241 if (inode_is_open_for_write(inode)) { 313 if (inode_is_open_for_write(inode)) {
242 dfprintk(FSCACHE, "NFS: nfsi 0x%p disabling cache\n", nfsi); 314 dfprintk(FSCACHE, "NFS: nfsi 0x%p disabling cache\n", nfsi);
243 clear_bit(NFS_INO_FSCACHE, &nfsi->flags); 315 clear_bit(NFS_INO_FSCACHE, &nfsi->flags);
244 fscache_disable_cookie(cookie, true); 316 fscache_disable_cookie(cookie, &auxdata, true);
245 fscache_uncache_all_inode_pages(cookie, inode); 317 fscache_uncache_all_inode_pages(cookie, inode);
246 } else { 318 } else {
247 dfprintk(FSCACHE, "NFS: nfsi 0x%p enabling cache\n", nfsi); 319 dfprintk(FSCACHE, "NFS: nfsi 0x%p enabling cache\n", nfsi);
248 fscache_enable_cookie(cookie, nfs_fscache_can_enable, inode); 320 fscache_enable_cookie(cookie, &auxdata,
321 nfs_fscache_can_enable, inode);
249 if (fscache_cookie_enabled(cookie)) 322 if (fscache_cookie_enabled(cookie))
250 set_bit(NFS_INO_FSCACHE, &NFS_I(inode)->flags); 323 set_bit(NFS_INO_FSCACHE, &NFS_I(inode)->flags);
251 } 324 }