From 266d4f40370757459f8aa063976c932d0de5e59b Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Tue, 6 Mar 2007 19:20:11 +0000 Subject: [PATCH] suspend regression: sysfs deadlock Suspend deadlocks when trying to unregister /sys/block/sr0. This comes from Oliver's commit 94bebf4d1b8e7719f0f3944c037a21cfd99a4af7 "Driver core: fix race in sysfs between sysfs_remove_file() and read()/write()". sysfs_write_file downs buffer->sem while calling flush_write_buffer, and flushing that particular write buffer entails downing buffer->sem in orphan_all_buffers, resulting in the obvious self-deadlock. Signed-off-by: Linus Torvalds --- fs/sysfs/inode.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'fs/sysfs/inode.c') diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index dd1344b007f5..ccb7d722c558 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -227,11 +227,8 @@ static inline void orphan_all_buffers(struct inode *node) mutex_lock_nested(&node->i_mutex, I_MUTEX_CHILD); if (node->i_private) { - list_for_each_entry(buf, &set->associates, associates) { - down(&buf->sem); + list_for_each_entry(buf, &set->associates, associates) buf->orphaned = 1; - up(&buf->sem); - } } mutex_unlock(&node->i_mutex); } -- cgit From e7b0d26a86943370c04d6833c6edba2a72a6e240 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 15 Mar 2007 15:51:28 -0400 Subject: [PATCH] sysfs: reinstate exclusion between method calls and attribute unregistration This patch (as869) reinstates the mutual exclusion between sysfs attribute method calls and attribute unregistration. The previously-reported deadlocks have been fixed, and this exclusion is by far the simplest way to avoid races during driver unbinding. The check for orphaned read-buffers has been moved down slightly, so that the remainder of a partially-read buffer will still be available to userspace even after the attribute has been unregistered. Signed-off-by: Alan Stern Cc: Hugh Dickins Cc: Cornelia Huck Cc: Oliver Neukum Signed-off-by: Linus Torvalds --- fs/sysfs/file.c | 10 +++++----- fs/sysfs/inode.c | 10 +++++++--- 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'fs/sysfs/inode.c') diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 1bafdf6e171c..fc4633378dc0 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -168,12 +168,12 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) ssize_t retval = 0; down(&buffer->sem); - if (buffer->orphaned) { - retval = -ENODEV; - goto out; - } if (buffer->needs_read_fill) { - if ((retval = fill_read_buffer(file->f_path.dentry,buffer))) + if (buffer->orphaned) + retval = -ENODEV; + else + retval = fill_read_buffer(file->f_path.dentry,buffer); + if (retval) goto out; } pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n", diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index ccb7d722c558..4de5c6b89918 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -222,13 +222,17 @@ const unsigned char * sysfs_get_name(struct sysfs_dirent *sd) static inline void orphan_all_buffers(struct inode *node) { - struct sysfs_buffer_collection *set = node->i_private; + struct sysfs_buffer_collection *set; struct sysfs_buffer *buf; mutex_lock_nested(&node->i_mutex, I_MUTEX_CHILD); - if (node->i_private) { - list_for_each_entry(buf, &set->associates, associates) + set = node->i_private; + if (set) { + list_for_each_entry(buf, &set->associates, associates) { + down(&buf->sem); buf->orphaned = 1; + up(&buf->sem); + } } mutex_unlock(&node->i_mutex); } -- cgit