|
@@ -4211,9 +4211,8 @@ xfs_bmap_validate_ret(
|
|
|
ASSERT(i == 0 ||
|
|
|
mval[i - 1].br_startoff + mval[i - 1].br_blockcount ==
|
|
|
mval[i].br_startoff);
|
|
|
- if (flags & XFS_BMAPI_WRITE)
|
|
|
- ASSERT(mval[i].br_startblock != DELAYSTARTBLOCK &&
|
|
|
- mval[i].br_startblock != HOLESTARTBLOCK);
|
|
|
+ ASSERT(mval[i].br_startblock != DELAYSTARTBLOCK &&
|
|
|
+ mval[i].br_startblock != HOLESTARTBLOCK);
|
|
|
ASSERT(mval[i].br_state == XFS_EXT_NORM ||
|
|
|
mval[i].br_state == XFS_EXT_UNWRITTEN);
|
|
|
}
|
|
@@ -4809,60 +4808,57 @@ xfs_bmapi_convert_unwritten(
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Map file blocks to filesystem blocks.
|
|
|
- * File range is given by the bno/len pair.
|
|
|
- * Adds blocks to file if a write ("flags & XFS_BMAPI_WRITE" set)
|
|
|
- * into a hole or past eof.
|
|
|
- * Only allocates blocks from a single allocation group,
|
|
|
- * to avoid locking problems.
|
|
|
+ * Map file blocks to filesystem blocks, and allocate blocks or convert the
|
|
|
+ * extent state if necessary. Details behaviour is controlled by the flags
|
|
|
+ * parameter. Only allocates blocks from a single allocation group, to avoid
|
|
|
+ * locking problems.
|
|
|
+ *
|
|
|
* The returned value in "firstblock" from the first call in a transaction
|
|
|
* must be remembered and presented to subsequent calls in "firstblock".
|
|
|
* An upper bound for the number of blocks to be allocated is supplied to
|
|
|
* the first call in "total"; if no allocation group has that many free
|
|
|
* blocks then the call will fail (return NULLFSBLOCK in "firstblock").
|
|
|
*/
|
|
|
-int /* error */
|
|
|
-xfs_bmapi(
|
|
|
- xfs_trans_t *tp, /* transaction pointer */
|
|
|
- xfs_inode_t *ip, /* incore inode */
|
|
|
- xfs_fileoff_t bno, /* starting file offs. mapped */
|
|
|
- xfs_filblks_t len, /* length to map in file */
|
|
|
- int flags, /* XFS_BMAPI_... */
|
|
|
- xfs_fsblock_t *firstblock, /* first allocated block
|
|
|
- controls a.g. for allocs */
|
|
|
- xfs_extlen_t total, /* total blocks needed */
|
|
|
- xfs_bmbt_irec_t *mval, /* output: map values */
|
|
|
- int *nmap, /* i/o: mval size/count */
|
|
|
- xfs_bmap_free_t *flist) /* i/o: list extents to free */
|
|
|
+int
|
|
|
+xfs_bmapi_write(
|
|
|
+ struct xfs_trans *tp, /* transaction pointer */
|
|
|
+ struct xfs_inode *ip, /* incore inode */
|
|
|
+ xfs_fileoff_t bno, /* starting file offs. mapped */
|
|
|
+ xfs_filblks_t len, /* length to map in file */
|
|
|
+ int flags, /* XFS_BMAPI_... */
|
|
|
+ xfs_fsblock_t *firstblock, /* first allocated block
|
|
|
+ controls a.g. for allocs */
|
|
|
+ xfs_extlen_t total, /* total blocks needed */
|
|
|
+ struct xfs_bmbt_irec *mval, /* output: map values */
|
|
|
+ int *nmap, /* i/o: mval size/count */
|
|
|
+ struct xfs_bmap_free *flist) /* i/o: list extents to free */
|
|
|
{
|
|
|
- xfs_bmalloca_t bma = { 0 }; /* args for xfs_bmap_alloc */
|
|
|
- xfs_btree_cur_t *cur; /* bmap btree cursor */
|
|
|
- xfs_fileoff_t end; /* end of mapped file region */
|
|
|
- int eof; /* we've hit the end of extents */
|
|
|
- xfs_bmbt_rec_host_t *ep; /* extent record pointer */
|
|
|
- int error; /* error return */
|
|
|
- xfs_bmbt_irec_t got; /* current file extent record */
|
|
|
- xfs_ifork_t *ifp; /* inode fork pointer */
|
|
|
- xfs_extnum_t lastx; /* last useful extent number */
|
|
|
- int logflags; /* flags for transaction logging */
|
|
|
- xfs_extlen_t minleft; /* min blocks left after allocation */
|
|
|
- xfs_mount_t *mp; /* xfs mount structure */
|
|
|
- int n; /* current extent index */
|
|
|
- int nallocs; /* number of extents alloc'd */
|
|
|
- xfs_fileoff_t obno; /* old block number (offset) */
|
|
|
- xfs_bmbt_irec_t prev; /* previous file extent record */
|
|
|
- int tmp_logflags; /* temp flags holder */
|
|
|
- int whichfork; /* data or attr fork */
|
|
|
- char inhole; /* current location is hole in file */
|
|
|
- char wasdelay; /* old extent was delayed */
|
|
|
- char wr; /* this is a write request */
|
|
|
- char rt; /* this is a realtime file */
|
|
|
+ struct xfs_mount *mp = ip->i_mount;
|
|
|
+ struct xfs_ifork *ifp;
|
|
|
+ struct xfs_bmalloca bma = { 0 }; /* args for xfs_bmap_alloc */
|
|
|
+ struct xfs_btree_cur *cur; /* bmap btree cursor */
|
|
|
+ xfs_fileoff_t end; /* end of mapped file region */
|
|
|
+ int eof; /* after the end of extents */
|
|
|
+ int error; /* error return */
|
|
|
+ struct xfs_bmbt_irec got; /* current file extent record */
|
|
|
+ xfs_extnum_t lastx; /* last useful extent number */
|
|
|
+ int logflags; /* flags for transaction logging */
|
|
|
+ xfs_extlen_t minleft; /* min blocks left after allocation */
|
|
|
+ int n; /* current extent index */
|
|
|
+ int nallocs; /* number of extents alloc'd */
|
|
|
+ xfs_fileoff_t obno; /* old block number (offset) */
|
|
|
+ struct xfs_bmbt_irec prev; /* previous file extent record */
|
|
|
+ int tmp_logflags; /* temp flags holder */
|
|
|
+ int whichfork; /* data or attr fork */
|
|
|
+ char inhole; /* current location is hole in file */
|
|
|
+ char wasdelay; /* old extent was delayed */
|
|
|
+
|
|
|
#ifdef DEBUG
|
|
|
- xfs_fileoff_t orig_bno; /* original block number value */
|
|
|
- int orig_flags; /* original flags arg value */
|
|
|
- xfs_filblks_t orig_len; /* original value of len arg */
|
|
|
- xfs_bmbt_irec_t *orig_mval; /* original value of mval */
|
|
|
- int orig_nmap; /* original value of *nmap */
|
|
|
+ xfs_fileoff_t orig_bno; /* original block number value */
|
|
|
+ int orig_flags; /* original flags arg value */
|
|
|
+ xfs_filblks_t orig_len; /* original value of len arg */
|
|
|
+ struct xfs_bmbt_irec *orig_mval; /* original value of mval */
|
|
|
+ int orig_nmap; /* original value of *nmap */
|
|
|
|
|
|
orig_bno = bno;
|
|
|
orig_len = len;
|
|
@@ -4870,69 +4866,60 @@ xfs_bmapi(
|
|
|
orig_mval = mval;
|
|
|
orig_nmap = *nmap;
|
|
|
#endif
|
|
|
+
|
|
|
ASSERT(*nmap >= 1);
|
|
|
- ASSERT(*nmap <= XFS_BMAP_MAX_NMAP || !(flags & XFS_BMAPI_WRITE));
|
|
|
+ ASSERT(*nmap <= XFS_BMAP_MAX_NMAP);
|
|
|
+ ASSERT(!(flags & XFS_BMAPI_IGSTATE));
|
|
|
+ ASSERT(tp != NULL);
|
|
|
+
|
|
|
whichfork = (flags & XFS_BMAPI_ATTRFORK) ?
|
|
|
XFS_ATTR_FORK : XFS_DATA_FORK;
|
|
|
- mp = ip->i_mount;
|
|
|
+
|
|
|
if (unlikely(XFS_TEST_ERROR(
|
|
|
(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
|
|
|
XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
|
|
|
XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL),
|
|
|
mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) {
|
|
|
- XFS_ERROR_REPORT("xfs_bmapi", XFS_ERRLEVEL_LOW, mp);
|
|
|
+ XFS_ERROR_REPORT("xfs_bmapi_write", XFS_ERRLEVEL_LOW, mp);
|
|
|
return XFS_ERROR(EFSCORRUPTED);
|
|
|
}
|
|
|
+
|
|
|
if (XFS_FORCED_SHUTDOWN(mp))
|
|
|
return XFS_ERROR(EIO);
|
|
|
- rt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip);
|
|
|
+
|
|
|
ifp = XFS_IFORK_PTR(ip, whichfork);
|
|
|
ASSERT(ifp->if_ext_max ==
|
|
|
XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
|
|
|
- if ((wr = (flags & XFS_BMAPI_WRITE)) != 0)
|
|
|
- XFS_STATS_INC(xs_blk_mapw);
|
|
|
- else
|
|
|
- XFS_STATS_INC(xs_blk_mapr);
|
|
|
- /*
|
|
|
- * IGSTATE flag is used to combine extents which
|
|
|
- * differ only due to the state of the extents.
|
|
|
- * This technique is used from xfs_getbmap()
|
|
|
- * when the caller does not wish to see the
|
|
|
- * separation (which is the default).
|
|
|
- *
|
|
|
- * This technique is also used when writing a
|
|
|
- * buffer which has been partially written,
|
|
|
- * (usually by being flushed during a chunkread),
|
|
|
- * to ensure one write takes place. This also
|
|
|
- * prevents a change in the xfs inode extents at
|
|
|
- * this time, intentionally. This change occurs
|
|
|
- * on completion of the write operation, in
|
|
|
- * xfs_strat_comp(), where the xfs_bmapi() call
|
|
|
- * is transactioned, and the extents combined.
|
|
|
- */
|
|
|
- if ((flags & XFS_BMAPI_IGSTATE) && wr) /* if writing unwritten space */
|
|
|
- wr = 0; /* no allocations are allowed */
|
|
|
+
|
|
|
+ XFS_STATS_INC(xs_blk_mapw);
|
|
|
+
|
|
|
logflags = 0;
|
|
|
nallocs = 0;
|
|
|
cur = NULL;
|
|
|
+
|
|
|
if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
|
|
|
- ASSERT(wr && tp);
|
|
|
- if ((error = xfs_bmap_local_to_extents(tp, ip,
|
|
|
- firstblock, total, &logflags, whichfork)))
|
|
|
+ error = xfs_bmap_local_to_extents(tp, ip, firstblock, total,
|
|
|
+ &logflags, whichfork);
|
|
|
+ if (error)
|
|
|
goto error0;
|
|
|
}
|
|
|
- if (wr && *firstblock == NULLFSBLOCK) {
|
|
|
+
|
|
|
+ if (*firstblock == NULLFSBLOCK) {
|
|
|
if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE)
|
|
|
minleft = be16_to_cpu(ifp->if_broot->bb_level) + 1;
|
|
|
else
|
|
|
minleft = 1;
|
|
|
- } else
|
|
|
+ } else {
|
|
|
minleft = 0;
|
|
|
- if (!(ifp->if_flags & XFS_IFEXTENTS) &&
|
|
|
- (error = xfs_iread_extents(tp, ip, whichfork)))
|
|
|
- goto error0;
|
|
|
- ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got,
|
|
|
- &prev);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!(ifp->if_flags & XFS_IFEXTENTS)) {
|
|
|
+ error = xfs_iread_extents(tp, ip, whichfork);
|
|
|
+ if (error)
|
|
|
+ goto error0;
|
|
|
+ }
|
|
|
+
|
|
|
+ xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, &prev);
|
|
|
n = 0;
|
|
|
end = bno + len;
|
|
|
obno = bno;
|
|
@@ -4945,19 +4932,14 @@ xfs_bmapi(
|
|
|
bma.userdata = 0;
|
|
|
|
|
|
while (bno < end && n < *nmap) {
|
|
|
- /*
|
|
|
- * Reading past eof, act as though there's a hole
|
|
|
- * up to end.
|
|
|
- */
|
|
|
- if (eof && !wr)
|
|
|
- got.br_startoff = end;
|
|
|
inhole = eof || got.br_startoff > bno;
|
|
|
- wasdelay = wr && !inhole && isnullstartblock(got.br_startblock);
|
|
|
+ wasdelay = !inhole && isnullstartblock(got.br_startblock);
|
|
|
+
|
|
|
/*
|
|
|
* First, deal with the hole before the allocated space
|
|
|
* that we found, if any.
|
|
|
*/
|
|
|
- if (wr && (inhole || wasdelay)) {
|
|
|
+ if (inhole || wasdelay) {
|
|
|
bma.eof = eof;
|
|
|
bma.conv = !!(flags & XFS_BMAPI_CONVERT);
|
|
|
bma.wasdel = wasdelay;
|
|
@@ -4975,36 +4957,20 @@ xfs_bmapi(
|
|
|
minleft = 0;
|
|
|
if (bma.rval == NULLFSBLOCK)
|
|
|
break;
|
|
|
- } else if (inhole) {
|
|
|
- /*
|
|
|
- * Reading in a hole.
|
|
|
- */
|
|
|
- mval->br_startoff = bno;
|
|
|
- mval->br_startblock = HOLESTARTBLOCK;
|
|
|
- mval->br_blockcount =
|
|
|
- XFS_FILBLKS_MIN(len, got.br_startoff - bno);
|
|
|
- mval->br_state = XFS_EXT_NORM;
|
|
|
- bno += mval->br_blockcount;
|
|
|
- len -= mval->br_blockcount;
|
|
|
- mval++;
|
|
|
- n++;
|
|
|
- continue;
|
|
|
}
|
|
|
|
|
|
/* Deal with the allocated space we found. */
|
|
|
xfs_bmapi_trim_map(mval, &got, &bno, len, obno, end, n, flags);
|
|
|
|
|
|
/* Execute unwritten extent conversion if necessary */
|
|
|
- if (wr) {
|
|
|
- error = xfs_bmapi_convert_unwritten(&bma, mval, len,
|
|
|
- &lastx, &cur, firstblock, flist, flags,
|
|
|
- &tmp_logflags);
|
|
|
- logflags |= tmp_logflags;
|
|
|
- if (error == EAGAIN)
|
|
|
- continue;
|
|
|
- if (error)
|
|
|
- goto error0;
|
|
|
- }
|
|
|
+ error = xfs_bmapi_convert_unwritten(&bma, mval, len, &lastx,
|
|
|
+ &cur, firstblock, flist,
|
|
|
+ flags, &tmp_logflags);
|
|
|
+ logflags |= tmp_logflags;
|
|
|
+ if (error == EAGAIN)
|
|
|
+ continue;
|
|
|
+ if (error)
|
|
|
+ goto error0;
|
|
|
|
|
|
/* update the extent map to return */
|
|
|
xfs_bmapi_update_map(&mval, &bno, &len, obno, end, &n, flags);
|
|
@@ -5016,24 +4982,22 @@ xfs_bmapi(
|
|
|
*/
|
|
|
if (bno >= end || n >= *nmap || nallocs >= *nmap)
|
|
|
break;
|
|
|
- /*
|
|
|
- * Else go on to the next record.
|
|
|
- */
|
|
|
+
|
|
|
+ /* Else go on to the next record. */
|
|
|
prev = got;
|
|
|
- if (++lastx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t)) {
|
|
|
- ep = xfs_iext_get_ext(ifp, lastx);
|
|
|
- xfs_bmbt_get_all(ep, &got);
|
|
|
- } else {
|
|
|
+ if (++lastx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t))
|
|
|
+ xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx), &got);
|
|
|
+ else
|
|
|
eof = 1;
|
|
|
- }
|
|
|
}
|
|
|
*nmap = n;
|
|
|
+
|
|
|
/*
|
|
|
* Transform from btree to extents, give it cur.
|
|
|
*/
|
|
|
- if (tp && XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE &&
|
|
|
+ if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE &&
|
|
|
XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max) {
|
|
|
- ASSERT(wr && cur);
|
|
|
+ ASSERT(cur);
|
|
|
error = xfs_bmap_btree_to_extents(tp, ip, cur,
|
|
|
&tmp_logflags, whichfork);
|
|
|
logflags |= tmp_logflags;
|
|
@@ -5061,10 +5025,9 @@ error0:
|
|
|
* detecting a case where the data is changed, there's an error,
|
|
|
* and it's not logged so we don't shutdown when we should.
|
|
|
*/
|
|
|
- if (logflags) {
|
|
|
- ASSERT(tp && wr);
|
|
|
+ if (logflags)
|
|
|
xfs_trans_log_inode(tp, ip, logflags);
|
|
|
- }
|
|
|
+
|
|
|
if (cur) {
|
|
|
if (!error) {
|
|
|
ASSERT(*firstblock == NULLFSBLOCK ||
|