Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 1165

kernel-2.6.18-238.el5.src.rpm

From: Steve Best <sbest@redhat.com>
Date: Mon, 29 Nov 2010 15:39:51 -0500
Subject: [fs] proc: fix NULL ->i_fop oops
Message-id: <20101129153428.7915.29829.sendpatchset@squad5-lp1.lab.bos.redhat.com>
Patchwork-id: 29651
O-Subject: [PATCH RHEL5.6 BZ655083] proc: fix NULL ->i_fop oops
Bugzilla: 655083
RH-Acked-by: Amerigo Wang <amwang@redhat.com>
RH-Acked-by: Stefan Assmann <sassmann@redhat.com>
RH-Acked-by: David Howells <dhowells@redhat.com>

RHBZ#:
------
https://bugzilla.redhat.com/show_bug.cgi?id=655083

Description:
------------
A powerpc system dropped into xmon at .vfs_readdir+0xc0/0x13c after running
stress tests for about 96 hours.
mon> e
cpu 0xb: Vector: 300 (Data Access) at [c0000000fee03a40]
    pc: c00000000011828c: .vfs_readdir+0xc0/0x13c
    lr: c000000000118268: .vfs_readdir+0x9c/0x13c
    sp: c0000000fee03cc0
   msr: 8000000000009032
   dar: 30
 dsisr: 40000000
  current = 0xc00000011ca7c530
  paca    = 0xc00000000054ef00
    pid   = 2732, comm = kexec
b:mon> t
[c0000000fee03d70] c000000000118494 .sys_getdents+0x7c/0x120
[c0000000fee03e30] c0000000000086a4 syscall_exit+0x0/0x40
--- Exception: c00 (System Call) at 0000008024557060
SP (ffffffb1d00) is in userspace
b:mon> r
R00 = 0000000000000000   R16 = 000000001004f052
R01 = c0000000fee03cc0   R17 = 000000001004f028
R02 = c000000000619d80   R18 = 0000000010021580
R03 = c0000000fdff9580   R19 = 00000000100ae5b0
R04 = c0000000fee03de0   R20 = 00000ffffffb60f0
R05 = c0000000005efa58   R21 = 0000000010049040
R06 = 0000000024002442   R22 = 0000000000000002
R07 = 00000000006fb480   R23 = 0000000000000000
R08 = 0000000000000000   R24 = 0000000000000000
R09 = 0000000000000000   R25 = c0000000fee03de0
R10 = c0000000dfaef178   R26 = c0000000005efa58
R11 = c0000000dfaef178   R27 = c0000000dfaef170
R12 = d000000000131480   R28 = c0000000dfaef0b8
R13 = c00000000054ef00   R29 = fffffffffffffffe
R14 = 00000ffffffba758   R30 = c00000000059e328
R15 = 0000000000000000   R31 = c0000000fdff9580
pc  = c00000000011828c .vfs_readdir+0xc0/0x13c
lr  = c000000000118268 .vfs_readdir+0x9c/0x13c
msr = 8000000000009032   cr  = 24002442
ctr = c0000000003e0f8c   xer = 0000000020000001   trap =  300
dar = 0000000000000030   dsisr = 40000000

b:mon> di c00000000011828c
c00000000011828c  e9290030      ld      r9,48(r9)  <=====  Hitting the panic
here
c000000000118290  e8090000      ld      r0,0(r9)
c000000000118294  f8410028      std     r2,40(r1)
c000000000118298  7c0903a6      mtctr   r0
c00000000011829c  e9690010      ld      r11,16(r9)
c0000000001182a0  e8490008      ld      r2,8(r9)
c0000000001182a4  4e800421      bctrl
c0000000001182a8  e8410028      ld      r2,40(r1)
c0000000001182ac  801f002c      lwz     r0,44(r31)
c0000000001182b0  7c7d1b78      mr      r29,r3
c0000000001182b4  780977e3      rldicl. r9,r0,46,63
c0000000001182b8  40820014      bne     c0000000001182cc        #
.vfs_readdir+0x100/0x13c

Register r9 contains 0 and thus resulting in trying to access the invalid
address 0x00000030
as shown in the syslog too:
<4>remove_proc_entry: cpus/PowerPC,POWER7@c busy, count=1.
<1>Unable to handle kernel paging request for data at address 0x00000030.
<1>Faulting instruction address: 0xc00000000011828c.............

The following upstream commit c2319540cd7330fa9066e5b9b84d357a2c8631a2
fixes this issue.

proc_kill_inodes() can clear ->i_fop in the middle of vfs_readdir resulting in
NULL dereference during "file->f_op->readdir(file, buf, filler)".

    The solution is to remove proc_kill_inodes() completely:

Signed-off-by: Alexey Dobriyan <[EMAIL PROTECTED]>
    Acked-by: Christoph Hellwig <[EMAIL PROTECTED]>
    Cc: Al Viro <[EMAIL PROTECTED]>
    Cc: Stephen Smalley <[EMAIL PROTECTED]>
    Cc: James Morris <[EMAIL PROTECTED]>
    Cc: "Eric W. Biederman" <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>

RHEL Version Found:
-------------------
RHEL 5.6

Brew:
-----
http://brewweb.devel.redhat.com/brew/taskinfo?taskID=2906092

Upstream:
---------
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;
a=commit;h=c2319540cd7330fa9066e5b9b84d357a2c8631a2

Test Status:
------------

Tested by the IBM ppc stress test team.

---------------------------------------------------------------
Steve Best
IBM on-site partner

Proposed Patch:
---------------

Signed-off-by: Jarod Wilson <jarod@redhat.com>

diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 96e9156..9e8e204 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -544,35 +544,6 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp
 	return 0;
 }
 
-/*
- * Kill an inode that got unregistered..
- */
-static void proc_kill_inodes(struct proc_dir_entry *de)
-{
-	struct list_head *p;
-	struct super_block *sb = proc_mnt->mnt_sb;
-
-	/*
-	 * Actually it's a partial revoke().
-	 */
-	file_list_lock();
-	list_for_each(p, &sb->s_files) {
-		struct file * filp = list_entry(p, struct file, f_u.fu_list);
-		struct dentry * dentry = filp->f_dentry;
-		struct inode * inode;
-		const struct file_operations *fops;
-
-		if (dentry->d_op != &proc_dentry_operations)
-			continue;
-		inode = dentry->d_inode;
-		if (PDE(inode) != de)
-			continue;
-		fops = filp->f_op;
-		filp->f_op = NULL;
-		fops_put(fops);
-	}
-	file_list_unlock();
-}
 
 static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
 					  const char *name,
@@ -759,7 +730,6 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
 		de->next = NULL;
 		if (S_ISDIR(de->mode))
 			parent->nlink--;
-		proc_kill_inodes(de);
 		de->nlink = 0;
 		WARN_ON(de->subdir);
 		if (!atomic_read(&de->count))