aboutsummaryrefslogtreecommitdiff
path: root/include/linux/rcupreempt.h
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2008-02-08 04:21:59 -0800
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-08 09:22:42 -0800
commit535ee2fbf79ab52d26bce3d2e127c9007503581e (patch)
tree9d7cdbd98e481ec2fb6d5ff6eebf65f4d422ec8c /include/linux/rcupreempt.h
parentf6f21c81464ce52dbeec921bdc2e8b288c491920 (diff)
buffer_head: fix private_list handling
There are two possible races in handling of private_list in buffer cache. 1) When fsync_buffers_list() processes a private_list, it clears b_assoc_mapping and moves buffer to its private list. Now drop_buffers() comes, sees a buffer is on list so it calls __remove_assoc_queue() which complains about b_assoc_mapping being cleared (as it cannot propagate possible IO error). This race has been actually observed in the wild. 2) When fsync_buffers_list() processes a private_list, mark_buffer_dirty_inode() can be called on bh which is already on the private list of fsync_buffers_list(). As buffer is on some list (note that the check is performed without private_lock), it is not readded to the mapping's private_list and after fsync_buffers_list() finishes, we have a dirty buffer which should be on private_list but it isn't. This race has not been reported, probably because most (but not all) callers of mark_buffer_dirty_inode() hold i_mutex and thus are serialized with fsync(). Fix these issues by not clearing b_assoc_map when fsync_buffers_list() moves buffer to a dedicated list and by reinserting buffer in private_list when it is found dirty after we have submitted buffer for IO. We also change the tests whether a buffer is on a private list from !list_empty(&bh->b_assoc_buffers) to bh->b_assoc_map so that they are single word reads and hence lockless checks are safe. Signed-off-by: Jan Kara <jack@suse.cz> Cc: Nick Piggin <npiggin@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include/linux/rcupreempt.h')
0 files changed, 0 insertions, 0 deletions