2000-10-29 15:14:16

by Erik Mouw

[permalink] [raw]
Subject: Oops in block_read_full_page()


I just got an Oops in block_read_full_page() (fs/buffer.c) in
test10-pre6 while logging out from X. The system is an Asus P6300
notebook with Mobile PII/266 and 112MB memory running SuSE 6.4.
Here is the output from ksymoops:

ksymoops 0.7c on i686 2.4.0-test10. Options used
-V (default)
-k /proc/ksyms (default)
-l /proc/modules (default)
-o /lib/modules/2.4.0-test10/ (default)
-m /usr/src/linux/System.map (default)

Warning: You did not tell me where to find symbol information. I will
assume that the log matches the kernel and modules that are running
right now and I'll use the default options above for symbol resolution.
If the current kernel and/or modules do not match the log, you can get
more accurate output by telling me the kernel version and where to find
map, modules, ksyms etc. ksymoops -h explains the options.

Warning (compare_maps): snd symbol pm_register not found in /lib/modules/2.4.0-test10/misc/snd.o. Ignoring /lib/modules/2.4.0-test10/misc/snd.o entry
Warning (compare_maps): snd symbol pm_send not found in /lib/modules/2.4.0-test10/misc/snd.o. Ignoring /lib/modules/2.4.0-test10/misc/snd.o entry
Warning (compare_maps): snd symbol pm_unregister not found in /lib/modules/2.4.0-test10/misc/snd.o. Ignoring /lib/modules/2.4.0-test10/misc/snd.o entry
Unable to handle kernel NULL pointer dereference at virtual address 00000010
*pde = 00000000
Oops: 0000
CPU: 0
EIP: 0010:[<c012fb46>]
Using defaults from ksymoops -t elf32-i386 -a i386
EFLAGS: 00010282
eax: 00000000 ebx: 00000000 ecx: c421ff24 edx: c111f030
esi: c111f030 edi: c412a5dc ebp: 00000000 esp: c4321ee4
ds: 0018 es: 0018 ss: 0018
Process tcsh (pid: 439, stackpage=c4321000)
Stack: 00000000 c111f030 c412a5dc 00000000 0000001f 00000000 c0224540 00000246
c012275e 00000000 c111f030 c412a5dc 00000000 c4321f1c 01234567 c4320000
c111f05c c421ff24 c014a54f c111f030 c0149ec8 c0123005 c4805540 c111f030
Call Trace: [<c012275e>] [<c014a54f>] [<c0149ec8>] [<c0123005>] [<c01232df>] [<c0123230>] [<c012d646>]
Code: 8b 40 10 89 44 24 24 c7 44 24 18 00 00 00 00 8b 42 18 a8 01

>>EIP; c012fb46 <block_read_full_page+e/1e8> <=====
Trace; c012275e <___wait_on_page+ca/d4>
Trace; c014a54f <ext2_readpage+f/14>
Trace; c0149ec8 <ext2_get_block+0/490>
Trace; c0123005 <do_generic_file_read+29d/4c8>
Trace; c01232df <generic_file_read+5b/78>
Trace; c0123230 <file_read_actor+0/54>
Trace; c012d646 <sys_read+96/cc>
Trace; c010a317 <system_call+33/38>
Code; c012fb46 <block_read_full_page+e/1e8>
00000000 <_EIP>:
Code; c012fb46 <block_read_full_page+e/1e8> <=====
0: 8b 40 10 mov 0x10(%eax),%eax <=====
Code; c012fb49 <block_read_full_page+11/1e8>
3: 89 44 24 24 mov %eax,0x24(%esp,1)
Code; c012fb4d <block_read_full_page+15/1e8>
7: c7 44 24 18 00 00 00 movl $0x0,0x18(%esp,1)
Code; c012fb54 <block_read_full_page+1c/1e8>
e: 00
Code; c012fb55 <block_read_full_page+1d/1e8>
f: 8b 42 18 mov 0x18(%edx),%eax
Code; c012fb58 <block_read_full_page+20/1e8>
12: a8 01 test $0x1,%al

4 warnings issued. Results may not be reliable.

I'm using linux-2.4.0-test10-pre6 with John Kennedy's single line
PCMCIA patch and ALSA 0.5.9d (that's what the ksymoops warnings are
coming from).

Closer examination of block_read_full_page() shows that it crashes in
the first line:

struct inode *inode = (struct inode*)page->mapping->host;

A little bit further in the function, it tests if the page is not

if (!PageLocked(page))

I'm not an expert in this area, but I can imagine that the inode
extraction in the first line fails if there is something wrong with the
page parameter itself. To catch those cases, I'd like to propose the
following diff:

--- linux-2.4.0-test10-pre6/fs/buffer.c.old Sun Oct 29 15:28:56 2000
+++ linux-2.4.0-test10-pre6/fs/buffer.c Sun Oct 29 15:29:35 2000
@@ -1581,7 +1581,7 @@
int block_read_full_page(struct page *page, get_block_t *get_block)
- struct inode *inode = (struct inode*)page->mapping->host;
+ struct inode *inode;
unsigned long iblock, lblock;
struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
unsigned int blocksize, blocks;
@@ -1590,6 +1590,9 @@

if (!PageLocked(page))
+ inode = (struct inode*)page->mapping->host;
blocksize = inode->i_sb->s_blocksize;
if (!page->buffers)
create_empty_buffers(page, inode, blocksize);

I'm currently running a kernel with this diff applied, but haven't yet
succeeded in reproducing the Oops. Config file is attached.


J.A.K. (Erik) Mouw, Information and Communication Theory Group, Department
of Electrical Engineering, Faculty of Information Technology and Systems,
Delft University of Technology, PO BOX 5031, 2600 GA Delft, The Netherlands
Phone: +31-15-2783635 Fax: +31-15-2781843 Email: [email protected]
WWW: http://www-ict.its.tudelft.nl/~erik/

config.arthur (19.96 kB)