1 /* fscache.c: NFS filesystem cache interface
3 * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
13 #include <linux/init.h>
14 #include <linux/kernel.h>
16 #include <linux/nfs_fs.h>
17 #include <linux/nfs_fs_sb.h>
18 #include <linux/in6.h>
25 atomic_t nfs_fscache_to_pages;
26 atomic_t nfs_fscache_from_pages;
27 atomic_t nfs_fscache_uncache_page;
28 int nfs_fscache_from_error;
29 int nfs_fscache_to_error;
31 #define NFSDBG_FACILITY NFSDBG_FSCACHE
33 /* the auxiliary data in the cache (used for coherency management) */
34 struct nfs_fh_auxdata {
35 struct timespec i_mtime;
36 struct timespec i_ctime;
40 static struct fscache_netfs_operations nfs_cache_ops = {
43 struct fscache_netfs nfs_cache_netfs = {
46 .ops = &nfs_cache_ops,
49 static const uint8_t nfs_cache_ipv6_wrapper_for_ipv4[12] = {
54 struct nfs_server_key {
59 uint8_t ipv6wrapper[12];
62 struct in6_addr ipv6_addr;
66 static uint16_t nfs_server_get_key(const void *cookie_netfs_data,
67 void *buffer, uint16_t bufmax)
69 const struct nfs_client *clp = cookie_netfs_data;
70 struct nfs_server_key *key = buffer;
73 key->nfsversion = clp->cl_nfsversion;
75 switch (clp->cl_addr.sin_family) {
77 key->port = clp->cl_addr.sin_port;
79 memcpy(&key->ipv4_addr.ipv6wrapper,
80 &nfs_cache_ipv6_wrapper_for_ipv4,
81 sizeof(key->ipv4_addr.ipv6wrapper));
82 memcpy(&key->ipv4_addr.addr,
83 &clp->cl_addr.sin_addr,
84 sizeof(key->ipv4_addr.addr));
85 len = sizeof(struct nfs_server_key);
89 key->port = clp->cl_addr.sin_port;
91 memcpy(&key->ipv6_addr,
92 &clp->cl_addr.sin_addr,
93 sizeof(key->ipv6_addr));
94 len = sizeof(struct nfs_server_key);
99 printk(KERN_WARNING "NFS: Unknown network family '%d'\n",
100 clp->cl_addr.sin_family);
108 * the root index for the filesystem is defined by nfsd IP address and ports
110 struct fscache_cookie_def nfs_cache_server_index_def = {
111 .name = "NFS.servers",
112 .type = FSCACHE_COOKIE_TYPE_INDEX,
113 .get_key = nfs_server_get_key,
116 static uint16_t nfs_fh_get_key(const void *cookie_netfs_data,
117 void *buffer, uint16_t bufmax)
119 const struct nfs_inode *nfsi = cookie_netfs_data;
122 /* set the file handle */
123 nsize = nfsi->fh.size;
124 memcpy(buffer, nfsi->fh.data, nsize);
129 * indication of pages that now have cache metadata retained
130 * - this function should mark the specified pages as now being cached
132 static void nfs_fh_mark_pages_cached(void *cookie_netfs_data,
133 struct address_space *mapping,
134 struct pagevec *cached_pvec)
136 struct nfs_inode *nfsi = cookie_netfs_data;
139 dprintk("NFS: nfs_fh_mark_pages_cached: nfs_inode 0x%p pages %ld\n",
140 nfsi, cached_pvec->nr);
142 for (loop = 0; loop < cached_pvec->nr; loop++)
143 SetPageNfsCached(cached_pvec->pages[loop]);
147 * get an extra reference on a read context
148 * - this function can be absent if the completion function doesn't
151 static void nfs_fh_get_context(void *cookie_netfs_data, void *context)
153 get_nfs_open_context(context);
157 * release an extra reference on a read context
158 * - this function can be absent if the completion function doesn't
161 static void nfs_fh_put_context(void *cookie_netfs_data, void *context)
164 put_nfs_open_context(context);
168 * indication the cookie is no longer uncached
169 * - this function is called when the backing store currently caching a cookie
171 * - the netfs should use this to clean up any markers indicating cached pages
172 * - this is mandatory for any object that may have data
174 static void nfs_fh_now_uncached(void *cookie_netfs_data)
176 struct nfs_inode *nfsi = cookie_netfs_data;
181 pagevec_init(&pvec, 0);
184 dprintk("NFS: nfs_fh_now_uncached: nfs_inode 0x%p\n", nfsi);
187 /* grab a bunch of pages to clean */
188 nr_pages = pagevec_lookup(&pvec,
189 nfsi->vfs_inode.i_mapping,
191 PAGEVEC_SIZE - pagevec_count(&pvec));
195 for (loop = 0; loop < nr_pages; loop++)
196 ClearPageNfsCached(pvec.pages[loop]);
198 first = pvec.pages[nr_pages - 1]->index + 1;
201 pagevec_release(&pvec);
207 * get certain file attributes from the netfs data
208 * - this function can be absent for an index
209 * - not permitted to return an error
210 * - the netfs data from the cookie being used as the source is
213 static void nfs_fh_get_attr(const void *cookie_netfs_data, uint64_t *size)
215 const struct nfs_inode *nfsi = cookie_netfs_data;
217 *size = nfsi->vfs_inode.i_size;
221 * get the auxilliary data from netfs data
222 * - this function can be absent if the index carries no state data
223 * - should store the auxilliary data in the buffer
224 * - should return the amount of amount stored
225 * - not permitted to return an error
226 * - the netfs data from the cookie being used as the source is
229 static uint16_t nfs_fh_get_aux(const void *cookie_netfs_data,
230 void *buffer, uint16_t bufmax)
232 struct nfs_fh_auxdata auxdata;
233 const struct nfs_inode *nfsi = cookie_netfs_data;
235 auxdata.i_size = nfsi->vfs_inode.i_size;
236 auxdata.i_mtime = nfsi->vfs_inode.i_mtime;
237 auxdata.i_ctime = nfsi->vfs_inode.i_ctime;
239 if (bufmax > sizeof(auxdata))
240 bufmax = sizeof(auxdata);
242 memcpy(buffer, &auxdata, bufmax);
247 * consult the netfs about the state of an object
248 * - this function can be absent if the index carries no state data
249 * - the netfs data from the cookie being used as the target is
250 * presented, as is the auxilliary data
252 static fscache_checkaux_t nfs_fh_check_aux(void *cookie_netfs_data,
253 const void *data, uint16_t datalen)
255 struct nfs_fh_auxdata auxdata;
256 struct nfs_inode *nfsi = cookie_netfs_data;
258 if (datalen > sizeof(auxdata))
259 return FSCACHE_CHECKAUX_OBSOLETE;
261 auxdata.i_size = nfsi->vfs_inode.i_size;
262 auxdata.i_mtime = nfsi->vfs_inode.i_mtime;
263 auxdata.i_ctime = nfsi->vfs_inode.i_ctime;
265 if (memcmp(data, &auxdata, datalen) != 0)
266 return FSCACHE_CHECKAUX_OBSOLETE;
268 return FSCACHE_CHECKAUX_OKAY;
272 * the primary index for each server is simply made up of a series of NFS file
275 struct fscache_cookie_def nfs_cache_fh_index_def = {
277 .type = FSCACHE_COOKIE_TYPE_DATAFILE,
278 .get_key = nfs_fh_get_key,
279 .get_attr = nfs_fh_get_attr,
280 .get_aux = nfs_fh_get_aux,
281 .check_aux = nfs_fh_check_aux,
282 .get_context = nfs_fh_get_context,
283 .put_context = nfs_fh_put_context,
284 .mark_pages_cached = nfs_fh_mark_pages_cached,
285 .now_uncached = nfs_fh_now_uncached,
288 static int nfs_file_page_mkwrite(struct vm_area_struct *vma, struct page *page)
290 wait_on_page_fs_misc(page);
294 struct vm_operations_struct nfs_fs_vm_operations = {
295 .nopage = filemap_nopage,
296 .populate = filemap_populate,
297 .page_mkwrite = nfs_file_page_mkwrite,
301 * handle completion of a page being stored in the cache
303 void nfs_readpage_to_fscache_complete(struct page *page, void *data, int error)
306 "NFS: readpage_to_fscache_complete (p:%p(i:%lx f:%lx)/%d)\n",
307 page, page->index, page->flags, error);
309 end_page_fs_misc(page);
313 * handle completion of a page being read from the cache
314 * - called in process (keventd) context
316 void nfs_readpage_from_fscache_complete(struct page *page,
321 "NFS: readpage_from_fscache_complete (0x%p/0x%p/%d)\n",
322 page, context, error);
324 /* if the read completes with an error, we just unlock the page and let
325 * the VM reissue the readpage */
327 SetPageUptodate(page);
330 error = nfs_readpage_async(context, page->mapping->host, page);
337 * handle completion of a page being read from the cache
338 * - really need to synchronise the end of writeback, probably using a page
339 * flag, but for the moment we disable caching on writable files
341 void nfs_writepage_to_fscache_complete(struct page *page,