mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] splitlru: shmem_getpage SetPageSwapBacked sooner
@ 2008-06-29  0:20 Hugh Dickins
  2008-06-29  0:22 ` [PATCH] splitlru: memcg swapbacked pages active Hugh Dickins
                   ` (2 more replies)
  0 siblings, 3 replies; 24+ messages in thread
From: Hugh Dickins @ 2008-06-29  0:20 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Rik van Riel, Lee Schermerhorn, linux-kernel

shmem_getpage must SetPageSwapBacked before the mem_cgroup_cache_charge,
otherwise try_to_free_mem_cgroup_pages cannot find the shmem/tmpfs pages
it needs to free, and OOMs result.

Signed-off-by: Hugh Dickins <hugh@veritas.com>
---
Should follow mmotm's define-page_file_cache-function.patch

 mm/shmem.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- mmotm/mm/shmem.c	2008-06-27 13:39:20.000000000 +0100
+++ linux/mm/shmem.c	2008-06-27 17:25:41.000000000 +0100
@@ -1369,6 +1369,7 @@ repeat:
 				error = -ENOMEM;
 				goto failed;
 			}
+			SetPageSwapBacked(filepage);
 
 			/* Precharge page while we can wait, compensate after */
 			error = mem_cgroup_cache_charge(filepage, current->mm,
@@ -1381,7 +1382,6 @@ repeat:
 				goto failed;
 			}
 
-			SetPageSwapBacked(filepage);
 			spin_lock(&info->lock);
 			entry = shmem_swp_alloc(info, idx, sgp);
 			if (IS_ERR(entry))

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH] splitlru: memcg swapbacked pages active
  2008-06-29  0:20 [PATCH] splitlru: shmem_getpage SetPageSwapBacked sooner Hugh Dickins
@ 2008-06-29  0:22 ` Hugh Dickins
  2008-06-29  8:19   ` KOSAKI Motohiro
                     ` (2 more replies)
  2008-06-29  0:24 ` [PATCH] splitlru: BDI_CAP_SWAP_BACKED Hugh Dickins
  2008-06-29  8:09 ` [PATCH] splitlru: shmem_getpage SetPageSwapBacked sooner KOSAKI Motohiro
  2 siblings, 3 replies; 24+ messages in thread
From: Hugh Dickins @ 2008-06-29  0:22 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Rik van Riel, Lee Schermerhorn, KAMEZAWA Hiroyuki, Balbir Singh,
	linux-kernel

add_to_page_cache_lru puts PageSwapBacked pages on the active_anon lru,
so shouldn't mem_cgroup_charge_common mirror that by setting FLAG_ACTIVE?

Signed-off-by: Hugh Dickins <hugh@veritas.com>
---
Should follow mmotm's vmscan-split-lru-lists-into-anon-file-sets.patch

 mm/memcontrol.c |    2 ++
 1 file changed, 2 insertions(+)

--- mmotm/mm/memcontrol.c	2008-06-27 13:39:20.000000000 +0100
+++ linux/mm/memcontrol.c	2008-06-27 17:32:29.000000000 +0100
@@ -560,6 +560,8 @@ static int mem_cgroup_charge_common(stru
 		pc->flags = PAGE_CGROUP_FLAG_CACHE;
 		if (page_is_file_cache(page))
 			pc->flags |= PAGE_CGROUP_FLAG_FILE;
+		else
+			pc->flags |= PAGE_CGROUP_FLAG_ACTIVE;
 	} else
 		pc->flags = PAGE_CGROUP_FLAG_ACTIVE;
 

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH] splitlru: BDI_CAP_SWAP_BACKED
  2008-06-29  0:20 [PATCH] splitlru: shmem_getpage SetPageSwapBacked sooner Hugh Dickins
  2008-06-29  0:22 ` [PATCH] splitlru: memcg swapbacked pages active Hugh Dickins
@ 2008-06-29  0:24 ` Hugh Dickins
  2008-06-29  8:48   ` KOSAKI Motohiro
  2008-06-29  8:09 ` [PATCH] splitlru: shmem_getpage SetPageSwapBacked sooner KOSAKI Motohiro
  2 siblings, 1 reply; 24+ messages in thread
From: Hugh Dickins @ 2008-06-29  0:24 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Rik van Riel, Lee Schermerhorn, Nick Piggin, linux-kernel

The split-lru patches put file and swap-backed pages on different lrus.
shmem/tmpfs pages are awkward because they are swap-backed file pages.
Since it's difficult to change lru midstream, they are treated as swap-
backed throughout, with SetPageSwapBacked on allocation in shmem_getpage.

However, splice read (used by loop and sendfile) and readahead* allocate
pages first, add_to_page_cache_lru, and then call into the filesystem
through ->readpage.  Under memory pressure, the shmem pages arrive at
add_to_swap_cache and hit its BUG_ON(!PageSwapBacked(page)).

I've not yet found a better way to handle this than a "capability"
flag in shmem_backing_dev_info, tested by add_to_page_cache_lru.
And solely because it would look suspicious without it, set that
BDI_CAP_SWAP_BACKED in swap_backing_dev_info also.

* readahead on shmem/tmpfs?  I'd always thought ra_pages 0 prevented
that; but in fact readahead(2), fadvise(POSIX_FADV_WILLNEED) and
madvise(MADV_WILLNEED) all force_page_cache_readahead and get there.

Signed-off-by: Hugh Dickins <hugh@veritas.com>
---
Should follow mmotm's vmscan-split-lru-lists-into-anon-file-sets.patch

 include/linux/backing-dev.h |   13 +++++++++++++
 mm/filemap.c                |   13 ++++++++++++-
 mm/shmem.c                  |    2 +-
 mm/swap_state.c             |    2 +-
 4 files changed, 27 insertions(+), 3 deletions(-)

--- mmotm/include/linux/backing-dev.h	2008-05-03 21:55:10.000000000 +0100
+++ linux/include/linux/backing-dev.h	2008-06-27 17:02:45.000000000 +0100
@@ -175,6 +175,8 @@ int bdi_set_max_ratio(struct backing_dev
  * BDI_CAP_READ_MAP:       Can be mapped for reading
  * BDI_CAP_WRITE_MAP:      Can be mapped for writing
  * BDI_CAP_EXEC_MAP:       Can be mapped for execution
+ *
+ * BDI_CAP_SWAP_BACKED:    Count shmem/tmpfs objects as swap-backed.
  */
 #define BDI_CAP_NO_ACCT_DIRTY	0x00000001
 #define BDI_CAP_NO_WRITEBACK	0x00000002
@@ -184,6 +186,7 @@ int bdi_set_max_ratio(struct backing_dev
 #define BDI_CAP_WRITE_MAP	0x00000020
 #define BDI_CAP_EXEC_MAP	0x00000040
 #define BDI_CAP_NO_ACCT_WB	0x00000080
+#define BDI_CAP_SWAP_BACKED	0x00000100
 
 #define BDI_CAP_VMFLAGS \
 	(BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP)
@@ -248,6 +251,11 @@ static inline bool bdi_cap_account_write
 				      BDI_CAP_NO_WRITEBACK));
 }
 
+static inline bool bdi_cap_swap_backed(struct backing_dev_info *bdi)
+{
+	return bdi->capabilities & BDI_CAP_SWAP_BACKED;
+}
+
 static inline bool mapping_cap_writeback_dirty(struct address_space *mapping)
 {
 	return bdi_cap_writeback_dirty(mapping->backing_dev_info);
@@ -258,4 +266,9 @@ static inline bool mapping_cap_account_d
 	return bdi_cap_account_dirty(mapping->backing_dev_info);
 }
 
+static inline bool mapping_cap_swap_backed(struct address_space *mapping)
+{
+	return bdi_cap_swap_backed(mapping->backing_dev_info);
+}
+
 #endif		/* _LINUX_BACKING_DEV_H */
--- mmotm/mm/filemap.c	2008-06-27 13:39:20.000000000 +0100
+++ linux/mm/filemap.c	2008-06-27 18:16:07.000000000 +0100
@@ -493,7 +493,18 @@ EXPORT_SYMBOL(add_to_page_cache);
 int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
 				pgoff_t offset, gfp_t gfp_mask)
 {
-	int ret = add_to_page_cache(page, mapping, offset, gfp_mask);
+	int ret;
+
+	/*
+	 * Splice_read and readahead add shmem/tmpfs pages into the page cache
+	 * before shmem_readpage has a chance to mark them as SwapBacked: they
+	 * need to go on the active_anon lru below, and mem_cgroup_cache_charge
+	 * (called in add_to_page_cache) needs to know where they're going too.
+	 */
+	if (mapping_cap_swap_backed(mapping))
+		SetPageSwapBacked(page);
+
+	ret = add_to_page_cache(page, mapping, offset, gfp_mask);
 	if (ret == 0) {
 		if (page_is_file_cache(page))
 			lru_cache_add_file(page);
--- mmotm/mm/shmem.c	2008-06-27 13:39:20.000000000 +0100
+++ linux/mm/shmem.c	2008-06-27 17:25:41.000000000 +0100
@@ -201,7 +201,7 @@ static struct vm_operations_struct shmem
 
 static struct backing_dev_info shmem_backing_dev_info  __read_mostly = {
 	.ra_pages	= 0,	/* No readahead */
-	.capabilities	= BDI_CAP_NO_ACCT_AND_WRITEBACK,
+	.capabilities	= BDI_CAP_NO_ACCT_AND_WRITEBACK | BDI_CAP_SWAP_BACKED,
 	.unplug_io_fn	= default_unplug_io_fn,
 };
 
--- mmotm/mm/swap_state.c	2008-06-27 13:39:20.000000000 +0100
+++ linux/mm/swap_state.c	2008-06-27 17:26:49.000000000 +0100
@@ -33,7 +33,7 @@ static const struct address_space_operat
 };
 
 static struct backing_dev_info swap_backing_dev_info = {
-	.capabilities	= BDI_CAP_NO_ACCT_AND_WRITEBACK,
+	.capabilities	= BDI_CAP_NO_ACCT_AND_WRITEBACK | BDI_CAP_SWAP_BACKED,
 	.unplug_io_fn	= swap_unplug_io_fn,
 };
 

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] splitlru: shmem_getpage SetPageSwapBacked sooner
  2008-06-29  0:20 [PATCH] splitlru: shmem_getpage SetPageSwapBacked sooner Hugh Dickins
  2008-06-29  0:22 ` [PATCH] splitlru: memcg swapbacked pages active Hugh Dickins
  2008-06-29  0:24 ` [PATCH] splitlru: BDI_CAP_SWAP_BACKED Hugh Dickins
@ 2008-06-29  8:09 ` KOSAKI Motohiro
  2 siblings, 0 replies; 24+ messages in thread
From: KOSAKI Motohiro @ 2008-06-29  8:09 UTC (permalink / raw)
  To: Hugh Dickins
  Cc: kosaki.motohiro, Andrew Morton, Rik van Riel, Lee Schermerhorn,
	linux-kernel

> shmem_getpage must SetPageSwapBacked before the mem_cgroup_cache_charge,
> otherwise try_to_free_mem_cgroup_pages cannot find the shmem/tmpfs pages
> it needs to free, and OOMs result.
> 
> Signed-off-by: Hugh Dickins <hugh@veritas.com>

it seems makes sense.

	Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] splitlru: memcg swapbacked pages active
  2008-06-29  0:22 ` [PATCH] splitlru: memcg swapbacked pages active Hugh Dickins
@ 2008-06-29  8:19   ` KOSAKI Motohiro
  2008-06-29 12:20     ` Hugh Dickins
  2008-06-30  2:44   ` KAMEZAWA Hiroyuki
  2008-06-30  8:36   ` [RFC][PATCH] memcg: change shmem handler KAMEZAWA Hiroyuki
  2 siblings, 1 reply; 24+ messages in thread
From: KOSAKI Motohiro @ 2008-06-29  8:19 UTC (permalink / raw)
  To: Hugh Dickins
  Cc: kosaki.motohiro, Andrew Morton, Rik van Riel, Lee Schermerhorn,
	KAMEZAWA Hiroyuki, Balbir Singh, linux-kernel

> add_to_page_cache_lru puts PageSwapBacked pages on the active_anon lru,
> so shouldn't mem_cgroup_charge_common mirror that by setting FLAG_ACTIVE?
> 
> Signed-off-by: Hugh Dickins <hugh@veritas.com>

I don't think so.

in global lru, active vs inactive anon ratio is controlled by 
inactive_anon_is_low().
but memcg doesn't have any sililar things.

thus, this patch increase active anon. and too many active page cause
decrease reclaim throuput.

yes, We should implement SEQ replacement reclaim (like global reclaim)
for memcg.
I'm working on this.




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] splitlru: BDI_CAP_SWAP_BACKED
  2008-06-29  0:24 ` [PATCH] splitlru: BDI_CAP_SWAP_BACKED Hugh Dickins
@ 2008-06-29  8:48   ` KOSAKI Motohiro
  2008-06-29 15:16     ` Rik van Riel
  2008-06-30  2:53     ` KAMEZAWA Hiroyuki
  0 siblings, 2 replies; 24+ messages in thread
From: KOSAKI Motohiro @ 2008-06-29  8:48 UTC (permalink / raw)
  To: Hugh Dickins
  Cc: kosaki.motohiro, Andrew Morton, Rik van Riel, Lee Schermerhorn,
	Nick Piggin, linux-kernel

> The split-lru patches put file and swap-backed pages on different lrus.
> shmem/tmpfs pages are awkward because they are swap-backed file pages.
> Since it's difficult to change lru midstream, they are treated as swap-
> backed throughout, with SetPageSwapBacked on allocation in shmem_getpage.
> 
> However, splice read (used by loop and sendfile) and readahead* allocate
> pages first, add_to_page_cache_lru, and then call into the filesystem
> through ->readpage.  Under memory pressure, the shmem pages arrive at
> add_to_swap_cache and hit its BUG_ON(!PageSwapBacked(page)).
> 
> I've not yet found a better way to handle this than a "capability"
> flag in shmem_backing_dev_info, tested by add_to_page_cache_lru.
> And solely because it would look suspicious without it, set that
> BDI_CAP_SWAP_BACKED in swap_backing_dev_info also.
> 
> * readahead on shmem/tmpfs?  I'd always thought ra_pages 0 prevented
> that; but in fact readahead(2), fadvise(POSIX_FADV_WILLNEED) and
> madvise(MADV_WILLNEED) all force_page_cache_readahead and get there.
> 
> Signed-off-by: Hugh Dickins <hugh@veritas.com>

great.

I'm not sure about this patch is perfect.
but it seems makes sense and very good code.

So, I'll testing this patch for a while.

Rik, What do you think about it?






^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] splitlru: memcg swapbacked pages active
  2008-06-29  8:19   ` KOSAKI Motohiro
@ 2008-06-29 12:20     ` Hugh Dickins
  2008-06-29 12:58       ` KOSAKI Motohiro
  0 siblings, 1 reply; 24+ messages in thread
From: Hugh Dickins @ 2008-06-29 12:20 UTC (permalink / raw)
  To: KOSAKI Motohiro
  Cc: Andrew Morton, Rik van Riel, Lee Schermerhorn, KAMEZAWA Hiroyuki,
	Balbir Singh, linux-kernel

On Sun, 29 Jun 2008, KOSAKI Motohiro wrote:
> > add_to_page_cache_lru puts PageSwapBacked pages on the active_anon lru,
> > so shouldn't mem_cgroup_charge_common mirror that by setting FLAG_ACTIVE?
> > 
> > Signed-off-by: Hugh Dickins <hugh@veritas.com>
> 
> I don't think so.
> 
> in global lru, active vs inactive anon ratio is controlled by 
> inactive_anon_is_low().
> but memcg doesn't have any sililar things.
> 
> thus, this patch increase active anon. and too many active page cause
> decrease reclaim throuput.
> 
> yes, We should implement SEQ replacement reclaim (like global reclaim)
> for memcg.
> I'm working on this.

Hmm.  Thanks for looking into it (and the others).  This is something
I noticed as a discrepancy in the source, rather than something from
which I observed any OOMs.  So if you're already working on bringing
the global and memcg approaches into line, I defer to your judgement.

But it seems to me worrying and fragile while they diverge in this way.
If the global has anon, active anon, file, active file and unevictable
lrus for the page; and the memcg has anon, active anon, file, active file
and unevictable lrus for the page cgroup; but different choices are made
which to put on where, then we're heading for confusion and trouble.

And when called, __mem_cgroup_move_lists tries to keep the activ-ity of
the memcg lrus in step with the activ-ity of the global lrus, doesn't
it?  So it's beyond my comprehension to start them off out of step.

Hugh

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] splitlru: memcg swapbacked pages active
  2008-06-29 12:20     ` Hugh Dickins
@ 2008-06-29 12:58       ` KOSAKI Motohiro
  2008-06-29 13:51         ` Hugh Dickins
  0 siblings, 1 reply; 24+ messages in thread
From: KOSAKI Motohiro @ 2008-06-29 12:58 UTC (permalink / raw)
  To: Hugh Dickins
  Cc: kosaki.motohiro, Andrew Morton, Rik van Riel, Lee Schermerhorn,
	KAMEZAWA Hiroyuki, Balbir Singh, linux-kernel


> But it seems to me worrying and fragile while they diverge in this way.
> If the global has anon, active anon, file, active file and unevictable
> lrus for the page; and the memcg has anon, active anon, file, active file
> and unevictable lrus for the page cgroup; but different choices are made
> which to put on where, then we're heading for confusion and trouble.
>
> And when called, __mem_cgroup_move_lists tries to keep the activ-ity of
> the memcg lrus in step with the activ-ity of the global lrus, doesn't
> it?  So it's beyond my comprehension to start them off out of step.

Well...
you are right.

Hmm.. OK, I propse alternative way.

step1: commit this patch
step2: implement active/inactive anon balancing routine

	Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>

Thank you for good patch.


btw, furtunately, memcg reclaim has some retry.
thus, lru imbalancing doesn't cause OOM, it only cause small performance degression.
IMHO your patch doesn't have any risk.




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] splitlru: memcg swapbacked pages active
  2008-06-29 12:58       ` KOSAKI Motohiro
@ 2008-06-29 13:51         ` Hugh Dickins
  0 siblings, 0 replies; 24+ messages in thread
From: Hugh Dickins @ 2008-06-29 13:51 UTC (permalink / raw)
  To: KOSAKI Motohiro
  Cc: Andrew Morton, Rik van Riel, Lee Schermerhorn, KAMEZAWA Hiroyuki,
	Balbir Singh, linux-kernel

On Sun, 29 Jun 2008, KOSAKI Motohiro wrote:
> 
> Well...
> you are right.

Not proved!  This is all quite complex.  But it looks that way.

> 
> Hmm.. OK, I propse alternative way.
> 
> step1: commit this patch
> step2: implement active/inactive anon balancing routine

That sounds a good plan to me.

> 
> 	Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
> 
> Thank you for good patch.

Thank you; and please accept my apology for not Cc'ing you on
the patches - I had intended to, but forgot just when sending.

> 
> btw, furtunately, memcg reclaim has some retry.
> thus, lru imbalancing doesn't cause OOM, it only cause small performance degression.
> IMHO your patch doesn't have any risk.

These things can work out so differently in practice than one would
expect.  Tests seem to be chugging along okay with the change in,
but I haven't explicitly tested performance with and without.

It just seems a sensible starting point to have the global and
memcg views in synch: if departing from that proves to work better,
then we should do so later.

I've no view yet on the performance characteristics of any of this,
just focussed on getting tmpfs working correctly again.  The notion
of keeping unevictable pages away from the regularly scanned lists
seems an obvious gain; but the swapbacked/filebacked distinction
is not so obvious to me (and particularly problematic for tmpfs).

Hugh

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] splitlru: BDI_CAP_SWAP_BACKED
  2008-06-29  8:48   ` KOSAKI Motohiro
@ 2008-06-29 15:16     ` Rik van Riel
  2008-06-30  2:53     ` KAMEZAWA Hiroyuki
  1 sibling, 0 replies; 24+ messages in thread
From: Rik van Riel @ 2008-06-29 15:16 UTC (permalink / raw)
  To: KOSAKI Motohiro
  Cc: Hugh Dickins, kosaki.motohiro, Andrew Morton, Lee Schermerhorn,
	Nick Piggin, linux-kernel

On Sun, 29 Jun 2008 17:48:59 +0900
KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> wrote:

> I'm not sure about this patch is perfect.
> but it seems makes sense and very good code.
> 
> So, I'll testing this patch for a while.
> 
> Rik, What do you think about it?

I have been running with a similar patch for a while, and
got my system to OOM :)

However, the patch is correct and the OOM is caused by
a different issue.  When stress-testing with a loopback
device on a tmpfs file, the VM thinks that we succeed
in evicting pages from the loopback device (file LRUs)
and continues scanning those LRUs.

Unfortunately for the VM, the loopback writepage function,
in combination with splice, end up moving the pages to the
anon LRUs, instead of freeing any pages.  

This confuses the balancing code, which thinks the pages
got freed.  As a result, the VM keeps scanning the file
LRUs and will eventually realize it failed to free any
memory.

One of Kosaki-san's recent patches may fix this, though.

-- 
All rights reversed.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] splitlru: memcg swapbacked pages active
  2008-06-29  0:22 ` [PATCH] splitlru: memcg swapbacked pages active Hugh Dickins
  2008-06-29  8:19   ` KOSAKI Motohiro
@ 2008-06-30  2:44   ` KAMEZAWA Hiroyuki
  2008-06-30 19:19     ` Hugh Dickins
  2008-06-30  8:36   ` [RFC][PATCH] memcg: change shmem handler KAMEZAWA Hiroyuki
  2 siblings, 1 reply; 24+ messages in thread
From: KAMEZAWA Hiroyuki @ 2008-06-30  2:44 UTC (permalink / raw)
  To: Hugh Dickins
  Cc: Andrew Morton, Rik van Riel, Lee Schermerhorn, Balbir Singh,
	linux-kernel

On Sun, 29 Jun 2008 01:22:22 +0100 (BST)
Hugh Dickins <hugh@veritas.com> wrote:

> add_to_page_cache_lru puts PageSwapBacked pages on the active_anon lru,
> so shouldn't mem_cgroup_charge_common mirror that by setting FLAG_ACTIVE?
> 
> Signed-off-by: Hugh Dickins <hugh@veritas.com>
> ---
> Should follow mmotm's vmscan-split-lru-lists-into-anon-file-sets.patch
> 
>  mm/memcontrol.c |    2 ++
>  1 file changed, 2 insertions(+)
> 
> --- mmotm/mm/memcontrol.c	2008-06-27 13:39:20.000000000 +0100
> +++ linux/mm/memcontrol.c	2008-06-27 17:32:29.000000000 +0100
> @@ -560,6 +560,8 @@ static int mem_cgroup_charge_common(stru
>  		pc->flags = PAGE_CGROUP_FLAG_CACHE;
>  		if (page_is_file_cache(page))
>  			pc->flags |= PAGE_CGROUP_FLAG_FILE;
> +		else
> +			pc->flags |= PAGE_CGROUP_FLAG_ACTIVE;
>  	} else
>  		pc->flags = PAGE_CGROUP_FLAG_ACTIVE;
>  
> 
Hmm, maybe no trouble but we'll have to care shmem's page is not marked as
PAGE_CGROUP_FLAG_CACHE but charged by mem_cgroup_charge_cache_page(). 
(I think why shmem is charged as cache is because shmem is used for tmpfs)

pc->flags |= PAGE_CGROUP_FLAG_FILE |  PAGE_CGROUP_FLAG_ACTIVE;

is bad ? (or not work ? I can't catch yet.)


And we have to change this again ;)
==
        [MEM_CGROUP_STAT_RSS] = { "anon/swapcache", PAGE_SIZE, },
==


Thanks,
-Kame



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] splitlru: BDI_CAP_SWAP_BACKED
  2008-06-29  8:48   ` KOSAKI Motohiro
  2008-06-29 15:16     ` Rik van Riel
@ 2008-06-30  2:53     ` KAMEZAWA Hiroyuki
  2008-06-30 19:23       ` Hugh Dickins
  1 sibling, 1 reply; 24+ messages in thread
From: KAMEZAWA Hiroyuki @ 2008-06-30  2:53 UTC (permalink / raw)
  To: KOSAKI Motohiro
  Cc: Hugh Dickins, Andrew Morton, Rik van Riel, Lee Schermerhorn,
	Nick Piggin, linux-kernel

On Sun, 29 Jun 2008 17:48:59 +0900
KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> wrote:

> > The split-lru patches put file and swap-backed pages on different lrus.
> > shmem/tmpfs pages are awkward because they are swap-backed file pages.
> > Since it's difficult to change lru midstream, they are treated as swap-
> > backed throughout, with SetPageSwapBacked on allocation in shmem_getpage.
> > 
> > However, splice read (used by loop and sendfile) and readahead* allocate
> > pages first, add_to_page_cache_lru, and then call into the filesystem
> > through ->readpage.  Under memory pressure, the shmem pages arrive at
> > add_to_swap_cache and hit its BUG_ON(!PageSwapBacked(page)).
> > 
> > I've not yet found a better way to handle this than a "capability"
> > flag in shmem_backing_dev_info, tested by add_to_page_cache_lru.
> > And solely because it would look suspicious without it, set that
> > BDI_CAP_SWAP_BACKED in swap_backing_dev_info also.
> > 
> > * readahead on shmem/tmpfs?  I'd always thought ra_pages 0 prevented
> > that; but in fact readahead(2), fadvise(POSIX_FADV_WILLNEED) and
> > madvise(MADV_WILLNEED) all force_page_cache_readahead and get there.
> > 
> > Signed-off-by: Hugh Dickins <hugh@veritas.com>
> 
> great.
> 
> I'm not sure about this patch is perfect.
> but it seems makes sense and very good code.
> 
> So, I'll testing this patch for a while.
> 

Hmm, how about adding LRU only for shmem/tmpfs ? nonsense ? ;)
It's just a file if not mapped but it's swap backed.


Thanks,
-Kame


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC][PATCH] memcg: change shmem handler.
  2008-06-29  0:22 ` [PATCH] splitlru: memcg swapbacked pages active Hugh Dickins
  2008-06-29  8:19   ` KOSAKI Motohiro
  2008-06-30  2:44   ` KAMEZAWA Hiroyuki
@ 2008-06-30  8:36   ` KAMEZAWA Hiroyuki
  2008-06-30 19:52     ` Hugh Dickins
                       ` (3 more replies)
  2 siblings, 4 replies; 24+ messages in thread
From: KAMEZAWA Hiroyuki @ 2008-06-30  8:36 UTC (permalink / raw)
  To: Hugh Dickins
  Cc: Andrew Morton, Rik van Riel, Lee Schermerhorn, Balbir Singh,
	linux-kernel

On Sun, 29 Jun 2008 01:22:22 +0100 (BST)
Hugh Dickins <hugh@veritas.com> wrote:

> add_to_page_cache_lru puts PageSwapBacked pages on the active_anon lru,
> so shouldn't mem_cgroup_charge_common mirror that by setting FLAG_ACTIVE?
> 
> Signed-off-by: Hugh Dickins <hugh@veritas.com>

How about a patch like this ?
==
a RFC patch: memcg-change-shmem-handler. 

Should be divided into 2-4 patches, and may have some problem.
(I did many careless misses today.....)

But please see idea/concepts. Maybe right way.

shmem has following characteristics.
In general.
  - seems like file cache
  - swap-backed
  - when it's swapped out, it's removed from radix-tree and added to swap.
  - when it's swapped in, it's removed from swap and added to radix-tree.

With memcg.
  - shmem is treted just as a file-cache. So, started from inactive list.
  - shmem's page fault routine is sensitive to GFP_xxx in which used.
    (GFP_NOWAIT is used) and pre-charge is done before add_to_page_cache.
  - shmem's page is removed by mem_cgroup_uncharge_cache_page(), So,
    shmem's swapcache is not charged.

This patch fixes some mess by
  - PAGE_CGROUP_FLAG_CACHE is deleted (and replaced by FLAG_FILE)
  - PAGE_CGROUP_FLAG_SHMEM is added.
  - add_to_page_cache_nocharge() is added.
    This avoids mem_cgroup_charge_cache_page(). This is useful when page is
    pre-charged.
  - uses add_to_page_cache_nocharge() also in hugemem.
    (I think hugemem controller should be independent from memcg.
     Balbir, how do you think ?)
  - PageSwapBacked() is checked.
    (A imported patch from Hugh Dickins)

As result.
  - shmem will be in SwapBacked/Active list at first.
  - memcg has "shmem/tmpfs" counter.

Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>

--
 include/linux/pagemap.h |   16 +++++++++
 mm/filemap.c            |   49 ++++++++++++++++++++++--------
 mm/hugetlb.c            |    3 +
 mm/memcontrol.c         |   78 +++++++++++++++++++++++++-----------------------
 mm/shmem.c              |   17 ++++++----
 5 files changed, 107 insertions(+), 56 deletions(-)

Index: linux-2.6.26-rc5-mm3-kosaki/mm/memcontrol.c
===================================================================
--- linux-2.6.26-rc5-mm3-kosaki.orig/mm/memcontrol.c	2008-06-30 15:02:52.000000000 +0900
+++ linux-2.6.26-rc5-mm3-kosaki/mm/memcontrol.c	2008-06-30 16:26:34.000000000 +0900
@@ -49,6 +49,7 @@
 	 */
 	MEM_CGROUP_STAT_CACHE, 	   /* # of pages charged as cache */
 	MEM_CGROUP_STAT_RSS,	   /* # of pages charged as anon/swapcache */
+	MEM_CGROUP_STAT_SHMEM,     /* # of pages charges as shmem/tmpfs */
 	MEM_CGROUP_STAT_PGPGIN_COUNT,	/* # of pages paged in */
 	MEM_CGROUP_STAT_PGPGOUT_COUNT,	/* # of pages paged out */
 
@@ -160,10 +161,10 @@
 	struct mem_cgroup *mem_cgroup;
 	int flags;
 };
-#define PAGE_CGROUP_FLAG_CACHE	   (0x1)	/* charged as cache */
-#define PAGE_CGROUP_FLAG_ACTIVE    (0x2)	/* page is active in this cgroup */
-#define PAGE_CGROUP_FLAG_FILE	   (0x4)	/* page is file system backed */
-#define PAGE_CGROUP_FLAG_UNEVICTABLE (0x8)	/* page is unevictableable */
+#define PAGE_CGROUP_FLAG_ACTIVE    (0x1)	/* page is active in this cgroup */
+#define PAGE_CGROUP_FLAG_FILE	   (0x2)	/* page is file system backed */
+#define PAGE_CGROUP_FLAG_UNEVICTABLE (0x4)	/* page is unevictableable */
+#define PAGE_CGROUP_FLAG_SHMEM	   (0x8)       /* page is shmem/tmpfs */
 
 static int page_cgroup_nid(struct page_cgroup *pc)
 {
@@ -178,6 +179,7 @@
 enum charge_type {
 	MEM_CGROUP_CHARGE_TYPE_CACHE = 0,
 	MEM_CGROUP_CHARGE_TYPE_MAPPED,
+	MEM_CGROUP_CHARGE_TYPE_SHMEM,
 	MEM_CGROUP_CHARGE_TYPE_FORCE,	/* used by force_empty */
 };
 
@@ -191,8 +193,10 @@
 	struct mem_cgroup_stat *stat = &mem->stat;
 
 	VM_BUG_ON(!irqs_disabled());
-	if (flags & PAGE_CGROUP_FLAG_CACHE)
+	if (flags & PAGE_CGROUP_FLAG_FILE)
 		__mem_cgroup_stat_add_safe(stat, MEM_CGROUP_STAT_CACHE, val);
+	else if (flags & PAGE_CGROUP_FLAG_SHMEM)
+		__mem_cgroup_stat_add_safe(stat, MEM_CGROUP_STAT_SHMEM, val);
 	else
 		__mem_cgroup_stat_add_safe(stat, MEM_CGROUP_STAT_RSS, val);
 
@@ -573,12 +577,19 @@
 	 * If a page is accounted as a page cache, insert to inactive list.
 	 * If anon, insert to active list.
 	 */
-	if (ctype == MEM_CGROUP_CHARGE_TYPE_CACHE) {
-		pc->flags = PAGE_CGROUP_FLAG_CACHE;
-		if (page_is_file_cache(page))
-			pc->flags |= PAGE_CGROUP_FLAG_FILE;
-	} else
+	switch (ctype) {
+	case MEM_CGROUP_CHARGE_TYPE_CACHE:
+		pc->flags = PAGE_CGROUP_FLAG_FILE;
+		break;
+	case MEM_CGROUP_CHARGE_TYPE_SHMEM:
+		pc->flags = PAGE_CGROUP_FLAG_SHMEM | PAGE_CGROUP_FLAG_ACTIVE;
+		break;
+	case MEM_CGROUP_CHARGE_TYPE_MAPPED:
 		pc->flags = PAGE_CGROUP_FLAG_ACTIVE;
+		break;
+	default:
+		BUG();
+	}
 
 	lock_page_cgroup(page);
 	if (unlikely(page_get_page_cgroup(page))) {
@@ -625,28 +636,10 @@
 int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
 				gfp_t gfp_mask)
 {
-	/*
-	 * Corner case handling. This is called from add_to_page_cache()
-	 * in usual. But some FS (shmem) precharges this page before calling it
-	 * and call add_to_page_cache() with GFP_NOWAIT.
-	 *
-	 * For GFP_NOWAIT case, the page may be pre-charged before calling
-	 * add_to_page_cache(). (See shmem.c) check it here and avoid to call
-	 * charge twice. (It works but has to pay a bit larger cost.)
-	 */
-	if (!(gfp_mask & __GFP_WAIT)) {
-		struct page_cgroup *pc;
+	enum charge_type ctype = MEM_CGROUP_CHARGE_TYPE_CACHE;
 
-		lock_page_cgroup(page);
-		pc = page_get_page_cgroup(page);
-		if (pc) {
-			VM_BUG_ON(pc->page != page);
-			VM_BUG_ON(!pc->mem_cgroup);
-			unlock_page_cgroup(page);
-			return 0;
-		}
-		unlock_page_cgroup(page);
-	}
+	if (PageSwapBacked(page))
+		ctype = MEM_CGROUP_CHARGE_TYPE_SHMEM;
 
 	if (unlikely(!mm))
 		mm = &init_mm;
@@ -678,11 +671,19 @@
 		goto unlock;
 
 	VM_BUG_ON(pc->page != page);
-
+	/*
+	 * There are 2 cases.
+	 * 1. anon pages are swapped out.
+	 * 2. shmem pages are swapped out.
+	 * In both case, PageSwapCache() returns 1 and we don't want to
+	 * uncharge it.
+	 */
+	if (PageSwapCache(page))
+		goto unlock;
+	/* When the page is unmapped, file-cache and shmem memory is alive */
 	if ((ctype == MEM_CGROUP_CHARGE_TYPE_MAPPED)
-	    && ((pc->flags & PAGE_CGROUP_FLAG_CACHE)
-		|| page_mapped(page)
-		|| PageSwapCache(page)))
+	    && ((pc->flags & (PAGE_CGROUP_FLAG_FILE | PAGE_CGROUP_FLAG_SHMEM))
+		|| page_mapped(page)))
 		goto unlock;
 
 	mz = page_cgroup_zoneinfo(pc);
@@ -732,8 +733,10 @@
 	if (pc) {
 		mem = pc->mem_cgroup;
 		css_get(&mem->css);
-		if (pc->flags & PAGE_CGROUP_FLAG_CACHE)
+		if (pc->flags & PAGE_CGROUP_FLAG_FILE)
 			ctype = MEM_CGROUP_CHARGE_TYPE_CACHE;
+		else if (pc->flags & PAGE_CGROUP_FLAG_SHMEM)
+			ctype = MEM_CGROUP_CHARGE_TYPE_SHMEM;
 	}
 	unlock_page_cgroup(page);
 	if (mem) {
@@ -785,6 +788,8 @@
 		progress = try_to_free_mem_cgroup_pages(mem, gfp_mask);
 	} while (!progress && --retry);
 
+	css_put(&mem->css);
+
 	if (!retry)
 		return -ENOMEM;
 	return 0;
@@ -920,6 +925,7 @@
 } mem_cgroup_stat_desc[] = {
 	[MEM_CGROUP_STAT_CACHE] = { "cache", PAGE_SIZE, },
 	[MEM_CGROUP_STAT_RSS] = { "anon/swapcache", PAGE_SIZE, },
+	[MEM_CGROUP_STAT_SHMEM] = { "shmem/tmpfs", PAGE_SIZE, },
 	[MEM_CGROUP_STAT_PGPGIN_COUNT] = {"pgpgin", 1, },
 	[MEM_CGROUP_STAT_PGPGOUT_COUNT] = {"pgpgout", 1, },
 };
Index: linux-2.6.26-rc5-mm3-kosaki/include/linux/pagemap.h
===================================================================
--- linux-2.6.26-rc5-mm3-kosaki.orig/include/linux/pagemap.h	2008-06-30 15:00:04.000000000 +0900
+++ linux-2.6.26-rc5-mm3-kosaki/include/linux/pagemap.h	2008-06-30 15:03:02.000000000 +0900
@@ -258,6 +258,22 @@
 				pgoff_t index, gfp_t gfp_mask);
 int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
 				pgoff_t index, gfp_t gfp_mask);
+
+#ifdef CONFIG_CGROUP_MEM_RES_CTLR
+/*
+ * If the page is pre-charged before add_to_page_cache() this routine is
+ * light-weight.
+ */
+int add_to_page_cache_nocharge(struct page *page, struct address_space *mapping,
+				pgoff_t index, gfp_t gfp_mask);
+#else
+static inline int add_to_page_cache_nocharge(struct page *page,
+				struct address_space *mapping, pgoff_t index,
+				gfp_t mask)
+{
+	return add_to_page_cache(page, mapping, index, gfp_mask);
+}
+#endif
 extern void remove_from_page_cache(struct page *page);
 extern void __remove_from_page_cache(struct page *page);
 
Index: linux-2.6.26-rc5-mm3-kosaki/mm/filemap.c
===================================================================
--- linux-2.6.26-rc5-mm3-kosaki.orig/mm/filemap.c	2008-06-30 15:00:04.000000000 +0900
+++ linux-2.6.26-rc5-mm3-kosaki/mm/filemap.c	2008-06-30 15:23:36.000000000 +0900
@@ -442,8 +442,9 @@
 	return err;
 }
 
+
 /**
- * add_to_page_cache - add newly allocated pagecache pages
+ * add_to_page_cache_nocharge() - add newly allocated pagecache pages
  * @page:	page to add
  * @mapping:	the page's address_space
  * @offset:	page index
@@ -454,22 +455,20 @@
  * The other page state flags were set by rmqueue().
  *
  * This function does not add the page to the LRU.  The caller must do that.
+ * This doesn't call memory resource control routine.
  */
-int add_to_page_cache(struct page *page, struct address_space *mapping,
-		pgoff_t offset, gfp_t gfp_mask)
+
+int add_to_page_cache_nocharge(struct page *page,
+			       struct address_space *mapping,
+			       pgoff_t offset, gfp_t gfp_mask)
 {
-	int error = mem_cgroup_cache_charge(page, current->mm,
-					gfp_mask & ~__GFP_HIGHMEM);
-	if (error)
-		goto out;
 
-	error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
+	int error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
 	if (error == 0) {
 		page_cache_get(page);
 		SetPageLocked(page);
 		page->mapping = mapping;
 		page->index = offset;
-
 		spin_lock_irq(&mapping->tree_lock);
 		error = radix_tree_insert(&mapping->page_tree, offset, page);
 		if (likely(!error)) {
@@ -478,15 +477,39 @@
 		} else {
 			page->mapping = NULL;
 			ClearPageLocked(page);
-			mem_cgroup_uncharge_cache_page(page);
 			page_cache_release(page);
 		}
 
 		spin_unlock_irq(&mapping->tree_lock);
 		radix_tree_preload_end();
-	} else
-		mem_cgroup_uncharge_cache_page(page);
-out:
+	}
+	return error;
+}
+
+/**
+ * add_to_page_cache - add newly allocated pagecache pages
+ * @page:	page to add
+ * @mapping:	the page's address_space
+ * @offset:	page index
+ * @gfp_mask:	page allocation mode
+ *
+ * This function is used to add newly allocated pagecache pages;
+ * the page is new, so we can just run SetPageLocked() against it.
+ * The other page state flags were set by rmqueue().
+ *
+ * This function does not add the page to the LRU.  The caller must do that.
+ */
+int add_to_page_cache(struct page *page, struct address_space *mapping,
+		pgoff_t offset, gfp_t gfp_mask)
+{
+	int error = mem_cgroup_cache_charge(page, current->mm,
+					gfp_mask & ~__GFP_HIGHMEM);
+	if (!error) {
+		error = add_to_page_cache_nocharge(page, mapping, offset,
+						  gfp_mask);
+		if (error)
+			mem_cgroup_uncharge_cache_page(page);
+	}
 	return error;
 }
 EXPORT_SYMBOL(add_to_page_cache);
Index: linux-2.6.26-rc5-mm3-kosaki/mm/shmem.c
===================================================================
--- linux-2.6.26-rc5-mm3-kosaki.orig/mm/shmem.c	2008-06-30 15:00:04.000000000 +0900
+++ linux-2.6.26-rc5-mm3-kosaki/mm/shmem.c	2008-06-30 15:37:11.000000000 +0900
@@ -940,10 +940,8 @@
 	spin_lock(&info->lock);
 	ptr = shmem_swp_entry(info, idx, NULL);
 	if (ptr && ptr->val == entry.val)
-		error = add_to_page_cache(page, inode->i_mapping, idx,
+		error = add_to_page_cache_nocharge(page, inode->i_mapping, idx,
 					GFP_NOWAIT);
-	else /* we don't have to account this page. */
-		mem_cgroup_uncharge_cache_page(page);
 
 	if (error == -EEXIST) {
 		struct page *filepage = find_get_page(inode->i_mapping, idx);
@@ -955,6 +953,7 @@
 			 */
 			if (PageUptodate(filepage))
 				error = 0;
+			mem_cgroup_uncharge_cache_page(page);
 			page_cache_release(filepage);
 		}
 	}
@@ -965,7 +964,9 @@
 		shmem_swp_set(info, ptr, 0);
 		swap_free(entry);
 		error = 1;	/* not an error, but entry was found */
-	}
+	} else
+		mem_cgroup_uncharge_cache_page(page);
+
 	if (ptr)
 		shmem_swp_unmap(ptr);
 	spin_unlock(&info->lock);
@@ -1375,6 +1376,7 @@
 				error = -ENOMEM;
 				goto failed;
 			}
+			SetPageSwapBacked(filepage);
 
 			/* Precharge page while we can wait, compensate after */
 			error = mem_cgroup_cache_charge(filepage, current->mm,
@@ -1387,7 +1389,6 @@
 				goto failed;
 			}
 
-			SetPageSwapBacked(filepage);
 			spin_lock(&info->lock);
 			entry = shmem_swp_alloc(info, idx, sgp);
 			if (IS_ERR(entry))
@@ -1400,7 +1401,8 @@
 			if (ret)
 				mem_cgroup_uncharge_cache_page(filepage);
 			else
-				ret = add_to_page_cache_lru(filepage, mapping,
+				ret = add_to_page_cache_nocharge(filepage,
+						mapping,
 						idx, GFP_NOWAIT);
 			/*
 			 * At add_to_page_cache_lru() failure, uncharge will
@@ -1408,6 +1410,7 @@
 			 */
 			if (ret) {
 				spin_unlock(&info->lock);
+				mem_cgroup_uncharge_cache_page(filepage);
 				page_cache_release(filepage);
 				shmem_unacct_blocks(info->flags, 1);
 				shmem_free_blocks(inode, 1);
@@ -1415,6 +1418,8 @@
 				if (error)
 					goto failed;
 				goto repeat;
+			} else {
+				lru_cache_add_active_anon(filepage);
 			}
 			info->flags |= SHMEM_PAGEIN;
 		}
Index: linux-2.6.26-rc5-mm3-kosaki/mm/hugetlb.c
===================================================================
--- linux-2.6.26-rc5-mm3-kosaki.orig/mm/hugetlb.c	2008-06-25 18:07:09.000000000 +0900
+++ linux-2.6.26-rc5-mm3-kosaki/mm/hugetlb.c	2008-06-30 15:08:16.000000000 +0900
@@ -1813,7 +1813,8 @@
 			int err;
 			struct inode *inode = mapping->host;
 
-			err = add_to_page_cache(page, mapping, idx, GFP_KERNEL);
+			err = add_to_page_cache_nocharge(page, mapping,
+						idx, GFP_KERNEL);
 			if (err) {
 				put_page(page);
 				if (err == -EEXIST)


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] splitlru: memcg swapbacked pages active
  2008-06-30  2:44   ` KAMEZAWA Hiroyuki
@ 2008-06-30 19:19     ` Hugh Dickins
  0 siblings, 0 replies; 24+ messages in thread
From: Hugh Dickins @ 2008-06-30 19:19 UTC (permalink / raw)
  To: KAMEZAWA Hiroyuki
  Cc: Andrew Morton, Rik van Riel, Lee Schermerhorn, Balbir Singh,
	linux-kernel

On Mon, 30 Jun 2008, KAMEZAWA Hiroyuki wrote:
> On Sun, 29 Jun 2008 01:22:22 +0100 (BST)
> Hugh Dickins <hugh@veritas.com> wrote:
> > 
> > --- mmotm/mm/memcontrol.c	2008-06-27 13:39:20.000000000 +0100
> > +++ linux/mm/memcontrol.c	2008-06-27 17:32:29.000000000 +0100
> > @@ -560,6 +560,8 @@ static int mem_cgroup_charge_common(stru
> >  		pc->flags = PAGE_CGROUP_FLAG_CACHE;
> >  		if (page_is_file_cache(page))
> >  			pc->flags |= PAGE_CGROUP_FLAG_FILE;
> > +		else
> > +			pc->flags |= PAGE_CGROUP_FLAG_ACTIVE;
> >  	} else
> >  		pc->flags = PAGE_CGROUP_FLAG_ACTIVE;
> >  
>
> Hmm, maybe no trouble but we'll have to care shmem's page is not marked as
> PAGE_CGROUP_FLAG_CACHE but charged by mem_cgroup_charge_cache_page(). 
> (I think why shmem is charged as cache is because shmem is used for tmpfs)
> 
> pc->flags |= PAGE_CGROUP_FLAG_FILE |  PAGE_CGROUP_FLAG_ACTIVE;
> 
> is bad ? (or not work ? I can't catch yet.)

Sorry, I've tried several times to understand you here, but still don't.

I thought shmem's page is marked as PAGE_CGROUP_FLAG_CACHE, and is
charged by mem_cgroup_charge_cache_page(), and that's what memcg wants?

It is a bit weird that PAGE_CGROUP_FLAG_CACHE and PAGE_CGROUP_FLAG_FILE
diverge, I'm not thrilled with that: that's an aspect of splitlru
treating shmem/tmpfs pages as not-file pages, which I'm unhappy with.

Hugh

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] splitlru: BDI_CAP_SWAP_BACKED
  2008-06-30  2:53     ` KAMEZAWA Hiroyuki
@ 2008-06-30 19:23       ` Hugh Dickins
  2008-06-30 19:49         ` Rik van Riel
  0 siblings, 1 reply; 24+ messages in thread
From: Hugh Dickins @ 2008-06-30 19:23 UTC (permalink / raw)
  To: KAMEZAWA Hiroyuki
  Cc: KOSAKI Motohiro, Andrew Morton, Rik van Riel, Lee Schermerhorn,
	Nick Piggin, linux-kernel

On Mon, 30 Jun 2008, KAMEZAWA Hiroyuki wrote:
> 
> Hmm, how about adding LRU only for shmem/tmpfs ? nonsense ? ;)

I'd much prefer not: the more LRUs, the more balancing problems;
And I don't think shmem/tmpfs _deserves_ its own LRUs.
But it cannot be ruled out.

Hugh

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] splitlru: BDI_CAP_SWAP_BACKED
  2008-06-30 19:23       ` Hugh Dickins
@ 2008-06-30 19:49         ` Rik van Riel
  2008-06-30 20:55           ` Hugh Dickins
  0 siblings, 1 reply; 24+ messages in thread
From: Rik van Riel @ 2008-06-30 19:49 UTC (permalink / raw)
  To: Hugh Dickins
  Cc: KAMEZAWA Hiroyuki, KOSAKI Motohiro, Andrew Morton,
	Lee Schermerhorn, Nick Piggin, linux-kernel

On Mon, 30 Jun 2008 20:23:54 +0100 (BST)
Hugh Dickins <hugh@veritas.com> wrote:

> On Mon, 30 Jun 2008, KAMEZAWA Hiroyuki wrote:
> > 
> > Hmm, how about adding LRU only for shmem/tmpfs ? nonsense ? ;)
> 
> I'd much prefer not: the more LRUs, the more balancing problems;
> And I don't think shmem/tmpfs _deserves_ its own LRUs.
> But it cannot be ruled out.

Tmpfs is often in the same boat as anonymous memory.
Used for shared memory segments, or for files that
are temporary and will be gone soon.

If swap space runs out, tmpfs pages should not be
scanned.

To me, this suggests they should probably continue
to live on the *_ANON LRUs.  Worst case we make
tmpfs pages in files that are not mmaped (/tmp use)
start out on the inactive list, so they get evicted
first.

-- 
All rights reversed.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC][PATCH] memcg: change shmem handler.
  2008-06-30  8:36   ` [RFC][PATCH] memcg: change shmem handler KAMEZAWA Hiroyuki
@ 2008-06-30 19:52     ` Hugh Dickins
  2008-07-01  0:56     ` kamezawa.hiroyu
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 24+ messages in thread
From: Hugh Dickins @ 2008-06-30 19:52 UTC (permalink / raw)
  To: KAMEZAWA Hiroyuki
  Cc: Andrew Morton, Rik van Riel, Lee Schermerhorn, Balbir Singh,
	linux-kernel

On Mon, 30 Jun 2008, KAMEZAWA Hiroyuki wrote:
> 
> How about a patch like this ?
> ==
> a RFC patch: memcg-change-shmem-handler. 
> 
> Should be divided into 2-4 patches, and may have some problem.
> (I did many careless misses today.....)
> 
> But please see idea/concepts. Maybe right way.

As you say, should be divided.  In particular, some changes are
assuming the splitlru patches (e.g. SwapBacked), and other changes
are independent of them.  Those very much have to be separated.

> 
> shmem has following characteristics.
> In general.
>   - seems like file cache
>   - swap-backed
>   - when it's swapped out, it's removed from radix-tree and added to swap.
>   - when it's swapped in, it's removed from swap and added to radix-tree.

True (aside from swap pages being in a radix-tree of their own).
Though splitlru is muddying the "seems like file cache".

> 
> With memcg.
>   - shmem is treted just as a file-cache. So, started from inactive list.

Depends on what set of patches we're talking about.

>   - shmem's page fault routine is sensitive to GFP_xxx in which used.
>     (GFP_NOWAIT is used) and pre-charge is done before add_to_page_cache.

Nothing particular to shmem or page fault routine, I think; but
shmem implementation is peculiar in calling add_to_page_cache etc.
while holding a spinlock, so needs to precharge, yes.

>   - shmem's page is removed by mem_cgroup_uncharge_cache_page(), So,
>     shmem's swapcache is not charged.

Ah, that's interesting: I'd assumed you'd changed that in your
no-refcount patches, and had been surprised not to notice a slowdown
(waiting for swap to be written and freed before coming under limit).
Now you want to make them wait: not entirely an improvement,
but I see your point.

> 
> This patch fixes some mess by
>   - PAGE_CGROUP_FLAG_CACHE is deleted (and replaced by FLAG_FILE)

That's good.

>   - PAGE_CGROUP_FLAG_SHMEM is added.

That's not good.

>   - add_to_page_cache_nocharge() is added.
>     This avoids mem_cgroup_charge_cache_page(). This is useful when page is
>     pre-charged.

Do you have to?  I get so sick of such variants.  I agree the GFP_NOWAIT
test looked rather a hack, but it's really quite appropriate.  Fragile
in that it relies on the right thing having been done; but there's a
lot of fragility in the way the memcg microcosm is hoping to mimic
the global macrocosm.  (Sorry if I'm being pretentiously obscure!)

>   - uses add_to_page_cache_nocharge() also in hugemem.
>     (I think hugemem controller should be independent from memcg.
>      Balbir, how do you think ?)
>   - PageSwapBacked() is checked.
>     (A imported patch from Hugh Dickins)

Nothing to do with the rest of it?

> 
> As result.
>   - shmem will be in SwapBacked/Active list at first.

Assuming splitlru.  Didn't my two-liner deal with that?

>   - memcg has "shmem/tmpfs" counter.

Is that a good thing?  If we really decide that globally we
need such a counter, then fine for memcg to follow; but I've
not yet heard it asked for.

> 
> Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
> 
> --
>  include/linux/pagemap.h |   16 +++++++++
>  mm/filemap.c            |   49 ++++++++++++++++++++++--------
>  mm/hugetlb.c            |    3 +
>  mm/memcontrol.c         |   78 +++++++++++++++++++++++++-----------------------
>  mm/shmem.c              |   17 ++++++----
>  5 files changed, 107 insertions(+), 56 deletions(-)

Not so good (though hardly the end of the world).

Hugh

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] splitlru: BDI_CAP_SWAP_BACKED
  2008-06-30 19:49         ` Rik van Riel
@ 2008-06-30 20:55           ` Hugh Dickins
  2008-06-30 21:17             ` Rik van Riel
  0 siblings, 1 reply; 24+ messages in thread
From: Hugh Dickins @ 2008-06-30 20:55 UTC (permalink / raw)
  To: Rik van Riel
  Cc: KAMEZAWA Hiroyuki, KOSAKI Motohiro, Andrew Morton,
	Lee Schermerhorn, Nick Piggin, linux-kernel

On Mon, 30 Jun 2008, Rik van Riel wrote:
> 
> Tmpfs is often in the same boat as anonymous memory.
> Used for shared memory segments, or for files that
> are temporary and will be gone soon.

Anonymous memory, and temporary files, are often soon gone,
okay.  But I don't find that generalization compelling; and
if they're soon gone, does it matter which lru they go on?

> If swap space runs out, tmpfs pages should not be
> scanned.

That point I like.  But I hope they'd go to the Unevictable
on systems with no swap at all (of course, as with mlocking,
that can change soon after).

> To me, this suggests they should probably continue
> to live on the *_ANON LRUs.  Worst case we make
> tmpfs pages in files that are not mmaped (/tmp use)
> start out on the inactive list, so they get evicted
> first.

Tweaking in/active I'll gladly leave to you!  Whatever
proves best.  What's worrying me is that we have always treated
shmem/tmpfs pages as file pages (e.g. in /proc/meminfo as Cached
not as SwapCached), up until the point that we retire them to
swap; but in splitlru you're sending them down another path;
then mem cgroups seem to want them as something else again.

Your SwapBacked may indeed turn out to be the only implementable
distinction, but it does worry me.  A more useful distinction,
my gut tells me, would be separate LRUs for page_mapped() and
!page_mapped(), which reflects the existing swappiness notion.

But that immediately hits the difficulty we have in switching LRU
midstream, which your SwapBacked-throughout tmpfs neatly sidesteps.

I'd really like to be able to try page_mapped/!page_mapped versus
swap-backed/file-backed, but it would need some LRU-switching
infrastructure (which might come at a prohibitive performance
cost, since it's the batching that poses the problem).

Hugh

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] splitlru: BDI_CAP_SWAP_BACKED
  2008-06-30 20:55           ` Hugh Dickins
@ 2008-06-30 21:17             ` Rik van Riel
  0 siblings, 0 replies; 24+ messages in thread
From: Rik van Riel @ 2008-06-30 21:17 UTC (permalink / raw)
  To: Hugh Dickins
  Cc: KAMEZAWA Hiroyuki, KOSAKI Motohiro, Andrew Morton,
	Lee Schermerhorn, Nick Piggin, linux-kernel

On Mon, 30 Jun 2008 21:55:13 +0100 (BST)
Hugh Dickins <hugh@veritas.com> wrote:
> On Mon, 30 Jun 2008, Rik van Riel wrote:
> > 
> > Tmpfs is often in the same boat as anonymous memory.
> > Used for shared memory segments, or for files that
> > are temporary and will be gone soon.
> 
> Anonymous memory, and temporary files, are often soon gone,
> okay.  But I don't find that generalization compelling; and
> if they're soon gone, does it matter which lru they go on?

Temporary files are often soon gone.

Anonymous memory and shmem segments tend to stick around
for longer.
 
> > If swap space runs out, tmpfs pages should not be
> > scanned.
> 
> That point I like.  But I hope they'd go to the Unevictable
> on systems with no swap at all (of course, as with mlocking,
> that can change soon after).

If we have them on the *_ANON LRUs, we will automatically
not scan them when swap space runs out.  Just like we do
not scan anonymous pages when there is no swap space left.

> > To me, this suggests they should probably continue
> > to live on the *_ANON LRUs.  Worst case we make
> > tmpfs pages in files that are not mmaped (/tmp use)
> > start out on the inactive list, so they get evicted
> > first.
> 
> Tweaking in/active I'll gladly leave to you!  Whatever
> proves best.  What's worrying me is that we have always treated
> shmem/tmpfs pages as file pages

This is a performance problem for database systems,
where the system ends up swapping out the shared
memory segment.

> (e.g. in /proc/meminfo as Cached
> not as SwapCached), up until the point that we retire them to
> swap; but in splitlru you're sending them down another path;
> then mem cgroups seem to want them as something else again.

Having the mem cgroups consistent with the global LRU
implementation would be good, indeed.  That will make
balancing a bit easier.
 
> Your SwapBacked may indeed turn out to be the only implementable
> distinction, but it does worry me.  A more useful distinction,
> my gut tells me, would be separate LRUs for page_mapped() and
> !page_mapped(), which reflects the existing swappiness notion.
> 
> But that immediately hits the difficulty we have in switching LRU
> midstream, which your SwapBacked-throughout tmpfs neatly sidesteps.
>
> I'd really like to be able to try page_mapped/!page_mapped versus
> swap-backed/file-backed, but it would need some LRU-switching
> infrastructure (which might come at a prohibitive performance
> cost, since it's the batching that poses the problem).

Agreed, we understand the page_mapped/!page_mapped distinction
quite well.  On the other hand, we do not understand LRU
acrobatics (moving pages between lists on mmap/munmap) and the
consequences of that...

I suspect we'll just have to tweak the swap-backed/file-backed
code until it works right.  Once Andrew comes out with a new
-mm (with all the stability fixes), I will create a kernel RPM
with the latest split LRU code for Fedora 9, so we can get some
wider testing.

I have some performance tweaks in mind already, but not enough
data yet to justify them.  I will continue working on that.

-- 
All rights reversed.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Re: [RFC][PATCH] memcg: change shmem handler.
  2008-06-30  8:36   ` [RFC][PATCH] memcg: change shmem handler KAMEZAWA Hiroyuki
  2008-06-30 19:52     ` Hugh Dickins
@ 2008-07-01  0:56     ` kamezawa.hiroyu
  2008-07-02  2:16       ` [RFC][PATCH] memcg: shmem swap cache KAMEZAWA Hiroyuki
  2008-07-01  1:06     ` Re: Re: [RFC][PATCH] memcg: change shmem handler kamezawa.hiroyu
  2008-07-03  7:15     ` Balbir Singh
  3 siblings, 1 reply; 24+ messages in thread
From: kamezawa.hiroyu @ 2008-07-01  0:56 UTC (permalink / raw)
  To: Hugh Dickins
  Cc: KAMEZAWA Hiroyuki, Andrew Morton, Rik van Riel, Lee Schermerhorn,
	Balbir Singh, linux-kernel

----- Original Message -----
>> 
>> With memcg.
>>   - shmem is treted just as a file-cache. So, started from inactive list.
>
>Depends on what set of patches we're talking about.
>
just means it's charged by mem_cgroup_cache_charge()

>>   - shmem's page fault routine is sensitive to GFP_xxx in which used.
>>     (GFP_NOWAIT is used) and pre-charge is done before add_to_page_cache.
>
>Nothing particular to shmem or page fault routine, I think; but
>shmem implementation is peculiar in calling add_to_page_cache etc.
>while holding a spinlock, so needs to precharge, yes.
>
>>   - shmem's page is removed by mem_cgroup_uncharge_cache_page(), So,
>>     shmem's swapcache is not charged.
>
>Ah, that's interesting: I'd assumed you'd changed that in your
>no-refcount patches, and had been surprised not to notice a slowdown
>(waiting for swap to be written and freed before coming under limit).
>Now you want to make them wait: not entirely an improvement,
>but I see your point.
>
To do this is (maybe) a few line patch. I'll CC you if I wrote some.

>> 
>> This patch fixes some mess by
>>   - PAGE_CGROUP_FLAG_CACHE is deleted (and replaced by FLAG_FILE)
>
>That's good.
>
will do as an independent patch.

>>   - PAGE_CGROUP_FLAG_SHMEM is added.
>
>That's not good.
>
Hmm

>>   - add_to_page_cache_nocharge() is added.
>>     This avoids mem_cgroup_charge_cache_page(). This is useful when page is
>>     pre-charged.
>
>Do you have to?  I get so sick of such variants.  I agree the GFP_NOWAIT
>test looked rather a hack, but it's really quite appropriate.  Fragile
>in that it relies on the right thing having been done; but there's a
>lot of fragility in the way the memcg microcosm is hoping to mimic
>the global macrocosm.  (Sorry if I'm being pretentiously obscure!)
>
Hmm..okay, find a way to detect precharged case without adding anything.

>>   - uses add_to_page_cache_nocharge() also in hugemem.
>>     (I think hugemem controller should be independent from memcg.
>>      Balbir, how do you think ?)
>>   - PageSwapBacked() is checked.
>>     (A imported patch from Hugh Dickins)
>
>Nothing to do with the rest of it?
>
Just imported I need it to this. I'm sorry if I don't catch what you mean.


>> 
>> As result.
>>   - shmem will be in SwapBacked/Active list at first.
>
>Assuming splitlru.  Didn't my two-liner deal with that?
>
yes. yours do. just want to use switch-case rather than unclear "if" s.

>>   - memcg has "shmem/tmpfs" counter.
>
>Is that a good thing?  If we really decide that globally we
>need such a counter, then fine for memcg to follow; but I've
>not yet heard it asked for.
After swap-controller is introduced, I can imagine there will be a
swap-full/swap-less cgroup. And shmem will be able to be swapped out.
memcg handles limit of memory usage and Admin/Middleware will want to
know current limit is good or bad. So, showing amount of tmpfs 
will be good (It's now shown as Cache...a pages easily kicked out ;)

>
>> 
>> Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
>> 
>> --
>>  include/linux/pagemap.h |   16 +++++++++
>>  mm/filemap.c            |   49 ++++++++++++++++++++++--------
>>  mm/hugetlb.c            |    3 +
>>  mm/memcontrol.c         |   78 +++++++++++++++++++++++++------------------
-----
>>  mm/shmem.c              |   17 ++++++----
>>  5 files changed, 107 insertions(+), 56 deletions(-)
>
>Not so good (though hardly the end of the world).
>
I'll divide and make this clearer.
Anyway I want to wait until -mm's VMM seems stable.

Thanks,
-Kame


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Re: Re: [RFC][PATCH] memcg: change shmem handler.
  2008-06-30  8:36   ` [RFC][PATCH] memcg: change shmem handler KAMEZAWA Hiroyuki
  2008-06-30 19:52     ` Hugh Dickins
  2008-07-01  0:56     ` kamezawa.hiroyu
@ 2008-07-01  1:06     ` kamezawa.hiroyu
  2008-07-03  7:15     ` Balbir Singh
  3 siblings, 0 replies; 24+ messages in thread
From: kamezawa.hiroyu @ 2008-07-01  1:06 UTC (permalink / raw)
  To: kamezawa.hiroyu
  Cc: Hugh Dickins, KAMEZAWA Hiroyuki, Andrew Morton, Rik van Riel,
	Lee Schermerhorn, Balbir Singh, linux-kernel

----- Original Message -----
Sorry..a bit more words.
>>Is that a good thing?  If we really decide that globally we
>>need such a counter, then fine for memcg to follow; but I've
>>not yet heard it asked for.
>After swap-controller is introduced, I can imagine there will be a
>swap-full/swap-less cgroup. And shmem will be able to be swapped out.
                                          not
>memcg handles limit of memory usage and Admin/Middleware will want to
>know current limit is good or bad. So, showing amount of tmpfs 
>will be good (It's now shown as Cache...a pages easily kicked out ;)
>
I'm not sure but how this seems under memcg in which DataBase runs.

Now.
   - anon
   - cache (including DataBase's shmem)
After
   - anon
   - cache (file cache)
   - shmem (DataBase's working area)

not good ?

Thanks,
-Kame

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC][PATCH] memcg: shmem swap cache
  2008-07-01  0:56     ` kamezawa.hiroyu
@ 2008-07-02  2:16       ` KAMEZAWA Hiroyuki
  0 siblings, 0 replies; 24+ messages in thread
From: KAMEZAWA Hiroyuki @ 2008-07-02  2:16 UTC (permalink / raw)
  To: kamezawa.hiroyu
  Cc: Hugh Dickins, Andrew Morton, Rik van Riel, Lee Schermerhorn,
	Balbir Singh, linux-kernel, kosaki.motohiro, nishimura

On Tue, 1 Jul 2008 09:56:45 +0900 (JST)
kamezawa.hiroyu@jp.fujitsu.com wrote:

> >>   - shmem's page is removed by mem_cgroup_uncharge_cache_page(), So,
> >>     shmem's swapcache is not charged.
> >
> >Ah, that's interesting: I'd assumed you'd changed that in your
> >no-refcount patches, and had been surprised not to notice a slowdown
> >(waiting for swap to be written and freed before coming under limit).
> >Now you want to make them wait: not entirely an improvement,
> >but I see your point.
> >
> To do this is (maybe) a few line patch. I'll CC you if I wrote some.
> 
maybe like this. how do you feel ?
I'll stack this on my queue and test for a while.

==
SwapCache handling fix.

memcg failed to handle shmem's swapcache. This patch tries to fix it.

After this:

Any page marked as SwapCache is not uncharged.
(until delelte_from_swap_cache() delete the flag.)

To check a page is alive shmem-page-cache or not we use
 page->mapping && !PageAnon(page) instead of pc->flags & PAGE_CGROUP_FLAG_CACHE.

Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>

Index: test-2.6.26-rc5-mm3++/mm/memcontrol.c
===================================================================
--- test-2.6.26-rc5-mm3++.orig/mm/memcontrol.c	2008-07-02 09:29:52.000000000 +0900
+++ test-2.6.26-rc5-mm3++/mm/memcontrol.c	2008-07-02 10:58:15.000000000 +0900
@@ -685,11 +685,45 @@
 
 	VM_BUG_ON(pc->page != page);
 
-	if ((ctype == MEM_CGROUP_CHARGE_TYPE_MAPPED)
-	    && ((pc->flags & PAGE_CGROUP_FLAG_CACHE)
-		|| page_mapped(page)
-		|| PageSwapCache(page)))
+	/*
+	 * File Cache
+	 * If called with MEM_CGROUP_CHARGE_TYPE_MAPPED, check page->mapping.
+	 * add_to_page_cache() .... charged before inserting radix-tree.
+	 * remove_from_page_cache() .... uncharged at removing from radix-tree.
+	 * page->mapping && !PageAnon(page) catches file cache.
+	 *
+	 * Anon/Shmem.....We check PageSwapCache(page).
+	 * Anon .... charged before mapped.
+	 * Shmem .... charged at add_to_page_cache() as usual File Cache.
+	 *
+	 * This page will be finally uncharged when removed from swap-cache
+	 *
+	 * we treat 2 cases here.
+	 * A. anonymous page  B. shmem.
+	 * We never uncharge if page is marked as SwapCache.
+	 * add_to_swap_cache() have nothing to do with charge/uncharge.
+	 * SwapCache flag is deleted before delete_from_swap_cache() calls this
+	 *
+	 * shmem's behavior is following. (see shmem.c/swap_state.c also)
+	 * at swap-out:
+	 * 	0. add_to_page_cache()//charged at page creation.
+	 * 	1. add_to_swap_cache() (marked as SwapCache)
+	 *	2. remove_from_page_cache().  (calls this.)
+	 *	(finally) delete_from_swap_cache(). (calls this.)
+	 * at swap-in:
+	 * 	3. add_to_swap_cache() (no charge here.)
+	 * 	4. add_to_page_cache() (charged here.)
+	 * 	5. delete_from_swap_cache() (calls this.)
+	 * PageSwapCache(page) catches "2".
+	 * page->mapping && !PageAnon() catches "5" and avoid uncharging.
+	 */
+	if (PageSwapCache(page))
 		goto unlock;
+	/* called from unmap or delete_from_swap_cache() */
+	if ((ctype == MEM_CGROUP_CHARGE_TYPE_MAPPED)
+		&& (page_mapped(page)
+		    || (page->mapping && !PageAnon(page))))/* alive cache ? */
+			goto unlock;
 
 	mz = page_cgroup_zoneinfo(pc);
 	spin_lock_irqsave(&mz->lru_lock, flags);


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC][PATCH] memcg: change shmem handler.
  2008-06-30  8:36   ` [RFC][PATCH] memcg: change shmem handler KAMEZAWA Hiroyuki
                       ` (2 preceding siblings ...)
  2008-07-01  1:06     ` Re: Re: [RFC][PATCH] memcg: change shmem handler kamezawa.hiroyu
@ 2008-07-03  7:15     ` Balbir Singh
  2008-07-03  7:56       ` KAMEZAWA Hiroyuki
  3 siblings, 1 reply; 24+ messages in thread
From: Balbir Singh @ 2008-07-03  7:15 UTC (permalink / raw)
  To: KAMEZAWA Hiroyuki
  Cc: Hugh Dickins, Andrew Morton, Rik van Riel, Lee Schermerhorn,
	Balbir Singh, linux-kernel

KAMEZAWA Hiroyuki wrote:
> On Sun, 29 Jun 2008 01:22:22 +0100 (BST)
> Hugh Dickins <hugh@veritas.com> wrote:
> 
>> add_to_page_cache_lru puts PageSwapBacked pages on the active_anon lru,
>> so shouldn't mem_cgroup_charge_common mirror that by setting FLAG_ACTIVE?
>>
>> Signed-off-by: Hugh Dickins <hugh@veritas.com>
> 
> How about a patch like this ?
> ==
> a RFC patch: memcg-change-shmem-handler. 
> 
> Should be divided into 2-4 patches, and may have some problem.
> (I did many careless misses today.....)
> 
> But please see idea/concepts. Maybe right way.
> 
> shmem has following characteristics.
> In general.
>   - seems like file cache
>   - swap-backed
>   - when it's swapped out, it's removed from radix-tree and added to swap.
>   - when it's swapped in, it's removed from swap and added to radix-tree.
> 
> With memcg.
>   - shmem is treted just as a file-cache. So, started from inactive list.
>   - shmem's page fault routine is sensitive to GFP_xxx in which used.
>     (GFP_NOWAIT is used) and pre-charge is done before add_to_page_cache.
>   - shmem's page is removed by mem_cgroup_uncharge_cache_page(), So,
>     shmem's swapcache is not charged.
> 
> This patch fixes some mess by
>   - PAGE_CGROUP_FLAG_CACHE is deleted (and replaced by FLAG_FILE)
>   - PAGE_CGROUP_FLAG_SHMEM is added.
>   - add_to_page_cache_nocharge() is added.
>     This avoids mem_cgroup_charge_cache_page(). This is useful when page is
>     pre-charged.
>   - uses add_to_page_cache_nocharge() also in hugemem.
>     (I think hugemem controller should be independent from memcg.
>      Balbir, how do you think ?)

I am not 100% sure of that right now. I definitely want different control
parameters (not included as a part of memory.limit_in_bytes). If there is
leverage from memory controller, we could consider adding that to it or a
separate controller if that makes more sense.

>   - PageSwapBacked() is checked.
>     (A imported patch from Hugh Dickins)
> 
> As result.
>   - shmem will be in SwapBacked/Active list at first.

Good

>   - memcg has "shmem/tmpfs" counter.
> 

I think this will be useful too (but I need to play with it)

> Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
> 
> --
>  include/linux/pagemap.h |   16 +++++++++
>  mm/filemap.c            |   49 ++++++++++++++++++++++--------
>  mm/hugetlb.c            |    3 +
>  mm/memcontrol.c         |   78 +++++++++++++++++++++++++-----------------------
>  mm/shmem.c              |   17 ++++++----
>  5 files changed, 107 insertions(+), 56 deletions(-)
> 
> Index: linux-2.6.26-rc5-mm3-kosaki/mm/memcontrol.c
> ===================================================================
> --- linux-2.6.26-rc5-mm3-kosaki.orig/mm/memcontrol.c	2008-06-30 15:02:52.000000000 +0900
> +++ linux-2.6.26-rc5-mm3-kosaki/mm/memcontrol.c	2008-06-30 16:26:34.000000000 +0900
> @@ -49,6 +49,7 @@
>  	 */
>  	MEM_CGROUP_STAT_CACHE, 	   /* # of pages charged as cache */
>  	MEM_CGROUP_STAT_RSS,	   /* # of pages charged as anon/swapcache */
> +	MEM_CGROUP_STAT_SHMEM,     /* # of pages charges as shmem/tmpfs */
>  	MEM_CGROUP_STAT_PGPGIN_COUNT,	/* # of pages paged in */
>  	MEM_CGROUP_STAT_PGPGOUT_COUNT,	/* # of pages paged out */
> 
> @@ -160,10 +161,10 @@
>  	struct mem_cgroup *mem_cgroup;
>  	int flags;
>  };
> -#define PAGE_CGROUP_FLAG_CACHE	   (0x1)	/* charged as cache */
> -#define PAGE_CGROUP_FLAG_ACTIVE    (0x2)	/* page is active in this cgroup */
> -#define PAGE_CGROUP_FLAG_FILE	   (0x4)	/* page is file system backed */
> -#define PAGE_CGROUP_FLAG_UNEVICTABLE (0x8)	/* page is unevictableable */
> +#define PAGE_CGROUP_FLAG_ACTIVE    (0x1)	/* page is active in this cgroup */
> +#define PAGE_CGROUP_FLAG_FILE	   (0x2)	/* page is file system backed */
> +#define PAGE_CGROUP_FLAG_UNEVICTABLE (0x4)	/* page is unevictableable */
> +#define PAGE_CGROUP_FLAG_SHMEM	   (0x8)       /* page is shmem/tmpfs */
> 
>  static int page_cgroup_nid(struct page_cgroup *pc)
>  {
> @@ -178,6 +179,7 @@
>  enum charge_type {
>  	MEM_CGROUP_CHARGE_TYPE_CACHE = 0,
>  	MEM_CGROUP_CHARGE_TYPE_MAPPED,
> +	MEM_CGROUP_CHARGE_TYPE_SHMEM,
>  	MEM_CGROUP_CHARGE_TYPE_FORCE,	/* used by force_empty */
>  };
> 
> @@ -191,8 +193,10 @@
>  	struct mem_cgroup_stat *stat = &mem->stat;
> 
>  	VM_BUG_ON(!irqs_disabled());
> -	if (flags & PAGE_CGROUP_FLAG_CACHE)
> +	if (flags & PAGE_CGROUP_FLAG_FILE)
>  		__mem_cgroup_stat_add_safe(stat, MEM_CGROUP_STAT_CACHE, val);
> +	else if (flags & PAGE_CGROUP_FLAG_SHMEM)
> +		__mem_cgroup_stat_add_safe(stat, MEM_CGROUP_STAT_SHMEM, val);
>  	else
>  		__mem_cgroup_stat_add_safe(stat, MEM_CGROUP_STAT_RSS, val);
> 
> @@ -573,12 +577,19 @@
>  	 * If a page is accounted as a page cache, insert to inactive list.
>  	 * If anon, insert to active list.
>  	 */
> -	if (ctype == MEM_CGROUP_CHARGE_TYPE_CACHE) {
> -		pc->flags = PAGE_CGROUP_FLAG_CACHE;
> -		if (page_is_file_cache(page))
> -			pc->flags |= PAGE_CGROUP_FLAG_FILE;
> -	} else
> +	switch (ctype) {
> +	case MEM_CGROUP_CHARGE_TYPE_CACHE:
> +		pc->flags = PAGE_CGROUP_FLAG_FILE;
> +		break;
> +	case MEM_CGROUP_CHARGE_TYPE_SHMEM:
> +		pc->flags = PAGE_CGROUP_FLAG_SHMEM | PAGE_CGROUP_FLAG_ACTIVE;
> +		break;
> +	case MEM_CGROUP_CHARGE_TYPE_MAPPED:
>  		pc->flags = PAGE_CGROUP_FLAG_ACTIVE;
> +		break;
> +	default:
> +		BUG();
> +	}
> 
>  	lock_page_cgroup(page);
>  	if (unlikely(page_get_page_cgroup(page))) {
> @@ -625,28 +636,10 @@
>  int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
>  				gfp_t gfp_mask)
>  {
> -	/*
> -	 * Corner case handling. This is called from add_to_page_cache()
> -	 * in usual. But some FS (shmem) precharges this page before calling it
> -	 * and call add_to_page_cache() with GFP_NOWAIT.
> -	 *
> -	 * For GFP_NOWAIT case, the page may be pre-charged before calling
> -	 * add_to_page_cache(). (See shmem.c) check it here and avoid to call
> -	 * charge twice. (It works but has to pay a bit larger cost.)
> -	 */
> -	if (!(gfp_mask & __GFP_WAIT)) {
> -		struct page_cgroup *pc;
> +	enum charge_type ctype = MEM_CGROUP_CHARGE_TYPE_CACHE;
> 
> -		lock_page_cgroup(page);
> -		pc = page_get_page_cgroup(page);
> -		if (pc) {
> -			VM_BUG_ON(pc->page != page);
> -			VM_BUG_ON(!pc->mem_cgroup);
> -			unlock_page_cgroup(page);
> -			return 0;
> -		}
> -		unlock_page_cgroup(page);
> -	}
> +	if (PageSwapBacked(page))
> +		ctype = MEM_CGROUP_CHARGE_TYPE_SHMEM;
> 
>  	if (unlikely(!mm))
>  		mm = &init_mm;
> @@ -678,11 +671,19 @@
>  		goto unlock;
> 
>  	VM_BUG_ON(pc->page != page);
> -
> +	/*
> +	 * There are 2 cases.
> +	 * 1. anon pages are swapped out.
> +	 * 2. shmem pages are swapped out.
> +	 * In both case, PageSwapCache() returns 1 and we don't want to
> +	 * uncharge it.
> +	 */
> +	if (PageSwapCache(page))
> +		goto unlock;
> +	/* When the page is unmapped, file-cache and shmem memory is alive */
>  	if ((ctype == MEM_CGROUP_CHARGE_TYPE_MAPPED)
> -	    && ((pc->flags & PAGE_CGROUP_FLAG_CACHE)
> -		|| page_mapped(page)
> -		|| PageSwapCache(page)))
> +	    && ((pc->flags & (PAGE_CGROUP_FLAG_FILE | PAGE_CGROUP_FLAG_SHMEM))
> +		|| page_mapped(page)))
>  		goto unlock;
> 
>  	mz = page_cgroup_zoneinfo(pc);
> @@ -732,8 +733,10 @@
>  	if (pc) {
>  		mem = pc->mem_cgroup;
>  		css_get(&mem->css);
> -		if (pc->flags & PAGE_CGROUP_FLAG_CACHE)
> +		if (pc->flags & PAGE_CGROUP_FLAG_FILE)
>  			ctype = MEM_CGROUP_CHARGE_TYPE_CACHE;
> +		else if (pc->flags & PAGE_CGROUP_FLAG_SHMEM)
> +			ctype = MEM_CGROUP_CHARGE_TYPE_SHMEM;
>  	}
>  	unlock_page_cgroup(page);
>  	if (mem) {
> @@ -785,6 +788,8 @@
>  		progress = try_to_free_mem_cgroup_pages(mem, gfp_mask);
>  	} while (!progress && --retry);
> 
> +	css_put(&mem->css);
> +

Didn't Hugh fix this as a part of his patchset.

>  	if (!retry)
>  		return -ENOMEM;
>  	return 0;
> @@ -920,6 +925,7 @@
>  } mem_cgroup_stat_desc[] = {
>  	[MEM_CGROUP_STAT_CACHE] = { "cache", PAGE_SIZE, },
>  	[MEM_CGROUP_STAT_RSS] = { "anon/swapcache", PAGE_SIZE, },
> +	[MEM_CGROUP_STAT_SHMEM] = { "shmem/tmpfs", PAGE_SIZE, },
>  	[MEM_CGROUP_STAT_PGPGIN_COUNT] = {"pgpgin", 1, },
>  	[MEM_CGROUP_STAT_PGPGOUT_COUNT] = {"pgpgout", 1, },
>  };
> Index: linux-2.6.26-rc5-mm3-kosaki/include/linux/pagemap.h
> ===================================================================
> --- linux-2.6.26-rc5-mm3-kosaki.orig/include/linux/pagemap.h	2008-06-30 15:00:04.000000000 +0900
> +++ linux-2.6.26-rc5-mm3-kosaki/include/linux/pagemap.h	2008-06-30 15:03:02.000000000 +0900
> @@ -258,6 +258,22 @@
>  				pgoff_t index, gfp_t gfp_mask);
>  int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
>  				pgoff_t index, gfp_t gfp_mask);
> +
> +#ifdef CONFIG_CGROUP_MEM_RES_CTLR
> +/*
> + * If the page is pre-charged before add_to_page_cache() this routine is
> + * light-weight.
> + */
> +int add_to_page_cache_nocharge(struct page *page, struct address_space *mapping,
> +				pgoff_t index, gfp_t gfp_mask);
> +#else
> +static inline int add_to_page_cache_nocharge(struct page *page,
> +				struct address_space *mapping, pgoff_t index,
> +				gfp_t mask)
> +{
> +	return add_to_page_cache(page, mapping, index, gfp_mask);
> +}
> +#endif
>  extern void remove_from_page_cache(struct page *page);
>  extern void __remove_from_page_cache(struct page *page);
> 
> Index: linux-2.6.26-rc5-mm3-kosaki/mm/filemap.c
> ===================================================================
> --- linux-2.6.26-rc5-mm3-kosaki.orig/mm/filemap.c	2008-06-30 15:00:04.000000000 +0900
> +++ linux-2.6.26-rc5-mm3-kosaki/mm/filemap.c	2008-06-30 15:23:36.000000000 +0900
> @@ -442,8 +442,9 @@
>  	return err;
>  }
> 
> +
>  /**
> - * add_to_page_cache - add newly allocated pagecache pages
> + * add_to_page_cache_nocharge() - add newly allocated pagecache pages
>   * @page:	page to add
>   * @mapping:	the page's address_space
>   * @offset:	page index
> @@ -454,22 +455,20 @@
>   * The other page state flags were set by rmqueue().
>   *
>   * This function does not add the page to the LRU.  The caller must do that.
> + * This doesn't call memory resource control routine.
>   */
> -int add_to_page_cache(struct page *page, struct address_space *mapping,
> -		pgoff_t offset, gfp_t gfp_mask)
> +
> +int add_to_page_cache_nocharge(struct page *page,
> +			       struct address_space *mapping,
> +			       pgoff_t offset, gfp_t gfp_mask)
>  {

I wonder if we should modify a generic routine and add charge/no charge variants
to it. Charging is very memory controller specific operation. Can't we infer the
charging/no charging from gfp_mask or another flag?

> -	int error = mem_cgroup_cache_charge(page, current->mm,
> -					gfp_mask & ~__GFP_HIGHMEM);
> -	if (error)
> -		goto out;
> 
> -	error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
> +	int error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
>  	if (error == 0) {
>  		page_cache_get(page);
>  		SetPageLocked(page);
>  		page->mapping = mapping;
>  		page->index = offset;
> -
>  		spin_lock_irq(&mapping->tree_lock);
>  		error = radix_tree_insert(&mapping->page_tree, offset, page);
>  		if (likely(!error)) {
> @@ -478,15 +477,39 @@
>  		} else {
>  			page->mapping = NULL;
>  			ClearPageLocked(page);
> -			mem_cgroup_uncharge_cache_page(page);
>  			page_cache_release(page);
>  		}
> 
>  		spin_unlock_irq(&mapping->tree_lock);
>  		radix_tree_preload_end();
> -	} else
> -		mem_cgroup_uncharge_cache_page(page);
> -out:
> +	}
> +	return error;
> +}
> +
> +/**
> + * add_to_page_cache - add newly allocated pagecache pages
> + * @page:	page to add
> + * @mapping:	the page's address_space
> + * @offset:	page index
> + * @gfp_mask:	page allocation mode
> + *
> + * This function is used to add newly allocated pagecache pages;
> + * the page is new, so we can just run SetPageLocked() against it.
> + * The other page state flags were set by rmqueue().
> + *
> + * This function does not add the page to the LRU.  The caller must do that.
> + */
> +int add_to_page_cache(struct page *page, struct address_space *mapping,
> +		pgoff_t offset, gfp_t gfp_mask)
> +{
> +	int error = mem_cgroup_cache_charge(page, current->mm,
> +					gfp_mask & ~__GFP_HIGHMEM);
> +	if (!error) {
> +		error = add_to_page_cache_nocharge(page, mapping, offset,
> +						  gfp_mask);
> +		if (error)
> +			mem_cgroup_uncharge_cache_page(page);
> +	}
>  	return error;
>  }
>  EXPORT_SYMBOL(add_to_page_cache);
> Index: linux-2.6.26-rc5-mm3-kosaki/mm/shmem.c
> ===================================================================
> --- linux-2.6.26-rc5-mm3-kosaki.orig/mm/shmem.c	2008-06-30 15:00:04.000000000 +0900
> +++ linux-2.6.26-rc5-mm3-kosaki/mm/shmem.c	2008-06-30 15:37:11.000000000 +0900
> @@ -940,10 +940,8 @@
>  	spin_lock(&info->lock);
>  	ptr = shmem_swp_entry(info, idx, NULL);
>  	if (ptr && ptr->val == entry.val)
> -		error = add_to_page_cache(page, inode->i_mapping, idx,
> +		error = add_to_page_cache_nocharge(page, inode->i_mapping, idx,
>  					GFP_NOWAIT);
> -	else /* we don't have to account this page. */
> -		mem_cgroup_uncharge_cache_page(page);
> 
>  	if (error == -EEXIST) {
>  		struct page *filepage = find_get_page(inode->i_mapping, idx);
> @@ -955,6 +953,7 @@
>  			 */
>  			if (PageUptodate(filepage))
>  				error = 0;
> +			mem_cgroup_uncharge_cache_page(page);
>  			page_cache_release(filepage);
>  		}
>  	}
> @@ -965,7 +964,9 @@
>  		shmem_swp_set(info, ptr, 0);
>  		swap_free(entry);
>  		error = 1;	/* not an error, but entry was found */
> -	}
> +	} else
> +		mem_cgroup_uncharge_cache_page(page);
> +
>  	if (ptr)
>  		shmem_swp_unmap(ptr);
>  	spin_unlock(&info->lock);
> @@ -1375,6 +1376,7 @@
>  				error = -ENOMEM;
>  				goto failed;
>  			}
> +			SetPageSwapBacked(filepage);
> 
>  			/* Precharge page while we can wait, compensate after */
>  			error = mem_cgroup_cache_charge(filepage, current->mm,
> @@ -1387,7 +1389,6 @@
>  				goto failed;
>  			}
> 
> -			SetPageSwapBacked(filepage);

I thought I saw a patch from Hugh for this one too.. but I might be missing the
chronological ordering of which came first.

>  			spin_lock(&info->lock);
>  			entry = shmem_swp_alloc(info, idx, sgp);
>  			if (IS_ERR(entry))
> @@ -1400,7 +1401,8 @@
>  			if (ret)
>  				mem_cgroup_uncharge_cache_page(filepage);
>  			else
> -				ret = add_to_page_cache_lru(filepage, mapping,
> +				ret = add_to_page_cache_nocharge(filepage,
> +						mapping,
>  						idx, GFP_NOWAIT);
>  			/*
>  			 * At add_to_page_cache_lru() failure, uncharge will
> @@ -1408,6 +1410,7 @@
>  			 */
>  			if (ret) {
>  				spin_unlock(&info->lock);
> +				mem_cgroup_uncharge_cache_page(filepage);
>  				page_cache_release(filepage);
>  				shmem_unacct_blocks(info->flags, 1);
>  				shmem_free_blocks(inode, 1);
> @@ -1415,6 +1418,8 @@
>  				if (error)
>  					goto failed;
>  				goto repeat;
> +			} else {
> +				lru_cache_add_active_anon(filepage);
>  			}
>  			info->flags |= SHMEM_PAGEIN;
>  		}
> Index: linux-2.6.26-rc5-mm3-kosaki/mm/hugetlb.c
> ===================================================================
> --- linux-2.6.26-rc5-mm3-kosaki.orig/mm/hugetlb.c	2008-06-25 18:07:09.000000000 +0900
> +++ linux-2.6.26-rc5-mm3-kosaki/mm/hugetlb.c	2008-06-30 15:08:16.000000000 +0900
> @@ -1813,7 +1813,8 @@
>  			int err;
>  			struct inode *inode = mapping->host;
> 
> -			err = add_to_page_cache(page, mapping, idx, GFP_KERNEL);
> +			err = add_to_page_cache_nocharge(page, mapping,
> +						idx, GFP_KERNEL);
>  			if (err) {
>  				put_page(page);
>  				if (err == -EEXIST)
> 


-- 
	Warm Regards,
	Balbir Singh
	Linux Technology Center
	IBM, ISTL

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC][PATCH] memcg: change shmem handler.
  2008-07-03  7:15     ` Balbir Singh
@ 2008-07-03  7:56       ` KAMEZAWA Hiroyuki
  0 siblings, 0 replies; 24+ messages in thread
From: KAMEZAWA Hiroyuki @ 2008-07-03  7:56 UTC (permalink / raw)
  To: balbir
  Cc: Hugh Dickins, Andrew Morton, Rik van Riel, Lee Schermerhorn,
	Balbir Singh, linux-kernel

On Thu, 03 Jul 2008 12:45:14 +0530
Balbir Singh <balbir@linux.vnet.ibm.com> wrote:

> > This patch fixes some mess by
> >   - PAGE_CGROUP_FLAG_CACHE is deleted (and replaced by FLAG_FILE)
> >   - PAGE_CGROUP_FLAG_SHMEM is added.
> >   - add_to_page_cache_nocharge() is added.
> >     This avoids mem_cgroup_charge_cache_page(). This is useful when page is
> >     pre-charged.
> >   - uses add_to_page_cache_nocharge() also in hugemem.
> >     (I think hugemem controller should be independent from memcg.
> >      Balbir, how do you think ?)
> 
> I am not 100% sure of that right now. I definitely want different control
> parameters (not included as a part of memory.limit_in_bytes). If there is
> leverage from memory controller, we could consider adding that to it or a
> separate controller if that makes more sense.
> 
Checking PG_compound in mem_cgroup_charge_cache_page() is enough, maybe.
(If multi-page-file-cache is added, need rework ;)

> >   - PageSwapBacked() is checked.
> >     (A imported patch from Hugh Dickins)
> > 
> > As result.
> >   - shmem will be in SwapBacked/Active list at first.
> 
> Good
> 
> >   - memcg has "shmem/tmpfs" counter.
> > 
> 
> I think this will be useful too (but I need to play with it)
> 
I've been argued that "if you want to add such a stupid counter, add the
same parameter to global lru without any overhead."

I'll postpone this ;) I have many other thing to do.

But the total number of pages used for shmem is already counted by
address_space->nr_pages. So, not very difficult for global lru if we can
walk all inodes of shmem. The problem will be "whether it's worth to do or not"

Thanks,
-Kame



^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2008-07-03  8:32 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-06-29  0:20 [PATCH] splitlru: shmem_getpage SetPageSwapBacked sooner Hugh Dickins
2008-06-29  0:22 ` [PATCH] splitlru: memcg swapbacked pages active Hugh Dickins
2008-06-29  8:19   ` KOSAKI Motohiro
2008-06-29 12:20     ` Hugh Dickins
2008-06-29 12:58       ` KOSAKI Motohiro
2008-06-29 13:51         ` Hugh Dickins
2008-06-30  2:44   ` KAMEZAWA Hiroyuki
2008-06-30 19:19     ` Hugh Dickins
2008-06-30  8:36   ` [RFC][PATCH] memcg: change shmem handler KAMEZAWA Hiroyuki
2008-06-30 19:52     ` Hugh Dickins
2008-07-01  0:56     ` kamezawa.hiroyu
2008-07-02  2:16       ` [RFC][PATCH] memcg: shmem swap cache KAMEZAWA Hiroyuki
2008-07-01  1:06     ` Re: Re: [RFC][PATCH] memcg: change shmem handler kamezawa.hiroyu
2008-07-03  7:15     ` Balbir Singh
2008-07-03  7:56       ` KAMEZAWA Hiroyuki
2008-06-29  0:24 ` [PATCH] splitlru: BDI_CAP_SWAP_BACKED Hugh Dickins
2008-06-29  8:48   ` KOSAKI Motohiro
2008-06-29 15:16     ` Rik van Riel
2008-06-30  2:53     ` KAMEZAWA Hiroyuki
2008-06-30 19:23       ` Hugh Dickins
2008-06-30 19:49         ` Rik van Riel
2008-06-30 20:55           ` Hugh Dickins
2008-06-30 21:17             ` Rik van Riel
2008-06-29  8:09 ` [PATCH] splitlru: shmem_getpage SetPageSwapBacked sooner KOSAKI Motohiro

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®