Merge branch 'v6v7' into devel
[linux/fpc-iii.git] / fs / 9p / cache.c
blob0dbe0d139ac2aa3e03375188f1308c7cbadf6b57
1 /*
2 * V9FS cache definitions.
4 * Copyright (C) 2009 by Abhishek Kulkarni <adkulkar@umail.iu.edu>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to:
17 * Free Software Foundation
18 * 51 Franklin Street, Fifth Floor
19 * Boston, MA 02111-1301 USA
23 #include <linux/jiffies.h>
24 #include <linux/file.h>
25 #include <linux/slab.h>
26 #include <linux/stat.h>
27 #include <linux/sched.h>
28 #include <linux/fs.h>
29 #include <net/9p/9p.h>
31 #include "v9fs.h"
32 #include "cache.h"
34 #define CACHETAG_LEN 11
36 struct kmem_cache *vcookie_cache;
38 struct fscache_netfs v9fs_cache_netfs = {
39 .name = "9p",
40 .version = 0,
43 static void init_once(void *foo)
45 struct v9fs_cookie *vcookie = (struct v9fs_cookie *) foo;
46 vcookie->fscache = NULL;
47 vcookie->qid = NULL;
48 inode_init_once(&vcookie->inode);
51 /**
52 * v9fs_init_vcookiecache - initialize a cache for vcookies to maintain
53 * vcookie to inode mapping
55 * Returns 0 on success.
58 static int v9fs_init_vcookiecache(void)
60 vcookie_cache = kmem_cache_create("vcookie_cache",
61 sizeof(struct v9fs_cookie),
62 0, (SLAB_RECLAIM_ACCOUNT|
63 SLAB_MEM_SPREAD),
64 init_once);
65 if (!vcookie_cache)
66 return -ENOMEM;
68 return 0;
71 /**
72 * v9fs_destroy_vcookiecache - destroy the cache of vcookies
76 static void v9fs_destroy_vcookiecache(void)
78 kmem_cache_destroy(vcookie_cache);
81 int __v9fs_cache_register(void)
83 int ret;
84 ret = v9fs_init_vcookiecache();
85 if (ret < 0)
86 return ret;
88 return fscache_register_netfs(&v9fs_cache_netfs);
91 void __v9fs_cache_unregister(void)
93 v9fs_destroy_vcookiecache();
94 fscache_unregister_netfs(&v9fs_cache_netfs);
97 /**
98 * v9fs_random_cachetag - Generate a random tag to be associated
99 * with a new cache session.
101 * The value of jiffies is used for a fairly randomly cache tag.
104 static
105 int v9fs_random_cachetag(struct v9fs_session_info *v9ses)
107 v9ses->cachetag = kmalloc(CACHETAG_LEN, GFP_KERNEL);
108 if (!v9ses->cachetag)
109 return -ENOMEM;
111 return scnprintf(v9ses->cachetag, CACHETAG_LEN, "%lu", jiffies);
114 static uint16_t v9fs_cache_session_get_key(const void *cookie_netfs_data,
115 void *buffer, uint16_t bufmax)
117 struct v9fs_session_info *v9ses;
118 uint16_t klen = 0;
120 v9ses = (struct v9fs_session_info *)cookie_netfs_data;
121 P9_DPRINTK(P9_DEBUG_FSC, "session %p buf %p size %u", v9ses,
122 buffer, bufmax);
124 if (v9ses->cachetag)
125 klen = strlen(v9ses->cachetag);
127 if (klen > bufmax)
128 return 0;
130 memcpy(buffer, v9ses->cachetag, klen);
131 P9_DPRINTK(P9_DEBUG_FSC, "cache session tag %s", v9ses->cachetag);
132 return klen;
135 const struct fscache_cookie_def v9fs_cache_session_index_def = {
136 .name = "9P.session",
137 .type = FSCACHE_COOKIE_TYPE_INDEX,
138 .get_key = v9fs_cache_session_get_key,
141 void v9fs_cache_session_get_cookie(struct v9fs_session_info *v9ses)
143 /* If no cache session tag was specified, we generate a random one. */
144 if (!v9ses->cachetag)
145 v9fs_random_cachetag(v9ses);
147 v9ses->fscache = fscache_acquire_cookie(v9fs_cache_netfs.primary_index,
148 &v9fs_cache_session_index_def,
149 v9ses);
150 P9_DPRINTK(P9_DEBUG_FSC, "session %p get cookie %p", v9ses,
151 v9ses->fscache);
154 void v9fs_cache_session_put_cookie(struct v9fs_session_info *v9ses)
156 P9_DPRINTK(P9_DEBUG_FSC, "session %p put cookie %p", v9ses,
157 v9ses->fscache);
158 fscache_relinquish_cookie(v9ses->fscache, 0);
159 v9ses->fscache = NULL;
163 static uint16_t v9fs_cache_inode_get_key(const void *cookie_netfs_data,
164 void *buffer, uint16_t bufmax)
166 const struct v9fs_cookie *vcookie = cookie_netfs_data;
167 memcpy(buffer, &vcookie->qid->path, sizeof(vcookie->qid->path));
169 P9_DPRINTK(P9_DEBUG_FSC, "inode %p get key %llu", &vcookie->inode,
170 vcookie->qid->path);
171 return sizeof(vcookie->qid->path);
174 static void v9fs_cache_inode_get_attr(const void *cookie_netfs_data,
175 uint64_t *size)
177 const struct v9fs_cookie *vcookie = cookie_netfs_data;
178 *size = i_size_read(&vcookie->inode);
180 P9_DPRINTK(P9_DEBUG_FSC, "inode %p get attr %llu", &vcookie->inode,
181 *size);
184 static uint16_t v9fs_cache_inode_get_aux(const void *cookie_netfs_data,
185 void *buffer, uint16_t buflen)
187 const struct v9fs_cookie *vcookie = cookie_netfs_data;
188 memcpy(buffer, &vcookie->qid->version, sizeof(vcookie->qid->version));
190 P9_DPRINTK(P9_DEBUG_FSC, "inode %p get aux %u", &vcookie->inode,
191 vcookie->qid->version);
192 return sizeof(vcookie->qid->version);
195 static enum
196 fscache_checkaux v9fs_cache_inode_check_aux(void *cookie_netfs_data,
197 const void *buffer,
198 uint16_t buflen)
200 const struct v9fs_cookie *vcookie = cookie_netfs_data;
202 if (buflen != sizeof(vcookie->qid->version))
203 return FSCACHE_CHECKAUX_OBSOLETE;
205 if (memcmp(buffer, &vcookie->qid->version,
206 sizeof(vcookie->qid->version)))
207 return FSCACHE_CHECKAUX_OBSOLETE;
209 return FSCACHE_CHECKAUX_OKAY;
212 static void v9fs_cache_inode_now_uncached(void *cookie_netfs_data)
214 struct v9fs_cookie *vcookie = cookie_netfs_data;
215 struct pagevec pvec;
216 pgoff_t first;
217 int loop, nr_pages;
219 pagevec_init(&pvec, 0);
220 first = 0;
222 for (;;) {
223 nr_pages = pagevec_lookup(&pvec, vcookie->inode.i_mapping,
224 first,
225 PAGEVEC_SIZE - pagevec_count(&pvec));
226 if (!nr_pages)
227 break;
229 for (loop = 0; loop < nr_pages; loop++)
230 ClearPageFsCache(pvec.pages[loop]);
232 first = pvec.pages[nr_pages - 1]->index + 1;
234 pvec.nr = nr_pages;
235 pagevec_release(&pvec);
236 cond_resched();
240 const struct fscache_cookie_def v9fs_cache_inode_index_def = {
241 .name = "9p.inode",
242 .type = FSCACHE_COOKIE_TYPE_DATAFILE,
243 .get_key = v9fs_cache_inode_get_key,
244 .get_attr = v9fs_cache_inode_get_attr,
245 .get_aux = v9fs_cache_inode_get_aux,
246 .check_aux = v9fs_cache_inode_check_aux,
247 .now_uncached = v9fs_cache_inode_now_uncached,
250 void v9fs_cache_inode_get_cookie(struct inode *inode)
252 struct v9fs_cookie *vcookie;
253 struct v9fs_session_info *v9ses;
255 if (!S_ISREG(inode->i_mode))
256 return;
258 vcookie = v9fs_inode2cookie(inode);
259 if (vcookie->fscache)
260 return;
262 v9ses = v9fs_inode2v9ses(inode);
263 vcookie->fscache = fscache_acquire_cookie(v9ses->fscache,
264 &v9fs_cache_inode_index_def,
265 vcookie);
267 P9_DPRINTK(P9_DEBUG_FSC, "inode %p get cookie %p", inode,
268 vcookie->fscache);
271 void v9fs_cache_inode_put_cookie(struct inode *inode)
273 struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
275 if (!vcookie->fscache)
276 return;
277 P9_DPRINTK(P9_DEBUG_FSC, "inode %p put cookie %p", inode,
278 vcookie->fscache);
280 fscache_relinquish_cookie(vcookie->fscache, 0);
281 vcookie->fscache = NULL;
284 void v9fs_cache_inode_flush_cookie(struct inode *inode)
286 struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
288 if (!vcookie->fscache)
289 return;
290 P9_DPRINTK(P9_DEBUG_FSC, "inode %p flush cookie %p", inode,
291 vcookie->fscache);
293 fscache_relinquish_cookie(vcookie->fscache, 1);
294 vcookie->fscache = NULL;
297 void v9fs_cache_inode_set_cookie(struct inode *inode, struct file *filp)
299 struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
300 struct p9_fid *fid;
302 if (!vcookie->fscache)
303 return;
305 spin_lock(&vcookie->lock);
306 fid = filp->private_data;
307 if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
308 v9fs_cache_inode_flush_cookie(inode);
309 else
310 v9fs_cache_inode_get_cookie(inode);
312 spin_unlock(&vcookie->lock);
315 void v9fs_cache_inode_reset_cookie(struct inode *inode)
317 struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
318 struct v9fs_session_info *v9ses;
319 struct fscache_cookie *old;
321 if (!vcookie->fscache)
322 return;
324 old = vcookie->fscache;
326 spin_lock(&vcookie->lock);
327 fscache_relinquish_cookie(vcookie->fscache, 1);
329 v9ses = v9fs_inode2v9ses(inode);
330 vcookie->fscache = fscache_acquire_cookie(v9ses->fscache,
331 &v9fs_cache_inode_index_def,
332 vcookie);
334 P9_DPRINTK(P9_DEBUG_FSC, "inode %p revalidating cookie old %p new %p",
335 inode, old, vcookie->fscache);
337 spin_unlock(&vcookie->lock);
340 int __v9fs_fscache_release_page(struct page *page, gfp_t gfp)
342 struct inode *inode = page->mapping->host;
343 struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
345 BUG_ON(!vcookie->fscache);
347 return fscache_maybe_release_page(vcookie->fscache, page, gfp);
350 void __v9fs_fscache_invalidate_page(struct page *page)
352 struct inode *inode = page->mapping->host;
353 struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
355 BUG_ON(!vcookie->fscache);
357 if (PageFsCache(page)) {
358 fscache_wait_on_page_write(vcookie->fscache, page);
359 BUG_ON(!PageLocked(page));
360 fscache_uncache_page(vcookie->fscache, page);
364 static void v9fs_vfs_readpage_complete(struct page *page, void *data,
365 int error)
367 if (!error)
368 SetPageUptodate(page);
370 unlock_page(page);
374 * __v9fs_readpage_from_fscache - read a page from cache
376 * Returns 0 if the pages are in cache and a BIO is submitted,
377 * 1 if the pages are not in cache and -error otherwise.
380 int __v9fs_readpage_from_fscache(struct inode *inode, struct page *page)
382 int ret;
383 const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
385 P9_DPRINTK(P9_DEBUG_FSC, "inode %p page %p", inode, page);
386 if (!vcookie->fscache)
387 return -ENOBUFS;
389 ret = fscache_read_or_alloc_page(vcookie->fscache,
390 page,
391 v9fs_vfs_readpage_complete,
392 NULL,
393 GFP_KERNEL);
394 switch (ret) {
395 case -ENOBUFS:
396 case -ENODATA:
397 P9_DPRINTK(P9_DEBUG_FSC, "page/inode not in cache %d", ret);
398 return 1;
399 case 0:
400 P9_DPRINTK(P9_DEBUG_FSC, "BIO submitted");
401 return ret;
402 default:
403 P9_DPRINTK(P9_DEBUG_FSC, "ret %d", ret);
404 return ret;
409 * __v9fs_readpages_from_fscache - read multiple pages from cache
411 * Returns 0 if the pages are in cache and a BIO is submitted,
412 * 1 if the pages are not in cache and -error otherwise.
415 int __v9fs_readpages_from_fscache(struct inode *inode,
416 struct address_space *mapping,
417 struct list_head *pages,
418 unsigned *nr_pages)
420 int ret;
421 const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
423 P9_DPRINTK(P9_DEBUG_FSC, "inode %p pages %u", inode, *nr_pages);
424 if (!vcookie->fscache)
425 return -ENOBUFS;
427 ret = fscache_read_or_alloc_pages(vcookie->fscache,
428 mapping, pages, nr_pages,
429 v9fs_vfs_readpage_complete,
430 NULL,
431 mapping_gfp_mask(mapping));
432 switch (ret) {
433 case -ENOBUFS:
434 case -ENODATA:
435 P9_DPRINTK(P9_DEBUG_FSC, "pages/inodes not in cache %d", ret);
436 return 1;
437 case 0:
438 BUG_ON(!list_empty(pages));
439 BUG_ON(*nr_pages != 0);
440 P9_DPRINTK(P9_DEBUG_FSC, "BIO submitted");
441 return ret;
442 default:
443 P9_DPRINTK(P9_DEBUG_FSC, "ret %d", ret);
444 return ret;
449 * __v9fs_readpage_to_fscache - write a page to the cache
453 void __v9fs_readpage_to_fscache(struct inode *inode, struct page *page)
455 int ret;
456 const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
458 P9_DPRINTK(P9_DEBUG_FSC, "inode %p page %p", inode, page);
459 ret = fscache_write_page(vcookie->fscache, page, GFP_KERNEL);
460 P9_DPRINTK(P9_DEBUG_FSC, "ret = %d", ret);
461 if (ret != 0)
462 v9fs_uncache_page(inode, page);