Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jlbec...
[safe/jmp/linux-2.6] / fs / ocfs2 / namei.c
index 8601f93..db5dd3e 100644 (file)
@@ -69,7 +69,6 @@
 static int ocfs2_mknod_locked(struct ocfs2_super *osb,
                              struct inode *dir,
                              struct inode *inode,
-                             struct dentry *dentry,
                              dev_t dev,
                              struct buffer_head **new_fe_bh,
                              struct buffer_head *parent_fe_bh,
@@ -78,14 +77,14 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
 
 static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
                                    struct inode **ret_orphan_dir,
-                                   struct inode *inode,
+                                   u64 blkno,
                                    char *name,
                                    struct ocfs2_dir_lookup_result *lookup);
 
 static int ocfs2_orphan_add(struct ocfs2_super *osb,
                            handle_t *handle,
                            struct inode *inode,
-                           struct ocfs2_dinode *fe,
+                           struct buffer_head *fe_bh,
                            char *name,
                            struct ocfs2_dir_lookup_result *lookup,
                            struct inode *orphan_dir_inode);
@@ -213,7 +212,7 @@ static struct inode *ocfs2_get_init_inode(struct inode *dir, int mode)
        } else
                inode->i_gid = current_fsgid();
        inode->i_mode = mode;
-       vfs_dq_init(inode);
+       dquot_initialize(inode);
        return inode;
 }
 
@@ -240,11 +239,15 @@ static int ocfs2_mknod(struct inode *dir,
        };
        int did_quota_inode = 0;
        struct ocfs2_dir_lookup_result lookup = { NULL, };
+       sigset_t oldset;
+       int did_block_signals = 0;
 
        mlog_entry("(0x%p, 0x%p, %d, %lu, '%.*s')\n", dir, dentry, mode,
                   (unsigned long)dev, dentry->d_name.len,
                   dentry->d_name.name);
 
+       dquot_initialize(dir);
+
        /* get our super block */
        osb = OCFS2_SB(dir->i_sb);
 
@@ -349,17 +352,21 @@ static int ocfs2_mknod(struct inode *dir,
                goto leave;
        }
 
-       /* We don't use standard VFS wrapper because we don't want vfs_dq_init
-        * to be called. */
-       if (sb_any_quota_active(osb->sb) &&
-           osb->sb->dq_op->alloc_inode(inode, 1) == NO_QUOTA) {
-               status = -EDQUOT;
+       /* Starting to change things, restart is no longer possible. */
+       ocfs2_block_signals(&oldset);
+       did_block_signals = 1;
+
+       status = dquot_alloc_inode(inode);
+       if (status)
                goto leave;
-       }
        did_quota_inode = 1;
 
+       mlog_entry("(0x%p, 0x%p, %d, %lu, '%.*s')\n", dir, dentry,
+                  inode->i_mode, (unsigned long)dev, dentry->d_name.len,
+                  dentry->d_name.name);
+
        /* do the real work now. */
-       status = ocfs2_mknod_locked(osb, dir, inode, dentry, dev,
+       status = ocfs2_mknod_locked(osb, dir, inode, dev,
                                    &new_fe_bh, parent_fe_bh, handle,
                                    inode_ac);
        if (status < 0) {
@@ -375,18 +382,15 @@ static int ocfs2_mknod(struct inode *dir,
                        goto leave;
                }
 
-               status = ocfs2_journal_access_di(handle, dir, parent_fe_bh,
+               status = ocfs2_journal_access_di(handle, INODE_CACHE(dir),
+                                                parent_fe_bh,
                                                 OCFS2_JOURNAL_ACCESS_WRITE);
                if (status < 0) {
                        mlog_errno(status);
                        goto leave;
                }
                ocfs2_add_links_count(dirfe, 1);
-               status = ocfs2_journal_dirty(handle, parent_fe_bh);
-               if (status < 0) {
-                       mlog_errno(status);
-                       goto leave;
-               }
+               ocfs2_journal_dirty(handle, parent_fe_bh);
                inc_nlink(dir);
        }
 
@@ -406,32 +410,39 @@ static int ocfs2_mknod(struct inode *dir,
                }
        }
 
-       status = ocfs2_add_entry(handle, dentry, inode,
-                                OCFS2_I(inode)->ip_blkno, parent_fe_bh,
-                                &lookup);
-       if (status < 0) {
+       /*
+        * Do this before adding the entry to the directory. We add
+        * also set d_op after success so that ->d_iput() will cleanup
+        * the dentry lock even if ocfs2_add_entry() fails below.
+        */
+       status = ocfs2_dentry_attach_lock(dentry, inode,
+                                         OCFS2_I(dir)->ip_blkno);
+       if (status) {
                mlog_errno(status);
                goto leave;
        }
+       dentry->d_op = &ocfs2_dentry_ops;
 
-       status = ocfs2_dentry_attach_lock(dentry, inode,
-                                         OCFS2_I(dir)->ip_blkno);
-       if (status) {
+       status = ocfs2_add_entry(handle, dentry, inode,
+                                OCFS2_I(inode)->ip_blkno, parent_fe_bh,
+                                &lookup);
+       if (status < 0) {
                mlog_errno(status);
                goto leave;
        }
 
        insert_inode_hash(inode);
-       dentry->d_op = &ocfs2_dentry_ops;
        d_instantiate(dentry, inode);
        status = 0;
 leave:
        if (status < 0 && did_quota_inode)
-               vfs_dq_free_inode(inode);
+               dquot_free_inode(inode);
        if (handle)
                ocfs2_commit_trans(osb, handle);
 
        ocfs2_inode_unlock(dir, 1);
+       if (did_block_signals)
+               ocfs2_unblock_signals(&oldset);
 
        if (status == -ENOSPC)
                mlog(0, "Disk is full\n");
@@ -443,11 +454,6 @@ leave:
 
        ocfs2_free_dir_lookup_result(&lookup);
 
-       if ((status < 0) && inode) {
-               clear_nlink(inode);
-               iput(inode);
-       }
-
        if (inode_ac)
                ocfs2_free_alloc_context(inode_ac);
 
@@ -457,6 +463,17 @@ leave:
        if (meta_ac)
                ocfs2_free_alloc_context(meta_ac);
 
+       /*
+        * We should call iput after the i_mutex of the bitmap been
+        * unlocked in ocfs2_free_alloc_context, or the
+        * ocfs2_delete_inode will mutex_lock again.
+        */
+       if ((status < 0) && inode) {
+               OCFS2_I(inode)->ip_flags |= OCFS2_INODE_SKIP_ORPHAN_DIR;
+               clear_nlink(inode);
+               iput(inode);
+       }
+
        mlog_exit(status);
 
        return status;
@@ -465,7 +482,6 @@ leave:
 static int ocfs2_mknod_locked(struct ocfs2_super *osb,
                              struct inode *dir,
                              struct inode *inode,
-                             struct dentry *dentry,
                              dev_t dev,
                              struct buffer_head **new_fe_bh,
                              struct buffer_head *parent_fe_bh,
@@ -475,18 +491,15 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
        int status = 0;
        struct ocfs2_dinode *fe = NULL;
        struct ocfs2_extent_list *fel;
-       u64 fe_blkno = 0;
+       u64 suballoc_loc, fe_blkno = 0;
        u16 suballoc_bit;
        u16 feat;
 
-       mlog_entry("(0x%p, 0x%p, %d, %lu, '%.*s')\n", dir, dentry,
-                  inode->i_mode, (unsigned long)dev, dentry->d_name.len,
-                  dentry->d_name.name);
-
        *new_fe_bh = NULL;
 
-       status = ocfs2_claim_new_inode(osb, handle, dir, parent_fe_bh,
-                                      inode_ac, &suballoc_bit, &fe_blkno);
+       status = ocfs2_claim_new_inode(handle, dir, parent_fe_bh,
+                                      inode_ac, &suballoc_loc,
+                                      &suballoc_bit, &fe_blkno);
        if (status < 0) {
                mlog_errno(status);
                goto leave;
@@ -507,9 +520,10 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
                mlog_errno(status);
                goto leave;
        }
-       ocfs2_set_new_buffer_uptodate(inode, *new_fe_bh);
+       ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode), *new_fe_bh);
 
-       status = ocfs2_journal_access_di(handle, inode, *new_fe_bh,
+       status = ocfs2_journal_access_di(handle, INODE_CACHE(inode),
+                                        *new_fe_bh,
                                         OCFS2_JOURNAL_ACCESS_CREATE);
        if (status < 0) {
                mlog_errno(status);
@@ -522,6 +536,7 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
        fe->i_generation = cpu_to_le32(inode->i_generation);
        fe->i_fs_generation = cpu_to_le32(osb->fs_generation);
        fe->i_blkno = cpu_to_le64(fe_blkno);
+       fe->i_suballoc_loc = cpu_to_le64(suballoc_loc);
        fe->i_suballoc_bit = cpu_to_le16(suballoc_bit);
        fe->i_suballoc_slot = cpu_to_le16(inode_ac->ac_alloc_slot);
        fe->i_uid = cpu_to_le32(inode->i_uid);
@@ -558,14 +573,10 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
                fel->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(osb->sb));
        }
 
-       status = ocfs2_journal_dirty(handle, *new_fe_bh);
-       if (status < 0) {
-               mlog_errno(status);
-               goto leave;
-       }
+       ocfs2_journal_dirty(handle, *new_fe_bh);
 
        ocfs2_populate_inode(inode, fe, 1);
-       ocfs2_inode_set_new(osb, inode);
+       ocfs2_ci_set_new(osb, INODE_CACHE(inode));
        if (!ocfs2_mount_local(osb)) {
                status = ocfs2_create_new_inode_locks(inode);
                if (status < 0)
@@ -628,6 +639,7 @@ static int ocfs2_link(struct dentry *old_dentry,
        struct ocfs2_dinode *fe = NULL;
        struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
        struct ocfs2_dir_lookup_result lookup = { NULL, };
+       sigset_t oldset;
 
        mlog_entry("(inode=%lu, old='%.*s' new='%.*s')\n", inode->i_ino,
                   old_dentry->d_name.len, old_dentry->d_name.name,
@@ -636,6 +648,8 @@ static int ocfs2_link(struct dentry *old_dentry,
        if (S_ISDIR(inode->i_mode))
                return -EPERM;
 
+       dquot_initialize(dir);
+
        err = ocfs2_inode_lock_nested(dir, &parent_fe_bh, 1, OI_LS_PARENT);
        if (err < 0) {
                if (err != -ENOENT)
@@ -682,7 +696,10 @@ static int ocfs2_link(struct dentry *old_dentry,
                goto out_unlock_inode;
        }
 
-       err = ocfs2_journal_access_di(handle, inode, fe_bh,
+       /* Starting to change things, restart is no longer possible. */
+       ocfs2_block_signals(&oldset);
+
+       err = ocfs2_journal_access_di(handle, INODE_CACHE(inode), fe_bh,
                                      OCFS2_JOURNAL_ACCESS_WRITE);
        if (err < 0) {
                mlog_errno(err);
@@ -694,14 +711,7 @@ static int ocfs2_link(struct dentry *old_dentry,
        ocfs2_set_links_count(fe, inode->i_nlink);
        fe->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
        fe->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
-
-       err = ocfs2_journal_dirty(handle, fe_bh);
-       if (err < 0) {
-               ocfs2_add_links_count(fe, -1);
-               drop_nlink(inode);
-               mlog_errno(err);
-               goto out_commit;
-       }
+       ocfs2_journal_dirty(handle, fe_bh);
 
        err = ocfs2_add_entry(handle, dentry, inode,
                              OCFS2_I(inode)->ip_blkno,
@@ -725,6 +735,7 @@ static int ocfs2_link(struct dentry *old_dentry,
 
 out_commit:
        ocfs2_commit_trans(osb, handle);
+       ocfs2_unblock_signals(&oldset);
 out_unlock_inode:
        ocfs2_inode_unlock(inode, 1);
 
@@ -791,6 +802,8 @@ static int ocfs2_unlink(struct inode *dir,
        mlog_entry("(0x%p, 0x%p, '%.*s')\n", dir, dentry,
                   dentry->d_name.len, dentry->d_name.name);
 
+       dquot_initialize(dir);
+
        BUG_ON(dentry->d_parent->d_inode != dir);
 
        mlog(0, "ino = %llu\n", (unsigned long long)OCFS2_I(inode)->ip_blkno);
@@ -850,7 +863,8 @@ static int ocfs2_unlink(struct inode *dir,
        }
 
        if (inode_is_unlinkable(inode)) {
-               status = ocfs2_prepare_orphan_dir(osb, &orphan_dir, inode,
+               status = ocfs2_prepare_orphan_dir(osb, &orphan_dir,
+                                                 OCFS2_I(inode)->ip_blkno,
                                                  orphan_name, &orphan_insert);
                if (status < 0) {
                        mlog_errno(status);
@@ -866,7 +880,7 @@ static int ocfs2_unlink(struct inode *dir,
                goto leave;
        }
 
-       status = ocfs2_journal_access_di(handle, inode, fe_bh,
+       status = ocfs2_journal_access_di(handle, INODE_CACHE(inode), fe_bh,
                                         OCFS2_JOURNAL_ACCESS_WRITE);
        if (status < 0) {
                mlog_errno(status);
@@ -876,7 +890,7 @@ static int ocfs2_unlink(struct inode *dir,
        fe = (struct ocfs2_dinode *) fe_bh->b_data;
 
        if (inode_is_unlinkable(inode)) {
-               status = ocfs2_orphan_add(osb, handle, inode, fe, orphan_name,
+               status = ocfs2_orphan_add(osb, handle, inode, fe_bh, orphan_name,
                                          &orphan_insert, orphan_dir);
                if (status < 0) {
                        mlog_errno(status);
@@ -895,12 +909,7 @@ static int ocfs2_unlink(struct inode *dir,
                drop_nlink(inode);
        drop_nlink(inode);
        ocfs2_set_links_count(fe, inode->i_nlink);
-
-       status = ocfs2_journal_dirty(handle, fe_bh);
-       if (status < 0) {
-               mlog_errno(status);
-               goto leave;
-       }
+       ocfs2_journal_dirty(handle, fe_bh);
 
        dir->i_ctime = dir->i_mtime = CURRENT_TIME;
        if (S_ISDIR(inode->i_mode))
@@ -1050,6 +1059,9 @@ static int ocfs2_rename(struct inode *old_dir,
                   old_dentry->d_name.len, old_dentry->d_name.name,
                   new_dentry->d_name.len, new_dentry->d_name.name);
 
+       dquot_initialize(old_dir);
+       dquot_initialize(new_dir);
+
        osb = OCFS2_SB(old_dir->i_sb);
 
        if (new_inode) {
@@ -1241,9 +1253,8 @@ static int ocfs2_rename(struct inode *old_dir,
 
                if (S_ISDIR(new_inode->i_mode) || (new_inode->i_nlink == 1)) {
                        status = ocfs2_prepare_orphan_dir(osb, &orphan_dir,
-                                                         new_inode,
-                                                         orphan_name,
-                                                         &orphan_insert);
+                                               OCFS2_I(new_inode)->ip_blkno,
+                                               orphan_name, &orphan_insert);
                        if (status < 0) {
                                mlog_errno(status);
                                goto bail;
@@ -1284,7 +1295,8 @@ static int ocfs2_rename(struct inode *old_dir,
                                goto bail;
                        }
                }
-               status = ocfs2_journal_access_di(handle, new_inode, newfe_bh,
+               status = ocfs2_journal_access_di(handle, INODE_CACHE(new_inode),
+                                                newfe_bh,
                                                 OCFS2_JOURNAL_ACCESS_WRITE);
                if (status < 0) {
                        mlog_errno(status);
@@ -1294,7 +1306,7 @@ static int ocfs2_rename(struct inode *old_dir,
                if (S_ISDIR(new_inode->i_mode) ||
                    (ocfs2_read_links_count(newfe) == 1)) {
                        status = ocfs2_orphan_add(osb, handle, new_inode,
-                                                 newfe, orphan_name,
+                                                 newfe_bh, orphan_name,
                                                  &orphan_insert, orphan_dir);
                        if (status < 0) {
                                mlog_errno(status);
@@ -1315,12 +1327,7 @@ static int ocfs2_rename(struct inode *old_dir,
                        ocfs2_set_links_count(newfe, 0);
                else
                        ocfs2_add_links_count(newfe, -1);
-
-               status = ocfs2_journal_dirty(handle, newfe_bh);
-               if (status < 0) {
-                       mlog_errno(status);
-                       goto bail;
-               }
+               ocfs2_journal_dirty(handle, newfe_bh);
        } else {
                /* if the name was not found in new_dir, add it now */
                status = ocfs2_add_entry(handle, new_dentry, old_inode,
@@ -1331,17 +1338,15 @@ static int ocfs2_rename(struct inode *old_dir,
        old_inode->i_ctime = CURRENT_TIME;
        mark_inode_dirty(old_inode);
 
-       status = ocfs2_journal_access_di(handle, old_inode, old_inode_bh,
+       status = ocfs2_journal_access_di(handle, INODE_CACHE(old_inode),
+                                        old_inode_bh,
                                         OCFS2_JOURNAL_ACCESS_WRITE);
        if (status >= 0) {
                old_di = (struct ocfs2_dinode *) old_inode_bh->b_data;
 
                old_di->i_ctime = cpu_to_le64(old_inode->i_ctime.tv_sec);
                old_di->i_ctime_nsec = cpu_to_le32(old_inode->i_ctime.tv_nsec);
-
-               status = ocfs2_journal_dirty(handle, old_inode_bh);
-               if (status < 0)
-                       mlog_errno(status);
+               ocfs2_journal_dirty(handle, old_inode_bh);
        } else
                mlog_errno(status);
 
@@ -1407,12 +1412,13 @@ static int ocfs2_rename(struct inode *old_dir,
                             (int)old_dir_nlink, old_dir->i_nlink);
                } else {
                        struct ocfs2_dinode *fe;
-                       status = ocfs2_journal_access_di(handle, old_dir,
-                                                     old_dir_bh,
-                                                     OCFS2_JOURNAL_ACCESS_WRITE);
+                       status = ocfs2_journal_access_di(handle,
+                                                        INODE_CACHE(old_dir),
+                                                        old_dir_bh,
+                                                        OCFS2_JOURNAL_ACCESS_WRITE);
                        fe = (struct ocfs2_dinode *) old_dir_bh->b_data;
                        ocfs2_set_links_count(fe, old_dir->i_nlink);
-                       status = ocfs2_journal_dirty(handle, old_dir_bh);
+                       ocfs2_journal_dirty(handle, old_dir_bh);
                }
        }
        ocfs2_dentry_move(old_dentry, new_dentry, old_dir, new_dir);
@@ -1527,9 +1533,11 @@ static int ocfs2_create_symlink_data(struct ocfs2_super *osb,
                        mlog_errno(status);
                        goto bail;
                }
-               ocfs2_set_new_buffer_uptodate(inode, bhs[virtual]);
+               ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode),
+                                             bhs[virtual]);
 
-               status = ocfs2_journal_access(handle, inode, bhs[virtual],
+               status = ocfs2_journal_access(handle, INODE_CACHE(inode),
+                                             bhs[virtual],
                                              OCFS2_JOURNAL_ACCESS_CREATE);
                if (status < 0) {
                        mlog_errno(status);
@@ -1542,11 +1550,7 @@ static int ocfs2_create_symlink_data(struct ocfs2_super *osb,
                       (bytes_left > sb->s_blocksize) ? sb->s_blocksize :
                       bytes_left);
 
-               status = ocfs2_journal_dirty(handle, bhs[virtual]);
-               if (status < 0) {
-                       mlog_errno(status);
-                       goto bail;
-               }
+               ocfs2_journal_dirty(handle, bhs[virtual]);
 
                virtual++;
                p_blkno++;
@@ -1590,10 +1594,14 @@ static int ocfs2_symlink(struct inode *dir,
        };
        int did_quota = 0, did_quota_inode = 0;
        struct ocfs2_dir_lookup_result lookup = { NULL, };
+       sigset_t oldset;
+       int did_block_signals = 0;
 
        mlog_entry("(0x%p, 0x%p, symname='%s' actual='%.*s')\n", dir,
                   dentry, symname, dentry->d_name.len, dentry->d_name.name);
 
+       dquot_initialize(dir);
+
        sb = dir->i_sb;
        osb = OCFS2_SB(sb);
 
@@ -1683,16 +1691,20 @@ static int ocfs2_symlink(struct inode *dir,
                goto bail;
        }
 
-       /* We don't use standard VFS wrapper because we don't want vfs_dq_init
-        * to be called. */
-       if (sb_any_quota_active(osb->sb) &&
-           osb->sb->dq_op->alloc_inode(inode, 1) == NO_QUOTA) {
-               status = -EDQUOT;
+       /* Starting to change things, restart is no longer possible. */
+       ocfs2_block_signals(&oldset);
+       did_block_signals = 1;
+
+       status = dquot_alloc_inode(inode);
+       if (status)
                goto bail;
-       }
        did_quota_inode = 1;
 
-       status = ocfs2_mknod_locked(osb, dir, inode, dentry,
+       mlog_entry("(0x%p, 0x%p, %d, '%.*s')\n", dir, dentry,
+                  inode->i_mode, dentry->d_name.len,
+                  dentry->d_name.name);
+
+       status = ocfs2_mknod_locked(osb, dir, inode,
                                    0, &new_fe_bh, parent_fe_bh, handle,
                                    inode_ac);
        if (status < 0) {
@@ -1707,11 +1719,10 @@ static int ocfs2_symlink(struct inode *dir,
                u32 offset = 0;
 
                inode->i_op = &ocfs2_symlink_inode_operations;
-               if (vfs_dq_alloc_space_nodirty(inode,
-                   ocfs2_clusters_to_bytes(osb->sb, 1))) {
-                       status = -EDQUOT;
+               status = dquot_alloc_space_nodirty(inode,
+                   ocfs2_clusters_to_bytes(osb->sb, 1));
+               if (status)
                        goto bail;
-               }
                did_quota = 1;
                status = ocfs2_add_inode_data(osb, inode, &offset, 1, 0,
                                              new_fe_bh,
@@ -1760,33 +1771,40 @@ static int ocfs2_symlink(struct inode *dir,
                }
        }
 
-       status = ocfs2_add_entry(handle, dentry, inode,
-                                le64_to_cpu(fe->i_blkno), parent_fe_bh,
-                                &lookup);
-       if (status < 0) {
+       /*
+        * Do this before adding the entry to the directory. We add
+        * also set d_op after success so that ->d_iput() will cleanup
+        * the dentry lock even if ocfs2_add_entry() fails below.
+        */
+       status = ocfs2_dentry_attach_lock(dentry, inode, OCFS2_I(dir)->ip_blkno);
+       if (status) {
                mlog_errno(status);
                goto bail;
        }
+       dentry->d_op = &ocfs2_dentry_ops;
 
-       status = ocfs2_dentry_attach_lock(dentry, inode, OCFS2_I(dir)->ip_blkno);
-       if (status) {
+       status = ocfs2_add_entry(handle, dentry, inode,
+                                le64_to_cpu(fe->i_blkno), parent_fe_bh,
+                                &lookup);
+       if (status < 0) {
                mlog_errno(status);
                goto bail;
        }
 
        insert_inode_hash(inode);
-       dentry->d_op = &ocfs2_dentry_ops;
        d_instantiate(dentry, inode);
 bail:
        if (status < 0 && did_quota)
-               vfs_dq_free_space_nodirty(inode,
+               dquot_free_space_nodirty(inode,
                                        ocfs2_clusters_to_bytes(osb->sb, 1));
        if (status < 0 && did_quota_inode)
-               vfs_dq_free_inode(inode);
+               dquot_free_inode(inode);
        if (handle)
                ocfs2_commit_trans(osb, handle);
 
        ocfs2_inode_unlock(dir, 1);
+       if (did_block_signals)
+               ocfs2_unblock_signals(&oldset);
 
        brelse(new_fe_bh);
        brelse(parent_fe_bh);
@@ -1800,6 +1818,7 @@ bail:
        if (xattr_ac)
                ocfs2_free_alloc_context(xattr_ac);
        if ((status < 0) && inode) {
+               OCFS2_I(inode)->ip_flags |= OCFS2_INODE_SKIP_ORPHAN_DIR;
                clear_nlink(inode);
                iput(inode);
        }
@@ -1842,7 +1861,7 @@ bail:
 
 static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
                                    struct inode **ret_orphan_dir,
-                                   struct inode *inode,
+                                   u64 blkno,
                                    char *name,
                                    struct ocfs2_dir_lookup_result *lookup)
 {
@@ -1850,7 +1869,7 @@ static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
        struct buffer_head *orphan_dir_bh = NULL;
        int status = 0;
 
-       status = ocfs2_blkno_stringify(OCFS2_I(inode)->ip_blkno, name);
+       status = ocfs2_blkno_stringify(blkno, name);
        if (status < 0) {
                mlog_errno(status);
                return status;
@@ -1900,7 +1919,7 @@ leave:
 static int ocfs2_orphan_add(struct ocfs2_super *osb,
                            handle_t *handle,
                            struct inode *inode,
-                           struct ocfs2_dinode *fe,
+                           struct buffer_head *fe_bh,
                            char *name,
                            struct ocfs2_dir_lookup_result *lookup,
                            struct inode *orphan_dir_inode)
@@ -1908,6 +1927,7 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb,
        struct buffer_head *orphan_dir_bh = NULL;
        int status = 0;
        struct ocfs2_dinode *orphan_fe;
+       struct ocfs2_dinode *fe = (struct ocfs2_dinode *) fe_bh->b_data;
 
        mlog_entry("(inode->i_ino = %lu)\n", inode->i_ino);
 
@@ -1917,7 +1937,9 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb,
                goto leave;
        }
 
-       status = ocfs2_journal_access_di(handle, orphan_dir_inode, orphan_dir_bh,
+       status = ocfs2_journal_access_di(handle,
+                                        INODE_CACHE(orphan_dir_inode),
+                                        orphan_dir_bh,
                                         OCFS2_JOURNAL_ACCESS_WRITE);
        if (status < 0) {
                mlog_errno(status);
@@ -1930,29 +1952,42 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb,
        if (S_ISDIR(inode->i_mode))
                ocfs2_add_links_count(orphan_fe, 1);
        orphan_dir_inode->i_nlink = ocfs2_read_links_count(orphan_fe);
+       ocfs2_journal_dirty(handle, orphan_dir_bh);
 
-       status = ocfs2_journal_dirty(handle, orphan_dir_bh);
+       status = __ocfs2_add_entry(handle, orphan_dir_inode, name,
+                                  OCFS2_ORPHAN_NAMELEN, inode,
+                                  OCFS2_I(inode)->ip_blkno,
+                                  orphan_dir_bh, lookup);
        if (status < 0) {
                mlog_errno(status);
                goto leave;
        }
 
-       status = __ocfs2_add_entry(handle, orphan_dir_inode, name,
-                                  OCFS2_ORPHAN_NAMELEN, inode,
-                                  OCFS2_I(inode)->ip_blkno,
-                                  orphan_dir_bh, lookup);
+       /*
+        * We're going to journal the change of i_flags and i_orphaned_slot.
+        * It's safe anyway, though some callers may duplicate the journaling.
+        * Journaling within the func just make the logic look more
+        * straightforward.
+        */
+       status = ocfs2_journal_access_di(handle,
+                                        INODE_CACHE(inode),
+                                        fe_bh,
+                                        OCFS2_JOURNAL_ACCESS_WRITE);
        if (status < 0) {
                mlog_errno(status);
                goto leave;
        }
 
        le32_add_cpu(&fe->i_flags, OCFS2_ORPHANED_FL);
+       OCFS2_I(inode)->ip_flags &= ~OCFS2_INODE_SKIP_ORPHAN_DIR;
 
        /* Record which orphan dir our inode now resides
         * in. delete_inode will use this to determine which orphan
         * dir to lock. */
        fe->i_orphaned_slot = cpu_to_le16(osb->slot_num);
 
+       ocfs2_journal_dirty(handle, fe_bh);
+
        mlog(0, "Inode %llu orphaned in slot %d\n",
             (unsigned long long)OCFS2_I(inode)->ip_blkno, osb->slot_num);
 
@@ -2002,7 +2037,9 @@ int ocfs2_orphan_del(struct ocfs2_super *osb,
                goto leave;
        }
 
-       status = ocfs2_journal_access_di(handle,orphan_dir_inode,  orphan_dir_bh,
+       status = ocfs2_journal_access_di(handle,
+                                        INODE_CACHE(orphan_dir_inode),
+                                        orphan_dir_bh,
                                         OCFS2_JOURNAL_ACCESS_WRITE);
        if (status < 0) {
                mlog_errno(status);
@@ -2014,17 +2051,279 @@ int ocfs2_orphan_del(struct ocfs2_super *osb,
        if (S_ISDIR(inode->i_mode))
                ocfs2_add_links_count(orphan_fe, -1);
        orphan_dir_inode->i_nlink = ocfs2_read_links_count(orphan_fe);
+       ocfs2_journal_dirty(handle, orphan_dir_bh);
 
-       status = ocfs2_journal_dirty(handle, orphan_dir_bh);
+leave:
+       ocfs2_free_dir_lookup_result(&lookup);
+
+       mlog_exit(status);
+       return status;
+}
+
+int ocfs2_create_inode_in_orphan(struct inode *dir,
+                                int mode,
+                                struct inode **new_inode)
+{
+       int status, did_quota_inode = 0;
+       struct inode *inode = NULL;
+       struct inode *orphan_dir = NULL;
+       struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
+       struct ocfs2_dinode *di = NULL;
+       handle_t *handle = NULL;
+       char orphan_name[OCFS2_ORPHAN_NAMELEN + 1];
+       struct buffer_head *parent_di_bh = NULL;
+       struct buffer_head *new_di_bh = NULL;
+       struct ocfs2_alloc_context *inode_ac = NULL;
+       struct ocfs2_dir_lookup_result orphan_insert = { NULL, };
+
+       status = ocfs2_inode_lock(dir, &parent_di_bh, 1);
+       if (status < 0) {
+               if (status != -ENOENT)
+                       mlog_errno(status);
+               return status;
+       }
+
+       /*
+        * We give the orphan dir the root blkno to fake an orphan name,
+        * and allocate enough space for our insertion.
+        */
+       status = ocfs2_prepare_orphan_dir(osb, &orphan_dir,
+                                         osb->root_blkno,
+                                         orphan_name, &orphan_insert);
        if (status < 0) {
                mlog_errno(status);
                goto leave;
        }
 
+       /* reserve an inode spot */
+       status = ocfs2_reserve_new_inode(osb, &inode_ac);
+       if (status < 0) {
+               if (status != -ENOSPC)
+                       mlog_errno(status);
+               goto leave;
+       }
+
+       inode = ocfs2_get_init_inode(dir, mode);
+       if (!inode) {
+               status = -ENOMEM;
+               mlog_errno(status);
+               goto leave;
+       }
+
+       handle = ocfs2_start_trans(osb, ocfs2_mknod_credits(osb->sb, 0, 0));
+       if (IS_ERR(handle)) {
+               status = PTR_ERR(handle);
+               handle = NULL;
+               mlog_errno(status);
+               goto leave;
+       }
+
+       status = dquot_alloc_inode(inode);
+       if (status)
+               goto leave;
+       did_quota_inode = 1;
+
+       inode->i_nlink = 0;
+       /* do the real work now. */
+       status = ocfs2_mknod_locked(osb, dir, inode,
+                                   0, &new_di_bh, parent_di_bh, handle,
+                                   inode_ac);
+       if (status < 0) {
+               mlog_errno(status);
+               goto leave;
+       }
+
+       status = ocfs2_blkno_stringify(OCFS2_I(inode)->ip_blkno, orphan_name);
+       if (status < 0) {
+               mlog_errno(status);
+               goto leave;
+       }
+
+       di = (struct ocfs2_dinode *)new_di_bh->b_data;
+       status = ocfs2_orphan_add(osb, handle, inode, new_di_bh, orphan_name,
+                                 &orphan_insert, orphan_dir);
+       if (status < 0) {
+               mlog_errno(status);
+               goto leave;
+       }
+
+       /* get open lock so that only nodes can't remove it from orphan dir. */
+       status = ocfs2_open_lock(inode);
+       if (status < 0)
+               mlog_errno(status);
+
+       insert_inode_hash(inode);
 leave:
+       if (status < 0 && did_quota_inode)
+               dquot_free_inode(inode);
+       if (handle)
+               ocfs2_commit_trans(osb, handle);
+
+       if (orphan_dir) {
+               /* This was locked for us in ocfs2_prepare_orphan_dir() */
+               ocfs2_inode_unlock(orphan_dir, 1);
+               mutex_unlock(&orphan_dir->i_mutex);
+               iput(orphan_dir);
+       }
+
+       if (status == -ENOSPC)
+               mlog(0, "Disk is full\n");
+
+       if ((status < 0) && inode) {
+               clear_nlink(inode);
+               iput(inode);
+       }
+
+       if (inode_ac)
+               ocfs2_free_alloc_context(inode_ac);
+
+       brelse(new_di_bh);
+
+       if (!status)
+               *new_inode = inode;
+
+       ocfs2_free_dir_lookup_result(&orphan_insert);
+
+       ocfs2_inode_unlock(dir, 1);
+       brelse(parent_di_bh);
+       return status;
+}
+
+int ocfs2_mv_orphaned_inode_to_new(struct inode *dir,
+                                  struct inode *inode,
+                                  struct dentry *dentry)
+{
+       int status = 0;
+       struct buffer_head *parent_di_bh = NULL;
+       handle_t *handle = NULL;
+       struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
+       struct ocfs2_dinode *dir_di, *di;
+       struct inode *orphan_dir_inode = NULL;
+       struct buffer_head *orphan_dir_bh = NULL;
+       struct buffer_head *di_bh = NULL;
+       struct ocfs2_dir_lookup_result lookup = { NULL, };
+
+       mlog_entry("(0x%p, 0x%p, %.*s')\n", dir, dentry,
+                  dentry->d_name.len, dentry->d_name.name);
+
+       status = ocfs2_inode_lock(dir, &parent_di_bh, 1);
+       if (status < 0) {
+               if (status != -ENOENT)
+                       mlog_errno(status);
+               return status;
+       }
+
+       dir_di = (struct ocfs2_dinode *) parent_di_bh->b_data;
+       if (!dir_di->i_links_count) {
+               /* can't make a file in a deleted directory. */
+               status = -ENOENT;
+               goto leave;
+       }
+
+       status = ocfs2_check_dir_for_entry(dir, dentry->d_name.name,
+                                          dentry->d_name.len);
+       if (status)
+               goto leave;
+
+       /* get a spot inside the dir. */
+       status = ocfs2_prepare_dir_for_insert(osb, dir, parent_di_bh,
+                                             dentry->d_name.name,
+                                             dentry->d_name.len, &lookup);
+       if (status < 0) {
+               mlog_errno(status);
+               goto leave;
+       }
+
+       orphan_dir_inode = ocfs2_get_system_file_inode(osb,
+                                                      ORPHAN_DIR_SYSTEM_INODE,
+                                                      osb->slot_num);
+       if (!orphan_dir_inode) {
+               status = -EEXIST;
+               mlog_errno(status);
+               goto leave;
+       }
+
+       mutex_lock(&orphan_dir_inode->i_mutex);
+
+       status = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1);
+       if (status < 0) {
+               mlog_errno(status);
+               mutex_unlock(&orphan_dir_inode->i_mutex);
+               iput(orphan_dir_inode);
+               goto leave;
+       }
+
+       status = ocfs2_read_inode_block(inode, &di_bh);
+       if (status < 0) {
+               mlog_errno(status);
+               goto orphan_unlock;
+       }
+
+       handle = ocfs2_start_trans(osb, ocfs2_rename_credits(osb->sb));
+       if (IS_ERR(handle)) {
+               status = PTR_ERR(handle);
+               handle = NULL;
+               mlog_errno(status);
+               goto orphan_unlock;
+       }
+
+       status = ocfs2_journal_access_di(handle, INODE_CACHE(inode),
+                                        di_bh, OCFS2_JOURNAL_ACCESS_WRITE);
+       if (status < 0) {
+               mlog_errno(status);
+               goto out_commit;
+       }
+
+       status = ocfs2_orphan_del(osb, handle, orphan_dir_inode, inode,
+                                 orphan_dir_bh);
+       if (status < 0) {
+               mlog_errno(status);
+               goto out_commit;
+       }
+
+       di = (struct ocfs2_dinode *)di_bh->b_data;
+       le32_add_cpu(&di->i_flags, -OCFS2_ORPHANED_FL);
+       di->i_orphaned_slot = 0;
+       inode->i_nlink = 1;
+       ocfs2_set_links_count(di, inode->i_nlink);
+       ocfs2_journal_dirty(handle, di_bh);
+
+       status = ocfs2_add_entry(handle, dentry, inode,
+                                OCFS2_I(inode)->ip_blkno, parent_di_bh,
+                                &lookup);
+       if (status < 0) {
+               mlog_errno(status);
+               goto out_commit;
+       }
+
+       status = ocfs2_dentry_attach_lock(dentry, inode,
+                                         OCFS2_I(dir)->ip_blkno);
+       if (status) {
+               mlog_errno(status);
+               goto out_commit;
+       }
+
+       dentry->d_op = &ocfs2_dentry_ops;
+       d_instantiate(dentry, inode);
+       status = 0;
+out_commit:
+       ocfs2_commit_trans(osb, handle);
+orphan_unlock:
+       ocfs2_inode_unlock(orphan_dir_inode, 1);
+       mutex_unlock(&orphan_dir_inode->i_mutex);
+       iput(orphan_dir_inode);
+leave:
+
+       ocfs2_inode_unlock(dir, 1);
+
+       brelse(di_bh);
+       brelse(parent_di_bh);
+       brelse(orphan_dir_bh);
+
        ocfs2_free_dir_lookup_result(&lookup);
 
        mlog_exit(status);
+
        return status;
 }
 
@@ -2045,4 +2344,5 @@ const struct inode_operations ocfs2_dir_iops = {
        .getxattr       = generic_getxattr,
        .listxattr      = ocfs2_listxattr,
        .removexattr    = generic_removexattr,
+       .fiemap         = ocfs2_fiemap,
 };