Shrinker API v4.

Yet another major shrinker API evolution in v6.6-rc4-53-gc42d50aefd17.
The struct shrinker now has to be dynamically allocated. This is
purposely a backwards incompatible break. We add another KC_ wrapper
around the new shrinker_alloc() and move some initialization around to
make this as much as possible low impact, but compatible with the old
APIs through substitution.

Signed-off-by: Auke Kok <auke.kok@versity.com>
This commit is contained in:
Auke Kok
2025-04-22 19:15:22 -04:00
parent d13bbb27eb
commit f8d2cd759e
7 changed files with 74 additions and 34 deletions

View File

@@ -484,3 +484,12 @@ ifneq (,$(shell grep -s 'define __assign_str.dst, src' \
include/trace/stages/stage6_event_callback.h))
ccflags-y += -DKC_HAVE_ASSIGN_STR_PARMS
endif
#
# v6.6-rc4-53-gc42d50aefd17
#
# el10 yet again modifies the shrinker API significantly, breaking our current
# implementation.
ifneq (,$(shell grep 'struct shrinker .shrinker_alloc' include/linux/shrinker.h))
ccflags-y += -DKC_SHRINKER_ALLOC
endif

View File

@@ -1300,9 +1300,9 @@ int scoutfs_block_setup(struct super_block *sb)
atomic_set(&binf->total_inserted, 0);
atomic64_set(&binf->access_counter, 0);
init_waitqueue_head(&binf->waitq);
KC_INIT_SHRINKER_FUNCS(&binf->shrinker, block_count_objects,
block_scan_objects);
KC_REGISTER_SHRINKER(&binf->shrinker, "scoutfs-block:" SCSBF, SCSB_ARGS(sb));
KC_ALLOC_SHRINKER(binf->shrinker, binf, 0, "scoutfs-block:" SCSBF, SCSB_ARGS(sb));
KC_INIT_SHRINKER_FUNCS(binf->shrinker, block_count_objects, block_scan_objects);
KC_REGISTER_SHRINKER(binf->shrinker);
INIT_WORK(&binf->free_work, block_free_work);
init_llist_head(&binf->free_llist);
@@ -1322,7 +1322,7 @@ void scoutfs_block_destroy(struct super_block *sb)
struct block_info *binf = SCOUTFS_SB(sb)->block_info;
if (binf) {
KC_UNREGISTER_SHRINKER(&binf->shrinker);
KC_UNREGISTER_SHRINKER(binf->shrinker);
block_remove_all(sb);
flush_work(&binf->free_work);
rhashtable_destroy(&binf->ht);

View File

@@ -2690,10 +2690,9 @@ int scoutfs_item_setup(struct super_block *sb)
for_each_possible_cpu(cpu)
init_pcpu_pages(cinf, cpu);
KC_INIT_SHRINKER_FUNCS(&cinf->shrinker, item_cache_count_objects,
item_cache_scan_objects);
KC_REGISTER_SHRINKER(&cinf->shrinker, "scoutfs-item:" SCSBF, SCSB_ARGS(sb));
KC_ALLOC_SHRINKER(cinf->shrinker, cinf, 0, "scoutfs-item:" SCSBF, SCSB_ARGS(sb));
KC_INIT_SHRINKER_FUNCS(cinf->shrinker, item_cache_count_objects, item_cache_scan_objects);
KC_REGISTER_SHRINKER(cinf->shrinker);
#ifdef KC_CPU_NOTIFIER
cinf->notifier.notifier_call = item_cpu_callback;
register_hotcpu_notifier(&cinf->notifier);
@@ -2720,7 +2719,7 @@ void scoutfs_item_destroy(struct super_block *sb)
#ifdef KC_CPU_NOTIFIER
unregister_hotcpu_notifier(&cinf->notifier);
#endif
KC_UNREGISTER_SHRINKER(&cinf->shrinker);
KC_UNREGISTER_SHRINKER(cinf->shrinker);
for_each_possible_cpu(cpu)
drop_pcpu_pages(sb, cinf, cpu);

View File

@@ -142,25 +142,53 @@ struct timespec64 kc_current_time(struct inode *inode);
#define kc_timespec timespec64
#endif
#ifndef KC_SHRINKER_SHRINK
#ifdef KC_SHRINKER_ALLOC
// el10+
#define KC_DEFINE_SHRINKER(name) struct shrinker name
#define KC_DEFINE_SHRINKER(name) struct shrinker *(name)
#define KC_SHRINKER_CONTAINER_OF(ptr, type) ptr->private_data
#define KC_ALLOC_SHRINKER(ptr, priv, flags, fmt, args) \
do { \
ptr = shrinker_alloc(flags, fmt, args); \
if (ptr) { \
ptr->private_data = (priv); \
ptr->seeks = 0; \
} \
} while (0)
#define KC_INIT_SHRINKER_FUNCS(ptr, countfn, scanfn) \
do { \
(ptr)->count_objects = countfn; \
(ptr)->scan_objects = scanfn; \
} while (0)
#define KC_REGISTER_SHRINKER(ptr) shrinker_register(ptr)
#define KC_UNREGISTER_SHRINKER(ptr) shrinker_free(ptr);
#define KC_SHRINKER_FN(ptr) (ptr)
#else /* KC_SHRINKER_ALLOC */
#ifndef KC_SHRINKER_SHRINK
// el9, el8
#define KC_DEFINE_SHRINKER(name) struct shrinker (name)
#define KC_INIT_SHRINKER_FUNCS(name, countfn, scanfn) do { \
__typeof__(name) _shrink = (name); \
__typeof__(name) *_shrink = &(name); \
_shrink->count_objects = (countfn); \
_shrink->scan_objects = (scanfn); \
_shrink->seeks = DEFAULT_SEEKS; \
_shrink->seeks = DEFAULT_SEEKS; \
} while (0)
#define KC_SHRINKER_CONTAINER_OF(ptr, type) container_of(ptr, type, shrinker)
#ifdef KC_SHRINKER_NAME
#define KC_REGISTER_SHRINKER register_shrinker
#define KC_ALLOC_SHRINKER(ptr, priv, flags, fmt, args) register_shrinker(&ptr, fmt, args)
#define KC_REGISTER_SHRINKER(ptr) do {} while(0)
#else
#define KC_REGISTER_SHRINKER(ptr, fmt, ...) (register_shrinker(ptr))
#define KC_ALLOC_SHRINKER(ptr, priv, flags, fmt, args) do {} while(0)
#define KC_REGISTER_SHRINKER(ptr) (register_shrinker(&ptr))
#endif /* KC_SHRINKER_NAME */
#define KC_UNREGISTER_SHRINKER(ptr) (unregister_shrinker(ptr))
#define KC_SHRINKER_FN(ptr) (ptr)
#else
#define KC_UNREGISTER_SHRINKER(ptr) (unregister_shrinker(&(ptr)))
#define KC_SHRINKER_FN(ptr) (&ptr)
#else /* KC_SHRINKER_SHRINK */
// el7
#include <linux/shrinker.h>
#ifndef SHRINK_STOP
@@ -177,18 +205,20 @@ struct kc_shrinker_wrapper {
#define KC_DEFINE_SHRINKER(name) struct kc_shrinker_wrapper name;
#define KC_INIT_SHRINKER_FUNCS(name, countfn, scanfn) do { \
struct kc_shrinker_wrapper *_wrap = (name); \
struct kc_shrinker_wrapper *_wrap = &(name); \
_wrap->count_objects = (countfn); \
_wrap->scan_objects = (scanfn); \
_wrap->shrink.shrink = kc_shrink_wrapper_fn; \
_wrap->shrink.seeks = DEFAULT_SEEKS; \
} while (0)
#define KC_SHRINKER_CONTAINER_OF(ptr, type) container_of(container_of(ptr, struct kc_shrinker_wrapper, shrink), type, shrinker)
#define KC_REGISTER_SHRINKER(ptr, fmt, ...) (register_shrinker(ptr.shrink))
#define KC_UNREGISTER_SHRINKER(ptr) (unregister_shrinker(ptr.shrink))
#define KC_SHRINKER_FN(ptr) (ptr.shrink)
#define KC_ALLOC_SHRINKER(ptr, priv, flags, fmt, args) do {} while(0)
#define KC_REGISTER_SHRINKER(ptr) (register_shrinker(&(ptr).shrink))
#define KC_UNREGISTER_SHRINKER(ptr) (unregister_shrinker(&(ptr).shrink))
#define KC_SHRINKER_FN(ptr) (&(ptr).shrink)
#endif /* KC_SHRINKER_SHRINK */
#endif /* KC_SHRINKER_ALLOC */
#ifdef KC_KERNEL_GETSOCKNAME_ADDRLEN
#include <linux/net.h>

View File

@@ -1505,7 +1505,7 @@ void scoutfs_free_unused_locks(struct super_block *sb)
.nr_to_scan = INT_MAX,
};
lock_scan_objects(KC_SHRINKER_FN(&linfo->shrinker), &sc);
lock_scan_objects(KC_SHRINKER_FN(linfo->shrinker), &sc);
}
static void lock_tseq_show(struct seq_file *m, struct scoutfs_tseq_entry *ent)
@@ -1612,7 +1612,7 @@ void scoutfs_lock_shutdown(struct super_block *sb)
trace_scoutfs_lock_shutdown(sb, linfo);
/* stop the shrinker from queueing work */
KC_UNREGISTER_SHRINKER(&linfo->shrinker);
KC_UNREGISTER_SHRINKER(linfo->shrinker);
flush_work(&linfo->shrink_work);
/* cause current and future lock calls to return errors */
@@ -1731,9 +1731,9 @@ int scoutfs_lock_setup(struct super_block *sb)
spin_lock_init(&linfo->lock);
linfo->lock_tree = RB_ROOT;
linfo->lock_range_tree = RB_ROOT;
KC_INIT_SHRINKER_FUNCS(&linfo->shrinker, lock_count_objects,
lock_scan_objects);
KC_REGISTER_SHRINKER(&linfo->shrinker, "scoutfs-lock:" SCSBF, SCSB_ARGS(sb));
KC_ALLOC_SHRINKER(linfo->shrinker, linfo, 0, "scoutfs-lock:" SCSBF, SCSB_ARGS(sb));
KC_INIT_SHRINKER_FUNCS(linfo->shrinker, lock_count_objects, lock_scan_objects);
KC_REGISTER_SHRINKER(linfo->shrinker);
INIT_LIST_HEAD(&linfo->lru_list);
INIT_WORK(&linfo->inv_work, lock_invalidate_worker);
INIT_LIST_HEAD(&linfo->inv_list);

View File

@@ -269,7 +269,7 @@ static void shrink_all_cached_checks(struct squota_info *qtinf)
{
struct shrink_control sc = { .nr_to_scan = LONG_MAX, };
scan_cached_checks(KC_SHRINKER_FN(&qtinf->shrinker), &sc);
scan_cached_checks(KC_SHRINKER_FN(qtinf->shrinker), &sc);
}
static u8 ns_is_attr(u8 ns)
@@ -1225,8 +1225,9 @@ int scoutfs_quota_setup(struct super_block *sb)
spin_lock_init(&qtinf->lock);
init_waitqueue_head(&qtinf->waitq);
KC_INIT_SHRINKER_FUNCS(&qtinf->shrinker, count_cached_checks, scan_cached_checks);
KC_REGISTER_SHRINKER(&qtinf->shrinker, "scoutfs-quota:" SCSBF, SCSB_ARGS(sb));
KC_ALLOC_SHRINKER(qtinf->shrinker, qtinf, 0, "scoutfs-quota:" SCSBF, SCSB_ARGS(sb));
KC_INIT_SHRINKER_FUNCS(qtinf->shrinker, count_cached_checks, scan_cached_checks);
KC_REGISTER_SHRINKER(qtinf->shrinker);
sbi->squota_info = qtinf;
@@ -1250,7 +1251,7 @@ void scoutfs_quota_destroy(struct super_block *sb)
if (qtinf) {
debugfs_remove(qtinf->drop_dentry);
KC_UNREGISTER_SHRINKER(&qtinf->shrinker);
KC_UNREGISTER_SHRINKER(qtinf->shrinker);
spin_lock(&qtinf->lock);
rs = rcu_dereference_protected(qtinf->ruleset, lockdep_is_held(&qtinf->lock));

View File

@@ -1112,8 +1112,9 @@ int scoutfs_wkic_setup(struct super_block *sb)
}
winf->sb = sb;
KC_INIT_SHRINKER_FUNCS(&winf->shrinker, wkic_shrink_count, wkic_shrink_scan);
KC_REGISTER_SHRINKER(&winf->shrinker, "scoutfs-weak_item:" SCSBF, SCSB_ARGS(sb));
KC_ALLOC_SHRINKER(winf->shrinker, winf, 0, "scoutfs-weak_item:" SCSBF, SCSB_ARGS(sb));
KC_INIT_SHRINKER_FUNCS(winf->shrinker, wkic_shrink_count, wkic_shrink_scan);
KC_REGISTER_SHRINKER(winf->shrinker);
sbi->wkic_info = winf;
return 0;
@@ -1141,7 +1142,7 @@ void scoutfs_wkic_destroy(struct super_block *sb)
if (winf) {
debugfs_remove(winf->drop_dentry);
KC_UNREGISTER_SHRINKER(&winf->shrinker);
KC_UNREGISTER_SHRINKER(winf->shrinker);
/* trees are in sync so tearing down one frees all pages */
rbtree_postorder_for_each_entry_safe(wpage, tmp, &winf->wpage_roots[0], nodes[0]) {