ceph: improve fscache revalidation
[cascardo/linux.git] / fs / ceph / cache.c
1 /*
2  * Ceph cache definitions.
3  *
4  *  Copyright (C) 2013 by Adfin Solutions, Inc. All Rights Reserved.
5  *  Written by Milosz Tanski (milosz@adfin.com)
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2
9  *  as published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to:
18  *  Free Software Foundation
19  *  51 Franklin Street, Fifth Floor
20  *  Boston, MA  02111-1301  USA
21  *
22  */
23
24 #include "super.h"
25 #include "cache.h"
26
27 struct ceph_aux_inode {
28         struct timespec mtime;
29         loff_t          size;
30 };
31
32 struct fscache_netfs ceph_cache_netfs = {
33         .name           = "ceph",
34         .version        = 0,
35 };
36
37 static uint16_t ceph_fscache_session_get_key(const void *cookie_netfs_data,
38                                              void *buffer, uint16_t maxbuf)
39 {
40         const struct ceph_fs_client* fsc = cookie_netfs_data;
41         uint16_t klen;
42
43         klen = sizeof(fsc->client->fsid);
44         if (klen > maxbuf)
45                 return 0;
46
47         memcpy(buffer, &fsc->client->fsid, klen);
48         return klen;
49 }
50
51 static const struct fscache_cookie_def ceph_fscache_fsid_object_def = {
52         .name           = "CEPH.fsid",
53         .type           = FSCACHE_COOKIE_TYPE_INDEX,
54         .get_key        = ceph_fscache_session_get_key,
55 };
56
57 int ceph_fscache_register(void)
58 {
59         return fscache_register_netfs(&ceph_cache_netfs);
60 }
61
62 void ceph_fscache_unregister(void)
63 {
64         fscache_unregister_netfs(&ceph_cache_netfs);
65 }
66
67 int ceph_fscache_register_fs(struct ceph_fs_client* fsc)
68 {
69         fsc->fscache = fscache_acquire_cookie(ceph_cache_netfs.primary_index,
70                                               &ceph_fscache_fsid_object_def,
71                                               fsc, true);
72         if (!fsc->fscache)
73                 pr_err("Unable to resgister fsid: %p fscache cookie", fsc);
74
75         return 0;
76 }
77
78 static uint16_t ceph_fscache_inode_get_key(const void *cookie_netfs_data,
79                                            void *buffer, uint16_t maxbuf)
80 {
81         const struct ceph_inode_info* ci = cookie_netfs_data;
82         uint16_t klen;
83
84         /* use ceph virtual inode (id + snapshot) */
85         klen = sizeof(ci->i_vino);
86         if (klen > maxbuf)
87                 return 0;
88
89         memcpy(buffer, &ci->i_vino, klen);
90         return klen;
91 }
92
93 static uint16_t ceph_fscache_inode_get_aux(const void *cookie_netfs_data,
94                                            void *buffer, uint16_t bufmax)
95 {
96         struct ceph_aux_inode aux;
97         const struct ceph_inode_info* ci = cookie_netfs_data;
98         const struct inode* inode = &ci->vfs_inode;
99
100         memset(&aux, 0, sizeof(aux));
101         aux.mtime = inode->i_mtime;
102         aux.size = i_size_read(inode);
103
104         memcpy(buffer, &aux, sizeof(aux));
105
106         return sizeof(aux);
107 }
108
109 static void ceph_fscache_inode_get_attr(const void *cookie_netfs_data,
110                                         uint64_t *size)
111 {
112         const struct ceph_inode_info* ci = cookie_netfs_data;
113         *size = i_size_read(&ci->vfs_inode);
114 }
115
116 static enum fscache_checkaux ceph_fscache_inode_check_aux(
117         void *cookie_netfs_data, const void *data, uint16_t dlen)
118 {
119         struct ceph_aux_inode aux;
120         struct ceph_inode_info* ci = cookie_netfs_data;
121         struct inode* inode = &ci->vfs_inode;
122
123         if (dlen != sizeof(aux))
124                 return FSCACHE_CHECKAUX_OBSOLETE;
125
126         memset(&aux, 0, sizeof(aux));
127         aux.mtime = inode->i_mtime;
128         aux.size = i_size_read(inode);
129
130         if (memcmp(data, &aux, sizeof(aux)) != 0)
131                 return FSCACHE_CHECKAUX_OBSOLETE;
132
133         dout("ceph inode 0x%p cached okay", ci);
134         return FSCACHE_CHECKAUX_OKAY;
135 }
136
137 static void ceph_fscache_inode_now_uncached(void* cookie_netfs_data)
138 {
139         struct ceph_inode_info* ci = cookie_netfs_data;
140         struct pagevec pvec;
141         pgoff_t first;
142         int loop, nr_pages;
143
144         pagevec_init(&pvec, 0);
145         first = 0;
146
147         dout("ceph inode 0x%p now uncached", ci);
148
149         while (1) {
150                 nr_pages = pagevec_lookup(&pvec, ci->vfs_inode.i_mapping, first,
151                                           PAGEVEC_SIZE - pagevec_count(&pvec));
152
153                 if (!nr_pages)
154                         break;
155
156                 for (loop = 0; loop < nr_pages; loop++)
157                         ClearPageFsCache(pvec.pages[loop]);
158
159                 first = pvec.pages[nr_pages - 1]->index + 1;
160
161                 pvec.nr = nr_pages;
162                 pagevec_release(&pvec);
163                 cond_resched();
164         }
165 }
166
167 static const struct fscache_cookie_def ceph_fscache_inode_object_def = {
168         .name           = "CEPH.inode",
169         .type           = FSCACHE_COOKIE_TYPE_DATAFILE,
170         .get_key        = ceph_fscache_inode_get_key,
171         .get_attr       = ceph_fscache_inode_get_attr,
172         .get_aux        = ceph_fscache_inode_get_aux,
173         .check_aux      = ceph_fscache_inode_check_aux,
174         .now_uncached   = ceph_fscache_inode_now_uncached,
175 };
176
177 void ceph_fscache_register_inode_cookie(struct inode *inode)
178 {
179         struct ceph_inode_info *ci = ceph_inode(inode);
180         struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
181
182         /* No caching for filesystem */
183         if (fsc->fscache == NULL)
184                 return;
185
186         /* Only cache for regular files that are read only */
187         if (!S_ISREG(inode->i_mode))
188                 return;
189
190         inode_lock_nested(inode, I_MUTEX_CHILD);
191         if (!ci->fscache) {
192                 ci->fscache = fscache_acquire_cookie(fsc->fscache,
193                                         &ceph_fscache_inode_object_def,
194                                         ci, false);
195         }
196         inode_unlock(inode);
197 }
198
199 void ceph_fscache_unregister_inode_cookie(struct ceph_inode_info* ci)
200 {
201         struct fscache_cookie* cookie;
202
203         if ((cookie = ci->fscache) == NULL)
204                 return;
205
206         ci->fscache = NULL;
207
208         fscache_uncache_all_inode_pages(cookie, &ci->vfs_inode);
209         fscache_relinquish_cookie(cookie, 0);
210 }
211
212 static bool ceph_fscache_can_enable(void *data)
213 {
214         struct inode *inode = data;
215         return !inode_is_open_for_write(inode);
216 }
217
218 void ceph_fscache_file_set_cookie(struct inode *inode, struct file *filp)
219 {
220         struct ceph_inode_info *ci = ceph_inode(inode);
221
222         if (!fscache_cookie_valid(ci->fscache))
223                 return;
224
225         if (inode_is_open_for_write(inode)) {
226                 dout("fscache_file_set_cookie %p %p disabling cache\n",
227                      inode, filp);
228                 fscache_disable_cookie(ci->fscache, false);
229                 fscache_uncache_all_inode_pages(ci->fscache, inode);
230         } else {
231                 fscache_enable_cookie(ci->fscache, ceph_fscache_can_enable,
232                                 inode);
233                 if (fscache_cookie_enabled(ci->fscache)) {
234                         dout("fscache_file_set_cookie %p %p enabing cache\n",
235                              inode, filp);
236                 }
237         }
238 }
239
240 static void ceph_vfs_readpage_complete(struct page *page, void *data, int error)
241 {
242         if (!error)
243                 SetPageUptodate(page);
244 }
245
246 static void ceph_vfs_readpage_complete_unlock(struct page *page, void *data, int error)
247 {
248         if (!error)
249                 SetPageUptodate(page);
250
251         unlock_page(page);
252 }
253
254 static inline bool cache_valid(struct ceph_inode_info *ci)
255 {
256         return ci->i_fscache_gen == ci->i_rdcache_gen;
257 }
258
259
260 /* Atempt to read from the fscache,
261  *
262  * This function is called from the readpage_nounlock context. DO NOT attempt to
263  * unlock the page here (or in the callback).
264  */
265 int ceph_readpage_from_fscache(struct inode *inode, struct page *page)
266 {
267         struct ceph_inode_info *ci = ceph_inode(inode);
268         int ret;
269
270         if (!cache_valid(ci))
271                 return -ENOBUFS;
272
273         ret = fscache_read_or_alloc_page(ci->fscache, page,
274                                          ceph_vfs_readpage_complete, NULL,
275                                          GFP_KERNEL);
276
277         switch (ret) {
278                 case 0: /* Page found */
279                         dout("page read submitted\n");
280                         return 0;
281                 case -ENOBUFS: /* Pages were not found, and can't be */
282                 case -ENODATA: /* Pages were not found */
283                         dout("page/inode not in cache\n");
284                         return ret;
285                 default:
286                         dout("%s: unknown error ret = %i\n", __func__, ret);
287                         return ret;
288         }
289 }
290
291 int ceph_readpages_from_fscache(struct inode *inode,
292                                   struct address_space *mapping,
293                                   struct list_head *pages,
294                                   unsigned *nr_pages)
295 {
296         struct ceph_inode_info *ci = ceph_inode(inode);
297         int ret;
298
299         if (!cache_valid(ci))
300                 return -ENOBUFS;
301
302         ret = fscache_read_or_alloc_pages(ci->fscache, mapping, pages, nr_pages,
303                                           ceph_vfs_readpage_complete_unlock,
304                                           NULL, mapping_gfp_mask(mapping));
305
306         switch (ret) {
307                 case 0: /* All pages found */
308                         dout("all-page read submitted\n");
309                         return 0;
310                 case -ENOBUFS: /* Some pages were not found, and can't be */
311                 case -ENODATA: /* some pages were not found */
312                         dout("page/inode not in cache\n");
313                         return ret;
314                 default:
315                         dout("%s: unknown error ret = %i\n", __func__, ret);
316                         return ret;
317         }
318 }
319
320 void ceph_readpage_to_fscache(struct inode *inode, struct page *page)
321 {
322         struct ceph_inode_info *ci = ceph_inode(inode);
323         int ret;
324
325         if (!PageFsCache(page))
326                 return;
327
328         if (!cache_valid(ci))
329                 return;
330
331         ret = fscache_write_page(ci->fscache, page, GFP_KERNEL);
332         if (ret)
333                  fscache_uncache_page(ci->fscache, page);
334 }
335
336 void ceph_invalidate_fscache_page(struct inode* inode, struct page *page)
337 {
338         struct ceph_inode_info *ci = ceph_inode(inode);
339
340         if (!PageFsCache(page))
341                 return;
342
343         fscache_wait_on_page_write(ci->fscache, page);
344         fscache_uncache_page(ci->fscache, page);
345 }
346
347 void ceph_fscache_unregister_fs(struct ceph_fs_client* fsc)
348 {
349         fscache_relinquish_cookie(fsc->fscache, 0);
350         fsc->fscache = NULL;
351 }
352
353 /*
354  * caller should hold CEPH_CAP_FILE_{RD,CACHE}
355  */
356 void ceph_fscache_revalidate_cookie(struct ceph_inode_info *ci)
357 {
358         if (cache_valid(ci))
359                 return;
360
361         /* resue i_truncate_mutex. There should be no pending
362          * truncate while the caller holds CEPH_CAP_FILE_RD */
363         mutex_lock(&ci->i_truncate_mutex);
364         if (!cache_valid(ci)) {
365                 if (fscache_check_consistency(ci->fscache))
366                         fscache_invalidate(ci->fscache);
367                 spin_lock(&ci->i_ceph_lock);
368                 ci->i_fscache_gen = ci->i_rdcache_gen;
369                 spin_unlock(&ci->i_ceph_lock);
370         }
371         mutex_unlock(&ci->i_truncate_mutex);
372 }