diff options
author | Oliver Neukum <oliver@neukum.org> | 2006-12-20 04:52:44 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-02-07 13:37:13 -0500 |
commit | 94bebf4d1b8e7719f0f3944c037a21cfd99a4af7 (patch) | |
tree | 25c6ba1836e74f608b4e434b4f0f4d5c28b11de1 /fs/sysfs/mount.c | |
parent | cb986b749c7178422bfbc982cd30e04d5db54bbc (diff) |
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.c | 9 |
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 @@ | |||
8 | #include <linux/mount.h> | 8 | #include <linux/mount.h> |
9 | #include <linux/pagemap.h> | 9 | #include <linux/pagemap.h> |
10 | #include <linux/init.h> | 10 | #include <linux/init.h> |
11 | #include <asm/semaphore.h> | ||
11 | 12 | ||
12 | #include "sysfs.h" | 13 | #include "sysfs.h" |
13 | 14 | ||
@@ -18,9 +19,12 @@ struct vfsmount *sysfs_mount; | |||
18 | struct super_block * sysfs_sb = NULL; | 19 | struct super_block * sysfs_sb = NULL; |
19 | struct kmem_cache *sysfs_dir_cachep; | 20 | struct kmem_cache *sysfs_dir_cachep; |
20 | 21 | ||
22 | static void sysfs_clear_inode(struct inode *inode); | ||
23 | |||
21 | static struct super_operations sysfs_ops = { | 24 | static struct super_operations sysfs_ops = { |
22 | .statfs = simple_statfs, | 25 | .statfs = simple_statfs, |
23 | .drop_inode = generic_delete_inode, | 26 | .drop_inode = generic_delete_inode, |
27 | .clear_inode = sysfs_clear_inode, | ||
24 | }; | 28 | }; |
25 | 29 | ||
26 | static struct sysfs_dirent sysfs_root = { | 30 | static struct sysfs_dirent sysfs_root = { |
@@ -31,6 +35,11 @@ static struct sysfs_dirent sysfs_root = { | |||
31 | .s_iattr = NULL, | 35 | .s_iattr = NULL, |
32 | }; | 36 | }; |
33 | 37 | ||
38 | static void sysfs_clear_inode(struct inode *inode) | ||
39 | { | ||
40 | kfree(inode->i_private); | ||
41 | } | ||
42 | |||
34 | static int sysfs_fill_super(struct super_block *sb, void *data, int silent) | 43 | static int sysfs_fill_super(struct super_block *sb, void *data, int silent) |
35 | { | 44 | { |
36 | struct inode *inode; | 45 | struct inode *inode; |