Merge branch 'xfs-4.10-extent-lookup' into for-next

This commit is contained in:
Dave Chinner 2016-11-24 11:41:59 +11:00
commit ed24bee6f2
9 changed files with 178 additions and 267 deletions

View File

@ -1370,97 +1370,6 @@ error0:
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
/*
* Search the extent records for the entry containing block bno.
* If bno lies in a hole, point to the next entry. If bno lies
* past eof, *eofp will be set, and *prevp will contain the last
* entry (null if none). Else, *lastxp will be set to the index
* of the found entry; *gotp will contain the entry.
*/
STATIC xfs_bmbt_rec_host_t * /* pointer to found extent entry */
xfs_bmap_search_multi_extents(
xfs_ifork_t *ifp, /* inode fork pointer */
xfs_fileoff_t bno, /* block number searched for */
int *eofp, /* out: end of file found */
xfs_extnum_t *lastxp, /* out: last extent index */
xfs_bmbt_irec_t *gotp, /* out: extent entry found */
xfs_bmbt_irec_t *prevp) /* out: previous extent entry found */
{
xfs_bmbt_rec_host_t *ep; /* extent record pointer */
xfs_extnum_t lastx; /* last extent index */
/*
* Initialize the extent entry structure to catch access to
* uninitialized br_startblock field.
*/
gotp->br_startoff = 0xffa5a5a5a5a5a5a5LL;
gotp->br_blockcount = 0xa55a5a5a5a5a5a5aLL;
gotp->br_state = XFS_EXT_INVALID;
gotp->br_startblock = 0xffffa5a5a5a5a5a5LL;
prevp->br_startoff = NULLFILEOFF;
ep = xfs_iext_bno_to_ext(ifp, bno, &lastx);
if (lastx > 0) {
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx - 1), prevp);
}
if (lastx < xfs_iext_count(ifp)) {
xfs_bmbt_get_all(ep, gotp);
*eofp = 0;
} else {
if (lastx > 0) {
*gotp = *prevp;
}
*eofp = 1;
ep = NULL;
}
*lastxp = lastx;
return ep;
}
/*
* Search the extents list for the inode, for the extent containing bno.
* If bno lies in a hole, point to the next entry. If bno lies past eof,
* *eofp will be set, and *prevp will contain the last entry (null if none).
* Else, *lastxp will be set to the index of the found
* entry; *gotp will contain the entry.
*/
xfs_bmbt_rec_host_t * /* pointer to found extent entry */
xfs_bmap_search_extents(
xfs_inode_t *ip, /* incore inode pointer */
xfs_fileoff_t bno, /* block number searched for */
int fork, /* data or attr fork */
int *eofp, /* out: end of file found */
xfs_extnum_t *lastxp, /* out: last extent index */
xfs_bmbt_irec_t *gotp, /* out: extent entry found */
xfs_bmbt_irec_t *prevp) /* out: previous extent entry found */
{
xfs_ifork_t *ifp; /* inode fork pointer */
xfs_bmbt_rec_host_t *ep; /* extent record pointer */
XFS_STATS_INC(ip->i_mount, xs_look_exlist);
ifp = XFS_IFORK_PTR(ip, fork);
ep = xfs_bmap_search_multi_extents(ifp, bno, eofp, lastxp, gotp, prevp);
if (unlikely(!(gotp->br_startblock) && (*lastxp != NULLEXTNUM) &&
!(XFS_IS_REALTIME_INODE(ip) && fork == XFS_DATA_FORK))) {
xfs_alert_tag(ip->i_mount, XFS_PTAG_FSBLOCK_ZERO,
"Access to block zero in inode %llu "
"start_block: %llx start_off: %llx "
"blkcnt: %llx extent-state: %x lastx: %x",
(unsigned long long)ip->i_ino,
(unsigned long long)gotp->br_startblock,
(unsigned long long)gotp->br_startoff,
(unsigned long long)gotp->br_blockcount,
gotp->br_state, *lastxp);
*lastxp = NULLEXTNUM;
*eofp = 1;
return NULL;
}
return ep;
}
/* /*
* Returns the file-relative block number of the first unused block(s) * Returns the file-relative block number of the first unused block(s)
* in the file with at least "len" logically contiguous blocks free. * in the file with at least "len" logically contiguous blocks free.
@ -1523,44 +1432,44 @@ xfs_bmap_first_unused(
*/ */
int /* error */ int /* error */
xfs_bmap_last_before( xfs_bmap_last_before(
xfs_trans_t *tp, /* transaction pointer */ struct xfs_trans *tp, /* transaction pointer */
xfs_inode_t *ip, /* incore inode */ struct xfs_inode *ip, /* incore inode */
xfs_fileoff_t *last_block, /* last block */ xfs_fileoff_t *last_block, /* last block */
int whichfork) /* data or attr fork */ int whichfork) /* data or attr fork */
{ {
xfs_fileoff_t bno; /* input file offset */ struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork);
int eof; /* hit end of file */ struct xfs_bmbt_irec got;
xfs_bmbt_rec_host_t *ep; /* pointer to last extent */ xfs_extnum_t idx;
int error; /* error return value */ int error;
xfs_bmbt_irec_t got; /* current extent value */
xfs_ifork_t *ifp; /* inode fork pointer */
xfs_extnum_t lastx; /* last extent used */
xfs_bmbt_irec_t prev; /* previous extent value */
if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && switch (XFS_IFORK_FORMAT(ip, whichfork)) {
XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && case XFS_DINODE_FMT_LOCAL:
XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL)
return -EIO;
if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
*last_block = 0; *last_block = 0;
return 0; return 0;
case XFS_DINODE_FMT_BTREE:
case XFS_DINODE_FMT_EXTENTS:
break;
default:
return -EIO;
} }
ifp = XFS_IFORK_PTR(ip, whichfork);
if (!(ifp->if_flags & XFS_IFEXTENTS) && if (!(ifp->if_flags & XFS_IFEXTENTS)) {
(error = xfs_iread_extents(tp, ip, whichfork))) error = xfs_iread_extents(tp, ip, whichfork);
return error; if (error)
bno = *last_block - 1; return error;
ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got,
&prev);
if (eof || xfs_bmbt_get_startoff(ep) > bno) {
if (prev.br_startoff == NULLFILEOFF)
*last_block = 0;
else
*last_block = prev.br_startoff + prev.br_blockcount;
} }
/*
* Otherwise *last_block is already the right answer. if (xfs_iext_lookup_extent(ip, ifp, *last_block - 1, &idx, &got)) {
*/ if (got.br_startoff <= *last_block - 1)
return 0;
}
if (xfs_iext_get_extent(ifp, idx - 1, &got)) {
*last_block = got.br_startoff + got.br_blockcount;
return 0;
}
*last_block = 0;
return 0; return 0;
} }
@ -4145,12 +4054,11 @@ xfs_bmapi_read(
struct xfs_mount *mp = ip->i_mount; struct xfs_mount *mp = ip->i_mount;
struct xfs_ifork *ifp; struct xfs_ifork *ifp;
struct xfs_bmbt_irec got; struct xfs_bmbt_irec got;
struct xfs_bmbt_irec prev;
xfs_fileoff_t obno; xfs_fileoff_t obno;
xfs_fileoff_t end; xfs_fileoff_t end;
xfs_extnum_t lastx; xfs_extnum_t idx;
int error; int error;
int eof; bool eof = false;
int n = 0; int n = 0;
int whichfork = xfs_bmapi_whichfork(flags); int whichfork = xfs_bmapi_whichfork(flags);
@ -4190,7 +4098,8 @@ xfs_bmapi_read(
return error; return error;
} }
xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, &prev); if (!xfs_iext_lookup_extent(ip, ifp, bno, &idx, &got))
eof = true;
end = bno + len; end = bno + len;
obno = bno; obno = bno;
@ -4221,10 +4130,8 @@ xfs_bmapi_read(
break; break;
/* Else go on to the next record. */ /* Else go on to the next record. */
if (++lastx < xfs_iext_count(ifp)) if (!xfs_iext_get_extent(ifp, ++idx, &got))
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx), &got); eof = true;
else
eof = 1;
} }
*nmap = n; *nmap = n;
return 0; return 0;
@ -4237,7 +4144,6 @@ xfs_bmapi_reserve_delalloc(
xfs_fileoff_t aoff, xfs_fileoff_t aoff,
xfs_filblks_t len, xfs_filblks_t len,
struct xfs_bmbt_irec *got, struct xfs_bmbt_irec *got,
struct xfs_bmbt_irec *prev,
xfs_extnum_t *lastx, xfs_extnum_t *lastx,
int eof) int eof)
{ {
@ -4259,7 +4165,12 @@ xfs_bmapi_reserve_delalloc(
else else
extsz = xfs_get_extsz_hint(ip); extsz = xfs_get_extsz_hint(ip);
if (extsz) { if (extsz) {
error = xfs_bmap_extsize_align(mp, got, prev, extsz, rt, eof, struct xfs_bmbt_irec prev;
if (!xfs_iext_get_extent(ifp, *lastx - 1, &prev))
prev.br_startoff = NULLFILEOFF;
error = xfs_bmap_extsize_align(mp, got, &prev, extsz, rt, eof,
1, 0, &aoff, &alen); 1, 0, &aoff, &alen);
ASSERT(!error); ASSERT(!error);
} }
@ -4349,7 +4260,7 @@ xfs_bmapi_allocate(
if (bma->wasdel) { if (bma->wasdel) {
bma->length = (xfs_extlen_t)bma->got.br_blockcount; bma->length = (xfs_extlen_t)bma->got.br_blockcount;
bma->offset = bma->got.br_startoff; bma->offset = bma->got.br_startoff;
if (bma->idx != NULLEXTNUM && bma->idx) { if (bma->idx) {
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx - 1), xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx - 1),
&bma->prev); &bma->prev);
} }
@ -4563,7 +4474,7 @@ xfs_bmapi_write(
struct xfs_ifork *ifp; struct xfs_ifork *ifp;
struct xfs_bmalloca bma = { NULL }; /* args for xfs_bmap_alloc */ struct xfs_bmalloca bma = { NULL }; /* args for xfs_bmap_alloc */
xfs_fileoff_t end; /* end of mapped file region */ xfs_fileoff_t end; /* end of mapped file region */
int eof; /* after the end of extents */ bool eof = false; /* after the end of extents */
int error; /* error return */ int error; /* error return */
int n; /* current extent index */ int n; /* current extent index */
xfs_fileoff_t obno; /* old block number (offset) */ xfs_fileoff_t obno; /* old block number (offset) */
@ -4641,12 +4552,14 @@ xfs_bmapi_write(
goto error0; goto error0;
} }
xfs_bmap_search_extents(ip, bno, whichfork, &eof, &bma.idx, &bma.got,
&bma.prev);
n = 0; n = 0;
end = bno + len; end = bno + len;
obno = bno; obno = bno;
if (!xfs_iext_lookup_extent(ip, ifp, bno, &bma.idx, &bma.got))
eof = true;
if (!xfs_iext_get_extent(ifp, bma.idx - 1, &bma.prev))
bma.prev.br_startoff = NULLFILEOFF;
bma.tp = tp; bma.tp = tp;
bma.ip = ip; bma.ip = ip;
bma.total = total; bma.total = total;
@ -4733,11 +4646,8 @@ xfs_bmapi_write(
/* Else go on to the next record. */ /* Else go on to the next record. */
bma.prev = bma.got; bma.prev = bma.got;
if (++bma.idx < xfs_iext_count(ifp)) { if (!xfs_iext_get_extent(ifp, ++bma.idx, &bma.got))
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma.idx), eof = true;
&bma.got);
} else
eof = 1;
} }
*nmap = n; *nmap = n;
@ -5436,8 +5346,6 @@ __xfs_bunmapi(
{ {
xfs_btree_cur_t *cur; /* bmap btree cursor */ xfs_btree_cur_t *cur; /* bmap btree cursor */
xfs_bmbt_irec_t del; /* extent being deleted */ xfs_bmbt_irec_t del; /* extent being deleted */
int eof; /* is deleting at eof */
xfs_bmbt_rec_host_t *ep; /* extent record pointer */
int error; /* error return value */ int error; /* error return value */
xfs_extnum_t extno; /* extent number in list */ xfs_extnum_t extno; /* extent number in list */
xfs_bmbt_irec_t got; /* current extent record */ xfs_bmbt_irec_t got; /* current extent record */
@ -5447,7 +5355,6 @@ __xfs_bunmapi(
int logflags; /* transaction logging flags */ int logflags; /* transaction logging flags */
xfs_extlen_t mod; /* rt extent offset */ xfs_extlen_t mod; /* rt extent offset */
xfs_mount_t *mp; /* mount structure */ xfs_mount_t *mp; /* mount structure */
xfs_bmbt_irec_t prev; /* previous extent record */
xfs_fileoff_t start; /* first file offset deleted */ xfs_fileoff_t start; /* first file offset deleted */
int tmp_logflags; /* partial logging flags */ int tmp_logflags; /* partial logging flags */
int wasdel; /* was a delayed alloc extent */ int wasdel; /* was a delayed alloc extent */
@ -5486,18 +5393,17 @@ __xfs_bunmapi(
isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip); isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip);
start = bno; start = bno;
bno = start + len - 1; bno = start + len - 1;
ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got,
&prev);
/* /*
* Check to see if the given block number is past the end of the * Check to see if the given block number is past the end of the
* file, back up to the last block if so... * file, back up to the last block if so...
*/ */
if (eof) { if (!xfs_iext_lookup_extent(ip, ifp, bno, &lastx, &got)) {
ep = xfs_iext_get_ext(ifp, --lastx); ASSERT(lastx > 0);
xfs_bmbt_get_all(ep, &got); xfs_iext_get_extent(ifp, --lastx, &got);
bno = got.br_startoff + got.br_blockcount - 1; bno = got.br_startoff + got.br_blockcount - 1;
} }
logflags = 0; logflags = 0;
if (ifp->if_flags & XFS_IFBROOT) { if (ifp->if_flags & XFS_IFBROOT) {
ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE); ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE);
@ -5528,8 +5434,7 @@ __xfs_bunmapi(
if (got.br_startoff > bno) { if (got.br_startoff > bno) {
if (--lastx < 0) if (--lastx < 0)
break; break;
ep = xfs_iext_get_ext(ifp, lastx); xfs_iext_get_extent(ifp, lastx, &got);
xfs_bmbt_get_all(ep, &got);
} }
/* /*
* Is the last block of this extent before the range * Is the last block of this extent before the range
@ -5543,7 +5448,6 @@ __xfs_bunmapi(
* Then deal with the (possibly delayed) allocated space * Then deal with the (possibly delayed) allocated space
* we found. * we found.
*/ */
ASSERT(ep != NULL);
del = got; del = got;
wasdel = isnullstartblock(del.br_startblock); wasdel = isnullstartblock(del.br_startblock);
if (got.br_startoff < start) { if (got.br_startoff < start) {
@ -5624,15 +5528,12 @@ __xfs_bunmapi(
*/ */
ASSERT(bno >= del.br_blockcount); ASSERT(bno >= del.br_blockcount);
bno -= del.br_blockcount; bno -= del.br_blockcount;
if (got.br_startoff > bno) { if (got.br_startoff > bno && --lastx >= 0)
if (--lastx >= 0) { xfs_iext_get_extent(ifp, lastx, &got);
ep = xfs_iext_get_ext(ifp,
lastx);
xfs_bmbt_get_all(ep, &got);
}
}
continue; continue;
} else if (del.br_state == XFS_EXT_UNWRITTEN) { } else if (del.br_state == XFS_EXT_UNWRITTEN) {
struct xfs_bmbt_irec prev;
/* /*
* This one is already unwritten. * This one is already unwritten.
* It must have a written left neighbor. * It must have a written left neighbor.
@ -5640,8 +5541,7 @@ __xfs_bunmapi(
* try again. * try again.
*/ */
ASSERT(lastx > 0); ASSERT(lastx > 0);
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, xfs_iext_get_extent(ifp, lastx - 1, &prev);
lastx - 1), &prev);
ASSERT(prev.br_state == XFS_EXT_NORM); ASSERT(prev.br_state == XFS_EXT_NORM);
ASSERT(!isnullstartblock(prev.br_startblock)); ASSERT(!isnullstartblock(prev.br_startblock));
ASSERT(del.br_startblock == ASSERT(del.br_startblock ==
@ -5739,13 +5639,9 @@ nodelete:
*/ */
if (bno != (xfs_fileoff_t)-1 && bno >= start) { if (bno != (xfs_fileoff_t)-1 && bno >= start) {
if (lastx >= 0) { if (lastx >= 0) {
ep = xfs_iext_get_ext(ifp, lastx); xfs_iext_get_extent(ifp, lastx, &got);
if (xfs_bmbt_get_startoff(ep) > bno) { if (got.br_startoff > bno && --lastx >= 0)
if (--lastx >= 0) xfs_iext_get_extent(ifp, lastx, &got);
ep = xfs_iext_get_ext(ifp,
lastx);
}
xfs_bmbt_get_all(ep, &got);
} }
extno++; extno++;
} }

View File

@ -237,14 +237,9 @@ int xfs_bmap_shift_extents(struct xfs_trans *tp, struct xfs_inode *ip,
struct xfs_defer_ops *dfops, enum shift_direction direction, struct xfs_defer_ops *dfops, enum shift_direction direction,
int num_exts); int num_exts);
int xfs_bmap_split_extent(struct xfs_inode *ip, xfs_fileoff_t split_offset); int xfs_bmap_split_extent(struct xfs_inode *ip, xfs_fileoff_t split_offset);
struct xfs_bmbt_rec_host *
xfs_bmap_search_extents(struct xfs_inode *ip, xfs_fileoff_t bno,
int fork, int *eofp, xfs_extnum_t *lastxp,
struct xfs_bmbt_irec *gotp, struct xfs_bmbt_irec *prevp);
int xfs_bmapi_reserve_delalloc(struct xfs_inode *ip, int whichfork, int xfs_bmapi_reserve_delalloc(struct xfs_inode *ip, int whichfork,
xfs_fileoff_t aoff, xfs_filblks_t len, xfs_fileoff_t aoff, xfs_filblks_t len,
struct xfs_bmbt_irec *got, struct xfs_bmbt_irec *prev, struct xfs_bmbt_irec *got, xfs_extnum_t *lastx, int eof);
xfs_extnum_t *lastx, int eof);
enum xfs_bmap_intent_type { enum xfs_bmap_intent_type {
XFS_BMAP_MAP = 1, XFS_BMAP_MAP = 1,

View File

@ -2003,3 +2003,49 @@ xfs_ifork_init_cow(
ip->i_cformat = XFS_DINODE_FMT_EXTENTS; ip->i_cformat = XFS_DINODE_FMT_EXTENTS;
ip->i_cnextents = 0; ip->i_cnextents = 0;
} }
/*
* Lookup the extent covering bno.
*
* If there is an extent covering bno return the extent index, and store the
* expanded extent structure in *gotp, and the extent index in *idx.
* If there is no extent covering bno, but there is an extent after it (e.g.
* it lies in a hole) return that extent in *gotp and its index in *idx
* instead.
* If bno is beyond the last extent return false, and return the index after
* the last valid index in *idxp.
*/
bool
xfs_iext_lookup_extent(
struct xfs_inode *ip,
struct xfs_ifork *ifp,
xfs_fileoff_t bno,
xfs_extnum_t *idxp,
struct xfs_bmbt_irec *gotp)
{
struct xfs_bmbt_rec_host *ep;
XFS_STATS_INC(ip->i_mount, xs_look_exlist);
ep = xfs_iext_bno_to_ext(ifp, bno, idxp);
if (!ep)
return false;
xfs_bmbt_get_all(ep, gotp);
return true;
}
/*
* Return true if there is an extent at index idx, and return the expanded
* extent structure at idx in that case. Else return false.
*/
bool
xfs_iext_get_extent(
struct xfs_ifork *ifp,
xfs_extnum_t idx,
struct xfs_bmbt_irec *gotp)
{
if (idx < 0 || idx >= xfs_iext_count(ifp))
return false;
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx), gotp);
return true;
}

View File

@ -182,6 +182,12 @@ void xfs_iext_irec_compact_pages(struct xfs_ifork *);
void xfs_iext_irec_compact_full(struct xfs_ifork *); void xfs_iext_irec_compact_full(struct xfs_ifork *);
void xfs_iext_irec_update_extoffs(struct xfs_ifork *, int, int); void xfs_iext_irec_update_extoffs(struct xfs_ifork *, int, int);
bool xfs_iext_lookup_extent(struct xfs_inode *ip,
struct xfs_ifork *ifp, xfs_fileoff_t bno,
xfs_extnum_t *idxp, struct xfs_bmbt_irec *gotp);
bool xfs_iext_get_extent(struct xfs_ifork *ifp, xfs_extnum_t idx,
struct xfs_bmbt_irec *gotp);
extern struct kmem_zone *xfs_ifork_zone; extern struct kmem_zone *xfs_ifork_zone;
extern void xfs_ifork_init_cow(struct xfs_inode *ip); extern void xfs_ifork_init_cow(struct xfs_inode *ip);

View File

@ -57,7 +57,6 @@ typedef __int64_t xfs_sfiloff_t; /* signed block number in a file */
#define NULLAGBLOCK ((xfs_agblock_t)-1) #define NULLAGBLOCK ((xfs_agblock_t)-1)
#define NULLAGNUMBER ((xfs_agnumber_t)-1) #define NULLAGNUMBER ((xfs_agnumber_t)-1)
#define NULLEXTNUM ((xfs_extnum_t)-1)
#define NULLCOMMITLSN ((xfs_lsn_t)-1) #define NULLCOMMITLSN ((xfs_lsn_t)-1)

View File

@ -777,7 +777,7 @@ xfs_map_cow(
{ {
struct xfs_inode *ip = XFS_I(inode); struct xfs_inode *ip = XFS_I(inode);
struct xfs_bmbt_irec imap; struct xfs_bmbt_irec imap;
bool is_cow = false, need_alloc = false; bool is_cow = false;
int error; int error;
/* /*
@ -795,7 +795,7 @@ xfs_map_cow(
* Else we need to check if there is a COW mapping at this offset. * Else we need to check if there is a COW mapping at this offset.
*/ */
xfs_ilock(ip, XFS_ILOCK_SHARED); xfs_ilock(ip, XFS_ILOCK_SHARED);
is_cow = xfs_reflink_find_cow_mapping(ip, offset, &imap, &need_alloc); is_cow = xfs_reflink_find_cow_mapping(ip, offset, &imap);
xfs_iunlock(ip, XFS_ILOCK_SHARED); xfs_iunlock(ip, XFS_ILOCK_SHARED);
if (!is_cow) if (!is_cow)
@ -805,7 +805,7 @@ xfs_map_cow(
* And if the COW mapping has a delayed extent here we need to * And if the COW mapping has a delayed extent here we need to
* allocate real space for it now. * allocate real space for it now.
*/ */
if (need_alloc) { if (isnullstartblock(imap.br_startblock)) {
error = xfs_iomap_write_allocate(ip, XFS_COW_FORK, offset, error = xfs_iomap_write_allocate(ip, XFS_COW_FORK, offset,
&imap); &imap);
if (error) if (error)
@ -1311,7 +1311,6 @@ __xfs_get_blocks(
ssize_t size; ssize_t size;
int new = 0; int new = 0;
bool is_cow = false; bool is_cow = false;
bool need_alloc = false;
BUG_ON(create && !direct); BUG_ON(create && !direct);
@ -1337,9 +1336,11 @@ __xfs_get_blocks(
end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + size); end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + size);
offset_fsb = XFS_B_TO_FSBT(mp, offset); offset_fsb = XFS_B_TO_FSBT(mp, offset);
if (create && direct && xfs_is_reflink_inode(ip)) if (create && direct && xfs_is_reflink_inode(ip)) {
is_cow = xfs_reflink_find_cow_mapping(ip, offset, &imap, is_cow = xfs_reflink_find_cow_mapping(ip, offset, &imap);
&need_alloc); ASSERT(!is_cow || !isnullstartblock(imap.br_startblock));
}
if (!is_cow) { if (!is_cow) {
error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb,
&imap, &nimaps, XFS_BMAPI_ENTIRE); &imap, &nimaps, XFS_BMAPI_ENTIRE);
@ -1356,7 +1357,6 @@ __xfs_get_blocks(
xfs_reflink_trim_irec_to_next_cow(ip, offset_fsb, xfs_reflink_trim_irec_to_next_cow(ip, offset_fsb,
&imap); &imap);
} }
ASSERT(!need_alloc);
if (error) if (error)
goto out_unlock; goto out_unlock;

View File

@ -395,11 +395,12 @@ xfs_iomap_prealloc_size(
struct xfs_inode *ip, struct xfs_inode *ip,
loff_t offset, loff_t offset,
loff_t count, loff_t count,
xfs_extnum_t idx, xfs_extnum_t idx)
struct xfs_bmbt_irec *prev)
{ {
struct xfs_mount *mp = ip->i_mount; struct xfs_mount *mp = ip->i_mount;
struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset); xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset);
struct xfs_bmbt_irec prev;
int shift = 0; int shift = 0;
int64_t freesp; int64_t freesp;
xfs_fsblock_t qblocks; xfs_fsblock_t qblocks;
@ -419,8 +420,8 @@ xfs_iomap_prealloc_size(
*/ */
if ((mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) || if ((mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) ||
XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_dalign) || XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_dalign) ||
idx == 0 || !xfs_iext_get_extent(ifp, idx - 1, &prev) ||
prev->br_startoff + prev->br_blockcount < offset_fsb) prev.br_startoff + prev.br_blockcount < offset_fsb)
return mp->m_writeio_blocks; return mp->m_writeio_blocks;
/* /*
@ -439,8 +440,8 @@ xfs_iomap_prealloc_size(
* always extends to MAXEXTLEN rather than falling short due to things * always extends to MAXEXTLEN rather than falling short due to things
* like stripe unit/width alignment of real extents. * like stripe unit/width alignment of real extents.
*/ */
if (prev->br_blockcount <= (MAXEXTLEN >> 1)) if (prev.br_blockcount <= (MAXEXTLEN >> 1))
alloc_blocks = prev->br_blockcount << 1; alloc_blocks = prev.br_blockcount << 1;
else else
alloc_blocks = XFS_B_TO_FSB(mp, offset); alloc_blocks = XFS_B_TO_FSB(mp, offset);
if (!alloc_blocks) if (!alloc_blocks)
@ -538,7 +539,6 @@ xfs_file_iomap_begin_delay(
xfs_fileoff_t end_fsb, orig_end_fsb; xfs_fileoff_t end_fsb, orig_end_fsb;
int error = 0, eof = 0; int error = 0, eof = 0;
struct xfs_bmbt_irec got; struct xfs_bmbt_irec got;
struct xfs_bmbt_irec prev;
xfs_extnum_t idx; xfs_extnum_t idx;
ASSERT(!XFS_IS_REALTIME_INODE(ip)); ASSERT(!XFS_IS_REALTIME_INODE(ip));
@ -563,8 +563,7 @@ xfs_file_iomap_begin_delay(
goto out_unlock; goto out_unlock;
} }
xfs_bmap_search_extents(ip, offset_fsb, XFS_DATA_FORK, &eof, &idx, eof = !xfs_iext_lookup_extent(ip, ifp, offset_fsb, &idx, &got);
&got, &prev);
if (!eof && got.br_startoff <= offset_fsb) { if (!eof && got.br_startoff <= offset_fsb) {
if (xfs_is_reflink_inode(ip)) { if (xfs_is_reflink_inode(ip)) {
bool shared; bool shared;
@ -601,8 +600,7 @@ xfs_file_iomap_begin_delay(
if (eof) { if (eof) {
xfs_fsblock_t prealloc_blocks; xfs_fsblock_t prealloc_blocks;
prealloc_blocks = prealloc_blocks = xfs_iomap_prealloc_size(ip, offset, count, idx);
xfs_iomap_prealloc_size(ip, offset, count, idx, &prev);
if (prealloc_blocks) { if (prealloc_blocks) {
xfs_extlen_t align; xfs_extlen_t align;
xfs_off_t end_offset; xfs_off_t end_offset;
@ -622,8 +620,7 @@ xfs_file_iomap_begin_delay(
retry: retry:
error = xfs_bmapi_reserve_delalloc(ip, XFS_DATA_FORK, offset_fsb, error = xfs_bmapi_reserve_delalloc(ip, XFS_DATA_FORK, offset_fsb,
end_fsb - offset_fsb, &got, end_fsb - offset_fsb, &got, &idx, eof);
&prev, &idx, eof);
switch (error) { switch (error) {
case 0: case 0:
break; break;

View File

@ -243,10 +243,11 @@ xfs_reflink_reserve_cow(
struct xfs_bmbt_irec *imap, struct xfs_bmbt_irec *imap,
bool *shared) bool *shared)
{ {
struct xfs_bmbt_irec got, prev; struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
struct xfs_bmbt_irec got;
xfs_fileoff_t end_fsb, orig_end_fsb; xfs_fileoff_t end_fsb, orig_end_fsb;
int eof = 0, error = 0; int error = 0;
bool trimmed; bool eof = false, trimmed;
xfs_extnum_t idx; xfs_extnum_t idx;
xfs_extlen_t align; xfs_extlen_t align;
@ -258,8 +259,9 @@ xfs_reflink_reserve_cow(
* extent list is generally faster than going out to the shared extent * extent list is generally faster than going out to the shared extent
* tree. * tree.
*/ */
xfs_bmap_search_extents(ip, imap->br_startoff, XFS_COW_FORK, &eof, &idx,
&got, &prev); if (!xfs_iext_lookup_extent(ip, ifp, imap->br_startoff, &idx, &got))
eof = true;
if (!eof && got.br_startoff <= imap->br_startoff) { if (!eof && got.br_startoff <= imap->br_startoff) {
trace_xfs_reflink_cow_found(ip, imap); trace_xfs_reflink_cow_found(ip, imap);
xfs_trim_extent(imap, got.br_startoff, got.br_blockcount); xfs_trim_extent(imap, got.br_startoff, got.br_blockcount);
@ -293,7 +295,7 @@ xfs_reflink_reserve_cow(
retry: retry:
error = xfs_bmapi_reserve_delalloc(ip, XFS_COW_FORK, imap->br_startoff, error = xfs_bmapi_reserve_delalloc(ip, XFS_COW_FORK, imap->br_startoff,
end_fsb - imap->br_startoff, &got, &prev, &idx, eof); end_fsb - imap->br_startoff, &got, &idx, eof);
switch (error) { switch (error) {
case 0: case 0:
break; break;
@ -418,87 +420,65 @@ xfs_reflink_allocate_cow_range(
} }
/* /*
* Find the CoW reservation (and whether or not it needs block allocation) * Find the CoW reservation for a given byte offset of a file.
* for a given byte offset of a file.
*/ */
bool bool
xfs_reflink_find_cow_mapping( xfs_reflink_find_cow_mapping(
struct xfs_inode *ip, struct xfs_inode *ip,
xfs_off_t offset, xfs_off_t offset,
struct xfs_bmbt_irec *imap, struct xfs_bmbt_irec *imap)
bool *need_alloc)
{ {
struct xfs_bmbt_irec irec; struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
struct xfs_ifork *ifp; xfs_fileoff_t offset_fsb;
struct xfs_bmbt_rec_host *gotp; struct xfs_bmbt_irec got;
xfs_fileoff_t bno;
xfs_extnum_t idx; xfs_extnum_t idx;
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL | XFS_ILOCK_SHARED)); ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL | XFS_ILOCK_SHARED));
ASSERT(xfs_is_reflink_inode(ip)); ASSERT(xfs_is_reflink_inode(ip));
/* Find the extent in the CoW fork. */ offset_fsb = XFS_B_TO_FSBT(ip->i_mount, offset);
ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &idx, &got))
bno = XFS_B_TO_FSBT(ip->i_mount, offset);
gotp = xfs_iext_bno_to_ext(ifp, bno, &idx);
if (!gotp)
return false; return false;
if (got.br_startoff > offset_fsb)
xfs_bmbt_get_all(gotp, &irec);
if (bno >= irec.br_startoff + irec.br_blockcount ||
bno < irec.br_startoff)
return false; return false;
trace_xfs_reflink_find_cow_mapping(ip, offset, 1, XFS_IO_OVERWRITE, trace_xfs_reflink_find_cow_mapping(ip, offset, 1, XFS_IO_OVERWRITE,
&irec); &got);
*imap = got;
/* If it's still delalloc, we must allocate later. */
*imap = irec;
*need_alloc = !!(isnullstartblock(irec.br_startblock));
return true; return true;
} }
/* /*
* Trim an extent to end at the next CoW reservation past offset_fsb. * Trim an extent to end at the next CoW reservation past offset_fsb.
*/ */
int void
xfs_reflink_trim_irec_to_next_cow( xfs_reflink_trim_irec_to_next_cow(
struct xfs_inode *ip, struct xfs_inode *ip,
xfs_fileoff_t offset_fsb, xfs_fileoff_t offset_fsb,
struct xfs_bmbt_irec *imap) struct xfs_bmbt_irec *imap)
{ {
struct xfs_bmbt_irec irec; struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
struct xfs_ifork *ifp; struct xfs_bmbt_irec got;
struct xfs_bmbt_rec_host *gotp;
xfs_extnum_t idx; xfs_extnum_t idx;
if (!xfs_is_reflink_inode(ip)) if (!xfs_is_reflink_inode(ip))
return 0; return;
/* Find the extent in the CoW fork. */ /* Find the extent in the CoW fork. */
ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &idx, &got))
gotp = xfs_iext_bno_to_ext(ifp, offset_fsb, &idx); return;
if (!gotp)
return 0;
xfs_bmbt_get_all(gotp, &irec);
/* This is the extent before; try sliding up one. */ /* This is the extent before; try sliding up one. */
if (irec.br_startoff < offset_fsb) { if (got.br_startoff < offset_fsb) {
idx++; if (!xfs_iext_get_extent(ifp, idx + 1, &got))
if (idx >= xfs_iext_count(ifp)) return;
return 0;
gotp = xfs_iext_get_ext(ifp, idx);
xfs_bmbt_get_all(gotp, &irec);
} }
if (irec.br_startoff >= imap->br_startoff + imap->br_blockcount) if (got.br_startoff >= imap->br_startoff + imap->br_blockcount)
return 0; return;
imap->br_blockcount = irec.br_startoff - imap->br_startoff; imap->br_blockcount = got.br_startoff - imap->br_startoff;
trace_xfs_reflink_trim_irec(ip, imap); trace_xfs_reflink_trim_irec(ip, imap);
return 0;
} }
/* /*
@ -512,18 +492,15 @@ xfs_reflink_cancel_cow_blocks(
xfs_fileoff_t end_fsb) xfs_fileoff_t end_fsb)
{ {
struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
struct xfs_bmbt_irec got, prev, del; struct xfs_bmbt_irec got, del;
xfs_extnum_t idx; xfs_extnum_t idx;
xfs_fsblock_t firstfsb; xfs_fsblock_t firstfsb;
struct xfs_defer_ops dfops; struct xfs_defer_ops dfops;
int error = 0, eof = 0; int error = 0;
if (!xfs_is_reflink_inode(ip)) if (!xfs_is_reflink_inode(ip))
return 0; return 0;
if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &idx, &got))
xfs_bmap_search_extents(ip, offset_fsb, XFS_COW_FORK, &eof, &idx,
&got, &prev);
if (eof)
return 0; return 0;
while (got.br_startoff < end_fsb) { while (got.br_startoff < end_fsb) {
@ -566,9 +543,8 @@ xfs_reflink_cancel_cow_blocks(
xfs_bmap_del_extent_cow(ip, &idx, &got, &del); xfs_bmap_del_extent_cow(ip, &idx, &got, &del);
} }
if (++idx >= xfs_iext_count(ifp)) if (!xfs_iext_get_extent(ifp, ++idx, &got))
break; break;
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx), &got);
} }
/* clear tag if cow fork is emptied */ /* clear tag if cow fork is emptied */
@ -638,13 +614,13 @@ xfs_reflink_end_cow(
xfs_off_t count) xfs_off_t count)
{ {
struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
struct xfs_bmbt_irec got, prev, del; struct xfs_bmbt_irec got, del;
struct xfs_trans *tp; struct xfs_trans *tp;
xfs_fileoff_t offset_fsb; xfs_fileoff_t offset_fsb;
xfs_fileoff_t end_fsb; xfs_fileoff_t end_fsb;
xfs_fsblock_t firstfsb; xfs_fsblock_t firstfsb;
struct xfs_defer_ops dfops; struct xfs_defer_ops dfops;
int error, eof = 0; int error;
unsigned int resblks; unsigned int resblks;
xfs_filblks_t rlen; xfs_filblks_t rlen;
xfs_extnum_t idx; xfs_extnum_t idx;
@ -668,13 +644,11 @@ xfs_reflink_end_cow(
xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, ip, 0); xfs_trans_ijoin(tp, ip, 0);
xfs_bmap_search_extents(ip, end_fsb - 1, XFS_COW_FORK, &eof, &idx,
&got, &prev);
/* If there is a hole at end_fsb - 1 go to the previous extent */ /* If there is a hole at end_fsb - 1 go to the previous extent */
if (eof || got.br_startoff > end_fsb) { if (!xfs_iext_lookup_extent(ip, ifp, end_fsb - 1, &idx, &got) ||
got.br_startoff > end_fsb) {
ASSERT(idx > 0); ASSERT(idx > 0);
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, --idx), &got); xfs_iext_get_extent(ifp, --idx, &got);
} }
/* Walk backwards until we're out of the I/O range... */ /* Walk backwards until we're out of the I/O range... */
@ -722,11 +696,9 @@ xfs_reflink_end_cow(
error = xfs_defer_finish(&tp, &dfops, ip); error = xfs_defer_finish(&tp, &dfops, ip);
if (error) if (error)
goto out_defer; goto out_defer;
next_extent: next_extent:
if (idx < 0) if (!xfs_iext_get_extent(ifp, idx, &got))
break; break;
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx), &got);
} }
error = xfs_trans_commit(tp); error = xfs_trans_commit(tp);

View File

@ -31,8 +31,8 @@ extern int xfs_reflink_reserve_cow(struct xfs_inode *ip,
extern int xfs_reflink_allocate_cow_range(struct xfs_inode *ip, extern int xfs_reflink_allocate_cow_range(struct xfs_inode *ip,
xfs_off_t offset, xfs_off_t count); xfs_off_t offset, xfs_off_t count);
extern bool xfs_reflink_find_cow_mapping(struct xfs_inode *ip, xfs_off_t offset, extern bool xfs_reflink_find_cow_mapping(struct xfs_inode *ip, xfs_off_t offset,
struct xfs_bmbt_irec *imap, bool *need_alloc); struct xfs_bmbt_irec *imap);
extern int xfs_reflink_trim_irec_to_next_cow(struct xfs_inode *ip, extern void xfs_reflink_trim_irec_to_next_cow(struct xfs_inode *ip,
xfs_fileoff_t offset_fsb, struct xfs_bmbt_irec *imap); xfs_fileoff_t offset_fsb, struct xfs_bmbt_irec *imap);
extern int xfs_reflink_cancel_cow_blocks(struct xfs_inode *ip, extern int xfs_reflink_cancel_cow_blocks(struct xfs_inode *ip,