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