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 @@ xfs_bmap_read_extents(
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)
* in the file with at least "len" logically contiguous blocks free.
@ -1523,44 +1432,44 @@ xfs_bmap_first_unused(
*/
int /* error */
xfs_bmap_last_before(
xfs_trans_t *tp, /* transaction pointer */
xfs_inode_t *ip, /* incore inode */
xfs_fileoff_t *last_block, /* last block */
int whichfork) /* data or attr fork */
struct xfs_trans *tp, /* transaction pointer */
struct xfs_inode *ip, /* incore inode */
xfs_fileoff_t *last_block, /* last block */
int whichfork) /* data or attr fork */
{
xfs_fileoff_t bno; /* input file offset */
int eof; /* hit end of file */
xfs_bmbt_rec_host_t *ep; /* pointer to last extent */
int error; /* error return value */
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 */
struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork);
struct xfs_bmbt_irec got;
xfs_extnum_t idx;
int error;
if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL)
return -EIO;
if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
switch (XFS_IFORK_FORMAT(ip, whichfork)) {
case XFS_DINODE_FMT_LOCAL:
*last_block = 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) &&
(error = xfs_iread_extents(tp, ip, whichfork)))
return error;
bno = *last_block - 1;
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;
if (!(ifp->if_flags & XFS_IFEXTENTS)) {
error = xfs_iread_extents(tp, ip, whichfork);
if (error)
return error;
}
/*
* 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;
}
@ -4145,12 +4054,11 @@ xfs_bmapi_read(
struct xfs_mount *mp = ip->i_mount;
struct xfs_ifork *ifp;
struct xfs_bmbt_irec got;
struct xfs_bmbt_irec prev;
xfs_fileoff_t obno;
xfs_fileoff_t end;
xfs_extnum_t lastx;
xfs_extnum_t idx;
int error;
int eof;
bool eof = false;
int n = 0;
int whichfork = xfs_bmapi_whichfork(flags);
@ -4190,7 +4098,8 @@ xfs_bmapi_read(
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;
obno = bno;
@ -4221,10 +4130,8 @@ xfs_bmapi_read(
break;
/* Else go on to the next record. */
if (++lastx < xfs_iext_count(ifp))
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx), &got);
else
eof = 1;
if (!xfs_iext_get_extent(ifp, ++idx, &got))
eof = true;
}
*nmap = n;
return 0;
@ -4237,7 +4144,6 @@ xfs_bmapi_reserve_delalloc(
xfs_fileoff_t aoff,
xfs_filblks_t len,
struct xfs_bmbt_irec *got,
struct xfs_bmbt_irec *prev,
xfs_extnum_t *lastx,
int eof)
{
@ -4259,7 +4165,12 @@ xfs_bmapi_reserve_delalloc(
else
extsz = xfs_get_extsz_hint(ip);
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);
ASSERT(!error);
}
@ -4349,7 +4260,7 @@ xfs_bmapi_allocate(
if (bma->wasdel) {
bma->length = (xfs_extlen_t)bma->got.br_blockcount;
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),
&bma->prev);
}
@ -4563,7 +4474,7 @@ xfs_bmapi_write(
struct xfs_ifork *ifp;
struct xfs_bmalloca bma = { NULL }; /* args for xfs_bmap_alloc */
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 n; /* current extent index */
xfs_fileoff_t obno; /* old block number (offset) */
@ -4641,12 +4552,14 @@ xfs_bmapi_write(
goto error0;
}
xfs_bmap_search_extents(ip, bno, whichfork, &eof, &bma.idx, &bma.got,
&bma.prev);
n = 0;
end = bno + len;
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.ip = ip;
bma.total = total;
@ -4733,11 +4646,8 @@ xfs_bmapi_write(
/* Else go on to the next record. */
bma.prev = bma.got;
if (++bma.idx < xfs_iext_count(ifp)) {
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma.idx),
&bma.got);
} else
eof = 1;
if (!xfs_iext_get_extent(ifp, ++bma.idx, &bma.got))
eof = true;
}
*nmap = n;
@ -5436,8 +5346,6 @@ __xfs_bunmapi(
{
xfs_btree_cur_t *cur; /* bmap btree cursor */
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 */
xfs_extnum_t extno; /* extent number in list */
xfs_bmbt_irec_t got; /* current extent record */
@ -5447,7 +5355,6 @@ __xfs_bunmapi(
int logflags; /* transaction logging flags */
xfs_extlen_t mod; /* rt extent offset */
xfs_mount_t *mp; /* mount structure */
xfs_bmbt_irec_t prev; /* previous extent record */
xfs_fileoff_t start; /* first file offset deleted */
int tmp_logflags; /* partial logging flags */
int wasdel; /* was a delayed alloc extent */
@ -5486,18 +5393,17 @@ __xfs_bunmapi(
isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip);
start = bno;
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
* file, back up to the last block if so...
*/
if (eof) {
ep = xfs_iext_get_ext(ifp, --lastx);
xfs_bmbt_get_all(ep, &got);
if (!xfs_iext_lookup_extent(ip, ifp, bno, &lastx, &got)) {
ASSERT(lastx > 0);
xfs_iext_get_extent(ifp, --lastx, &got);
bno = got.br_startoff + got.br_blockcount - 1;
}
logflags = 0;
if (ifp->if_flags & XFS_IFBROOT) {
ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE);
@ -5528,8 +5434,7 @@ __xfs_bunmapi(
if (got.br_startoff > bno) {
if (--lastx < 0)
break;
ep = xfs_iext_get_ext(ifp, lastx);
xfs_bmbt_get_all(ep, &got);
xfs_iext_get_extent(ifp, lastx, &got);
}
/*
* Is the last block of this extent before the range
@ -5543,7 +5448,6 @@ __xfs_bunmapi(
* Then deal with the (possibly delayed) allocated space
* we found.
*/
ASSERT(ep != NULL);
del = got;
wasdel = isnullstartblock(del.br_startblock);
if (got.br_startoff < start) {
@ -5624,15 +5528,12 @@ __xfs_bunmapi(
*/
ASSERT(bno >= del.br_blockcount);
bno -= del.br_blockcount;
if (got.br_startoff > bno) {
if (--lastx >= 0) {
ep = xfs_iext_get_ext(ifp,
lastx);
xfs_bmbt_get_all(ep, &got);
}
}
if (got.br_startoff > bno && --lastx >= 0)
xfs_iext_get_extent(ifp, lastx, &got);
continue;
} else if (del.br_state == XFS_EXT_UNWRITTEN) {
struct xfs_bmbt_irec prev;
/*
* This one is already unwritten.
* It must have a written left neighbor.
@ -5640,8 +5541,7 @@ __xfs_bunmapi(
* try again.
*/
ASSERT(lastx > 0);
xfs_bmbt_get_all(xfs_iext_get_ext(ifp,
lastx - 1), &prev);
xfs_iext_get_extent(ifp, lastx - 1, &prev);
ASSERT(prev.br_state == XFS_EXT_NORM);
ASSERT(!isnullstartblock(prev.br_startblock));
ASSERT(del.br_startblock ==
@ -5739,13 +5639,9 @@ __xfs_bunmapi(
*/
if (bno != (xfs_fileoff_t)-1 && bno >= start) {
if (lastx >= 0) {
ep = xfs_iext_get_ext(ifp, lastx);
if (xfs_bmbt_get_startoff(ep) > bno) {
if (--lastx >= 0)
ep = xfs_iext_get_ext(ifp,
lastx);
}
xfs_bmbt_get_all(ep, &got);
xfs_iext_get_extent(ifp, lastx, &got);
if (got.br_startoff > bno && --lastx >= 0)
xfs_iext_get_extent(ifp, lastx, &got);
}
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,
int num_exts);
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,
xfs_fileoff_t aoff, xfs_filblks_t len,
struct xfs_bmbt_irec *got, struct xfs_bmbt_irec *prev,
xfs_extnum_t *lastx, int eof);
struct xfs_bmbt_irec *got, xfs_extnum_t *lastx, int eof);
enum xfs_bmap_intent_type {
XFS_BMAP_MAP = 1,

View file

@ -2003,3 +2003,49 @@ xfs_ifork_init_cow(
ip->i_cformat = XFS_DINODE_FMT_EXTENTS;
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_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 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 NULLAGNUMBER ((xfs_agnumber_t)-1)
#define NULLEXTNUM ((xfs_extnum_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_bmbt_irec imap;
bool is_cow = false, need_alloc = false;
bool is_cow = false;
int error;
/*
@ -795,7 +795,7 @@ xfs_map_cow(
* Else we need to check if there is a COW mapping at this offset.
*/
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);
if (!is_cow)
@ -805,7 +805,7 @@ xfs_map_cow(
* And if the COW mapping has a delayed extent here we need to
* allocate real space for it now.
*/
if (need_alloc) {
if (isnullstartblock(imap.br_startblock)) {
error = xfs_iomap_write_allocate(ip, XFS_COW_FORK, offset,
&imap);
if (error)
@ -1311,7 +1311,6 @@ __xfs_get_blocks(
ssize_t size;
int new = 0;
bool is_cow = false;
bool need_alloc = false;
BUG_ON(create && !direct);
@ -1337,9 +1336,11 @@ __xfs_get_blocks(
end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + size);
offset_fsb = XFS_B_TO_FSBT(mp, offset);
if (create && direct && xfs_is_reflink_inode(ip))
is_cow = xfs_reflink_find_cow_mapping(ip, offset, &imap,
&need_alloc);
if (create && direct && xfs_is_reflink_inode(ip)) {
is_cow = xfs_reflink_find_cow_mapping(ip, offset, &imap);
ASSERT(!is_cow || !isnullstartblock(imap.br_startblock));
}
if (!is_cow) {
error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb,
&imap, &nimaps, XFS_BMAPI_ENTIRE);
@ -1356,7 +1357,6 @@ __xfs_get_blocks(
xfs_reflink_trim_irec_to_next_cow(ip, offset_fsb,
&imap);
}
ASSERT(!need_alloc);
if (error)
goto out_unlock;

View file

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

View file

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