// SPDX-License-Identifier: GPL-2.0-or-later /* Volume-level cache cookie handling. * * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com)
*/
/* * Pin the cache behind a volume so that we can access it.
*/ staticvoid __fscache_begin_volume_access(struct fscache_volume *volume, struct fscache_cookie *cookie, enum fscache_access_trace why)
{ int n_accesses;
/** * fscache_begin_volume_access - Pin a cache so a volume can be accessed * @volume: The volume cookie * @cookie: A datafile cookie for a tracing reference (or NULL) * @why: An indication of the circumstances of the access for tracing * * Attempt to pin the cache to prevent it from going away whilst we're * accessing a volume and returns true if successful. This works as follows: * * (1) If the cache tests as not live (state is not FSCACHE_CACHE_IS_ACTIVE), * then we return false to indicate access was not permitted. * * (2) If the cache tests as live, then we increment the volume's n_accesses * count and then recheck the cache liveness, ending the access if it * ceased to be live. * * (3) When we end the access, we decrement the volume's n_accesses and wake * up the any waiters if it reaches 0. * * (4) Whilst the cache is caching, the volume's n_accesses is kept * artificially incremented to prevent wakeups from happening. * * (5) When the cache is taken offline, the state is changed to prevent new * accesses, the volume's n_accesses is decremented and we wait for it to * become 0. * * The datafile @cookie and the @why indicator are merely provided for tracing * purposes.
*/ bool fscache_begin_volume_access(struct fscache_volume *volume, struct fscache_cookie *cookie, enum fscache_access_trace why)
{ if (!fscache_cache_is_live(volume->cache)) returnfalse;
__fscache_begin_volume_access(volume, cookie, why); if (!fscache_cache_is_live(volume->cache)) {
fscache_end_volume_access(volume, cookie, fscache_access_unlive); returnfalse;
} returntrue;
}
/** * fscache_end_volume_access - Unpin a cache at the end of an access. * @volume: The volume cookie * @cookie: A datafile cookie for a tracing reference (or NULL) * @why: An indication of the circumstances of the access for tracing * * Unpin a cache volume after we've accessed it. The datafile @cookie and the * @why indicator are merely provided for tracing purposes.
*/ void fscache_end_volume_access(struct fscache_volume *volume, struct fscache_cookie *cookie, enum fscache_access_trace why)
{ int n_accesses;
/* * Attempt to insert the new volume into the hash. If there's a collision, we * wait for the old volume to complete if it's being relinquished and an error * otherwise.
*/ staticbool fscache_hash_volume(struct fscache_volume *candidate)
{ struct fscache_volume *cursor; struct hlist_bl_head *h; struct hlist_bl_node *p; unsignedint bucket, collidee_debug_id = 0;
bucket = candidate->key_hash & (ARRAY_SIZE(fscache_volume_hash) - 1);
h = &fscache_volume_hash[bucket];
/* Stick the length on the front of the key and pad it out to make * hashing easier.
*/
hlen = round_up(1 + klen + 1, sizeof(__le32));
key = kzalloc(hlen, GFP_KERNEL); if (!key) goto err_vol;
key[0] = klen;
memcpy(key + 1, volume_key, klen);
/* * Create a volume's representation on disk. Have a volume ref and a cache * access we have to release.
*/ staticvoid fscache_create_volume_work(struct work_struct *work)
{ conststruct fscache_cache_ops *ops; struct fscache_volume *volume =
container_of(work, struct fscache_volume, work);
/* * Dispatch a worker thread to create a volume's representation on disk.
*/ void fscache_create_volume(struct fscache_volume *volume, bool wait)
{ if (test_and_set_bit(FSCACHE_VOLUME_CREATING, &volume->flags)) goto maybe_wait; if (volume->cache_priv) goto no_wait; /* We raced */ if (!fscache_begin_cache_access(volume->cache,
fscache_access_acquire_volume)) goto no_wait;
fscache_get_volume(volume, fscache_volume_get_create_work); if (!schedule_work(&volume->work))
fscache_put_volume(volume, fscache_volume_put_create_work);
/* * Acquire a volume representation cookie and link it to a (proposed) cache.
*/ struct fscache_volume *__fscache_acquire_volume(constchar *volume_key, constchar *cache_name, constvoid *coherency_data,
size_t coherency_len)
{ struct fscache_volume *volume;
volume = fscache_alloc_volume(volume_key, cache_name,
coherency_data, coherency_len); if (!volume) return ERR_PTR(-ENOMEM);
if (!fscache_hash_volume(volume)) {
fscache_put_volume(volume, fscache_volume_put_hash_collision); return ERR_PTR(-EBUSY);
}
/* * Drop a reference to a volume cookie.
*/ void fscache_put_volume(struct fscache_volume *volume, enum fscache_volume_trace where)
{ if (volume) { unsignedint debug_id = volume->debug_id; bool zero; int ref;
zero = __refcount_dec_and_test(&volume->ref, &ref);
trace_fscache_volume(debug_id, ref - 1, where); if (zero)
fscache_free_volume(volume);
}
}
EXPORT_SYMBOL(fscache_put_volume);
/** * fscache_withdraw_volume - Withdraw a volume from being cached * @volume: Volume cookie * * Withdraw a cache volume from service, waiting for all accesses to complete * before returning.
*/ void fscache_withdraw_volume(struct fscache_volume *volume)
{ int n_accesses;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.