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))