From: Pete Zaitcev <zaitcev@redhat.com> Date: Wed, 20 Aug 2008 14:40:07 -0600 Subject: [usb] removing bus with an open file causes an oops Message-id: 20080820144007.65cbd065.zaitcev@redhat.com O-Subject: [RHEL 5.3 patch] bz#450786 Oops in usbdev_read Bugzilla: 450786 RH-Acked-by: Rik van Riel <riel@redhat.com> Stratus found that an oops happens in usbdev_read if a USB bus is removed. Apparently, we forgot to dissociate two structures with dissimilar lifetimes: inode and usb_device. The struct usb_device disappears upon a disconnect. But an open in progress may have inode referenced already and so it does not disappear when we drop the reference a dentry had for it. Notice that usbfs_mutex provides the exclusion, so the zeroing of i_private by itself does not race other CPU. It was plainly forgotten. This fix is not yet upstream. I consulted with Al Viro about the issue and he says that although the i_private=NULL is correct, a better solution would be to pin the struct usb_device (the embedded struct device really) from usbfs. This is more involved than I would like for RHEL 5, in fact I haven't wrote the code for it yet. It needs things like: <viro> f) that open() loses checks for ->...dentry->d_inode - just check the state <viro> now, we need to make sure that bus count won't get screwed by races <viro> and carefully checks if simple_dir_... stuff will work with that <viro> check, even I'll get there eventually. The patch was tested to fix the problem by Stratus. Please ack. -- Pete diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 58b4b10..ccba5bf 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -529,6 +529,7 @@ static void fs_remove_file (struct dentry *dentry) mutex_lock_nested(&parent->d_inode->i_mutex, I_MUTEX_PARENT); if (usbfs_positive(dentry)) { if (dentry->d_inode) { + dentry->d_inode->i_private = NULL; if (S_ISDIR(dentry->d_inode->i_mode)) usbfs_rmdir(parent->d_inode, dentry); else