Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jlbec...
[safe/jmp/linux-2.6] / fs / ocfs2 / inode.c
index 9a17251..abb0a95 100644 (file)
@@ -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>
@@ -562,6 +561,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;
                }
@@ -637,11 +637,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 */
@@ -715,38 +717,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
@@ -787,6 +790,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);
@@ -882,7 +888,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,