xref: /linux/fs/9p/cache.c (revision 402cb8dda949d9b8c0df20ad2527d139faad7ca1)
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 fscache_netfs v9fs_cache_netfs = {
37 	.name 		= "9p",
38 	.version 	= 0,
39 };
40 
41 /**
42  * v9fs_random_cachetag - Generate a random tag to be associated
43  *			  with a new cache session.
44  *
45  * The value of jiffies is used for a fairly randomly cache tag.
46  */
47 
48 static
49 int v9fs_random_cachetag(struct v9fs_session_info *v9ses)
50 {
51 	v9ses->cachetag = kmalloc(CACHETAG_LEN, GFP_KERNEL);
52 	if (!v9ses->cachetag)
53 		return -ENOMEM;
54 
55 	return scnprintf(v9ses->cachetag, CACHETAG_LEN, "%lu", jiffies);
56 }
57 
58 const struct fscache_cookie_def v9fs_cache_session_index_def = {
59 	.name		= "9P.session",
60 	.type		= FSCACHE_COOKIE_TYPE_INDEX,
61 };
62 
63 void v9fs_cache_session_get_cookie(struct v9fs_session_info *v9ses)
64 {
65 	/* If no cache session tag was specified, we generate a random one. */
66 	if (!v9ses->cachetag) {
67 		if (v9fs_random_cachetag(v9ses) < 0) {
68 			v9ses->fscache = NULL;
69 			return;
70 		}
71 	}
72 
73 	v9ses->fscache = fscache_acquire_cookie(v9fs_cache_netfs.primary_index,
74 						&v9fs_cache_session_index_def,
75 						v9ses->cachetag,
76 						strlen(v9ses->cachetag),
77 						NULL, 0,
78 						v9ses, true);
79 	p9_debug(P9_DEBUG_FSC, "session %p get cookie %p\n",
80 		 v9ses, v9ses->fscache);
81 }
82 
83 void v9fs_cache_session_put_cookie(struct v9fs_session_info *v9ses)
84 {
85 	p9_debug(P9_DEBUG_FSC, "session %p put cookie %p\n",
86 		 v9ses, v9ses->fscache);
87 	fscache_relinquish_cookie(v9ses->fscache, NULL, false);
88 	v9ses->fscache = NULL;
89 }
90 
91 static void v9fs_cache_inode_get_attr(const void *cookie_netfs_data,
92 				      uint64_t *size)
93 {
94 	const struct v9fs_inode *v9inode = cookie_netfs_data;
95 	*size = i_size_read(&v9inode->vfs_inode);
96 
97 	p9_debug(P9_DEBUG_FSC, "inode %p get attr %llu\n",
98 		 &v9inode->vfs_inode, *size);
99 }
100 
101 static enum
102 fscache_checkaux v9fs_cache_inode_check_aux(void *cookie_netfs_data,
103 					    const void *buffer,
104 					    uint16_t buflen)
105 {
106 	const struct v9fs_inode *v9inode = cookie_netfs_data;
107 
108 	if (buflen != sizeof(v9inode->qid.version))
109 		return FSCACHE_CHECKAUX_OBSOLETE;
110 
111 	if (memcmp(buffer, &v9inode->qid.version,
112 		   sizeof(v9inode->qid.version)))
113 		return FSCACHE_CHECKAUX_OBSOLETE;
114 
115 	return FSCACHE_CHECKAUX_OKAY;
116 }
117 
118 const struct fscache_cookie_def v9fs_cache_inode_index_def = {
119 	.name		= "9p.inode",
120 	.type		= FSCACHE_COOKIE_TYPE_DATAFILE,
121 	.get_attr	= v9fs_cache_inode_get_attr,
122 	.check_aux	= v9fs_cache_inode_check_aux,
123 };
124 
125 void v9fs_cache_inode_get_cookie(struct inode *inode)
126 {
127 	struct v9fs_inode *v9inode;
128 	struct v9fs_session_info *v9ses;
129 
130 	if (!S_ISREG(inode->i_mode))
131 		return;
132 
133 	v9inode = V9FS_I(inode);
134 	if (v9inode->fscache)
135 		return;
136 
137 	v9ses = v9fs_inode2v9ses(inode);
138 	v9inode->fscache = fscache_acquire_cookie(v9ses->fscache,
139 						  &v9fs_cache_inode_index_def,
140 						  &v9inode->qid.path,
141 						  sizeof(v9inode->qid.path),
142 						  &v9inode->qid.version,
143 						  sizeof(v9inode->qid.version),
144 						  v9inode, true);
145 
146 	p9_debug(P9_DEBUG_FSC, "inode %p get cookie %p\n",
147 		 inode, v9inode->fscache);
148 }
149 
150 void v9fs_cache_inode_put_cookie(struct inode *inode)
151 {
152 	struct v9fs_inode *v9inode = V9FS_I(inode);
153 
154 	if (!v9inode->fscache)
155 		return;
156 	p9_debug(P9_DEBUG_FSC, "inode %p put cookie %p\n",
157 		 inode, v9inode->fscache);
158 
159 	fscache_relinquish_cookie(v9inode->fscache, &v9inode->qid.version,
160 				  false);
161 	v9inode->fscache = NULL;
162 }
163 
164 void v9fs_cache_inode_flush_cookie(struct inode *inode)
165 {
166 	struct v9fs_inode *v9inode = V9FS_I(inode);
167 
168 	if (!v9inode->fscache)
169 		return;
170 	p9_debug(P9_DEBUG_FSC, "inode %p flush cookie %p\n",
171 		 inode, v9inode->fscache);
172 
173 	fscache_relinquish_cookie(v9inode->fscache, NULL, true);
174 	v9inode->fscache = NULL;
175 }
176 
177 void v9fs_cache_inode_set_cookie(struct inode *inode, struct file *filp)
178 {
179 	struct v9fs_inode *v9inode = V9FS_I(inode);
180 
181 	if (!v9inode->fscache)
182 		return;
183 
184 	mutex_lock(&v9inode->fscache_lock);
185 
186 	if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
187 		v9fs_cache_inode_flush_cookie(inode);
188 	else
189 		v9fs_cache_inode_get_cookie(inode);
190 
191 	mutex_unlock(&v9inode->fscache_lock);
192 }
193 
194 void v9fs_cache_inode_reset_cookie(struct inode *inode)
195 {
196 	struct v9fs_inode *v9inode = V9FS_I(inode);
197 	struct v9fs_session_info *v9ses;
198 	struct fscache_cookie *old;
199 
200 	if (!v9inode->fscache)
201 		return;
202 
203 	old = v9inode->fscache;
204 
205 	mutex_lock(&v9inode->fscache_lock);
206 	fscache_relinquish_cookie(v9inode->fscache, NULL, true);
207 
208 	v9ses = v9fs_inode2v9ses(inode);
209 	v9inode->fscache = fscache_acquire_cookie(v9ses->fscache,
210 						  &v9fs_cache_inode_index_def,
211 						  &v9inode->qid.path,
212 						  sizeof(v9inode->qid.path),
213 						  &v9inode->qid.version,
214 						  sizeof(v9inode->qid.version),
215 						  v9inode, true);
216 	p9_debug(P9_DEBUG_FSC, "inode %p revalidating cookie old %p new %p\n",
217 		 inode, old, v9inode->fscache);
218 
219 	mutex_unlock(&v9inode->fscache_lock);
220 }
221 
222 int __v9fs_fscache_release_page(struct page *page, gfp_t gfp)
223 {
224 	struct inode *inode = page->mapping->host;
225 	struct v9fs_inode *v9inode = V9FS_I(inode);
226 
227 	BUG_ON(!v9inode->fscache);
228 
229 	return fscache_maybe_release_page(v9inode->fscache, page, gfp);
230 }
231 
232 void __v9fs_fscache_invalidate_page(struct page *page)
233 {
234 	struct inode *inode = page->mapping->host;
235 	struct v9fs_inode *v9inode = V9FS_I(inode);
236 
237 	BUG_ON(!v9inode->fscache);
238 
239 	if (PageFsCache(page)) {
240 		fscache_wait_on_page_write(v9inode->fscache, page);
241 		BUG_ON(!PageLocked(page));
242 		fscache_uncache_page(v9inode->fscache, page);
243 	}
244 }
245 
246 static void v9fs_vfs_readpage_complete(struct page *page, void *data,
247 				       int error)
248 {
249 	if (!error)
250 		SetPageUptodate(page);
251 
252 	unlock_page(page);
253 }
254 
255 /**
256  * __v9fs_readpage_from_fscache - read a page from cache
257  *
258  * Returns 0 if the pages are in cache and a BIO is submitted,
259  * 1 if the pages are not in cache and -error otherwise.
260  */
261 
262 int __v9fs_readpage_from_fscache(struct inode *inode, struct page *page)
263 {
264 	int ret;
265 	const struct v9fs_inode *v9inode = V9FS_I(inode);
266 
267 	p9_debug(P9_DEBUG_FSC, "inode %p page %p\n", inode, page);
268 	if (!v9inode->fscache)
269 		return -ENOBUFS;
270 
271 	ret = fscache_read_or_alloc_page(v9inode->fscache,
272 					 page,
273 					 v9fs_vfs_readpage_complete,
274 					 NULL,
275 					 GFP_KERNEL);
276 	switch (ret) {
277 	case -ENOBUFS:
278 	case -ENODATA:
279 		p9_debug(P9_DEBUG_FSC, "page/inode not in cache %d\n", ret);
280 		return 1;
281 	case 0:
282 		p9_debug(P9_DEBUG_FSC, "BIO submitted\n");
283 		return ret;
284 	default:
285 		p9_debug(P9_DEBUG_FSC, "ret %d\n", ret);
286 		return ret;
287 	}
288 }
289 
290 /**
291  * __v9fs_readpages_from_fscache - read multiple pages from cache
292  *
293  * Returns 0 if the pages are in cache and a BIO is submitted,
294  * 1 if the pages are not in cache and -error otherwise.
295  */
296 
297 int __v9fs_readpages_from_fscache(struct inode *inode,
298 				  struct address_space *mapping,
299 				  struct list_head *pages,
300 				  unsigned *nr_pages)
301 {
302 	int ret;
303 	const struct v9fs_inode *v9inode = V9FS_I(inode);
304 
305 	p9_debug(P9_DEBUG_FSC, "inode %p pages %u\n", inode, *nr_pages);
306 	if (!v9inode->fscache)
307 		return -ENOBUFS;
308 
309 	ret = fscache_read_or_alloc_pages(v9inode->fscache,
310 					  mapping, pages, nr_pages,
311 					  v9fs_vfs_readpage_complete,
312 					  NULL,
313 					  mapping_gfp_mask(mapping));
314 	switch (ret) {
315 	case -ENOBUFS:
316 	case -ENODATA:
317 		p9_debug(P9_DEBUG_FSC, "pages/inodes not in cache %d\n", ret);
318 		return 1;
319 	case 0:
320 		BUG_ON(!list_empty(pages));
321 		BUG_ON(*nr_pages != 0);
322 		p9_debug(P9_DEBUG_FSC, "BIO submitted\n");
323 		return ret;
324 	default:
325 		p9_debug(P9_DEBUG_FSC, "ret %d\n", ret);
326 		return ret;
327 	}
328 }
329 
330 /**
331  * __v9fs_readpage_to_fscache - write a page to the cache
332  *
333  */
334 
335 void __v9fs_readpage_to_fscache(struct inode *inode, struct page *page)
336 {
337 	int ret;
338 	const struct v9fs_inode *v9inode = V9FS_I(inode);
339 
340 	p9_debug(P9_DEBUG_FSC, "inode %p page %p\n", inode, page);
341 	ret = fscache_write_page(v9inode->fscache, page, GFP_KERNEL);
342 	p9_debug(P9_DEBUG_FSC, "ret =  %d\n", ret);
343 	if (ret != 0)
344 		v9fs_uncache_page(inode, page);
345 }
346 
347 /*
348  * wait for a page to complete writing to the cache
349  */
350 void __v9fs_fscache_wait_on_page_write(struct inode *inode, struct page *page)
351 {
352 	const struct v9fs_inode *v9inode = V9FS_I(inode);
353 	p9_debug(P9_DEBUG_FSC, "inode %p page %p\n", inode, page);
354 	if (PageFsCache(page))
355 		fscache_wait_on_page_write(v9inode->fscache, page);
356 }
357