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