Merge patch series "lockref tidy ups + touch ups to it's usage by dcache"

Mateusz Guzik <mjguzik@gmail.com> says:

The open-coded check for < 0 indicating a dead object uses information
it should not know, so to speak.

This is a preliminary clean up for a longer term goal of moving dcache
away from lockref into an approach which can atomic_add both ways
instead of suffering the cmpxchg loop.

* patches from https://patch.msgid.link/20260724171422.429284-1-mjguzik@gmail.com:
  dcache: use lockref routines for dead count checks
  lockref: tidy up dead count handling

Link: https://patch.msgid.link/20260724171422.429284-1-mjguzik@gmail.com
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
Christian Brauner
2026-07-27 16:20:29 +02:00
10 changed files with 34 additions and 26 deletions

View File

@@ -1667,7 +1667,7 @@ __dentry_leases_walk(struct ceph_mds_client *mdsc,
if (!spin_trylock(&dentry->d_lock))
continue;
if (__lockref_is_dead(&dentry->d_lockref)) {
if (lockref_is_dead(&dentry->d_lockref)) {
list_del_init(&di->lease_list);
goto next;
}

View File

@@ -434,7 +434,7 @@ static inline void __d_clear_type_and_inode(struct dentry *dentry)
static void dentry_free(struct dentry *dentry)
{
DENTRY_WARN_ONCE(d_really_is_positive(dentry), dentry);
DENTRY_WARN_ONCE(dentry->d_lockref.count >= 0, dentry);
DENTRY_WARN_ONCE(!lockref_is_dead(&dentry->d_lockref), dentry);
D_FLAG_VERIFY(dentry, 0);
if (unlikely(dname_external(dentry))) {
struct external_name *p = external_name(dentry);
@@ -782,7 +782,7 @@ static bool lock_for_kill(struct dentry *dentry)
*
* If @dentry is idle and remains such after we assemble the full
* locking environment for eviction (see lock_for_kill() for details)
* we mark it doomed (->d_lockref.count < 0) and proceed to detaching
* we mark it doomed (see lockref_mark_dead()) and proceed to detaching
* it from any filesystem objects. Otherwise we drop ->d_lock and
* return %NULL.
*
@@ -946,7 +946,7 @@ static inline bool fast_dput(struct dentry *dentry)
if (unlikely(ret < 0)) {
spin_lock(&dentry->d_lock);
rcu_read_unlock();
if (WARN_ON_ONCE(dentry->d_lockref.count <= 0)) {
if (WARN_ON_ONCE(lockref_is_dead_or_zero(&dentry->d_lockref))) {
spin_unlock(&dentry->d_lock);
return true;
}
@@ -1644,7 +1644,7 @@ static enum d_walk_ret select_collect(void *_data, struct dentry *dentry)
if (data->start == dentry)
goto out;
if (dentry->d_lockref.count <= 0) {
if (lockref_is_dead_or_zero(&dentry->d_lockref)) {
__move_to_shrink_list(dentry, &data->dispose);
data->found++;
}
@@ -1676,7 +1676,7 @@ static enum d_walk_ret select_collect2(void *_data, struct dentry *dentry)
if (data->start == dentry)
goto out;
if (dentry->d_lockref.count <= 0) {
if (lockref_is_dead_or_zero(&dentry->d_lockref)) {
if (!__move_to_shrink_list(dentry, &data->dispose)) {
/*
* We need an enter RCU read-side critical area that
@@ -1747,7 +1747,7 @@ static void shrink_dcache_tree(struct dentry *parent, bool for_umount)
spin_lock(&v->d_lock);
rcu_read_unlock();
if (unlikely(v->d_lockref.count < 0)) {
if (unlikely(lockref_is_dead(&v->d_lockref))) {
// It's doomed; if it isn't dead yet, notify us
// once it becomes invisible to d_walk().
need_wait = d_add_waiter(v, &wait);
@@ -1823,7 +1823,7 @@ void shrink_dcache_for_umount(struct super_block *sb)
spin_unlock(&sb->s_roots_lock);
spin_lock(&dentry->d_lock);
rcu_read_unlock();
if (unlikely(dentry->d_lockref.count < 0)) {
if (unlikely(lockref_is_dead(&dentry->d_lockref))) {
struct completion_list wait;
bool need_wait = d_add_waiter(dentry, &wait);
@@ -2822,7 +2822,7 @@ struct dentry *d_alloc_parallel(struct dentry *parent,
spin_lock(&dentry->d_lock);
rcu_read_unlock();
/* now we can try to grab a reference */
if (unlikely(dentry->d_lockref.count < 0)) {
if (unlikely(lockref_is_dead(&dentry->d_lockref))) {
spin_unlock(&dentry->d_lock);
goto retry;
}

View File

@@ -725,7 +725,7 @@ static bool z_erofs_get_pcluster(struct z_erofs_pcluster *pcl)
return true;
spin_lock(&pcl->lockref.lock);
if (__lockref_is_dead(&pcl->lockref)) {
if (lockref_is_dead(&pcl->lockref)) {
spin_unlock(&pcl->lockref.lock);
return false;
}
@@ -945,7 +945,7 @@ static void z_erofs_put_pcluster(struct erofs_sb_info *sbi,
if (lockref_put_or_lock(&pcl->lockref))
return;
DBG_BUGON(__lockref_is_dead(&pcl->lockref));
DBG_BUGON(lockref_is_dead(&pcl->lockref));
if (!--pcl->lockref.count) {
if (try_free && xa_trylock(&sbi->managed_pslots)) {
free = __erofs_try_to_release_pcluster(sbi, pcl);

View File

@@ -2080,7 +2080,7 @@ static void clear_glock(struct gfs2_glock *gl)
gfs2_glock_remove_from_lru(gl);
spin_lock(&gl->gl_lockref.lock);
if (!__lockref_is_dead(&gl->gl_lockref)) {
if (!lockref_is_dead(&gl->gl_lockref)) {
gl->gl_lockref.count++;
if (gl->gl_state != LM_ST_UNLOCKED)
request_demote(gl, LM_ST_UNLOCKED, 0, false);
@@ -2115,7 +2115,7 @@ static void dump_glock_func(struct gfs2_glock *gl)
static void withdraw_glock(struct gfs2_glock *gl)
{
spin_lock(&gl->gl_lockref.lock);
if (!__lockref_is_dead(&gl->gl_lockref)) {
if (!lockref_is_dead(&gl->gl_lockref)) {
/*
* We don't want to write back any more dirty data. Unlock the
* remaining inode and resource group glocks; this will cause
@@ -2483,7 +2483,7 @@ static void gfs2_glock_iter_next(struct gfs2_glock_iter *gi, loff_t n)
continue;
break;
} else {
if (__lockref_is_dead(&gl->gl_lockref))
if (lockref_is_dead(&gl->gl_lockref))
continue;
n--;
}

View File

@@ -126,7 +126,7 @@ static void gdlm_ast(void *arg)
clear_bit(GLF_BLOCKING, &gl->gl_flags);
/* If the glock is dead, we only react to a dlm_unlock() reply. */
if (__lockref_is_dead(&gl->gl_lockref) &&
if (lockref_is_dead(&gl->gl_lockref) &&
gl->gl_lksb.sb_status != -DLM_EUNLOCK)
return;
@@ -182,7 +182,7 @@ static void gdlm_bast(void *arg, int mode)
{
struct gfs2_glock *gl = arg;
if (__lockref_is_dead(&gl->gl_lockref))
if (lockref_is_dead(&gl->gl_lockref))
return;
switch (mode) {
@@ -329,7 +329,7 @@ static void gdlm_put_lock(struct gfs2_glock *gl)
uint32_t flags = 0;
int error;
BUG_ON(!__lockref_is_dead(&gl->gl_lockref));
BUG_ON(!lockref_is_dead(&gl->gl_lockref));
if (test_bit(GLF_INITIAL, &gl->gl_flags)) {
gfs2_glock_free(gl);

View File

@@ -342,7 +342,7 @@ static void qd_put(struct gfs2_quota_data *qd)
if (lockref_put_or_lock(&qd->qd_lockref))
return;
BUG_ON(__lockref_is_dead(&qd->qd_lockref));
BUG_ON(lockref_is_dead(&qd->qd_lockref));
sdp = qd->qd_sbd;
if (unlikely(!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))) {
lockref_mark_dead(&qd->qd_lockref);
@@ -486,7 +486,7 @@ static bool qd_grab_sync(struct gfs2_sbd *sdp, struct gfs2_quota_data *qd,
qd->qd_sync_gen >= sync_gen)
goto out;
if (__lockref_is_dead(&qd->qd_lockref))
if (lockref_is_dead(&qd->qd_lockref))
goto out;
qd->qd_lockref.count++;

View File

@@ -80,7 +80,7 @@ xfs_buf_stale(
spin_lock(&bp->b_lockref.lock);
atomic_set(&bp->b_lru_ref, 0);
if (!__lockref_is_dead(&bp->b_lockref))
if (!lockref_is_dead(&bp->b_lockref))
list_lru_del_obj(&bp->b_target->bt_lru, &bp->b_lru);
spin_unlock(&bp->b_lockref.lock);
}
@@ -826,7 +826,7 @@ static void
xfs_buf_destroy(
struct xfs_buf *bp)
{
ASSERT(__lockref_is_dead(&bp->b_lockref));
ASSERT(lockref_is_dead(&bp->b_lockref));
ASSERT(!(bp->b_flags & _XBF_DELWRI_Q));
if (bp->b_pag)

View File

@@ -128,7 +128,7 @@ xfs_qm_dqpurge(
struct xfs_quotainfo *qi = dqp->q_mount->m_quotainfo;
spin_lock(&dqp->q_lockref.lock);
if (dqp->q_lockref.count > 0 || __lockref_is_dead(&dqp->q_lockref)) {
if (dqp->q_lockref.count > 0 || lockref_is_dead(&dqp->q_lockref)) {
spin_unlock(&dqp->q_lockref.lock);
return -EAGAIN;
}
@@ -430,7 +430,7 @@ xfs_qm_dquot_isolate(
* from the LRU, leave it for the freeing task to complete the freeing
* process rather than risk it being free from under us here.
*/
if (__lockref_is_dead(&dqp->q_lockref))
if (lockref_is_dead(&dqp->q_lockref))
goto out_miss_unlock;
/*

View File

@@ -34,6 +34,8 @@ struct lockref {
};
};
#define __LOCKREF_DEAD_VAL -128
/**
* lockref_init - Initialize a lockref
* @lockref: pointer to lockref structure
@@ -55,9 +57,15 @@ void lockref_mark_dead(struct lockref *lockref);
bool lockref_get_not_dead(struct lockref *lockref);
/* Must be called under spinlock for reliable results */
static inline bool __lockref_is_dead(const struct lockref *l)
static inline bool lockref_is_dead(const struct lockref *l)
{
return ((int)l->count < 0);
return (READ_ONCE(l->count) == __LOCKREF_DEAD_VAL);
}
static inline bool lockref_is_dead_or_zero(const struct lockref *l)
{
int count = READ_ONCE(l->count);
return (count == __LOCKREF_DEAD_VAL || count == 0);
}
#endif /* __LINUX_LOCKREF_H */

View File

@@ -131,7 +131,7 @@ EXPORT_SYMBOL(lockref_put_or_lock);
void lockref_mark_dead(struct lockref *lockref)
{
assert_spin_locked(&lockref->lock);
lockref->count = -128;
lockref->count = __LOCKREF_DEAD_VAL;
}
EXPORT_SYMBOL(lockref_mark_dead);