1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * V9FS cache definitions. 4 * 5 * Copyright (C) 2009 by Abhishek Kulkarni <adkulkar@umail.iu.edu> 6 */ 7 8 #include <linux/jiffies.h> 9 #include <linux/file.h> 10 #include <linux/slab.h> 11 #include <linux/stat.h> 12 #include <linux/sched.h> 13 #include <linux/fs.h> 14 #include <net/9p/9p.h> 15 16 #include "v9fs.h" 17 #include "cache.h" 18 19 #define CACHETAG_LEN 11 20 21 struct fscache_netfs v9fs_cache_netfs = { 22 .name = "9p", 23 .version = 0, 24 }; 25 26 /* 27 * v9fs_random_cachetag - Generate a random tag to be associated 28 * with a new cache session. 29 * 30 * The value of jiffies is used for a fairly randomly cache tag. 31 */ 32 33 static 34 int v9fs_random_cachetag(struct v9fs_session_info *v9ses) 35 { 36 v9ses->cachetag = kmalloc(CACHETAG_LEN, GFP_KERNEL); 37 if (!v9ses->cachetag) 38 return -ENOMEM; 39 40 return scnprintf(v9ses->cachetag, CACHETAG_LEN, "%lu", jiffies); 41 } 42 43 const struct fscache_cookie_def v9fs_cache_session_index_def = { 44 .name = "9P.session", 45 .type = FSCACHE_COOKIE_TYPE_INDEX, 46 }; 47 48 void v9fs_cache_session_get_cookie(struct v9fs_session_info *v9ses) 49 { 50 /* If no cache session tag was specified, we generate a random one. */ 51 if (!v9ses->cachetag) { 52 if (v9fs_random_cachetag(v9ses) < 0) { 53 v9ses->fscache = NULL; 54 kfree(v9ses->cachetag); 55 v9ses->cachetag = NULL; 56 return; 57 } 58 } 59 60 v9ses->fscache = fscache_acquire_cookie(v9fs_cache_netfs.primary_index, 61 &v9fs_cache_session_index_def, 62 v9ses->cachetag, 63 strlen(v9ses->cachetag), 64 NULL, 0, 65 v9ses, 0, true); 66 p9_debug(P9_DEBUG_FSC, "session %p get cookie %p\n", 67 v9ses, v9ses->fscache); 68 } 69 70 void v9fs_cache_session_put_cookie(struct v9fs_session_info *v9ses) 71 { 72 p9_debug(P9_DEBUG_FSC, "session %p put cookie %p\n", 73 v9ses, v9ses->fscache); 74 fscache_relinquish_cookie(v9ses->fscache, NULL, false); 75 v9ses->fscache = NULL; 76 } 77 78 static enum 79 fscache_checkaux v9fs_cache_inode_check_aux(void *cookie_netfs_data, 80 const void *buffer, 81 uint16_t buflen, 82 loff_t object_size) 83 { 84 const struct v9fs_inode *v9inode = cookie_netfs_data; 85 86 if (buflen != sizeof(v9inode->qid.version)) 87 return FSCACHE_CHECKAUX_OBSOLETE; 88 89 if (memcmp(buffer, &v9inode->qid.version, 90 sizeof(v9inode->qid.version))) 91 return FSCACHE_CHECKAUX_OBSOLETE; 92 93 return FSCACHE_CHECKAUX_OKAY; 94 } 95 96 const struct fscache_cookie_def v9fs_cache_inode_index_def = { 97 .name = "9p.inode", 98 .type = FSCACHE_COOKIE_TYPE_DATAFILE, 99 .check_aux = v9fs_cache_inode_check_aux, 100 }; 101 102 void v9fs_cache_inode_get_cookie(struct inode *inode) 103 { 104 struct v9fs_inode *v9inode; 105 struct v9fs_session_info *v9ses; 106 107 if (!S_ISREG(inode->i_mode)) 108 return; 109 110 v9inode = V9FS_I(inode); 111 if (v9inode->fscache) 112 return; 113 114 v9ses = v9fs_inode2v9ses(inode); 115 v9inode->fscache = fscache_acquire_cookie(v9ses->fscache, 116 &v9fs_cache_inode_index_def, 117 &v9inode->qid.path, 118 sizeof(v9inode->qid.path), 119 &v9inode->qid.version, 120 sizeof(v9inode->qid.version), 121 v9inode, 122 i_size_read(&v9inode->vfs_inode), 123 true); 124 125 p9_debug(P9_DEBUG_FSC, "inode %p get cookie %p\n", 126 inode, v9inode->fscache); 127 } 128 129 void v9fs_cache_inode_put_cookie(struct inode *inode) 130 { 131 struct v9fs_inode *v9inode = V9FS_I(inode); 132 133 if (!v9inode->fscache) 134 return; 135 p9_debug(P9_DEBUG_FSC, "inode %p put cookie %p\n", 136 inode, v9inode->fscache); 137 138 fscache_relinquish_cookie(v9inode->fscache, &v9inode->qid.version, 139 false); 140 v9inode->fscache = NULL; 141 } 142 143 void v9fs_cache_inode_flush_cookie(struct inode *inode) 144 { 145 struct v9fs_inode *v9inode = V9FS_I(inode); 146 147 if (!v9inode->fscache) 148 return; 149 p9_debug(P9_DEBUG_FSC, "inode %p flush cookie %p\n", 150 inode, v9inode->fscache); 151 152 fscache_relinquish_cookie(v9inode->fscache, NULL, true); 153 v9inode->fscache = NULL; 154 } 155 156 void v9fs_cache_inode_set_cookie(struct inode *inode, struct file *filp) 157 { 158 struct v9fs_inode *v9inode = V9FS_I(inode); 159 160 if (!v9inode->fscache) 161 return; 162 163 mutex_lock(&v9inode->fscache_lock); 164 165 if ((filp->f_flags & O_ACCMODE) != O_RDONLY) 166 v9fs_cache_inode_flush_cookie(inode); 167 else 168 v9fs_cache_inode_get_cookie(inode); 169 170 mutex_unlock(&v9inode->fscache_lock); 171 } 172 173 void v9fs_cache_inode_reset_cookie(struct inode *inode) 174 { 175 struct v9fs_inode *v9inode = V9FS_I(inode); 176 struct v9fs_session_info *v9ses; 177 struct fscache_cookie *old; 178 179 if (!v9inode->fscache) 180 return; 181 182 old = v9inode->fscache; 183 184 mutex_lock(&v9inode->fscache_lock); 185 fscache_relinquish_cookie(v9inode->fscache, NULL, true); 186 187 v9ses = v9fs_inode2v9ses(inode); 188 v9inode->fscache = fscache_acquire_cookie(v9ses->fscache, 189 &v9fs_cache_inode_index_def, 190 &v9inode->qid.path, 191 sizeof(v9inode->qid.path), 192 &v9inode->qid.version, 193 sizeof(v9inode->qid.version), 194 v9inode, 195 i_size_read(&v9inode->vfs_inode), 196 true); 197 p9_debug(P9_DEBUG_FSC, "inode %p revalidating cookie old %p new %p\n", 198 inode, old, v9inode->fscache); 199 200 mutex_unlock(&v9inode->fscache_lock); 201 } 202