summaryrefslogtreecommitdiff
path: root/fs/xfs/libxfs/xfs_bmap.c
diff options
context:
space:
mode:
authorDave Chinner <david@fromorbit.com>2016-11-28 07:06:03 +0300
committerDave Chinner <david@fromorbit.com>2016-11-28 07:06:03 +0300
commitb7b26110edf88bad41b87e96a9f0148bed5e2ff8 (patch)
tree70f3e1a3f5a387ccfe0af4e67e29e08046f5db0f /fs/xfs/libxfs/xfs_bmap.c
parented24bee6f26b268669702cf7521756d9031383af (diff)
parentf782088c9e5d08e9494c63e68b4e85716df3e5f8 (diff)
downloadlinux-b7b26110edf88bad41b87e96a9f0148bed5e2ff8.tar.xz
Merge branch 'xfs-4.10-misc-fixes-2' into for-next
Diffstat (limited to 'fs/xfs/libxfs/xfs_bmap.c')
-rw-r--r--fs/xfs/libxfs/xfs_bmap.c40
1 files changed, 36 insertions, 4 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index 4a5b335c7bb3..6f2881430c84 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -49,6 +49,8 @@
#include "xfs_rmap.h"
#include "xfs_ag_resv.h"
#include "xfs_refcount.h"
+#include "xfs_rmap_btree.h"
+#include "xfs_icache.h"
kmem_zone_t *xfs_bmap_free_item_zone;
@@ -190,8 +192,12 @@ xfs_bmap_worst_indlen(
int maxrecs; /* maximum record count at this level */
xfs_mount_t *mp; /* mount structure */
xfs_filblks_t rval; /* return value */
+ xfs_filblks_t orig_len;
mp = ip->i_mount;
+
+ /* Calculate the worst-case size of the bmbt. */
+ orig_len = len;
maxrecs = mp->m_bmap_dmxr[0];
for (level = 0, rval = 0;
level < XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK);
@@ -199,12 +205,20 @@ xfs_bmap_worst_indlen(
len += maxrecs - 1;
do_div(len, maxrecs);
rval += len;
- if (len == 1)
- return rval + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) -
+ if (len == 1) {
+ rval += XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) -
level - 1;
+ break;
+ }
if (level == 0)
maxrecs = mp->m_bmap_dmxr[1];
}
+
+ /* Calculate the worst-case size of the rmapbt. */
+ if (xfs_sb_version_hasrmapbt(&mp->m_sb))
+ rval += 1 + xfs_rmapbt_calc_size(mp, orig_len) +
+ mp->m_rmap_maxlevels;
+
return rval;
}
@@ -4141,8 +4155,9 @@ int
xfs_bmapi_reserve_delalloc(
struct xfs_inode *ip,
int whichfork,
- xfs_fileoff_t aoff,
+ xfs_fileoff_t off,
xfs_filblks_t len,
+ xfs_filblks_t prealloc,
struct xfs_bmbt_irec *got,
xfs_extnum_t *lastx,
int eof)
@@ -4154,10 +4169,17 @@ xfs_bmapi_reserve_delalloc(
char rt = XFS_IS_REALTIME_INODE(ip);
xfs_extlen_t extsz;
int error;
+ xfs_fileoff_t aoff = off;
- alen = XFS_FILBLKS_MIN(len, MAXEXTLEN);
+ /*
+ * Cap the alloc length. Keep track of prealloc so we know whether to
+ * tag the inode before we return.
+ */
+ alen = XFS_FILBLKS_MIN(len + prealloc, MAXEXTLEN);
if (!eof)
alen = XFS_FILBLKS_MIN(alen, got->br_startoff - aoff);
+ if (prealloc && alen >= len)
+ prealloc = alen - len;
/* Figure out the extent size, adjust alen */
if (whichfork == XFS_COW_FORK)
@@ -4223,6 +4245,16 @@ xfs_bmapi_reserve_delalloc(
*/
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx), got);
+ /*
+ * Tag the inode if blocks were preallocated. Note that COW fork
+ * preallocation can occur at the start or end of the extent, even when
+ * prealloc == 0, so we must also check the aligned offset and length.
+ */
+ if (whichfork == XFS_DATA_FORK && prealloc)
+ xfs_inode_set_eofblocks_tag(ip);
+ if (whichfork == XFS_COW_FORK && (prealloc || aoff < off || alen > len))
+ xfs_inode_set_cowblocks_tag(ip);
+
ASSERT(got->br_startoff <= aoff);
ASSERT(got->br_startoff + got->br_blockcount >= aoff + alen);
ASSERT(isnullstartblock(got->br_startblock));