]> git.baikalelectronics.ru Git - kernel.git/commit
Btrfs: fix race between snapshot deletion and getting inode
authorLiu Bo <bo.li.liu@oracle.com>
Tue, 29 Jan 2013 03:22:10 +0000 (03:22 +0000)
committerJosef Bacik <jbacik@fusionio.com>
Tue, 5 Feb 2013 21:09:13 +0000 (16:09 -0500)
commit8e6e328de332706568f8e1c1790d8e7c8f02653b
treea7417741e5f6680981dc64dabaffe7d0c1a02f53
parent0d5ad3cab0a2738e59cf49a92f7533385f1bd7c7
Btrfs: fix race between snapshot deletion and getting inode

While running snapshot testscript created by Mitch and David,
the race between autodefrag and snapshot deletion can lead to
corruption of dead_root list so that we can get crash on
btrfs_clean_old_snapshots().

And besides autodefrag, scrub also does the same thing, ie. read
root first and get inode.

Here is the story(take autodefrag as an example):
(1) when we delete a snapshot or subvolume, it will set its root's
refs to zero and do a iput() on its own inode, and if this inode happens
to be the only active in-meory one in root's inode rbtree, it will add
itself to the global dead_roots list for later cleanup.

(2) after (1), the autodefrag thread may read another inode for defrag
and the inode is just in the deleted snapshot/subvolume, but all of these
are without checking if the root is still valid(refs > 0).  So the end up
result is adding the deleted snapshot/subvolume's root to the global
dead_roots list AGAIN.

Fortunately, we already have a srcu lock to avoid the race, ie. subvol_srcu.

So all we need to do is to take the lock to protect 'read root and get inode',
since we synchronize to wait for the rcu grace period before adding something
to the global dead_roots list.

Reported-by: Mitch Harder <mitch.harder@sabayonlinux.org>
Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
fs/btrfs/file.c
fs/btrfs/scrub.c