ocfs2: fix readonly issue in ocfs2_unlink()
[platform/adaptation/renesas_rcar/renesas_kernel.git] / fs / ocfs2 / namei.c
index b4a5cdf..be3f867 100644 (file)
@@ -522,7 +522,7 @@ static int __ocfs2_mknod_locked(struct inode *dir,
 
        fe->i_last_eb_blk = 0;
        strcpy(fe->i_signature, OCFS2_INODE_SIGNATURE);
-       le32_add_cpu(&fe->i_flags, OCFS2_VALID_FL);
+       fe->i_flags |= cpu_to_le32(OCFS2_VALID_FL);
        fe->i_atime = fe->i_ctime = fe->i_mtime =
                cpu_to_le64(CURRENT_TIME.tv_sec);
        fe->i_mtime_nsec = fe->i_ctime_nsec = fe->i_atime_nsec =
@@ -773,7 +773,7 @@ static int ocfs2_remote_dentry_delete(struct dentry *dentry)
        return ret;
 }
 
-static inline int inode_is_unlinkable(struct inode *inode)
+static inline int ocfs2_inode_is_unlinkable(struct inode *inode)
 {
        if (S_ISDIR(inode->i_mode)) {
                if (inode->i_nlink == 2)
@@ -791,6 +791,7 @@ static int ocfs2_unlink(struct inode *dir,
 {
        int status;
        int child_locked = 0;
+       bool is_unlinkable = false;
        struct inode *inode = dentry->d_inode;
        struct inode *orphan_dir = NULL;
        struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
@@ -865,7 +866,7 @@ static int ocfs2_unlink(struct inode *dir,
                goto leave;
        }
 
-       if (inode_is_unlinkable(inode)) {
+       if (ocfs2_inode_is_unlinkable(inode)) {
                status = ocfs2_prepare_orphan_dir(osb, &orphan_dir,
                                                  OCFS2_I(inode)->ip_blkno,
                                                  orphan_name, &orphan_insert);
@@ -873,6 +874,7 @@ static int ocfs2_unlink(struct inode *dir,
                        mlog_errno(status);
                        goto leave;
                }
+               is_unlinkable = true;
        }
 
        handle = ocfs2_start_trans(osb, ocfs2_unlink_credits(osb->sb));
@@ -892,15 +894,6 @@ 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_bh, orphan_name,
-                                         &orphan_insert, orphan_dir);
-               if (status < 0) {
-                       mlog_errno(status);
-                       goto leave;
-               }
-       }
-
        /* delete the name from the parent dir */
        status = ocfs2_delete_entry(handle, dir, &lookup);
        if (status < 0) {
@@ -923,6 +916,14 @@ static int ocfs2_unlink(struct inode *dir,
                mlog_errno(status);
                if (S_ISDIR(inode->i_mode))
                        inc_nlink(dir);
+               goto leave;
+       }
+
+       if (is_unlinkable) {
+               status = ocfs2_orphan_add(osb, handle, inode, fe_bh,
+                               orphan_name, &orphan_insert, orphan_dir);
+               if (status < 0)
+                       mlog_errno(status);
        }
 
 leave:
@@ -2012,6 +2013,21 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb,
                goto leave;
        }
 
+       /*
+        * 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;
+       }
+
        /* we're a cluster, and nlink can change on disk from
         * underneath us... */
        orphan_fe = (struct ocfs2_dinode *) orphan_dir_bh->b_data;
@@ -2026,25 +2042,10 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb,
                                   orphan_dir_bh, lookup);
        if (status < 0) {
                mlog_errno(status);
-               goto leave;
-       }
-
-       /*
-        * 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;
+               goto rollback;
        }
 
-       le32_add_cpu(&fe->i_flags, OCFS2_ORPHANED_FL);
+       fe->i_flags |= cpu_to_le32(OCFS2_ORPHANED_FL);
        OCFS2_I(inode)->ip_flags &= ~OCFS2_INODE_SKIP_ORPHAN_DIR;
 
        /* Record which orphan dir our inode now resides
@@ -2057,11 +2058,16 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb,
        trace_ocfs2_orphan_add_end((unsigned long long)OCFS2_I(inode)->ip_blkno,
                                   osb->slot_num);
 
+rollback:
+       if (status < 0) {
+               if (S_ISDIR(inode->i_mode))
+                       ocfs2_add_links_count(orphan_fe, -1);
+               set_nlink(orphan_dir_inode, ocfs2_read_links_count(orphan_fe));
+       }
+
 leave:
        brelse(orphan_dir_bh);
 
-       if (status)
-               mlog_errno(status);
        return status;
 }
 
@@ -2434,7 +2440,7 @@ int ocfs2_mv_orphaned_inode_to_new(struct inode *dir,
        }
 
        di = (struct ocfs2_dinode *)di_bh->b_data;
-       le32_add_cpu(&di->i_flags, -OCFS2_ORPHANED_FL);
+       di->i_flags &= ~cpu_to_le32(OCFS2_ORPHANED_FL);
        di->i_orphaned_slot = 0;
        set_nlink(inode, 1);
        ocfs2_set_links_count(di, inode->i_nlink);