if (error)
                return error;
 
-       /*
-        * The extent shifting code works on extent granularity. So, if stop_fsb
-        * is not the starting block of extent, we need to split the extent at
-        * stop_fsb.
-        */
        error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write,
                        XFS_DIOSTRAT_SPACE_RES(mp, 0), 0, 0, &tp);
        if (error)
                return error;
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, ip, 0);
 
+       /*
+        * The extent shifting code works on extent granularity. So, if stop_fsb
+        * is not the starting block of extent, we need to split the extent at
+        * stop_fsb.
+        */
        error = xfs_bmap_split_extent(tp, ip, stop_fsb);
        if (error)
                goto out_trans_cancel;
 
-       error = xfs_trans_commit(tp);
-       if (error)
-               return error;
-
-       while (!error && !done) {
-               error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, 0, 0, 0,
-                                       &tp);
+       do {
+               error = xfs_trans_roll_inode(&tp, ip);
                if (error)
-                       break;
+                       goto out_trans_cancel;
 
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-               xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
                error = xfs_bmap_insert_extents(tp, ip, &next_fsb, shift_fsb,
                                &done, stop_fsb);
                if (error)
                        goto out_trans_cancel;
+       } while (!done);
 
-               error = xfs_trans_commit(tp);
-       }
-
+       error = xfs_trans_commit(tp);
+       xfs_iunlock(ip, XFS_ILOCK_EXCL);
        return error;
 
 out_trans_cancel:
        xfs_trans_cancel(tp);
+       xfs_iunlock(ip, XFS_ILOCK_EXCL);
        return error;
 }