1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* Volume-level cache cookie handling. 3 * 4 * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved. 5 * Written by David Howells (dhowells@redhat.com) 6 */ 7 8 #define FSCACHE_DEBUG_LEVEL COOKIE 9 #include <linux/export.h> 10 #include <linux/slab.h> 11 #include "internal.h" 12 13 #define fscache_volume_hash_shift 10 14 static struct hlist_bl_head fscache_volume_hash[1 << fscache_volume_hash_shift]; 15 static atomic_t fscache_volume_debug_id; 16 static LIST_HEAD(fscache_volumes); 17 18 static void fscache_create_volume_work(struct work_struct *work); 19 20 struct fscache_volume *fscache_get_volume(struct fscache_volume *volume, 21 enum fscache_volume_trace where) 22 { 23 int ref; 24 25 __refcount_inc(&volume->ref, &ref); 26 trace_fscache_volume(volume->debug_id, ref + 1, where); 27 return volume; 28 } 29 30 struct fscache_volume *fscache_try_get_volume(struct fscache_volume *volume, 31 enum fscache_volume_trace where) 32 { 33 int ref; 34 35 if (!__refcount_inc_not_zero(&volume->ref, &ref)) 36 return NULL; 37 38 trace_fscache_volume(volume->debug_id, ref + 1, where); 39 return volume; 40 } 41 EXPORT_SYMBOL(fscache_try_get_volume); 42 43 static void fscache_see_volume(struct fscache_volume *volume, 44 enum fscache_volume_trace where) 45 { 46 int ref = refcount_read(&volume->ref); 47 48 trace_fscache_volume(volume->debug_id, ref, where); 49 } 50 51 /* 52 * Pin the cache behind a volume so that we can access it. 53 */ 54 static void __fscache_begin_volume_access(struct fscache_volume *volume, 55 struct fscache_cookie *cookie, 56 enum fscache_access_trace why) 57 { 58 int n_accesses; 59 60 n_accesses = atomic_inc_return(&volume->n_accesses); 61 smp_mb__after_atomic(); 62 trace_fscache_access_volume(volume->debug_id, cookie ? cookie->debug_id : 0, 63 refcount_read(&volume->ref), 64 n_accesses, why); 65 } 66 67 /** 68 * fscache_begin_volume_access - Pin a cache so a volume can be accessed 69 * @volume: The volume cookie 70 * @cookie: A datafile cookie for a tracing reference (or NULL) 71 * @why: An indication of the circumstances of the access for tracing 72 * 73 * Attempt to pin the cache to prevent it from going away whilst we're 74 * accessing a volume and returns true if successful. This works as follows: 75 * 76 * (1) If the cache tests as not live (state is not FSCACHE_CACHE_IS_ACTIVE), 77 * then we return false to indicate access was not permitted. 78 * 79 * (2) If the cache tests as live, then we increment the volume's n_accesses 80 * count and then recheck the cache liveness, ending the access if it 81 * ceased to be live. 82 * 83 * (3) When we end the access, we decrement the volume's n_accesses and wake 84 * up the any waiters if it reaches 0. 85 * 86 * (4) Whilst the cache is caching, the volume's n_accesses is kept 87 * artificially incremented to prevent wakeups from happening. 88 * 89 * (5) When the cache is taken offline, the state is changed to prevent new 90 * accesses, the volume's n_accesses is decremented and we wait for it to 91 * become 0. 92 * 93 * The datafile @cookie and the @why indicator are merely provided for tracing 94 * purposes. 95 */ 96 bool fscache_begin_volume_access(struct fscache_volume *volume, 97 struct fscache_cookie *cookie, 98 enum fscache_access_trace why) 99 { 100 if (!fscache_cache_is_live(volume->cache)) 101 return false; 102 __fscache_begin_volume_access(volume, cookie, why); 103 if (!fscache_cache_is_live(volume->cache)) { 104 fscache_end_volume_access(volume, cookie, fscache_access_unlive); 105 return false; 106 } 107 return true; 108 } 109 110 /** 111 * fscache_end_volume_access - Unpin a cache at the end of an access. 112 * @volume: The volume cookie 113 * @cookie: A datafile cookie for a tracing reference (or NULL) 114 * @why: An indication of the circumstances of the access for tracing 115 * 116 * Unpin a cache volume after we've accessed it. The datafile @cookie and the 117 * @why indicator are merely provided for tracing purposes. 118 */ 119 void fscache_end_volume_access(struct fscache_volume *volume, 120 struct fscache_cookie *cookie, 121 enum fscache_access_trace why) 122 { 123 int n_accesses; 124 125 smp_mb__before_atomic(); 126 n_accesses = atomic_dec_return(&volume->n_accesses); 127 trace_fscache_access_volume(volume->debug_id, cookie ? cookie->debug_id : 0, 128 refcount_read(&volume->ref), 129 n_accesses, why); 130 if (n_accesses == 0) 131 wake_up_var(&volume->n_accesses); 132 } 133 EXPORT_SYMBOL(fscache_end_volume_access); 134 135 static bool fscache_volume_same(const struct fscache_volume *a, 136 const struct fscache_volume *b) 137 { 138 size_t klen; 139 140 if (a->key_hash != b->key_hash || 141 a->cache != b->cache || 142 a->key[0] != b->key[0]) 143 return false; 144 145 klen = round_up(a->key[0] + 1, sizeof(__le32)); 146 return memcmp(a->key, b->key, klen) == 0; 147 } 148 149 static bool fscache_is_acquire_pending(struct fscache_volume *volume) 150 { 151 return test_bit(FSCACHE_VOLUME_ACQUIRE_PENDING, &volume->flags); 152 } 153 154 static void fscache_wait_on_volume_collision(struct fscache_volume *candidate, 155 unsigned int collidee_debug_id) 156 { 157 wait_on_bit_timeout(&candidate->flags, FSCACHE_VOLUME_ACQUIRE_PENDING, 158 TASK_UNINTERRUPTIBLE, 20 * HZ); 159 if (fscache_is_acquire_pending(candidate)) { 160 pr_notice("Potential volume collision new=%08x old=%08x", 161 candidate->debug_id, collidee_debug_id); 162 fscache_stat(&fscache_n_volumes_collision); 163 wait_on_bit(&candidate->flags, FSCACHE_VOLUME_ACQUIRE_PENDING, 164 TASK_UNINTERRUPTIBLE); 165 } 166 } 167 168 /* 169 * Attempt to insert the new volume into the hash. If there's a collision, we 170 * wait for the old volume to complete if it's being relinquished and an error 171 * otherwise. 172 */ 173 static bool fscache_hash_volume(struct fscache_volume *candidate) 174 { 175 struct fscache_volume *cursor; 176 struct hlist_bl_head *h; 177 struct hlist_bl_node *p; 178 unsigned int bucket, collidee_debug_id = 0; 179 180 bucket = candidate->key_hash & (ARRAY_SIZE(fscache_volume_hash) - 1); 181 h = &fscache_volume_hash[bucket]; 182 183 hlist_bl_lock(h); 184 hlist_bl_for_each_entry(cursor, p, h, hash_link) { 185 if (fscache_volume_same(candidate, cursor)) { 186 if (!test_bit(FSCACHE_VOLUME_RELINQUISHED, &cursor->flags)) 187 goto collision; 188 fscache_see_volume(cursor, fscache_volume_get_hash_collision); 189 set_bit(FSCACHE_VOLUME_COLLIDED_WITH, &cursor->flags); 190 set_bit(FSCACHE_VOLUME_ACQUIRE_PENDING, &candidate->flags); 191 collidee_debug_id = cursor->debug_id; 192 break; 193 } 194 } 195 196 hlist_bl_add_head(&candidate->hash_link, h); 197 hlist_bl_unlock(h); 198 199 if (fscache_is_acquire_pending(candidate)) 200 fscache_wait_on_volume_collision(candidate, collidee_debug_id); 201 return true; 202 203 collision: 204 fscache_see_volume(cursor, fscache_volume_collision); 205 hlist_bl_unlock(h); 206 return false; 207 } 208 209 /* 210 * Allocate and initialise a volume representation cookie. 211 */ 212 static struct fscache_volume *fscache_alloc_volume(const char *volume_key, 213 const char *cache_name, 214 const void *coherency_data, 215 size_t coherency_len) 216 { 217 struct fscache_volume *volume; 218 struct fscache_cache *cache; 219 size_t klen, hlen; 220 u8 *key; 221 222 klen = strlen(volume_key); 223 if (klen > NAME_MAX) 224 return NULL; 225 226 if (!coherency_data) 227 coherency_len = 0; 228 229 cache = fscache_lookup_cache(cache_name, false); 230 if (IS_ERR(cache)) 231 return NULL; 232 233 volume = kzalloc(struct_size(volume, coherency, coherency_len), 234 GFP_KERNEL); 235 if (!volume) 236 goto err_cache; 237 238 volume->cache = cache; 239 volume->coherency_len = coherency_len; 240 if (coherency_data) 241 memcpy(volume->coherency, coherency_data, coherency_len); 242 INIT_LIST_HEAD(&volume->proc_link); 243 INIT_WORK(&volume->work, fscache_create_volume_work); 244 refcount_set(&volume->ref, 1); 245 spin_lock_init(&volume->lock); 246 247 /* Stick the length on the front of the key and pad it out to make 248 * hashing easier. 249 */ 250 hlen = round_up(1 + klen + 1, sizeof(__le32)); 251 key = kzalloc(hlen, GFP_KERNEL); 252 if (!key) 253 goto err_vol; 254 key[0] = klen; 255 memcpy(key + 1, volume_key, klen); 256 257 volume->key = key; 258 volume->key_hash = fscache_hash(0, key, hlen); 259 260 volume->debug_id = atomic_inc_return(&fscache_volume_debug_id); 261 down_write(&fscache_addremove_sem); 262 atomic_inc(&cache->n_volumes); 263 list_add_tail(&volume->proc_link, &fscache_volumes); 264 fscache_see_volume(volume, fscache_volume_new_acquire); 265 fscache_stat(&fscache_n_volumes); 266 up_write(&fscache_addremove_sem); 267 _leave(" = v=%x", volume->debug_id); 268 return volume; 269 270 err_vol: 271 kfree(volume); 272 err_cache: 273 fscache_put_cache(cache, fscache_cache_put_alloc_volume); 274 fscache_stat(&fscache_n_volumes_nomem); 275 return NULL; 276 } 277 278 /* 279 * Create a volume's representation on disk. Have a volume ref and a cache 280 * access we have to release. 281 */ 282 static void fscache_create_volume_work(struct work_struct *work) 283 { 284 const struct fscache_cache_ops *ops; 285 struct fscache_volume *volume = 286 container_of(work, struct fscache_volume, work); 287 288 fscache_see_volume(volume, fscache_volume_see_create_work); 289 290 ops = volume->cache->ops; 291 if (ops->acquire_volume) 292 ops->acquire_volume(volume); 293 fscache_end_cache_access(volume->cache, 294 fscache_access_acquire_volume_end); 295 296 clear_and_wake_up_bit(FSCACHE_VOLUME_CREATING, &volume->flags); 297 fscache_put_volume(volume, fscache_volume_put_create_work); 298 } 299 300 /* 301 * Dispatch a worker thread to create a volume's representation on disk. 302 */ 303 void fscache_create_volume(struct fscache_volume *volume, bool wait) 304 { 305 if (test_and_set_bit(FSCACHE_VOLUME_CREATING, &volume->flags)) 306 goto maybe_wait; 307 if (volume->cache_priv) 308 goto no_wait; /* We raced */ 309 if (!fscache_begin_cache_access(volume->cache, 310 fscache_access_acquire_volume)) 311 goto no_wait; 312 313 fscache_get_volume(volume, fscache_volume_get_create_work); 314 if (!schedule_work(&volume->work)) 315 fscache_put_volume(volume, fscache_volume_put_create_work); 316 317 maybe_wait: 318 if (wait) { 319 fscache_see_volume(volume, fscache_volume_wait_create_work); 320 wait_on_bit(&volume->flags, FSCACHE_VOLUME_CREATING, 321 TASK_UNINTERRUPTIBLE); 322 } 323 return; 324 no_wait: 325 clear_and_wake_up_bit(FSCACHE_VOLUME_CREATING, &volume->flags); 326 } 327 328 /* 329 * Acquire a volume representation cookie and link it to a (proposed) cache. 330 */ 331 struct fscache_volume *__fscache_acquire_volume(const char *volume_key, 332 const char *cache_name, 333 const void *coherency_data, 334 size_t coherency_len) 335 { 336 struct fscache_volume *volume; 337 338 volume = fscache_alloc_volume(volume_key, cache_name, 339 coherency_data, coherency_len); 340 if (!volume) 341 return ERR_PTR(-ENOMEM); 342 343 if (!fscache_hash_volume(volume)) { 344 fscache_put_volume(volume, fscache_volume_put_hash_collision); 345 return ERR_PTR(-EBUSY); 346 } 347 348 fscache_create_volume(volume, false); 349 return volume; 350 } 351 EXPORT_SYMBOL(__fscache_acquire_volume); 352 353 static void fscache_wake_pending_volume(struct fscache_volume *volume, 354 struct hlist_bl_head *h) 355 { 356 struct fscache_volume *cursor; 357 struct hlist_bl_node *p; 358 359 hlist_bl_for_each_entry(cursor, p, h, hash_link) { 360 if (fscache_volume_same(cursor, volume)) { 361 fscache_see_volume(cursor, fscache_volume_see_hash_wake); 362 clear_and_wake_up_bit(FSCACHE_VOLUME_ACQUIRE_PENDING, 363 &cursor->flags); 364 return; 365 } 366 } 367 } 368 369 /* 370 * Remove a volume cookie from the hash table. 371 */ 372 static void fscache_unhash_volume(struct fscache_volume *volume) 373 { 374 struct hlist_bl_head *h; 375 unsigned int bucket; 376 377 bucket = volume->key_hash & (ARRAY_SIZE(fscache_volume_hash) - 1); 378 h = &fscache_volume_hash[bucket]; 379 380 hlist_bl_lock(h); 381 hlist_bl_del(&volume->hash_link); 382 if (test_bit(FSCACHE_VOLUME_COLLIDED_WITH, &volume->flags)) 383 fscache_wake_pending_volume(volume, h); 384 hlist_bl_unlock(h); 385 } 386 387 /* 388 * Drop a cache's volume attachments. 389 */ 390 static void fscache_free_volume(struct fscache_volume *volume) 391 { 392 struct fscache_cache *cache = volume->cache; 393 394 if (volume->cache_priv) { 395 __fscache_begin_volume_access(volume, NULL, 396 fscache_access_relinquish_volume); 397 if (volume->cache_priv) 398 cache->ops->free_volume(volume); 399 fscache_end_volume_access(volume, NULL, 400 fscache_access_relinquish_volume_end); 401 } 402 403 down_write(&fscache_addremove_sem); 404 list_del_init(&volume->proc_link); 405 atomic_dec(&volume->cache->n_volumes); 406 up_write(&fscache_addremove_sem); 407 408 if (!hlist_bl_unhashed(&volume->hash_link)) 409 fscache_unhash_volume(volume); 410 411 trace_fscache_volume(volume->debug_id, 0, fscache_volume_free); 412 kfree(volume->key); 413 kfree(volume); 414 fscache_stat_d(&fscache_n_volumes); 415 fscache_put_cache(cache, fscache_cache_put_volume); 416 } 417 418 /* 419 * Drop a reference to a volume cookie. 420 */ 421 void fscache_put_volume(struct fscache_volume *volume, 422 enum fscache_volume_trace where) 423 { 424 if (volume) { 425 unsigned int debug_id = volume->debug_id; 426 bool zero; 427 int ref; 428 429 zero = __refcount_dec_and_test(&volume->ref, &ref); 430 trace_fscache_volume(debug_id, ref - 1, where); 431 if (zero) 432 fscache_free_volume(volume); 433 } 434 } 435 EXPORT_SYMBOL(fscache_put_volume); 436 437 /* 438 * Relinquish a volume representation cookie. 439 */ 440 void __fscache_relinquish_volume(struct fscache_volume *volume, 441 const void *coherency_data, 442 bool invalidate) 443 { 444 if (WARN_ON(test_and_set_bit(FSCACHE_VOLUME_RELINQUISHED, &volume->flags))) 445 return; 446 447 if (invalidate) { 448 set_bit(FSCACHE_VOLUME_INVALIDATE, &volume->flags); 449 } else if (coherency_data) { 450 memcpy(volume->coherency, coherency_data, volume->coherency_len); 451 } 452 453 fscache_put_volume(volume, fscache_volume_put_relinquish); 454 } 455 EXPORT_SYMBOL(__fscache_relinquish_volume); 456 457 /** 458 * fscache_withdraw_volume - Withdraw a volume from being cached 459 * @volume: Volume cookie 460 * 461 * Withdraw a cache volume from service, waiting for all accesses to complete 462 * before returning. 463 */ 464 void fscache_withdraw_volume(struct fscache_volume *volume) 465 { 466 int n_accesses; 467 468 _debug("withdraw V=%x", volume->debug_id); 469 470 /* Allow wakeups on dec-to-0 */ 471 n_accesses = atomic_dec_return(&volume->n_accesses); 472 trace_fscache_access_volume(volume->debug_id, 0, 473 refcount_read(&volume->ref), 474 n_accesses, fscache_access_cache_unpin); 475 476 wait_var_event(&volume->n_accesses, 477 atomic_read(&volume->n_accesses) == 0); 478 } 479 EXPORT_SYMBOL(fscache_withdraw_volume); 480 481 #ifdef CONFIG_PROC_FS 482 /* 483 * Generate a list of volumes in /proc/fs/fscache/volumes 484 */ 485 static int fscache_volumes_seq_show(struct seq_file *m, void *v) 486 { 487 struct fscache_volume *volume; 488 489 if (v == &fscache_volumes) { 490 seq_puts(m, 491 "VOLUME REF nCOOK ACC FL CACHE KEY\n" 492 "======== ===== ===== === == =============== ================\n"); 493 return 0; 494 } 495 496 volume = list_entry(v, struct fscache_volume, proc_link); 497 seq_printf(m, 498 "%08x %5d %5d %3d %02lx %-15.15s %s\n", 499 volume->debug_id, 500 refcount_read(&volume->ref), 501 atomic_read(&volume->n_cookies), 502 atomic_read(&volume->n_accesses), 503 volume->flags, 504 volume->cache->name ?: "-", 505 volume->key + 1); 506 return 0; 507 } 508 509 static void *fscache_volumes_seq_start(struct seq_file *m, loff_t *_pos) 510 __acquires(&fscache_addremove_sem) 511 { 512 down_read(&fscache_addremove_sem); 513 return seq_list_start_head(&fscache_volumes, *_pos); 514 } 515 516 static void *fscache_volumes_seq_next(struct seq_file *m, void *v, loff_t *_pos) 517 { 518 return seq_list_next(v, &fscache_volumes, _pos); 519 } 520 521 static void fscache_volumes_seq_stop(struct seq_file *m, void *v) 522 __releases(&fscache_addremove_sem) 523 { 524 up_read(&fscache_addremove_sem); 525 } 526 527 const struct seq_operations fscache_volumes_seq_ops = { 528 .start = fscache_volumes_seq_start, 529 .next = fscache_volumes_seq_next, 530 .stop = fscache_volumes_seq_stop, 531 .show = fscache_volumes_seq_show, 532 }; 533 #endif /* CONFIG_PROC_FS */ 534