1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Ceph cache definitions. 4 * 5 * Copyright (C) 2013 by Adfin Solutions, Inc. All Rights Reserved. 6 * Written by Milosz Tanski (milosz@adfin.com) 7 */ 8 9 #include <linux/ceph/ceph_debug.h> 10 11 #include <linux/fs_context.h> 12 #include "super.h" 13 #include "cache.h" 14 15 struct fscache_netfs ceph_cache_netfs = { 16 .name = "ceph", 17 .version = 0, 18 }; 19 20 static DEFINE_MUTEX(ceph_fscache_lock); 21 static LIST_HEAD(ceph_fscache_list); 22 23 struct ceph_fscache_entry { 24 struct list_head list; 25 struct fscache_cookie *fscache; 26 size_t uniq_len; 27 /* The following members must be last */ 28 struct ceph_fsid fsid; 29 char uniquifier[]; 30 }; 31 32 static const struct fscache_cookie_def ceph_fscache_fsid_object_def = { 33 .name = "CEPH.fsid", 34 .type = FSCACHE_COOKIE_TYPE_INDEX, 35 }; 36 37 int __init ceph_fscache_register(void) 38 { 39 return fscache_register_netfs(&ceph_cache_netfs); 40 } 41 42 void ceph_fscache_unregister(void) 43 { 44 fscache_unregister_netfs(&ceph_cache_netfs); 45 } 46 47 int ceph_fscache_register_fs(struct ceph_fs_client* fsc, struct fs_context *fc) 48 { 49 const struct ceph_fsid *fsid = &fsc->client->fsid; 50 const char *fscache_uniq = fsc->mount_options->fscache_uniq; 51 size_t uniq_len = fscache_uniq ? strlen(fscache_uniq) : 0; 52 struct ceph_fscache_entry *ent; 53 int err = 0; 54 55 mutex_lock(&ceph_fscache_lock); 56 list_for_each_entry(ent, &ceph_fscache_list, list) { 57 if (memcmp(&ent->fsid, fsid, sizeof(*fsid))) 58 continue; 59 if (ent->uniq_len != uniq_len) 60 continue; 61 if (uniq_len && memcmp(ent->uniquifier, fscache_uniq, uniq_len)) 62 continue; 63 64 errorfc(fc, "fscache cookie already registered for fsid %pU, use fsc=<uniquifier> option", 65 fsid); 66 err = -EBUSY; 67 goto out_unlock; 68 } 69 70 ent = kzalloc(sizeof(*ent) + uniq_len, GFP_KERNEL); 71 if (!ent) { 72 err = -ENOMEM; 73 goto out_unlock; 74 } 75 76 memcpy(&ent->fsid, fsid, sizeof(*fsid)); 77 if (uniq_len > 0) { 78 memcpy(&ent->uniquifier, fscache_uniq, uniq_len); 79 ent->uniq_len = uniq_len; 80 } 81 82 fsc->fscache = fscache_acquire_cookie(ceph_cache_netfs.primary_index, 83 &ceph_fscache_fsid_object_def, 84 &ent->fsid, sizeof(ent->fsid) + uniq_len, 85 NULL, 0, 86 fsc, 0, true); 87 88 if (fsc->fscache) { 89 ent->fscache = fsc->fscache; 90 list_add_tail(&ent->list, &ceph_fscache_list); 91 } else { 92 kfree(ent); 93 errorfc(fc, "unable to register fscache cookie for fsid %pU", 94 fsid); 95 /* all other fs ignore this error */ 96 } 97 out_unlock: 98 mutex_unlock(&ceph_fscache_lock); 99 return err; 100 } 101 102 static enum fscache_checkaux ceph_fscache_inode_check_aux( 103 void *cookie_netfs_data, const void *data, uint16_t dlen, 104 loff_t object_size) 105 { 106 struct ceph_inode_info* ci = cookie_netfs_data; 107 struct inode* inode = &ci->vfs_inode; 108 109 if (dlen != sizeof(ci->i_version) || 110 i_size_read(inode) != object_size) 111 return FSCACHE_CHECKAUX_OBSOLETE; 112 113 if (*(u64 *)data != ci->i_version) 114 return FSCACHE_CHECKAUX_OBSOLETE; 115 116 dout("ceph inode 0x%p cached okay\n", ci); 117 return FSCACHE_CHECKAUX_OKAY; 118 } 119 120 static const struct fscache_cookie_def ceph_fscache_inode_object_def = { 121 .name = "CEPH.inode", 122 .type = FSCACHE_COOKIE_TYPE_DATAFILE, 123 .check_aux = ceph_fscache_inode_check_aux, 124 }; 125 126 void ceph_fscache_register_inode_cookie(struct inode *inode) 127 { 128 struct ceph_inode_info *ci = ceph_inode(inode); 129 struct ceph_fs_client *fsc = ceph_inode_to_client(inode); 130 131 /* No caching for filesystem */ 132 if (!fsc->fscache) 133 return; 134 135 /* Only cache for regular files that are read only */ 136 if (!S_ISREG(inode->i_mode)) 137 return; 138 139 inode_lock_nested(inode, I_MUTEX_CHILD); 140 if (!ci->fscache) { 141 ci->fscache = fscache_acquire_cookie(fsc->fscache, 142 &ceph_fscache_inode_object_def, 143 &ci->i_vino, sizeof(ci->i_vino), 144 &ci->i_version, sizeof(ci->i_version), 145 ci, i_size_read(inode), false); 146 } 147 inode_unlock(inode); 148 } 149 150 void ceph_fscache_unregister_inode_cookie(struct ceph_inode_info* ci) 151 { 152 struct fscache_cookie* cookie; 153 154 if ((cookie = ci->fscache) == NULL) 155 return; 156 157 ci->fscache = NULL; 158 159 fscache_relinquish_cookie(cookie, &ci->i_vino, false); 160 } 161 162 static bool ceph_fscache_can_enable(void *data) 163 { 164 struct inode *inode = data; 165 return !inode_is_open_for_write(inode); 166 } 167 168 void ceph_fscache_file_set_cookie(struct inode *inode, struct file *filp) 169 { 170 struct ceph_inode_info *ci = ceph_inode(inode); 171 172 if (!fscache_cookie_valid(ci->fscache)) 173 return; 174 175 if (inode_is_open_for_write(inode)) { 176 dout("fscache_file_set_cookie %p %p disabling cache\n", 177 inode, filp); 178 fscache_disable_cookie(ci->fscache, &ci->i_vino, false); 179 } else { 180 fscache_enable_cookie(ci->fscache, &ci->i_vino, i_size_read(inode), 181 ceph_fscache_can_enable, inode); 182 if (fscache_cookie_enabled(ci->fscache)) { 183 dout("fscache_file_set_cookie %p %p enabling cache\n", 184 inode, filp); 185 } 186 } 187 } 188 189 void ceph_fscache_unregister_fs(struct ceph_fs_client* fsc) 190 { 191 if (fscache_cookie_valid(fsc->fscache)) { 192 struct ceph_fscache_entry *ent; 193 bool found = false; 194 195 mutex_lock(&ceph_fscache_lock); 196 list_for_each_entry(ent, &ceph_fscache_list, list) { 197 if (ent->fscache == fsc->fscache) { 198 list_del(&ent->list); 199 kfree(ent); 200 found = true; 201 break; 202 } 203 } 204 WARN_ON_ONCE(!found); 205 mutex_unlock(&ceph_fscache_lock); 206 207 __fscache_relinquish_cookie(fsc->fscache, NULL, false); 208 } 209 fsc->fscache = NULL; 210 } 211