Skip to content

Commit

Permalink
zram: introduce an aged idle interface
Browse files Browse the repository at this point in the history
This change introduces an aged idle interface to the existing idle sysfs
file for zram.

When CONFIG_ZRAM_MEMORY_TRACKING is enabled the idle file now also
accepts an integer argument.  This integer is the age (in seconds) of
pages to mark as idle.  The idle file still supports 'all' as it always
has.  This new approach allows for much more control over which pages
get marked as idle.

[bgeffon@google.com: use IS_ENABLED and cleanup comment]
  Link: https://lkml.kernel.org/r/20210924161128.1508015-1-bgeffon@google.com
[bgeffon@google.com: Sergey's cleanup suggestions]
  Link: https://lkml.kernel.org/r/20210929143056.13067-1-bgeffon@google.com

Link: https://lkml.kernel.org/r/20210923130115.1344361-1-bgeffon@google.com
Signed-off-by: Brian Geffon <bgeffon@google.com>
Acked-by: Minchan Kim <minchan@kernel.org>
Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
Cc: Nitin Gupta <ngupta@vflare.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Suleiman Souhlal <suleiman@google.com>
Cc: Jesse Barnes <jsbarnes@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
bgaff authored and torvalds committed Nov 6, 2021
1 parent a88e03c commit 755804d
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 16 deletions.
8 changes: 8 additions & 0 deletions Documentation/admin-guide/blockdev/zram.rst
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,14 @@ as idle::
From now on, any pages on zram are idle pages. The idle mark
will be removed until someone requests access of the block.
IOW, unless there is access request, those pages are still idle pages.
Additionally, when CONFIG_ZRAM_MEMORY_TRACKING is enabled pages can be
marked as idle based on how long (in seconds) it's been since they were
last accessed::

echo 86400 > /sys/block/zramX/idle

In this example all pages which haven't been accessed in more than 86400
seconds (one day) will be marked idle.

Admin can request writeback of those idle pages at right timing via::

Expand Down
62 changes: 46 additions & 16 deletions drivers/block/zram/zram_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -291,37 +291,67 @@ static ssize_t mem_used_max_store(struct device *dev,
return len;
}

static ssize_t idle_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
/*
* Mark all pages which are older than or equal to cutoff as IDLE.
* Callers should hold the zram init lock in read mode
*/
static void mark_idle(struct zram *zram, ktime_t cutoff)
{
struct zram *zram = dev_to_zram(dev);
int is_idle = 1;
unsigned long nr_pages = zram->disksize >> PAGE_SHIFT;
int index;

if (!sysfs_streq(buf, "all"))
return -EINVAL;

down_read(&zram->init_lock);
if (!init_done(zram)) {
up_read(&zram->init_lock);
return -EINVAL;
}

for (index = 0; index < nr_pages; index++) {
/*
* Do not mark ZRAM_UNDER_WB slot as ZRAM_IDLE to close race.
* See the comment in writeback_store.
*/
zram_slot_lock(zram, index);
if (zram_allocated(zram, index) &&
!zram_test_flag(zram, index, ZRAM_UNDER_WB))
zram_set_flag(zram, index, ZRAM_IDLE);
!zram_test_flag(zram, index, ZRAM_UNDER_WB)) {
#ifdef CONFIG_ZRAM_MEMORY_TRACKING
is_idle = !cutoff || ktime_after(cutoff, zram->table[index].ac_time);
#endif
if (is_idle)
zram_set_flag(zram, index, ZRAM_IDLE);
}
zram_slot_unlock(zram, index);
}
}

up_read(&zram->init_lock);
static ssize_t idle_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
struct zram *zram = dev_to_zram(dev);
ktime_t cutoff_time = 0;
ssize_t rv = -EINVAL;

return len;
if (!sysfs_streq(buf, "all")) {
/*
* If it did not parse as 'all' try to treat it as an integer when
* we have memory tracking enabled.
*/
u64 age_sec;

if (IS_ENABLED(CONFIG_ZRAM_MEMORY_TRACKING) && !kstrtoull(buf, 0, &age_sec))
cutoff_time = ktime_sub(ktime_get_boottime(),
ns_to_ktime(age_sec * NSEC_PER_SEC));
else
goto out;
}

down_read(&zram->init_lock);
if (!init_done(zram))
goto out_unlock;

/* A cutoff_time of 0 marks everything as idle, this is the "all" behavior */
mark_idle(zram, cutoff_time);
rv = len;

out_unlock:
up_read(&zram->init_lock);
out:
return rv;
}

#ifdef CONFIG_ZRAM_WRITEBACK
Expand Down

0 comments on commit 755804d

Please sign in to comment.