You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'for-linus-v3.8-rc1' of git://oss.sgi.com/xfs/xfs
Pull xfs update from Ben Myers: "There is plenty going on, including the cleanup of xfssyncd, metadata verifiers, CRC infrastructure for the log, tracking of inodes with speculative allocation, a cleanup of xfs_fs_subr.c, fixes for XFS_IOC_ZERO_RANGE, and important fix related to log replay (only update the last_sync_lsn when a transaction completes), a fix for deadlock on AGF buffers, documentation and comment updates, and a few more cleanups and fixes. Details: - remove the xfssyncd mess - only update the last_sync_lsn when a transaction completes - zero allocation_args on the kernel stack - fix AGF/alloc workqueue deadlock - silence uninitialised f.file warning - Update inode alloc comments - Update mount options documentation - report projid32bit feature in geometry call - speculative preallocation inode tracking - fix attr tree double split corruption - fix broken error handling in xfs_vm_writepage - drop buffer io reference when a bad bio is built - add more attribute tree trace points - growfs infrastructure changes for 3.8 - fs/xfs/xfs_fs_subr.c die die die - add CRC infrastructure - add CRC checks to the log - Remove description of nodelaylog mount option from xfs.txt - inode allocation should use unmapped buffers - byte range granularity for XFS_IOC_ZERO_RANGE - fix direct IO nested transaction deadlock - fix stray dquot unlock when reclaiming dquots - fix sparse reported log CRC endian issue" Fix up trivial conflict in fs/xfs/xfs_fsops.c due to the same patch having been applied twice (commitseaef854335and1375cb65e8: "xfs: growfs: don't read garbage for new secondary superblocks") with later updates to the affected code in the XFS tree. * tag 'for-linus-v3.8-rc1' of git://oss.sgi.com/xfs/xfs: (78 commits) xfs: fix sparse reported log CRC endian issue xfs: fix stray dquot unlock when reclaiming dquots xfs: fix direct IO nested transaction deadlock. xfs: byte range granularity for XFS_IOC_ZERO_RANGE xfs: inode allocation should use unmapped buffers. xfs: Remove the description of nodelaylog mount option from xfs.txt xfs: add CRC checks to the log xfs: add CRC infrastructure xfs: convert buffer verifiers to an ops structure. xfs: connect up write verifiers to new buffers xfs: add pre-write metadata buffer verifier callbacks xfs: add buffer pre-write callback xfs: Add verifiers to dir2 data readahead. xfs: add xfs_da_node verification xfs: factor and verify attr leaf reads xfs: factor dir2 leaf read xfs: factor out dir2 data block reading xfs: factor dir2 free block reading xfs: verify dir2 block format buffers xfs: factor dir2 block read operations ...
This commit is contained in:
@@ -43,7 +43,7 @@ When mounting an XFS filesystem, the following options are accepted.
|
||||
Issue command to let the block device reclaim space freed by the
|
||||
filesystem. This is useful for SSD devices, thinly provisioned
|
||||
LUNs and virtual machine images, but may have a performance
|
||||
impact. This option is incompatible with the nodelaylog option.
|
||||
impact.
|
||||
|
||||
dmapi
|
||||
Enable the DMAPI (Data Management API) event callouts.
|
||||
@@ -72,8 +72,15 @@ When mounting an XFS filesystem, the following options are accepted.
|
||||
Indicates that XFS is allowed to create inodes at any location
|
||||
in the filesystem, including those which will result in inode
|
||||
numbers occupying more than 32 bits of significance. This is
|
||||
provided for backwards compatibility, but causes problems for
|
||||
backup applications that cannot handle large inode numbers.
|
||||
the default allocation option. Applications which do not handle
|
||||
inode numbers bigger than 32 bits, should use inode32 option.
|
||||
|
||||
inode32
|
||||
Indicates that XFS is limited to create inodes at locations which
|
||||
will not result in inode numbers with more than 32 bits of
|
||||
significance. This is provided for backwards compatibility, since
|
||||
64 bits inode numbers might cause problems for some applications
|
||||
that cannot handle large inode numbers.
|
||||
|
||||
largeio/nolargeio
|
||||
If "nolargeio" is specified, the optimal I/O reported in
|
||||
|
||||
@@ -2,6 +2,7 @@ config XFS_FS
|
||||
tristate "XFS filesystem support"
|
||||
depends on BLOCK
|
||||
select EXPORTFS
|
||||
select LIBCRC32C
|
||||
help
|
||||
XFS is a high performance journaling filesystem which originated
|
||||
on the SGI IRIX platform. It is completely multi-threaded, can
|
||||
|
||||
+1
-3
@@ -37,9 +37,8 @@ xfs-y += xfs_aops.o \
|
||||
xfs_file.o \
|
||||
xfs_filestream.o \
|
||||
xfs_fsops.o \
|
||||
xfs_fs_subr.o \
|
||||
xfs_globals.o \
|
||||
xfs_iget.o \
|
||||
xfs_icache.o \
|
||||
xfs_ioctl.o \
|
||||
xfs_iomap.o \
|
||||
xfs_iops.o \
|
||||
@@ -47,7 +46,6 @@ xfs-y += xfs_aops.o \
|
||||
xfs_message.o \
|
||||
xfs_mru_cache.o \
|
||||
xfs_super.o \
|
||||
xfs_sync.o \
|
||||
xfs_xattr.o \
|
||||
xfs_rename.o \
|
||||
xfs_utils.o \
|
||||
|
||||
@@ -26,4 +26,10 @@ extern int uuid_is_nil(uuid_t *uuid);
|
||||
extern int uuid_equal(uuid_t *uuid1, uuid_t *uuid2);
|
||||
extern void uuid_getnodeuniq(uuid_t *uuid, int fsid [2]);
|
||||
|
||||
static inline void
|
||||
uuid_copy(uuid_t *dst, uuid_t *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(uuid_t));
|
||||
}
|
||||
|
||||
#endif /* __XFS_SUPPORT_UUID_H__ */
|
||||
|
||||
@@ -108,6 +108,8 @@ typedef struct xfs_agf {
|
||||
extern int xfs_read_agf(struct xfs_mount *mp, struct xfs_trans *tp,
|
||||
xfs_agnumber_t agno, int flags, struct xfs_buf **bpp);
|
||||
|
||||
extern const struct xfs_buf_ops xfs_agf_buf_ops;
|
||||
|
||||
/*
|
||||
* Size of the unlinked inode hash table in the agi.
|
||||
*/
|
||||
@@ -161,6 +163,8 @@ typedef struct xfs_agi {
|
||||
extern int xfs_read_agi(struct xfs_mount *mp, struct xfs_trans *tp,
|
||||
xfs_agnumber_t agno, struct xfs_buf **bpp);
|
||||
|
||||
extern const struct xfs_buf_ops xfs_agi_buf_ops;
|
||||
|
||||
/*
|
||||
* The third a.g. block contains the a.g. freelist, an array
|
||||
* of block pointers to blocks owned by the allocation btree code.
|
||||
@@ -233,6 +237,7 @@ typedef struct xfs_perag {
|
||||
#define XFS_ICI_NO_TAG (-1) /* special flag for an untagged lookup
|
||||
in xfs_inode_ag_iterator */
|
||||
#define XFS_ICI_RECLAIM_TAG 0 /* inode is to be reclaimed */
|
||||
#define XFS_ICI_EOFBLOCKS_TAG 1 /* inode has blocks beyond EOF */
|
||||
|
||||
#define XFS_AG_MAXLEVELS(mp) ((mp)->m_ag_maxlevels)
|
||||
#define XFS_MIN_FREELIST_RAW(bl,cl,mp) \
|
||||
|
||||
+113
-27
@@ -430,6 +430,60 @@ xfs_alloc_fixup_trees(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
xfs_agfl_verify(
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
#ifdef WHEN_CRCS_COME_ALONG
|
||||
/*
|
||||
* we cannot actually do any verification of the AGFL because mkfs does
|
||||
* not initialise the AGFL to zero or NULL. Hence the only valid part of
|
||||
* the AGFL is what the AGF says is active. We can't get to the AGF, so
|
||||
* we can't verify just those entries are valid.
|
||||
*
|
||||
* This problem goes away when the CRC format change comes along as that
|
||||
* requires the AGFL to be initialised by mkfs. At that point, we can
|
||||
* verify the blocks in the agfl -active or not- lie within the bounds
|
||||
* of the AG. Until then, just leave this check ifdef'd out.
|
||||
*/
|
||||
struct xfs_mount *mp = bp->b_target->bt_mount;
|
||||
struct xfs_agfl *agfl = XFS_BUF_TO_AGFL(bp);
|
||||
int agfl_ok = 1;
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < XFS_AGFL_SIZE(mp); i++) {
|
||||
if (be32_to_cpu(agfl->agfl_bno[i]) == NULLAGBLOCK ||
|
||||
be32_to_cpu(agfl->agfl_bno[i]) >= mp->m_sb.sb_agblocks)
|
||||
agfl_ok = 0;
|
||||
}
|
||||
|
||||
if (!agfl_ok) {
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, agfl);
|
||||
xfs_buf_ioerror(bp, EFSCORRUPTED);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
xfs_agfl_write_verify(
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
xfs_agfl_verify(bp);
|
||||
}
|
||||
|
||||
static void
|
||||
xfs_agfl_read_verify(
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
xfs_agfl_verify(bp);
|
||||
}
|
||||
|
||||
const struct xfs_buf_ops xfs_agfl_buf_ops = {
|
||||
.verify_read = xfs_agfl_read_verify,
|
||||
.verify_write = xfs_agfl_write_verify,
|
||||
};
|
||||
|
||||
/*
|
||||
* Read in the allocation group free block array.
|
||||
*/
|
||||
@@ -447,7 +501,7 @@ xfs_alloc_read_agfl(
|
||||
error = xfs_trans_read_buf(
|
||||
mp, tp, mp->m_ddev_targp,
|
||||
XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)),
|
||||
XFS_FSS_TO_BB(mp, 1), 0, &bp);
|
||||
XFS_FSS_TO_BB(mp, 1), 0, &bp, &xfs_agfl_buf_ops);
|
||||
if (error)
|
||||
return error;
|
||||
ASSERT(!xfs_buf_geterror(bp));
|
||||
@@ -2091,6 +2145,63 @@ xfs_alloc_put_freelist(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
xfs_agf_verify(
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
struct xfs_mount *mp = bp->b_target->bt_mount;
|
||||
struct xfs_agf *agf;
|
||||
int agf_ok;
|
||||
|
||||
agf = XFS_BUF_TO_AGF(bp);
|
||||
|
||||
agf_ok = agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
|
||||
XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) &&
|
||||
be32_to_cpu(agf->agf_freeblks) <= be32_to_cpu(agf->agf_length) &&
|
||||
be32_to_cpu(agf->agf_flfirst) < XFS_AGFL_SIZE(mp) &&
|
||||
be32_to_cpu(agf->agf_fllast) < XFS_AGFL_SIZE(mp) &&
|
||||
be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp);
|
||||
|
||||
/*
|
||||
* during growfs operations, the perag is not fully initialised,
|
||||
* so we can't use it for any useful checking. growfs ensures we can't
|
||||
* use it by using uncached buffers that don't have the perag attached
|
||||
* so we can detect and avoid this problem.
|
||||
*/
|
||||
if (bp->b_pag)
|
||||
agf_ok = agf_ok && be32_to_cpu(agf->agf_seqno) ==
|
||||
bp->b_pag->pag_agno;
|
||||
|
||||
if (xfs_sb_version_haslazysbcount(&mp->m_sb))
|
||||
agf_ok = agf_ok && be32_to_cpu(agf->agf_btreeblks) <=
|
||||
be32_to_cpu(agf->agf_length);
|
||||
|
||||
if (unlikely(XFS_TEST_ERROR(!agf_ok, mp, XFS_ERRTAG_ALLOC_READ_AGF,
|
||||
XFS_RANDOM_ALLOC_READ_AGF))) {
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, agf);
|
||||
xfs_buf_ioerror(bp, EFSCORRUPTED);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xfs_agf_read_verify(
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
xfs_agf_verify(bp);
|
||||
}
|
||||
|
||||
static void
|
||||
xfs_agf_write_verify(
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
xfs_agf_verify(bp);
|
||||
}
|
||||
|
||||
const struct xfs_buf_ops xfs_agf_buf_ops = {
|
||||
.verify_read = xfs_agf_read_verify,
|
||||
.verify_write = xfs_agf_write_verify,
|
||||
};
|
||||
|
||||
/*
|
||||
* Read in the allocation group header (free/alloc section).
|
||||
*/
|
||||
@@ -2102,44 +2213,19 @@ xfs_read_agf(
|
||||
int flags, /* XFS_BUF_ */
|
||||
struct xfs_buf **bpp) /* buffer for the ag freelist header */
|
||||
{
|
||||
struct xfs_agf *agf; /* ag freelist header */
|
||||
int agf_ok; /* set if agf is consistent */
|
||||
int error;
|
||||
|
||||
ASSERT(agno != NULLAGNUMBER);
|
||||
error = xfs_trans_read_buf(
|
||||
mp, tp, mp->m_ddev_targp,
|
||||
XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
|
||||
XFS_FSS_TO_BB(mp, 1), flags, bpp);
|
||||
XFS_FSS_TO_BB(mp, 1), flags, bpp, &xfs_agf_buf_ops);
|
||||
if (error)
|
||||
return error;
|
||||
if (!*bpp)
|
||||
return 0;
|
||||
|
||||
ASSERT(!(*bpp)->b_error);
|
||||
agf = XFS_BUF_TO_AGF(*bpp);
|
||||
|
||||
/*
|
||||
* Validate the magic number of the agf block.
|
||||
*/
|
||||
agf_ok =
|
||||
agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
|
||||
XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) &&
|
||||
be32_to_cpu(agf->agf_freeblks) <= be32_to_cpu(agf->agf_length) &&
|
||||
be32_to_cpu(agf->agf_flfirst) < XFS_AGFL_SIZE(mp) &&
|
||||
be32_to_cpu(agf->agf_fllast) < XFS_AGFL_SIZE(mp) &&
|
||||
be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp) &&
|
||||
be32_to_cpu(agf->agf_seqno) == agno;
|
||||
if (xfs_sb_version_haslazysbcount(&mp->m_sb))
|
||||
agf_ok = agf_ok && be32_to_cpu(agf->agf_btreeblks) <=
|
||||
be32_to_cpu(agf->agf_length);
|
||||
if (unlikely(XFS_TEST_ERROR(!agf_ok, mp, XFS_ERRTAG_ALLOC_READ_AGF,
|
||||
XFS_RANDOM_ALLOC_READ_AGF))) {
|
||||
XFS_CORRUPTION_ERROR("xfs_alloc_read_agf",
|
||||
XFS_ERRLEVEL_LOW, mp, agf);
|
||||
xfs_trans_brelse(tp, *bpp);
|
||||
return XFS_ERROR(EFSCORRUPTED);
|
||||
}
|
||||
xfs_buf_set_ref(*bpp, XFS_AGF_REF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -231,4 +231,7 @@ xfs_alloc_get_rec(
|
||||
xfs_extlen_t *len, /* output: length of extent */
|
||||
int *stat); /* output: success/failure */
|
||||
|
||||
extern const struct xfs_buf_ops xfs_agf_buf_ops;
|
||||
extern const struct xfs_buf_ops xfs_agfl_buf_ops;
|
||||
|
||||
#endif /* __XFS_ALLOC_H__ */
|
||||
|
||||
@@ -272,6 +272,82 @@ xfs_allocbt_key_diff(
|
||||
return (__int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock;
|
||||
}
|
||||
|
||||
static void
|
||||
xfs_allocbt_verify(
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
struct xfs_mount *mp = bp->b_target->bt_mount;
|
||||
struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
|
||||
struct xfs_perag *pag = bp->b_pag;
|
||||
unsigned int level;
|
||||
int sblock_ok; /* block passes checks */
|
||||
|
||||
/*
|
||||
* magic number and level verification
|
||||
*
|
||||
* During growfs operations, we can't verify the exact level as the
|
||||
* perag is not fully initialised and hence not attached to the buffer.
|
||||
* In this case, check against the maximum tree depth.
|
||||
*/
|
||||
level = be16_to_cpu(block->bb_level);
|
||||
switch (block->bb_magic) {
|
||||
case cpu_to_be32(XFS_ABTB_MAGIC):
|
||||
if (pag)
|
||||
sblock_ok = level < pag->pagf_levels[XFS_BTNUM_BNOi];
|
||||
else
|
||||
sblock_ok = level < mp->m_ag_maxlevels;
|
||||
break;
|
||||
case cpu_to_be32(XFS_ABTC_MAGIC):
|
||||
if (pag)
|
||||
sblock_ok = level < pag->pagf_levels[XFS_BTNUM_CNTi];
|
||||
else
|
||||
sblock_ok = level < mp->m_ag_maxlevels;
|
||||
break;
|
||||
default:
|
||||
sblock_ok = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* numrecs verification */
|
||||
sblock_ok = sblock_ok &&
|
||||
be16_to_cpu(block->bb_numrecs) <= mp->m_alloc_mxr[level != 0];
|
||||
|
||||
/* sibling pointer verification */
|
||||
sblock_ok = sblock_ok &&
|
||||
(block->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK) ||
|
||||
be32_to_cpu(block->bb_u.s.bb_leftsib) < mp->m_sb.sb_agblocks) &&
|
||||
block->bb_u.s.bb_leftsib &&
|
||||
(block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK) ||
|
||||
be32_to_cpu(block->bb_u.s.bb_rightsib) < mp->m_sb.sb_agblocks) &&
|
||||
block->bb_u.s.bb_rightsib;
|
||||
|
||||
if (!sblock_ok) {
|
||||
trace_xfs_btree_corrupt(bp, _RET_IP_);
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, block);
|
||||
xfs_buf_ioerror(bp, EFSCORRUPTED);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xfs_allocbt_read_verify(
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
xfs_allocbt_verify(bp);
|
||||
}
|
||||
|
||||
static void
|
||||
xfs_allocbt_write_verify(
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
xfs_allocbt_verify(bp);
|
||||
}
|
||||
|
||||
const struct xfs_buf_ops xfs_allocbt_buf_ops = {
|
||||
.verify_read = xfs_allocbt_read_verify,
|
||||
.verify_write = xfs_allocbt_write_verify,
|
||||
};
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
STATIC int
|
||||
xfs_allocbt_keys_inorder(
|
||||
@@ -327,6 +403,7 @@ static const struct xfs_btree_ops xfs_allocbt_ops = {
|
||||
.init_rec_from_cur = xfs_allocbt_init_rec_from_cur,
|
||||
.init_ptr_from_cur = xfs_allocbt_init_ptr_from_cur,
|
||||
.key_diff = xfs_allocbt_key_diff,
|
||||
.buf_ops = &xfs_allocbt_buf_ops,
|
||||
#ifdef DEBUG
|
||||
.keys_inorder = xfs_allocbt_keys_inorder,
|
||||
.recs_inorder = xfs_allocbt_recs_inorder,
|
||||
|
||||
@@ -93,4 +93,6 @@ extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *,
|
||||
xfs_agnumber_t, xfs_btnum_t);
|
||||
extern int xfs_allocbt_maxrecs(struct xfs_mount *, int, int);
|
||||
|
||||
extern const struct xfs_buf_ops xfs_allocbt_buf_ops;
|
||||
|
||||
#endif /* __XFS_ALLOC_BTREE_H__ */
|
||||
|
||||
+31
-54
@@ -124,7 +124,7 @@ xfs_setfilesize_trans_alloc(
|
||||
ioend->io_append_trans = tp;
|
||||
|
||||
/*
|
||||
* We will pass freeze protection with a transaction. So tell lockdep
|
||||
* We may pass freeze protection with a transaction. So tell lockdep
|
||||
* we released it.
|
||||
*/
|
||||
rwsem_release(&ioend->io_inode->i_sb->s_writers.lock_map[SB_FREEZE_FS-1],
|
||||
@@ -149,11 +149,13 @@ xfs_setfilesize(
|
||||
xfs_fsize_t isize;
|
||||
|
||||
/*
|
||||
* The transaction was allocated in the I/O submission thread,
|
||||
* thus we need to mark ourselves as beeing in a transaction
|
||||
* manually.
|
||||
* The transaction may have been allocated in the I/O submission thread,
|
||||
* thus we need to mark ourselves as beeing in a transaction manually.
|
||||
* Similarly for freeze protection.
|
||||
*/
|
||||
current_set_flags_nested(&tp->t_pflags, PF_FSTRANS);
|
||||
rwsem_acquire_read(&VFS_I(ip)->i_sb->s_writers.lock_map[SB_FREEZE_FS-1],
|
||||
0, 1, _THIS_IP_);
|
||||
|
||||
xfs_ilock(ip, XFS_ILOCK_EXCL);
|
||||
isize = xfs_new_eof(ip, ioend->io_offset + ioend->io_size);
|
||||
@@ -187,7 +189,8 @@ xfs_finish_ioend(
|
||||
|
||||
if (ioend->io_type == XFS_IO_UNWRITTEN)
|
||||
queue_work(mp->m_unwritten_workqueue, &ioend->io_work);
|
||||
else if (ioend->io_append_trans)
|
||||
else if (ioend->io_append_trans ||
|
||||
(ioend->io_isdirect && xfs_ioend_is_append(ioend)))
|
||||
queue_work(mp->m_data_workqueue, &ioend->io_work);
|
||||
else
|
||||
xfs_destroy_ioend(ioend);
|
||||
@@ -205,15 +208,6 @@ xfs_end_io(
|
||||
struct xfs_inode *ip = XFS_I(ioend->io_inode);
|
||||
int error = 0;
|
||||
|
||||
if (ioend->io_append_trans) {
|
||||
/*
|
||||
* We've got freeze protection passed with the transaction.
|
||||
* Tell lockdep about it.
|
||||
*/
|
||||
rwsem_acquire_read(
|
||||
&ioend->io_inode->i_sb->s_writers.lock_map[SB_FREEZE_FS-1],
|
||||
0, 1, _THIS_IP_);
|
||||
}
|
||||
if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
|
||||
ioend->io_error = -EIO;
|
||||
goto done;
|
||||
@@ -226,35 +220,31 @@ xfs_end_io(
|
||||
* range to normal written extens after the data I/O has finished.
|
||||
*/
|
||||
if (ioend->io_type == XFS_IO_UNWRITTEN) {
|
||||
/*
|
||||
* For buffered I/O we never preallocate a transaction when
|
||||
* doing the unwritten extent conversion, but for direct I/O
|
||||
* we do not know if we are converting an unwritten extent
|
||||
* or not at the point where we preallocate the transaction.
|
||||
*/
|
||||
if (ioend->io_append_trans) {
|
||||
ASSERT(ioend->io_isdirect);
|
||||
|
||||
current_set_flags_nested(
|
||||
&ioend->io_append_trans->t_pflags, PF_FSTRANS);
|
||||
xfs_trans_cancel(ioend->io_append_trans, 0);
|
||||
}
|
||||
|
||||
error = xfs_iomap_write_unwritten(ip, ioend->io_offset,
|
||||
ioend->io_size);
|
||||
if (error) {
|
||||
ioend->io_error = -error;
|
||||
ioend->io_size);
|
||||
} else if (ioend->io_isdirect && xfs_ioend_is_append(ioend)) {
|
||||
/*
|
||||
* For direct I/O we do not know if we need to allocate blocks
|
||||
* or not so we can't preallocate an append transaction as that
|
||||
* results in nested reservations and log space deadlocks. Hence
|
||||
* allocate the transaction here. While this is sub-optimal and
|
||||
* can block IO completion for some time, we're stuck with doing
|
||||
* it this way until we can pass the ioend to the direct IO
|
||||
* allocation callbacks and avoid nesting that way.
|
||||
*/
|
||||
error = xfs_setfilesize_trans_alloc(ioend);
|
||||
if (error)
|
||||
goto done;
|
||||
}
|
||||
error = xfs_setfilesize(ioend);
|
||||
} else if (ioend->io_append_trans) {
|
||||
error = xfs_setfilesize(ioend);
|
||||
if (error)
|
||||
ioend->io_error = -error;
|
||||
} else {
|
||||
ASSERT(!xfs_ioend_is_append(ioend));
|
||||
}
|
||||
|
||||
done:
|
||||
if (error)
|
||||
ioend->io_error = -error;
|
||||
xfs_destroy_ioend(ioend);
|
||||
}
|
||||
|
||||
@@ -1432,25 +1422,21 @@ xfs_vm_direct_IO(
|
||||
size_t size = iov_length(iov, nr_segs);
|
||||
|
||||
/*
|
||||
* We need to preallocate a transaction for a size update
|
||||
* here. In the case that this write both updates the size
|
||||
* and converts at least on unwritten extent we will cancel
|
||||
* the still clean transaction after the I/O has finished.
|
||||
* We cannot preallocate a size update transaction here as we
|
||||
* don't know whether allocation is necessary or not. Hence we
|
||||
* can only tell IO completion that one is necessary if we are
|
||||
* not doing unwritten extent conversion.
|
||||
*/
|
||||
iocb->private = ioend = xfs_alloc_ioend(inode, XFS_IO_DIRECT);
|
||||
if (offset + size > XFS_I(inode)->i_d.di_size) {
|
||||
ret = xfs_setfilesize_trans_alloc(ioend);
|
||||
if (ret)
|
||||
goto out_destroy_ioend;
|
||||
if (offset + size > XFS_I(inode)->i_d.di_size)
|
||||
ioend->io_isdirect = 1;
|
||||
}
|
||||
|
||||
ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov,
|
||||
offset, nr_segs,
|
||||
xfs_get_blocks_direct,
|
||||
xfs_end_io_direct_write, NULL, 0);
|
||||
if (ret != -EIOCBQUEUED && iocb->private)
|
||||
goto out_trans_cancel;
|
||||
goto out_destroy_ioend;
|
||||
} else {
|
||||
ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov,
|
||||
offset, nr_segs,
|
||||
@@ -1460,15 +1446,6 @@ xfs_vm_direct_IO(
|
||||
|
||||
return ret;
|
||||
|
||||
out_trans_cancel:
|
||||
if (ioend->io_append_trans) {
|
||||
current_set_flags_nested(&ioend->io_append_trans->t_pflags,
|
||||
PF_FSTRANS);
|
||||
rwsem_acquire_read(
|
||||
&inode->i_sb->s_writers.lock_map[SB_FREEZE_FS-1],
|
||||
0, 1, _THIS_IP_);
|
||||
xfs_trans_cancel(ioend->io_append_trans, 0);
|
||||
}
|
||||
out_destroy_ioend:
|
||||
xfs_destroy_ioend(ioend);
|
||||
return ret;
|
||||
@@ -1641,7 +1618,7 @@ xfs_vm_bmap(
|
||||
|
||||
trace_xfs_vm_bmap(XFS_I(inode));
|
||||
xfs_ilock(ip, XFS_IOLOCK_SHARED);
|
||||
xfs_flush_pages(ip, (xfs_off_t)0, -1, 0, FI_REMAPF);
|
||||
filemap_write_and_wait(mapping);
|
||||
xfs_iunlock(ip, XFS_IOLOCK_SHARED);
|
||||
return generic_block_bmap(mapping, block, xfs_get_blocks);
|
||||
}
|
||||
|
||||
+41
-62
@@ -903,11 +903,9 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
|
||||
*/
|
||||
dp = args->dp;
|
||||
args->blkno = 0;
|
||||
error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp,
|
||||
XFS_ATTR_FORK);
|
||||
error = xfs_attr_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
|
||||
if (error)
|
||||
return(error);
|
||||
ASSERT(bp != NULL);
|
||||
return error;
|
||||
|
||||
/*
|
||||
* Look up the given attribute in the leaf block. Figure out if
|
||||
@@ -1031,12 +1029,12 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
|
||||
* Read in the block containing the "old" attr, then
|
||||
* remove the "old" attr from that block (neat, huh!)
|
||||
*/
|
||||
error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1,
|
||||
&bp, XFS_ATTR_FORK);
|
||||
error = xfs_attr_leaf_read(args->trans, args->dp, args->blkno,
|
||||
-1, &bp);
|
||||
if (error)
|
||||
return(error);
|
||||
ASSERT(bp != NULL);
|
||||
(void)xfs_attr_leaf_remove(bp, args);
|
||||
return error;
|
||||
|
||||
xfs_attr_leaf_remove(bp, args);
|
||||
|
||||
/*
|
||||
* If the result is small enough, shrink it all into the inode.
|
||||
@@ -1100,20 +1098,17 @@ xfs_attr_leaf_removename(xfs_da_args_t *args)
|
||||
*/
|
||||
dp = args->dp;
|
||||
args->blkno = 0;
|
||||
error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp,
|
||||
XFS_ATTR_FORK);
|
||||
if (error) {
|
||||
return(error);
|
||||
}
|
||||
error = xfs_attr_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
ASSERT(bp != NULL);
|
||||
error = xfs_attr_leaf_lookup_int(bp, args);
|
||||
if (error == ENOATTR) {
|
||||
xfs_trans_brelse(args->trans, bp);
|
||||
return(error);
|
||||
}
|
||||
|
||||
(void)xfs_attr_leaf_remove(bp, args);
|
||||
xfs_attr_leaf_remove(bp, args);
|
||||
|
||||
/*
|
||||
* If the result is small enough, shrink it all into the inode.
|
||||
@@ -1155,12 +1150,12 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
|
||||
struct xfs_buf *bp;
|
||||
int error;
|
||||
|
||||
trace_xfs_attr_leaf_get(args);
|
||||
|
||||
args->blkno = 0;
|
||||
error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp,
|
||||
XFS_ATTR_FORK);
|
||||
error = xfs_attr_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
|
||||
if (error)
|
||||
return(error);
|
||||
ASSERT(bp != NULL);
|
||||
return error;
|
||||
|
||||
error = xfs_attr_leaf_lookup_int(bp, args);
|
||||
if (error != EEXIST) {
|
||||
@@ -1181,22 +1176,15 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
|
||||
STATIC int
|
||||
xfs_attr_leaf_list(xfs_attr_list_context_t *context)
|
||||
{
|
||||
xfs_attr_leafblock_t *leaf;
|
||||
int error;
|
||||
struct xfs_buf *bp;
|
||||
|
||||
trace_xfs_attr_leaf_list(context);
|
||||
|
||||
context->cursor->blkno = 0;
|
||||
error = xfs_da_read_buf(NULL, context->dp, 0, -1, &bp, XFS_ATTR_FORK);
|
||||
error = xfs_attr_leaf_read(NULL, context->dp, 0, -1, &bp);
|
||||
if (error)
|
||||
return XFS_ERROR(error);
|
||||
ASSERT(bp != NULL);
|
||||
leaf = bp->b_addr;
|
||||
if (unlikely(leaf->hdr.info.magic != cpu_to_be16(XFS_ATTR_LEAF_MAGIC))) {
|
||||
XFS_CORRUPTION_ERROR("xfs_attr_leaf_list", XFS_ERRLEVEL_LOW,
|
||||
context->dp->i_mount, leaf);
|
||||
xfs_trans_brelse(NULL, bp);
|
||||
return XFS_ERROR(EFSCORRUPTED);
|
||||
}
|
||||
|
||||
error = xfs_attr_leaf_list_int(bp, context);
|
||||
xfs_trans_brelse(NULL, bp);
|
||||
@@ -1600,12 +1588,9 @@ xfs_attr_node_removename(xfs_da_args_t *args)
|
||||
ASSERT(state->path.blk[0].bp);
|
||||
state->path.blk[0].bp = NULL;
|
||||
|
||||
error = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp,
|
||||
XFS_ATTR_FORK);
|
||||
error = xfs_attr_leaf_read(args->trans, args->dp, 0, -1, &bp);
|
||||
if (error)
|
||||
goto out;
|
||||
ASSERT((((xfs_attr_leafblock_t *)bp->b_addr)->hdr.info.magic) ==
|
||||
cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
|
||||
|
||||
if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
|
||||
xfs_bmap_init(args->flist, args->firstblock);
|
||||
@@ -1653,6 +1638,8 @@ xfs_attr_fillstate(xfs_da_state_t *state)
|
||||
xfs_da_state_blk_t *blk;
|
||||
int level;
|
||||
|
||||
trace_xfs_attr_fillstate(state->args);
|
||||
|
||||
/*
|
||||
* Roll down the "path" in the state structure, storing the on-disk
|
||||
* block number for those buffers in the "path".
|
||||
@@ -1699,6 +1686,8 @@ xfs_attr_refillstate(xfs_da_state_t *state)
|
||||
xfs_da_state_blk_t *blk;
|
||||
int level, error;
|
||||
|
||||
trace_xfs_attr_refillstate(state->args);
|
||||
|
||||
/*
|
||||
* Roll down the "path" in the state structure, storing the on-disk
|
||||
* block number for those buffers in the "path".
|
||||
@@ -1707,7 +1696,7 @@ xfs_attr_refillstate(xfs_da_state_t *state)
|
||||
ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
|
||||
for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
|
||||
if (blk->disk_blkno) {
|
||||
error = xfs_da_read_buf(state->args->trans,
|
||||
error = xfs_da_node_read(state->args->trans,
|
||||
state->args->dp,
|
||||
blk->blkno, blk->disk_blkno,
|
||||
&blk->bp, XFS_ATTR_FORK);
|
||||
@@ -1726,7 +1715,7 @@ xfs_attr_refillstate(xfs_da_state_t *state)
|
||||
ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
|
||||
for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
|
||||
if (blk->disk_blkno) {
|
||||
error = xfs_da_read_buf(state->args->trans,
|
||||
error = xfs_da_node_read(state->args->trans,
|
||||
state->args->dp,
|
||||
blk->blkno, blk->disk_blkno,
|
||||
&blk->bp, XFS_ATTR_FORK);
|
||||
@@ -1755,6 +1744,8 @@ xfs_attr_node_get(xfs_da_args_t *args)
|
||||
int error, retval;
|
||||
int i;
|
||||
|
||||
trace_xfs_attr_node_get(args);
|
||||
|
||||
state = xfs_da_state_alloc();
|
||||
state->args = args;
|
||||
state->mp = args->dp->i_mount;
|
||||
@@ -1804,6 +1795,8 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
|
||||
int error, i;
|
||||
struct xfs_buf *bp;
|
||||
|
||||
trace_xfs_attr_node_list(context);
|
||||
|
||||
cursor = context->cursor;
|
||||
cursor->initted = 1;
|
||||
|
||||
@@ -1814,7 +1807,7 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
|
||||
*/
|
||||
bp = NULL;
|
||||
if (cursor->blkno > 0) {
|
||||
error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1,
|
||||
error = xfs_da_node_read(NULL, context->dp, cursor->blkno, -1,
|
||||
&bp, XFS_ATTR_FORK);
|
||||
if ((error != 0) && (error != EFSCORRUPTED))
|
||||
return(error);
|
||||
@@ -1856,17 +1849,11 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
|
||||
if (bp == NULL) {
|
||||
cursor->blkno = 0;
|
||||
for (;;) {
|
||||
error = xfs_da_read_buf(NULL, context->dp,
|
||||
error = xfs_da_node_read(NULL, context->dp,
|
||||
cursor->blkno, -1, &bp,
|
||||
XFS_ATTR_FORK);
|
||||
if (error)
|
||||
return(error);
|
||||
if (unlikely(bp == NULL)) {
|
||||
XFS_ERROR_REPORT("xfs_attr_node_list(2)",
|
||||
XFS_ERRLEVEL_LOW,
|
||||
context->dp->i_mount);
|
||||
return(XFS_ERROR(EFSCORRUPTED));
|
||||
}
|
||||
node = bp->b_addr;
|
||||
if (node->hdr.info.magic ==
|
||||
cpu_to_be16(XFS_ATTR_LEAF_MAGIC))
|
||||
@@ -1907,14 +1894,6 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
|
||||
*/
|
||||
for (;;) {
|
||||
leaf = bp->b_addr;
|
||||
if (unlikely(leaf->hdr.info.magic !=
|
||||
cpu_to_be16(XFS_ATTR_LEAF_MAGIC))) {
|
||||
XFS_CORRUPTION_ERROR("xfs_attr_node_list(4)",
|
||||
XFS_ERRLEVEL_LOW,
|
||||
context->dp->i_mount, leaf);
|
||||
xfs_trans_brelse(NULL, bp);
|
||||
return(XFS_ERROR(EFSCORRUPTED));
|
||||
}
|
||||
error = xfs_attr_leaf_list_int(bp, context);
|
||||
if (error) {
|
||||
xfs_trans_brelse(NULL, bp);
|
||||
@@ -1924,16 +1903,10 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
|
||||
break;
|
||||
cursor->blkno = be32_to_cpu(leaf->hdr.info.forw);
|
||||
xfs_trans_brelse(NULL, bp);
|
||||
error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1,
|
||||
&bp, XFS_ATTR_FORK);
|
||||
error = xfs_attr_leaf_read(NULL, context->dp, cursor->blkno, -1,
|
||||
&bp);
|
||||
if (error)
|
||||
return(error);
|
||||
if (unlikely((bp == NULL))) {
|
||||
XFS_ERROR_REPORT("xfs_attr_node_list(5)",
|
||||
XFS_ERRLEVEL_LOW,
|
||||
context->dp->i_mount);
|
||||
return(XFS_ERROR(EFSCORRUPTED));
|
||||
}
|
||||
return error;
|
||||
}
|
||||
xfs_trans_brelse(NULL, bp);
|
||||
return(0);
|
||||
@@ -1959,6 +1932,8 @@ xfs_attr_rmtval_get(xfs_da_args_t *args)
|
||||
int nmap, error, tmp, valuelen, blkcnt, i;
|
||||
xfs_dablk_t lblkno;
|
||||
|
||||
trace_xfs_attr_rmtval_get(args);
|
||||
|
||||
ASSERT(!(args->flags & ATTR_KERNOVAL));
|
||||
|
||||
mp = args->dp->i_mount;
|
||||
@@ -1980,7 +1955,7 @@ xfs_attr_rmtval_get(xfs_da_args_t *args)
|
||||
dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
|
||||
blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
|
||||
error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
|
||||
dblkno, blkcnt, 0, &bp);
|
||||
dblkno, blkcnt, 0, &bp, NULL);
|
||||
if (error)
|
||||
return(error);
|
||||
|
||||
@@ -2014,6 +1989,8 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
|
||||
xfs_dablk_t lblkno;
|
||||
int blkcnt, valuelen, nmap, error, tmp, committed;
|
||||
|
||||
trace_xfs_attr_rmtval_set(args);
|
||||
|
||||
dp = args->dp;
|
||||
mp = dp->i_mount;
|
||||
src = args->value;
|
||||
@@ -2143,6 +2120,8 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
|
||||
xfs_dablk_t lblkno;
|
||||
int valuelen, blkcnt, nmap, error, done, committed;
|
||||
|
||||
trace_xfs_attr_rmtval_remove(args);
|
||||
|
||||
mp = args->dp->i_mount;
|
||||
|
||||
/*
|
||||
|
||||
+89
-54
@@ -57,7 +57,8 @@ STATIC int xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t which_block,
|
||||
struct xfs_buf **bpp);
|
||||
STATIC int xfs_attr_leaf_add_work(struct xfs_buf *leaf_buffer,
|
||||
xfs_da_args_t *args, int freemap_index);
|
||||
STATIC void xfs_attr_leaf_compact(xfs_trans_t *tp, struct xfs_buf *leaf_buffer);
|
||||
STATIC void xfs_attr_leaf_compact(struct xfs_da_args *args,
|
||||
struct xfs_buf *leaf_buffer);
|
||||
STATIC void xfs_attr_leaf_rebalance(xfs_da_state_t *state,
|
||||
xfs_da_state_blk_t *blk1,
|
||||
xfs_da_state_blk_t *blk2);
|
||||
@@ -87,6 +88,52 @@ STATIC void xfs_attr_leaf_moveents(xfs_attr_leafblock_t *src_leaf,
|
||||
xfs_mount_t *mp);
|
||||
STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index);
|
||||
|
||||
static void
|
||||
xfs_attr_leaf_verify(
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
struct xfs_mount *mp = bp->b_target->bt_mount;
|
||||
struct xfs_attr_leaf_hdr *hdr = bp->b_addr;
|
||||
int block_ok = 0;
|
||||
|
||||
block_ok = hdr->info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC);
|
||||
if (!block_ok) {
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, hdr);
|
||||
xfs_buf_ioerror(bp, EFSCORRUPTED);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xfs_attr_leaf_read_verify(
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
xfs_attr_leaf_verify(bp);
|
||||
}
|
||||
|
||||
static void
|
||||
xfs_attr_leaf_write_verify(
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
xfs_attr_leaf_verify(bp);
|
||||
}
|
||||
|
||||
const struct xfs_buf_ops xfs_attr_leaf_buf_ops = {
|
||||
.verify_read = xfs_attr_leaf_read_verify,
|
||||
.verify_write = xfs_attr_leaf_write_verify,
|
||||
};
|
||||
|
||||
int
|
||||
xfs_attr_leaf_read(
|
||||
struct xfs_trans *tp,
|
||||
struct xfs_inode *dp,
|
||||
xfs_dablk_t bno,
|
||||
xfs_daddr_t mappedbno,
|
||||
struct xfs_buf **bpp)
|
||||
{
|
||||
return xfs_da_read_buf(tp, dp, bno, mappedbno, bpp,
|
||||
XFS_ATTR_FORK, &xfs_attr_leaf_buf_ops);
|
||||
}
|
||||
|
||||
/*========================================================================
|
||||
* Namespace helper routines
|
||||
*========================================================================*/
|
||||
@@ -869,17 +916,16 @@ xfs_attr_leaf_to_node(xfs_da_args_t *args)
|
||||
error = xfs_da_grow_inode(args, &blkno);
|
||||
if (error)
|
||||
goto out;
|
||||
error = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp1,
|
||||
XFS_ATTR_FORK);
|
||||
error = xfs_attr_leaf_read(args->trans, args->dp, 0, -1, &bp1);
|
||||
if (error)
|
||||
goto out;
|
||||
ASSERT(bp1 != NULL);
|
||||
|
||||
bp2 = NULL;
|
||||
error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp2,
|
||||
XFS_ATTR_FORK);
|
||||
if (error)
|
||||
goto out;
|
||||
ASSERT(bp2 != NULL);
|
||||
bp2->b_ops = bp1->b_ops;
|
||||
memcpy(bp2->b_addr, bp1->b_addr, XFS_LBSIZE(dp->i_mount));
|
||||
bp1 = NULL;
|
||||
xfs_trans_log_buf(args->trans, bp2, 0, XFS_LBSIZE(dp->i_mount) - 1);
|
||||
@@ -933,7 +979,7 @@ xfs_attr_leaf_create(
|
||||
XFS_ATTR_FORK);
|
||||
if (error)
|
||||
return(error);
|
||||
ASSERT(bp != NULL);
|
||||
bp->b_ops = &xfs_attr_leaf_buf_ops;
|
||||
leaf = bp->b_addr;
|
||||
memset((char *)leaf, 0, XFS_LBSIZE(dp->i_mount));
|
||||
hdr = &leaf->hdr;
|
||||
@@ -1071,7 +1117,7 @@ xfs_attr_leaf_add(
|
||||
* Compact the entries to coalesce free space.
|
||||
* This may change the hdr->count via dropping INCOMPLETE entries.
|
||||
*/
|
||||
xfs_attr_leaf_compact(args->trans, bp);
|
||||
xfs_attr_leaf_compact(args, bp);
|
||||
|
||||
/*
|
||||
* After compaction, the block is guaranteed to have only one
|
||||
@@ -1102,6 +1148,8 @@ xfs_attr_leaf_add_work(
|
||||
xfs_mount_t *mp;
|
||||
int tmp, i;
|
||||
|
||||
trace_xfs_attr_leaf_add_work(args);
|
||||
|
||||
leaf = bp->b_addr;
|
||||
ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
|
||||
hdr = &leaf->hdr;
|
||||
@@ -1214,15 +1262,17 @@ xfs_attr_leaf_add_work(
|
||||
*/
|
||||
STATIC void
|
||||
xfs_attr_leaf_compact(
|
||||
struct xfs_trans *trans,
|
||||
struct xfs_buf *bp)
|
||||
struct xfs_da_args *args,
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
xfs_attr_leafblock_t *leaf_s, *leaf_d;
|
||||
xfs_attr_leaf_hdr_t *hdr_s, *hdr_d;
|
||||
xfs_mount_t *mp;
|
||||
char *tmpbuffer;
|
||||
xfs_attr_leafblock_t *leaf_s, *leaf_d;
|
||||
xfs_attr_leaf_hdr_t *hdr_s, *hdr_d;
|
||||
struct xfs_trans *trans = args->trans;
|
||||
struct xfs_mount *mp = trans->t_mountp;
|
||||
char *tmpbuffer;
|
||||
|
||||
trace_xfs_attr_leaf_compact(args);
|
||||
|
||||
mp = trans->t_mountp;
|
||||
tmpbuffer = kmem_alloc(XFS_LBSIZE(mp), KM_SLEEP);
|
||||
ASSERT(tmpbuffer != NULL);
|
||||
memcpy(tmpbuffer, bp->b_addr, XFS_LBSIZE(mp));
|
||||
@@ -1345,9 +1395,8 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
|
||||
max = be16_to_cpu(hdr2->firstused)
|
||||
- sizeof(xfs_attr_leaf_hdr_t);
|
||||
max -= be16_to_cpu(hdr2->count) * sizeof(xfs_attr_leaf_entry_t);
|
||||
if (space > max) {
|
||||
xfs_attr_leaf_compact(args->trans, blk2->bp);
|
||||
}
|
||||
if (space > max)
|
||||
xfs_attr_leaf_compact(args, blk2->bp);
|
||||
|
||||
/*
|
||||
* Move high entries from leaf1 to low end of leaf2.
|
||||
@@ -1378,9 +1427,8 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
|
||||
max = be16_to_cpu(hdr1->firstused)
|
||||
- sizeof(xfs_attr_leaf_hdr_t);
|
||||
max -= be16_to_cpu(hdr1->count) * sizeof(xfs_attr_leaf_entry_t);
|
||||
if (space > max) {
|
||||
xfs_attr_leaf_compact(args->trans, blk1->bp);
|
||||
}
|
||||
if (space > max)
|
||||
xfs_attr_leaf_compact(args, blk1->bp);
|
||||
|
||||
/*
|
||||
* Move low entries from leaf2 to high end of leaf1.
|
||||
@@ -1577,6 +1625,8 @@ xfs_attr_leaf_toosmall(xfs_da_state_t *state, int *action)
|
||||
xfs_dablk_t blkno;
|
||||
struct xfs_buf *bp;
|
||||
|
||||
trace_xfs_attr_leaf_toosmall(state->args);
|
||||
|
||||
/*
|
||||
* Check for the degenerate case of the block being over 50% full.
|
||||
* If so, it's not worth even looking to see if we might be able
|
||||
@@ -1636,18 +1686,16 @@ xfs_attr_leaf_toosmall(xfs_da_state_t *state, int *action)
|
||||
blkno = be32_to_cpu(info->back);
|
||||
if (blkno == 0)
|
||||
continue;
|
||||
error = xfs_da_read_buf(state->args->trans, state->args->dp,
|
||||
blkno, -1, &bp, XFS_ATTR_FORK);
|
||||
error = xfs_attr_leaf_read(state->args->trans, state->args->dp,
|
||||
blkno, -1, &bp);
|
||||
if (error)
|
||||
return(error);
|
||||
ASSERT(bp != NULL);
|
||||
|
||||
leaf = (xfs_attr_leafblock_t *)info;
|
||||
count = be16_to_cpu(leaf->hdr.count);
|
||||
bytes = state->blocksize - (state->blocksize>>2);
|
||||
bytes -= be16_to_cpu(leaf->hdr.usedbytes);
|
||||
leaf = bp->b_addr;
|
||||
ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
|
||||
count += be16_to_cpu(leaf->hdr.count);
|
||||
bytes -= be16_to_cpu(leaf->hdr.usedbytes);
|
||||
bytes -= count * sizeof(xfs_attr_leaf_entry_t);
|
||||
@@ -1702,6 +1750,8 @@ xfs_attr_leaf_remove(
|
||||
int tablesize, tmp, i;
|
||||
xfs_mount_t *mp;
|
||||
|
||||
trace_xfs_attr_leaf_remove(args);
|
||||
|
||||
leaf = bp->b_addr;
|
||||
ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
|
||||
hdr = &leaf->hdr;
|
||||
@@ -2511,15 +2561,11 @@ xfs_attr_leaf_clearflag(xfs_da_args_t *args)
|
||||
/*
|
||||
* Set up the operation.
|
||||
*/
|
||||
error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp,
|
||||
XFS_ATTR_FORK);
|
||||
if (error) {
|
||||
error = xfs_attr_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
|
||||
if (error)
|
||||
return(error);
|
||||
}
|
||||
ASSERT(bp != NULL);
|
||||
|
||||
leaf = bp->b_addr;
|
||||
ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
|
||||
ASSERT(args->index < be16_to_cpu(leaf->hdr.count));
|
||||
ASSERT(args->index >= 0);
|
||||
entry = &leaf->entries[ args->index ];
|
||||
@@ -2576,15 +2622,11 @@ xfs_attr_leaf_setflag(xfs_da_args_t *args)
|
||||
/*
|
||||
* Set up the operation.
|
||||
*/
|
||||
error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp,
|
||||
XFS_ATTR_FORK);
|
||||
if (error) {
|
||||
error = xfs_attr_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
|
||||
if (error)
|
||||
return(error);
|
||||
}
|
||||
ASSERT(bp != NULL);
|
||||
|
||||
leaf = bp->b_addr;
|
||||
ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
|
||||
ASSERT(args->index < be16_to_cpu(leaf->hdr.count));
|
||||
ASSERT(args->index >= 0);
|
||||
entry = &leaf->entries[ args->index ];
|
||||
@@ -2633,35 +2675,28 @@ xfs_attr_leaf_flipflags(xfs_da_args_t *args)
|
||||
/*
|
||||
* Read the block containing the "old" attr
|
||||
*/
|
||||
error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp1,
|
||||
XFS_ATTR_FORK);
|
||||
if (error) {
|
||||
return(error);
|
||||
}
|
||||
ASSERT(bp1 != NULL);
|
||||
error = xfs_attr_leaf_read(args->trans, args->dp, args->blkno, -1, &bp1);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* Read the block containing the "new" attr, if it is different
|
||||
*/
|
||||
if (args->blkno2 != args->blkno) {
|
||||
error = xfs_da_read_buf(args->trans, args->dp, args->blkno2,
|
||||
-1, &bp2, XFS_ATTR_FORK);
|
||||
if (error) {
|
||||
return(error);
|
||||
}
|
||||
ASSERT(bp2 != NULL);
|
||||
error = xfs_attr_leaf_read(args->trans, args->dp, args->blkno2,
|
||||
-1, &bp2);
|
||||
if (error)
|
||||
return error;
|
||||
} else {
|
||||
bp2 = bp1;
|
||||
}
|
||||
|
||||
leaf1 = bp1->b_addr;
|
||||
ASSERT(leaf1->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
|
||||
ASSERT(args->index < be16_to_cpu(leaf1->hdr.count));
|
||||
ASSERT(args->index >= 0);
|
||||
entry1 = &leaf1->entries[ args->index ];
|
||||
|
||||
leaf2 = bp2->b_addr;
|
||||
ASSERT(leaf2->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
|
||||
ASSERT(args->index2 < be16_to_cpu(leaf2->hdr.count));
|
||||
ASSERT(args->index2 >= 0);
|
||||
entry2 = &leaf2->entries[ args->index2 ];
|
||||
@@ -2746,7 +2781,7 @@ xfs_attr_root_inactive(xfs_trans_t **trans, xfs_inode_t *dp)
|
||||
* the extents in reverse order the extent containing
|
||||
* block 0 must still be there.
|
||||
*/
|
||||
error = xfs_da_read_buf(*trans, dp, 0, -1, &bp, XFS_ATTR_FORK);
|
||||
error = xfs_da_node_read(*trans, dp, 0, -1, &bp, XFS_ATTR_FORK);
|
||||
if (error)
|
||||
return(error);
|
||||
blkno = XFS_BUF_ADDR(bp);
|
||||
@@ -2831,7 +2866,7 @@ xfs_attr_node_inactive(
|
||||
* traversal of the tree so we may deal with many blocks
|
||||
* before we come back to this one.
|
||||
*/
|
||||
error = xfs_da_read_buf(*trans, dp, child_fsb, -2, &child_bp,
|
||||
error = xfs_da_node_read(*trans, dp, child_fsb, -2, &child_bp,
|
||||
XFS_ATTR_FORK);
|
||||
if (error)
|
||||
return(error);
|
||||
@@ -2872,8 +2907,8 @@ xfs_attr_node_inactive(
|
||||
* child block number.
|
||||
*/
|
||||
if ((i+1) < count) {
|
||||
error = xfs_da_read_buf(*trans, dp, 0, parent_blkno,
|
||||
&bp, XFS_ATTR_FORK);
|
||||
error = xfs_da_node_read(*trans, dp, 0, parent_blkno,
|
||||
&bp, XFS_ATTR_FORK);
|
||||
if (error)
|
||||
return(error);
|
||||
child_fsb = be32_to_cpu(node->btree[i+1].before);
|
||||
|
||||
@@ -261,4 +261,10 @@ int xfs_attr_leaf_order(struct xfs_buf *leaf1_bp,
|
||||
struct xfs_buf *leaf2_bp);
|
||||
int xfs_attr_leaf_newentsize(int namelen, int valuelen, int blocksize,
|
||||
int *local);
|
||||
int xfs_attr_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp,
|
||||
xfs_dablk_t bno, xfs_daddr_t mappedbno,
|
||||
struct xfs_buf **bpp);
|
||||
|
||||
extern const struct xfs_buf_ops xfs_attr_leaf_buf_ops;
|
||||
|
||||
#endif /* __XFS_ATTR_LEAF_H__ */
|
||||
|
||||
+39
-25
@@ -2662,8 +2662,9 @@ xfs_bmap_btree_to_extents(
|
||||
if ((error = xfs_btree_check_lptr(cur, cbno, 1)))
|
||||
return error;
|
||||
#endif
|
||||
if ((error = xfs_btree_read_bufl(mp, tp, cbno, 0, &cbp,
|
||||
XFS_BMAP_BTREE_REF)))
|
||||
error = xfs_btree_read_bufl(mp, tp, cbno, 0, &cbp, XFS_BMAP_BTREE_REF,
|
||||
&xfs_bmbt_buf_ops);
|
||||
if (error)
|
||||
return error;
|
||||
cblock = XFS_BUF_TO_BLOCK(cbp);
|
||||
if ((error = xfs_btree_check_block(cur, cblock, 0, cbp)))
|
||||
@@ -3123,6 +3124,7 @@ xfs_bmap_extents_to_btree(
|
||||
/*
|
||||
* Fill in the child block.
|
||||
*/
|
||||
abp->b_ops = &xfs_bmbt_buf_ops;
|
||||
ablock = XFS_BUF_TO_BLOCK(abp);
|
||||
ablock->bb_magic = cpu_to_be32(XFS_BMAP_MAGIC);
|
||||
ablock->bb_level = 0;
|
||||
@@ -3269,6 +3271,7 @@ xfs_bmap_local_to_extents(
|
||||
ASSERT(args.len == 1);
|
||||
*firstblock = args.fsbno;
|
||||
bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0);
|
||||
bp->b_ops = &xfs_bmbt_buf_ops;
|
||||
memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
|
||||
xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
|
||||
xfs_bmap_forkoff_reset(args.mp, ip, whichfork);
|
||||
@@ -4078,8 +4081,9 @@ xfs_bmap_read_extents(
|
||||
* pointer (leftmost) at each level.
|
||||
*/
|
||||
while (level-- > 0) {
|
||||
if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp,
|
||||
XFS_BMAP_BTREE_REF)))
|
||||
error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp,
|
||||
XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops);
|
||||
if (error)
|
||||
return error;
|
||||
block = XFS_BUF_TO_BLOCK(bp);
|
||||
XFS_WANT_CORRUPTED_GOTO(
|
||||
@@ -4124,7 +4128,8 @@ xfs_bmap_read_extents(
|
||||
*/
|
||||
nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
|
||||
if (nextbno != NULLFSBLOCK)
|
||||
xfs_btree_reada_bufl(mp, nextbno, 1);
|
||||
xfs_btree_reada_bufl(mp, nextbno, 1,
|
||||
&xfs_bmbt_buf_ops);
|
||||
/*
|
||||
* Copy records into the extent records.
|
||||
*/
|
||||
@@ -4156,8 +4161,9 @@ xfs_bmap_read_extents(
|
||||
*/
|
||||
if (bno == NULLFSBLOCK)
|
||||
break;
|
||||
if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp,
|
||||
XFS_BMAP_BTREE_REF)))
|
||||
error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp,
|
||||
XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops);
|
||||
if (error)
|
||||
return error;
|
||||
block = XFS_BUF_TO_BLOCK(bp);
|
||||
}
|
||||
@@ -5599,7 +5605,7 @@ xfs_getbmap(
|
||||
xfs_ilock(ip, XFS_IOLOCK_SHARED);
|
||||
if (whichfork == XFS_DATA_FORK && !(iflags & BMV_IF_DELALLOC)) {
|
||||
if (ip->i_delayed_blks || XFS_ISIZE(ip) > ip->i_d.di_size) {
|
||||
error = xfs_flush_pages(ip, 0, -1, 0, FI_REMAPF);
|
||||
error = -filemap_write_and_wait(VFS_I(ip)->i_mapping);
|
||||
if (error)
|
||||
goto out_unlock_iolock;
|
||||
}
|
||||
@@ -5868,15 +5874,16 @@ xfs_bmap_check_leaf_extents(
|
||||
*/
|
||||
while (level-- > 0) {
|
||||
/* See if buf is in cur first */
|
||||
bp_release = 0;
|
||||
bp = xfs_bmap_get_bp(cur, XFS_FSB_TO_DADDR(mp, bno));
|
||||
if (bp) {
|
||||
bp_release = 0;
|
||||
} else {
|
||||
if (!bp) {
|
||||
bp_release = 1;
|
||||
error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp,
|
||||
XFS_BMAP_BTREE_REF,
|
||||
&xfs_bmbt_buf_ops);
|
||||
if (error)
|
||||
goto error_norelse;
|
||||
}
|
||||
if (!bp && (error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp,
|
||||
XFS_BMAP_BTREE_REF)))
|
||||
goto error_norelse;
|
||||
block = XFS_BUF_TO_BLOCK(bp);
|
||||
XFS_WANT_CORRUPTED_GOTO(
|
||||
xfs_bmap_sanity_check(mp, bp, level),
|
||||
@@ -5953,15 +5960,16 @@ xfs_bmap_check_leaf_extents(
|
||||
if (bno == NULLFSBLOCK)
|
||||
break;
|
||||
|
||||
bp_release = 0;
|
||||
bp = xfs_bmap_get_bp(cur, XFS_FSB_TO_DADDR(mp, bno));
|
||||
if (bp) {
|
||||
bp_release = 0;
|
||||
} else {
|
||||
if (!bp) {
|
||||
bp_release = 1;
|
||||
error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp,
|
||||
XFS_BMAP_BTREE_REF,
|
||||
&xfs_bmbt_buf_ops);
|
||||
if (error)
|
||||
goto error_norelse;
|
||||
}
|
||||
if (!bp && (error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp,
|
||||
XFS_BMAP_BTREE_REF)))
|
||||
goto error_norelse;
|
||||
block = XFS_BUF_TO_BLOCK(bp);
|
||||
}
|
||||
if (bp_release) {
|
||||
@@ -6052,7 +6060,9 @@ xfs_bmap_count_tree(
|
||||
struct xfs_btree_block *block, *nextblock;
|
||||
int numrecs;
|
||||
|
||||
if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, XFS_BMAP_BTREE_REF)))
|
||||
error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, XFS_BMAP_BTREE_REF,
|
||||
&xfs_bmbt_buf_ops);
|
||||
if (error)
|
||||
return error;
|
||||
*count += 1;
|
||||
block = XFS_BUF_TO_BLOCK(bp);
|
||||
@@ -6061,8 +6071,10 @@ xfs_bmap_count_tree(
|
||||
/* Not at node above leaves, count this level of nodes */
|
||||
nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
|
||||
while (nextbno != NULLFSBLOCK) {
|
||||
if ((error = xfs_btree_read_bufl(mp, tp, nextbno,
|
||||
0, &nbp, XFS_BMAP_BTREE_REF)))
|
||||
error = xfs_btree_read_bufl(mp, tp, nextbno, 0, &nbp,
|
||||
XFS_BMAP_BTREE_REF,
|
||||
&xfs_bmbt_buf_ops);
|
||||
if (error)
|
||||
return error;
|
||||
*count += 1;
|
||||
nextblock = XFS_BUF_TO_BLOCK(nbp);
|
||||
@@ -6091,8 +6103,10 @@ xfs_bmap_count_tree(
|
||||
if (nextbno == NULLFSBLOCK)
|
||||
break;
|
||||
bno = nextbno;
|
||||
if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp,
|
||||
XFS_BMAP_BTREE_REF)))
|
||||
error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp,
|
||||
XFS_BMAP_BTREE_REF,
|
||||
&xfs_bmbt_buf_ops);
|
||||
if (error)
|
||||
return error;
|
||||
*count += 1;
|
||||
block = XFS_BUF_TO_BLOCK(bp);
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "xfs_bmap.h"
|
||||
#include "xfs_error.h"
|
||||
#include "xfs_quota.h"
|
||||
#include "xfs_trace.h"
|
||||
|
||||
/*
|
||||
* Determine the extent state.
|
||||
@@ -707,6 +708,67 @@ xfs_bmbt_key_diff(
|
||||
cur->bc_rec.b.br_startoff;
|
||||
}
|
||||
|
||||
static void
|
||||
xfs_bmbt_verify(
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
struct xfs_mount *mp = bp->b_target->bt_mount;
|
||||
struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
|
||||
unsigned int level;
|
||||
int lblock_ok; /* block passes checks */
|
||||
|
||||
/* magic number and level verification.
|
||||
*
|
||||
* We don't know waht fork we belong to, so just verify that the level
|
||||
* is less than the maximum of the two. Later checks will be more
|
||||
* precise.
|
||||
*/
|
||||
level = be16_to_cpu(block->bb_level);
|
||||
lblock_ok = block->bb_magic == cpu_to_be32(XFS_BMAP_MAGIC) &&
|
||||
level < max(mp->m_bm_maxlevels[0], mp->m_bm_maxlevels[1]);
|
||||
|
||||
/* numrecs verification */
|
||||
lblock_ok = lblock_ok &&
|
||||
be16_to_cpu(block->bb_numrecs) <= mp->m_bmap_dmxr[level != 0];
|
||||
|
||||
/* sibling pointer verification */
|
||||
lblock_ok = lblock_ok &&
|
||||
block->bb_u.l.bb_leftsib &&
|
||||
(block->bb_u.l.bb_leftsib == cpu_to_be64(NULLDFSBNO) ||
|
||||
XFS_FSB_SANITY_CHECK(mp,
|
||||
be64_to_cpu(block->bb_u.l.bb_leftsib))) &&
|
||||
block->bb_u.l.bb_rightsib &&
|
||||
(block->bb_u.l.bb_rightsib == cpu_to_be64(NULLDFSBNO) ||
|
||||
XFS_FSB_SANITY_CHECK(mp,
|
||||
be64_to_cpu(block->bb_u.l.bb_rightsib)));
|
||||
|
||||
if (!lblock_ok) {
|
||||
trace_xfs_btree_corrupt(bp, _RET_IP_);
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, block);
|
||||
xfs_buf_ioerror(bp, EFSCORRUPTED);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xfs_bmbt_read_verify(
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
xfs_bmbt_verify(bp);
|
||||
}
|
||||
|
||||
static void
|
||||
xfs_bmbt_write_verify(
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
xfs_bmbt_verify(bp);
|
||||
}
|
||||
|
||||
const struct xfs_buf_ops xfs_bmbt_buf_ops = {
|
||||
.verify_read = xfs_bmbt_read_verify,
|
||||
.verify_write = xfs_bmbt_write_verify,
|
||||
};
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
STATIC int
|
||||
xfs_bmbt_keys_inorder(
|
||||
@@ -746,6 +808,7 @@ static const struct xfs_btree_ops xfs_bmbt_ops = {
|
||||
.init_rec_from_cur = xfs_bmbt_init_rec_from_cur,
|
||||
.init_ptr_from_cur = xfs_bmbt_init_ptr_from_cur,
|
||||
.key_diff = xfs_bmbt_key_diff,
|
||||
.buf_ops = &xfs_bmbt_buf_ops,
|
||||
#ifdef DEBUG
|
||||
.keys_inorder = xfs_bmbt_keys_inorder,
|
||||
.recs_inorder = xfs_bmbt_recs_inorder,
|
||||
|
||||
@@ -236,5 +236,6 @@ extern int xfs_bmbt_maxrecs(struct xfs_mount *, int blocklen, int leaf);
|
||||
extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *,
|
||||
struct xfs_trans *, struct xfs_inode *, int);
|
||||
|
||||
extern const struct xfs_buf_ops xfs_bmbt_buf_ops;
|
||||
|
||||
#endif /* __XFS_BMAP_BTREE_H__ */
|
||||
|
||||
+65
-44
@@ -266,9 +266,13 @@ xfs_btree_dup_cursor(
|
||||
for (i = 0; i < new->bc_nlevels; i++) {
|
||||
new->bc_ptrs[i] = cur->bc_ptrs[i];
|
||||
new->bc_ra[i] = cur->bc_ra[i];
|
||||
if ((bp = cur->bc_bufs[i])) {
|
||||
if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
|
||||
XFS_BUF_ADDR(bp), mp->m_bsize, 0, &bp))) {
|
||||
bp = cur->bc_bufs[i];
|
||||
if (bp) {
|
||||
error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
|
||||
XFS_BUF_ADDR(bp), mp->m_bsize,
|
||||
0, &bp,
|
||||
cur->bc_ops->buf_ops);
|
||||
if (error) {
|
||||
xfs_btree_del_cursor(new, error);
|
||||
*ncur = NULL;
|
||||
return error;
|
||||
@@ -609,25 +613,26 @@ xfs_btree_offsets(
|
||||
* Get a buffer for the block, return it read in.
|
||||
* Long-form addressing.
|
||||
*/
|
||||
int /* error */
|
||||
int
|
||||
xfs_btree_read_bufl(
|
||||
xfs_mount_t *mp, /* file system mount point */
|
||||
xfs_trans_t *tp, /* transaction pointer */
|
||||
xfs_fsblock_t fsbno, /* file system block number */
|
||||
uint lock, /* lock flags for read_buf */
|
||||
xfs_buf_t **bpp, /* buffer for fsbno */
|
||||
int refval) /* ref count value for buffer */
|
||||
struct xfs_mount *mp, /* file system mount point */
|
||||
struct xfs_trans *tp, /* transaction pointer */
|
||||
xfs_fsblock_t fsbno, /* file system block number */
|
||||
uint lock, /* lock flags for read_buf */
|
||||
struct xfs_buf **bpp, /* buffer for fsbno */
|
||||
int refval, /* ref count value for buffer */
|
||||
const struct xfs_buf_ops *ops)
|
||||
{
|
||||
xfs_buf_t *bp; /* return value */
|
||||
struct xfs_buf *bp; /* return value */
|
||||
xfs_daddr_t d; /* real disk block address */
|
||||
int error;
|
||||
int error;
|
||||
|
||||
ASSERT(fsbno != NULLFSBLOCK);
|
||||
d = XFS_FSB_TO_DADDR(mp, fsbno);
|
||||
if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d,
|
||||
mp->m_bsize, lock, &bp))) {
|
||||
error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d,
|
||||
mp->m_bsize, lock, &bp, ops);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
ASSERT(!xfs_buf_geterror(bp));
|
||||
if (bp)
|
||||
xfs_buf_set_ref(bp, refval);
|
||||
@@ -642,15 +647,16 @@ xfs_btree_read_bufl(
|
||||
/* ARGSUSED */
|
||||
void
|
||||
xfs_btree_reada_bufl(
|
||||
xfs_mount_t *mp, /* file system mount point */
|
||||
xfs_fsblock_t fsbno, /* file system block number */
|
||||
xfs_extlen_t count) /* count of filesystem blocks */
|
||||
struct xfs_mount *mp, /* file system mount point */
|
||||
xfs_fsblock_t fsbno, /* file system block number */
|
||||
xfs_extlen_t count, /* count of filesystem blocks */
|
||||
const struct xfs_buf_ops *ops)
|
||||
{
|
||||
xfs_daddr_t d;
|
||||
|
||||
ASSERT(fsbno != NULLFSBLOCK);
|
||||
d = XFS_FSB_TO_DADDR(mp, fsbno);
|
||||
xfs_buf_readahead(mp->m_ddev_targp, d, mp->m_bsize * count);
|
||||
xfs_buf_readahead(mp->m_ddev_targp, d, mp->m_bsize * count, ops);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -660,17 +666,18 @@ xfs_btree_reada_bufl(
|
||||
/* ARGSUSED */
|
||||
void
|
||||
xfs_btree_reada_bufs(
|
||||
xfs_mount_t *mp, /* file system mount point */
|
||||
xfs_agnumber_t agno, /* allocation group number */
|
||||
xfs_agblock_t agbno, /* allocation group block number */
|
||||
xfs_extlen_t count) /* count of filesystem blocks */
|
||||
struct xfs_mount *mp, /* file system mount point */
|
||||
xfs_agnumber_t agno, /* allocation group number */
|
||||
xfs_agblock_t agbno, /* allocation group block number */
|
||||
xfs_extlen_t count, /* count of filesystem blocks */
|
||||
const struct xfs_buf_ops *ops)
|
||||
{
|
||||
xfs_daddr_t d;
|
||||
|
||||
ASSERT(agno != NULLAGNUMBER);
|
||||
ASSERT(agbno != NULLAGBLOCK);
|
||||
d = XFS_AGB_TO_DADDR(mp, agno, agbno);
|
||||
xfs_buf_readahead(mp->m_ddev_targp, d, mp->m_bsize * count);
|
||||
xfs_buf_readahead(mp->m_ddev_targp, d, mp->m_bsize * count, ops);
|
||||
}
|
||||
|
||||
STATIC int
|
||||
@@ -684,12 +691,14 @@ xfs_btree_readahead_lblock(
|
||||
xfs_dfsbno_t right = be64_to_cpu(block->bb_u.l.bb_rightsib);
|
||||
|
||||
if ((lr & XFS_BTCUR_LEFTRA) && left != NULLDFSBNO) {
|
||||
xfs_btree_reada_bufl(cur->bc_mp, left, 1);
|
||||
xfs_btree_reada_bufl(cur->bc_mp, left, 1,
|
||||
cur->bc_ops->buf_ops);
|
||||
rval++;
|
||||
}
|
||||
|
||||
if ((lr & XFS_BTCUR_RIGHTRA) && right != NULLDFSBNO) {
|
||||
xfs_btree_reada_bufl(cur->bc_mp, right, 1);
|
||||
xfs_btree_reada_bufl(cur->bc_mp, right, 1,
|
||||
cur->bc_ops->buf_ops);
|
||||
rval++;
|
||||
}
|
||||
|
||||
@@ -709,13 +718,13 @@ xfs_btree_readahead_sblock(
|
||||
|
||||
if ((lr & XFS_BTCUR_LEFTRA) && left != NULLAGBLOCK) {
|
||||
xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno,
|
||||
left, 1);
|
||||
left, 1, cur->bc_ops->buf_ops);
|
||||
rval++;
|
||||
}
|
||||
|
||||
if ((lr & XFS_BTCUR_RIGHTRA) && right != NULLAGBLOCK) {
|
||||
xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno,
|
||||
right, 1);
|
||||
right, 1, cur->bc_ops->buf_ops);
|
||||
rval++;
|
||||
}
|
||||
|
||||
@@ -853,18 +862,22 @@ xfs_btree_set_sibling(
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void
|
||||
void
|
||||
xfs_btree_init_block(
|
||||
struct xfs_btree_cur *cur,
|
||||
int level,
|
||||
int numrecs,
|
||||
struct xfs_btree_block *new) /* new block */
|
||||
struct xfs_mount *mp,
|
||||
struct xfs_buf *bp,
|
||||
__u32 magic,
|
||||
__u16 level,
|
||||
__u16 numrecs,
|
||||
unsigned int flags)
|
||||
{
|
||||
new->bb_magic = cpu_to_be32(xfs_magics[cur->bc_btnum]);
|
||||
struct xfs_btree_block *new = XFS_BUF_TO_BLOCK(bp);
|
||||
|
||||
new->bb_magic = cpu_to_be32(magic);
|
||||
new->bb_level = cpu_to_be16(level);
|
||||
new->bb_numrecs = cpu_to_be16(numrecs);
|
||||
|
||||
if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
|
||||
if (flags & XFS_BTREE_LONG_PTRS) {
|
||||
new->bb_u.l.bb_leftsib = cpu_to_be64(NULLDFSBNO);
|
||||
new->bb_u.l.bb_rightsib = cpu_to_be64(NULLDFSBNO);
|
||||
} else {
|
||||
@@ -873,6 +886,17 @@ xfs_btree_init_block(
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void
|
||||
xfs_btree_init_block_cur(
|
||||
struct xfs_btree_cur *cur,
|
||||
int level,
|
||||
int numrecs,
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
xfs_btree_init_block(cur->bc_mp, bp, xfs_magics[cur->bc_btnum],
|
||||
level, numrecs, cur->bc_flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if ptr is the last record in the btree and
|
||||
* we need to track updateѕ to this record. The decision
|
||||
@@ -972,6 +996,7 @@ xfs_btree_get_buf_block(
|
||||
if (!*bpp)
|
||||
return ENOMEM;
|
||||
|
||||
(*bpp)->b_ops = cur->bc_ops->buf_ops;
|
||||
*block = XFS_BUF_TO_BLOCK(*bpp);
|
||||
return 0;
|
||||
}
|
||||
@@ -998,19 +1023,15 @@ xfs_btree_read_buf_block(
|
||||
|
||||
d = xfs_btree_ptr_to_daddr(cur, ptr);
|
||||
error = xfs_trans_read_buf(mp, cur->bc_tp, mp->m_ddev_targp, d,
|
||||
mp->m_bsize, flags, bpp);
|
||||
mp->m_bsize, flags, bpp,
|
||||
cur->bc_ops->buf_ops);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
ASSERT(!xfs_buf_geterror(*bpp));
|
||||
|
||||
xfs_btree_set_refs(cur, *bpp);
|
||||
*block = XFS_BUF_TO_BLOCK(*bpp);
|
||||
|
||||
error = xfs_btree_check_block(cur, *block, level, *bpp);
|
||||
if (error)
|
||||
xfs_trans_brelse(cur->bc_tp, *bpp);
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2183,7 +2204,7 @@ xfs_btree_split(
|
||||
goto error0;
|
||||
|
||||
/* Fill in the btree header for the new right block. */
|
||||
xfs_btree_init_block(cur, xfs_btree_get_level(left), 0, right);
|
||||
xfs_btree_init_block_cur(cur, xfs_btree_get_level(left), 0, rbp);
|
||||
|
||||
/*
|
||||
* Split the entries between the old and the new block evenly.
|
||||
@@ -2492,7 +2513,7 @@ xfs_btree_new_root(
|
||||
nptr = 2;
|
||||
}
|
||||
/* Fill in the new block's btree header and log it. */
|
||||
xfs_btree_init_block(cur, cur->bc_nlevels, 2, new);
|
||||
xfs_btree_init_block_cur(cur, cur->bc_nlevels, 2, nbp);
|
||||
xfs_btree_log_block(cur, nbp, XFS_BB_ALL_BITS);
|
||||
ASSERT(!xfs_btree_ptr_is_null(cur, &lptr) &&
|
||||
!xfs_btree_ptr_is_null(cur, &rptr));
|
||||
|
||||
+19
-3
@@ -188,6 +188,8 @@ struct xfs_btree_ops {
|
||||
__int64_t (*key_diff)(struct xfs_btree_cur *cur,
|
||||
union xfs_btree_key *key);
|
||||
|
||||
const struct xfs_buf_ops *buf_ops;
|
||||
|
||||
#ifdef DEBUG
|
||||
/* check that k1 is lower than k2 */
|
||||
int (*keys_inorder)(struct xfs_btree_cur *cur,
|
||||
@@ -355,7 +357,8 @@ xfs_btree_read_bufl(
|
||||
xfs_fsblock_t fsbno, /* file system block number */
|
||||
uint lock, /* lock flags for read_buf */
|
||||
struct xfs_buf **bpp, /* buffer for fsbno */
|
||||
int refval);/* ref count value for buffer */
|
||||
int refval, /* ref count value for buffer */
|
||||
const struct xfs_buf_ops *ops);
|
||||
|
||||
/*
|
||||
* Read-ahead the block, don't wait for it, don't return a buffer.
|
||||
@@ -365,7 +368,8 @@ void /* error */
|
||||
xfs_btree_reada_bufl(
|
||||
struct xfs_mount *mp, /* file system mount point */
|
||||
xfs_fsblock_t fsbno, /* file system block number */
|
||||
xfs_extlen_t count); /* count of filesystem blocks */
|
||||
xfs_extlen_t count, /* count of filesystem blocks */
|
||||
const struct xfs_buf_ops *ops);
|
||||
|
||||
/*
|
||||
* Read-ahead the block, don't wait for it, don't return a buffer.
|
||||
@@ -376,8 +380,20 @@ xfs_btree_reada_bufs(
|
||||
struct xfs_mount *mp, /* file system mount point */
|
||||
xfs_agnumber_t agno, /* allocation group number */
|
||||
xfs_agblock_t agbno, /* allocation group block number */
|
||||
xfs_extlen_t count); /* count of filesystem blocks */
|
||||
xfs_extlen_t count, /* count of filesystem blocks */
|
||||
const struct xfs_buf_ops *ops);
|
||||
|
||||
/*
|
||||
* Initialise a new btree block header
|
||||
*/
|
||||
void
|
||||
xfs_btree_init_block(
|
||||
struct xfs_mount *mp,
|
||||
struct xfs_buf *bp,
|
||||
__u32 magic,
|
||||
__u16 level,
|
||||
__u16 numrecs,
|
||||
unsigned int flags);
|
||||
|
||||
/*
|
||||
* Common btree core entry points.
|
||||
|
||||
+43
-16
@@ -569,7 +569,9 @@ found:
|
||||
*/
|
||||
if (bp->b_flags & XBF_STALE) {
|
||||
ASSERT((bp->b_flags & _XBF_DELWRI_Q) == 0);
|
||||
ASSERT(bp->b_iodone == NULL);
|
||||
bp->b_flags &= _XBF_KMEM | _XBF_PAGES;
|
||||
bp->b_ops = NULL;
|
||||
}
|
||||
|
||||
trace_xfs_buf_find(bp, flags, _RET_IP_);
|
||||
@@ -654,7 +656,8 @@ xfs_buf_read_map(
|
||||
struct xfs_buftarg *target,
|
||||
struct xfs_buf_map *map,
|
||||
int nmaps,
|
||||
xfs_buf_flags_t flags)
|
||||
xfs_buf_flags_t flags,
|
||||
const struct xfs_buf_ops *ops)
|
||||
{
|
||||
struct xfs_buf *bp;
|
||||
|
||||
@@ -666,6 +669,7 @@ xfs_buf_read_map(
|
||||
|
||||
if (!XFS_BUF_ISDONE(bp)) {
|
||||
XFS_STATS_INC(xb_get_read);
|
||||
bp->b_ops = ops;
|
||||
_xfs_buf_read(bp, flags);
|
||||
} else if (flags & XBF_ASYNC) {
|
||||
/*
|
||||
@@ -691,13 +695,14 @@ void
|
||||
xfs_buf_readahead_map(
|
||||
struct xfs_buftarg *target,
|
||||
struct xfs_buf_map *map,
|
||||
int nmaps)
|
||||
int nmaps,
|
||||
const struct xfs_buf_ops *ops)
|
||||
{
|
||||
if (bdi_read_congested(target->bt_bdi))
|
||||
return;
|
||||
|
||||
xfs_buf_read_map(target, map, nmaps,
|
||||
XBF_TRYLOCK|XBF_ASYNC|XBF_READ_AHEAD);
|
||||
XBF_TRYLOCK|XBF_ASYNC|XBF_READ_AHEAD, ops);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -709,10 +714,10 @@ xfs_buf_read_uncached(
|
||||
struct xfs_buftarg *target,
|
||||
xfs_daddr_t daddr,
|
||||
size_t numblks,
|
||||
int flags)
|
||||
int flags,
|
||||
const struct xfs_buf_ops *ops)
|
||||
{
|
||||
xfs_buf_t *bp;
|
||||
int error;
|
||||
struct xfs_buf *bp;
|
||||
|
||||
bp = xfs_buf_get_uncached(target, numblks, flags);
|
||||
if (!bp)
|
||||
@@ -723,13 +728,10 @@ xfs_buf_read_uncached(
|
||||
bp->b_bn = daddr;
|
||||
bp->b_maps[0].bm_bn = daddr;
|
||||
bp->b_flags |= XBF_READ;
|
||||
bp->b_ops = ops;
|
||||
|
||||
xfsbdstrat(target->bt_mount, bp);
|
||||
error = xfs_buf_iowait(bp);
|
||||
if (error) {
|
||||
xfs_buf_relse(bp);
|
||||
return NULL;
|
||||
}
|
||||
xfs_buf_iowait(bp);
|
||||
return bp;
|
||||
}
|
||||
|
||||
@@ -999,27 +1001,37 @@ STATIC void
|
||||
xfs_buf_iodone_work(
|
||||
struct work_struct *work)
|
||||
{
|
||||
xfs_buf_t *bp =
|
||||
struct xfs_buf *bp =
|
||||
container_of(work, xfs_buf_t, b_iodone_work);
|
||||
bool read = !!(bp->b_flags & XBF_READ);
|
||||
|
||||
bp->b_flags &= ~(XBF_READ | XBF_WRITE | XBF_READ_AHEAD);
|
||||
if (read && bp->b_ops)
|
||||
bp->b_ops->verify_read(bp);
|
||||
|
||||
if (bp->b_iodone)
|
||||
(*(bp->b_iodone))(bp);
|
||||
else if (bp->b_flags & XBF_ASYNC)
|
||||
xfs_buf_relse(bp);
|
||||
else {
|
||||
ASSERT(read && bp->b_ops);
|
||||
complete(&bp->b_iowait);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xfs_buf_ioend(
|
||||
xfs_buf_t *bp,
|
||||
int schedule)
|
||||
struct xfs_buf *bp,
|
||||
int schedule)
|
||||
{
|
||||
bool read = !!(bp->b_flags & XBF_READ);
|
||||
|
||||
trace_xfs_buf_iodone(bp, _RET_IP_);
|
||||
|
||||
bp->b_flags &= ~(XBF_READ | XBF_WRITE | XBF_READ_AHEAD);
|
||||
if (bp->b_error == 0)
|
||||
bp->b_flags |= XBF_DONE;
|
||||
|
||||
if ((bp->b_iodone) || (bp->b_flags & XBF_ASYNC)) {
|
||||
if (bp->b_iodone || (read && bp->b_ops) || (bp->b_flags & XBF_ASYNC)) {
|
||||
if (schedule) {
|
||||
INIT_WORK(&bp->b_iodone_work, xfs_buf_iodone_work);
|
||||
queue_work(xfslogd_workqueue, &bp->b_iodone_work);
|
||||
@@ -1027,6 +1039,7 @@ xfs_buf_ioend(
|
||||
xfs_buf_iodone_work(&bp->b_iodone_work);
|
||||
}
|
||||
} else {
|
||||
bp->b_flags &= ~(XBF_READ | XBF_WRITE | XBF_READ_AHEAD);
|
||||
complete(&bp->b_iowait);
|
||||
}
|
||||
}
|
||||
@@ -1314,6 +1327,20 @@ _xfs_buf_ioapply(
|
||||
rw |= REQ_FUA;
|
||||
if (bp->b_flags & XBF_FLUSH)
|
||||
rw |= REQ_FLUSH;
|
||||
|
||||
/*
|
||||
* Run the write verifier callback function if it exists. If
|
||||
* this function fails it will mark the buffer with an error and
|
||||
* the IO should not be dispatched.
|
||||
*/
|
||||
if (bp->b_ops) {
|
||||
bp->b_ops->verify_write(bp);
|
||||
if (bp->b_error) {
|
||||
xfs_force_shutdown(bp->b_target->bt_mount,
|
||||
SHUTDOWN_CORRUPT_INCORE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (bp->b_flags & XBF_READ_AHEAD) {
|
||||
rw = READA;
|
||||
} else {
|
||||
|
||||
+19
-8
@@ -100,6 +100,7 @@ typedef struct xfs_buftarg {
|
||||
struct xfs_buf;
|
||||
typedef void (*xfs_buf_iodone_t)(struct xfs_buf *);
|
||||
|
||||
|
||||
#define XB_PAGES 2
|
||||
|
||||
struct xfs_buf_map {
|
||||
@@ -110,6 +111,11 @@ struct xfs_buf_map {
|
||||
#define DEFINE_SINGLE_BUF_MAP(map, blkno, numblk) \
|
||||
struct xfs_buf_map (map) = { .bm_bn = (blkno), .bm_len = (numblk) };
|
||||
|
||||
struct xfs_buf_ops {
|
||||
void (*verify_read)(struct xfs_buf *);
|
||||
void (*verify_write)(struct xfs_buf *);
|
||||
};
|
||||
|
||||
typedef struct xfs_buf {
|
||||
/*
|
||||
* first cacheline holds all the fields needed for an uncontended cache
|
||||
@@ -153,13 +159,13 @@ typedef struct xfs_buf {
|
||||
unsigned int b_page_count; /* size of page array */
|
||||
unsigned int b_offset; /* page offset in first page */
|
||||
unsigned short b_error; /* error code on I/O */
|
||||
const struct xfs_buf_ops *b_ops;
|
||||
|
||||
#ifdef XFS_BUF_LOCK_TRACKING
|
||||
int b_last_holder;
|
||||
#endif
|
||||
} xfs_buf_t;
|
||||
|
||||
|
||||
/* Finding and Reading Buffers */
|
||||
struct xfs_buf *_xfs_buf_find(struct xfs_buftarg *target,
|
||||
struct xfs_buf_map *map, int nmaps,
|
||||
@@ -196,9 +202,11 @@ struct xfs_buf *xfs_buf_get_map(struct xfs_buftarg *target,
|
||||
xfs_buf_flags_t flags);
|
||||
struct xfs_buf *xfs_buf_read_map(struct xfs_buftarg *target,
|
||||
struct xfs_buf_map *map, int nmaps,
|
||||
xfs_buf_flags_t flags);
|
||||
xfs_buf_flags_t flags,
|
||||
const struct xfs_buf_ops *ops);
|
||||
void xfs_buf_readahead_map(struct xfs_buftarg *target,
|
||||
struct xfs_buf_map *map, int nmaps);
|
||||
struct xfs_buf_map *map, int nmaps,
|
||||
const struct xfs_buf_ops *ops);
|
||||
|
||||
static inline struct xfs_buf *
|
||||
xfs_buf_get(
|
||||
@@ -216,20 +224,22 @@ xfs_buf_read(
|
||||
struct xfs_buftarg *target,
|
||||
xfs_daddr_t blkno,
|
||||
size_t numblks,
|
||||
xfs_buf_flags_t flags)
|
||||
xfs_buf_flags_t flags,
|
||||
const struct xfs_buf_ops *ops)
|
||||
{
|
||||
DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
|
||||
return xfs_buf_read_map(target, &map, 1, flags);
|
||||
return xfs_buf_read_map(target, &map, 1, flags, ops);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xfs_buf_readahead(
|
||||
struct xfs_buftarg *target,
|
||||
xfs_daddr_t blkno,
|
||||
size_t numblks)
|
||||
size_t numblks,
|
||||
const struct xfs_buf_ops *ops)
|
||||
{
|
||||
DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
|
||||
return xfs_buf_readahead_map(target, &map, 1);
|
||||
return xfs_buf_readahead_map(target, &map, 1, ops);
|
||||
}
|
||||
|
||||
struct xfs_buf *xfs_buf_get_empty(struct xfs_buftarg *target, size_t numblks);
|
||||
@@ -239,7 +249,8 @@ int xfs_buf_associate_memory(struct xfs_buf *bp, void *mem, size_t length);
|
||||
struct xfs_buf *xfs_buf_get_uncached(struct xfs_buftarg *target, size_t numblks,
|
||||
int flags);
|
||||
struct xfs_buf *xfs_buf_read_uncached(struct xfs_buftarg *target,
|
||||
xfs_daddr_t daddr, size_t numblks, int flags);
|
||||
xfs_daddr_t daddr, size_t numblks, int flags,
|
||||
const struct xfs_buf_ops *ops);
|
||||
void xfs_buf_hold(struct xfs_buf *bp);
|
||||
|
||||
/* Releasing Buffers */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user