1// SPDX-License-Identifier: GPL-2.0 2/* 3 * fs/hmdfs/dentry.c 4 * 5 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. 6 */ 7 8#include <linux/ctype.h> 9#include <linux/slab.h> 10 11#include "comm/connection.h" 12#include "hmdfs_dentryfile.h" 13#include "hmdfs_device_view.h" 14#include "hmdfs_merge_view.h" 15 16extern struct kmem_cache *hmdfs_dentry_cachep; 17 18void hmdfs_set_time(struct dentry *dentry, unsigned long time) 19{ 20 struct hmdfs_dentry_info *d_info = dentry->d_fsdata; 21 22 if (d_info) 23 d_info->time = time; 24} 25 26unsigned long hmdfs_get_time(struct dentry *dentry) 27{ 28 struct hmdfs_dentry_info *d_info = dentry->d_fsdata; 29 30 if (d_info) 31 return (unsigned long)d_info->time; 32 return 0; 33} 34 35static int hmdfs_d_remote_revalidate(struct hmdfs_peer *conn, 36 struct dentry *target, 37 struct dentry *parent) 38{ 39 unsigned int timeout = hmdfs_sb(target->d_sb)->dcache_timeout; 40 unsigned long dentry_time = hmdfs_get_time(target); 41 struct clearcache_item *item; 42 43 item = hmdfs_find_cache_item(conn->device_id, parent); 44 if (!item) 45 return 0; 46 kref_put(&item->ref, release_cache_item); 47 48 if (cache_item_revalidate(READ_ONCE(conn->conn_time), 49 dentry_time, timeout)) 50 return 1; 51 52 return 0; 53} 54 55static inline void lock_for_dname_cmp(struct dentry *dentry, 56 struct dentry *lower_dentry) 57{ 58 if (dentry < lower_dentry) { 59 spin_lock(&dentry->d_lock); 60 spin_lock_nested(&lower_dentry->d_lock, DENTRY_D_LOCK_NESTED); 61 } else { 62 spin_lock(&lower_dentry->d_lock); 63 spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); 64 } 65} 66 67static inline void unlock_for_dname_cmp(struct dentry *dentry, 68 struct dentry *lower_dentry) 69{ 70 spin_unlock(&dentry->d_lock); 71 spin_unlock(&lower_dentry->d_lock); 72} 73 74static int hmdfs_dev_d_revalidate(struct dentry *direntry, unsigned int flags) 75{ 76 struct inode *dinode = NULL; 77 struct hmdfs_inode_info *info = NULL; 78 79 spin_lock(&direntry->d_lock); 80 if (IS_ROOT(direntry)) { 81 spin_unlock(&direntry->d_lock); 82 return 1; 83 } 84 spin_unlock(&direntry->d_lock); 85 86 dinode = d_inode(direntry); 87 if (!dinode) 88 return 0; 89 90 info = hmdfs_i(dinode); 91 if (info->inode_type == HMDFS_LAYER_SECOND_LOCAL || 92 info->inode_type == HMDFS_LAYER_FIRST_DEVICE) { 93 return 1; 94 } 95 if (info->conn && info->conn->status == NODE_STAT_ONLINE) 96 return 1; 97 98 return 0; 99} 100 101static int hmdfs_d_revalidate(struct dentry *direntry, unsigned int flags) 102{ 103 struct inode *dinode = NULL; 104 struct hmdfs_inode_info *info = NULL; 105 struct path lower_path, parent_lower_path; 106 struct dentry *parent_dentry = NULL; 107 struct dentry *parent_lower_dentry = NULL; 108 struct dentry *lower_cur_parent_dentry = NULL; 109 struct dentry *lower_dentry = NULL; 110 int ret; 111 112 if (flags & LOOKUP_RCU) 113 return -ECHILD; 114 115 if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET | LOOKUP_REVAL)) 116 return 0; 117 118 dinode = d_inode(direntry); 119 if (!dinode) 120 return 0; 121 122 /* remote dentry timeout */ 123 info = hmdfs_i(dinode); 124 parent_dentry = dget_parent(direntry); 125 if (info->conn) { 126 ret = hmdfs_d_remote_revalidate(info->conn, direntry, 127 parent_dentry); 128 dput(parent_dentry); 129 return ret; 130 } 131 132 hmdfs_get_lower_path(direntry, &lower_path); 133 lower_dentry = lower_path.dentry; 134 lower_cur_parent_dentry = dget_parent(lower_dentry); 135 hmdfs_get_lower_path(parent_dentry, &parent_lower_path); 136 parent_lower_dentry = parent_lower_path.dentry; 137 if ((lower_dentry->d_flags & DCACHE_OP_REVALIDATE)) { 138 ret = lower_dentry->d_op->d_revalidate(lower_dentry, flags); 139 if (ret == 0) 140 goto out; 141 } 142 143 spin_lock(&lower_dentry->d_lock); 144 if (d_unhashed(lower_dentry)) { 145 spin_unlock(&lower_dentry->d_lock); 146 ret = 0; 147 goto out; 148 } 149 spin_unlock(&lower_dentry->d_lock); 150 151 if (parent_lower_dentry != lower_cur_parent_dentry) { 152 ret = 0; 153 goto out; 154 } 155 156 ret = 1; 157 lock_for_dname_cmp(direntry, lower_dentry); 158 if (!qstr_case_eq(&direntry->d_name, &lower_dentry->d_name)) 159 ret = 0; 160 unlock_for_dname_cmp(direntry, lower_dentry); 161 162out: 163 hmdfs_put_lower_path(&parent_lower_path); 164 dput(lower_cur_parent_dentry); 165 hmdfs_put_lower_path(&lower_path); 166 dput(parent_dentry); 167 return ret; 168} 169 170static void hmdfs_dev_d_release(struct dentry *dentry) 171{ 172 struct clearcache_item *item; 173 if (!dentry || !dentry->d_fsdata) 174 return; 175 176 switch (hmdfs_d(dentry)->dentry_type) { 177 case HMDFS_LAYER_SECOND_LOCAL: 178 hmdfs_clear_cache_dents(dentry, false); 179 hmdfs_drop_remote_cache_dents(dentry); 180 path_put(&(hmdfs_d(dentry)->lower_path)); 181 break; 182 case HMDFS_LAYER_ZERO: 183 hmdfs_put_reset_lower_path(dentry); 184 break; 185 case HMDFS_LAYER_FIRST_DEVICE: 186 break; 187 case HMDFS_LAYER_SECOND_REMOTE: 188 hmdfs_clear_cache_dents(dentry, false); 189 break; 190 case HMDFS_LAYER_SECOND_CLOUD: 191 item = hmdfs_find_cache_item(CLOUD_DEVICE, dentry); 192 if (item) { 193 /* cloud dentryfile didn't link to 194 'struct cache_file_node', so close file here. 195 */ 196 filp_close(item->filp, NULL); 197 kref_put(&item->ref, release_cache_item); 198 } 199 hmdfs_clear_cache_dents(dentry, false); 200 break; 201 default: 202 hmdfs_err("Unexpected dentry type %d", 203 hmdfs_d(dentry)->dentry_type); 204 return; 205 } 206 207 kmem_cache_free(hmdfs_dentry_cachep, dentry->d_fsdata); 208 dentry->d_fsdata = NULL; 209} 210 211static void hmdfs_d_release(struct dentry *dentry) 212{ 213 if (!dentry || !dentry->d_fsdata) 214 return; 215 216 hmdfs_clear_cache_dents(dentry, false); 217 hmdfs_drop_remote_cache_dents(dentry); 218 hmdfs_put_reset_lower_path(dentry); 219 kmem_cache_free(hmdfs_dentry_cachep, dentry->d_fsdata); 220 dentry->d_fsdata = NULL; 221} 222 223static int hmdfs_cmp_ci(const struct dentry *dentry, unsigned int len, 224 const char *str, const struct qstr *name) 225{ 226 struct hmdfs_sb_info *sbi = hmdfs_sb(dentry->d_sb); 227 228 if (name->len != len) 229 return 1; 230 231 if (!sbi->s_case_sensitive) { 232 if (str_n_case_eq(name->name, str, len)) 233 return 0; 234 } else { 235 if (!strncmp(name->name, str, len)) 236 return 0; 237 } 238 return 1; 239} 240 241static int hmdfs_hash_ci(const struct dentry *dentry, struct qstr *qstr) 242{ 243 const unsigned char *name = qstr->name; 244 unsigned int len = qstr->len; 245 unsigned long hash; 246 struct hmdfs_sb_info *sbi = hmdfs_sb(dentry->d_sb); 247 248 if (sbi->s_case_sensitive) 249 return 0; 250 251 hash = init_name_hash(dentry); 252 while (len--) 253 hash = partial_name_hash(tolower(*name++), hash); 254 qstr->hash = end_name_hash(hash); 255 return 0; 256} 257 258void clear_comrades_locked(struct list_head *comrade_list) 259{ 260 struct hmdfs_dentry_comrade *cc, *nc; 261 262 WARN_ON(!comrade_list); 263 list_for_each_entry_safe(cc, nc, comrade_list, list) { 264 dput(cc->lo_d); 265 kfree(cc); 266 } 267 INIT_LIST_HEAD(comrade_list); 268} 269 270void clear_comrades(struct dentry *dentry) 271{ 272 struct hmdfs_dentry_info_merge *cdi = hmdfs_dm(dentry); 273 274 wait_event(cdi->wait_queue, !has_merge_lookup_work(cdi)); 275 mutex_lock(&cdi->comrade_list_lock); 276 clear_comrades_locked(&cdi->comrade_list); 277 mutex_unlock(&cdi->comrade_list_lock); 278} 279 280/** 281 * d_revalidate_merge - revalidate a merge dentry 282 * 283 * Always return 0 to invalidate a dentry for fault-tolerance. 284 * The cost is acceptable for a overlay filesystem. 285 */ 286static int d_revalidate_merge(struct dentry *direntry, unsigned int flags) 287{ 288 struct hmdfs_dentry_info_merge *dim = hmdfs_dm(direntry); 289 struct hmdfs_dentry_comrade *comrade = NULL; 290 struct dentry *parent_dentry = NULL; 291 struct dentry *lower_cur_parent_dentry = NULL; 292 struct inode *dinode = NULL; 293 struct hmdfs_inode_info *info = NULL; 294 int ret = 1; 295 296 if (flags & LOOKUP_RCU) { 297 return -ECHILD; 298 } 299 300 if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET | LOOKUP_REVAL)) { 301 return 0; 302 } 303 304 dinode = d_inode(direntry); 305 if (!dinode) 306 return 0; 307 308 info = hmdfs_i(dinode); 309 if (info->inode_type == HMDFS_LAYER_FIRST_MERGE_CLOUD) 310 return 1; 311 312 parent_dentry = dget_parent(direntry); 313 mutex_lock(&dim->comrade_list_lock); 314 list_for_each_entry(comrade, &(dim->comrade_list), list) { 315 lower_cur_parent_dentry = dget_parent(comrade->lo_d); 316 if ((comrade->lo_d->d_flags & DCACHE_OP_REVALIDATE)) { 317 ret = comrade->lo_d->d_op->d_revalidate( 318 comrade->lo_d, flags); 319 if (ret == 0) { 320 dput(lower_cur_parent_dentry); 321 goto out; 322 } 323 } 324 dput(lower_cur_parent_dentry); 325 } 326out: 327 mutex_unlock(&dim->comrade_list_lock); 328 dput(parent_dentry); 329 return ret; 330} 331 332static void d_release_merge(struct dentry *dentry) 333{ 334 if (!dentry || !dentry->d_fsdata) 335 return; 336 337 clear_comrades(dentry); 338 kmem_cache_free(hmdfs_dentry_merge_cachep, dentry->d_fsdata); 339 dentry->d_fsdata = NULL; 340} 341 342const struct dentry_operations hmdfs_dops_merge = { 343 .d_revalidate = d_revalidate_merge, 344 .d_release = d_release_merge, 345}; 346 347const struct dentry_operations hmdfs_dev_dops = { 348 .d_revalidate = hmdfs_dev_d_revalidate, 349 .d_release = hmdfs_dev_d_release, 350}; 351 352const struct dentry_operations hmdfs_dops = { 353 .d_revalidate = hmdfs_d_revalidate, 354 .d_release = hmdfs_d_release, 355 .d_compare = hmdfs_cmp_ci, 356 .d_hash = hmdfs_hash_ci, 357}; 358