diff options
Diffstat (limited to 'fs/ocfs2/inode.c')
| -rw-r--r-- | fs/ocfs2/inode.c | 84 | 
1 files changed, 53 insertions, 31 deletions
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 278a223aae1..af189887201 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -25,7 +25,6 @@  #include <linux/fs.h>  #include <linux/types.h> -#include <linux/slab.h>  #include <linux/highmem.h>  #include <linux/pagemap.h>  #include <linux/quotaops.h> @@ -559,6 +558,7 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb,  		handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);  		if (IS_ERR(handle)) {  			status = PTR_ERR(handle); +			handle = NULL;  			mlog_errno(status);  			goto out;  		} @@ -640,11 +640,13 @@ static int ocfs2_remove_inode(struct inode *inode,  		goto bail_unlock;  	} -	status = ocfs2_orphan_del(osb, handle, orphan_dir_inode, inode, -				  orphan_dir_bh); -	if (status < 0) { -		mlog_errno(status); -		goto bail_commit; +	if (!(OCFS2_I(inode)->ip_flags & OCFS2_INODE_SKIP_ORPHAN_DIR)) { +		status = ocfs2_orphan_del(osb, handle, orphan_dir_inode, inode, +					  orphan_dir_bh); +		if (status < 0) { +			mlog_errno(status); +			goto bail_commit; +		}  	}  	/* set the inodes dtime */ @@ -723,38 +725,39 @@ static void ocfs2_signal_wipe_completion(struct ocfs2_super *osb,  static int ocfs2_wipe_inode(struct inode *inode,  			    struct buffer_head *di_bh)  { -	int status, orphaned_slot; +	int status, orphaned_slot = -1;  	struct inode *orphan_dir_inode = NULL;  	struct buffer_head *orphan_dir_bh = NULL;  	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); -	struct ocfs2_dinode *di; +	struct ocfs2_dinode *di = (struct ocfs2_dinode *) di_bh->b_data; -	di = (struct ocfs2_dinode *) di_bh->b_data; -	orphaned_slot = le16_to_cpu(di->i_orphaned_slot); +	if (!(OCFS2_I(inode)->ip_flags & OCFS2_INODE_SKIP_ORPHAN_DIR)) { +		orphaned_slot = le16_to_cpu(di->i_orphaned_slot); -	status = ocfs2_check_orphan_recovery_state(osb, orphaned_slot); -	if (status) -		return status; +		status = ocfs2_check_orphan_recovery_state(osb, orphaned_slot); +		if (status) +			return status; -	orphan_dir_inode = ocfs2_get_system_file_inode(osb, -						       ORPHAN_DIR_SYSTEM_INODE, -						       orphaned_slot); -	if (!orphan_dir_inode) { -		status = -EEXIST; -		mlog_errno(status); -		goto bail; -	} +		orphan_dir_inode = ocfs2_get_system_file_inode(osb, +							       ORPHAN_DIR_SYSTEM_INODE, +							       orphaned_slot); +		if (!orphan_dir_inode) { +			status = -EEXIST; +			mlog_errno(status); +			goto bail; +		} -	/* Lock the orphan dir. The lock will be held for the entire -	 * delete_inode operation. We do this now to avoid races with -	 * recovery completion on other nodes. */ -	mutex_lock(&orphan_dir_inode->i_mutex); -	status = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1); -	if (status < 0) { -		mutex_unlock(&orphan_dir_inode->i_mutex); +		/* Lock the orphan dir. The lock will be held for the entire +		 * delete_inode operation. We do this now to avoid races with +		 * recovery completion on other nodes. */ +		mutex_lock(&orphan_dir_inode->i_mutex); +		status = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1); +		if (status < 0) { +			mutex_unlock(&orphan_dir_inode->i_mutex); -		mlog_errno(status); -		goto bail; +			mlog_errno(status); +			goto bail; +		}  	}  	/* we do this while holding the orphan dir lock because we @@ -795,6 +798,9 @@ static int ocfs2_wipe_inode(struct inode *inode,  		mlog_errno(status);  bail_unlock_dir: +	if (OCFS2_I(inode)->ip_flags & OCFS2_INODE_SKIP_ORPHAN_DIR) +		return status; +  	ocfs2_inode_unlock(orphan_dir_inode, 1);  	mutex_unlock(&orphan_dir_inode->i_mutex);  	brelse(orphan_dir_bh); @@ -890,7 +896,23 @@ static int ocfs2_query_inode_wipe(struct inode *inode,  	/* Do some basic inode verification... */  	di = (struct ocfs2_dinode *) di_bh->b_data; -	if (!(di->i_flags & cpu_to_le32(OCFS2_ORPHANED_FL))) { +	if (!(di->i_flags & cpu_to_le32(OCFS2_ORPHANED_FL)) && +	    !(oi->ip_flags & OCFS2_INODE_SKIP_ORPHAN_DIR)) { +		/* +		 * Inodes in the orphan dir must have ORPHANED_FL.  The only +		 * inodes that come back out of the orphan dir are reflink +		 * targets. A reflink target may be moved out of the orphan +		 * dir between the time we scan the directory and the time we +		 * process it. This would lead to HAS_REFCOUNT_FL being set but +		 * ORPHANED_FL not. +		 */ +		if (di->i_dyn_features & cpu_to_le16(OCFS2_HAS_REFCOUNT_FL)) { +			mlog(0, "Reflinked inode %llu is no longer orphaned.  " +			     "it shouldn't be deleted\n", +			     (unsigned long long)oi->ip_blkno); +			goto bail; +		} +  		/* for lack of a better error? */  		status = -EEXIST;  		mlog(ML_ERROR,  |