// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Red Hat, Inc. * * This file is released under the GPL.
*/ #include"dm-block-manager.h" #include"dm-persistent-data-internal.h"
/* * This is a read/write semaphore with a couple of differences. * * i) There is a restriction on the number of concurrent read locks that * may be held at once. This is just an implementation detail. * * ii) Recursive locking attempts are detected and return EINVAL. A stack * trace is also emitted for the previous lock acquisition. * * iii) Priority is given to write locks.
*/ #define MAX_HOLDERS 4 #define MAX_STACK 10
for (i = 0; i < MAX_HOLDERS; i++) { if (lock->holders[i] == current) {
DMERR("recursive lock detected in metadata"); #ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING
DMERR("previously held here:");
stack_trace_print(lock->traces[i].entries,
lock->traces[i].nr_entries, 4);
/* * Writers given priority. We know there's only one mutator in the * system, so ignoring the ordering reversal.
*/
list_add(&w.list, &lock->waiters);
spin_unlock(&lock->lock);
staticvoid report_recursive_bug(dm_block_t b, int r)
{ if (r == -EINVAL)
DMERR("recursive acquisition of block %llu requested.",
(unsignedlonglong) b);
}
#else/* !CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING */
#define bl_init(x) do { } while (0) #define bl_down_read(x) 0 #define bl_down_read_nonblock(x) 0 #define bl_up_read(x) do { } while (0) #define bl_down_write(x) 0 #define bl_up_write(x) do { } while (0) #define report_recursive_bug(x, y) do { } while (0)
/* * Block manager is currently implemented using dm-bufio. struct * dm_block_manager and struct dm_block map directly onto a couple of * structs in the bufio interface. I want to retain the freedom to move * away from bufio in the future. So these structs are just cast within * this .c file, rather than making it through to the public interface.
*/ staticstruct dm_buffer *to_buffer(struct dm_block *b)
{ return (struct dm_buffer *) b;
}
p = dm_bufio_read(bm->bufio, b, (struct dm_buffer **) result); if (IS_ERR(p)) return PTR_ERR(p);
aux = dm_bufio_get_aux_data(to_buffer(*result));
r = bl_down_read(&aux->lock); if (unlikely(r)) {
dm_bufio_release(to_buffer(*result));
report_recursive_bug(b, r); return r;
}
aux->write_locked = 0;
r = dm_bm_validate_buffer(bm, to_buffer(*result), aux, v); if (unlikely(r)) {
bl_up_read(&aux->lock);
dm_bufio_release(to_buffer(*result)); return r;
}
return 0;
}
EXPORT_SYMBOL_GPL(dm_bm_read_lock);
int dm_bm_write_lock(struct dm_block_manager *bm,
dm_block_t b, conststruct dm_block_validator *v, struct dm_block **result)
{ struct buffer_aux *aux; void *p; int r;
if (dm_bm_is_read_only(bm)) return -EPERM;
p = dm_bufio_read(bm->bufio, b, (struct dm_buffer **) result); if (IS_ERR(p)) return PTR_ERR(p);
aux = dm_bufio_get_aux_data(to_buffer(*result));
r = bl_down_write(&aux->lock); if (r) {
dm_bufio_release(to_buffer(*result));
report_recursive_bug(b, r); return r;
}
aux->write_locked = 1;
r = dm_bm_validate_buffer(bm, to_buffer(*result), aux, v); if (unlikely(r)) {
bl_up_write(&aux->lock);
dm_bufio_release(to_buffer(*result)); return r;
}
return 0;
}
EXPORT_SYMBOL_GPL(dm_bm_write_lock);
int dm_bm_read_try_lock(struct dm_block_manager *bm,
dm_block_t b, conststruct dm_block_validator *v, struct dm_block **result)
{ struct buffer_aux *aux; void *p; int r;
p = dm_bufio_get(bm->bufio, b, (struct dm_buffer **) result); if (IS_ERR(p)) return PTR_ERR(p); if (unlikely(!p)) return -EWOULDBLOCK;
aux = dm_bufio_get_aux_data(to_buffer(*result));
r = bl_down_read_nonblock(&aux->lock); if (r < 0) {
dm_bufio_release(to_buffer(*result));
report_recursive_bug(b, r); return r;
}
aux->write_locked = 0;
r = dm_bm_validate_buffer(bm, to_buffer(*result), aux, v); if (unlikely(r)) {
bl_up_read(&aux->lock);
dm_bufio_release(to_buffer(*result)); return r;
}
return 0;
}
int dm_bm_write_lock_zero(struct dm_block_manager *bm,
dm_block_t b, conststruct dm_block_validator *v, struct dm_block **result)
{ int r; struct buffer_aux *aux; void *p;
if (dm_bm_is_read_only(bm)) return -EPERM;
p = dm_bufio_new(bm->bufio, b, (struct dm_buffer **) result); if (IS_ERR(p)) return PTR_ERR(p);
memset(p, 0, dm_bm_block_size(bm));
aux = dm_bufio_get_aux_data(to_buffer(*result));
r = bl_down_write(&aux->lock); if (r) {
dm_bufio_release(to_buffer(*result)); return r;
}
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.