diff options
author | Tristan Ye <tristan.ye@oracle.com> | 2010-03-18 21:21:10 -0400 |
---|---|---|
committer | Joel Becker <joel.becker@oracle.com> | 2010-03-23 21:22:55 -0400 |
commit | b54c2ca475fa7d7450a45b6d778dae9dbe0bcbfe (patch) | |
tree | a67f530a3f426d756a0383f8dc11b5928810d0f5 /fs | |
parent | 3939fda4b389993caf8741df5739b3e49f33a263 (diff) |
Ocfs2: Handle deletion of reflinked oprhan inodes correctly.
The rule is that all inodes in the orphan dir have ORPHANED_FL,
otherwise we treated it as an ERROR. This rule works well except
for some rare cases of reflink operation:
http://oss.oracle.com/bugzilla/show_bug.cgi?id=1215
The problem is caused by how reflink and our orphan_scan thread
interact.
* The orphan scan pulls the orphans into a queue first, then runs the
queue at a later time. We only hold the orphan_dir's lock
during scanning.
* Reflink create a oprhaned target in orphan_dir as its first step.
It removes the target and clears the flag as the final step.
These two steps take the orphan_dir's lock, but it is not held for
the duration.
Based on the above semantics, a reflink inode can be moved out of the
orphan dir and have its ORPHANED_FL cleared before the queue of orphans
is run. This leads to a ERROR in ocfs2_query_wipde_inode().
This patch teaches ocfs2_query_wipe_inode() to detect previously
orphaned reflink targets. If a reflink fails or a crash occurs during
the relfink operation, the inode will retain ORPHANED_FL and will be
properly wiped.
Signed-off-by: Tristan Ye <tristan.ye@oracle.com>
Signed-off-by: Joel Becker <joel.becker@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/inode.c | 15 |
1 files changed, 15 insertions, 0 deletions
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 278a223aae14..ab207901d32a 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c | |||
@@ -891,6 +891,21 @@ static int ocfs2_query_inode_wipe(struct inode *inode, | |||
891 | /* Do some basic inode verification... */ | 891 | /* Do some basic inode verification... */ |
892 | di = (struct ocfs2_dinode *) di_bh->b_data; | 892 | di = (struct ocfs2_dinode *) di_bh->b_data; |
893 | if (!(di->i_flags & cpu_to_le32(OCFS2_ORPHANED_FL))) { | 893 | if (!(di->i_flags & cpu_to_le32(OCFS2_ORPHANED_FL))) { |
894 | /* | ||
895 | * Inodes in the orphan dir must have ORPHANED_FL. The only | ||
896 | * inodes that come back out of the orphan dir are reflink | ||
897 | * targets. A reflink target may be moved out of the orphan | ||
898 | * dir between the time we scan the directory and the time we | ||
899 | * process it. This would lead to HAS_REFCOUNT_FL being set but | ||
900 | * ORPHANED_FL not. | ||
901 | */ | ||
902 | if (di->i_dyn_features & cpu_to_le16(OCFS2_HAS_REFCOUNT_FL)) { | ||
903 | mlog(0, "Reflinked inode %llu is no longer orphaned. " | ||
904 | "it shouldn't be deleted\n", | ||
905 | (unsigned long long)oi->ip_blkno); | ||
906 | goto bail; | ||
907 | } | ||
908 | |||
894 | /* for lack of a better error? */ | 909 | /* for lack of a better error? */ |
895 | status = -EEXIST; | 910 | status = -EEXIST; |
896 | mlog(ML_ERROR, | 911 | mlog(ML_ERROR, |