Bug fixes for 6.10-rc2:

* Fix a livelock by dropping an xfarray sortinfo folio when an error is
    encountered.
  * During extended attribute operations, Initialize transaction reservation
    computation based on attribute operation code.
  * Relax symbolic link's ondisk verification code to allow symbolic links
    with short remote targets.
  * Prevent soft lockups when unmapping file ranges and also during remapping
    blocks during a reflink operation.
  * Fix compilation warnings when XFS is built with W=1 option.
 
 Signed-off-by: Chandan Babu R <chandanbabu@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQQjMC4mbgVeU7MxEIYH7y4RirJu9AUCZlbRngAKCRAH7y4RirJu
 9DFfAP0aQYHIGOUx6YCvucoLtIRWYqaxDvgWPjLrtaeiUSmY7AEA1M4BVl/2Svkj
 hgs1/qqU8WGze/KqdG/aJbJS0ZqJKAU=
 =gxY4
 -----END PGP SIGNATURE-----

Merge tag 'xfs-6.10-fixes-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux

Pull xfs fixes from Chandan Babu:

 - Fix a livelock by dropping an xfarray sortinfo folio when an error
   is encountered

 - During extended attribute operations, Initialize transaction
   reservation computation based on attribute operation code

 - Relax symbolic link's ondisk verification code to allow symbolic
   links with short remote targets

 - Prevent soft lockups when unmapping file ranges and also during
   remapping blocks during a reflink operation

 - Fix compilation warnings when XFS is built with W=1 option

* tag 'xfs-6.10-fixes-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
  xfs: Add cond_resched to block unmap range and reflink remap path
  xfs: don't open-code u64_to_user_ptr
  xfs: allow symlinks with short remote targets
  xfs: fix xfs_init_attr_trans not handling explicit operation codes
  xfs: drop xfarray sortinfo folio on error
  xfs: Stop using __maybe_unused in xfs_alloc.c
  xfs: Clear W=1 warning in xfs_iwalk_run_callbacks()
This commit is contained in:
Linus Torvalds 2024-06-01 08:59:04 -07:00
commit bbeb1219ee
11 changed files with 72 additions and 45 deletions

View File

@ -1008,13 +1008,12 @@ xfs_alloc_cur_finish(
struct xfs_alloc_arg *args,
struct xfs_alloc_cur *acur)
{
struct xfs_agf __maybe_unused *agf = args->agbp->b_addr;
int error;
ASSERT(acur->cnt && acur->bnolt);
ASSERT(acur->bno >= acur->rec_bno);
ASSERT(acur->bno + acur->len <= acur->rec_bno + acur->rec_len);
ASSERT(acur->rec_bno + acur->rec_len <= be32_to_cpu(agf->agf_length));
ASSERT(xfs_verify_agbext(args->pag, acur->rec_bno, acur->rec_len));
error = xfs_alloc_fixup_trees(acur->cnt, acur->bnolt, acur->rec_bno,
acur->rec_len, acur->bno, acur->len, 0);
@ -1217,7 +1216,6 @@ STATIC int /* error */
xfs_alloc_ag_vextent_exact(
xfs_alloc_arg_t *args) /* allocation argument structure */
{
struct xfs_agf __maybe_unused *agf = args->agbp->b_addr;
struct xfs_btree_cur *bno_cur;/* by block-number btree cursor */
struct xfs_btree_cur *cnt_cur;/* by count btree cursor */
int error;
@ -1297,7 +1295,7 @@ xfs_alloc_ag_vextent_exact(
*/
cnt_cur = xfs_cntbt_init_cursor(args->mp, args->tp, args->agbp,
args->pag);
ASSERT(args->agbno + args->len <= be32_to_cpu(agf->agf_length));
ASSERT(xfs_verify_agbext(args->pag, args->agbno, args->len));
error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, args->agbno,
args->len, XFSA_FIXUP_BNO_OK);
if (error) {

View File

@ -329,26 +329,20 @@ xfs_attr_calc_size(
return nblks;
}
/* Initialize transaction reservation for attr operations */
void
xfs_init_attr_trans(
struct xfs_da_args *args,
struct xfs_trans_res *tres,
unsigned int *total)
/* Initialize transaction reservation for an xattr set/replace/upsert */
inline struct xfs_trans_res
xfs_attr_set_resv(
const struct xfs_da_args *args)
{
struct xfs_mount *mp = args->dp->i_mount;
struct xfs_mount *mp = args->dp->i_mount;
struct xfs_trans_res ret = {
.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
M_RES(mp)->tr_attrsetrt.tr_logres * args->total,
.tr_logcount = XFS_ATTRSET_LOG_COUNT,
.tr_logflags = XFS_TRANS_PERM_LOG_RES,
};
if (args->value) {
tres->tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
M_RES(mp)->tr_attrsetrt.tr_logres *
args->total;
tres->tr_logcount = XFS_ATTRSET_LOG_COUNT;
tres->tr_logflags = XFS_TRANS_PERM_LOG_RES;
*total = args->total;
} else {
*tres = M_RES(mp)->tr_attrrm;
*total = XFS_ATTRRM_SPACE_RES(mp);
}
return ret;
}
/*
@ -1006,7 +1000,7 @@ xfs_attr_set(
struct xfs_trans_res tres;
int error, local;
int rmt_blks = 0;
unsigned int total;
unsigned int total = 0;
ASSERT(!args->trans);
@ -1033,10 +1027,15 @@ xfs_attr_set(
if (!local)
rmt_blks = xfs_attr3_rmt_blocks(mp, args->valuelen);
tres = xfs_attr_set_resv(args);
total = args->total;
break;
case XFS_ATTRUPDATE_REMOVE:
XFS_STATS_INC(mp, xs_attr_remove);
rmt_blks = xfs_attr3_max_rmt_blocks(mp);
tres = M_RES(mp)->tr_attrrm;
total = XFS_ATTRRM_SPACE_RES(mp);
break;
}
@ -1044,7 +1043,6 @@ xfs_attr_set(
* Root fork attributes can use reserved data blocks for this
* operation if necessary
*/
xfs_init_attr_trans(args, &tres, &total);
error = xfs_trans_alloc_inode(dp, &tres, total, 0, rsvd, &args->trans);
if (error)
return error;

View File

@ -565,8 +565,7 @@ bool xfs_attr_check_namespace(unsigned int attr_flags);
bool xfs_attr_namecheck(unsigned int attr_flags, const void *name,
size_t length);
int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
void xfs_init_attr_trans(struct xfs_da_args *args, struct xfs_trans_res *tres,
unsigned int *total);
struct xfs_trans_res xfs_attr_set_resv(const struct xfs_da_args *args);
/*
* Check to see if the attr should be upgraded from non-existent or shortform to

View File

@ -6383,6 +6383,7 @@ xfs_bunmapi_range(
error = xfs_defer_finish(tpp);
if (error)
goto out;
cond_resched();
}
out:
return error;

View File

@ -374,17 +374,37 @@ xfs_dinode_verify_fork(
/*
* For fork types that can contain local data, check that the fork
* format matches the size of local data contained within the fork.
*
* For all types, check that when the size says the should be in extent
* or btree format, the inode isn't claiming it is in local format.
*/
if (whichfork == XFS_DATA_FORK) {
if (S_ISDIR(mode) || S_ISLNK(mode)) {
/*
* A directory small enough to fit in the inode must be stored
* in local format. The directory sf <-> extents conversion
* code updates the directory size accordingly.
*/
if (S_ISDIR(mode)) {
if (be64_to_cpu(dip->di_size) <= fork_size &&
fork_format != XFS_DINODE_FMT_LOCAL)
return __this_address;
}
/*
* A symlink with a target small enough to fit in the inode can
* be stored in extents format if xattrs were added (thus
* converting the data fork from shortform to remote format)
* and then removed.
*/
if (S_ISLNK(mode)) {
if (be64_to_cpu(dip->di_size) <= fork_size &&
fork_format != XFS_DINODE_FMT_EXTENTS &&
fork_format != XFS_DINODE_FMT_LOCAL)
return __this_address;
}
/*
* For all types, check that when the size says the fork should
* be in extent or btree format, the inode isn't claiming to be
* in local format.
*/
if (be64_to_cpu(dip->di_size) > fork_size &&
fork_format == XFS_DINODE_FMT_LOCAL)
return __this_address;

View File

@ -856,7 +856,7 @@ xfs_ioc_scrubv_metadata(
if (vec_bytes > PAGE_SIZE)
return -ENOMEM;
uvectors = (void __user *)(uintptr_t)head.svh_vectors;
uvectors = u64_to_user_ptr(head.svh_vectors);
vectors = memdup_user(uvectors, vec_bytes);
if (IS_ERR(vectors))
return PTR_ERR(vectors);

View File

@ -822,12 +822,14 @@ xfarray_sort_scan(
/* Grab the first folio that backs this array element. */
if (!si->folio) {
struct folio *folio;
loff_t next_pos;
si->folio = xfile_get_folio(si->array->xfile, idx_pos,
folio = xfile_get_folio(si->array->xfile, idx_pos,
si->array->obj_size, XFILE_ALLOC);
if (IS_ERR(si->folio))
return PTR_ERR(si->folio);
if (IS_ERR(folio))
return PTR_ERR(folio);
si->folio = folio;
si->first_folio_idx = xfarray_idx(si->array,
folio_pos(si->folio) + si->array->obj_size - 1);
@ -1048,6 +1050,7 @@ xfarray_sort(
out_free:
trace_xfarray_sort_stats(si, error);
xfarray_sort_scan_done(si);
kvfree(si);
return error;
}

View File

@ -746,7 +746,7 @@ xfs_attr_recover_work(
struct xfs_attri_log_format *attrp;
struct xfs_attri_log_nameval *nv = attrip->attri_nameval;
int error;
int total;
unsigned int total = 0;
/*
* First check the validity of the attr described by the ATTRI. If any
@ -763,7 +763,20 @@ xfs_attr_recover_work(
return PTR_ERR(attr);
args = attr->xattri_da_args;
xfs_init_attr_trans(args, &resv, &total);
switch (xfs_attr_intent_op(attr)) {
case XFS_ATTRI_OP_FLAGS_PPTR_SET:
case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:
case XFS_ATTRI_OP_FLAGS_SET:
case XFS_ATTRI_OP_FLAGS_REPLACE:
resv = xfs_attr_set_resv(args);
total = args->total;
break;
case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE:
case XFS_ATTRI_OP_FLAGS_REMOVE:
resv = M_RES(mp)->tr_attrrm;
total = XFS_ATTRRM_SPACE_RES(mp);
break;
}
resv = xlog_recover_resv(&resv);
error = xfs_trans_alloc(mp, &resv, total, 0, XFS_TRANS_RESERVE, &tp);
if (error)

View File

@ -773,11 +773,6 @@ xfs_getparents_expand_lastrec(
trace_xfs_getparents_expand_lastrec(gpx->ip, gp, &gpx->context, gpr);
}
static inline void __user *u64_to_uptr(u64 val)
{
return (void __user *)(uintptr_t)val;
}
/* Retrieve the parent pointers for a given inode. */
STATIC int
xfs_getparents(
@ -862,7 +857,7 @@ xfs_getparents(
ASSERT(gpx->context.firstu <= gpx->gph.gph_request.gp_bufsize);
/* Copy the records to userspace. */
if (copy_to_user(u64_to_uptr(gpx->gph.gph_request.gp_buffer),
if (copy_to_user(u64_to_user_ptr(gpx->gph.gph_request.gp_buffer),
gpx->krecords, gpx->context.firstu))
error = -EFAULT;

View File

@ -351,7 +351,6 @@ xfs_iwalk_run_callbacks(
int *has_more)
{
struct xfs_mount *mp = iwag->mp;
struct xfs_inobt_rec_incore *irec;
xfs_agino_t next_agino;
int error;
@ -361,8 +360,8 @@ xfs_iwalk_run_callbacks(
/* Delete cursor but remember the last record we cached... */
xfs_iwalk_del_inobt(iwag->tp, curpp, agi_bpp, 0);
irec = &iwag->recs[iwag->nr_recs - 1];
ASSERT(next_agino >= irec->ir_startino + XFS_INODES_PER_CHUNK);
ASSERT(next_agino >= iwag->recs[iwag->nr_recs - 1].ir_startino +
XFS_INODES_PER_CHUNK);
if (iwag->drop_trans) {
xfs_trans_cancel(iwag->tp);

View File

@ -1387,6 +1387,7 @@ xfs_reflink_remap_blocks(
destoff += imap.br_blockcount;
len -= imap.br_blockcount;
remapped_len += imap.br_blockcount;
cond_resched();
}
if (error)