This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / fs / nfs / fscache.c
1 /* fscache.c: NFS filesystem cache interface
2  *
3  * Copyright (C) 2006 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 License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11
12
13 #include <linux/init.h>
14 #include <linux/kernel.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
22 /*
23  * Sysctl variables
24  */
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;
30
31 #define NFSDBG_FACILITY         NFSDBG_FSCACHE
32
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;
37         loff_t          i_size;
38 };
39
40 static struct fscache_netfs_operations nfs_cache_ops = {
41 };
42
43 struct fscache_netfs nfs_cache_netfs = {
44         .name                   = "nfs",
45         .version                = 0,
46         .ops                    = &nfs_cache_ops,
47 };
48
49 static const uint8_t nfs_cache_ipv6_wrapper_for_ipv4[12] = {
50         [0 ... 9]       = 0x00,
51         [10 ... 11]     = 0xff
52 };
53
54 struct nfs_server_key {
55         uint16_t nfsversion;
56         uint16_t port;
57         union {
58                 struct {
59                         uint8_t         ipv6wrapper[12];
60                         struct in_addr  addr;
61                 } ipv4_addr;
62                 struct in6_addr ipv6_addr;
63         };
64 };
65
66 static uint16_t nfs_server_get_key(const void *cookie_netfs_data,
67                                    void *buffer, uint16_t bufmax)
68 {
69         const struct nfs_client *clp = cookie_netfs_data;
70         struct nfs_server_key *key = buffer;
71         uint16_t len = 0;
72
73         key->nfsversion = clp->cl_nfsversion;
74
75         switch (clp->cl_addr.sin_family) {
76         case AF_INET:
77                 key->port = clp->cl_addr.sin_port;
78
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);
86                 break;
87
88         case AF_INET6:
89                 key->port = clp->cl_addr.sin_port;
90
91                 memcpy(&key->ipv6_addr,
92                        &clp->cl_addr.sin_addr,
93                        sizeof(key->ipv6_addr));
94                 len = sizeof(struct nfs_server_key);
95                 break;
96
97         default:
98                 len = 0;
99                 printk(KERN_WARNING "NFS: Unknown network family '%d'\n",
100                         clp->cl_addr.sin_family);
101                 break;
102         }
103
104         return len;
105 }
106
107 /*
108  * the root index for the filesystem is defined by nfsd IP address and ports
109  */
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,
114 };
115
116 static uint16_t nfs_fh_get_key(const void *cookie_netfs_data,
117                 void *buffer, uint16_t bufmax)
118 {
119         const struct nfs_inode *nfsi = cookie_netfs_data;
120         uint16_t nsize;
121
122         /* set the file handle */
123         nsize = nfsi->fh.size;
124         memcpy(buffer, nfsi->fh.data, nsize);
125         return nsize;
126 }
127
128 /*
129  * indication of pages that now have cache metadata retained
130  * - this function should mark the specified pages as now being cached
131  */
132 static void nfs_fh_mark_pages_cached(void *cookie_netfs_data,
133                                      struct address_space *mapping,
134                                      struct pagevec *cached_pvec)
135 {
136         struct nfs_inode *nfsi = cookie_netfs_data;
137         unsigned long loop;
138
139         dprintk("NFS: nfs_fh_mark_pages_cached: nfs_inode 0x%p pages %ld\n",
140                 nfsi, cached_pvec->nr);
141
142         for (loop = 0; loop < cached_pvec->nr; loop++)
143                 SetPageNfsCached(cached_pvec->pages[loop]);
144 }
145
146 /*
147  * get an extra reference on a read context
148  * - this function can be absent if the completion function doesn't
149  *   require a context
150  */
151 static void nfs_fh_get_context(void *cookie_netfs_data, void *context)
152 {
153         get_nfs_open_context(context);
154 }
155
156 /*
157  * release an extra reference on a read context
158  * - this function can be absent if the completion function doesn't
159  *   require a context
160  */
161 static void nfs_fh_put_context(void *cookie_netfs_data, void *context)
162 {
163         if (context)
164                 put_nfs_open_context(context);
165 }
166
167 /*
168  * indication the cookie is no longer uncached
169  * - this function is called when the backing store currently caching a cookie
170  *   is removed
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
173  */
174 static void nfs_fh_now_uncached(void *cookie_netfs_data)
175 {
176         struct nfs_inode *nfsi = cookie_netfs_data;
177         struct pagevec pvec;
178         pgoff_t first;
179         int loop, nr_pages;
180
181         pagevec_init(&pvec, 0);
182         first = 0;
183
184         dprintk("NFS: nfs_fh_now_uncached: nfs_inode 0x%p\n", nfsi);
185
186         for (;;) {
187                 /* grab a bunch of pages to clean */
188                 nr_pages = pagevec_lookup(&pvec,
189                                           nfsi->vfs_inode.i_mapping,
190                                           first,
191                                           PAGEVEC_SIZE - pagevec_count(&pvec));
192                 if (!nr_pages)
193                         break;
194
195                 for (loop = 0; loop < nr_pages; loop++)
196                         ClearPageNfsCached(pvec.pages[loop]);
197
198                 first = pvec.pages[nr_pages - 1]->index + 1;
199
200                 pvec.nr = nr_pages;
201                 pagevec_release(&pvec);
202                 cond_resched();
203         }
204 }
205
206 /*
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
211  *   presented
212  */
213 static void nfs_fh_get_attr(const void *cookie_netfs_data, uint64_t *size)
214 {
215         const struct nfs_inode *nfsi = cookie_netfs_data;
216
217         *size = nfsi->vfs_inode.i_size;
218 }
219
220 /*
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
227  *   presented
228  */
229 static uint16_t nfs_fh_get_aux(const void *cookie_netfs_data,
230                                void *buffer, uint16_t bufmax)
231 {
232         struct nfs_fh_auxdata auxdata;
233         const struct nfs_inode *nfsi = cookie_netfs_data;
234
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;
238
239         if (bufmax > sizeof(auxdata))
240                 bufmax = sizeof(auxdata);
241
242         memcpy(buffer, &auxdata, bufmax);
243         return bufmax;
244 }
245
246 /*
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
251  */
252 static fscache_checkaux_t nfs_fh_check_aux(void *cookie_netfs_data,
253                                            const void *data, uint16_t datalen)
254 {
255         struct nfs_fh_auxdata auxdata;
256         struct nfs_inode *nfsi = cookie_netfs_data;
257
258         if (datalen > sizeof(auxdata))
259                 return FSCACHE_CHECKAUX_OBSOLETE;
260
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;
264
265         if (memcmp(data, &auxdata, datalen) != 0)
266                 return FSCACHE_CHECKAUX_OBSOLETE;
267
268         return FSCACHE_CHECKAUX_OKAY;
269 }
270
271 /*
272  * the primary index for each server is simply made up of a series of NFS file
273  * handles
274  */
275 struct fscache_cookie_def nfs_cache_fh_index_def = {
276         .name                   = "NFS.fh",
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,
286 };
287
288 static int nfs_file_page_mkwrite(struct vm_area_struct *vma, struct page *page)
289 {
290         wait_on_page_fs_misc(page);
291         return 0;
292 }
293
294 struct vm_operations_struct nfs_fs_vm_operations = {
295         .nopage         = filemap_nopage,
296         .populate       = filemap_populate,
297         .page_mkwrite   = nfs_file_page_mkwrite,
298 };
299
300 /*
301  * handle completion of a page being stored in the cache
302  */
303 void nfs_readpage_to_fscache_complete(struct page *page, void *data, int error)
304 {
305         dfprintk(FSCACHE,
306                 "NFS:     readpage_to_fscache_complete (p:%p(i:%lx f:%lx)/%d)\n",
307                 page, page->index, page->flags, error);
308
309         end_page_fs_misc(page);
310 }
311
312 /*
313  * handle completion of a page being read from the cache
314  * - called in process (keventd) context
315  */
316 void nfs_readpage_from_fscache_complete(struct page *page,
317                                         void *context,
318                                         int error)
319 {
320         dfprintk(FSCACHE,
321                  "NFS: readpage_from_fscache_complete (0x%p/0x%p/%d)\n",
322                  page, context, error);
323
324         /* if the read completes with an error, we just unlock the page and let
325          * the VM reissue the readpage */
326         if (!error) {
327                 SetPageUptodate(page);
328                 unlock_page(page);
329         } else {
330                 error = nfs_readpage_async(context, page->mapping->host, page);
331                 if (error)
332                         unlock_page(page);
333         }
334 }
335
336 /*
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
340  */
341 void nfs_writepage_to_fscache_complete(struct page *page,
342                                        void *data,
343                                        int error)
344 {
345 }