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 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 48 static 49 int 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 58 const struct fscache_cookie_def v9fs_cache_session_index_def = { 59 .name = "9P.session", 60 .type = FSCACHE_COOKIE_TYPE_INDEX, 61 }; 62 63 void v9fs_cache_session_get_cookie(struct v9fs_session_info *v9ses) 64 { 65 /* If no cache session tag was specified, we generate a random one. */ 66 if (!v9ses->cachetag) { 67 if (v9fs_random_cachetag(v9ses) < 0) { 68 v9ses->fscache = NULL; 69 return; 70 } 71 } 72 73 v9ses->fscache = fscache_acquire_cookie(v9fs_cache_netfs.primary_index, 74 &v9fs_cache_session_index_def, 75 v9ses->cachetag, 76 strlen(v9ses->cachetag), 77 NULL, 0, 78 v9ses, true); 79 p9_debug(P9_DEBUG_FSC, "session %p get cookie %p\n", 80 v9ses, v9ses->fscache); 81 } 82 83 void v9fs_cache_session_put_cookie(struct v9fs_session_info *v9ses) 84 { 85 p9_debug(P9_DEBUG_FSC, "session %p put cookie %p\n", 86 v9ses, v9ses->fscache); 87 fscache_relinquish_cookie(v9ses->fscache, NULL, false); 88 v9ses->fscache = NULL; 89 } 90 91 static void v9fs_cache_inode_get_attr(const void *cookie_netfs_data, 92 uint64_t *size) 93 { 94 const struct v9fs_inode *v9inode = cookie_netfs_data; 95 *size = i_size_read(&v9inode->vfs_inode); 96 97 p9_debug(P9_DEBUG_FSC, "inode %p get attr %llu\n", 98 &v9inode->vfs_inode, *size); 99 } 100 101 static enum 102 fscache_checkaux v9fs_cache_inode_check_aux(void *cookie_netfs_data, 103 const void *buffer, 104 uint16_t buflen) 105 { 106 const struct v9fs_inode *v9inode = cookie_netfs_data; 107 108 if (buflen != sizeof(v9inode->qid.version)) 109 return FSCACHE_CHECKAUX_OBSOLETE; 110 111 if (memcmp(buffer, &v9inode->qid.version, 112 sizeof(v9inode->qid.version))) 113 return FSCACHE_CHECKAUX_OBSOLETE; 114 115 return FSCACHE_CHECKAUX_OKAY; 116 } 117 118 const struct fscache_cookie_def v9fs_cache_inode_index_def = { 119 .name = "9p.inode", 120 .type = FSCACHE_COOKIE_TYPE_DATAFILE, 121 .get_attr = v9fs_cache_inode_get_attr, 122 .check_aux = v9fs_cache_inode_check_aux, 123 }; 124 125 void v9fs_cache_inode_get_cookie(struct inode *inode) 126 { 127 struct v9fs_inode *v9inode; 128 struct v9fs_session_info *v9ses; 129 130 if (!S_ISREG(inode->i_mode)) 131 return; 132 133 v9inode = V9FS_I(inode); 134 if (v9inode->fscache) 135 return; 136 137 v9ses = v9fs_inode2v9ses(inode); 138 v9inode->fscache = fscache_acquire_cookie(v9ses->fscache, 139 &v9fs_cache_inode_index_def, 140 &v9inode->qid.path, 141 sizeof(v9inode->qid.path), 142 &v9inode->qid.version, 143 sizeof(v9inode->qid.version), 144 v9inode, true); 145 146 p9_debug(P9_DEBUG_FSC, "inode %p get cookie %p\n", 147 inode, v9inode->fscache); 148 } 149 150 void v9fs_cache_inode_put_cookie(struct inode *inode) 151 { 152 struct v9fs_inode *v9inode = V9FS_I(inode); 153 154 if (!v9inode->fscache) 155 return; 156 p9_debug(P9_DEBUG_FSC, "inode %p put cookie %p\n", 157 inode, v9inode->fscache); 158 159 fscache_relinquish_cookie(v9inode->fscache, &v9inode->qid.version, 160 false); 161 v9inode->fscache = NULL; 162 } 163 164 void v9fs_cache_inode_flush_cookie(struct inode *inode) 165 { 166 struct v9fs_inode *v9inode = V9FS_I(inode); 167 168 if (!v9inode->fscache) 169 return; 170 p9_debug(P9_DEBUG_FSC, "inode %p flush cookie %p\n", 171 inode, v9inode->fscache); 172 173 fscache_relinquish_cookie(v9inode->fscache, NULL, true); 174 v9inode->fscache = NULL; 175 } 176 177 void v9fs_cache_inode_set_cookie(struct inode *inode, struct file *filp) 178 { 179 struct v9fs_inode *v9inode = V9FS_I(inode); 180 181 if (!v9inode->fscache) 182 return; 183 184 mutex_lock(&v9inode->fscache_lock); 185 186 if ((filp->f_flags & O_ACCMODE) != O_RDONLY) 187 v9fs_cache_inode_flush_cookie(inode); 188 else 189 v9fs_cache_inode_get_cookie(inode); 190 191 mutex_unlock(&v9inode->fscache_lock); 192 } 193 194 void v9fs_cache_inode_reset_cookie(struct inode *inode) 195 { 196 struct v9fs_inode *v9inode = V9FS_I(inode); 197 struct v9fs_session_info *v9ses; 198 struct fscache_cookie *old; 199 200 if (!v9inode->fscache) 201 return; 202 203 old = v9inode->fscache; 204 205 mutex_lock(&v9inode->fscache_lock); 206 fscache_relinquish_cookie(v9inode->fscache, NULL, true); 207 208 v9ses = v9fs_inode2v9ses(inode); 209 v9inode->fscache = fscache_acquire_cookie(v9ses->fscache, 210 &v9fs_cache_inode_index_def, 211 &v9inode->qid.path, 212 sizeof(v9inode->qid.path), 213 &v9inode->qid.version, 214 sizeof(v9inode->qid.version), 215 v9inode, true); 216 p9_debug(P9_DEBUG_FSC, "inode %p revalidating cookie old %p new %p\n", 217 inode, old, v9inode->fscache); 218 219 mutex_unlock(&v9inode->fscache_lock); 220 } 221 222 int __v9fs_fscache_release_page(struct page *page, gfp_t gfp) 223 { 224 struct inode *inode = page->mapping->host; 225 struct v9fs_inode *v9inode = V9FS_I(inode); 226 227 BUG_ON(!v9inode->fscache); 228 229 return fscache_maybe_release_page(v9inode->fscache, page, gfp); 230 } 231 232 void __v9fs_fscache_invalidate_page(struct page *page) 233 { 234 struct inode *inode = page->mapping->host; 235 struct v9fs_inode *v9inode = V9FS_I(inode); 236 237 BUG_ON(!v9inode->fscache); 238 239 if (PageFsCache(page)) { 240 fscache_wait_on_page_write(v9inode->fscache, page); 241 BUG_ON(!PageLocked(page)); 242 fscache_uncache_page(v9inode->fscache, page); 243 } 244 } 245 246 static void v9fs_vfs_readpage_complete(struct page *page, void *data, 247 int error) 248 { 249 if (!error) 250 SetPageUptodate(page); 251 252 unlock_page(page); 253 } 254 255 /** 256 * __v9fs_readpage_from_fscache - read a page from cache 257 * 258 * Returns 0 if the pages are in cache and a BIO is submitted, 259 * 1 if the pages are not in cache and -error otherwise. 260 */ 261 262 int __v9fs_readpage_from_fscache(struct inode *inode, struct page *page) 263 { 264 int ret; 265 const struct v9fs_inode *v9inode = V9FS_I(inode); 266 267 p9_debug(P9_DEBUG_FSC, "inode %p page %p\n", inode, page); 268 if (!v9inode->fscache) 269 return -ENOBUFS; 270 271 ret = fscache_read_or_alloc_page(v9inode->fscache, 272 page, 273 v9fs_vfs_readpage_complete, 274 NULL, 275 GFP_KERNEL); 276 switch (ret) { 277 case -ENOBUFS: 278 case -ENODATA: 279 p9_debug(P9_DEBUG_FSC, "page/inode not in cache %d\n", ret); 280 return 1; 281 case 0: 282 p9_debug(P9_DEBUG_FSC, "BIO submitted\n"); 283 return ret; 284 default: 285 p9_debug(P9_DEBUG_FSC, "ret %d\n", ret); 286 return ret; 287 } 288 } 289 290 /** 291 * __v9fs_readpages_from_fscache - read multiple pages from cache 292 * 293 * Returns 0 if the pages are in cache and a BIO is submitted, 294 * 1 if the pages are not in cache and -error otherwise. 295 */ 296 297 int __v9fs_readpages_from_fscache(struct inode *inode, 298 struct address_space *mapping, 299 struct list_head *pages, 300 unsigned *nr_pages) 301 { 302 int ret; 303 const struct v9fs_inode *v9inode = V9FS_I(inode); 304 305 p9_debug(P9_DEBUG_FSC, "inode %p pages %u\n", inode, *nr_pages); 306 if (!v9inode->fscache) 307 return -ENOBUFS; 308 309 ret = fscache_read_or_alloc_pages(v9inode->fscache, 310 mapping, pages, nr_pages, 311 v9fs_vfs_readpage_complete, 312 NULL, 313 mapping_gfp_mask(mapping)); 314 switch (ret) { 315 case -ENOBUFS: 316 case -ENODATA: 317 p9_debug(P9_DEBUG_FSC, "pages/inodes not in cache %d\n", ret); 318 return 1; 319 case 0: 320 BUG_ON(!list_empty(pages)); 321 BUG_ON(*nr_pages != 0); 322 p9_debug(P9_DEBUG_FSC, "BIO submitted\n"); 323 return ret; 324 default: 325 p9_debug(P9_DEBUG_FSC, "ret %d\n", ret); 326 return ret; 327 } 328 } 329 330 /** 331 * __v9fs_readpage_to_fscache - write a page to the cache 332 * 333 */ 334 335 void __v9fs_readpage_to_fscache(struct inode *inode, struct page *page) 336 { 337 int ret; 338 const struct v9fs_inode *v9inode = V9FS_I(inode); 339 340 p9_debug(P9_DEBUG_FSC, "inode %p page %p\n", inode, page); 341 ret = fscache_write_page(v9inode->fscache, page, GFP_KERNEL); 342 p9_debug(P9_DEBUG_FSC, "ret = %d\n", ret); 343 if (ret != 0) 344 v9fs_uncache_page(inode, page); 345 } 346 347 /* 348 * wait for a page to complete writing to the cache 349 */ 350 void __v9fs_fscache_wait_on_page_write(struct inode *inode, struct page *page) 351 { 352 const struct v9fs_inode *v9inode = V9FS_I(inode); 353 p9_debug(P9_DEBUG_FSC, "inode %p page %p\n", inode, page); 354 if (PageFsCache(page)) 355 fscache_wait_on_page_write(v9inode->fscache, page); 356 } 357