diff options
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/Kconfig | 8 | ||||
-rw-r--r-- | fs/nfs/Makefile | 1 | ||||
-rw-r--r-- | fs/nfs/client.c | 14 | ||||
-rw-r--r-- | fs/nfs/file.c | 38 | ||||
-rw-r--r-- | fs/nfs/fscache-index.c | 337 | ||||
-rw-r--r-- | fs/nfs/fscache.c | 523 | ||||
-rw-r--r-- | fs/nfs/fscache.h | 220 | ||||
-rw-r--r-- | fs/nfs/inode.c | 14 | ||||
-rw-r--r-- | fs/nfs/internal.h | 4 | ||||
-rw-r--r-- | fs/nfs/iostat.h | 18 | ||||
-rw-r--r-- | fs/nfs/read.c | 27 | ||||
-rw-r--r-- | fs/nfs/super.c | 45 |
12 files changed, 1241 insertions, 8 deletions
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index 36fe20d6eba2..e67f3ec07736 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig | |||
@@ -84,3 +84,11 @@ config ROOT_NFS | |||
84 | <file:Documentation/filesystems/nfsroot.txt>. | 84 | <file:Documentation/filesystems/nfsroot.txt>. |
85 | 85 | ||
86 | Most people say N here. | 86 | Most people say N here. |
87 | |||
88 | config NFS_FSCACHE | ||
89 | bool "Provide NFS client caching support (EXPERIMENTAL)" | ||
90 | depends on EXPERIMENTAL | ||
91 | depends on NFS_FS=m && FSCACHE || NFS_FS=y && FSCACHE=y | ||
92 | help | ||
93 | Say Y here if you want NFS data to be cached locally on disc through | ||
94 | the general filesystem cache manager | ||
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index ac6170c594a3..845159814de2 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile | |||
@@ -15,3 +15,4 @@ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ | |||
15 | callback.o callback_xdr.o callback_proc.o \ | 15 | callback.o callback_xdr.o callback_proc.o \ |
16 | nfs4namespace.o | 16 | nfs4namespace.o |
17 | nfs-$(CONFIG_SYSCTL) += sysctl.o | 17 | nfs-$(CONFIG_SYSCTL) += sysctl.o |
18 | nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o | ||
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index aba38017bdef..75c9cd2aa119 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include "delegation.h" | 45 | #include "delegation.h" |
46 | #include "iostat.h" | 46 | #include "iostat.h" |
47 | #include "internal.h" | 47 | #include "internal.h" |
48 | #include "fscache.h" | ||
48 | 49 | ||
49 | #define NFSDBG_FACILITY NFSDBG_CLIENT | 50 | #define NFSDBG_FACILITY NFSDBG_CLIENT |
50 | 51 | ||
@@ -154,6 +155,8 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
154 | if (!IS_ERR(cred)) | 155 | if (!IS_ERR(cred)) |
155 | clp->cl_machine_cred = cred; | 156 | clp->cl_machine_cred = cred; |
156 | 157 | ||
158 | nfs_fscache_get_client_cookie(clp); | ||
159 | |||
157 | return clp; | 160 | return clp; |
158 | 161 | ||
159 | error_3: | 162 | error_3: |
@@ -187,6 +190,8 @@ static void nfs_free_client(struct nfs_client *clp) | |||
187 | 190 | ||
188 | nfs4_shutdown_client(clp); | 191 | nfs4_shutdown_client(clp); |
189 | 192 | ||
193 | nfs_fscache_release_client_cookie(clp); | ||
194 | |||
190 | /* -EIO all pending I/O */ | 195 | /* -EIO all pending I/O */ |
191 | if (!IS_ERR(clp->cl_rpcclient)) | 196 | if (!IS_ERR(clp->cl_rpcclient)) |
192 | rpc_shutdown_client(clp->cl_rpcclient); | 197 | rpc_shutdown_client(clp->cl_rpcclient); |
@@ -760,6 +765,7 @@ static int nfs_init_server(struct nfs_server *server, | |||
760 | 765 | ||
761 | /* Initialise the client representation from the mount data */ | 766 | /* Initialise the client representation from the mount data */ |
762 | server->flags = data->flags; | 767 | server->flags = data->flags; |
768 | server->options = data->options; | ||
763 | 769 | ||
764 | if (data->rsize) | 770 | if (data->rsize) |
765 | server->rsize = nfs_block_size(data->rsize, NULL); | 771 | server->rsize = nfs_block_size(data->rsize, NULL); |
@@ -1148,6 +1154,7 @@ static int nfs4_init_server(struct nfs_server *server, | |||
1148 | /* Initialise the client representation from the mount data */ | 1154 | /* Initialise the client representation from the mount data */ |
1149 | server->flags = data->flags; | 1155 | server->flags = data->flags; |
1150 | server->caps |= NFS_CAP_ATOMIC_OPEN; | 1156 | server->caps |= NFS_CAP_ATOMIC_OPEN; |
1157 | server->options = data->options; | ||
1151 | 1158 | ||
1152 | /* Get a client record */ | 1159 | /* Get a client record */ |
1153 | error = nfs4_set_client(server, | 1160 | error = nfs4_set_client(server, |
@@ -1559,7 +1566,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v) | |||
1559 | 1566 | ||
1560 | /* display header on line 1 */ | 1567 | /* display header on line 1 */ |
1561 | if (v == &nfs_volume_list) { | 1568 | if (v == &nfs_volume_list) { |
1562 | seq_puts(m, "NV SERVER PORT DEV FSID\n"); | 1569 | seq_puts(m, "NV SERVER PORT DEV FSID FSC\n"); |
1563 | return 0; | 1570 | return 0; |
1564 | } | 1571 | } |
1565 | /* display one transport per line on subsequent lines */ | 1572 | /* display one transport per line on subsequent lines */ |
@@ -1573,12 +1580,13 @@ static int nfs_volume_list_show(struct seq_file *m, void *v) | |||
1573 | (unsigned long long) server->fsid.major, | 1580 | (unsigned long long) server->fsid.major, |
1574 | (unsigned long long) server->fsid.minor); | 1581 | (unsigned long long) server->fsid.minor); |
1575 | 1582 | ||
1576 | seq_printf(m, "v%u %s %s %-7s %-17s\n", | 1583 | seq_printf(m, "v%u %s %s %-7s %-17s %s\n", |
1577 | clp->rpc_ops->version, | 1584 | clp->rpc_ops->version, |
1578 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), | 1585 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), |
1579 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT), | 1586 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT), |
1580 | dev, | 1587 | dev, |
1581 | fsid); | 1588 | fsid, |
1589 | nfs_server_fscache_state(server)); | ||
1582 | 1590 | ||
1583 | return 0; | 1591 | return 0; |
1584 | } | 1592 | } |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 0abf3f331f56..3523b895eb4b 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include "delegation.h" | 35 | #include "delegation.h" |
36 | #include "internal.h" | 36 | #include "internal.h" |
37 | #include "iostat.h" | 37 | #include "iostat.h" |
38 | #include "fscache.h" | ||
38 | 39 | ||
39 | #define NFSDBG_FACILITY NFSDBG_FILE | 40 | #define NFSDBG_FACILITY NFSDBG_FILE |
40 | 41 | ||
@@ -409,6 +410,13 @@ static int nfs_write_end(struct file *file, struct address_space *mapping, | |||
409 | return copied; | 410 | return copied; |
410 | } | 411 | } |
411 | 412 | ||
413 | /* | ||
414 | * Partially or wholly invalidate a page | ||
415 | * - Release the private state associated with a page if undergoing complete | ||
416 | * page invalidation | ||
417 | * - Called if either PG_private or PG_fscache is set on the page | ||
418 | * - Caller holds page lock | ||
419 | */ | ||
412 | static void nfs_invalidate_page(struct page *page, unsigned long offset) | 420 | static void nfs_invalidate_page(struct page *page, unsigned long offset) |
413 | { | 421 | { |
414 | dfprintk(PAGECACHE, "NFS: invalidate_page(%p, %lu)\n", page, offset); | 422 | dfprintk(PAGECACHE, "NFS: invalidate_page(%p, %lu)\n", page, offset); |
@@ -417,23 +425,43 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset) | |||
417 | return; | 425 | return; |
418 | /* Cancel any unstarted writes on this page */ | 426 | /* Cancel any unstarted writes on this page */ |
419 | nfs_wb_page_cancel(page->mapping->host, page); | 427 | nfs_wb_page_cancel(page->mapping->host, page); |
428 | |||
429 | nfs_fscache_invalidate_page(page, page->mapping->host); | ||
420 | } | 430 | } |
421 | 431 | ||
432 | /* | ||
433 | * Attempt to release the private state associated with a page | ||
434 | * - Called if either PG_private or PG_fscache is set on the page | ||
435 | * - Caller holds page lock | ||
436 | * - Return true (may release page) or false (may not) | ||
437 | */ | ||
422 | static int nfs_release_page(struct page *page, gfp_t gfp) | 438 | static int nfs_release_page(struct page *page, gfp_t gfp) |
423 | { | 439 | { |
424 | dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); | 440 | dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); |
425 | 441 | ||
426 | /* If PagePrivate() is set, then the page is not freeable */ | 442 | /* If PagePrivate() is set, then the page is not freeable */ |
427 | return 0; | 443 | if (PagePrivate(page)) |
444 | return 0; | ||
445 | return nfs_fscache_release_page(page, gfp); | ||
428 | } | 446 | } |
429 | 447 | ||
448 | /* | ||
449 | * Attempt to clear the private state associated with a page when an error | ||
450 | * occurs that requires the cached contents of an inode to be written back or | ||
451 | * destroyed | ||
452 | * - Called if either PG_private or fscache is set on the page | ||
453 | * - Caller holds page lock | ||
454 | * - Return 0 if successful, -error otherwise | ||
455 | */ | ||
430 | static int nfs_launder_page(struct page *page) | 456 | static int nfs_launder_page(struct page *page) |
431 | { | 457 | { |
432 | struct inode *inode = page->mapping->host; | 458 | struct inode *inode = page->mapping->host; |
459 | struct nfs_inode *nfsi = NFS_I(inode); | ||
433 | 460 | ||
434 | dfprintk(PAGECACHE, "NFS: launder_page(%ld, %llu)\n", | 461 | dfprintk(PAGECACHE, "NFS: launder_page(%ld, %llu)\n", |
435 | inode->i_ino, (long long)page_offset(page)); | 462 | inode->i_ino, (long long)page_offset(page)); |
436 | 463 | ||
464 | nfs_fscache_wait_on_page_write(nfsi, page); | ||
437 | return nfs_wb_page(inode, page); | 465 | return nfs_wb_page(inode, page); |
438 | } | 466 | } |
439 | 467 | ||
@@ -451,6 +479,11 @@ const struct address_space_operations nfs_file_aops = { | |||
451 | .launder_page = nfs_launder_page, | 479 | .launder_page = nfs_launder_page, |
452 | }; | 480 | }; |
453 | 481 | ||
482 | /* | ||
483 | * Notification that a PTE pointing to an NFS page is about to be made | ||
484 | * writable, implying that someone is about to modify the page through a | ||
485 | * shared-writable mapping | ||
486 | */ | ||
454 | static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | 487 | static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) |
455 | { | 488 | { |
456 | struct page *page = vmf->page; | 489 | struct page *page = vmf->page; |
@@ -465,6 +498,9 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
465 | filp->f_mapping->host->i_ino, | 498 | filp->f_mapping->host->i_ino, |
466 | (long long)page_offset(page)); | 499 | (long long)page_offset(page)); |
467 | 500 | ||
501 | /* make sure the cache has finished storing the page */ | ||
502 | nfs_fscache_wait_on_page_write(NFS_I(dentry->d_inode), page); | ||
503 | |||
468 | lock_page(page); | 504 | lock_page(page); |
469 | mapping = page->mapping; | 505 | mapping = page->mapping; |
470 | if (mapping != dentry->d_inode->i_mapping) | 506 | if (mapping != dentry->d_inode->i_mapping) |
diff --git a/fs/nfs/fscache-index.c b/fs/nfs/fscache-index.c new file mode 100644 index 000000000000..5b1006480bc2 --- /dev/null +++ b/fs/nfs/fscache-index.c | |||
@@ -0,0 +1,337 @@ | |||
1 | /* NFS FS-Cache index structure definition | ||
2 | * | ||
3 | * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/nfs_fs.h> | ||
17 | #include <linux/nfs_fs_sb.h> | ||
18 | #include <linux/in6.h> | ||
19 | |||
20 | #include "internal.h" | ||
21 | #include "fscache.h" | ||
22 | |||
23 | #define NFSDBG_FACILITY NFSDBG_FSCACHE | ||
24 | |||
25 | /* | ||
26 | * Define the NFS filesystem for FS-Cache. Upon registration FS-Cache sticks | ||
27 | * the cookie for the top-level index object for NFS into here. The top-level | ||
28 | * index can than have other cache objects inserted into it. | ||
29 | */ | ||
30 | struct fscache_netfs nfs_fscache_netfs = { | ||
31 | .name = "nfs", | ||
32 | .version = 0, | ||
33 | }; | ||
34 | |||
35 | /* | ||
36 | * Register NFS for caching | ||
37 | */ | ||
38 | int nfs_fscache_register(void) | ||
39 | { | ||
40 | return fscache_register_netfs(&nfs_fscache_netfs); | ||
41 | } | ||
42 | |||
43 | /* | ||
44 | * Unregister NFS for caching | ||
45 | */ | ||
46 | void nfs_fscache_unregister(void) | ||
47 | { | ||
48 | fscache_unregister_netfs(&nfs_fscache_netfs); | ||
49 | } | ||
50 | |||
51 | /* | ||
52 | * Layout of the key for an NFS server cache object. | ||
53 | */ | ||
54 | struct nfs_server_key { | ||
55 | uint16_t nfsversion; /* NFS protocol version */ | ||
56 | uint16_t family; /* address family */ | ||
57 | uint16_t port; /* IP port */ | ||
58 | union { | ||
59 | struct in_addr ipv4_addr; /* IPv4 address */ | ||
60 | struct in6_addr ipv6_addr; /* IPv6 address */ | ||
61 | } addr[0]; | ||
62 | }; | ||
63 | |||
64 | /* | ||
65 | * Generate a key to describe a server in the main NFS index | ||
66 | * - We return the length of the key, or 0 if we can't generate one | ||
67 | */ | ||
68 | static uint16_t nfs_server_get_key(const void *cookie_netfs_data, | ||
69 | void *buffer, uint16_t bufmax) | ||
70 | { | ||
71 | const struct nfs_client *clp = cookie_netfs_data; | ||
72 | const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &clp->cl_addr; | ||
73 | const struct sockaddr_in *sin = (struct sockaddr_in *) &clp->cl_addr; | ||
74 | struct nfs_server_key *key = buffer; | ||
75 | uint16_t len = sizeof(struct nfs_server_key); | ||
76 | |||
77 | key->nfsversion = clp->rpc_ops->version; | ||
78 | key->family = clp->cl_addr.ss_family; | ||
79 | |||
80 | memset(key, 0, len); | ||
81 | |||
82 | switch (clp->cl_addr.ss_family) { | ||
83 | case AF_INET: | ||
84 | key->port = sin->sin_port; | ||
85 | key->addr[0].ipv4_addr = sin->sin_addr; | ||
86 | len += sizeof(key->addr[0].ipv4_addr); | ||
87 | break; | ||
88 | |||
89 | case AF_INET6: | ||
90 | key->port = sin6->sin6_port; | ||
91 | key->addr[0].ipv6_addr = sin6->sin6_addr; | ||
92 | len += sizeof(key->addr[0].ipv6_addr); | ||
93 | break; | ||
94 | |||
95 | default: | ||
96 | printk(KERN_WARNING "NFS: Unknown network family '%d'\n", | ||
97 | clp->cl_addr.ss_family); | ||
98 | len = 0; | ||
99 | break; | ||
100 | } | ||
101 | |||
102 | return len; | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * Define the server object for FS-Cache. This is used to describe a server | ||
107 | * object to fscache_acquire_cookie(). It is keyed by the NFS protocol and | ||
108 | * server address parameters. | ||
109 | */ | ||
110 | const struct fscache_cookie_def nfs_fscache_server_index_def = { | ||
111 | .name = "NFS.server", | ||
112 | .type = FSCACHE_COOKIE_TYPE_INDEX, | ||
113 | .get_key = nfs_server_get_key, | ||
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 | }; | ||
149 | |||
150 | /* | ||
151 | * Definition of the auxiliary data attached to NFS inode storage objects | ||
152 | * within the cache. | ||
153 | * | ||
154 | * The contents of this struct are recorded in the on-disk local cache in the | ||
155 | * auxiliary data attached to the data storage object backing an inode. This | ||
156 | * permits coherency to be managed when a new inode binds to an already extant | ||
157 | * cache object. | ||
158 | */ | ||
159 | struct nfs_fscache_inode_auxdata { | ||
160 | struct timespec mtime; | ||
161 | struct timespec ctime; | ||
162 | loff_t size; | ||
163 | u64 change_attr; | ||
164 | }; | ||
165 | |||
166 | /* | ||
167 | * Generate a key to describe an NFS inode in an NFS server's index | ||
168 | */ | ||
169 | static uint16_t nfs_fscache_inode_get_key(const void *cookie_netfs_data, | ||
170 | void *buffer, uint16_t bufmax) | ||
171 | { | ||
172 | const struct nfs_inode *nfsi = cookie_netfs_data; | ||
173 | uint16_t nsize; | ||
174 | |||
175 | /* use the inode's NFS filehandle as the key */ | ||
176 | nsize = nfsi->fh.size; | ||
177 | memcpy(buffer, nfsi->fh.data, nsize); | ||
178 | return nsize; | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * Get certain file attributes from the netfs data | ||
183 | * - This function can be absent for an index | ||
184 | * - Not permitted to return an error | ||
185 | * - The netfs data from the cookie being used as the source is presented | ||
186 | */ | ||
187 | static void nfs_fscache_inode_get_attr(const void *cookie_netfs_data, | ||
188 | uint64_t *size) | ||
189 | { | ||
190 | const struct nfs_inode *nfsi = cookie_netfs_data; | ||
191 | |||
192 | *size = nfsi->vfs_inode.i_size; | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * Get the auxiliary data from netfs data | ||
197 | * - This function can be absent if the index carries no state data | ||
198 | * - Should store the auxiliary data in the buffer | ||
199 | * - Should return the amount of amount stored | ||
200 | * - Not permitted to return an error | ||
201 | * - The netfs data from the cookie being used as the source is presented | ||
202 | */ | ||
203 | static uint16_t nfs_fscache_inode_get_aux(const void *cookie_netfs_data, | ||
204 | void *buffer, uint16_t bufmax) | ||
205 | { | ||
206 | struct nfs_fscache_inode_auxdata auxdata; | ||
207 | const struct nfs_inode *nfsi = cookie_netfs_data; | ||
208 | |||
209 | memset(&auxdata, 0, sizeof(auxdata)); | ||
210 | auxdata.size = nfsi->vfs_inode.i_size; | ||
211 | auxdata.mtime = nfsi->vfs_inode.i_mtime; | ||
212 | auxdata.ctime = nfsi->vfs_inode.i_ctime; | ||
213 | |||
214 | if (NFS_SERVER(&nfsi->vfs_inode)->nfs_client->rpc_ops->version == 4) | ||
215 | auxdata.change_attr = nfsi->change_attr; | ||
216 | |||
217 | if (bufmax > sizeof(auxdata)) | ||
218 | bufmax = sizeof(auxdata); | ||
219 | |||
220 | memcpy(buffer, &auxdata, bufmax); | ||
221 | return bufmax; | ||
222 | } | ||
223 | |||
224 | /* | ||
225 | * Consult the netfs about the state of an object | ||
226 | * - This function can be absent if the index carries no state data | ||
227 | * - The netfs data from the cookie being used as the target is | ||
228 | * presented, as is the auxiliary data | ||
229 | */ | ||
230 | static | ||
231 | enum fscache_checkaux nfs_fscache_inode_check_aux(void *cookie_netfs_data, | ||
232 | const void *data, | ||
233 | uint16_t datalen) | ||
234 | { | ||
235 | struct nfs_fscache_inode_auxdata auxdata; | ||
236 | struct nfs_inode *nfsi = cookie_netfs_data; | ||
237 | |||
238 | if (datalen != sizeof(auxdata)) | ||
239 | return FSCACHE_CHECKAUX_OBSOLETE; | ||
240 | |||
241 | memset(&auxdata, 0, sizeof(auxdata)); | ||
242 | auxdata.size = nfsi->vfs_inode.i_size; | ||
243 | auxdata.mtime = nfsi->vfs_inode.i_mtime; | ||
244 | auxdata.ctime = nfsi->vfs_inode.i_ctime; | ||
245 | |||
246 | if (NFS_SERVER(&nfsi->vfs_inode)->nfs_client->rpc_ops->version == 4) | ||
247 | auxdata.change_attr = nfsi->change_attr; | ||
248 | |||
249 | if (memcmp(data, &auxdata, datalen) != 0) | ||
250 | return FSCACHE_CHECKAUX_OBSOLETE; | ||
251 | |||
252 | return FSCACHE_CHECKAUX_OKAY; | ||
253 | } | ||
254 | |||
255 | /* | ||
256 | * Indication from FS-Cache that the cookie is no longer cached | ||
257 | * - This function is called when the backing store currently caching a cookie | ||
258 | * is removed | ||
259 | * - The netfs should use this to clean up any markers indicating cached pages | ||
260 | * - This is mandatory for any object that may have data | ||
261 | */ | ||
262 | static void nfs_fscache_inode_now_uncached(void *cookie_netfs_data) | ||
263 | { | ||
264 | struct nfs_inode *nfsi = cookie_netfs_data; | ||
265 | struct pagevec pvec; | ||
266 | pgoff_t first; | ||
267 | int loop, nr_pages; | ||
268 | |||
269 | pagevec_init(&pvec, 0); | ||
270 | first = 0; | ||
271 | |||
272 | dprintk("NFS: nfs_inode_now_uncached: nfs_inode 0x%p\n", nfsi); | ||
273 | |||
274 | for (;;) { | ||
275 | /* grab a bunch of pages to unmark */ | ||
276 | nr_pages = pagevec_lookup(&pvec, | ||
277 | nfsi->vfs_inode.i_mapping, | ||
278 | first, | ||
279 | PAGEVEC_SIZE - pagevec_count(&pvec)); | ||
280 | if (!nr_pages) | ||
281 | break; | ||
282 | |||
283 | for (loop = 0; loop < nr_pages; loop++) | ||
284 | ClearPageFsCache(pvec.pages[loop]); | ||
285 | |||
286 | first = pvec.pages[nr_pages - 1]->index + 1; | ||
287 | |||
288 | pvec.nr = nr_pages; | ||
289 | pagevec_release(&pvec); | ||
290 | cond_resched(); | ||
291 | } | ||
292 | } | ||
293 | |||
294 | /* | ||
295 | * Get an extra reference on a read context. | ||
296 | * - This function can be absent if the completion function doesn't require a | ||
297 | * context. | ||
298 | * - The read context is passed back to NFS in the event that a data read on the | ||
299 | * cache fails with EIO - in which case the server must be contacted to | ||
300 | * retrieve the data, which requires the read context for security. | ||
301 | */ | ||
302 | static void nfs_fh_get_context(void *cookie_netfs_data, void *context) | ||
303 | { | ||
304 | get_nfs_open_context(context); | ||
305 | } | ||
306 | |||
307 | /* | ||
308 | * Release an extra reference on a read context. | ||
309 | * - This function can be absent if the completion function doesn't require a | ||
310 | * context. | ||
311 | */ | ||
312 | static void nfs_fh_put_context(void *cookie_netfs_data, void *context) | ||
313 | { | ||
314 | if (context) | ||
315 | put_nfs_open_context(context); | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * Define the inode object for FS-Cache. This is used to describe an inode | ||
320 | * object to fscache_acquire_cookie(). It is keyed by the NFS file handle for | ||
321 | * an inode. | ||
322 | * | ||
323 | * Coherency is managed by comparing the copies of i_size, i_mtime and i_ctime | ||
324 | * held in the cache auxiliary data for the data storage object with those in | ||
325 | * the inode struct in memory. | ||
326 | */ | ||
327 | const struct fscache_cookie_def nfs_fscache_inode_object_def = { | ||
328 | .name = "NFS.fh", | ||
329 | .type = FSCACHE_COOKIE_TYPE_DATAFILE, | ||
330 | .get_key = nfs_fscache_inode_get_key, | ||
331 | .get_attr = nfs_fscache_inode_get_attr, | ||
332 | .get_aux = nfs_fscache_inode_get_aux, | ||
333 | .check_aux = nfs_fscache_inode_check_aux, | ||
334 | .now_uncached = nfs_fscache_inode_now_uncached, | ||
335 | .get_context = nfs_fh_get_context, | ||
336 | .put_context = nfs_fh_put_context, | ||
337 | }; | ||
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c new file mode 100644 index 000000000000..379be678cb7e --- /dev/null +++ b/fs/nfs/fscache.c | |||
@@ -0,0 +1,523 @@ | |||
1 | /* NFS filesystem cache interface | ||
2 | * | ||
3 | * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/nfs_fs.h> | ||
17 | #include <linux/nfs_fs_sb.h> | ||
18 | #include <linux/in6.h> | ||
19 | #include <linux/seq_file.h> | ||
20 | |||
21 | #include "internal.h" | ||
22 | #include "iostat.h" | ||
23 | #include "fscache.h" | ||
24 | |||
25 | #define NFSDBG_FACILITY NFSDBG_FSCACHE | ||
26 | |||
27 | static struct rb_root nfs_fscache_keys = RB_ROOT; | ||
28 | static DEFINE_SPINLOCK(nfs_fscache_keys_lock); | ||
29 | |||
30 | /* | ||
31 | * Get the per-client index cookie for an NFS client if the appropriate mount | ||
32 | * flag was set | ||
33 | * - We always try and get an index cookie for the client, but get filehandle | ||
34 | * cookies on a per-superblock basis, depending on the mount flags | ||
35 | */ | ||
36 | void nfs_fscache_get_client_cookie(struct nfs_client *clp) | ||
37 | { | ||
38 | /* create a cache index for looking up filehandles */ | ||
39 | clp->fscache = fscache_acquire_cookie(nfs_fscache_netfs.primary_index, | ||
40 | &nfs_fscache_server_index_def, | ||
41 | clp); | ||
42 | dfprintk(FSCACHE, "NFS: get client cookie (0x%p/0x%p)\n", | ||
43 | clp, clp->fscache); | ||
44 | } | ||
45 | |||
46 | /* | ||
47 | * Dispose of a per-client cookie | ||
48 | */ | ||
49 | void nfs_fscache_release_client_cookie(struct nfs_client *clp) | ||
50 | { | ||
51 | dfprintk(FSCACHE, "NFS: releasing client cookie (0x%p/0x%p)\n", | ||
52 | clp, clp->fscache); | ||
53 | |||
54 | fscache_relinquish_cookie(clp->fscache, 0); | ||
55 | clp->fscache = NULL; | ||
56 | } | ||
57 | |||
58 | /* | ||
59 | * Get the cache cookie for an NFS superblock. We have to handle | ||
60 | * uniquification here because the cache doesn't do it for us. | ||
61 | */ | ||
62 | void nfs_fscache_get_super_cookie(struct super_block *sb, | ||
63 | struct nfs_parsed_mount_data *data) | ||
64 | { | ||
65 | struct nfs_fscache_key *key, *xkey; | ||
66 | struct nfs_server *nfss = NFS_SB(sb); | ||
67 | struct rb_node **p, *parent; | ||
68 | const char *uniq = data->fscache_uniq ?: ""; | ||
69 | int diff, ulen; | ||
70 | |||
71 | ulen = strlen(uniq); | ||
72 | key = kzalloc(sizeof(*key) + ulen, GFP_KERNEL); | ||
73 | if (!key) | ||
74 | return; | ||
75 | |||
76 | key->nfs_client = nfss->nfs_client; | ||
77 | key->key.super.s_flags = sb->s_flags & NFS_MS_MASK; | ||
78 | key->key.nfs_server.flags = nfss->flags; | ||
79 | key->key.nfs_server.rsize = nfss->rsize; | ||
80 | key->key.nfs_server.wsize = nfss->wsize; | ||
81 | key->key.nfs_server.acregmin = nfss->acregmin; | ||
82 | key->key.nfs_server.acregmax = nfss->acregmax; | ||
83 | key->key.nfs_server.acdirmin = nfss->acdirmin; | ||
84 | key->key.nfs_server.acdirmax = nfss->acdirmax; | ||
85 | key->key.nfs_server.fsid = nfss->fsid; | ||
86 | key->key.rpc_auth.au_flavor = nfss->client->cl_auth->au_flavor; | ||
87 | |||
88 | key->key.uniq_len = ulen; | ||
89 | memcpy(key->key.uniquifier, uniq, ulen); | ||
90 | |||
91 | spin_lock(&nfs_fscache_keys_lock); | ||
92 | p = &nfs_fscache_keys.rb_node; | ||
93 | parent = NULL; | ||
94 | while (*p) { | ||
95 | parent = *p; | ||
96 | xkey = rb_entry(parent, struct nfs_fscache_key, node); | ||
97 | |||
98 | if (key->nfs_client < xkey->nfs_client) | ||
99 | goto go_left; | ||
100 | if (key->nfs_client > xkey->nfs_client) | ||
101 | goto go_right; | ||
102 | |||
103 | diff = memcmp(&key->key, &xkey->key, sizeof(key->key)); | ||
104 | if (diff < 0) | ||
105 | goto go_left; | ||
106 | if (diff > 0) | ||
107 | goto go_right; | ||
108 | |||
109 | if (key->key.uniq_len == 0) | ||
110 | goto non_unique; | ||
111 | diff = memcmp(key->key.uniquifier, | ||
112 | xkey->key.uniquifier, | ||
113 | key->key.uniq_len); | ||
114 | if (diff < 0) | ||
115 | goto go_left; | ||
116 | if (diff > 0) | ||
117 | goto go_right; | ||
118 | goto non_unique; | ||
119 | |||
120 | go_left: | ||
121 | p = &(*p)->rb_left; | ||
122 | continue; | ||
123 | go_right: | ||
124 | p = &(*p)->rb_right; | ||
125 | } | ||
126 | |||
127 | rb_link_node(&key->node, parent, p); | ||
128 | rb_insert_color(&key->node, &nfs_fscache_keys); | ||
129 | spin_unlock(&nfs_fscache_keys_lock); | ||
130 | nfss->fscache_key = key; | ||
131 | |||
132 | /* create a cache index for looking up filehandles */ | ||
133 | nfss->fscache = fscache_acquire_cookie(nfss->nfs_client->fscache, | ||
134 | &nfs_fscache_super_index_def, | ||
135 | nfss); | ||
136 | dfprintk(FSCACHE, "NFS: get superblock cookie (0x%p/0x%p)\n", | ||
137 | nfss, nfss->fscache); | ||
138 | return; | ||
139 | |||
140 | non_unique: | ||
141 | spin_unlock(&nfs_fscache_keys_lock); | ||
142 | kfree(key); | ||
143 | nfss->fscache_key = NULL; | ||
144 | nfss->fscache = NULL; | ||
145 | printk(KERN_WARNING "NFS:" | ||
146 | " Cache request denied due to non-unique superblock keys\n"); | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | * release a per-superblock cookie | ||
151 | */ | ||
152 | void nfs_fscache_release_super_cookie(struct super_block *sb) | ||
153 | { | ||
154 | struct nfs_server *nfss = NFS_SB(sb); | ||
155 | |||
156 | dfprintk(FSCACHE, "NFS: releasing superblock cookie (0x%p/0x%p)\n", | ||
157 | nfss, nfss->fscache); | ||
158 | |||
159 | fscache_relinquish_cookie(nfss->fscache, 0); | ||
160 | nfss->fscache = NULL; | ||
161 | |||
162 | if (nfss->fscache_key) { | ||
163 | spin_lock(&nfs_fscache_keys_lock); | ||
164 | rb_erase(&nfss->fscache_key->node, &nfs_fscache_keys); | ||
165 | spin_unlock(&nfs_fscache_keys_lock); | ||
166 | kfree(nfss->fscache_key); | ||
167 | nfss->fscache_key = NULL; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | * Initialise the per-inode cache cookie pointer for an NFS inode. | ||
173 | */ | ||
174 | void nfs_fscache_init_inode_cookie(struct inode *inode) | ||
175 | { | ||
176 | NFS_I(inode)->fscache = NULL; | ||
177 | if (S_ISREG(inode->i_mode)) | ||
178 | set_bit(NFS_INO_FSCACHE, &NFS_I(inode)->flags); | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * Get the per-inode cache cookie for an NFS inode. | ||
183 | */ | ||
184 | static void nfs_fscache_enable_inode_cookie(struct inode *inode) | ||
185 | { | ||
186 | struct super_block *sb = inode->i_sb; | ||
187 | struct nfs_inode *nfsi = NFS_I(inode); | ||
188 | |||
189 | if (nfsi->fscache || !NFS_FSCACHE(inode)) | ||
190 | return; | ||
191 | |||
192 | if ((NFS_SB(sb)->options & NFS_OPTION_FSCACHE)) { | ||
193 | nfsi->fscache = fscache_acquire_cookie( | ||
194 | NFS_SB(sb)->fscache, | ||
195 | &nfs_fscache_inode_object_def, | ||
196 | nfsi); | ||
197 | |||
198 | dfprintk(FSCACHE, "NFS: get FH cookie (0x%p/0x%p/0x%p)\n", | ||
199 | sb, nfsi, nfsi->fscache); | ||
200 | } | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * Release a per-inode cookie. | ||
205 | */ | ||
206 | void nfs_fscache_release_inode_cookie(struct inode *inode) | ||
207 | { | ||
208 | struct nfs_inode *nfsi = NFS_I(inode); | ||
209 | |||
210 | dfprintk(FSCACHE, "NFS: clear cookie (0x%p/0x%p)\n", | ||
211 | nfsi, nfsi->fscache); | ||
212 | |||
213 | fscache_relinquish_cookie(nfsi->fscache, 0); | ||
214 | nfsi->fscache = NULL; | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * Retire a per-inode cookie, destroying the data attached to it. | ||
219 | */ | ||
220 | void nfs_fscache_zap_inode_cookie(struct inode *inode) | ||
221 | { | ||
222 | struct nfs_inode *nfsi = NFS_I(inode); | ||
223 | |||
224 | dfprintk(FSCACHE, "NFS: zapping cookie (0x%p/0x%p)\n", | ||
225 | nfsi, nfsi->fscache); | ||
226 | |||
227 | fscache_relinquish_cookie(nfsi->fscache, 1); | ||
228 | nfsi->fscache = NULL; | ||
229 | } | ||
230 | |||
231 | /* | ||
232 | * Turn off the cache with regard to a per-inode cookie if opened for writing, | ||
233 | * invalidating all the pages in the page cache relating to the associated | ||
234 | * inode to clear the per-page caching. | ||
235 | */ | ||
236 | static void nfs_fscache_disable_inode_cookie(struct inode *inode) | ||
237 | { | ||
238 | clear_bit(NFS_INO_FSCACHE, &NFS_I(inode)->flags); | ||
239 | |||
240 | if (NFS_I(inode)->fscache) { | ||
241 | dfprintk(FSCACHE, | ||
242 | "NFS: nfsi 0x%p turning cache off\n", NFS_I(inode)); | ||
243 | |||
244 | /* Need to invalidate any mapped pages that were read in before | ||
245 | * turning off the cache. | ||
246 | */ | ||
247 | if (inode->i_mapping && inode->i_mapping->nrpages) | ||
248 | invalidate_inode_pages2(inode->i_mapping); | ||
249 | |||
250 | nfs_fscache_zap_inode_cookie(inode); | ||
251 | } | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * wait_on_bit() sleep function for uninterruptible waiting | ||
256 | */ | ||
257 | static int nfs_fscache_wait_bit(void *flags) | ||
258 | { | ||
259 | schedule(); | ||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * Lock against someone else trying to also acquire or relinquish a cookie | ||
265 | */ | ||
266 | static inline void nfs_fscache_inode_lock(struct inode *inode) | ||
267 | { | ||
268 | struct nfs_inode *nfsi = NFS_I(inode); | ||
269 | |||
270 | while (test_and_set_bit(NFS_INO_FSCACHE_LOCK, &nfsi->flags)) | ||
271 | wait_on_bit(&nfsi->flags, NFS_INO_FSCACHE_LOCK, | ||
272 | nfs_fscache_wait_bit, TASK_UNINTERRUPTIBLE); | ||
273 | } | ||
274 | |||
275 | /* | ||
276 | * Unlock cookie management lock | ||
277 | */ | ||
278 | static inline void nfs_fscache_inode_unlock(struct inode *inode) | ||
279 | { | ||
280 | struct nfs_inode *nfsi = NFS_I(inode); | ||
281 | |||
282 | smp_mb__before_clear_bit(); | ||
283 | clear_bit(NFS_INO_FSCACHE_LOCK, &nfsi->flags); | ||
284 | smp_mb__after_clear_bit(); | ||
285 | wake_up_bit(&nfsi->flags, NFS_INO_FSCACHE_LOCK); | ||
286 | } | ||
287 | |||
288 | /* | ||
289 | * Decide if we should enable or disable local caching for this inode. | ||
290 | * - For now, with NFS, only regular files that are open read-only will be able | ||
291 | * to use the cache. | ||
292 | * - May be invoked multiple times in parallel by parallel nfs_open() functions. | ||
293 | */ | ||
294 | void nfs_fscache_set_inode_cookie(struct inode *inode, struct file *filp) | ||
295 | { | ||
296 | if (NFS_FSCACHE(inode)) { | ||
297 | nfs_fscache_inode_lock(inode); | ||
298 | if ((filp->f_flags & O_ACCMODE) != O_RDONLY) | ||
299 | nfs_fscache_disable_inode_cookie(inode); | ||
300 | else | ||
301 | nfs_fscache_enable_inode_cookie(inode); | ||
302 | nfs_fscache_inode_unlock(inode); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * Replace a per-inode cookie due to revalidation detecting a file having | ||
308 | * changed on the server. | ||
309 | */ | ||
310 | void nfs_fscache_reset_inode_cookie(struct inode *inode) | ||
311 | { | ||
312 | struct nfs_inode *nfsi = NFS_I(inode); | ||
313 | struct nfs_server *nfss = NFS_SERVER(inode); | ||
314 | struct fscache_cookie *old = nfsi->fscache; | ||
315 | |||
316 | nfs_fscache_inode_lock(inode); | ||
317 | if (nfsi->fscache) { | ||
318 | /* retire the current fscache cache and get a new one */ | ||
319 | fscache_relinquish_cookie(nfsi->fscache, 1); | ||
320 | |||
321 | nfsi->fscache = fscache_acquire_cookie( | ||
322 | nfss->nfs_client->fscache, | ||
323 | &nfs_fscache_inode_object_def, | ||
324 | nfsi); | ||
325 | |||
326 | dfprintk(FSCACHE, | ||
327 | "NFS: revalidation new cookie (0x%p/0x%p/0x%p/0x%p)\n", | ||
328 | nfss, nfsi, old, nfsi->fscache); | ||
329 | } | ||
330 | nfs_fscache_inode_unlock(inode); | ||
331 | } | ||
332 | |||
333 | /* | ||
334 | * Release the caching state associated with a page, if the page isn't busy | ||
335 | * interacting with the cache. | ||
336 | * - Returns true (can release page) or false (page busy). | ||
337 | */ | ||
338 | int nfs_fscache_release_page(struct page *page, gfp_t gfp) | ||
339 | { | ||
340 | struct nfs_inode *nfsi = NFS_I(page->mapping->host); | ||
341 | struct fscache_cookie *cookie = nfsi->fscache; | ||
342 | |||
343 | BUG_ON(!cookie); | ||
344 | |||
345 | if (fscache_check_page_write(cookie, page)) { | ||
346 | if (!(gfp & __GFP_WAIT)) | ||
347 | return 0; | ||
348 | fscache_wait_on_page_write(cookie, page); | ||
349 | } | ||
350 | |||
351 | if (PageFsCache(page)) { | ||
352 | dfprintk(FSCACHE, "NFS: fscache releasepage (0x%p/0x%p/0x%p)\n", | ||
353 | cookie, page, nfsi); | ||
354 | |||
355 | fscache_uncache_page(cookie, page); | ||
356 | nfs_add_fscache_stats(page->mapping->host, | ||
357 | NFSIOS_FSCACHE_PAGES_UNCACHED, 1); | ||
358 | } | ||
359 | |||
360 | return 1; | ||
361 | } | ||
362 | |||
363 | /* | ||
364 | * Release the caching state associated with a page if undergoing complete page | ||
365 | * invalidation. | ||
366 | */ | ||
367 | void __nfs_fscache_invalidate_page(struct page *page, struct inode *inode) | ||
368 | { | ||
369 | struct nfs_inode *nfsi = NFS_I(inode); | ||
370 | struct fscache_cookie *cookie = nfsi->fscache; | ||
371 | |||
372 | BUG_ON(!cookie); | ||
373 | |||
374 | dfprintk(FSCACHE, "NFS: fscache invalidatepage (0x%p/0x%p/0x%p)\n", | ||
375 | cookie, page, nfsi); | ||
376 | |||
377 | fscache_wait_on_page_write(cookie, page); | ||
378 | |||
379 | BUG_ON(!PageLocked(page)); | ||
380 | fscache_uncache_page(cookie, page); | ||
381 | nfs_add_fscache_stats(page->mapping->host, | ||
382 | NFSIOS_FSCACHE_PAGES_UNCACHED, 1); | ||
383 | } | ||
384 | |||
385 | /* | ||
386 | * Handle completion of a page being read from the cache. | ||
387 | * - Called in process (keventd) context. | ||
388 | */ | ||
389 | static void nfs_readpage_from_fscache_complete(struct page *page, | ||
390 | void *context, | ||
391 | int error) | ||
392 | { | ||
393 | dfprintk(FSCACHE, | ||
394 | "NFS: readpage_from_fscache_complete (0x%p/0x%p/%d)\n", | ||
395 | page, context, error); | ||
396 | |||
397 | /* if the read completes with an error, we just unlock the page and let | ||
398 | * the VM reissue the readpage */ | ||
399 | if (!error) { | ||
400 | SetPageUptodate(page); | ||
401 | unlock_page(page); | ||
402 | } else { | ||
403 | error = nfs_readpage_async(context, page->mapping->host, page); | ||
404 | if (error) | ||
405 | unlock_page(page); | ||
406 | } | ||
407 | } | ||
408 | |||
409 | /* | ||
410 | * Retrieve a page from fscache | ||
411 | */ | ||
412 | int __nfs_readpage_from_fscache(struct nfs_open_context *ctx, | ||
413 | struct inode *inode, struct page *page) | ||
414 | { | ||
415 | int ret; | ||
416 | |||
417 | dfprintk(FSCACHE, | ||
418 | "NFS: readpage_from_fscache(fsc:%p/p:%p(i:%lx f:%lx)/0x%p)\n", | ||
419 | NFS_I(inode)->fscache, page, page->index, page->flags, inode); | ||
420 | |||
421 | ret = fscache_read_or_alloc_page(NFS_I(inode)->fscache, | ||
422 | page, | ||
423 | nfs_readpage_from_fscache_complete, | ||
424 | ctx, | ||
425 | GFP_KERNEL); | ||
426 | |||
427 | switch (ret) { | ||
428 | case 0: /* read BIO submitted (page in fscache) */ | ||
429 | dfprintk(FSCACHE, | ||
430 | "NFS: readpage_from_fscache: BIO submitted\n"); | ||
431 | nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_OK, 1); | ||
432 | return ret; | ||
433 | |||
434 | case -ENOBUFS: /* inode not in cache */ | ||
435 | case -ENODATA: /* page not in cache */ | ||
436 | nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_FAIL, 1); | ||
437 | dfprintk(FSCACHE, | ||
438 | "NFS: readpage_from_fscache %d\n", ret); | ||
439 | return 1; | ||
440 | |||
441 | default: | ||
442 | dfprintk(FSCACHE, "NFS: readpage_from_fscache %d\n", ret); | ||
443 | nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_FAIL, 1); | ||
444 | } | ||
445 | return ret; | ||
446 | } | ||
447 | |||
448 | /* | ||
449 | * Retrieve a set of pages from fscache | ||
450 | */ | ||
451 | int __nfs_readpages_from_fscache(struct nfs_open_context *ctx, | ||
452 | struct inode *inode, | ||
453 | struct address_space *mapping, | ||
454 | struct list_head *pages, | ||
455 | unsigned *nr_pages) | ||
456 | { | ||
457 | int ret, npages = *nr_pages; | ||
458 | |||
459 | dfprintk(FSCACHE, "NFS: nfs_getpages_from_fscache (0x%p/%u/0x%p)\n", | ||
460 | NFS_I(inode)->fscache, npages, inode); | ||
461 | |||
462 | ret = fscache_read_or_alloc_pages(NFS_I(inode)->fscache, | ||
463 | mapping, pages, nr_pages, | ||
464 | nfs_readpage_from_fscache_complete, | ||
465 | ctx, | ||
466 | mapping_gfp_mask(mapping)); | ||
467 | if (*nr_pages < npages) | ||
468 | nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_OK, | ||
469 | npages); | ||
470 | if (*nr_pages > 0) | ||
471 | nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_FAIL, | ||
472 | *nr_pages); | ||
473 | |||
474 | switch (ret) { | ||
475 | case 0: /* read submitted to the cache for all pages */ | ||
476 | BUG_ON(!list_empty(pages)); | ||
477 | BUG_ON(*nr_pages != 0); | ||
478 | dfprintk(FSCACHE, | ||
479 | "NFS: nfs_getpages_from_fscache: submitted\n"); | ||
480 | |||
481 | return ret; | ||
482 | |||
483 | case -ENOBUFS: /* some pages aren't cached and can't be */ | ||
484 | case -ENODATA: /* some pages aren't cached */ | ||
485 | dfprintk(FSCACHE, | ||
486 | "NFS: nfs_getpages_from_fscache: no page: %d\n", ret); | ||
487 | return 1; | ||
488 | |||
489 | default: | ||
490 | dfprintk(FSCACHE, | ||
491 | "NFS: nfs_getpages_from_fscache: ret %d\n", ret); | ||
492 | } | ||
493 | |||
494 | return ret; | ||
495 | } | ||
496 | |||
497 | /* | ||
498 | * Store a newly fetched page in fscache | ||
499 | * - PG_fscache must be set on the page | ||
500 | */ | ||
501 | void __nfs_readpage_to_fscache(struct inode *inode, struct page *page, int sync) | ||
502 | { | ||
503 | int ret; | ||
504 | |||
505 | dfprintk(FSCACHE, | ||
506 | "NFS: readpage_to_fscache(fsc:%p/p:%p(i:%lx f:%lx)/%d)\n", | ||
507 | NFS_I(inode)->fscache, page, page->index, page->flags, sync); | ||
508 | |||
509 | ret = fscache_write_page(NFS_I(inode)->fscache, page, GFP_KERNEL); | ||
510 | dfprintk(FSCACHE, | ||
511 | "NFS: readpage_to_fscache: p:%p(i:%lu f:%lx) ret %d\n", | ||
512 | page, page->index, page->flags, ret); | ||
513 | |||
514 | if (ret != 0) { | ||
515 | fscache_uncache_page(NFS_I(inode)->fscache, page); | ||
516 | nfs_add_fscache_stats(inode, | ||
517 | NFSIOS_FSCACHE_PAGES_WRITTEN_FAIL, 1); | ||
518 | nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_UNCACHED, 1); | ||
519 | } else { | ||
520 | nfs_add_fscache_stats(inode, | ||
521 | NFSIOS_FSCACHE_PAGES_WRITTEN_OK, 1); | ||
522 | } | ||
523 | } | ||
diff --git a/fs/nfs/fscache.h b/fs/nfs/fscache.h new file mode 100644 index 000000000000..6e809bb0ff08 --- /dev/null +++ b/fs/nfs/fscache.h | |||
@@ -0,0 +1,220 @@ | |||
1 | /* NFS filesystem cache interface definitions | ||
2 | * | ||
3 | * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #ifndef _NFS_FSCACHE_H | ||
13 | #define _NFS_FSCACHE_H | ||
14 | |||
15 | #include <linux/nfs_fs.h> | ||
16 | #include <linux/nfs_mount.h> | ||
17 | #include <linux/nfs4_mount.h> | ||
18 | #include <linux/fscache.h> | ||
19 | |||
20 | #ifdef CONFIG_NFS_FSCACHE | ||
21 | |||
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 | /* | ||
60 | * fscache-index.c | ||
61 | */ | ||
62 | extern struct fscache_netfs nfs_fscache_netfs; | ||
63 | extern const struct fscache_cookie_def nfs_fscache_server_index_def; | ||
64 | extern const struct fscache_cookie_def nfs_fscache_super_index_def; | ||
65 | extern const struct fscache_cookie_def nfs_fscache_inode_object_def; | ||
66 | |||
67 | extern int nfs_fscache_register(void); | ||
68 | extern void nfs_fscache_unregister(void); | ||
69 | |||
70 | /* | ||
71 | * fscache.c | ||
72 | */ | ||
73 | extern void nfs_fscache_get_client_cookie(struct nfs_client *); | ||
74 | extern void nfs_fscache_release_client_cookie(struct nfs_client *); | ||
75 | |||
76 | extern void nfs_fscache_get_super_cookie(struct super_block *, | ||
77 | struct nfs_parsed_mount_data *); | ||
78 | extern void nfs_fscache_release_super_cookie(struct super_block *); | ||
79 | |||
80 | extern void nfs_fscache_init_inode_cookie(struct inode *); | ||
81 | extern void nfs_fscache_release_inode_cookie(struct inode *); | ||
82 | extern void nfs_fscache_zap_inode_cookie(struct inode *); | ||
83 | extern void nfs_fscache_set_inode_cookie(struct inode *, struct file *); | ||
84 | extern void nfs_fscache_reset_inode_cookie(struct inode *); | ||
85 | |||
86 | extern void __nfs_fscache_invalidate_page(struct page *, struct inode *); | ||
87 | extern int nfs_fscache_release_page(struct page *, gfp_t); | ||
88 | |||
89 | extern int __nfs_readpage_from_fscache(struct nfs_open_context *, | ||
90 | struct inode *, struct page *); | ||
91 | extern int __nfs_readpages_from_fscache(struct nfs_open_context *, | ||
92 | struct inode *, struct address_space *, | ||
93 | struct list_head *, unsigned *); | ||
94 | extern void __nfs_readpage_to_fscache(struct inode *, struct page *, int); | ||
95 | |||
96 | /* | ||
97 | * wait for a page to complete writing to the cache | ||
98 | */ | ||
99 | static inline void nfs_fscache_wait_on_page_write(struct nfs_inode *nfsi, | ||
100 | struct page *page) | ||
101 | { | ||
102 | if (PageFsCache(page)) | ||
103 | fscache_wait_on_page_write(nfsi->fscache, page); | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * release the caching state associated with a page if undergoing complete page | ||
108 | * invalidation | ||
109 | */ | ||
110 | static inline void nfs_fscache_invalidate_page(struct page *page, | ||
111 | struct inode *inode) | ||
112 | { | ||
113 | if (PageFsCache(page)) | ||
114 | __nfs_fscache_invalidate_page(page, inode); | ||
115 | } | ||
116 | |||
117 | /* | ||
118 | * Retrieve a page from an inode data storage object. | ||
119 | */ | ||
120 | static inline int nfs_readpage_from_fscache(struct nfs_open_context *ctx, | ||
121 | struct inode *inode, | ||
122 | struct page *page) | ||
123 | { | ||
124 | if (NFS_I(inode)->fscache) | ||
125 | return __nfs_readpage_from_fscache(ctx, inode, page); | ||
126 | return -ENOBUFS; | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * Retrieve a set of pages from an inode data storage object. | ||
131 | */ | ||
132 | static inline int nfs_readpages_from_fscache(struct nfs_open_context *ctx, | ||
133 | struct inode *inode, | ||
134 | struct address_space *mapping, | ||
135 | struct list_head *pages, | ||
136 | unsigned *nr_pages) | ||
137 | { | ||
138 | if (NFS_I(inode)->fscache) | ||
139 | return __nfs_readpages_from_fscache(ctx, inode, mapping, pages, | ||
140 | nr_pages); | ||
141 | return -ENOBUFS; | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * Store a page newly fetched from the server in an inode data storage object | ||
146 | * in the cache. | ||
147 | */ | ||
148 | static inline void nfs_readpage_to_fscache(struct inode *inode, | ||
149 | struct page *page, | ||
150 | int sync) | ||
151 | { | ||
152 | if (PageFsCache(page)) | ||
153 | __nfs_readpage_to_fscache(inode, page, sync); | ||
154 | } | ||
155 | |||
156 | /* | ||
157 | * indicate the client caching state as readable text | ||
158 | */ | ||
159 | static inline const char *nfs_server_fscache_state(struct nfs_server *server) | ||
160 | { | ||
161 | if (server->fscache && (server->options & NFS_OPTION_FSCACHE)) | ||
162 | return "yes"; | ||
163 | return "no "; | ||
164 | } | ||
165 | |||
166 | |||
167 | #else /* CONFIG_NFS_FSCACHE */ | ||
168 | static inline int nfs_fscache_register(void) { return 0; } | ||
169 | static inline void nfs_fscache_unregister(void) {} | ||
170 | |||
171 | static inline void nfs_fscache_get_client_cookie(struct nfs_client *clp) {} | ||
172 | static inline void nfs_fscache_release_client_cookie(struct nfs_client *clp) {} | ||
173 | |||
174 | static inline void nfs_fscache_get_super_cookie( | ||
175 | struct super_block *sb, | ||
176 | struct nfs_parsed_mount_data *data) | ||
177 | { | ||
178 | } | ||
179 | static inline void nfs_fscache_release_super_cookie(struct super_block *sb) {} | ||
180 | |||
181 | static inline void nfs_fscache_init_inode_cookie(struct inode *inode) {} | ||
182 | static inline void nfs_fscache_release_inode_cookie(struct inode *inode) {} | ||
183 | static inline void nfs_fscache_zap_inode_cookie(struct inode *inode) {} | ||
184 | static inline void nfs_fscache_set_inode_cookie(struct inode *inode, | ||
185 | struct file *filp) {} | ||
186 | static inline void nfs_fscache_reset_inode_cookie(struct inode *inode) {} | ||
187 | |||
188 | static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp) | ||
189 | { | ||
190 | return 1; /* True: may release page */ | ||
191 | } | ||
192 | static inline void nfs_fscache_invalidate_page(struct page *page, | ||
193 | struct inode *inode) {} | ||
194 | static inline void nfs_fscache_wait_on_page_write(struct nfs_inode *nfsi, | ||
195 | struct page *page) {} | ||
196 | |||
197 | static inline int nfs_readpage_from_fscache(struct nfs_open_context *ctx, | ||
198 | struct inode *inode, | ||
199 | struct page *page) | ||
200 | { | ||
201 | return -ENOBUFS; | ||
202 | } | ||
203 | static inline int nfs_readpages_from_fscache(struct nfs_open_context *ctx, | ||
204 | struct inode *inode, | ||
205 | struct address_space *mapping, | ||
206 | struct list_head *pages, | ||
207 | unsigned *nr_pages) | ||
208 | { | ||
209 | return -ENOBUFS; | ||
210 | } | ||
211 | static inline void nfs_readpage_to_fscache(struct inode *inode, | ||
212 | struct page *page, int sync) {} | ||
213 | |||
214 | static inline const char *nfs_server_fscache_state(struct nfs_server *server) | ||
215 | { | ||
216 | return "no "; | ||
217 | } | ||
218 | |||
219 | #endif /* CONFIG_NFS_FSCACHE */ | ||
220 | #endif /* _NFS_FSCACHE_H */ | ||
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index a834d1d850b7..64f87194d390 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include "delegation.h" | 46 | #include "delegation.h" |
47 | #include "iostat.h" | 47 | #include "iostat.h" |
48 | #include "internal.h" | 48 | #include "internal.h" |
49 | #include "fscache.h" | ||
49 | 50 | ||
50 | #define NFSDBG_FACILITY NFSDBG_VFS | 51 | #define NFSDBG_FACILITY NFSDBG_VFS |
51 | 52 | ||
@@ -121,6 +122,7 @@ void nfs_clear_inode(struct inode *inode) | |||
121 | BUG_ON(!list_empty(&NFS_I(inode)->open_files)); | 122 | BUG_ON(!list_empty(&NFS_I(inode)->open_files)); |
122 | nfs_zap_acl_cache(inode); | 123 | nfs_zap_acl_cache(inode); |
123 | nfs_access_zap_cache(inode); | 124 | nfs_access_zap_cache(inode); |
125 | nfs_fscache_release_inode_cookie(inode); | ||
124 | } | 126 | } |
125 | 127 | ||
126 | /** | 128 | /** |
@@ -355,6 +357,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
355 | nfsi->attrtimeo_timestamp = now; | 357 | nfsi->attrtimeo_timestamp = now; |
356 | nfsi->access_cache = RB_ROOT; | 358 | nfsi->access_cache = RB_ROOT; |
357 | 359 | ||
360 | nfs_fscache_init_inode_cookie(inode); | ||
361 | |||
358 | unlock_new_inode(inode); | 362 | unlock_new_inode(inode); |
359 | } else | 363 | } else |
360 | nfs_refresh_inode(inode, fattr); | 364 | nfs_refresh_inode(inode, fattr); |
@@ -686,6 +690,7 @@ int nfs_open(struct inode *inode, struct file *filp) | |||
686 | ctx->mode = filp->f_mode; | 690 | ctx->mode = filp->f_mode; |
687 | nfs_file_set_open_context(filp, ctx); | 691 | nfs_file_set_open_context(filp, ctx); |
688 | put_nfs_open_context(ctx); | 692 | put_nfs_open_context(ctx); |
693 | nfs_fscache_set_inode_cookie(inode, filp); | ||
689 | return 0; | 694 | return 0; |
690 | } | 695 | } |
691 | 696 | ||
@@ -786,6 +791,7 @@ static int nfs_invalidate_mapping_nolock(struct inode *inode, struct address_spa | |||
786 | memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); | 791 | memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); |
787 | spin_unlock(&inode->i_lock); | 792 | spin_unlock(&inode->i_lock); |
788 | nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); | 793 | nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); |
794 | nfs_fscache_reset_inode_cookie(inode); | ||
789 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", | 795 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", |
790 | inode->i_sb->s_id, (long long)NFS_FILEID(inode)); | 796 | inode->i_sb->s_id, (long long)NFS_FILEID(inode)); |
791 | return 0; | 797 | return 0; |
@@ -1030,6 +1036,7 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1030 | spin_lock(&inode->i_lock); | 1036 | spin_lock(&inode->i_lock); |
1031 | status = nfs_refresh_inode_locked(inode, fattr); | 1037 | status = nfs_refresh_inode_locked(inode, fattr); |
1032 | spin_unlock(&inode->i_lock); | 1038 | spin_unlock(&inode->i_lock); |
1039 | |||
1033 | return status; | 1040 | return status; |
1034 | } | 1041 | } |
1035 | 1042 | ||
@@ -1436,6 +1443,10 @@ static int __init init_nfs_fs(void) | |||
1436 | { | 1443 | { |
1437 | int err; | 1444 | int err; |
1438 | 1445 | ||
1446 | err = nfs_fscache_register(); | ||
1447 | if (err < 0) | ||
1448 | goto out7; | ||
1449 | |||
1439 | err = nfsiod_start(); | 1450 | err = nfsiod_start(); |
1440 | if (err) | 1451 | if (err) |
1441 | goto out6; | 1452 | goto out6; |
@@ -1488,6 +1499,8 @@ out4: | |||
1488 | out5: | 1499 | out5: |
1489 | nfsiod_stop(); | 1500 | nfsiod_stop(); |
1490 | out6: | 1501 | out6: |
1502 | nfs_fscache_unregister(); | ||
1503 | out7: | ||
1491 | return err; | 1504 | return err; |
1492 | } | 1505 | } |
1493 | 1506 | ||
@@ -1498,6 +1511,7 @@ static void __exit exit_nfs_fs(void) | |||
1498 | nfs_destroy_readpagecache(); | 1511 | nfs_destroy_readpagecache(); |
1499 | nfs_destroy_inodecache(); | 1512 | nfs_destroy_inodecache(); |
1500 | nfs_destroy_nfspagecache(); | 1513 | nfs_destroy_nfspagecache(); |
1514 | nfs_fscache_unregister(); | ||
1501 | #ifdef CONFIG_PROC_FS | 1515 | #ifdef CONFIG_PROC_FS |
1502 | rpc_proc_unregister("nfs"); | 1516 | rpc_proc_unregister("nfs"); |
1503 | #endif | 1517 | #endif |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 2041f68ff1cc..e4d6a8348adf 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 |
@@ -37,10 +39,12 @@ struct nfs_parsed_mount_data { | |||
37 | int acregmin, acregmax, | 39 | int acregmin, acregmax, |
38 | acdirmin, acdirmax; | 40 | acdirmin, acdirmax; |
39 | int namlen; | 41 | int namlen; |
42 | unsigned int options; | ||
40 | unsigned int bsize; | 43 | unsigned int bsize; |
41 | unsigned int auth_flavor_len; | 44 | unsigned int auth_flavor_len; |
42 | rpc_authflavor_t auth_flavors[1]; | 45 | rpc_authflavor_t auth_flavors[1]; |
43 | char *client_address; | 46 | char *client_address; |
47 | char *fscache_uniq; | ||
44 | 48 | ||
45 | struct { | 49 | struct { |
46 | struct sockaddr_storage address; | 50 | struct sockaddr_storage address; |
diff --git a/fs/nfs/iostat.h b/fs/nfs/iostat.h index a36952810032..a2ab2529b5ca 100644 --- a/fs/nfs/iostat.h +++ b/fs/nfs/iostat.h | |||
@@ -16,6 +16,9 @@ | |||
16 | 16 | ||
17 | struct nfs_iostats { | 17 | struct nfs_iostats { |
18 | unsigned long long bytes[__NFSIOS_BYTESMAX]; | 18 | unsigned long long bytes[__NFSIOS_BYTESMAX]; |
19 | #ifdef CONFIG_NFS_FSCACHE | ||
20 | unsigned long long fscache[__NFSIOS_FSCACHEMAX]; | ||
21 | #endif | ||
19 | unsigned long events[__NFSIOS_COUNTSMAX]; | 22 | unsigned long events[__NFSIOS_COUNTSMAX]; |
20 | } ____cacheline_aligned; | 23 | } ____cacheline_aligned; |
21 | 24 | ||
@@ -57,6 +60,21 @@ static inline void nfs_add_stats(const struct inode *inode, | |||
57 | nfs_add_server_stats(NFS_SERVER(inode), stat, addend); | 60 | nfs_add_server_stats(NFS_SERVER(inode), stat, addend); |
58 | } | 61 | } |
59 | 62 | ||
63 | #ifdef CONFIG_NFS_FSCACHE | ||
64 | static inline void nfs_add_fscache_stats(struct inode *inode, | ||
65 | enum nfs_stat_fscachecounters stat, | ||
66 | unsigned long addend) | ||
67 | { | ||
68 | struct nfs_iostats *iostats; | ||
69 | int cpu; | ||
70 | |||
71 | cpu = get_cpu(); | ||
72 | iostats = per_cpu_ptr(NFS_SERVER(inode)->io_stats, cpu); | ||
73 | iostats->fscache[stat] += addend; | ||
74 | put_cpu_no_resched(); | ||
75 | } | ||
76 | #endif | ||
77 | |||
60 | static inline struct nfs_iostats *nfs_alloc_iostats(void) | 78 | static inline struct nfs_iostats *nfs_alloc_iostats(void) |
61 | { | 79 | { |
62 | return alloc_percpu(struct nfs_iostats); | 80 | return alloc_percpu(struct nfs_iostats); |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index f856004bb7fa..4ace3c50a8eb 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -24,6 +24,7 @@ | |||
24 | 24 | ||
25 | #include "internal.h" | 25 | #include "internal.h" |
26 | #include "iostat.h" | 26 | #include "iostat.h" |
27 | #include "fscache.h" | ||
27 | 28 | ||
28 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 29 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
29 | 30 | ||
@@ -111,8 +112,8 @@ static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data) | |||
111 | } | 112 | } |
112 | } | 113 | } |
113 | 114 | ||
114 | static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, | 115 | int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, |
115 | struct page *page) | 116 | struct page *page) |
116 | { | 117 | { |
117 | LIST_HEAD(one_request); | 118 | LIST_HEAD(one_request); |
118 | struct nfs_page *new; | 119 | struct nfs_page *new; |
@@ -139,6 +140,11 @@ static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, | |||
139 | 140 | ||
140 | static void nfs_readpage_release(struct nfs_page *req) | 141 | static void nfs_readpage_release(struct nfs_page *req) |
141 | { | 142 | { |
143 | struct inode *d_inode = req->wb_context->path.dentry->d_inode; | ||
144 | |||
145 | if (PageUptodate(req->wb_page)) | ||
146 | nfs_readpage_to_fscache(d_inode, req->wb_page, 0); | ||
147 | |||
142 | unlock_page(req->wb_page); | 148 | unlock_page(req->wb_page); |
143 | 149 | ||
144 | dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", | 150 | dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", |
@@ -510,8 +516,15 @@ int nfs_readpage(struct file *file, struct page *page) | |||
510 | } else | 516 | } else |
511 | ctx = get_nfs_open_context(nfs_file_open_context(file)); | 517 | ctx = get_nfs_open_context(nfs_file_open_context(file)); |
512 | 518 | ||
519 | if (!IS_SYNC(inode)) { | ||
520 | error = nfs_readpage_from_fscache(ctx, inode, page); | ||
521 | if (error == 0) | ||
522 | goto out; | ||
523 | } | ||
524 | |||
513 | error = nfs_readpage_async(ctx, inode, page); | 525 | error = nfs_readpage_async(ctx, inode, page); |
514 | 526 | ||
527 | out: | ||
515 | put_nfs_open_context(ctx); | 528 | put_nfs_open_context(ctx); |
516 | return error; | 529 | return error; |
517 | out_unlock: | 530 | out_unlock: |
@@ -584,6 +597,15 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, | |||
584 | return -EBADF; | 597 | return -EBADF; |
585 | } else | 598 | } else |
586 | desc.ctx = get_nfs_open_context(nfs_file_open_context(filp)); | 599 | desc.ctx = get_nfs_open_context(nfs_file_open_context(filp)); |
600 | |||
601 | /* attempt to read as many of the pages as possible from the cache | ||
602 | * - this returns -ENOBUFS immediately if the cookie is negative | ||
603 | */ | ||
604 | ret = nfs_readpages_from_fscache(desc.ctx, inode, mapping, | ||
605 | pages, &nr_pages); | ||
606 | if (ret == 0) | ||
607 | goto read_complete; /* all pages were read */ | ||
608 | |||
587 | if (rsize < PAGE_CACHE_SIZE) | 609 | if (rsize < PAGE_CACHE_SIZE) |
588 | nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0); | 610 | nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0); |
589 | else | 611 | else |
@@ -594,6 +616,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, | |||
594 | nfs_pageio_complete(&pgio); | 616 | nfs_pageio_complete(&pgio); |
595 | npages = (pgio.pg_bytes_written + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 617 | npages = (pgio.pg_bytes_written + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
596 | nfs_add_stats(inode, NFSIOS_READPAGES, npages); | 618 | nfs_add_stats(inode, NFSIOS_READPAGES, npages); |
619 | read_complete: | ||
597 | put_nfs_open_context(desc.ctx); | 620 | put_nfs_open_context(desc.ctx); |
598 | out: | 621 | out: |
599 | return ret; | 622 | return ret; |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 0942fcbbad3c..82eaadbff408 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 | ||
@@ -76,6 +77,7 @@ enum { | |||
76 | Opt_rdirplus, Opt_nordirplus, | 77 | Opt_rdirplus, Opt_nordirplus, |
77 | Opt_sharecache, Opt_nosharecache, | 78 | Opt_sharecache, Opt_nosharecache, |
78 | Opt_resvport, Opt_noresvport, | 79 | Opt_resvport, Opt_noresvport, |
80 | Opt_fscache, Opt_nofscache, | ||
79 | 81 | ||
80 | /* Mount options that take integer arguments */ | 82 | /* Mount options that take integer arguments */ |
81 | Opt_port, | 83 | Opt_port, |
@@ -93,6 +95,7 @@ enum { | |||
93 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, | 95 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, |
94 | Opt_addr, Opt_mountaddr, Opt_clientaddr, | 96 | Opt_addr, Opt_mountaddr, Opt_clientaddr, |
95 | Opt_lookupcache, | 97 | Opt_lookupcache, |
98 | Opt_fscache_uniq, | ||
96 | 99 | ||
97 | /* Special mount options */ | 100 | /* Special mount options */ |
98 | Opt_userspace, Opt_deprecated, Opt_sloppy, | 101 | Opt_userspace, Opt_deprecated, Opt_sloppy, |
@@ -132,6 +135,9 @@ static const match_table_t nfs_mount_option_tokens = { | |||
132 | { Opt_nosharecache, "nosharecache" }, | 135 | { Opt_nosharecache, "nosharecache" }, |
133 | { Opt_resvport, "resvport" }, | 136 | { Opt_resvport, "resvport" }, |
134 | { Opt_noresvport, "noresvport" }, | 137 | { Opt_noresvport, "noresvport" }, |
138 | { Opt_fscache, "fsc" }, | ||
139 | { Opt_fscache_uniq, "fsc=%s" }, | ||
140 | { Opt_nofscache, "nofsc" }, | ||
135 | 141 | ||
136 | { Opt_port, "port=%u" }, | 142 | { Opt_port, "port=%u" }, |
137 | { Opt_rsize, "rsize=%u" }, | 143 | { Opt_rsize, "rsize=%u" }, |
@@ -563,6 +569,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
563 | if (clp->rpc_ops->version == 4) | 569 | if (clp->rpc_ops->version == 4) |
564 | seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr); | 570 | seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr); |
565 | #endif | 571 | #endif |
572 | if (nfss->options & NFS_OPTION_FSCACHE) | ||
573 | seq_printf(m, ",fsc"); | ||
566 | } | 574 | } |
567 | 575 | ||
568 | /* | 576 | /* |
@@ -641,6 +649,10 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) | |||
641 | totals.events[i] += stats->events[i]; | 649 | totals.events[i] += stats->events[i]; |
642 | for (i = 0; i < __NFSIOS_BYTESMAX; i++) | 650 | for (i = 0; i < __NFSIOS_BYTESMAX; i++) |
643 | totals.bytes[i] += stats->bytes[i]; | 651 | totals.bytes[i] += stats->bytes[i]; |
652 | #ifdef CONFIG_NFS_FSCACHE | ||
653 | for (i = 0; i < __NFSIOS_FSCACHEMAX; i++) | ||
654 | totals.fscache[i] += stats->fscache[i]; | ||
655 | #endif | ||
644 | 656 | ||
645 | preempt_enable(); | 657 | preempt_enable(); |
646 | } | 658 | } |
@@ -651,6 +663,13 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) | |||
651 | seq_printf(m, "\n\tbytes:\t"); | 663 | seq_printf(m, "\n\tbytes:\t"); |
652 | for (i = 0; i < __NFSIOS_BYTESMAX; i++) | 664 | for (i = 0; i < __NFSIOS_BYTESMAX; i++) |
653 | seq_printf(m, "%Lu ", totals.bytes[i]); | 665 | seq_printf(m, "%Lu ", totals.bytes[i]); |
666 | #ifdef CONFIG_NFS_FSCACHE | ||
667 | if (nfss->options & NFS_OPTION_FSCACHE) { | ||
668 | seq_printf(m, "\n\tfsc:\t"); | ||
669 | for (i = 0; i < __NFSIOS_FSCACHEMAX; i++) | ||
670 | seq_printf(m, "%Lu ", totals.bytes[i]); | ||
671 | } | ||
672 | #endif | ||
654 | seq_printf(m, "\n"); | 673 | seq_printf(m, "\n"); |
655 | 674 | ||
656 | rpc_print_iostats(m, nfss->client); | 675 | rpc_print_iostats(m, nfss->client); |
@@ -1044,6 +1063,24 @@ static int nfs_parse_mount_options(char *raw, | |||
1044 | case Opt_noresvport: | 1063 | case Opt_noresvport: |
1045 | mnt->flags |= NFS_MOUNT_NORESVPORT; | 1064 | mnt->flags |= NFS_MOUNT_NORESVPORT; |
1046 | break; | 1065 | break; |
1066 | case Opt_fscache: | ||
1067 | mnt->options |= NFS_OPTION_FSCACHE; | ||
1068 | kfree(mnt->fscache_uniq); | ||
1069 | mnt->fscache_uniq = NULL; | ||
1070 | break; | ||
1071 | case Opt_nofscache: | ||
1072 | mnt->options &= ~NFS_OPTION_FSCACHE; | ||
1073 | kfree(mnt->fscache_uniq); | ||
1074 | mnt->fscache_uniq = NULL; | ||
1075 | break; | ||
1076 | case Opt_fscache_uniq: | ||
1077 | string = match_strdup(args); | ||
1078 | if (!string) | ||
1079 | goto out_nomem; | ||
1080 | kfree(mnt->fscache_uniq); | ||
1081 | mnt->fscache_uniq = string; | ||
1082 | mnt->options |= NFS_OPTION_FSCACHE; | ||
1083 | break; | ||
1047 | 1084 | ||
1048 | /* | 1085 | /* |
1049 | * options that take numeric values | 1086 | * options that take numeric values |
@@ -1870,8 +1907,6 @@ static void nfs_clone_super(struct super_block *sb, | |||
1870 | nfs_initialise_sb(sb); | 1907 | nfs_initialise_sb(sb); |
1871 | } | 1908 | } |
1872 | 1909 | ||
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) | 1910 | static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags) |
1876 | { | 1911 | { |
1877 | const struct nfs_server *a = s->s_fs_info; | 1912 | const struct nfs_server *a = s->s_fs_info; |
@@ -2036,6 +2071,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
2036 | if (!s->s_root) { | 2071 | if (!s->s_root) { |
2037 | /* initial superblock/root creation */ | 2072 | /* initial superblock/root creation */ |
2038 | nfs_fill_super(s, data); | 2073 | nfs_fill_super(s, data); |
2074 | nfs_fscache_get_super_cookie(s, data); | ||
2039 | } | 2075 | } |
2040 | 2076 | ||
2041 | mntroot = nfs_get_root(s, mntfh); | 2077 | mntroot = nfs_get_root(s, mntfh); |
@@ -2056,6 +2092,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
2056 | out: | 2092 | out: |
2057 | kfree(data->nfs_server.hostname); | 2093 | kfree(data->nfs_server.hostname); |
2058 | kfree(data->mount_server.hostname); | 2094 | kfree(data->mount_server.hostname); |
2095 | kfree(data->fscache_uniq); | ||
2059 | security_free_mnt_opts(&data->lsm_opts); | 2096 | security_free_mnt_opts(&data->lsm_opts); |
2060 | out_free_fh: | 2097 | out_free_fh: |
2061 | kfree(mntfh); | 2098 | kfree(mntfh); |
@@ -2083,6 +2120,7 @@ static void nfs_kill_super(struct super_block *s) | |||
2083 | 2120 | ||
2084 | bdi_unregister(&server->backing_dev_info); | 2121 | bdi_unregister(&server->backing_dev_info); |
2085 | kill_anon_super(s); | 2122 | kill_anon_super(s); |
2123 | nfs_fscache_release_super_cookie(s); | ||
2086 | nfs_free_server(server); | 2124 | nfs_free_server(server); |
2087 | } | 2125 | } |
2088 | 2126 | ||
@@ -2390,6 +2428,7 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
2390 | if (!s->s_root) { | 2428 | if (!s->s_root) { |
2391 | /* initial superblock/root creation */ | 2429 | /* initial superblock/root creation */ |
2392 | nfs4_fill_super(s); | 2430 | nfs4_fill_super(s); |
2431 | nfs_fscache_get_super_cookie(s, data); | ||
2393 | } | 2432 | } |
2394 | 2433 | ||
2395 | mntroot = nfs4_get_root(s, mntfh); | 2434 | mntroot = nfs4_get_root(s, mntfh); |
@@ -2411,6 +2450,7 @@ out: | |||
2411 | kfree(data->client_address); | 2450 | kfree(data->client_address); |
2412 | kfree(data->nfs_server.export_path); | 2451 | kfree(data->nfs_server.export_path); |
2413 | kfree(data->nfs_server.hostname); | 2452 | kfree(data->nfs_server.hostname); |
2453 | kfree(data->fscache_uniq); | ||
2414 | security_free_mnt_opts(&data->lsm_opts); | 2454 | security_free_mnt_opts(&data->lsm_opts); |
2415 | out_free_fh: | 2455 | out_free_fh: |
2416 | kfree(mntfh); | 2456 | kfree(mntfh); |
@@ -2437,6 +2477,7 @@ static void nfs4_kill_super(struct super_block *sb) | |||
2437 | kill_anon_super(sb); | 2477 | kill_anon_super(sb); |
2438 | 2478 | ||
2439 | nfs4_renewd_prepare_shutdown(server); | 2479 | nfs4_renewd_prepare_shutdown(server); |
2480 | nfs_fscache_release_super_cookie(sb); | ||
2440 | nfs_free_server(server); | 2481 | nfs_free_server(server); |
2441 | } | 2482 | } |
2442 | 2483 | ||