aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/mount.c
diff options
context:
space:
mode:
authorOliver Neukum <oliver@neukum.org>2006-12-20 10:52:44 +0100
committerGreg Kroah-Hartman <gregkh@suse.de>2007-02-07 10:37:13 -0800
commit94bebf4d1b8e7719f0f3944c037a21cfd99a4af7 (patch)
tree25c6ba1836e74f608b4e434b4f0f4d5c28b11de1 /fs/sysfs/mount.c
parentdriver core: Change function call order in device_bind_driver(). (diff)
downloadlinux-dev-94bebf4d1b8e7719f0f3944c037a21cfd99a4af7.tar.xz
linux-dev-94bebf4d1b8e7719f0f3944c037a21cfd99a4af7.zip
Driver core: fix race in sysfs between sysfs_remove_file() and read()/write()
This patch prevents a race between IO and removing a file from sysfs. It introduces a list of sysfs_buffers associated with a file at the inode. Upon removal of a file the list is walked and the buffers marked orphaned. IO to orphaned buffers fails with -ENODEV. The driver can safely free associated data structures or be unloaded. Signed-off-by: Oliver Neukum <oliver@neukum.name> Acked-by: Maneesh Soni <maneesh@in.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'fs/sysfs/mount.c')
-rw-r--r--fs/sysfs/mount.c9
1 files changed, 9 insertions, 0 deletions
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index e503f858fba8..a1a58b97f322 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -8,6 +8,7 @@
#include <linux/mount.h>
#include <linux/pagemap.h>
#include <linux/init.h>
+#include <asm/semaphore.h>
#include "sysfs.h"
@@ -18,9 +19,12 @@ struct vfsmount *sysfs_mount;
struct super_block * sysfs_sb = NULL;
struct kmem_cache *sysfs_dir_cachep;
+static void sysfs_clear_inode(struct inode *inode);
+
static struct super_operations sysfs_ops = {
.statfs = simple_statfs,
.drop_inode = generic_delete_inode,
+ .clear_inode = sysfs_clear_inode,
};
static struct sysfs_dirent sysfs_root = {
@@ -31,6 +35,11 @@ static struct sysfs_dirent sysfs_root = {
.s_iattr = NULL,
};
+static void sysfs_clear_inode(struct inode *inode)
+{
+ kfree(inode->i_private);
+}
+
static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *inode;