Btrfs: finish read pages in the order they are submitted
[linux-2.6.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/stat.h>
26 #include <linux/sched.h>
27 #include <linux/fs.h>
28 #include <net/9p/9p.h>
29
30 #include "v9fs.h"
31 #include "cache.h"
32
33 #define CACHETAG_LEN  11
34
35 struct kmem_cache *vcookie_cache;
36
37 struct fscache_netfs v9fs_cache_netfs = {
38         .name           = "9p",
39         .version        = 0,
40 };
41
42 static void init_once(void *foo)
43 {
44         struct v9fs_cookie *vcookie = (struct v9fs_cookie *) foo;
45         vcookie->fscache = NULL;
46         vcookie->qid = NULL;
47         inode_init_once(&vcookie->inode);
48 }
49
50 /**
51  * v9fs_init_vcookiecache - initialize a cache for vcookies to maintain
52  *                          vcookie to inode mapping
53  *
54  * Returns 0 on success.
55  */
56
57 static int v9fs_init_vcookiecache(void)
58 {
59         vcookie_cache = kmem_cache_create("vcookie_cache",
60                                           sizeof(struct v9fs_cookie),
61                                           0, (SLAB_RECLAIM_ACCOUNT|
62                                               SLAB_MEM_SPREAD),
63                                           init_once);
64         if (!vcookie_cache)
65                 return -ENOMEM;
66
67         return 0;
68 }
69
70 /**
71  * v9fs_destroy_vcookiecache - destroy the cache of vcookies
72  *
73  */
74
75 static void v9fs_destroy_vcookiecache(void)
76 {
77         kmem_cache_destroy(vcookie_cache);
78 }
79
80 int __v9fs_cache_register(void)
81 {
82         int ret;
83         ret = v9fs_init_vcookiecache();
84         if (ret < 0)
85                 return ret;
86
87         return fscache_register_netfs(&v9fs_cache_netfs);
88 }
89
90 void __v9fs_cache_unregister(void)
91 {
92         v9fs_destroy_vcookiecache();
93         fscache_unregister_netfs(&v9fs_cache_netfs);
94 }
95
96 /**
97  * v9fs_random_cachetag - Generate a random tag to be associated
98  *                        with a new cache session.
99  *
100  * The value of jiffies is used for a fairly randomly cache tag.
101  */
102
103 static
104 int v9fs_random_cachetag(struct v9fs_session_info *v9ses)
105 {
106         v9ses->cachetag = kmalloc(CACHETAG_LEN, GFP_KERNEL);
107         if (!v9ses->cachetag)
108                 return -ENOMEM;
109
110         return scnprintf(v9ses->cachetag, CACHETAG_LEN, "%lu", jiffies);
111 }
112
113 static uint16_t v9fs_cache_session_get_key(const void *cookie_netfs_data,
114                                            void *buffer, uint16_t bufmax)
115 {
116         struct v9fs_session_info *v9ses;
117         uint16_t klen = 0;
118
119         v9ses = (struct v9fs_session_info *)cookie_netfs_data;
120         P9_DPRINTK(P9_DEBUG_FSC, "session %p buf %p size %u", v9ses,
121                    buffer, bufmax);
122
123         if (v9ses->cachetag)
124                 klen = strlen(v9ses->cachetag);
125
126         if (klen > bufmax)
127                 return 0;
128
129         memcpy(buffer, v9ses->cachetag, klen);
130         P9_DPRINTK(P9_DEBUG_FSC, "cache session tag %s", v9ses->cachetag);
131         return klen;
132 }
133
134 const struct fscache_cookie_def v9fs_cache_session_index_def = {
135         .name           = "9P.session",
136         .type           = FSCACHE_COOKIE_TYPE_INDEX,
137         .get_key        = v9fs_cache_session_get_key,
138 };
139
140 void v9fs_cache_session_get_cookie(struct v9fs_session_info *v9ses)
141 {
142         /* If no cache session tag was specified, we generate a random one. */
143         if (!v9ses->cachetag)
144                 v9fs_random_cachetag(v9ses);
145
146         v9ses->fscache = fscache_acquire_cookie(v9fs_cache_netfs.primary_index,
147                                                 &v9fs_cache_session_index_def,
148                                                 v9ses);
149         P9_DPRINTK(P9_DEBUG_FSC, "session %p get cookie %p", v9ses,
150                    v9ses->fscache);
151 }
152
153 void v9fs_cache_session_put_cookie(struct v9fs_session_info *v9ses)
154 {
155         P9_DPRINTK(P9_DEBUG_FSC, "session %p put cookie %p", v9ses,
156                    v9ses->fscache);
157         fscache_relinquish_cookie(v9ses->fscache, 0);
158         v9ses->fscache = NULL;
159 }
160
161
162 static uint16_t v9fs_cache_inode_get_key(const void *cookie_netfs_data,
163                                          void *buffer, uint16_t bufmax)
164 {
165         const struct v9fs_cookie *vcookie = cookie_netfs_data;
166         memcpy(buffer, &vcookie->qid->path, sizeof(vcookie->qid->path));
167
168         P9_DPRINTK(P9_DEBUG_FSC, "inode %p get key %llu", &vcookie->inode,
169                    vcookie->qid->path);
170         return sizeof(vcookie->qid->path);
171 }
172
173 static void v9fs_cache_inode_get_attr(const void *cookie_netfs_data,
174                                       uint64_t *size)
175 {
176         const struct v9fs_cookie *vcookie = cookie_netfs_data;
177         *size = i_size_read(&vcookie->inode);
178
179         P9_DPRINTK(P9_DEBUG_FSC, "inode %p get attr %llu", &vcookie->inode,
180                    *size);
181 }
182
183 static uint16_t v9fs_cache_inode_get_aux(const void *cookie_netfs_data,
184                                          void *buffer, uint16_t buflen)
185 {
186         const struct v9fs_cookie *vcookie = cookie_netfs_data;
187         memcpy(buffer, &vcookie->qid->version, sizeof(vcookie->qid->version));
188
189         P9_DPRINTK(P9_DEBUG_FSC, "inode %p get aux %u", &vcookie->inode,
190                    vcookie->qid->version);
191         return sizeof(vcookie->qid->version);
192 }
193
194 static enum
195 fscache_checkaux v9fs_cache_inode_check_aux(void *cookie_netfs_data,
196                                             const void *buffer,
197                                             uint16_t buflen)
198 {
199         const struct v9fs_cookie *vcookie = cookie_netfs_data;
200
201         if (buflen != sizeof(vcookie->qid->version))
202                 return FSCACHE_CHECKAUX_OBSOLETE;
203
204         if (memcmp(buffer, &vcookie->qid->version,
205                    sizeof(vcookie->qid->version)))
206                 return FSCACHE_CHECKAUX_OBSOLETE;
207
208         return FSCACHE_CHECKAUX_OKAY;
209 }
210
211 static void v9fs_cache_inode_now_uncached(void *cookie_netfs_data)
212 {
213         struct v9fs_cookie *vcookie = cookie_netfs_data;
214         struct pagevec pvec;
215         pgoff_t first;
216         int loop, nr_pages;
217
218         pagevec_init(&pvec, 0);
219         first = 0;
220
221         for (;;) {
222                 nr_pages = pagevec_lookup(&pvec, vcookie->inode.i_mapping,
223                                           first,
224                                           PAGEVEC_SIZE - pagevec_count(&pvec));
225                 if (!nr_pages)
226                         break;
227
228                 for (loop = 0; loop < nr_pages; loop++)
229                         ClearPageFsCache(pvec.pages[loop]);
230
231                 first = pvec.pages[nr_pages - 1]->index + 1;
232
233                 pvec.nr = nr_pages;
234                 pagevec_release(&pvec);
235                 cond_resched();
236         }
237 }
238
239 const struct fscache_cookie_def v9fs_cache_inode_index_def = {
240         .name           = "9p.inode",
241         .type           = FSCACHE_COOKIE_TYPE_DATAFILE,
242         .get_key        = v9fs_cache_inode_get_key,
243         .get_attr       = v9fs_cache_inode_get_attr,
244         .get_aux        = v9fs_cache_inode_get_aux,
245         .check_aux      = v9fs_cache_inode_check_aux,
246         .now_uncached   = v9fs_cache_inode_now_uncached,
247 };
248
249 void v9fs_cache_inode_get_cookie(struct inode *inode)
250 {
251         struct v9fs_cookie *vcookie;
252         struct v9fs_session_info *v9ses;
253
254         if (!S_ISREG(inode->i_mode))
255                 return;
256
257         vcookie = v9fs_inode2cookie(inode);
258         if (vcookie->fscache)
259                 return;
260
261         v9ses = v9fs_inode2v9ses(inode);
262         vcookie->fscache = fscache_acquire_cookie(v9ses->fscache,
263                                                   &v9fs_cache_inode_index_def,
264                                                   vcookie);
265
266         P9_DPRINTK(P9_DEBUG_FSC, "inode %p get cookie %p", inode,
267                    vcookie->fscache);
268 }
269
270 void v9fs_cache_inode_put_cookie(struct inode *inode)
271 {
272         struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
273
274         if (!vcookie->fscache)
275                 return;
276         P9_DPRINTK(P9_DEBUG_FSC, "inode %p put cookie %p", inode,
277                    vcookie->fscache);
278
279         fscache_relinquish_cookie(vcookie->fscache, 0);
280         vcookie->fscache = NULL;
281 }
282
283 void v9fs_cache_inode_flush_cookie(struct inode *inode)
284 {
285         struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
286
287         if (!vcookie->fscache)
288                 return;
289         P9_DPRINTK(P9_DEBUG_FSC, "inode %p flush cookie %p", inode,
290                    vcookie->fscache);
291
292         fscache_relinquish_cookie(vcookie->fscache, 1);
293         vcookie->fscache = NULL;
294 }
295
296 void v9fs_cache_inode_set_cookie(struct inode *inode, struct file *filp)
297 {
298         struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
299         struct p9_fid *fid;
300
301         if (!vcookie->fscache)
302                 return;
303
304         spin_lock(&vcookie->lock);
305         fid = filp->private_data;
306         if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
307                 v9fs_cache_inode_flush_cookie(inode);
308         else
309                 v9fs_cache_inode_get_cookie(inode);
310
311         spin_unlock(&vcookie->lock);
312 }
313
314 void v9fs_cache_inode_reset_cookie(struct inode *inode)
315 {
316         struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
317         struct v9fs_session_info *v9ses;
318         struct fscache_cookie *old;
319
320         if (!vcookie->fscache)
321                 return;
322
323         old = vcookie->fscache;
324
325         spin_lock(&vcookie->lock);
326         fscache_relinquish_cookie(vcookie->fscache, 1);
327
328         v9ses = v9fs_inode2v9ses(inode);
329         vcookie->fscache = fscache_acquire_cookie(v9ses->fscache,
330                                                   &v9fs_cache_inode_index_def,
331                                                   vcookie);
332
333         P9_DPRINTK(P9_DEBUG_FSC, "inode %p revalidating cookie old %p new %p",
334                    inode, old, vcookie->fscache);
335
336         spin_unlock(&vcookie->lock);
337 }
338
339 int __v9fs_fscache_release_page(struct page *page, gfp_t gfp)
340 {
341         struct inode *inode = page->mapping->host;
342         struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
343
344         BUG_ON(!vcookie->fscache);
345
346         return fscache_maybe_release_page(vcookie->fscache, page, gfp);
347 }
348
349 void __v9fs_fscache_invalidate_page(struct page *page)
350 {
351         struct inode *inode = page->mapping->host;
352         struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
353
354         BUG_ON(!vcookie->fscache);
355
356         if (PageFsCache(page)) {
357                 fscache_wait_on_page_write(vcookie->fscache, page);
358                 BUG_ON(!PageLocked(page));
359                 fscache_uncache_page(vcookie->fscache, page);
360         }
361 }
362
363 static void v9fs_vfs_readpage_complete(struct page *page, void *data,
364                                        int error)
365 {
366         if (!error)
367                 SetPageUptodate(page);
368
369         unlock_page(page);
370 }
371
372 /**
373  * __v9fs_readpage_from_fscache - read a page from cache
374  *
375  * Returns 0 if the pages are in cache and a BIO is submitted,
376  * 1 if the pages are not in cache and -error otherwise.
377  */
378
379 int __v9fs_readpage_from_fscache(struct inode *inode, struct page *page)
380 {
381         int ret;
382         const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
383
384         P9_DPRINTK(P9_DEBUG_FSC, "inode %p page %p", inode, page);
385         if (!vcookie->fscache)
386                 return -ENOBUFS;
387
388         ret = fscache_read_or_alloc_page(vcookie->fscache,
389                                          page,
390                                          v9fs_vfs_readpage_complete,
391                                          NULL,
392                                          GFP_KERNEL);
393         switch (ret) {
394         case -ENOBUFS:
395         case -ENODATA:
396                 P9_DPRINTK(P9_DEBUG_FSC, "page/inode not in cache %d", ret);
397                 return 1;
398         case 0:
399                 P9_DPRINTK(P9_DEBUG_FSC, "BIO submitted");
400                 return ret;
401         default:
402                 P9_DPRINTK(P9_DEBUG_FSC, "ret %d", ret);
403                 return ret;
404         }
405 }
406
407 /**
408  * __v9fs_readpages_from_fscache - read multiple pages from cache
409  *
410  * Returns 0 if the pages are in cache and a BIO is submitted,
411  * 1 if the pages are not in cache and -error otherwise.
412  */
413
414 int __v9fs_readpages_from_fscache(struct inode *inode,
415                                   struct address_space *mapping,
416                                   struct list_head *pages,
417                                   unsigned *nr_pages)
418 {
419         int ret;
420         const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
421
422         P9_DPRINTK(P9_DEBUG_FSC, "inode %p pages %u", inode, *nr_pages);
423         if (!vcookie->fscache)
424                 return -ENOBUFS;
425
426         ret = fscache_read_or_alloc_pages(vcookie->fscache,
427                                           mapping, pages, nr_pages,
428                                           v9fs_vfs_readpage_complete,
429                                           NULL,
430                                           mapping_gfp_mask(mapping));
431         switch (ret) {
432         case -ENOBUFS:
433         case -ENODATA:
434                 P9_DPRINTK(P9_DEBUG_FSC, "pages/inodes not in cache %d", ret);
435                 return 1;
436         case 0:
437                 BUG_ON(!list_empty(pages));
438                 BUG_ON(*nr_pages != 0);
439                 P9_DPRINTK(P9_DEBUG_FSC, "BIO submitted");
440                 return ret;
441         default:
442                 P9_DPRINTK(P9_DEBUG_FSC, "ret %d", ret);
443                 return ret;
444         }
445 }
446
447 /**
448  * __v9fs_readpage_to_fscache - write a page to the cache
449  *
450  */
451
452 void __v9fs_readpage_to_fscache(struct inode *inode, struct page *page)
453 {
454         int ret;
455         const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
456
457         P9_DPRINTK(P9_DEBUG_FSC, "inode %p page %p", inode, page);
458         ret = fscache_write_page(vcookie->fscache, page, GFP_KERNEL);
459         P9_DPRINTK(P9_DEBUG_FSC, "ret =  %d", ret);
460         if (ret != 0)
461                 v9fs_uncache_page(inode, page);
462 }