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