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()
Unified · Split
| @@ -1008,13 +1008,12 @@ xfs_alloc_cur_finish( · 1007 unmodified lines | ||
| 1008 | 1008 | struct xfs_alloc_arg *args, |
| 1009 | 1009 | struct xfs_alloc_cur *acur) |
| 1010 | 1010 | { |
| 1011 | − struct xfs_agf __maybe_unused *agf = args->agbp->b_addr; | |
| 1012 | 1011 | int error; |
| 1013 | 1012 | |
| 1014 | 1013 | ASSERT(acur->cnt && acur->bnolt); |
| 1015 | 1014 | ASSERT(acur->bno >= acur->rec_bno); |
| 1016 | 1015 | ASSERT(acur->bno + acur->len <= acur->rec_bno + acur->rec_len); |
| 1017 | − ASSERT(acur->rec_bno + acur->rec_len <= be32_to_cpu(agf->agf_length)); | |
| 1016 | + ASSERT(xfs_verify_agbext(args->pag, acur->rec_bno, acur->rec_len)); | |
| 1018 | 1017 | |
| 1019 | 1018 | error = xfs_alloc_fixup_trees(acur->cnt, acur->bnolt, acur->rec_bno, |
| 1020 | 1019 | acur->rec_len, acur->bno, acur->len, 0); |
| @@ -1217,7 +1216,6 @@ STATIC int /* error */ · 196 unmodified lines | ||
| 1217 | 1216 | xfs_alloc_ag_vextent_exact( |
| 1218 | 1217 | xfs_alloc_arg_t *args) /* allocation argument structure */ |
| 1219 | 1218 | { |
| 1220 | − struct xfs_agf __maybe_unused *agf = args->agbp->b_addr; | |
| 1221 | 1219 | struct xfs_btree_cur *bno_cur;/* by block-number btree cursor */ |
| 1222 | 1220 | struct xfs_btree_cur *cnt_cur;/* by count btree cursor */ |
| 1223 | 1221 | int error; |
| @@ -1297,7 +1295,7 @@ xfs_alloc_ag_vextent_exact( · 73 unmodified lines | ||
| 1297 | 1295 | */ |
| 1298 | 1296 | cnt_cur = xfs_cntbt_init_cursor(args->mp, args->tp, args->agbp, |
| 1299 | 1297 | args->pag); |
| 1300 | − ASSERT(args->agbno + args->len <= be32_to_cpu(agf->agf_length)); | |
| 1298 | + ASSERT(xfs_verify_agbext(args->pag, args->agbno, args->len)); | |
| 1301 | 1299 | error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, args->agbno, |
| 1302 | 1300 | args->len, XFSA_FIXUP_BNO_OK); |
| 1303 | 1301 | if (error) { |
| @@ -329,26 +329,20 @@ xfs_attr_calc_size( · 328 unmodified lines | ||
| 329 | 329 | return nblks; |
| 330 | 330 | } |
| 331 | 331 | |
| 332 | −/* Initialize transaction reservation for attr operations */ | |
| 333 | −void | |
| 334 | −xfs_init_attr_trans( | |
| 335 | − struct xfs_da_args *args, | |
| 336 | − struct xfs_trans_res *tres, | |
| 337 | − unsigned int *total) | |
| 332 | +/* Initialize transaction reservation for an xattr set/replace/upsert */ | |
| 333 | +inline struct xfs_trans_res | |
| 334 | +xfs_attr_set_resv( | |
| 335 | + const struct xfs_da_args *args) | |
| 338 | 336 | { |
| 339 | − struct xfs_mount *mp = args->dp->i_mount; | |
| 340 | − | |
| 341 | − if (args->value) { | |
| 342 | − tres->tr_logres = M_RES(mp)->tr_attrsetm.tr_logres + | |
| 343 | − M_RES(mp)->tr_attrsetrt.tr_logres * | |
| 344 | − args->total; | |
| 345 | − tres->tr_logcount = XFS_ATTRSET_LOG_COUNT; | |
| 346 | − tres->tr_logflags = XFS_TRANS_PERM_LOG_RES; | |
| 347 | − *total = args->total; | |
| 348 | − } else { | |
| 349 | − *tres = M_RES(mp)->tr_attrrm; | |
| 350 | − *total = XFS_ATTRRM_SPACE_RES(mp); | |
| 351 | − } | |
| 337 | + struct xfs_mount *mp = args->dp->i_mount; | |
| 338 | + struct xfs_trans_res ret = { | |
| 339 | + .tr_logres = M_RES(mp)->tr_attrsetm.tr_logres + | |
| 340 | + M_RES(mp)->tr_attrsetrt.tr_logres * args->total, | |
| 341 | + .tr_logcount = XFS_ATTRSET_LOG_COUNT, | |
| 342 | + .tr_logflags = XFS_TRANS_PERM_LOG_RES, | |
| 343 | + }; | |
| 344 | + | |
| 345 | + return ret; | |
| 352 | 346 | } |
| 353 | 347 | |
| 354 | 348 | /* |
| @@ -1006,7 +1000,7 @@ xfs_attr_set( · 651 unmodified lines | ||
| 1006 | 1000 | struct xfs_trans_res tres; |
| 1007 | 1001 | int error, local; |
| 1008 | 1002 | int rmt_blks = 0; |
| 1009 | − unsigned int total; | |
| 1003 | + unsigned int total = 0; | |
| 1010 | 1004 | |
| 1011 | 1005 | ASSERT(!args->trans); |
| 1012 | 1006 | |
| @@ -1033,10 +1027,15 @@ xfs_attr_set( · 20 unmodified lines | ||
| 1033 | 1027 | |
| 1034 | 1028 | if (!local) |
| 1035 | 1029 | rmt_blks = xfs_attr3_rmt_blocks(mp, args->valuelen); |
| 1030 | + | |
| 1031 | + tres = xfs_attr_set_resv(args); | |
| 1032 | + total = args->total; | |
| 1036 | 1033 | break; |
| 1037 | 1034 | case XFS_ATTRUPDATE_REMOVE: |
| 1038 | 1035 | XFS_STATS_INC(mp, xs_attr_remove); |
| 1039 | 1036 | rmt_blks = xfs_attr3_max_rmt_blocks(mp); |
| 1037 | + tres = M_RES(mp)->tr_attrrm; | |
| 1038 | + total = XFS_ATTRRM_SPACE_RES(mp); | |
| 1040 | 1039 | break; |
| 1041 | 1040 | } |
| 1042 | 1041 | |
| @@ -1044,7 +1043,6 @@ xfs_attr_set( · 1 unmodified line | ||
| 1044 | 1043 | * Root fork attributes can use reserved data blocks for this |
| 1045 | 1044 | * operation if necessary |
| 1046 | 1045 | */ |
| 1047 | − xfs_init_attr_trans(args, &tres, &total); | |
| 1048 | 1046 | error = xfs_trans_alloc_inode(dp, &tres, total, 0, rsvd, &args->trans); |
| 1049 | 1047 | if (error) |
| 1050 | 1048 | return error; |
| @@ -565,8 +565,7 @@ bool xfs_attr_check_namespace(unsigned int attr_flags); · 564 unmodified lines | ||
| 565 | 565 | bool xfs_attr_namecheck(unsigned int attr_flags, const void *name, |
| 566 | 566 | size_t length); |
| 567 | 567 | int xfs_attr_calc_size(struct xfs_da_args *args, int *local); |
| 568 | −void xfs_init_attr_trans(struct xfs_da_args *args, struct xfs_trans_res *tres, | |
| 569 | − unsigned int *total); | |
| 568 | +struct xfs_trans_res xfs_attr_set_resv(const struct xfs_da_args *args); | |
| 570 | 569 | |
| 571 | 570 | /* |
| 572 | 571 | * Check to see if the attr should be upgraded from non-existent or shortform to |
| @@ -6383,6 +6383,7 @@ xfs_bunmapi_range( · 6382 unmodified lines | ||
| 6383 | 6383 | error = xfs_defer_finish(tpp); |
| 6384 | 6384 | if (error) |
| 6385 | 6385 | goto out; |
| 6386 | + cond_resched(); | |
| 6386 | 6387 | } |
| 6387 | 6388 | out: |
| 6388 | 6389 | return error; |
| @@ -374,17 +374,37 @@ xfs_dinode_verify_fork( · 373 unmodified lines | ||
| 374 | 374 | /* |
| 375 | 375 | * For fork types that can contain local data, check that the fork |
| 376 | 376 | * format matches the size of local data contained within the fork. |
| 377 | − * | |
| 378 | − * For all types, check that when the size says the should be in extent | |
| 379 | − * or btree format, the inode isn't claiming it is in local format. | |
| 380 | 377 | */ |
| 381 | 378 | if (whichfork == XFS_DATA_FORK) { |
| 382 | − if (S_ISDIR(mode) || S_ISLNK(mode)) { | |
| 379 | + /* | |
| 380 | + * A directory small enough to fit in the inode must be stored | |
| 381 | + * in local format. The directory sf <-> extents conversion | |
| 382 | + * code updates the directory size accordingly. | |
| 383 | + */ | |
| 384 | + if (S_ISDIR(mode)) { | |
| 385 | + if (be64_to_cpu(dip->di_size) <= fork_size && | |
| 386 | + fork_format != XFS_DINODE_FMT_LOCAL) | |
| 387 | + return __this_address; | |
| 388 | + } | |
| 389 | + | |
| 390 | + /* | |
| 391 | + * A symlink with a target small enough to fit in the inode can | |
| 392 | + * be stored in extents format if xattrs were added (thus | |
| 393 | + * converting the data fork from shortform to remote format) | |
| 394 | + * and then removed. | |
| 395 | + */ | |
| 396 | + if (S_ISLNK(mode)) { | |
| 383 | 397 | if (be64_to_cpu(dip->di_size) <= fork_size && |
| 398 | + fork_format != XFS_DINODE_FMT_EXTENTS && | |
| 384 | 399 | fork_format != XFS_DINODE_FMT_LOCAL) |
| 385 | 400 | return __this_address; |
| 386 | 401 | } |
| 387 | 402 | |
| 403 | + /* | |
| 404 | + * For all types, check that when the size says the fork should | |
| 405 | + * be in extent or btree format, the inode isn't claiming to be | |
| 406 | + * in local format. | |
| 407 | + */ | |
| 388 | 408 | if (be64_to_cpu(dip->di_size) > fork_size && |
| 389 | 409 | fork_format == XFS_DINODE_FMT_LOCAL) |
| 390 | 410 | return __this_address; |
| @@ -856,7 +856,7 @@ xfs_ioc_scrubv_metadata( · 855 unmodified lines | ||
| 856 | 856 | if (vec_bytes > PAGE_SIZE) |
| 857 | 857 | return -ENOMEM; |
| 858 | 858 | |
| 859 | − uvectors = (void __user *)(uintptr_t)head.svh_vectors; | |
| 859 | + uvectors = u64_to_user_ptr(head.svh_vectors); | |
| 860 | 860 | vectors = memdup_user(uvectors, vec_bytes); |
| 861 | 861 | if (IS_ERR(vectors)) |
| 862 | 862 | return PTR_ERR(vectors); |
| @@ -822,12 +822,14 @@ xfarray_sort_scan( · 821 unmodified lines | ||
| 822 | 822 | |
| 823 | 823 | /* Grab the first folio that backs this array element. */ |
| 824 | 824 | if (!si->folio) { |
| 825 | + struct folio *folio; | |
| 825 | 826 | loff_t next_pos; |
| 826 | 827 | |
| 827 | − si->folio = xfile_get_folio(si->array->xfile, idx_pos, | |
| 828 | + folio = xfile_get_folio(si->array->xfile, idx_pos, | |
| 828 | 829 | si->array->obj_size, XFILE_ALLOC); |
| 829 | − if (IS_ERR(si->folio)) | |
| 830 | − return PTR_ERR(si->folio); | |
| 830 | + if (IS_ERR(folio)) | |
| 831 | + return PTR_ERR(folio); | |
| 832 | + si->folio = folio; | |
| 831 | 833 | |
| 832 | 834 | si->first_folio_idx = xfarray_idx(si->array, |
| 833 | 835 | folio_pos(si->folio) + si->array->obj_size - 1); |
| @@ -1048,6 +1050,7 @@ xfarray_sort( · 214 unmodified lines | ||
| 1048 | 1050 | |
| 1049 | 1051 | out_free: |
| 1050 | 1052 | trace_xfarray_sort_stats(si, error); |
| 1053 | + xfarray_sort_scan_done(si); | |
| 1051 | 1054 | kvfree(si); |
| 1052 | 1055 | return error; |
| 1053 | 1056 | } |
| @@ -746,7 +746,7 @@ xfs_attr_recover_work( · 745 unmodified lines | ||
| 746 | 746 | struct xfs_attri_log_format *attrp; |
| 747 | 747 | struct xfs_attri_log_nameval *nv = attrip->attri_nameval; |
| 748 | 748 | int error; |
| 749 | − int total; | |
| 749 | + unsigned int total = 0; | |
| 750 | 750 | |
| 751 | 751 | /* |
| 752 | 752 | * First check the validity of the attr described by the ATTRI. If any |
| @@ -763,7 +763,20 @@ xfs_attr_recover_work( · 10 unmodified lines | ||
| 763 | 763 | return PTR_ERR(attr); |
| 764 | 764 | args = attr->xattri_da_args; |
| 765 | 765 | |
| 766 | − xfs_init_attr_trans(args, &resv, &total); | |
| 766 | + switch (xfs_attr_intent_op(attr)) { | |
| 767 | + case XFS_ATTRI_OP_FLAGS_PPTR_SET: | |
| 768 | + case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE: | |
| 769 | + case XFS_ATTRI_OP_FLAGS_SET: | |
| 770 | + case XFS_ATTRI_OP_FLAGS_REPLACE: | |
| 771 | + resv = xfs_attr_set_resv(args); | |
| 772 | + total = args->total; | |
| 773 | + break; | |
| 774 | + case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE: | |
| 775 | + case XFS_ATTRI_OP_FLAGS_REMOVE: | |
| 776 | + resv = M_RES(mp)->tr_attrrm; | |
| 777 | + total = XFS_ATTRRM_SPACE_RES(mp); | |
| 778 | + break; | |
| 779 | + } | |
| 767 | 780 | resv = xlog_recover_resv(&resv); |
| 768 | 781 | error = xfs_trans_alloc(mp, &resv, total, 0, XFS_TRANS_RESERVE, &tp); |
| 769 | 782 | if (error) |
| @@ -773,11 +773,6 @@ xfs_getparents_expand_lastrec( · 772 unmodified lines | ||
| 773 | 773 | trace_xfs_getparents_expand_lastrec(gpx->ip, gp, &gpx->context, gpr); |
| 774 | 774 | } |
| 775 | 775 | |
| 776 | −static inline void __user *u64_to_uptr(u64 val) | |
| 777 | −{ | |
| 778 | − return (void __user *)(uintptr_t)val; | |
| 779 | −} | |
| 780 | − | |
| 781 | 776 | /* Retrieve the parent pointers for a given inode. */ |
| 782 | 777 | STATIC int |
| 783 | 778 | xfs_getparents( |
| @@ -862,7 +857,7 @@ xfs_getparents( · 78 unmodified lines | ||
| 862 | 857 | ASSERT(gpx->context.firstu <= gpx->gph.gph_request.gp_bufsize); |
| 863 | 858 | |
| 864 | 859 | /* Copy the records to userspace. */ |
| 865 | − if (copy_to_user(u64_to_uptr(gpx->gph.gph_request.gp_buffer), | |
| 860 | + if (copy_to_user(u64_to_user_ptr(gpx->gph.gph_request.gp_buffer), | |
| 866 | 861 | gpx->krecords, gpx->context.firstu)) |
| 867 | 862 | error = -EFAULT; |
| 868 | 863 | |
| @@ -351,7 +351,6 @@ xfs_iwalk_run_callbacks( · 350 unmodified lines | ||
| 351 | 351 | int *has_more) |
| 352 | 352 | { |
| 353 | 353 | struct xfs_mount *mp = iwag->mp; |
| 354 | − struct xfs_inobt_rec_incore *irec; | |
| 355 | 354 | xfs_agino_t next_agino; |
| 356 | 355 | int error; |
| 357 | 356 | |
| @@ -361,8 +360,8 @@ xfs_iwalk_run_callbacks( · 3 unmodified lines | ||
| 361 | 360 | |
| 362 | 361 | /* Delete cursor but remember the last record we cached... */ |
| 363 | 362 | xfs_iwalk_del_inobt(iwag->tp, curpp, agi_bpp, 0); |
| 364 | − irec = &iwag->recs[iwag->nr_recs - 1]; | |
| 365 | − ASSERT(next_agino >= irec->ir_startino + XFS_INODES_PER_CHUNK); | |
| 363 | + ASSERT(next_agino >= iwag->recs[iwag->nr_recs - 1].ir_startino + | |
| 364 | + XFS_INODES_PER_CHUNK); | |
| 366 | 365 | |
| 367 | 366 | if (iwag->drop_trans) { |
| 368 | 367 | xfs_trans_cancel(iwag->tp); |
| @@ -1387,6 +1387,7 @@ xfs_reflink_remap_blocks( · 1386 unmodified lines | ||
| 1387 | 1387 | destoff += imap.br_blockcount; |
| 1388 | 1388 | len -= imap.br_blockcount; |
| 1389 | 1389 | remapped_len += imap.br_blockcount; |
| 1390 | + cond_resched(); | |
| 1390 | 1391 | } |
| 1391 | 1392 | |
| 1392 | 1393 | if (error) |