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 if (PageFsCache(page)) { 347 if (fscache_check_page_write(vcookie->fscache, page)) { 348 if (!(gfp & __GFP_WAIT)) 349 return 0; 350 fscache_wait_on_page_write(vcookie->fscache, page); 351 } 352 353 fscache_uncache_page(vcookie->fscache, page); 354 ClearPageFsCache(page); 355 } 356 357 return 1; 358 } 359 360 void __v9fs_fscache_invalidate_page(struct page *page) 361 { 362 struct inode *inode = page->mapping->host; 363 struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode); 364 365 BUG_ON(!vcookie->fscache); 366 367 if (PageFsCache(page)) { 368 fscache_wait_on_page_write(vcookie->fscache, page); 369 BUG_ON(!PageLocked(page)); 370 fscache_uncache_page(vcookie->fscache, page); 371 ClearPageFsCache(page); 372 } 373 } 374 375 static void v9fs_vfs_readpage_complete(struct page *page, void *data, 376 int error) 377 { 378 if (!error) 379 SetPageUptodate(page); 380 381 unlock_page(page); 382 } 383 384 /** 385 * __v9fs_readpage_from_fscache - read a page from cache 386 * 387 * Returns 0 if the pages are in cache and a BIO is submitted, 388 * 1 if the pages are not in cache and -error otherwise. 389 */ 390 391 int __v9fs_readpage_from_fscache(struct inode *inode, struct page *page) 392 { 393 int ret; 394 const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode); 395 396 P9_DPRINTK(P9_DEBUG_FSC, "inode %p page %p", inode, page); 397 if (!vcookie->fscache) 398 return -ENOBUFS; 399 400 ret = fscache_read_or_alloc_page(vcookie->fscache, 401 page, 402 v9fs_vfs_readpage_complete, 403 NULL, 404 GFP_KERNEL); 405 switch (ret) { 406 case -ENOBUFS: 407 case -ENODATA: 408 P9_DPRINTK(P9_DEBUG_FSC, "page/inode not in cache %d", ret); 409 return 1; 410 case 0: 411 P9_DPRINTK(P9_DEBUG_FSC, "BIO submitted"); 412 return ret; 413 default: 414 P9_DPRINTK(P9_DEBUG_FSC, "ret %d", ret); 415 return ret; 416 } 417 } 418 419 /** 420 * __v9fs_readpages_from_fscache - read multiple pages from cache 421 * 422 * Returns 0 if the pages are in cache and a BIO is submitted, 423 * 1 if the pages are not in cache and -error otherwise. 424 */ 425 426 int __v9fs_readpages_from_fscache(struct inode *inode, 427 struct address_space *mapping, 428 struct list_head *pages, 429 unsigned *nr_pages) 430 { 431 int ret; 432 const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode); 433 434 P9_DPRINTK(P9_DEBUG_FSC, "inode %p pages %u", inode, *nr_pages); 435 if (!vcookie->fscache) 436 return -ENOBUFS; 437 438 ret = fscache_read_or_alloc_pages(vcookie->fscache, 439 mapping, pages, nr_pages, 440 v9fs_vfs_readpage_complete, 441 NULL, 442 mapping_gfp_mask(mapping)); 443 switch (ret) { 444 case -ENOBUFS: 445 case -ENODATA: 446 P9_DPRINTK(P9_DEBUG_FSC, "pages/inodes not in cache %d", ret); 447 return 1; 448 case 0: 449 BUG_ON(!list_empty(pages)); 450 BUG_ON(*nr_pages != 0); 451 P9_DPRINTK(P9_DEBUG_FSC, "BIO submitted"); 452 return ret; 453 default: 454 P9_DPRINTK(P9_DEBUG_FSC, "ret %d", ret); 455 return ret; 456 } 457 } 458 459 /** 460 * __v9fs_readpage_to_fscache - write a page to the cache 461 * 462 */ 463 464 void __v9fs_readpage_to_fscache(struct inode *inode, struct page *page) 465 { 466 int ret; 467 const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode); 468 469 P9_DPRINTK(P9_DEBUG_FSC, "inode %p page %p", inode, page); 470 ret = fscache_write_page(vcookie->fscache, page, GFP_KERNEL); 471 P9_DPRINTK(P9_DEBUG_FSC, "ret = %d", ret); 472 if (ret != 0) 473 v9fs_uncache_page(inode, page); 474 } 475