Merge branch 'akpm' (patches from Andrew)
Merge misc fixes from Andrew Morton: "21 patches. Subsystems affected by this patch series: MAINTAINERS, mailmap, and mm (mlock, pagecache, damon, slub, memcg, hugetlb, and pagecache)" * emailed patches from Andrew Morton <akpm@linux-foundation.org>: (21 commits) mm: bdi: initialize bdi_min_ratio when bdi is unregistered hugetlbfs: fix issue of preallocation of gigantic pages can't work mm/memcg: relocate mod_objcg_mlstate(), get_obj_stock() and put_obj_stock() mm/slub: fix endianness bug for alloc/free_traces attributes selftests/damon: split test cases selftests/damon: test debugfs file reads/writes with huge count selftests/damon: test wrong DAMOS condition ranges input selftests/damon: test DAMON enabling with empty target_ids case selftests/damon: skip test if DAMON is running mm/damon/vaddr-test: remove unnecessary variables mm/damon/vaddr-test: split a test function having >1024 bytes frame size mm/damon/vaddr: remove an unnecessary warning message mm/damon/core: remove unnecessary error messages mm/damon/dbgfs: remove an unnecessary error message mm/damon/core: use better timer mechanisms selection threshold mm/damon/core: fix fake load reports due to uninterruptible sleeps timers: implement usleep_idle_range() filemap: remove PageHWPoison check from next_uptodate_page() mailmap: update email address for Guo Ren MAINTAINERS: update kdump maintainers ...
This commit is contained in:
commit
df442a4ec7
2
.mailmap
2
.mailmap
|
@ -126,6 +126,8 @@ Greg Kroah-Hartman <gregkh@suse.de>
|
|||
Greg Kroah-Hartman <greg@kroah.com>
|
||||
Greg Kurz <groug@kaod.org> <gkurz@linux.vnet.ibm.com>
|
||||
Gregory CLEMENT <gregory.clement@bootlin.com> <gregory.clement@free-electrons.com>
|
||||
Guo Ren <guoren@kernel.org> <guoren@linux.alibaba.com>
|
||||
Guo Ren <guoren@kernel.org> <ren_guo@c-sky.com>
|
||||
Gustavo Padovan <gustavo@las.ic.unicamp.br>
|
||||
Gustavo Padovan <padovan@profusion.mobi>
|
||||
Hanjun Guo <guohanjun@huawei.com> <hanjun.guo@linaro.org>
|
||||
|
|
|
@ -10279,9 +10279,9 @@ F: lib/Kconfig.kcsan
|
|||
F: scripts/Makefile.kcsan
|
||||
|
||||
KDUMP
|
||||
M: Dave Young <dyoung@redhat.com>
|
||||
M: Baoquan He <bhe@redhat.com>
|
||||
R: Vivek Goyal <vgoyal@redhat.com>
|
||||
R: Dave Young <dyoung@redhat.com>
|
||||
L: kexec@lists.infradead.org
|
||||
S: Maintained
|
||||
W: http://lse.sourceforge.net/kdump/
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/math.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
extern unsigned long loops_per_jiffy;
|
||||
|
||||
|
@ -58,7 +59,18 @@ void calibrate_delay(void);
|
|||
void __attribute__((weak)) calibration_delay_done(void);
|
||||
void msleep(unsigned int msecs);
|
||||
unsigned long msleep_interruptible(unsigned int msecs);
|
||||
void usleep_range(unsigned long min, unsigned long max);
|
||||
void usleep_range_state(unsigned long min, unsigned long max,
|
||||
unsigned int state);
|
||||
|
||||
static inline void usleep_range(unsigned long min, unsigned long max)
|
||||
{
|
||||
usleep_range_state(min, max, TASK_UNINTERRUPTIBLE);
|
||||
}
|
||||
|
||||
static inline void usleep_idle_range(unsigned long min, unsigned long max)
|
||||
{
|
||||
usleep_range_state(min, max, TASK_IDLE);
|
||||
}
|
||||
|
||||
static inline void ssleep(unsigned int seconds)
|
||||
{
|
||||
|
|
|
@ -66,10 +66,17 @@ struct rlimit64 {
|
|||
#define _STK_LIM (8*1024*1024)
|
||||
|
||||
/*
|
||||
* GPG2 wants 64kB of mlocked memory, to make sure pass phrases
|
||||
* and other sensitive information are never written to disk.
|
||||
* Limit the amount of locked memory by some sane default:
|
||||
* root can always increase this limit if needed.
|
||||
*
|
||||
* The main use-cases are (1) preventing sensitive memory
|
||||
* from being swapped; (2) real-time operations; (3) via
|
||||
* IOURING_REGISTER_BUFFERS.
|
||||
*
|
||||
* The first two don't need much. The latter will take as
|
||||
* much as it can get. 8MB is a reasonably sane default.
|
||||
*/
|
||||
#define MLOCK_LIMIT ((PAGE_SIZE > 64*1024) ? PAGE_SIZE : 64*1024)
|
||||
#define MLOCK_LIMIT (8*1024*1024)
|
||||
|
||||
/*
|
||||
* Due to binary compatibility, the actual resource numbers
|
||||
|
|
|
@ -2054,26 +2054,28 @@ unsigned long msleep_interruptible(unsigned int msecs)
|
|||
EXPORT_SYMBOL(msleep_interruptible);
|
||||
|
||||
/**
|
||||
* usleep_range - Sleep for an approximate time
|
||||
* @min: Minimum time in usecs to sleep
|
||||
* @max: Maximum time in usecs to sleep
|
||||
* usleep_range_state - Sleep for an approximate time in a given state
|
||||
* @min: Minimum time in usecs to sleep
|
||||
* @max: Maximum time in usecs to sleep
|
||||
* @state: State of the current task that will be while sleeping
|
||||
*
|
||||
* In non-atomic context where the exact wakeup time is flexible, use
|
||||
* usleep_range() instead of udelay(). The sleep improves responsiveness
|
||||
* usleep_range_state() instead of udelay(). The sleep improves responsiveness
|
||||
* by avoiding the CPU-hogging busy-wait of udelay(), and the range reduces
|
||||
* power usage by allowing hrtimers to take advantage of an already-
|
||||
* scheduled interrupt instead of scheduling a new one just for this sleep.
|
||||
*/
|
||||
void __sched usleep_range(unsigned long min, unsigned long max)
|
||||
void __sched usleep_range_state(unsigned long min, unsigned long max,
|
||||
unsigned int state)
|
||||
{
|
||||
ktime_t exp = ktime_add_us(ktime_get(), min);
|
||||
u64 delta = (u64)(max - min) * NSEC_PER_USEC;
|
||||
|
||||
for (;;) {
|
||||
__set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
__set_current_state(state);
|
||||
/* Do not return before the requested sleep time has elapsed */
|
||||
if (!schedule_hrtimeout_range(&exp, delta, HRTIMER_MODE_ABS))
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(usleep_range);
|
||||
EXPORT_SYMBOL(usleep_range_state);
|
||||
|
|
|
@ -945,6 +945,13 @@ void bdi_unregister(struct backing_dev_info *bdi)
|
|||
wb_shutdown(&bdi->wb);
|
||||
cgwb_bdi_unregister(bdi);
|
||||
|
||||
/*
|
||||
* If this BDI's min ratio has been set, use bdi_set_min_ratio() to
|
||||
* update the global bdi_min_ratio.
|
||||
*/
|
||||
if (bdi->min_ratio)
|
||||
bdi_set_min_ratio(bdi, 0);
|
||||
|
||||
if (bdi->dev) {
|
||||
bdi_debug_unregister(bdi);
|
||||
device_unregister(bdi->dev);
|
||||
|
|
|
@ -282,7 +282,6 @@ int damon_set_targets(struct damon_ctx *ctx,
|
|||
for (i = 0; i < nr_ids; i++) {
|
||||
t = damon_new_target(ids[i]);
|
||||
if (!t) {
|
||||
pr_err("Failed to alloc damon_target\n");
|
||||
/* The caller should do cleanup of the ids itself */
|
||||
damon_for_each_target_safe(t, next, ctx)
|
||||
damon_destroy_target(t);
|
||||
|
@ -312,16 +311,10 @@ int damon_set_attrs(struct damon_ctx *ctx, unsigned long sample_int,
|
|||
unsigned long aggr_int, unsigned long primitive_upd_int,
|
||||
unsigned long min_nr_reg, unsigned long max_nr_reg)
|
||||
{
|
||||
if (min_nr_reg < 3) {
|
||||
pr_err("min_nr_regions (%lu) must be at least 3\n",
|
||||
min_nr_reg);
|
||||
if (min_nr_reg < 3)
|
||||
return -EINVAL;
|
||||
}
|
||||
if (min_nr_reg > max_nr_reg) {
|
||||
pr_err("invalid nr_regions. min (%lu) > max (%lu)\n",
|
||||
min_nr_reg, max_nr_reg);
|
||||
if (min_nr_reg > max_nr_reg)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctx->sample_interval = sample_int;
|
||||
ctx->aggr_interval = aggr_int;
|
||||
|
@ -980,10 +973,11 @@ static unsigned long damos_wmark_wait_us(struct damos *scheme)
|
|||
|
||||
static void kdamond_usleep(unsigned long usecs)
|
||||
{
|
||||
if (usecs > 100 * 1000)
|
||||
schedule_timeout_interruptible(usecs_to_jiffies(usecs));
|
||||
/* See Documentation/timers/timers-howto.rst for the thresholds */
|
||||
if (usecs > 20 * USEC_PER_MSEC)
|
||||
schedule_timeout_idle(usecs_to_jiffies(usecs));
|
||||
else
|
||||
usleep_range(usecs, usecs + 1);
|
||||
usleep_idle_range(usecs, usecs + 1);
|
||||
}
|
||||
|
||||
/* Returns negative error code if it's not activated but should return */
|
||||
|
@ -1038,7 +1032,7 @@ static int kdamond_fn(void *data)
|
|||
ctx->callback.after_sampling(ctx))
|
||||
done = true;
|
||||
|
||||
usleep_range(ctx->sample_interval, ctx->sample_interval + 1);
|
||||
kdamond_usleep(ctx->sample_interval);
|
||||
|
||||
if (ctx->primitive.check_accesses)
|
||||
max_nr_accesses = ctx->primitive.check_accesses(ctx);
|
||||
|
|
|
@ -210,10 +210,8 @@ static struct damos **str_to_schemes(const char *str, ssize_t len,
|
|||
&wmarks.low, &parsed);
|
||||
if (ret != 18)
|
||||
break;
|
||||
if (!damos_action_valid(action)) {
|
||||
pr_err("wrong action %d\n", action);
|
||||
if (!damos_action_valid(action))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pos += parsed;
|
||||
scheme = damon_new_scheme(min_sz, max_sz, min_nr_a, max_nr_a,
|
||||
|
|
|
@ -135,7 +135,6 @@ static void damon_do_test_apply_three_regions(struct kunit *test,
|
|||
struct damon_addr_range *three_regions,
|
||||
unsigned long *expected, int nr_expected)
|
||||
{
|
||||
struct damon_ctx *ctx = damon_new_ctx();
|
||||
struct damon_target *t;
|
||||
struct damon_region *r;
|
||||
int i;
|
||||
|
@ -145,7 +144,6 @@ static void damon_do_test_apply_three_regions(struct kunit *test,
|
|||
r = damon_new_region(regions[i * 2], regions[i * 2 + 1]);
|
||||
damon_add_region(r, t);
|
||||
}
|
||||
damon_add_target(ctx, t);
|
||||
|
||||
damon_va_apply_three_regions(t, three_regions);
|
||||
|
||||
|
@ -154,8 +152,6 @@ static void damon_do_test_apply_three_regions(struct kunit *test,
|
|||
KUNIT_EXPECT_EQ(test, r->ar.start, expected[i * 2]);
|
||||
KUNIT_EXPECT_EQ(test, r->ar.end, expected[i * 2 + 1]);
|
||||
}
|
||||
|
||||
damon_destroy_ctx(ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -252,60 +248,59 @@ static void damon_test_apply_three_regions4(struct kunit *test)
|
|||
new_three_regions, expected, ARRAY_SIZE(expected));
|
||||
}
|
||||
|
||||
static void damon_test_split_evenly(struct kunit *test)
|
||||
static void damon_test_split_evenly_fail(struct kunit *test,
|
||||
unsigned long start, unsigned long end, unsigned int nr_pieces)
|
||||
{
|
||||
struct damon_ctx *c = damon_new_ctx();
|
||||
struct damon_target *t;
|
||||
struct damon_region *r;
|
||||
unsigned long i;
|
||||
|
||||
KUNIT_EXPECT_EQ(test, damon_va_evenly_split_region(NULL, NULL, 5),
|
||||
-EINVAL);
|
||||
|
||||
t = damon_new_target(42);
|
||||
r = damon_new_region(0, 100);
|
||||
KUNIT_EXPECT_EQ(test, damon_va_evenly_split_region(t, r, 0), -EINVAL);
|
||||
struct damon_target *t = damon_new_target(42);
|
||||
struct damon_region *r = damon_new_region(start, end);
|
||||
|
||||
damon_add_region(r, t);
|
||||
KUNIT_EXPECT_EQ(test, damon_va_evenly_split_region(t, r, 10), 0);
|
||||
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 10u);
|
||||
|
||||
i = 0;
|
||||
damon_for_each_region(r, t) {
|
||||
KUNIT_EXPECT_EQ(test, r->ar.start, i++ * 10);
|
||||
KUNIT_EXPECT_EQ(test, r->ar.end, i * 10);
|
||||
}
|
||||
damon_free_target(t);
|
||||
|
||||
t = damon_new_target(42);
|
||||
r = damon_new_region(5, 59);
|
||||
damon_add_region(r, t);
|
||||
KUNIT_EXPECT_EQ(test, damon_va_evenly_split_region(t, r, 5), 0);
|
||||
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 5u);
|
||||
|
||||
i = 0;
|
||||
damon_for_each_region(r, t) {
|
||||
if (i == 4)
|
||||
break;
|
||||
KUNIT_EXPECT_EQ(test, r->ar.start, 5 + 10 * i++);
|
||||
KUNIT_EXPECT_EQ(test, r->ar.end, 5 + 10 * i);
|
||||
}
|
||||
KUNIT_EXPECT_EQ(test, r->ar.start, 5 + 10 * i);
|
||||
KUNIT_EXPECT_EQ(test, r->ar.end, 59ul);
|
||||
damon_free_target(t);
|
||||
|
||||
t = damon_new_target(42);
|
||||
r = damon_new_region(5, 6);
|
||||
damon_add_region(r, t);
|
||||
KUNIT_EXPECT_EQ(test, damon_va_evenly_split_region(t, r, 2), -EINVAL);
|
||||
KUNIT_EXPECT_EQ(test,
|
||||
damon_va_evenly_split_region(t, r, nr_pieces), -EINVAL);
|
||||
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1u);
|
||||
|
||||
damon_for_each_region(r, t) {
|
||||
KUNIT_EXPECT_EQ(test, r->ar.start, 5ul);
|
||||
KUNIT_EXPECT_EQ(test, r->ar.end, 6ul);
|
||||
KUNIT_EXPECT_EQ(test, r->ar.start, start);
|
||||
KUNIT_EXPECT_EQ(test, r->ar.end, end);
|
||||
}
|
||||
|
||||
damon_free_target(t);
|
||||
damon_destroy_ctx(c);
|
||||
}
|
||||
|
||||
static void damon_test_split_evenly_succ(struct kunit *test,
|
||||
unsigned long start, unsigned long end, unsigned int nr_pieces)
|
||||
{
|
||||
struct damon_target *t = damon_new_target(42);
|
||||
struct damon_region *r = damon_new_region(start, end);
|
||||
unsigned long expected_width = (end - start) / nr_pieces;
|
||||
unsigned long i = 0;
|
||||
|
||||
damon_add_region(r, t);
|
||||
KUNIT_EXPECT_EQ(test,
|
||||
damon_va_evenly_split_region(t, r, nr_pieces), 0);
|
||||
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), nr_pieces);
|
||||
|
||||
damon_for_each_region(r, t) {
|
||||
if (i == nr_pieces - 1)
|
||||
break;
|
||||
KUNIT_EXPECT_EQ(test,
|
||||
r->ar.start, start + i++ * expected_width);
|
||||
KUNIT_EXPECT_EQ(test, r->ar.end, start + i * expected_width);
|
||||
}
|
||||
KUNIT_EXPECT_EQ(test, r->ar.start, start + i * expected_width);
|
||||
KUNIT_EXPECT_EQ(test, r->ar.end, end);
|
||||
damon_free_target(t);
|
||||
}
|
||||
|
||||
static void damon_test_split_evenly(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_EQ(test, damon_va_evenly_split_region(NULL, NULL, 5),
|
||||
-EINVAL);
|
||||
|
||||
damon_test_split_evenly_fail(test, 0, 100, 0);
|
||||
damon_test_split_evenly_succ(test, 0, 100, 10);
|
||||
damon_test_split_evenly_succ(test, 5, 59, 5);
|
||||
damon_test_split_evenly_fail(test, 5, 6, 2);
|
||||
}
|
||||
|
||||
static struct kunit_case damon_test_cases[] = {
|
||||
|
|
|
@ -627,7 +627,6 @@ int damon_va_apply_scheme(struct damon_ctx *ctx, struct damon_target *t,
|
|||
case DAMOS_STAT:
|
||||
return 0;
|
||||
default:
|
||||
pr_warn("Wrong action %d\n", scheme->action);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
@ -3253,8 +3253,6 @@ static struct page *next_uptodate_page(struct page *page,
|
|||
goto skip;
|
||||
if (!PageUptodate(page) || PageReadahead(page))
|
||||
goto skip;
|
||||
if (PageHWPoison(page))
|
||||
goto skip;
|
||||
if (!trylock_page(page))
|
||||
goto skip;
|
||||
if (page->mapping != mapping)
|
||||
|
|
|
@ -2973,7 +2973,7 @@ int __alloc_bootmem_huge_page(struct hstate *h, int nid)
|
|||
struct huge_bootmem_page *m = NULL; /* initialize for clang */
|
||||
int nr_nodes, node;
|
||||
|
||||
if (nid >= nr_online_nodes)
|
||||
if (nid != NUMA_NO_NODE && nid >= nr_online_nodes)
|
||||
return 0;
|
||||
/* do node specific alloc */
|
||||
if (nid != NUMA_NO_NODE) {
|
||||
|
|
106
mm/memcontrol.c
106
mm/memcontrol.c
|
@ -776,24 +776,6 @@ void __mod_lruvec_kmem_state(void *p, enum node_stat_item idx, int val)
|
|||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* mod_objcg_mlstate() may be called with irq enabled, so
|
||||
* mod_memcg_lruvec_state() should be used.
|
||||
*/
|
||||
static inline void mod_objcg_mlstate(struct obj_cgroup *objcg,
|
||||
struct pglist_data *pgdat,
|
||||
enum node_stat_item idx, int nr)
|
||||
{
|
||||
struct mem_cgroup *memcg;
|
||||
struct lruvec *lruvec;
|
||||
|
||||
rcu_read_lock();
|
||||
memcg = obj_cgroup_memcg(objcg);
|
||||
lruvec = mem_cgroup_lruvec(memcg, pgdat);
|
||||
mod_memcg_lruvec_state(lruvec, idx, nr);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* __count_memcg_events - account VM events in a cgroup
|
||||
* @memcg: the memory cgroup
|
||||
|
@ -2137,41 +2119,6 @@ static bool obj_stock_flush_required(struct memcg_stock_pcp *stock,
|
|||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Most kmem_cache_alloc() calls are from user context. The irq disable/enable
|
||||
* sequence used in this case to access content from object stock is slow.
|
||||
* To optimize for user context access, there are now two object stocks for
|
||||
* task context and interrupt context access respectively.
|
||||
*
|
||||
* The task context object stock can be accessed by disabling preemption only
|
||||
* which is cheap in non-preempt kernel. The interrupt context object stock
|
||||
* can only be accessed after disabling interrupt. User context code can
|
||||
* access interrupt object stock, but not vice versa.
|
||||
*/
|
||||
static inline struct obj_stock *get_obj_stock(unsigned long *pflags)
|
||||
{
|
||||
struct memcg_stock_pcp *stock;
|
||||
|
||||
if (likely(in_task())) {
|
||||
*pflags = 0UL;
|
||||
preempt_disable();
|
||||
stock = this_cpu_ptr(&memcg_stock);
|
||||
return &stock->task_obj;
|
||||
}
|
||||
|
||||
local_irq_save(*pflags);
|
||||
stock = this_cpu_ptr(&memcg_stock);
|
||||
return &stock->irq_obj;
|
||||
}
|
||||
|
||||
static inline void put_obj_stock(unsigned long flags)
|
||||
{
|
||||
if (likely(in_task()))
|
||||
preempt_enable();
|
||||
else
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* consume_stock: Try to consume stocked charge on this cpu.
|
||||
* @memcg: memcg to consume from.
|
||||
|
@ -2816,6 +2763,59 @@ retry:
|
|||
*/
|
||||
#define OBJCGS_CLEAR_MASK (__GFP_DMA | __GFP_RECLAIMABLE | __GFP_ACCOUNT)
|
||||
|
||||
/*
|
||||
* Most kmem_cache_alloc() calls are from user context. The irq disable/enable
|
||||
* sequence used in this case to access content from object stock is slow.
|
||||
* To optimize for user context access, there are now two object stocks for
|
||||
* task context and interrupt context access respectively.
|
||||
*
|
||||
* The task context object stock can be accessed by disabling preemption only
|
||||
* which is cheap in non-preempt kernel. The interrupt context object stock
|
||||
* can only be accessed after disabling interrupt. User context code can
|
||||
* access interrupt object stock, but not vice versa.
|
||||
*/
|
||||
static inline struct obj_stock *get_obj_stock(unsigned long *pflags)
|
||||
{
|
||||
struct memcg_stock_pcp *stock;
|
||||
|
||||
if (likely(in_task())) {
|
||||
*pflags = 0UL;
|
||||
preempt_disable();
|
||||
stock = this_cpu_ptr(&memcg_stock);
|
||||
return &stock->task_obj;
|
||||
}
|
||||
|
||||
local_irq_save(*pflags);
|
||||
stock = this_cpu_ptr(&memcg_stock);
|
||||
return &stock->irq_obj;
|
||||
}
|
||||
|
||||
static inline void put_obj_stock(unsigned long flags)
|
||||
{
|
||||
if (likely(in_task()))
|
||||
preempt_enable();
|
||||
else
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* mod_objcg_mlstate() may be called with irq enabled, so
|
||||
* mod_memcg_lruvec_state() should be used.
|
||||
*/
|
||||
static inline void mod_objcg_mlstate(struct obj_cgroup *objcg,
|
||||
struct pglist_data *pgdat,
|
||||
enum node_stat_item idx, int nr)
|
||||
{
|
||||
struct mem_cgroup *memcg;
|
||||
struct lruvec *lruvec;
|
||||
|
||||
rcu_read_lock();
|
||||
memcg = obj_cgroup_memcg(objcg);
|
||||
lruvec = mem_cgroup_lruvec(memcg, pgdat);
|
||||
mod_memcg_lruvec_state(lruvec, idx, nr);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
int memcg_alloc_page_obj_cgroups(struct page *page, struct kmem_cache *s,
|
||||
gfp_t gfp, bool new_page)
|
||||
{
|
||||
|
|
15
mm/slub.c
15
mm/slub.c
|
@ -5081,6 +5081,7 @@ struct loc_track {
|
|||
unsigned long max;
|
||||
unsigned long count;
|
||||
struct location *loc;
|
||||
loff_t idx;
|
||||
};
|
||||
|
||||
static struct dentry *slab_debugfs_root;
|
||||
|
@ -6052,11 +6053,11 @@ __initcall(slab_sysfs_init);
|
|||
#if defined(CONFIG_SLUB_DEBUG) && defined(CONFIG_DEBUG_FS)
|
||||
static int slab_debugfs_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
|
||||
struct location *l;
|
||||
unsigned int idx = *(unsigned int *)v;
|
||||
struct loc_track *t = seq->private;
|
||||
struct location *l;
|
||||
unsigned long idx;
|
||||
|
||||
idx = (unsigned long) t->idx;
|
||||
if (idx < t->count) {
|
||||
l = &t->loc[idx];
|
||||
|
||||
|
@ -6105,16 +6106,18 @@ static void *slab_debugfs_next(struct seq_file *seq, void *v, loff_t *ppos)
|
|||
{
|
||||
struct loc_track *t = seq->private;
|
||||
|
||||
v = ppos;
|
||||
++*ppos;
|
||||
t->idx = ++(*ppos);
|
||||
if (*ppos <= t->count)
|
||||
return v;
|
||||
return ppos;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *slab_debugfs_start(struct seq_file *seq, loff_t *ppos)
|
||||
{
|
||||
struct loc_track *t = seq->private;
|
||||
|
||||
t->idx = *ppos;
|
||||
return ppos;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
huge_count_read_write
|
|
@ -1,7 +1,10 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Makefile for damon selftests
|
||||
|
||||
TEST_FILES = _chk_dependency.sh
|
||||
TEST_PROGS = debugfs_attrs.sh
|
||||
TEST_GEN_FILES += huge_count_read_write
|
||||
|
||||
TEST_FILES = _chk_dependency.sh _debugfs_common.sh
|
||||
TEST_PROGS = debugfs_attrs.sh debugfs_schemes.sh debugfs_target_ids.sh
|
||||
TEST_PROGS += debugfs_empty_targets.sh debugfs_huge_count_read_write.sh
|
||||
|
||||
include ../lib.mk
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
test_write_result() {
|
||||
file=$1
|
||||
content=$2
|
||||
orig_content=$3
|
||||
expect_reason=$4
|
||||
expected=$5
|
||||
|
||||
echo "$content" > "$file"
|
||||
if [ $? -ne "$expected" ]
|
||||
then
|
||||
echo "writing $content to $file doesn't return $expected"
|
||||
echo "expected because: $expect_reason"
|
||||
echo "$orig_content" > "$file"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
test_write_succ() {
|
||||
test_write_result "$1" "$2" "$3" "$4" 0
|
||||
}
|
||||
|
||||
test_write_fail() {
|
||||
test_write_result "$1" "$2" "$3" "$4" 1
|
||||
}
|
||||
|
||||
test_content() {
|
||||
file=$1
|
||||
orig_content=$2
|
||||
expected=$3
|
||||
expect_reason=$4
|
||||
|
||||
content=$(cat "$file")
|
||||
if [ "$content" != "$expected" ]
|
||||
then
|
||||
echo "reading $file expected $expected but $content"
|
||||
echo "expected because: $expect_reason"
|
||||
echo "$orig_content" > "$file"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
source ./_chk_dependency.sh
|
||||
|
||||
damon_onoff="$DBGFS/monitor_on"
|
||||
if [ $(cat "$damon_onoff") = "on" ]
|
||||
then
|
||||
echo "monitoring is on"
|
||||
exit $ksft_skip
|
||||
fi
|
|
@ -1,48 +1,7 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
test_write_result() {
|
||||
file=$1
|
||||
content=$2
|
||||
orig_content=$3
|
||||
expect_reason=$4
|
||||
expected=$5
|
||||
|
||||
echo "$content" > "$file"
|
||||
if [ $? -ne "$expected" ]
|
||||
then
|
||||
echo "writing $content to $file doesn't return $expected"
|
||||
echo "expected because: $expect_reason"
|
||||
echo "$orig_content" > "$file"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
test_write_succ() {
|
||||
test_write_result "$1" "$2" "$3" "$4" 0
|
||||
}
|
||||
|
||||
test_write_fail() {
|
||||
test_write_result "$1" "$2" "$3" "$4" 1
|
||||
}
|
||||
|
||||
test_content() {
|
||||
file=$1
|
||||
orig_content=$2
|
||||
expected=$3
|
||||
expect_reason=$4
|
||||
|
||||
content=$(cat "$file")
|
||||
if [ "$content" != "$expected" ]
|
||||
then
|
||||
echo "reading $file expected $expected but $content"
|
||||
echo "expected because: $expect_reason"
|
||||
echo "$orig_content" > "$file"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
source ./_chk_dependency.sh
|
||||
source _debugfs_common.sh
|
||||
|
||||
# Test attrs file
|
||||
# ===============
|
||||
|
@ -56,33 +15,3 @@ test_write_fail "$file" "1 2 3 5 4" "$orig_content" \
|
|||
"min_nr_regions > max_nr_regions"
|
||||
test_content "$file" "$orig_content" "1 2 3 4 5" "successfully written"
|
||||
echo "$orig_content" > "$file"
|
||||
|
||||
# Test schemes file
|
||||
# =================
|
||||
|
||||
file="$DBGFS/schemes"
|
||||
orig_content=$(cat "$file")
|
||||
|
||||
test_write_succ "$file" "1 2 3 4 5 6 4 0 0 0 1 2 3 1 100 3 2 1" \
|
||||
"$orig_content" "valid input"
|
||||
test_write_fail "$file" "1 2
|
||||
3 4 5 6 3 0 0 0 1 2 3 1 100 3 2 1" "$orig_content" "multi lines"
|
||||
test_write_succ "$file" "" "$orig_content" "disabling"
|
||||
echo "$orig_content" > "$file"
|
||||
|
||||
# Test target_ids file
|
||||
# ====================
|
||||
|
||||
file="$DBGFS/target_ids"
|
||||
orig_content=$(cat "$file")
|
||||
|
||||
test_write_succ "$file" "1 2 3 4" "$orig_content" "valid input"
|
||||
test_write_succ "$file" "1 2 abc 4" "$orig_content" "still valid input"
|
||||
test_content "$file" "$orig_content" "1 2" "non-integer was there"
|
||||
test_write_succ "$file" "abc 2 3" "$orig_content" "the file allows wrong input"
|
||||
test_content "$file" "$orig_content" "" "wrong input written"
|
||||
test_write_succ "$file" "" "$orig_content" "empty input"
|
||||
test_content "$file" "$orig_content" "" "empty input written"
|
||||
echo "$orig_content" > "$file"
|
||||
|
||||
echo "PASS"
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
source _debugfs_common.sh
|
||||
|
||||
# Test empty targets case
|
||||
# =======================
|
||||
|
||||
orig_target_ids=$(cat "$DBGFS/target_ids")
|
||||
echo "" > "$DBGFS/target_ids"
|
||||
orig_monitor_on=$(cat "$DBGFS/monitor_on")
|
||||
test_write_fail "$DBGFS/monitor_on" "on" "orig_monitor_on" "empty target ids"
|
||||
echo "$orig_target_ids" > "$DBGFS/target_ids"
|
|
@ -0,0 +1,22 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
source _debugfs_common.sh
|
||||
|
||||
# Test huge count read write
|
||||
# ==========================
|
||||
|
||||
dmesg -C
|
||||
|
||||
for file in "$DBGFS/"*
|
||||
do
|
||||
./huge_count_read_write "$file"
|
||||
done
|
||||
|
||||
if dmesg | grep -q WARNING
|
||||
then
|
||||
dmesg
|
||||
exit 1
|
||||
else
|
||||
exit 0
|
||||
fi
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
source _debugfs_common.sh
|
||||
|
||||
# Test schemes file
|
||||
# =================
|
||||
|
||||
file="$DBGFS/schemes"
|
||||
orig_content=$(cat "$file")
|
||||
|
||||
test_write_succ "$file" "1 2 3 4 5 6 4 0 0 0 1 2 3 1 100 3 2 1" \
|
||||
"$orig_content" "valid input"
|
||||
test_write_fail "$file" "1 2
|
||||
3 4 5 6 3 0 0 0 1 2 3 1 100 3 2 1" "$orig_content" "multi lines"
|
||||
test_write_succ "$file" "" "$orig_content" "disabling"
|
||||
test_write_fail "$file" "2 1 2 1 10 1 3 10 1 1 1 1 1 1 1 1 2 3" \
|
||||
"$orig_content" "wrong condition ranges"
|
||||
echo "$orig_content" > "$file"
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
source _debugfs_common.sh
|
||||
|
||||
# Test target_ids file
|
||||
# ====================
|
||||
|
||||
file="$DBGFS/target_ids"
|
||||
orig_content=$(cat "$file")
|
||||
|
||||
test_write_succ "$file" "1 2 3 4" "$orig_content" "valid input"
|
||||
test_write_succ "$file" "1 2 abc 4" "$orig_content" "still valid input"
|
||||
test_content "$file" "$orig_content" "1 2" "non-integer was there"
|
||||
test_write_succ "$file" "abc 2 3" "$orig_content" "the file allows wrong input"
|
||||
test_content "$file" "$orig_content" "" "wrong input written"
|
||||
test_write_succ "$file" "" "$orig_content" "empty input"
|
||||
test_content "$file" "$orig_content" "" "empty input written"
|
||||
echo "$orig_content" > "$file"
|
|
@ -0,0 +1,39 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Author: SeongJae Park <sj@kernel.org>
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void write_read_with_huge_count(char *file)
|
||||
{
|
||||
int filedesc = open(file, O_RDWR);
|
||||
char buf[25];
|
||||
int ret;
|
||||
|
||||
printf("%s %s\n", __func__, file);
|
||||
if (filedesc < 0) {
|
||||
fprintf(stderr, "failed opening %s\n", file);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
write(filedesc, "", 0xfffffffful);
|
||||
perror("after write: ");
|
||||
ret = read(filedesc, buf, 0xfffffffful);
|
||||
perror("after read: ");
|
||||
close(filedesc);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s <file>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
write_read_with_huge_count(argv[1]);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue