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 'xfs-4.17-merge-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
Pull xfs updates from Darrick Wong:
"Here's the first round of fixes for XFS for 4.17.
The biggest new features this time around are the addition of lazytime
support, further enhancement of the on-disk inode metadata verifiers,
and a patch to smooth over some of the AGFL padding problems that have
intermittently plagued users since 4.5. I forsee sending a second pull
request next week with further bug fixes and speedups in the online
scrub code and elsewhere.
This series has been run through a full xfstests run over the weekend
and through a quick xfstests run against this morning's master, with
no major failures reported.
Summary of changes for this release:
- Various cleanups and code fixes
- Implement lazytime as a mount option
- Convert various on-disk metadata checks from asserts to -EFSCORRUPTED
- Fix accounting problems with the rmap per-ag reservations
- Refactorings and cleanups for xfs_log_force
- Various bugfixes for the reflink code
- Work around v5 AGFL padding problems to prevent fs shutdowns
- Establish inode fork verifiers to inspect on-disk metadata
correctness
- Various online scrub fixes
- Fix v5 swapext blowing up on deleted inodes"
* tag 'xfs-4.17-merge-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: (49 commits)
xfs: do not log/recover swapext extent owner changes for deleted inodes
xfs: clean up xfs_mount allocation and dynamic initializers
xfs: remove dead inode version setting code
xfs: catch inode allocation state mismatch corruption
xfs: xfs_scrub_iallocbt_xref_rmap_inodes should use xref_set_corrupt
xfs: flag inode corruption if parent ptr doesn't get us a real inode
xfs: don't accept inode buffers with suspicious unlinked chains
xfs: move inode extent size hint validation to libxfs
xfs: record inode buf errors as a xref error in inobt scrubber
xfs: remove xfs_buf parameter from inode scrub methods
xfs: inode scrubber shouldn't bother with raw checks
xfs: bmap scrubber should do rmap xref with bmap for sparse files
xfs: refactor inode buffer verifier error logging
xfs: refactor inode verifier error logging
xfs: refactor bmap record validation
xfs: sanity-check the unused space before trying to use it
xfs: detect agfl count corruption and reset agfl
xfs: unwind the try_again loop in xfs_log_force
xfs: refactor xfs_log_force_lsn
xfs: minor cleanup for xfs_reflink_end_cow
...
This commit is contained in:
+8
-4
@@ -346,9 +346,8 @@ void inc_nlink(struct inode *inode)
|
||||
}
|
||||
EXPORT_SYMBOL(inc_nlink);
|
||||
|
||||
void address_space_init_once(struct address_space *mapping)
|
||||
static void __address_space_init_once(struct address_space *mapping)
|
||||
{
|
||||
memset(mapping, 0, sizeof(*mapping));
|
||||
INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC | __GFP_ACCOUNT);
|
||||
spin_lock_init(&mapping->tree_lock);
|
||||
init_rwsem(&mapping->i_mmap_rwsem);
|
||||
@@ -356,6 +355,12 @@ void address_space_init_once(struct address_space *mapping)
|
||||
spin_lock_init(&mapping->private_lock);
|
||||
mapping->i_mmap = RB_ROOT_CACHED;
|
||||
}
|
||||
|
||||
void address_space_init_once(struct address_space *mapping)
|
||||
{
|
||||
memset(mapping, 0, sizeof(*mapping));
|
||||
__address_space_init_once(mapping);
|
||||
}
|
||||
EXPORT_SYMBOL(address_space_init_once);
|
||||
|
||||
/*
|
||||
@@ -371,7 +376,7 @@ void inode_init_once(struct inode *inode)
|
||||
INIT_LIST_HEAD(&inode->i_io_list);
|
||||
INIT_LIST_HEAD(&inode->i_wb_list);
|
||||
INIT_LIST_HEAD(&inode->i_lru);
|
||||
address_space_init_once(&inode->i_data);
|
||||
__address_space_init_once(&inode->i_data);
|
||||
i_size_ordered_init(inode);
|
||||
}
|
||||
EXPORT_SYMBOL(inode_init_once);
|
||||
@@ -1533,7 +1538,6 @@ retry:
|
||||
if (atomic_dec_and_lock(&inode->i_count, &inode->i_lock)) {
|
||||
if (inode->i_nlink && (inode->i_state & I_DIRTY_TIME)) {
|
||||
atomic_inc(&inode->i_count);
|
||||
inode->i_state &= ~I_DIRTY_TIME;
|
||||
spin_unlock(&inode->i_lock);
|
||||
trace_writeback_lazytime_iput(inode);
|
||||
mark_inode_dirty_sync(inode);
|
||||
|
||||
@@ -192,12 +192,8 @@ int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync)
|
||||
|
||||
if (!file->f_op->fsync)
|
||||
return -EINVAL;
|
||||
if (!datasync && (inode->i_state & I_DIRTY_TIME)) {
|
||||
spin_lock(&inode->i_lock);
|
||||
inode->i_state &= ~I_DIRTY_TIME;
|
||||
spin_unlock(&inode->i_lock);
|
||||
if (!datasync && (inode->i_state & I_DIRTY_TIME))
|
||||
mark_inode_dirty_sync(inode);
|
||||
}
|
||||
return file->f_op->fsync(file, start, end, datasync);
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_fsync_range);
|
||||
|
||||
+3
-3
@@ -46,13 +46,13 @@ kmem_alloc(size_t size, xfs_km_flags_t flags)
|
||||
}
|
||||
|
||||
void *
|
||||
kmem_zalloc_large(size_t size, xfs_km_flags_t flags)
|
||||
kmem_alloc_large(size_t size, xfs_km_flags_t flags)
|
||||
{
|
||||
unsigned nofs_flag = 0;
|
||||
void *ptr;
|
||||
gfp_t lflags;
|
||||
|
||||
ptr = kmem_zalloc(size, flags | KM_MAYFAIL);
|
||||
ptr = kmem_alloc(size, flags | KM_MAYFAIL);
|
||||
if (ptr)
|
||||
return ptr;
|
||||
|
||||
@@ -67,7 +67,7 @@ kmem_zalloc_large(size_t size, xfs_km_flags_t flags)
|
||||
nofs_flag = memalloc_nofs_save();
|
||||
|
||||
lflags = kmem_flags_convert(flags);
|
||||
ptr = __vmalloc(size, lflags | __GFP_ZERO, PAGE_KERNEL);
|
||||
ptr = __vmalloc(size, lflags, PAGE_KERNEL);
|
||||
|
||||
if (flags & KM_NOFS)
|
||||
memalloc_nofs_restore(nofs_flag);
|
||||
|
||||
+7
-1
@@ -71,7 +71,7 @@ kmem_flags_convert(xfs_km_flags_t flags)
|
||||
}
|
||||
|
||||
extern void *kmem_alloc(size_t, xfs_km_flags_t);
|
||||
extern void *kmem_zalloc_large(size_t size, xfs_km_flags_t);
|
||||
extern void *kmem_alloc_large(size_t size, xfs_km_flags_t);
|
||||
extern void *kmem_realloc(const void *, size_t, xfs_km_flags_t);
|
||||
static inline void kmem_free(const void *ptr)
|
||||
{
|
||||
@@ -85,6 +85,12 @@ kmem_zalloc(size_t size, xfs_km_flags_t flags)
|
||||
return kmem_alloc(size, flags | KM_ZERO);
|
||||
}
|
||||
|
||||
static inline void *
|
||||
kmem_zalloc_large(size_t size, xfs_km_flags_t flags)
|
||||
{
|
||||
return kmem_alloc_large(size, flags | KM_ZERO);
|
||||
}
|
||||
|
||||
/*
|
||||
* Zone interfaces
|
||||
*/
|
||||
|
||||
+22
-17
@@ -95,13 +95,13 @@ xfs_ag_resv_critical(
|
||||
|
||||
switch (type) {
|
||||
case XFS_AG_RESV_METADATA:
|
||||
avail = pag->pagf_freeblks - pag->pag_agfl_resv.ar_reserved;
|
||||
avail = pag->pagf_freeblks - pag->pag_rmapbt_resv.ar_reserved;
|
||||
orig = pag->pag_meta_resv.ar_asked;
|
||||
break;
|
||||
case XFS_AG_RESV_AGFL:
|
||||
case XFS_AG_RESV_RMAPBT:
|
||||
avail = pag->pagf_freeblks + pag->pagf_flcount -
|
||||
pag->pag_meta_resv.ar_reserved;
|
||||
orig = pag->pag_agfl_resv.ar_asked;
|
||||
orig = pag->pag_rmapbt_resv.ar_asked;
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
@@ -126,10 +126,10 @@ xfs_ag_resv_needed(
|
||||
{
|
||||
xfs_extlen_t len;
|
||||
|
||||
len = pag->pag_meta_resv.ar_reserved + pag->pag_agfl_resv.ar_reserved;
|
||||
len = pag->pag_meta_resv.ar_reserved + pag->pag_rmapbt_resv.ar_reserved;
|
||||
switch (type) {
|
||||
case XFS_AG_RESV_METADATA:
|
||||
case XFS_AG_RESV_AGFL:
|
||||
case XFS_AG_RESV_RMAPBT:
|
||||
len -= xfs_perag_resv(pag, type)->ar_reserved;
|
||||
break;
|
||||
case XFS_AG_RESV_NONE:
|
||||
@@ -160,10 +160,11 @@ __xfs_ag_resv_free(
|
||||
if (pag->pag_agno == 0)
|
||||
pag->pag_mount->m_ag_max_usable += resv->ar_asked;
|
||||
/*
|
||||
* AGFL blocks are always considered "free", so whatever
|
||||
* was reserved at mount time must be given back at umount.
|
||||
* RMAPBT blocks come from the AGFL and AGFL blocks are always
|
||||
* considered "free", so whatever was reserved at mount time must be
|
||||
* given back at umount.
|
||||
*/
|
||||
if (type == XFS_AG_RESV_AGFL)
|
||||
if (type == XFS_AG_RESV_RMAPBT)
|
||||
oldresv = resv->ar_orig_reserved;
|
||||
else
|
||||
oldresv = resv->ar_reserved;
|
||||
@@ -185,7 +186,7 @@ xfs_ag_resv_free(
|
||||
int error;
|
||||
int err2;
|
||||
|
||||
error = __xfs_ag_resv_free(pag, XFS_AG_RESV_AGFL);
|
||||
error = __xfs_ag_resv_free(pag, XFS_AG_RESV_RMAPBT);
|
||||
err2 = __xfs_ag_resv_free(pag, XFS_AG_RESV_METADATA);
|
||||
if (err2 && !error)
|
||||
error = err2;
|
||||
@@ -284,15 +285,15 @@ xfs_ag_resv_init(
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the AGFL metadata reservation */
|
||||
if (pag->pag_agfl_resv.ar_asked == 0) {
|
||||
/* Create the RMAPBT metadata reservation */
|
||||
if (pag->pag_rmapbt_resv.ar_asked == 0) {
|
||||
ask = used = 0;
|
||||
|
||||
error = xfs_rmapbt_calc_reserves(mp, agno, &ask, &used);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
error = __xfs_ag_resv_init(pag, XFS_AG_RESV_AGFL, ask, used);
|
||||
error = __xfs_ag_resv_init(pag, XFS_AG_RESV_RMAPBT, ask, used);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
@@ -304,7 +305,7 @@ xfs_ag_resv_init(
|
||||
return error;
|
||||
|
||||
ASSERT(xfs_perag_resv(pag, XFS_AG_RESV_METADATA)->ar_reserved +
|
||||
xfs_perag_resv(pag, XFS_AG_RESV_AGFL)->ar_reserved <=
|
||||
xfs_perag_resv(pag, XFS_AG_RESV_RMAPBT)->ar_reserved <=
|
||||
pag->pagf_freeblks + pag->pagf_flcount);
|
||||
#endif
|
||||
out:
|
||||
@@ -325,8 +326,10 @@ xfs_ag_resv_alloc_extent(
|
||||
trace_xfs_ag_resv_alloc_extent(pag, type, args->len);
|
||||
|
||||
switch (type) {
|
||||
case XFS_AG_RESV_METADATA:
|
||||
case XFS_AG_RESV_AGFL:
|
||||
return;
|
||||
case XFS_AG_RESV_METADATA:
|
||||
case XFS_AG_RESV_RMAPBT:
|
||||
resv = xfs_perag_resv(pag, type);
|
||||
break;
|
||||
default:
|
||||
@@ -341,7 +344,7 @@ xfs_ag_resv_alloc_extent(
|
||||
|
||||
len = min_t(xfs_extlen_t, args->len, resv->ar_reserved);
|
||||
resv->ar_reserved -= len;
|
||||
if (type == XFS_AG_RESV_AGFL)
|
||||
if (type == XFS_AG_RESV_RMAPBT)
|
||||
return;
|
||||
/* Allocations of reserved blocks only need on-disk sb updates... */
|
||||
xfs_trans_mod_sb(args->tp, XFS_TRANS_SB_RES_FDBLOCKS, -(int64_t)len);
|
||||
@@ -365,8 +368,10 @@ xfs_ag_resv_free_extent(
|
||||
trace_xfs_ag_resv_free_extent(pag, type, len);
|
||||
|
||||
switch (type) {
|
||||
case XFS_AG_RESV_METADATA:
|
||||
case XFS_AG_RESV_AGFL:
|
||||
return;
|
||||
case XFS_AG_RESV_METADATA:
|
||||
case XFS_AG_RESV_RMAPBT:
|
||||
resv = xfs_perag_resv(pag, type);
|
||||
break;
|
||||
default:
|
||||
@@ -379,7 +384,7 @@ xfs_ag_resv_free_extent(
|
||||
|
||||
leftover = min_t(xfs_extlen_t, len, resv->ar_asked - resv->ar_reserved);
|
||||
resv->ar_reserved += leftover;
|
||||
if (type == XFS_AG_RESV_AGFL)
|
||||
if (type == XFS_AG_RESV_RMAPBT)
|
||||
return;
|
||||
/* Freeing into the reserved pool only requires on-disk update... */
|
||||
xfs_trans_mod_sb(tp, XFS_TRANS_SB_RES_FDBLOCKS, len);
|
||||
|
||||
@@ -32,4 +32,35 @@ void xfs_ag_resv_alloc_extent(struct xfs_perag *pag, enum xfs_ag_resv_type type,
|
||||
void xfs_ag_resv_free_extent(struct xfs_perag *pag, enum xfs_ag_resv_type type,
|
||||
struct xfs_trans *tp, xfs_extlen_t len);
|
||||
|
||||
/*
|
||||
* RMAPBT reservation accounting wrappers. Since rmapbt blocks are sourced from
|
||||
* the AGFL, they are allocated one at a time and the reservation updates don't
|
||||
* require a transaction.
|
||||
*/
|
||||
static inline void
|
||||
xfs_ag_resv_rmapbt_alloc(
|
||||
struct xfs_mount *mp,
|
||||
xfs_agnumber_t agno)
|
||||
{
|
||||
struct xfs_alloc_arg args = {0};
|
||||
struct xfs_perag *pag;
|
||||
|
||||
args.len = 1;
|
||||
pag = xfs_perag_get(mp, agno);
|
||||
xfs_ag_resv_alloc_extent(pag, XFS_AG_RESV_RMAPBT, &args);
|
||||
xfs_perag_put(pag);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xfs_ag_resv_rmapbt_free(
|
||||
struct xfs_mount *mp,
|
||||
xfs_agnumber_t agno)
|
||||
{
|
||||
struct xfs_perag *pag;
|
||||
|
||||
pag = xfs_perag_get(mp, agno);
|
||||
xfs_ag_resv_free_extent(pag, XFS_AG_RESV_RMAPBT, NULL, 1);
|
||||
xfs_perag_put(pag);
|
||||
}
|
||||
|
||||
#endif /* __XFS_AG_RESV_H__ */
|
||||
|
||||
+121
-18
@@ -53,6 +53,23 @@ STATIC int xfs_alloc_ag_vextent_size(xfs_alloc_arg_t *);
|
||||
STATIC int xfs_alloc_ag_vextent_small(xfs_alloc_arg_t *,
|
||||
xfs_btree_cur_t *, xfs_agblock_t *, xfs_extlen_t *, int *);
|
||||
|
||||
/*
|
||||
* Size of the AGFL. For CRC-enabled filesystes we steal a couple of slots in
|
||||
* the beginning of the block for a proper header with the location information
|
||||
* and CRC.
|
||||
*/
|
||||
unsigned int
|
||||
xfs_agfl_size(
|
||||
struct xfs_mount *mp)
|
||||
{
|
||||
unsigned int size = mp->m_sb.sb_sectsize;
|
||||
|
||||
if (xfs_sb_version_hascrc(&mp->m_sb))
|
||||
size -= sizeof(struct xfs_agfl);
|
||||
|
||||
return size / sizeof(xfs_agblock_t);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
xfs_refc_block(
|
||||
struct xfs_mount *mp)
|
||||
@@ -550,7 +567,7 @@ xfs_agfl_verify(
|
||||
if (bp->b_pag && be32_to_cpu(agfl->agfl_seqno) != bp->b_pag->pag_agno)
|
||||
return __this_address;
|
||||
|
||||
for (i = 0; i < XFS_AGFL_SIZE(mp); 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)
|
||||
return __this_address;
|
||||
@@ -1564,7 +1581,6 @@ xfs_alloc_ag_vextent_small(
|
||||
int *stat) /* status: 0-freelist, 1-normal/none */
|
||||
{
|
||||
struct xfs_owner_info oinfo;
|
||||
struct xfs_perag *pag;
|
||||
int error;
|
||||
xfs_agblock_t fbno;
|
||||
xfs_extlen_t flen;
|
||||
@@ -1616,18 +1632,13 @@ xfs_alloc_ag_vextent_small(
|
||||
/*
|
||||
* If we're feeding an AGFL block to something that
|
||||
* doesn't live in the free space, we need to clear
|
||||
* out the OWN_AG rmap and add the block back to
|
||||
* the AGFL per-AG reservation.
|
||||
* out the OWN_AG rmap.
|
||||
*/
|
||||
xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_AG);
|
||||
error = xfs_rmap_free(args->tp, args->agbp, args->agno,
|
||||
fbno, 1, &oinfo);
|
||||
if (error)
|
||||
goto error0;
|
||||
pag = xfs_perag_get(args->mp, args->agno);
|
||||
xfs_ag_resv_free_extent(pag, XFS_AG_RESV_AGFL,
|
||||
args->tp, 1);
|
||||
xfs_perag_put(pag);
|
||||
|
||||
*stat = 0;
|
||||
return 0;
|
||||
@@ -1911,14 +1922,12 @@ xfs_free_ag_extent(
|
||||
XFS_STATS_INC(mp, xs_freex);
|
||||
XFS_STATS_ADD(mp, xs_freeb, len);
|
||||
|
||||
trace_xfs_free_extent(mp, agno, bno, len, type == XFS_AG_RESV_AGFL,
|
||||
haveleft, haveright);
|
||||
trace_xfs_free_extent(mp, agno, bno, len, type, haveleft, haveright);
|
||||
|
||||
return 0;
|
||||
|
||||
error0:
|
||||
trace_xfs_free_extent(mp, agno, bno, len, type == XFS_AG_RESV_AGFL,
|
||||
-1, -1);
|
||||
trace_xfs_free_extent(mp, agno, bno, len, type, -1, -1);
|
||||
if (bno_cur)
|
||||
xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR);
|
||||
if (cnt_cur)
|
||||
@@ -2053,6 +2062,93 @@ xfs_alloc_space_available(
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the agfl fields of the agf for inconsistency or corruption. The purpose
|
||||
* is to detect an agfl header padding mismatch between current and early v5
|
||||
* kernels. This problem manifests as a 1-slot size difference between the
|
||||
* on-disk flcount and the active [first, last] range of a wrapped agfl. This
|
||||
* may also catch variants of agfl count corruption unrelated to padding. Either
|
||||
* way, we'll reset the agfl and warn the user.
|
||||
*
|
||||
* Return true if a reset is required before the agfl can be used, false
|
||||
* otherwise.
|
||||
*/
|
||||
static bool
|
||||
xfs_agfl_needs_reset(
|
||||
struct xfs_mount *mp,
|
||||
struct xfs_agf *agf)
|
||||
{
|
||||
uint32_t f = be32_to_cpu(agf->agf_flfirst);
|
||||
uint32_t l = be32_to_cpu(agf->agf_fllast);
|
||||
uint32_t c = be32_to_cpu(agf->agf_flcount);
|
||||
int agfl_size = xfs_agfl_size(mp);
|
||||
int active;
|
||||
|
||||
/* no agfl header on v4 supers */
|
||||
if (!xfs_sb_version_hascrc(&mp->m_sb))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* The agf read verifier catches severe corruption of these fields.
|
||||
* Repeat some sanity checks to cover a packed -> unpacked mismatch if
|
||||
* the verifier allows it.
|
||||
*/
|
||||
if (f >= agfl_size || l >= agfl_size)
|
||||
return true;
|
||||
if (c > agfl_size)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Check consistency between the on-disk count and the active range. An
|
||||
* agfl padding mismatch manifests as an inconsistent flcount.
|
||||
*/
|
||||
if (c && l >= f)
|
||||
active = l - f + 1;
|
||||
else if (c)
|
||||
active = agfl_size - f + l + 1;
|
||||
else
|
||||
active = 0;
|
||||
|
||||
return active != c;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the agfl to an empty state. Ignore/drop any existing blocks since the
|
||||
* agfl content cannot be trusted. Warn the user that a repair is required to
|
||||
* recover leaked blocks.
|
||||
*
|
||||
* The purpose of this mechanism is to handle filesystems affected by the agfl
|
||||
* header padding mismatch problem. A reset keeps the filesystem online with a
|
||||
* relatively minor free space accounting inconsistency rather than suffer the
|
||||
* inevitable crash from use of an invalid agfl block.
|
||||
*/
|
||||
static void
|
||||
xfs_agfl_reset(
|
||||
struct xfs_trans *tp,
|
||||
struct xfs_buf *agbp,
|
||||
struct xfs_perag *pag)
|
||||
{
|
||||
struct xfs_mount *mp = tp->t_mountp;
|
||||
struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp);
|
||||
|
||||
ASSERT(pag->pagf_agflreset);
|
||||
trace_xfs_agfl_reset(mp, agf, 0, _RET_IP_);
|
||||
|
||||
xfs_warn(mp,
|
||||
"WARNING: Reset corrupted AGFL on AG %u. %d blocks leaked. "
|
||||
"Please unmount and run xfs_repair.",
|
||||
pag->pag_agno, pag->pagf_flcount);
|
||||
|
||||
agf->agf_flfirst = 0;
|
||||
agf->agf_fllast = cpu_to_be32(xfs_agfl_size(mp) - 1);
|
||||
agf->agf_flcount = 0;
|
||||
xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLFIRST | XFS_AGF_FLLAST |
|
||||
XFS_AGF_FLCOUNT);
|
||||
|
||||
pag->pagf_flcount = 0;
|
||||
pag->pagf_agflreset = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decide whether to use this allocation group for this allocation.
|
||||
* If so, fix up the btree freelist's size.
|
||||
@@ -2114,6 +2210,10 @@ xfs_alloc_fix_freelist(
|
||||
}
|
||||
}
|
||||
|
||||
/* reset a padding mismatched agfl before final free space check */
|
||||
if (pag->pagf_agflreset)
|
||||
xfs_agfl_reset(tp, agbp, pag);
|
||||
|
||||
/* If there isn't enough total space or single-extent, reject it. */
|
||||
need = xfs_alloc_min_freelist(mp, pag);
|
||||
if (!xfs_alloc_space_available(args, need, flags))
|
||||
@@ -2266,10 +2366,11 @@ xfs_alloc_get_freelist(
|
||||
bno = be32_to_cpu(agfl_bno[be32_to_cpu(agf->agf_flfirst)]);
|
||||
be32_add_cpu(&agf->agf_flfirst, 1);
|
||||
xfs_trans_brelse(tp, agflbp);
|
||||
if (be32_to_cpu(agf->agf_flfirst) == XFS_AGFL_SIZE(mp))
|
||||
if (be32_to_cpu(agf->agf_flfirst) == xfs_agfl_size(mp))
|
||||
agf->agf_flfirst = 0;
|
||||
|
||||
pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno));
|
||||
ASSERT(!pag->pagf_agflreset);
|
||||
be32_add_cpu(&agf->agf_flcount, -1);
|
||||
xfs_trans_agflist_delta(tp, -1);
|
||||
pag->pagf_flcount--;
|
||||
@@ -2377,10 +2478,11 @@ xfs_alloc_put_freelist(
|
||||
be32_to_cpu(agf->agf_seqno), &agflbp)))
|
||||
return error;
|
||||
be32_add_cpu(&agf->agf_fllast, 1);
|
||||
if (be32_to_cpu(agf->agf_fllast) == XFS_AGFL_SIZE(mp))
|
||||
if (be32_to_cpu(agf->agf_fllast) == xfs_agfl_size(mp))
|
||||
agf->agf_fllast = 0;
|
||||
|
||||
pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno));
|
||||
ASSERT(!pag->pagf_agflreset);
|
||||
be32_add_cpu(&agf->agf_flcount, 1);
|
||||
xfs_trans_agflist_delta(tp, 1);
|
||||
pag->pagf_flcount++;
|
||||
@@ -2395,7 +2497,7 @@ xfs_alloc_put_freelist(
|
||||
|
||||
xfs_alloc_log_agf(tp, agbp, logflags);
|
||||
|
||||
ASSERT(be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp));
|
||||
ASSERT(be32_to_cpu(agf->agf_flcount) <= xfs_agfl_size(mp));
|
||||
|
||||
agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agflbp);
|
||||
blockp = &agfl_bno[be32_to_cpu(agf->agf_fllast)];
|
||||
@@ -2428,9 +2530,9 @@ xfs_agf_verify(
|
||||
if (!(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_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)))
|
||||
return __this_address;
|
||||
|
||||
if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) < 1 ||
|
||||
@@ -2588,6 +2690,7 @@ xfs_alloc_read_agf(
|
||||
pag->pagb_count = 0;
|
||||
pag->pagb_tree = RB_ROOT;
|
||||
pag->pagf_init = 1;
|
||||
pag->pagf_agflreset = xfs_agfl_needs_reset(mp, agf);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
else if (!XFS_FORCED_SHUTDOWN(mp)) {
|
||||
|
||||
@@ -26,6 +26,8 @@ struct xfs_trans;
|
||||
|
||||
extern struct workqueue_struct *xfs_alloc_wq;
|
||||
|
||||
unsigned int xfs_agfl_size(struct xfs_mount *mp);
|
||||
|
||||
/*
|
||||
* Freespace allocation types. Argument to xfs_alloc_[v]extent.
|
||||
*/
|
||||
|
||||
@@ -74,18 +74,13 @@ xfs_allocbt_alloc_block(
|
||||
int error;
|
||||
xfs_agblock_t bno;
|
||||
|
||||
XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
|
||||
|
||||
/* Allocate the new block from the freelist. If we can't, give up. */
|
||||
error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp,
|
||||
&bno, 1);
|
||||
if (error) {
|
||||
XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
if (bno == NULLAGBLOCK) {
|
||||
XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
|
||||
*stat = 0;
|
||||
return 0;
|
||||
}
|
||||
@@ -95,7 +90,6 @@ xfs_allocbt_alloc_block(
|
||||
xfs_trans_agbtree_delta(cur->bc_tp, 1);
|
||||
new->s = cpu_to_be32(bno);
|
||||
|
||||
XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
|
||||
*stat = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1244,8 +1244,9 @@ xfs_iread_extents(
|
||||
xfs_warn(ip->i_mount,
|
||||
"corrupt dinode %Lu, (btree extents).",
|
||||
(unsigned long long) ip->i_ino);
|
||||
XFS_CORRUPTION_ERROR(__func__,
|
||||
XFS_ERRLEVEL_LOW, ip->i_mount, block);
|
||||
xfs_inode_verifier_error(ip, -EFSCORRUPTED,
|
||||
__func__, block, sizeof(*block),
|
||||
__this_address);
|
||||
error = -EFSCORRUPTED;
|
||||
goto out_brelse;
|
||||
}
|
||||
@@ -1261,11 +1262,15 @@ xfs_iread_extents(
|
||||
*/
|
||||
frp = XFS_BMBT_REC_ADDR(mp, block, 1);
|
||||
for (j = 0; j < num_recs; j++, frp++, i++) {
|
||||
xfs_failaddr_t fa;
|
||||
|
||||
xfs_bmbt_disk_get_all(frp, &new);
|
||||
if (!xfs_bmbt_validate_extent(mp, whichfork, &new)) {
|
||||
XFS_ERROR_REPORT("xfs_bmap_read_extents(2)",
|
||||
XFS_ERRLEVEL_LOW, mp);
|
||||
fa = xfs_bmap_validate_extent(ip, whichfork, &new);
|
||||
if (fa) {
|
||||
error = -EFSCORRUPTED;
|
||||
xfs_inode_verifier_error(ip, error,
|
||||
"xfs_iread_extents(2)",
|
||||
frp, sizeof(*frp), fa);
|
||||
goto out_brelse;
|
||||
}
|
||||
xfs_iext_insert(ip, &icur, &new, state);
|
||||
@@ -6154,3 +6159,39 @@ xfs_bmap_finish_one(
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Check that an inode's extent does not have invalid flags or bad ranges. */
|
||||
xfs_failaddr_t
|
||||
xfs_bmap_validate_extent(
|
||||
struct xfs_inode *ip,
|
||||
int whichfork,
|
||||
struct xfs_bmbt_irec *irec)
|
||||
{
|
||||
struct xfs_mount *mp = ip->i_mount;
|
||||
xfs_fsblock_t endfsb;
|
||||
bool isrt;
|
||||
|
||||
isrt = XFS_IS_REALTIME_INODE(ip);
|
||||
endfsb = irec->br_startblock + irec->br_blockcount - 1;
|
||||
if (isrt) {
|
||||
if (!xfs_verify_rtbno(mp, irec->br_startblock))
|
||||
return __this_address;
|
||||
if (!xfs_verify_rtbno(mp, endfsb))
|
||||
return __this_address;
|
||||
} else {
|
||||
if (!xfs_verify_fsbno(mp, irec->br_startblock))
|
||||
return __this_address;
|
||||
if (!xfs_verify_fsbno(mp, endfsb))
|
||||
return __this_address;
|
||||
if (XFS_FSB_TO_AGNO(mp, irec->br_startblock) !=
|
||||
XFS_FSB_TO_AGNO(mp, endfsb))
|
||||
return __this_address;
|
||||
}
|
||||
if (irec->br_state != XFS_EXT_NORM) {
|
||||
if (whichfork != XFS_DATA_FORK)
|
||||
return __this_address;
|
||||
if (!xfs_sb_version_hasextflgbit(&mp->m_sb))
|
||||
return __this_address;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -274,4 +274,7 @@ static inline int xfs_bmap_fork_to_state(int whichfork)
|
||||
}
|
||||
}
|
||||
|
||||
xfs_failaddr_t xfs_bmap_validate_extent(struct xfs_inode *ip, int whichfork,
|
||||
struct xfs_bmbt_irec *irec);
|
||||
|
||||
#endif /* __XFS_BMAP_H__ */
|
||||
|
||||
@@ -272,10 +272,10 @@ xfs_bmbt_alloc_block(
|
||||
cur->bc_private.b.dfops->dop_low = true;
|
||||
}
|
||||
if (WARN_ON_ONCE(args.fsbno == NULLFSBLOCK)) {
|
||||
XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
|
||||
*stat = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ASSERT(args.len == 1);
|
||||
cur->bc_private.b.firstblock = args.fsbno;
|
||||
cur->bc_private.b.allocated++;
|
||||
@@ -286,12 +286,10 @@ xfs_bmbt_alloc_block(
|
||||
|
||||
new->l = cpu_to_be64(args.fsbno);
|
||||
|
||||
XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
|
||||
*stat = 1;
|
||||
return 0;
|
||||
|
||||
error0:
|
||||
XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@@ -118,18 +118,4 @@ extern int xfs_bmbt_change_owner(struct xfs_trans *tp, struct xfs_inode *ip,
|
||||
extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *,
|
||||
struct xfs_trans *, struct xfs_inode *, int);
|
||||
|
||||
/*
|
||||
* Check that the extent does not contain an invalid unwritten extent flag.
|
||||
*/
|
||||
static inline bool xfs_bmbt_validate_extent(struct xfs_mount *mp, int whichfork,
|
||||
struct xfs_bmbt_irec *irec)
|
||||
{
|
||||
if (irec->br_state == XFS_EXT_NORM)
|
||||
return true;
|
||||
if (whichfork == XFS_DATA_FORK &&
|
||||
xfs_sb_version_hasextflgbit(&mp->m_sb))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* __XFS_BMAP_BTREE_H__ */
|
||||
|
||||
+9
-116
File diff suppressed because it is too large
Load Diff
@@ -473,25 +473,6 @@ static inline int xfs_btree_get_level(struct xfs_btree_block *block)
|
||||
#define XFS_FILBLKS_MIN(a,b) min_t(xfs_filblks_t, (a), (b))
|
||||
#define XFS_FILBLKS_MAX(a,b) max_t(xfs_filblks_t, (a), (b))
|
||||
|
||||
/*
|
||||
* Trace hooks. Currently not implemented as they need to be ported
|
||||
* over to the generic tracing functionality, which is some effort.
|
||||
*
|
||||
* i,j = integer (32 bit)
|
||||
* b = btree block buffer (xfs_buf_t)
|
||||
* p = btree ptr
|
||||
* r = btree record
|
||||
* k = btree key
|
||||
*/
|
||||
#define XFS_BTREE_TRACE_ARGBI(c, b, i)
|
||||
#define XFS_BTREE_TRACE_ARGBII(c, b, i, j)
|
||||
#define XFS_BTREE_TRACE_ARGI(c, i)
|
||||
#define XFS_BTREE_TRACE_ARGIPK(c, i, p, s)
|
||||
#define XFS_BTREE_TRACE_ARGIPR(c, i, p, r)
|
||||
#define XFS_BTREE_TRACE_ARGIK(c, i, k)
|
||||
#define XFS_BTREE_TRACE_ARGR(c, r)
|
||||
#define XFS_BTREE_TRACE_CURSOR(c, t)
|
||||
|
||||
xfs_failaddr_t xfs_btree_sblock_v5hdr_verify(struct xfs_buf *bp);
|
||||
xfs_failaddr_t xfs_btree_sblock_verify(struct xfs_buf *bp,
|
||||
unsigned int max_recs);
|
||||
|
||||
@@ -173,7 +173,7 @@ extern void xfs_dir2_data_log_unused(struct xfs_da_args *args,
|
||||
extern void xfs_dir2_data_make_free(struct xfs_da_args *args,
|
||||
struct xfs_buf *bp, xfs_dir2_data_aoff_t offset,
|
||||
xfs_dir2_data_aoff_t len, int *needlogp, int *needscanp);
|
||||
extern void xfs_dir2_data_use_free(struct xfs_da_args *args,
|
||||
extern int xfs_dir2_data_use_free(struct xfs_da_args *args,
|
||||
struct xfs_buf *bp, struct xfs_dir2_data_unused *dup,
|
||||
xfs_dir2_data_aoff_t offset, xfs_dir2_data_aoff_t len,
|
||||
int *needlogp, int *needscanp);
|
||||
|
||||
@@ -451,15 +451,19 @@ xfs_dir2_block_addname(
|
||||
* No stale entries, will use enddup space to hold new leaf.
|
||||
*/
|
||||
if (!btp->stale) {
|
||||
xfs_dir2_data_aoff_t aoff;
|
||||
|
||||
/*
|
||||
* Mark the space needed for the new leaf entry, now in use.
|
||||
*/
|
||||
xfs_dir2_data_use_free(args, bp, enddup,
|
||||
(xfs_dir2_data_aoff_t)
|
||||
((char *)enddup - (char *)hdr + be16_to_cpu(enddup->length) -
|
||||
sizeof(*blp)),
|
||||
(xfs_dir2_data_aoff_t)sizeof(*blp),
|
||||
&needlog, &needscan);
|
||||
aoff = (xfs_dir2_data_aoff_t)((char *)enddup - (char *)hdr +
|
||||
be16_to_cpu(enddup->length) - sizeof(*blp));
|
||||
error = xfs_dir2_data_use_free(args, bp, enddup, aoff,
|
||||
(xfs_dir2_data_aoff_t)sizeof(*blp), &needlog,
|
||||
&needscan);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* Update the tail (entry count).
|
||||
*/
|
||||
@@ -541,9 +545,11 @@ xfs_dir2_block_addname(
|
||||
/*
|
||||
* Mark space for the data entry used.
|
||||
*/
|
||||
xfs_dir2_data_use_free(args, bp, dup,
|
||||
(xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr),
|
||||
(xfs_dir2_data_aoff_t)len, &needlog, &needscan);
|
||||
error = xfs_dir2_data_use_free(args, bp, dup,
|
||||
(xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr),
|
||||
(xfs_dir2_data_aoff_t)len, &needlog, &needscan);
|
||||
if (error)
|
||||
return error;
|
||||
/*
|
||||
* Create the new data entry.
|
||||
*/
|
||||
@@ -997,8 +1003,10 @@ xfs_dir2_leaf_to_block(
|
||||
/*
|
||||
* Use up the space at the end of the block (blp/btp).
|
||||
*/
|
||||
xfs_dir2_data_use_free(args, dbp, dup, args->geo->blksize - size, size,
|
||||
&needlog, &needscan);
|
||||
error = xfs_dir2_data_use_free(args, dbp, dup,
|
||||
args->geo->blksize - size, size, &needlog, &needscan);
|
||||
if (error)
|
||||
return error;
|
||||
/*
|
||||
* Initialize the block tail.
|
||||
*/
|
||||
@@ -1110,18 +1118,14 @@ xfs_dir2_sf_to_block(
|
||||
* Add block 0 to the inode.
|
||||
*/
|
||||
error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &blkno);
|
||||
if (error) {
|
||||
kmem_free(sfp);
|
||||
return error;
|
||||
}
|
||||
if (error)
|
||||
goto out_free;
|
||||
/*
|
||||
* Initialize the data block, then convert it to block format.
|
||||
*/
|
||||
error = xfs_dir3_data_init(args, blkno, &bp);
|
||||
if (error) {
|
||||
kmem_free(sfp);
|
||||
return error;
|
||||
}
|
||||
if (error)
|
||||
goto out_free;
|
||||
xfs_dir3_block_init(mp, tp, bp, dp);
|
||||
hdr = bp->b_addr;
|
||||
|
||||
@@ -1136,8 +1140,10 @@ xfs_dir2_sf_to_block(
|
||||
*/
|
||||
dup = dp->d_ops->data_unused_p(hdr);
|
||||
needlog = needscan = 0;
|
||||
xfs_dir2_data_use_free(args, bp, dup, args->geo->blksize - i,
|
||||
i, &needlog, &needscan);
|
||||
error = xfs_dir2_data_use_free(args, bp, dup, args->geo->blksize - i,
|
||||
i, &needlog, &needscan);
|
||||
if (error)
|
||||
goto out_free;
|
||||
ASSERT(needscan == 0);
|
||||
/*
|
||||
* Fill in the tail.
|
||||
@@ -1150,9 +1156,11 @@ xfs_dir2_sf_to_block(
|
||||
/*
|
||||
* Remove the freespace, we'll manage it.
|
||||
*/
|
||||
xfs_dir2_data_use_free(args, bp, dup,
|
||||
(xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr),
|
||||
be16_to_cpu(dup->length), &needlog, &needscan);
|
||||
error = xfs_dir2_data_use_free(args, bp, dup,
|
||||
(xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr),
|
||||
be16_to_cpu(dup->length), &needlog, &needscan);
|
||||
if (error)
|
||||
goto out_free;
|
||||
/*
|
||||
* Create entry for .
|
||||
*/
|
||||
@@ -1256,4 +1264,7 @@ xfs_dir2_sf_to_block(
|
||||
xfs_dir2_block_log_tail(tp, bp);
|
||||
xfs_dir3_data_check(dp, bp);
|
||||
return 0;
|
||||
out_free:
|
||||
kmem_free(sfp);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -932,10 +932,51 @@ xfs_dir2_data_make_free(
|
||||
*needscanp = needscan;
|
||||
}
|
||||
|
||||
/* Check our free data for obvious signs of corruption. */
|
||||
static inline xfs_failaddr_t
|
||||
xfs_dir2_data_check_free(
|
||||
struct xfs_dir2_data_hdr *hdr,
|
||||
struct xfs_dir2_data_unused *dup,
|
||||
xfs_dir2_data_aoff_t offset,
|
||||
xfs_dir2_data_aoff_t len)
|
||||
{
|
||||
if (hdr->magic != cpu_to_be32(XFS_DIR2_DATA_MAGIC) &&
|
||||
hdr->magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC) &&
|
||||
hdr->magic != cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) &&
|
||||
hdr->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC))
|
||||
return __this_address;
|
||||
if (be16_to_cpu(dup->freetag) != XFS_DIR2_DATA_FREE_TAG)
|
||||
return __this_address;
|
||||
if (offset < (char *)dup - (char *)hdr)
|
||||
return __this_address;
|
||||
if (offset + len > (char *)dup + be16_to_cpu(dup->length) - (char *)hdr)
|
||||
return __this_address;
|
||||
if ((char *)dup - (char *)hdr !=
|
||||
be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)))
|
||||
return __this_address;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Sanity-check a new bestfree entry. */
|
||||
static inline xfs_failaddr_t
|
||||
xfs_dir2_data_check_new_free(
|
||||
struct xfs_dir2_data_hdr *hdr,
|
||||
struct xfs_dir2_data_free *dfp,
|
||||
struct xfs_dir2_data_unused *newdup)
|
||||
{
|
||||
if (dfp == NULL)
|
||||
return __this_address;
|
||||
if (dfp->length != newdup->length)
|
||||
return __this_address;
|
||||
if (be16_to_cpu(dfp->offset) != (char *)newdup - (char *)hdr)
|
||||
return __this_address;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Take a byte range out of an existing unused space and make it un-free.
|
||||
*/
|
||||
void
|
||||
int
|
||||
xfs_dir2_data_use_free(
|
||||
struct xfs_da_args *args,
|
||||
struct xfs_buf *bp,
|
||||
@@ -947,23 +988,19 @@ xfs_dir2_data_use_free(
|
||||
{
|
||||
xfs_dir2_data_hdr_t *hdr; /* data block header */
|
||||
xfs_dir2_data_free_t *dfp; /* bestfree pointer */
|
||||
xfs_dir2_data_unused_t *newdup; /* new unused entry */
|
||||
xfs_dir2_data_unused_t *newdup2; /* another new unused entry */
|
||||
struct xfs_dir2_data_free *bf;
|
||||
xfs_failaddr_t fa;
|
||||
int matchback; /* matches end of freespace */
|
||||
int matchfront; /* matches start of freespace */
|
||||
int needscan; /* need to regen bestfree */
|
||||
xfs_dir2_data_unused_t *newdup; /* new unused entry */
|
||||
xfs_dir2_data_unused_t *newdup2; /* another new unused entry */
|
||||
int oldlen; /* old unused entry's length */
|
||||
struct xfs_dir2_data_free *bf;
|
||||
|
||||
hdr = bp->b_addr;
|
||||
ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
|
||||
hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
|
||||
hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
|
||||
hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
|
||||
ASSERT(be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG);
|
||||
ASSERT(offset >= (char *)dup - (char *)hdr);
|
||||
ASSERT(offset + len <= (char *)dup + be16_to_cpu(dup->length) - (char *)hdr);
|
||||
ASSERT((char *)dup - (char *)hdr == be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)));
|
||||
fa = xfs_dir2_data_check_free(hdr, dup, offset, len);
|
||||
if (fa)
|
||||
goto corrupt;
|
||||
/*
|
||||
* Look up the entry in the bestfree table.
|
||||
*/
|
||||
@@ -1008,9 +1045,9 @@ xfs_dir2_data_use_free(
|
||||
xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
|
||||
dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup,
|
||||
needlogp);
|
||||
ASSERT(dfp != NULL);
|
||||
ASSERT(dfp->length == newdup->length);
|
||||
ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)hdr);
|
||||
fa = xfs_dir2_data_check_new_free(hdr, dfp, newdup);
|
||||
if (fa)
|
||||
goto corrupt;
|
||||
/*
|
||||
* If we got inserted at the last slot,
|
||||
* that means we don't know if there was a better
|
||||
@@ -1036,9 +1073,9 @@ xfs_dir2_data_use_free(
|
||||
xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
|
||||
dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup,
|
||||
needlogp);
|
||||
ASSERT(dfp != NULL);
|
||||
ASSERT(dfp->length == newdup->length);
|
||||
ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)hdr);
|
||||
fa = xfs_dir2_data_check_new_free(hdr, dfp, newdup);
|
||||
if (fa)
|
||||
goto corrupt;
|
||||
/*
|
||||
* If we got inserted at the last slot,
|
||||
* that means we don't know if there was a better
|
||||
@@ -1084,6 +1121,11 @@ xfs_dir2_data_use_free(
|
||||
}
|
||||
}
|
||||
*needscanp = needscan;
|
||||
return 0;
|
||||
corrupt:
|
||||
xfs_corruption_error(__func__, XFS_ERRLEVEL_LOW, args->dp->i_mount,
|
||||
hdr, __FILE__, __LINE__, fa);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
/* Find the end of the entry data in a data/block format dir block. */
|
||||
|
||||
@@ -877,9 +877,13 @@ xfs_dir2_leaf_addname(
|
||||
/*
|
||||
* Mark the initial part of our freespace in use for the new entry.
|
||||
*/
|
||||
xfs_dir2_data_use_free(args, dbp, dup,
|
||||
(xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), length,
|
||||
&needlog, &needscan);
|
||||
error = xfs_dir2_data_use_free(args, dbp, dup,
|
||||
(xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr),
|
||||
length, &needlog, &needscan);
|
||||
if (error) {
|
||||
xfs_trans_brelse(tp, lbp);
|
||||
return error;
|
||||
}
|
||||
/*
|
||||
* Initialize our new entry (at last).
|
||||
*/
|
||||
@@ -1415,7 +1419,8 @@ xfs_dir2_leaf_removename(
|
||||
oldbest = be16_to_cpu(bf[0].length);
|
||||
ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
|
||||
bestsp = xfs_dir2_leaf_bests_p(ltp);
|
||||
ASSERT(be16_to_cpu(bestsp[db]) == oldbest);
|
||||
if (be16_to_cpu(bestsp[db]) != oldbest)
|
||||
return -EFSCORRUPTED;
|
||||
/*
|
||||
* Mark the former data entry unused.
|
||||
*/
|
||||
|
||||
@@ -387,8 +387,9 @@ xfs_dir2_leaf_to_node(
|
||||
dp->d_ops->free_hdr_from_disk(&freehdr, free);
|
||||
leaf = lbp->b_addr;
|
||||
ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
|
||||
ASSERT(be32_to_cpu(ltp->bestcount) <=
|
||||
(uint)dp->i_d.di_size / args->geo->blksize);
|
||||
if (be32_to_cpu(ltp->bestcount) >
|
||||
(uint)dp->i_d.di_size / args->geo->blksize)
|
||||
return -EFSCORRUPTED;
|
||||
|
||||
/*
|
||||
* Copy freespace entries from the leaf block to the new block.
|
||||
@@ -1728,6 +1729,7 @@ xfs_dir2_node_addname_int(
|
||||
__be16 *bests;
|
||||
struct xfs_dir3_icfree_hdr freehdr;
|
||||
struct xfs_dir2_data_free *bf;
|
||||
xfs_dir2_data_aoff_t aoff;
|
||||
|
||||
dp = args->dp;
|
||||
mp = dp->i_mount;
|
||||
@@ -2022,9 +2024,13 @@ xfs_dir2_node_addname_int(
|
||||
/*
|
||||
* Mark the first part of the unused space, inuse for us.
|
||||
*/
|
||||
xfs_dir2_data_use_free(args, dbp, dup,
|
||||
(xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), length,
|
||||
&needlog, &needscan);
|
||||
aoff = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr);
|
||||
error = xfs_dir2_data_use_free(args, dbp, dup, aoff, length,
|
||||
&needlog, &needscan);
|
||||
if (error) {
|
||||
xfs_trans_brelse(tp, dbp);
|
||||
return error;
|
||||
}
|
||||
/*
|
||||
* Fill in the new entry and log it.
|
||||
*/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user