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