mirror of
https://github.com/versity/scoutfs.git
synced 2026-05-01 18:35:43 +00:00
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. Collapse the previous KC_ALLOC_SHRINKER, KC_INIT_SHRINKER_FUNCS, and KC_REGISTER_SHRINKER macros into a single KC_SETUP_SHRINKER macro. The three operations have to happen in different orders on different kernel APIs (the name is needed at alloc time on el10 and at register time on KC_SHRINKER_NAME kernels), so coupling them keeps the ordering correct per kernel. Add KC_SHRINKER_IS_NULL so callers can detect shrinker_alloc() failure on el10 and return -ENOMEM. The macro compiles to a constant 0 on older kernels where the shrinker is an embedded struct that cannot fail allocation. Signed-off-by: Auke Kok <auke.kok@versity.com>
This commit is contained in:
@@ -546,3 +546,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
|
||||
|
||||
@@ -1290,9 +1290,12 @@ int scoutfs_block_setup(struct super_block *sb)
|
||||
|
||||
binf->sb = sb;
|
||||
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_SETUP_SHRINKER(binf->shrinker, binf, 0, block_count_objects,
|
||||
block_scan_objects, "scoutfs-block:" SCSBF, SCSB_ARGS(sb));
|
||||
if (KC_SHRINKER_IS_NULL(binf->shrinker)) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
INIT_WORK(&binf->free_work, block_free_work);
|
||||
init_llist_head(&binf->free_llist);
|
||||
|
||||
@@ -1314,7 +1317,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_shrink_all(sb);
|
||||
flush_work(&binf->free_work);
|
||||
rhashtable_destroy(&binf->ht);
|
||||
|
||||
@@ -2626,10 +2626,10 @@ 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_SETUP_SHRINKER(cinf->shrinker, cinf, 0, item_cache_count_objects,
|
||||
item_cache_scan_objects, "scoutfs-item:" SCSBF, SCSB_ARGS(sb));
|
||||
if (KC_SHRINKER_IS_NULL(cinf->shrinker))
|
||||
return -ENOMEM;
|
||||
#ifdef KC_CPU_NOTIFIER
|
||||
cinf->notifier.notifier_call = item_cpu_callback;
|
||||
register_hotcpu_notifier(&cinf->notifier);
|
||||
@@ -2654,7 +2654,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);
|
||||
|
||||
@@ -142,25 +142,54 @@ 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_INIT_SHRINKER_FUNCS(name, countfn, scanfn) do { \
|
||||
__typeof__(name) _shrink = (name); \
|
||||
_shrink->count_objects = (countfn); \
|
||||
_shrink->scan_objects = (scanfn); \
|
||||
_shrink->seeks = DEFAULT_SEEKS; \
|
||||
#define KC_DEFINE_SHRINKER(name) struct shrinker *(name)
|
||||
#define KC_SHRINKER_CONTAINER_OF(ptr, type) ptr->private_data
|
||||
#define KC_SETUP_SHRINKER(ptr, priv, flags, countfn, scanfn, fmt, args) \
|
||||
do { \
|
||||
ptr = shrinker_alloc(flags, fmt, args); \
|
||||
if (ptr) { \
|
||||
ptr->private_data = (priv); \
|
||||
ptr->seeks = DEFAULT_SEEKS; \
|
||||
ptr->count_objects = countfn; \
|
||||
ptr->scan_objects = scanfn; \
|
||||
shrinker_register(ptr); \
|
||||
} \
|
||||
} while (0)
|
||||
#define KC_UNREGISTER_SHRINKER(ptr) shrinker_free(ptr)
|
||||
#define KC_SHRINKER_FN(ptr) (ptr)
|
||||
#define KC_SHRINKER_IS_NULL(ptr) (!(ptr))
|
||||
|
||||
#else /* KC_SHRINKER_ALLOC */
|
||||
#ifndef KC_SHRINKER_SHRINK
|
||||
// el9, el8
|
||||
|
||||
#define KC_DEFINE_SHRINKER(name) struct shrinker (name)
|
||||
#define KC_SHRINKER_CONTAINER_OF(ptr, type) container_of(ptr, type, shrinker)
|
||||
#ifdef KC_SHRINKER_NAME
|
||||
#define KC_REGISTER_SHRINKER register_shrinker
|
||||
#define KC_SETUP_SHRINKER(ptr, priv, flags, countfn, scanfn, fmt, args) \
|
||||
do { \
|
||||
(ptr).count_objects = (countfn); \
|
||||
(ptr).scan_objects = (scanfn); \
|
||||
(ptr).seeks = DEFAULT_SEEKS; \
|
||||
register_shrinker(&(ptr), fmt, args); \
|
||||
} while (0)
|
||||
#else
|
||||
#define KC_REGISTER_SHRINKER(ptr, fmt, ...) (register_shrinker(ptr))
|
||||
#define KC_SETUP_SHRINKER(ptr, priv, flags, countfn, scanfn, fmt, args) \
|
||||
do { \
|
||||
(ptr).count_objects = (countfn); \
|
||||
(ptr).scan_objects = (scanfn); \
|
||||
(ptr).seeks = DEFAULT_SEEKS; \
|
||||
register_shrinker(&(ptr)); \
|
||||
} while (0)
|
||||
#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
|
||||
@@ -176,19 +205,21 @@ 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); \
|
||||
_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_SETUP_SHRINKER(ptr, priv, flags, countfn, scanfn, fmt, args) \
|
||||
do { \
|
||||
(ptr).count_objects = (countfn); \
|
||||
(ptr).scan_objects = (scanfn); \
|
||||
(ptr).shrink.shrink = kc_shrink_wrapper_fn; \
|
||||
(ptr).shrink.seeks = DEFAULT_SEEKS; \
|
||||
register_shrinker(&(ptr).shrink); \
|
||||
} while (0)
|
||||
#define KC_UNREGISTER_SHRINKER(ptr) (unregister_shrinker(&(ptr).shrink))
|
||||
#define KC_SHRINKER_FN(ptr) (&(ptr).shrink)
|
||||
|
||||
#endif /* KC_SHRINKER_SHRINK */
|
||||
#define KC_SHRINKER_IS_NULL(ptr) (0)
|
||||
#endif /* KC_SHRINKER_ALLOC */
|
||||
|
||||
#ifdef KC_KERNEL_GETSOCKNAME_ADDRLEN
|
||||
#include <linux/net.h>
|
||||
|
||||
@@ -270,7 +270,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)
|
||||
@@ -1232,8 +1232,12 @@ 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_SETUP_SHRINKER(qtinf->shrinker, qtinf, 0, count_cached_checks,
|
||||
scan_cached_checks, "scoutfs-quota:" SCSBF, SCSB_ARGS(sb));
|
||||
if (KC_SHRINKER_IS_NULL(qtinf->shrinker)) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sbi->squota_info = qtinf;
|
||||
|
||||
@@ -1257,7 +1261,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));
|
||||
|
||||
@@ -1169,8 +1169,13 @@ 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_SETUP_SHRINKER(winf->shrinker, winf, 0, wkic_shrink_count,
|
||||
wkic_shrink_scan, "scoutfs-weak_item:" SCSBF, SCSB_ARGS(sb));
|
||||
if (KC_SHRINKER_IS_NULL(winf->shrinker)) {
|
||||
debugfs_remove(winf->drop_dentry);
|
||||
kfree(winf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sbi->wkic_info = winf;
|
||||
return 0;
|
||||
@@ -1198,7 +1203,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]) {
|
||||
|
||||
Reference in New Issue
Block a user