mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-02-23 00:00:02 +03:00
Update six locks
This commit is contained in:
parent
db39aa3e1b
commit
98b8f8d0c0
@ -1,4 +1,4 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
|
||||||
#ifndef _LINUX_SIX_H
|
#ifndef _LINUX_SIX_H
|
||||||
#define _LINUX_SIX_H
|
#define _LINUX_SIX_H
|
||||||
@ -50,12 +50,12 @@
|
|||||||
* six_trylock_convert(lock, from, to)
|
* six_trylock_convert(lock, from, to)
|
||||||
*
|
*
|
||||||
* A lock may be held multiple types by the same thread (for read or intent,
|
* A lock may be held multiple types by the same thread (for read or intent,
|
||||||
* not write) - up to SIX_LOCK_MAX_RECURSE. However, the six locks code does
|
* not write). However, the six locks code does _not_ implement the actual
|
||||||
* _not_ implement the actual recursive checks itself though - rather, if your
|
* recursive checks itself though - rather, if your code (e.g. btree iterator
|
||||||
* code (e.g. btree iterator code) knows that the current thread already has a
|
* code) knows that the current thread already has a lock held, and for the
|
||||||
* lock held, and for the correct type, six_lock_increment() may be used to
|
* correct type, six_lock_increment() may be used to bump up the counter for
|
||||||
* bump up the counter for that type - the only effect is that one more call to
|
* that type - the only effect is that one more call to unlock will be required
|
||||||
* unlock will be required before the lock is unlocked.
|
* before the lock is unlocked.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/lockdep.h>
|
#include <linux/lockdep.h>
|
||||||
@ -80,8 +80,8 @@ union six_lock_state {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
unsigned read_lock:26;
|
unsigned read_lock:28;
|
||||||
unsigned intent_lock:3;
|
unsigned intent_lock:1;
|
||||||
unsigned waiters:3;
|
unsigned waiters:3;
|
||||||
/*
|
/*
|
||||||
* seq works much like in seqlocks: it's incremented every time
|
* seq works much like in seqlocks: it's incremented every time
|
||||||
@ -96,8 +96,6 @@ union six_lock_state {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SIX_LOCK_MAX_RECURSE ((1 << 3) - 1)
|
|
||||||
|
|
||||||
enum six_lock_type {
|
enum six_lock_type {
|
||||||
SIX_LOCK_read,
|
SIX_LOCK_read,
|
||||||
SIX_LOCK_intent,
|
SIX_LOCK_intent,
|
||||||
@ -106,6 +104,7 @@ enum six_lock_type {
|
|||||||
|
|
||||||
struct six_lock {
|
struct six_lock {
|
||||||
union six_lock_state state;
|
union six_lock_state state;
|
||||||
|
unsigned intent_lock_recurse;
|
||||||
struct task_struct *owner;
|
struct task_struct *owner;
|
||||||
struct optimistic_spin_queue osq;
|
struct optimistic_spin_queue osq;
|
||||||
|
|
||||||
@ -139,8 +138,6 @@ do { \
|
|||||||
|
|
||||||
#define __SIX_VAL(field, _v) (((union six_lock_state) { .field = _v }).v)
|
#define __SIX_VAL(field, _v) (((union six_lock_state) { .field = _v }).v)
|
||||||
|
|
||||||
#ifdef SIX_LOCK_SEPARATE_LOCKFNS
|
|
||||||
|
|
||||||
#define __SIX_LOCK(type) \
|
#define __SIX_LOCK(type) \
|
||||||
bool six_trylock_##type(struct six_lock *); \
|
bool six_trylock_##type(struct six_lock *); \
|
||||||
bool six_relock_##type(struct six_lock *, u32); \
|
bool six_relock_##type(struct six_lock *, u32); \
|
||||||
@ -185,41 +182,6 @@ static inline void six_unlock_type(struct six_lock *lock, enum six_lock_type typ
|
|||||||
SIX_LOCK_DISPATCH(type, six_unlock, lock);
|
SIX_LOCK_DISPATCH(type, six_unlock, lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
bool six_trylock_type(struct six_lock *, enum six_lock_type);
|
|
||||||
bool six_relock_type(struct six_lock *, enum six_lock_type, unsigned);
|
|
||||||
void six_lock_type(struct six_lock *, enum six_lock_type);
|
|
||||||
void six_unlock_type(struct six_lock *, enum six_lock_type);
|
|
||||||
|
|
||||||
#define __SIX_LOCK(type) \
|
|
||||||
static __always_inline bool six_trylock_##type(struct six_lock *lock) \
|
|
||||||
{ \
|
|
||||||
return six_trylock_type(lock, SIX_LOCK_##type); \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
static __always_inline bool six_relock_##type(struct six_lock *lock, u32 seq)\
|
|
||||||
{ \
|
|
||||||
return six_relock_type(lock, SIX_LOCK_##type, seq); \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
static __always_inline void six_lock_##type(struct six_lock *lock) \
|
|
||||||
{ \
|
|
||||||
six_lock_type(lock, SIX_LOCK_##type); \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
static __always_inline void six_unlock_##type(struct six_lock *lock) \
|
|
||||||
{ \
|
|
||||||
six_unlock_type(lock, SIX_LOCK_##type); \
|
|
||||||
}
|
|
||||||
|
|
||||||
__SIX_LOCK(read)
|
|
||||||
__SIX_LOCK(intent)
|
|
||||||
__SIX_LOCK(write)
|
|
||||||
#undef __SIX_LOCK
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void six_lock_downgrade(struct six_lock *);
|
void six_lock_downgrade(struct six_lock *);
|
||||||
bool six_lock_tryupgrade(struct six_lock *);
|
bool six_lock_tryupgrade(struct six_lock *);
|
||||||
bool six_trylock_convert(struct six_lock *, enum six_lock_type,
|
bool six_trylock_convert(struct six_lock *, enum six_lock_type,
|
||||||
|
67
linux/six.c
67
linux/six.c
@ -76,17 +76,6 @@ static inline void six_set_owner(struct six_lock *lock, enum six_lock_type type,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void six_clear_owner(struct six_lock *lock, enum six_lock_type type)
|
|
||||||
{
|
|
||||||
if (type != SIX_LOCK_intent)
|
|
||||||
return;
|
|
||||||
|
|
||||||
EBUG_ON(lock->owner != current);
|
|
||||||
|
|
||||||
if (lock->state.intent_lock == 1)
|
|
||||||
lock->owner = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static __always_inline bool do_six_trylock_type(struct six_lock *lock,
|
static __always_inline bool do_six_trylock_type(struct six_lock *lock,
|
||||||
enum six_lock_type type)
|
enum six_lock_type type)
|
||||||
{
|
{
|
||||||
@ -393,16 +382,24 @@ static void __six_unlock_type(struct six_lock *lock, enum six_lock_type type)
|
|||||||
EBUG_ON(type == SIX_LOCK_write &&
|
EBUG_ON(type == SIX_LOCK_write &&
|
||||||
!(lock->state.v & __SIX_LOCK_HELD_intent));
|
!(lock->state.v & __SIX_LOCK_HELD_intent));
|
||||||
|
|
||||||
six_clear_owner(lock, type);
|
six_release(&lock->dep_map);
|
||||||
|
|
||||||
|
if (type == SIX_LOCK_intent) {
|
||||||
|
EBUG_ON(lock->owner != current);
|
||||||
|
|
||||||
|
if (lock->intent_lock_recurse) {
|
||||||
|
--lock->intent_lock_recurse;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock->owner = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
state.v = atomic64_add_return_release(l[type].unlock_val,
|
state.v = atomic64_add_return_release(l[type].unlock_val,
|
||||||
&lock->state.counter);
|
&lock->state.counter);
|
||||||
six_release(&lock->dep_map);
|
|
||||||
six_lock_wakeup(lock, state, l[type].unlock_wakeup);
|
six_lock_wakeup(lock, state, l[type].unlock_wakeup);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SIX_LOCK_SEPARATE_LOCKFNS
|
|
||||||
|
|
||||||
#define __SIX_LOCK(type) \
|
#define __SIX_LOCK(type) \
|
||||||
bool six_trylock_##type(struct six_lock *lock) \
|
bool six_trylock_##type(struct six_lock *lock) \
|
||||||
{ \
|
{ \
|
||||||
@ -434,36 +431,6 @@ __SIX_LOCK(write)
|
|||||||
|
|
||||||
#undef __SIX_LOCK
|
#undef __SIX_LOCK
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
bool six_trylock_type(struct six_lock *lock, enum six_lock_type type)
|
|
||||||
{
|
|
||||||
return __six_trylock_type(lock, type);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(six_trylock_type);
|
|
||||||
|
|
||||||
bool six_relock_type(struct six_lock *lock, enum six_lock_type type,
|
|
||||||
unsigned seq)
|
|
||||||
{
|
|
||||||
return __six_relock_type(lock, type, seq);
|
|
||||||
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(six_relock_type);
|
|
||||||
|
|
||||||
void six_lock_type(struct six_lock *lock, enum six_lock_type type)
|
|
||||||
{
|
|
||||||
__six_lock_type(lock, type);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(six_lock_type);
|
|
||||||
|
|
||||||
void six_unlock_type(struct six_lock *lock, enum six_lock_type type)
|
|
||||||
{
|
|
||||||
__six_unlock_type(lock, type);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(six_unlock_type);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Convert from intent to read: */
|
/* Convert from intent to read: */
|
||||||
void six_lock_downgrade(struct six_lock *lock)
|
void six_lock_downgrade(struct six_lock *lock)
|
||||||
{
|
{
|
||||||
@ -530,6 +497,16 @@ void six_lock_increment(struct six_lock *lock, enum six_lock_type type)
|
|||||||
|
|
||||||
/* XXX: assert already locked, and that we don't overflow: */
|
/* XXX: assert already locked, and that we don't overflow: */
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case SIX_LOCK_read:
|
||||||
atomic64_add(l[type].lock_val, &lock->state.counter);
|
atomic64_add(l[type].lock_val, &lock->state.counter);
|
||||||
|
break;
|
||||||
|
case SIX_LOCK_intent:
|
||||||
|
lock->intent_lock_recurse++;
|
||||||
|
break;
|
||||||
|
case SIX_LOCK_write:
|
||||||
|
BUG();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(six_lock_increment);
|
EXPORT_SYMBOL_GPL(six_lock_increment);
|
||||||
|
Loading…
Reference in New Issue
Block a user