Skip to contentSkip to conversation

2.6.33 pagemap endless read loop

PATCH In review Andi Kleen 5 participants 11 messages Jan 10, 2010 – Jan 14, 2010 7 messages not in the archive

Subsystems (2)
lore
Share & tools
lore

Andi Kleen

author
#0 lore raw

An LTP run on x86-64/2.6.33-rc3 run right now results in "proc01" hanging

lr-x------ 1 root root 64 2010-01-10 02:28 7 -> /proc/2679/task/2679/pagemap

strace shows an endless loop of

read(7, "\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0"..., 1024) = 1024 read(7, "\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0"..., 1024) = 1024 read(7, "\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0"..., 1024) = 1024 read(7, "\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0"..., 1024) = 1024 read(7, "\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0"..., 1024) = 1024 read(7, "\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0"..., 1024) = 1024 read(7, "\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0"..., 1024) = 10

cat of that file hangs in the same way so it seems like a kernel bug. A cat of /proc/2679/pagemap also hangs, in fact any pagemap cat seems to.

I tried to revert the latest change from Horiguchi-san:

commit 5dc37642cbce34619e4588a9f0bdad1d2f870956

Author: Naoya Horiguchi <[email protected]>
Date:   Mon Dec 14 18:00:01 2009 -0800

mm hugetlb: add hugepage support to pagemap

but that didn't fix it, so it must be something else.

Haven't done further bisect or anything, should be easy to reproduce.

-Andi

Signature · 1 line
[email protected] -- Speaking for myself only.
#1 lore raw
Quoted 15 lines · Andi Kleen

An LTP run on x86-64/2.6.33-rc3 run right now results in "proc01" hanging

lr-x------ 1 root root 64 2010-01-10 02:28 7 -> /proc/2679/task/2679/pagemap

strace shows an endless loop of

read(7, "\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0"..., 1024) = 1024 read(7, "\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0"..., 1024) = 1024 read(7, "\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0"..., 1024) = 1024 read(7, "\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0"..., 1024) = 1024 read(7, "\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0"..., 1024) = 1024 read(7, "\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0"..., 1024) = 1024 read(7, "\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0\0\0\0\0\6\0\0\0"..., 1024) = 10

Quoted 3 lines

cat of that file hangs in the same way so it seems like a kernel bug. A cat of /proc/2679/pagemap also hangs, in fact any pagemap cat seems to.

Are you sure?

On my 32bit machine, it runs for a long time, but finally exits.

Quoted 1 line

From the document of pagemap, it is the mapping of all the virtual pages

of a process, on x86-32, it should be 4G/4K = 1024*1024 pages, also that when you 'cat' it, tty layer is involved to display it too.

Signature · 1 line
Live like a child, think like the god.
author
#2 lore raw
Quoted 1 line

Are you sure

I don't know if it's really endless, but it's doing a good emulation of it if it's not.

Quoted 2 lines

On my 32bit machine, it runs for a long time, but finally exits.

That was on 64bit.

proc01 had accumulated several minutes of CPU time when I stopped it.

Quoted 2 lines

From the document of pagemap, it is the mapping of all the virtual pages of a process, on x86-32, it should be 4G/4K = 1024*1024 pages, also

Only the mapped ones surely?

Right now it looks like it dumps all the holes and that obviously will never finish on 64bit which has 47bits of address space.

-Andi

Signature · 1 line
[email protected] -- Speaking for myself only.
#3 lore raw
Quoted 12 lines · Andi Kleen
Quoted 1 line

Are you sure

I don't know if it's really endless, but it's doing a good emulation of it if it's not.

Quoted 2 lines

On my 32bit machine, it runs for a long time, but finally exits.

That was on 64bit.

proc01 had accumulated several minutes of CPU time when I stopped it.

Quoted 7 lines
Quoted 2 lines

From the document of pagemap, it is the mapping of all the virtual pages of a process, on x86-32, it should be 4G/4K = 1024*1024 pages, also

Only the mapped ones surely?

Right now it looks like it dumps all the holes and that obviously will never finish on 64bit which has 47bits of address space.

Takes forever if you whack .pagemap_pte_hole too, just spends it's life in pagemap_pte_range() instead.

start_vaddr:0x0 end_vaddr:0x7ffffffff000

Hm, zillion paces ain't a walk.

-Mike

#4 lore raw
In reply to Andi Kleen
Quoted 12 lines · Andi Kleen
Quoted 1 line

Are you sure

I don't know if it's really endless, but it's doing a good emulation of it if it's not.

Quoted 2 lines

On my 32bit machine, it runs for a long time, but finally exits.

That was on 64bit.

proc01 had accumulated several minutes of CPU time when I stopped it.

Quoted 8 lines
Quoted 2 lines

From the document of pagemap, it is the mapping of all the virtual pages of a process, on x86-32, it should be 4G/4K = 1024*1024 pages, also

Only the mapped ones surely?

Right now it looks like it dumps all the holes and that obviously will never finish on 64bit which has 47bits of address space.

Hmm, could you please try:

time cat /proc/self/pagemap >/dev/null

? Is it much faster than:

time cat /proc/self/pagemap

?

Thanks!

Signature · 1 line
Live like a child, think like the god.
author
#5 lore raw
Quoted 4 lines

Hmm, could you please try:

time cat /proc/self/pagemap >/dev/null

I stopped it after a minute of CPU time...

Obviously reading 47bits of zeroes take a long time.

-Andi

Signature · 1 line
[email protected] -- Speaking for myself only.
#6 lore raw
Quoted 9 lines · Andi Kleen
Quoted 4 lines

Hmm, could you please try:

     time cat /proc/self/pagemap >/dev/null

I stopped it after a minute of CPU time...

Obviously reading 47bits of zeroes take a long time.

Yeah, but this just proves it is not endless, doesn't it? :)

Thanks.

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): 1263421562.29868.5000.camel@calx

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): 1263423916.29868.5009.camel@calx

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): 20100114055319.GA17671@localhost

A message that is not in the archive (sent off-list or not yet received): [email protected]

#14 lore raw
Quoted 8 lines · Andrew Morton
Quoted 6 lines · On Thu, 14 Jan 2010 13:53:19 +0800 Wu Fengguang <[email protected]> wrote:

On Thu, Jan 14, 2010 at 07:15:02AM +0800, Andrew Morton wrote:

(quoted diff) +0 -0
@@ -740,6 +740,11 @@ static ssize_t pagemap_read(struct file 
 	if (!ptrace_may_access(task, PTRACE_MODE_READ))
 		goto out_task;
 
Quoted 11 lines

Review static ssize_t pagemap_read(struct file · line 750

Quoted 8 lines
(quoted diff) +5 -0
+	/* stop dumb cp/cat */
+	ret = -EFAULT;
+	if (!*ppos)
+		goto out_task;
+
 	ret = -EINVAL;
 	/* file position must be aligned */
 	if ((*ppos % PM_ENTRY_BYTES) || (count % PM_ENTRY_BYTES))

Seems simple. But is there a usecase for reading at that offset? I think it's possible to map a page at 0 with MAP_FIXED. I forget..

How about this trick?
Tests show that cp/cat will exit if read nothing :)

---
pagemap: early return on unmapped areas

This helps stop dumb cp/cat early instead of loop for days:

http://bugzilla.kernel.org/show_bug.cgi?id=15041

This also serves as an optimization to normal pagemap users (eg. page-types).

---
 fs/proc/task_mmu.c |    4 ++++
 1 file changed, 4 insertions(+)
fs/proc/task_mmu.c +4 -0
@@ -586,6 +586,10 @@ static int pagemap_pte_hole(unsigned lon
 	struct pagemapread *pm = walk->private;
 	unsigned long addr;
 	int err = 0;
+
+	if ((end - start) / PAGE_SIZE > pm->end - pm->out)
+		return PM_END_OF_BUFFER;
+
 	for (addr = start; addr < end; addr += PAGE_SIZE) {
 		err = add_to_pagemap(addr, PM_NOT_PRESENT, pm);
 		if (err)
author
#15 lore raw
Quoted 2 lines

---
pagemap: early return on unmapped areas

Yes seems like a reasonable idea.

-Andi

#16 lore raw

PATCH 1/1 pagemap: early return on unmapped areas

Quoted 4 lines · Andi Kleen
Quoted 2 lines

---
pagemap: early return on unmapped areas

Yes seems like a reasonable idea.

Thanks!

I just changed the ">" to ">=", because it happen to make a difference for cp/cat, which does 4k sized read:

4k read buffer = 4k/8 pages = 512 pages = NR_PMD_PAGES

So the change to ">=" makes cp exit immediately (4k buffer matches exactly one PMD hole).

before

        dd if=/proc/$$/pagemap of=/dev/null bs=4k
        512+0 records in
        512+0 records out
        2097152 bytes (2.1 MB) copied, 0.0225796 s, 92.9 MB/s

after
dd if=/proc/$$/pagemap of=/dev/null bs=4k 0+0 records in
0+0 records out
0 bytes (0 B) copied, 2.8029e-05 s, 0.0 kB/s

page-types still works (only faster;) with this patch.

Thanks,
Fengguang
---
pagemap: early return on unmapped areas

This helps stop dumb cp/cat early instead of loop for days:

http://bugzilla.kernel.org/show_bug.cgi?id=15041

This also serves as an optimization to normal pagemap users (eg. page-types).

---
 fs/proc/task_mmu.c |    4 ++++
 1 file changed, 4 insertions(+)
fs/proc/task_mmu.c +4 -0
@@ -586,6 +586,10 @@ static int pagemap_pte_hole(unsigned lon
 	struct pagemapread *pm = walk->private;
 	unsigned long addr;
 	int err = 0;
+
+	if ((end - start) / PAGE_SIZE >= pm->end - pm->out)
+		return PM_END_OF_BUFFER;
+
 	for (addr = start; addr < end; addr += PAGE_SIZE) {
 		err = add_to_pagemap(addr, PM_NOT_PRESENT, pm);
 		if (err)
#17 lore raw

Re: [PATCH] pagemap: early return on unmapped areas

Quoted 22 lines · Wu Fengguang
Quoted 4 lines · Andi Kleen
Quoted 2 lines

---
pagemap: early return on unmapped areas

Yes seems like a reasonable idea.

Thanks!

I just changed the ">" to ">=", because it happen to make a difference for cp/cat, which does 4k sized read:

4k read buffer = 4k/8 pages = 512 pages = NR_PMD_PAGES

So the change to ">=" makes cp exit immediately (4k buffer matches exactly one PMD hole).

before

        dd if=/proc/$$/pagemap of=/dev/null bs=4k
        512+0 records in
        512+0 records out
        2097152 bytes (2.1 MB) copied, 0.0225796 s, 92.9 MB/s
Quoted 5 lines

after
dd if=/proc/$$/pagemap of=/dev/null bs=4k 0+0 records in
0+0 records out
0 bytes (0 B) copied, 2.8029e-05 s, 0.0 kB/s

Have you guys lost your minds?

I regularly used the exact standard tool you just broke above to test pagemap when I was developing it. There's no doubt that this patch (or any similarly misguided ones) WILL regress existing naive or not intended to be portable 32-bit users. And if I was some poor future bastard trying to write a program against pagemap with your patch, odds of getting a concussion banging my head against the wall trying to figure out its highly non-file-like behavior would be quite high.

Why are we even still on this. There's no regression. LTP + pagemap + 64-bit has always behaved thus. Nor are large virtual files new. And LTP's n00b assumption that it can just read all of any file in /proc has always been wrong. LTP had the exact same problem on 64-bit /proc/kcore (how long has that existed?) and finally fixed it in 2005.

Signature · 1 line
http://selenic.com : development and support for Mercurial and Linux