xref: /linux/fs/9p/cache.c (revision d39d0ed196aa1685bb24771e92f78633c66ac9cb)
1 /*
2  * V9FS cache definitions.
3  *
4  *  Copyright (C) 2009 by Abhishek Kulkarni <adkulkar@umail.iu.edu>
5  *
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.
9  *
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.
14  *
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
20  *
21  */
22 
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>
30 
31 #include "v9fs.h"
32 #include "cache.h"
33 
34 #define CACHETAG_LEN  11
35 
36 struct kmem_cache *vcookie_cache;
37 
38 struct fscache_netfs v9fs_cache_netfs = {
39 	.name 		= "9p",
40 	.version 	= 0,
41 };
42 
43 static void init_once(void *foo)
44 {
45 	struct v9fs_cookie *vcookie = (struct v9fs_cookie *) foo;
46 	vcookie->fscache = NULL;
47 	vcookie->qid = NULL;
48 	inode_init_once(&vcookie->inode);
49 }
50 
51 /**
52  * v9fs_init_vcookiecache - initialize a cache for vcookies to maintain
53  *			    vcookie to inode mapping
54  *
55  * Returns 0 on success.
56  */
57 
58 static int v9fs_init_vcookiecache(void)
59 {
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;
67 
68 	return 0;
69 }
70 
71 /**
72  * v9fs_destroy_vcookiecache - destroy the cache of vcookies
73  *
74  */
75 
76 static void v9fs_destroy_vcookiecache(void)
77 {
78 	kmem_cache_destroy(vcookie_cache);
79 }
80 
81 int __v9fs_cache_register(void)
82 {
83 	int ret;
84 	ret = v9fs_init_vcookiecache();
85 	if (ret < 0)
86 		return ret;
87 
88 	return fscache_register_netfs(&v9fs_cache_netfs);
89 }
90 
91 void __v9fs_cache_unregister(void)
92 {
93 	v9fs_destroy_vcookiecache();
94 	fscache_unregister_netfs(&v9fs_cache_netfs);
95 }
96 
97 /**
98  * v9fs_random_cachetag - Generate a random tag to be associated
99  *			  with a new cache session.
100  *
101  * The value of jiffies is used for a fairly randomly cache tag.
102  */
103 
104 static
105 int v9fs_random_cachetag(struct v9fs_session_info *v9ses)
106 {
107 	v9ses->cachetag = kmalloc(CACHETAG_LEN, GFP_KERNEL);
108 	if (!v9ses->cachetag)
109 		return -ENOMEM;
110 
111 	return scnprintf(v9ses->cachetag, CACHETAG_LEN, "%lu", jiffies);
112 }
113 
114 static uint16_t v9fs_cache_session_get_key(const void *cookie_netfs_data,
115 					   void *buffer, uint16_t bufmax)
116 {
117 	struct v9fs_session_info *v9ses;
118 	uint16_t klen = 0;
119 
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);
123 
124 	if (v9ses->cachetag)
125 		klen = strlen(v9ses->cachetag);
126 
127 	if (klen > bufmax)
128 		return 0;
129 
130 	memcpy(buffer, v9ses->cachetag, klen);
131 	P9_DPRINTK(P9_DEBUG_FSC, "cache session tag %s", v9ses->cachetag);
132 	return klen;
133 }
134 
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,
139 };
140 
141 void v9fs_cache_session_get_cookie(struct v9fs_session_info *v9ses)
142 {
143 	/* If no cache session tag was specified, we generate a random one. */
144 	if (!v9ses->cachetag)
145 		v9fs_random_cachetag(v9ses);
146 
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);
152 }
153 
154 void v9fs_cache_session_put_cookie(struct v9fs_session_info *v9ses)
155 {
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;
160 }
161 
162 
163 static uint16_t v9fs_cache_inode_get_key(const void *cookie_netfs_data,
164 					 void *buffer, uint16_t bufmax)
165 {
166 	const struct v9fs_cookie *vcookie = cookie_netfs_data;
167 	memcpy(buffer, &vcookie->qid->path, sizeof(vcookie->qid->path));
168 
169 	P9_DPRINTK(P9_DEBUG_FSC, "inode %p get key %llu", &vcookie->inode,
170 		   vcookie->qid->path);
171 	return sizeof(vcookie->qid->path);
172 }
173 
174 static void v9fs_cache_inode_get_attr(const void *cookie_netfs_data,
175 				      uint64_t *size)
176 {
177 	const struct v9fs_cookie *vcookie = cookie_netfs_data;
178 	*size = i_size_read(&vcookie->inode);
179 
180 	P9_DPRINTK(P9_DEBUG_FSC, "inode %p get attr %llu", &vcookie->inode,
181 		   *size);
182 }
183 
184 static uint16_t v9fs_cache_inode_get_aux(const void *cookie_netfs_data,
185 					 void *buffer, uint16_t buflen)
186 {
187 	const struct v9fs_cookie *vcookie = cookie_netfs_data;
188 	memcpy(buffer, &vcookie->qid->version, sizeof(vcookie->qid->version));
189 
190 	P9_DPRINTK(P9_DEBUG_FSC, "inode %p get aux %u", &vcookie->inode,
191 		   vcookie->qid->version);
192 	return sizeof(vcookie->qid->version);
193 }
194 
195 static enum
196 fscache_checkaux v9fs_cache_inode_check_aux(void *cookie_netfs_data,
197 					    const void *buffer,
198 					    uint16_t buflen)
199 {
200 	const struct v9fs_cookie *vcookie = cookie_netfs_data;
201 
202 	if (buflen != sizeof(vcookie->qid->version))
203 		return FSCACHE_CHECKAUX_OBSOLETE;
204 
205 	if (memcmp(buffer, &vcookie->qid->version,
206 		   sizeof(vcookie->qid->version)))
207 		return FSCACHE_CHECKAUX_OBSOLETE;
208 
209 	return FSCACHE_CHECKAUX_OKAY;
210 }
211 
212 static void v9fs_cache_inode_now_uncached(void *cookie_netfs_data)
213 {
214 	struct v9fs_cookie *vcookie = cookie_netfs_data;
215 	struct pagevec pvec;
216 	pgoff_t first;
217 	int loop, nr_pages;
218 
219 	pagevec_init(&pvec, 0);
220 	first = 0;
221 
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;
228 
229 		for (loop = 0; loop < nr_pages; loop++)
230 			ClearPageFsCache(pvec.pages[loop]);
231 
232 		first = pvec.pages[nr_pages - 1]->index + 1;
233 
234 		pvec.nr = nr_pages;
235 		pagevec_release(&pvec);
236 		cond_resched();
237 	}
238 }
239 
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,
248 };
249 
250 void v9fs_cache_inode_get_cookie(struct inode *inode)
251 {
252 	struct v9fs_cookie *vcookie;
253 	struct v9fs_session_info *v9ses;
254 
255 	if (!S_ISREG(inode->i_mode))
256 		return;
257 
258 	vcookie = v9fs_inode2cookie(inode);
259 	if (vcookie->fscache)
260 		return;
261 
262 	v9ses = v9fs_inode2v9ses(inode);
263 	vcookie->fscache = fscache_acquire_cookie(v9ses->fscache,
264 						  &v9fs_cache_inode_index_def,
265 						  vcookie);
266 
267 	P9_DPRINTK(P9_DEBUG_FSC, "inode %p get cookie %p", inode,
268 		   vcookie->fscache);
269 }
270 
271 void v9fs_cache_inode_put_cookie(struct inode *inode)
272 {
273 	struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
274 
275 	if (!vcookie->fscache)
276 		return;
277 	P9_DPRINTK(P9_DEBUG_FSC, "inode %p put cookie %p", inode,
278 		   vcookie->fscache);
279 
280 	fscache_relinquish_cookie(vcookie->fscache, 0);
281 	vcookie->fscache = NULL;
282 }
283 
284 void v9fs_cache_inode_flush_cookie(struct inode *inode)
285 {
286 	struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
287 
288 	if (!vcookie->fscache)
289 		return;
290 	P9_DPRINTK(P9_DEBUG_FSC, "inode %p flush cookie %p", inode,
291 		   vcookie->fscache);
292 
293 	fscache_relinquish_cookie(vcookie->fscache, 1);
294 	vcookie->fscache = NULL;
295 }
296 
297 void v9fs_cache_inode_set_cookie(struct inode *inode, struct file *filp)
298 {
299 	struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
300 	struct p9_fid *fid;
301 
302 	if (!vcookie->fscache)
303 		return;
304 
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);
311 
312 	spin_unlock(&vcookie->lock);
313 }
314 
315 void v9fs_cache_inode_reset_cookie(struct inode *inode)
316 {
317 	struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
318 	struct v9fs_session_info *v9ses;
319 	struct fscache_cookie *old;
320 
321 	if (!vcookie->fscache)
322 		return;
323 
324 	old = vcookie->fscache;
325 
326 	spin_lock(&vcookie->lock);
327 	fscache_relinquish_cookie(vcookie->fscache, 1);
328 
329 	v9ses = v9fs_inode2v9ses(inode);
330 	vcookie->fscache = fscache_acquire_cookie(v9ses->fscache,
331 						  &v9fs_cache_inode_index_def,
332 						  vcookie);
333 
334 	P9_DPRINTK(P9_DEBUG_FSC, "inode %p revalidating cookie old %p new %p",
335 		   inode, old, vcookie->fscache);
336 
337 	spin_unlock(&vcookie->lock);
338 }
339 
340 int __v9fs_fscache_release_page(struct page *page, gfp_t gfp)
341 {
342 	struct inode *inode = page->mapping->host;
343 	struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
344 
345 	BUG_ON(!vcookie->fscache);
346 
347 	return fscache_maybe_release_page(vcookie->fscache, page, gfp);
348 }
349 
350 void __v9fs_fscache_invalidate_page(struct page *page)
351 {
352 	struct inode *inode = page->mapping->host;
353 	struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
354 
355 	BUG_ON(!vcookie->fscache);
356 
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);
361 	}
362 }
363 
364 static void v9fs_vfs_readpage_complete(struct page *page, void *data,
365 				       int error)
366 {
367 	if (!error)
368 		SetPageUptodate(page);
369 
370 	unlock_page(page);
371 }
372 
373 /**
374  * __v9fs_readpage_from_fscache - read a page from cache
375  *
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.
378  */
379 
380 int __v9fs_readpage_from_fscache(struct inode *inode, struct page *page)
381 {
382 	int ret;
383 	const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
384 
385 	P9_DPRINTK(P9_DEBUG_FSC, "inode %p page %p", inode, page);
386 	if (!vcookie->fscache)
387 		return -ENOBUFS;
388 
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;
405 	}
406 }
407 
408 /**
409  * __v9fs_readpages_from_fscache - read multiple pages from cache
410  *
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.
413  */
414 
415 int __v9fs_readpages_from_fscache(struct inode *inode,
416 				  struct address_space *mapping,
417 				  struct list_head *pages,
418 				  unsigned *nr_pages)
419 {
420 	int ret;
421 	const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
422 
423 	P9_DPRINTK(P9_DEBUG_FSC, "inode %p pages %u", inode, *nr_pages);
424 	if (!vcookie->fscache)
425 		return -ENOBUFS;
426 
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;
445 	}
446 }
447 
448 /**
449  * __v9fs_readpage_to_fscache - write a page to the cache
450  *
451  */
452 
453 void __v9fs_readpage_to_fscache(struct inode *inode, struct page *page)
454 {
455 	int ret;
456 	const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
457 
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);
463 }
464