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