memblock: replace memblock_alloc_base(ANYWHERE) with memblock_phys_alloc
[linux-2.6-microblaze.git] / fs / 9p / cache.c
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, 0, 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 enum
92 fscache_checkaux v9fs_cache_inode_check_aux(void *cookie_netfs_data,
93                                             const void *buffer,
94                                             uint16_t buflen,
95                                             loff_t object_size)
96 {
97         const struct v9fs_inode *v9inode = cookie_netfs_data;
98
99         if (buflen != sizeof(v9inode->qid.version))
100                 return FSCACHE_CHECKAUX_OBSOLETE;
101
102         if (memcmp(buffer, &v9inode->qid.version,
103                    sizeof(v9inode->qid.version)))
104                 return FSCACHE_CHECKAUX_OBSOLETE;
105
106         return FSCACHE_CHECKAUX_OKAY;
107 }
108
109 const struct fscache_cookie_def v9fs_cache_inode_index_def = {
110         .name           = "9p.inode",
111         .type           = FSCACHE_COOKIE_TYPE_DATAFILE,
112         .check_aux      = v9fs_cache_inode_check_aux,
113 };
114
115 void v9fs_cache_inode_get_cookie(struct inode *inode)
116 {
117         struct v9fs_inode *v9inode;
118         struct v9fs_session_info *v9ses;
119
120         if (!S_ISREG(inode->i_mode))
121                 return;
122
123         v9inode = V9FS_I(inode);
124         if (v9inode->fscache)
125                 return;
126
127         v9ses = v9fs_inode2v9ses(inode);
128         v9inode->fscache = fscache_acquire_cookie(v9ses->fscache,
129                                                   &v9fs_cache_inode_index_def,
130                                                   &v9inode->qid.path,
131                                                   sizeof(v9inode->qid.path),
132                                                   &v9inode->qid.version,
133                                                   sizeof(v9inode->qid.version),
134                                                   v9inode,
135                                                   i_size_read(&v9inode->vfs_inode),
136                                                   true);
137
138         p9_debug(P9_DEBUG_FSC, "inode %p get cookie %p\n",
139                  inode, v9inode->fscache);
140 }
141
142 void v9fs_cache_inode_put_cookie(struct inode *inode)
143 {
144         struct v9fs_inode *v9inode = V9FS_I(inode);
145
146         if (!v9inode->fscache)
147                 return;
148         p9_debug(P9_DEBUG_FSC, "inode %p put cookie %p\n",
149                  inode, v9inode->fscache);
150
151         fscache_relinquish_cookie(v9inode->fscache, &v9inode->qid.version,
152                                   false);
153         v9inode->fscache = NULL;
154 }
155
156 void v9fs_cache_inode_flush_cookie(struct inode *inode)
157 {
158         struct v9fs_inode *v9inode = V9FS_I(inode);
159
160         if (!v9inode->fscache)
161                 return;
162         p9_debug(P9_DEBUG_FSC, "inode %p flush cookie %p\n",
163                  inode, v9inode->fscache);
164
165         fscache_relinquish_cookie(v9inode->fscache, NULL, true);
166         v9inode->fscache = NULL;
167 }
168
169 void v9fs_cache_inode_set_cookie(struct inode *inode, struct file *filp)
170 {
171         struct v9fs_inode *v9inode = V9FS_I(inode);
172
173         if (!v9inode->fscache)
174                 return;
175
176         mutex_lock(&v9inode->fscache_lock);
177
178         if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
179                 v9fs_cache_inode_flush_cookie(inode);
180         else
181                 v9fs_cache_inode_get_cookie(inode);
182
183         mutex_unlock(&v9inode->fscache_lock);
184 }
185
186 void v9fs_cache_inode_reset_cookie(struct inode *inode)
187 {
188         struct v9fs_inode *v9inode = V9FS_I(inode);
189         struct v9fs_session_info *v9ses;
190         struct fscache_cookie *old;
191
192         if (!v9inode->fscache)
193                 return;
194
195         old = v9inode->fscache;
196
197         mutex_lock(&v9inode->fscache_lock);
198         fscache_relinquish_cookie(v9inode->fscache, NULL, true);
199
200         v9ses = v9fs_inode2v9ses(inode);
201         v9inode->fscache = fscache_acquire_cookie(v9ses->fscache,
202                                                   &v9fs_cache_inode_index_def,
203                                                   &v9inode->qid.path,
204                                                   sizeof(v9inode->qid.path),
205                                                   &v9inode->qid.version,
206                                                   sizeof(v9inode->qid.version),
207                                                   v9inode,
208                                                   i_size_read(&v9inode->vfs_inode),
209                                                   true);
210         p9_debug(P9_DEBUG_FSC, "inode %p revalidating cookie old %p new %p\n",
211                  inode, old, v9inode->fscache);
212
213         mutex_unlock(&v9inode->fscache_lock);
214 }
215
216 int __v9fs_fscache_release_page(struct page *page, gfp_t gfp)
217 {
218         struct inode *inode = page->mapping->host;
219         struct v9fs_inode *v9inode = V9FS_I(inode);
220
221         BUG_ON(!v9inode->fscache);
222
223         return fscache_maybe_release_page(v9inode->fscache, page, gfp);
224 }
225
226 void __v9fs_fscache_invalidate_page(struct page *page)
227 {
228         struct inode *inode = page->mapping->host;
229         struct v9fs_inode *v9inode = V9FS_I(inode);
230
231         BUG_ON(!v9inode->fscache);
232
233         if (PageFsCache(page)) {
234                 fscache_wait_on_page_write(v9inode->fscache, page);
235                 BUG_ON(!PageLocked(page));
236                 fscache_uncache_page(v9inode->fscache, page);
237         }
238 }
239
240 static void v9fs_vfs_readpage_complete(struct page *page, void *data,
241                                        int error)
242 {
243         if (!error)
244                 SetPageUptodate(page);
245
246         unlock_page(page);
247 }
248
249 /**
250  * __v9fs_readpage_from_fscache - read a page from cache
251  *
252  * Returns 0 if the pages are in cache and a BIO is submitted,
253  * 1 if the pages are not in cache and -error otherwise.
254  */
255
256 int __v9fs_readpage_from_fscache(struct inode *inode, struct page *page)
257 {
258         int ret;
259         const struct v9fs_inode *v9inode = V9FS_I(inode);
260
261         p9_debug(P9_DEBUG_FSC, "inode %p page %p\n", inode, page);
262         if (!v9inode->fscache)
263                 return -ENOBUFS;
264
265         ret = fscache_read_or_alloc_page(v9inode->fscache,
266                                          page,
267                                          v9fs_vfs_readpage_complete,
268                                          NULL,
269                                          GFP_KERNEL);
270         switch (ret) {
271         case -ENOBUFS:
272         case -ENODATA:
273                 p9_debug(P9_DEBUG_FSC, "page/inode not in cache %d\n", ret);
274                 return 1;
275         case 0:
276                 p9_debug(P9_DEBUG_FSC, "BIO submitted\n");
277                 return ret;
278         default:
279                 p9_debug(P9_DEBUG_FSC, "ret %d\n", ret);
280                 return ret;
281         }
282 }
283
284 /**
285  * __v9fs_readpages_from_fscache - read multiple pages from cache
286  *
287  * Returns 0 if the pages are in cache and a BIO is submitted,
288  * 1 if the pages are not in cache and -error otherwise.
289  */
290
291 int __v9fs_readpages_from_fscache(struct inode *inode,
292                                   struct address_space *mapping,
293                                   struct list_head *pages,
294                                   unsigned *nr_pages)
295 {
296         int ret;
297         const struct v9fs_inode *v9inode = V9FS_I(inode);
298
299         p9_debug(P9_DEBUG_FSC, "inode %p pages %u\n", inode, *nr_pages);
300         if (!v9inode->fscache)
301                 return -ENOBUFS;
302
303         ret = fscache_read_or_alloc_pages(v9inode->fscache,
304                                           mapping, pages, nr_pages,
305                                           v9fs_vfs_readpage_complete,
306                                           NULL,
307                                           mapping_gfp_mask(mapping));
308         switch (ret) {
309         case -ENOBUFS:
310         case -ENODATA:
311                 p9_debug(P9_DEBUG_FSC, "pages/inodes not in cache %d\n", ret);
312                 return 1;
313         case 0:
314                 BUG_ON(!list_empty(pages));
315                 BUG_ON(*nr_pages != 0);
316                 p9_debug(P9_DEBUG_FSC, "BIO submitted\n");
317                 return ret;
318         default:
319                 p9_debug(P9_DEBUG_FSC, "ret %d\n", ret);
320                 return ret;
321         }
322 }
323
324 /**
325  * __v9fs_readpage_to_fscache - write a page to the cache
326  *
327  */
328
329 void __v9fs_readpage_to_fscache(struct inode *inode, struct page *page)
330 {
331         int ret;
332         const struct v9fs_inode *v9inode = V9FS_I(inode);
333
334         p9_debug(P9_DEBUG_FSC, "inode %p page %p\n", inode, page);
335         ret = fscache_write_page(v9inode->fscache, page,
336                                  i_size_read(&v9inode->vfs_inode), GFP_KERNEL);
337         p9_debug(P9_DEBUG_FSC, "ret =  %d\n", ret);
338         if (ret != 0)
339                 v9fs_uncache_page(inode, page);
340 }
341
342 /*
343  * wait for a page to complete writing to the cache
344  */
345 void __v9fs_fscache_wait_on_page_write(struct inode *inode, struct page *page)
346 {
347         const struct v9fs_inode *v9inode = V9FS_I(inode);
348         p9_debug(P9_DEBUG_FSC, "inode %p page %p\n", inode, page);
349         if (PageFsCache(page))
350                 fscache_wait_on_page_write(v9inode->fscache, page);
351 }