diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 18818269..3bf3ccdb 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -425,3 +425,40 @@ endif ifneq (,$(shell grep 'int ..remap_pages..struct vm_area_struct' include/linux/mm.h)) ccflags-y += -DKC_MM_REMAP_PAGES endif + +# +# v3.19-4742-g503c358cf192 +# +# list_lru_shrink_count() and list_lru_shrink_walk() introduced +# +ifneq (,$(shell grep 'list_lru_shrink_count.*struct list_lru' include/linux/list_lru.h)) +ccflags-y += -DKC_LIST_LRU_SHRINK_COUNT_WALK +endif + +# +# v3.19-4757-g3f97b163207c +# +# lru_list_walk_cb lru arg added +# +ifneq (,$(shell grep 'struct list_head \*item, spinlock_t \*lock, void \*cb_arg' include/linux/list_lru.h)) +ccflags-y += -DKC_LIST_LRU_WALK_CB_ITEM_LOCK +endif + +# +# v6.7-rc4-153-g0a97c01cd20b +# +# list_lru_{add,del} -> list_lru_{add,del}_obj +# +ifneq (,$(shell grep '^bool list_lru_add_obj' include/linux/list_lru.h)) +ccflags-y += -DKC_LIST_LRU_ADD_OBJ +endif + +# +# v6.12-rc6-227-gda0c02516c50 +# +# lru_list_walk_cb lock arg removed +# +ifneq (,$(shell grep 'struct list_lru_one \*list, spinlock_t \*lock, void \*cb_arg' include/linux/list_lru.h)) +ccflags-y += -DKC_LIST_LRU_WALK_CB_LIST_LOCK +endif + diff --git a/kmod/src/kernelcompat.c b/kmod/src/kernelcompat.c index cf1de599..2463d134 100644 --- a/kmod/src/kernelcompat.c +++ b/kmod/src/kernelcompat.c @@ -81,3 +81,69 @@ kc_generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, return written ? written : status; } #endif + +#include + +#ifdef KC_LIST_LRU_WALK_CB_ITEM_LOCK +static enum lru_status kc_isolate(struct list_head *item, spinlock_t *lock, void *cb_arg) +{ + struct kc_isolate_args *args = cb_arg; + + /* isolate doesn't use list, nr_items updated in caller */ + return args->isolate(item, NULL, args->cb_arg); +} + +unsigned long kc_list_lru_walk(struct list_lru *lru, kc_list_lru_walk_cb_t isolate, void *cb_arg, + unsigned long nr_to_walk) +{ + struct kc_isolate_args args = { + .isolate = isolate, + .cb_arg = cb_arg, + }; + + return list_lru_walk(lru, kc_isolate, &args, nr_to_walk); +} + +unsigned long kc_list_lru_shrink_walk(struct list_lru *lru, struct shrink_control *sc, + kc_list_lru_walk_cb_t isolate, void *cb_arg) +{ + struct kc_isolate_args args = { + .isolate = isolate, + .cb_arg = cb_arg, + }; + + return list_lru_shrink_walk(lru, sc, kc_isolate, &args); +} +#endif + +#ifdef KC_LIST_LRU_WALK_CB_LIST_LOCK +static enum lru_status kc_isolate(struct list_head *item, struct list_lru_one *list, + spinlock_t *lock, void *cb_arg) +{ + struct kc_isolate_args *args = cb_arg; + + return args->isolate(item, list, args->cb_arg); +} + +unsigned long kc_list_lru_walk(struct list_lru *lru, kc_list_lru_walk_cb_t isolate, void *cb_arg, + unsigned long nr_to_walk) +{ + struct kc_isolate_args args = { + .isolate = isolate, + .cb_arg = cb_arg, + }; + + return list_lru_walk(lru, kc_isolate, &args, nr_to_walk); +} +unsigned long kc_list_lru_shrink_walk(struct list_lru *lru, struct shrink_control *sc, + kc_list_lru_walk_cb_t isolate, void *cb_arg) +{ + struct kc_isolate_args args = { + .isolate = isolate, + .cb_arg = cb_arg, + }; + + return list_lru_shrink_walk(lru, sc, kc_isolate, &args); +} + +#endif diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index 691db6b4..7fb566b5 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -410,4 +410,51 @@ static inline vm_fault_t vmf_error(int err) } #endif +#include + +#ifndef KC_LIST_LRU_SHRINK_COUNT_WALK +/* we don't bother with sc->{nid,memcg} (which doesn't exist in oldest kernels) */ +static inline unsigned long list_lru_shrink_count(struct list_lru *lru, + struct shrink_control *sc) +{ + return list_lru_count(lru); +} +static inline unsigned long +list_lru_shrink_walk(struct list_lru *lru, struct shrink_control *sc, + list_lru_walk_cb isolate, void *cb_arg) +{ + return list_lru_walk(lru, isolate, cb_arg, sc->nr_to_scan); +} +#endif + +#ifndef KC_LIST_LRU_ADD_OBJ +#define list_lru_add_obj list_lru_add +#define list_lru_del_obj list_lru_del +#endif + +#if defined(KC_LIST_LRU_WALK_CB_LIST_LOCK) || defined(KC_LIST_LRU_WALK_CB_ITEM_LOCK) +struct list_lru_one; +typedef enum lru_status (*kc_list_lru_walk_cb_t)(struct list_head *item, struct list_lru_one *list, + void *cb_arg); +struct kc_isolate_args { + kc_list_lru_walk_cb_t isolate; + void *cb_arg; +}; +unsigned long kc_list_lru_walk(struct list_lru *lru, kc_list_lru_walk_cb_t isolate, void *cb_arg, + unsigned long nr_to_walk); +unsigned long kc_list_lru_shrink_walk(struct list_lru *lru, struct shrink_control *sc, + kc_list_lru_walk_cb_t isolate, void *cb_arg); +#else +#define kc_list_lru_shrink_walk list_lru_shrink_walk +#endif + +#if defined(KC_LIST_LRU_WALK_CB_ITEM_LOCK) +/* isolate moved by hand, nr_items updated in walk as _REMOVE returned */ +static inline void list_lru_isolate_move(struct list_lru_one *list, struct list_head *item, + struct list_head *head) +{ + list_move(item, head); +} +#endif + #endif