Skip to content

Commit

Permalink
Merge tag 'xfs-6.10-fixes-1' of git://git.kernel.org/pub/scm/fs/xfs/x…
Browse files Browse the repository at this point in the history
…fs-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()
  • Loading branch information
torvalds committed Jun 1, 2024
2 parents f26ee67 + b0c6bcd commit bbeb121
Show file tree
Hide file tree
Showing 11 changed files with 73 additions and 46 deletions.
6 changes: 2 additions & 4 deletions fs/xfs/libxfs/xfs_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
40 changes: 19 additions & 21 deletions fs/xfs/libxfs/xfs_attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

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);
}
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,
};

return ret;
}

/*
Expand Down Expand Up @@ -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);

Expand All @@ -1033,18 +1027,22 @@ 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;
}

/*
* 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;
Expand Down
3 changes: 1 addition & 2 deletions fs/xfs/libxfs/xfs_attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions fs/xfs/libxfs/xfs_bmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -6383,6 +6383,7 @@ xfs_bunmapi_range(
error = xfs_defer_finish(tpp);
if (error)
goto out;
cond_resched();
}
out:
return error;
Expand Down
28 changes: 24 additions & 4 deletions fs/xfs/libxfs/xfs_inode_buf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/scrub/scrub.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
9 changes: 6 additions & 3 deletions fs/xfs/scrub/xfarray.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -1048,6 +1050,7 @@ xfarray_sort(

out_free:
trace_xfarray_sort_stats(si, error);
xfarray_sort_scan_done(si);
kvfree(si);
return error;
}
Expand Down
17 changes: 15 additions & 2 deletions fs/xfs/xfs_attr_item.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down
7 changes: 1 addition & 6 deletions fs/xfs/xfs_handle.c
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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;

Expand Down
5 changes: 2 additions & 3 deletions fs/xfs/xfs_iwalk.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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);
Expand Down
1 change: 1 addition & 0 deletions fs/xfs/xfs_reflink.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit bbeb121

Please sign in to comment.