Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

udf: refactor udf_next_aext() to handle error

Since udf_current_aext() has error handling, udf_next_aext() should have
error handling too. Besides, when too many indirect extents found in one
inode, return -EFSCORRUPTED; when reading block failed, return -EIO.

Signed-off-by: Zhao Mengmeng <zhaomengmeng@kylinos.cn>
Suggested-by: Jan Kara <jack@suse.cz>
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20241001115425.266556-3-zhaomzhao@126.com

authored by

Zhao Mengmeng and committed by
Jan Kara
b405c1e5 ee703a70

+143 -65
+25 -13
fs/udf/balloc.c
··· 370 370 struct extent_position oepos, epos; 371 371 int8_t etype; 372 372 struct udf_inode_info *iinfo; 373 + int ret = 0; 373 374 374 375 mutex_lock(&sbi->s_alloc_mutex); 375 376 iinfo = UDF_I(table); ··· 384 383 epos.block = oepos.block = iinfo->i_location; 385 384 epos.bh = oepos.bh = NULL; 386 385 387 - while (count && 388 - (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) { 386 + while (count) { 387 + ret = udf_next_aext(table, &epos, &eloc, &elen, &etype, 1); 388 + if (ret < 0) 389 + goto error_return; 390 + if (ret == 0) 391 + break; 389 392 if (((eloc.logicalBlockNum + 390 393 (elen >> sb->s_blocksize_bits)) == start)) { 391 394 if ((0x3FFFFFFF - elen) < ··· 464 459 adsize = sizeof(struct short_ad); 465 460 else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) 466 461 adsize = sizeof(struct long_ad); 467 - else { 468 - brelse(oepos.bh); 469 - brelse(epos.bh); 462 + else 470 463 goto error_return; 471 - } 472 464 473 465 if (epos.offset + (2 * adsize) > sb->s_blocksize) { 474 466 /* Steal a block from the extent being free'd */ ··· 481 479 __udf_add_aext(table, &epos, &eloc, elen, 1); 482 480 } 483 481 482 + error_return: 484 483 brelse(epos.bh); 485 484 brelse(oepos.bh); 486 485 487 - error_return: 488 486 mutex_unlock(&sbi->s_alloc_mutex); 489 487 return; 490 488 } ··· 500 498 struct extent_position epos; 501 499 int8_t etype = -1; 502 500 struct udf_inode_info *iinfo; 501 + int ret = 0; 503 502 504 503 if (first_block >= sbi->s_partmaps[partition].s_partition_len) 505 504 return 0; ··· 519 516 epos.bh = NULL; 520 517 eloc.logicalBlockNum = 0xFFFFFFFF; 521 518 522 - while (first_block != eloc.logicalBlockNum && 523 - (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) { 519 + while (first_block != eloc.logicalBlockNum) { 520 + ret = udf_next_aext(table, &epos, &eloc, &elen, &etype, 1); 521 + if (ret < 0) 522 + goto err_out; 523 + if (ret == 0) 524 + break; 524 525 udf_debug("eloc=%u, elen=%u, first_block=%u\n", 525 526 eloc.logicalBlockNum, elen, first_block); 526 - ; /* empty loop body */ 527 527 } 528 528 529 529 if (first_block == eloc.logicalBlockNum) { ··· 545 539 alloc_count = 0; 546 540 } 547 541 542 + err_out: 548 543 brelse(epos.bh); 549 544 550 545 if (alloc_count) ··· 567 560 struct extent_position epos, goal_epos; 568 561 int8_t etype; 569 562 struct udf_inode_info *iinfo = UDF_I(table); 563 + int ret = 0; 570 564 571 565 *err = -ENOSPC; 572 566 ··· 591 583 epos.block = iinfo->i_location; 592 584 epos.bh = goal_epos.bh = NULL; 593 585 594 - while (spread && 595 - (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) { 586 + while (spread) { 587 + ret = udf_next_aext(table, &epos, &eloc, &elen, &etype, 1); 588 + if (ret <= 0) 589 + break; 596 590 if (goal >= eloc.logicalBlockNum) { 597 591 if (goal < eloc.logicalBlockNum + 598 592 (elen >> sb->s_blocksize_bits)) ··· 622 612 623 613 brelse(epos.bh); 624 614 625 - if (spread == 0xFFFFFFFF) { 615 + if (ret < 0 || spread == 0xFFFFFFFF) { 626 616 brelse(goal_epos.bh); 627 617 mutex_unlock(&sbi->s_alloc_mutex); 618 + if (ret < 0) 619 + *err = ret; 628 620 return 0; 629 621 } 630 622
+8 -2
fs/udf/directory.c
··· 166 166 */ 167 167 static int udf_fiiter_advance_blk(struct udf_fileident_iter *iter) 168 168 { 169 + int8_t etype = -1; 170 + int err = 0; 171 + 169 172 iter->loffset++; 170 173 if (iter->loffset < DIV_ROUND_UP(iter->elen, 1<<iter->dir->i_blkbits)) 171 174 return 0; 172 175 173 176 iter->loffset = 0; 174 - if (udf_next_aext(iter->dir, &iter->epos, &iter->eloc, &iter->elen, 1) 175 - != (EXT_RECORDED_ALLOCATED >> 30)) { 177 + err = udf_next_aext(iter->dir, &iter->epos, &iter->eloc, 178 + &iter->elen, &etype, 1); 179 + if (err < 0) 180 + return err; 181 + else if (err == 0 || etype != (EXT_RECORDED_ALLOCATED >> 30)) { 176 182 if (iter->pos == iter->dir->i_size) { 177 183 iter->elen = 0; 178 184 return 0;
+83 -42
fs/udf/inode.c
··· 543 543 } else { 544 544 struct kernel_lb_addr tmploc; 545 545 uint32_t tmplen; 546 + int8_t tmptype; 546 547 547 548 udf_write_aext(inode, last_pos, &last_ext->extLocation, 548 549 last_ext->extLength, 1); ··· 553 552 * more extents, we may need to enter possible following 554 553 * empty indirect extent. 555 554 */ 556 - if (new_block_bytes) 557 - udf_next_aext(inode, last_pos, &tmploc, &tmplen, 0); 555 + if (new_block_bytes) { 556 + err = udf_next_aext(inode, last_pos, &tmploc, &tmplen, 557 + &tmptype, 0); 558 + if (err < 0) 559 + goto out_err; 560 + } 558 561 } 559 562 iinfo->i_lenExtents += add; 560 563 ··· 677 672 extent.extLength = EXT_NOT_RECORDED_NOT_ALLOCATED; 678 673 } else { 679 674 epos.offset -= adsize; 680 - etype = udf_next_aext(inode, &epos, &extent.extLocation, 681 - &extent.extLength, 0); 675 + err = udf_next_aext(inode, &epos, &extent.extLocation, 676 + &extent.extLength, &etype, 0); 677 + if (err <= 0) 678 + goto out; 682 679 extent.extLength |= etype << 30; 683 680 } 684 681 ··· 717 710 loff_t lbcount = 0, b_off = 0; 718 711 udf_pblk_t newblocknum; 719 712 sector_t offset = 0; 720 - int8_t etype; 713 + int8_t etype, tmpetype; 721 714 struct udf_inode_info *iinfo = UDF_I(inode); 722 715 udf_pblk_t goal = 0, pgoal = iinfo->i_location.logicalBlockNum; 723 716 int lastblock = 0; 724 - bool isBeyondEOF; 717 + bool isBeyondEOF = false; 725 718 int ret = 0; 726 719 727 720 prev_epos.offset = udf_file_entry_alloc_offset(inode); ··· 753 746 prev_epos.offset = cur_epos.offset; 754 747 cur_epos.offset = next_epos.offset; 755 748 756 - etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 1); 757 - if (etype == -1) 749 + ret = udf_next_aext(inode, &next_epos, &eloc, &elen, &etype, 1); 750 + if (ret < 0) { 751 + goto out_free; 752 + } else if (ret == 0) { 753 + isBeyondEOF = true; 758 754 break; 755 + } 759 756 760 757 c = !c; 761 758 ··· 780 769 * Move prev_epos and cur_epos into indirect extent if we are at 781 770 * the pointer to it 782 771 */ 783 - udf_next_aext(inode, &prev_epos, &tmpeloc, &tmpelen, 0); 784 - udf_next_aext(inode, &cur_epos, &tmpeloc, &tmpelen, 0); 772 + ret = udf_next_aext(inode, &prev_epos, &tmpeloc, &tmpelen, &tmpetype, 0); 773 + if (ret < 0) 774 + goto out_free; 775 + ret = udf_next_aext(inode, &cur_epos, &tmpeloc, &tmpelen, &tmpetype, 0); 776 + if (ret < 0) 777 + goto out_free; 785 778 786 779 /* if the extent is allocated and recorded, return the block 787 780 if the extent is not a multiple of the blocksize, round up */ 788 781 789 - if (etype == (EXT_RECORDED_ALLOCATED >> 30)) { 782 + if (!isBeyondEOF && etype == (EXT_RECORDED_ALLOCATED >> 30)) { 790 783 if (elen & (inode->i_sb->s_blocksize - 1)) { 791 784 elen = EXT_RECORDED_ALLOCATED | 792 785 ((elen + inode->i_sb->s_blocksize - 1) & ··· 806 791 } 807 792 808 793 /* Are we beyond EOF and preallocated extent? */ 809 - if (etype == -1) { 794 + if (isBeyondEOF) { 810 795 loff_t hole_len; 811 796 812 - isBeyondEOF = true; 813 797 if (count) { 814 798 if (c) 815 799 laarr[0] = laarr[1]; ··· 844 830 endnum = c + 1; 845 831 lastblock = 1; 846 832 } else { 847 - isBeyondEOF = false; 848 833 endnum = startnum = ((count > 2) ? 2 : count); 849 834 850 835 /* if the current extent is in position 0, ··· 857 844 858 845 /* if the current block is located in an extent, 859 846 read the next extent */ 860 - etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 0); 861 - if (etype != -1) { 847 + ret = udf_next_aext(inode, &next_epos, &eloc, &elen, &etype, 0); 848 + if (ret > 0) { 862 849 laarr[c + 1].extLength = (etype << 30) | elen; 863 850 laarr[c + 1].extLocation = eloc; 864 851 count++; 865 852 startnum++; 866 853 endnum++; 867 - } else 854 + } else if (ret == 0) 868 855 lastblock = 1; 856 + else 857 + goto out_free; 869 858 } 870 859 871 860 /* if the current extent is not recorded but allocated, get the ··· 1185 1170 int start = 0, i; 1186 1171 struct kernel_lb_addr tmploc; 1187 1172 uint32_t tmplen; 1173 + int8_t tmpetype; 1188 1174 int err; 1189 1175 1190 1176 if (startnum > endnum) { ··· 1203 1187 */ 1204 1188 if (err < 0) 1205 1189 return err; 1206 - udf_next_aext(inode, epos, &laarr[i].extLocation, 1207 - &laarr[i].extLength, 1); 1190 + err = udf_next_aext(inode, epos, &laarr[i].extLocation, 1191 + &laarr[i].extLength, &tmpetype, 1); 1192 + if (err < 0) 1193 + return err; 1208 1194 start++; 1209 1195 } 1210 1196 } 1211 1197 1212 1198 for (i = start; i < endnum; i++) { 1213 - udf_next_aext(inode, epos, &tmploc, &tmplen, 0); 1199 + err = udf_next_aext(inode, epos, &tmploc, &tmplen, &tmpetype, 0); 1200 + if (err < 0) 1201 + return err; 1202 + 1214 1203 udf_write_aext(inode, epos, &laarr[i].extLocation, 1215 1204 laarr[i].extLength, 1); 1216 1205 } ··· 2187 2166 */ 2188 2167 #define UDF_MAX_INDIR_EXTS 16 2189 2168 2190 - int8_t udf_next_aext(struct inode *inode, struct extent_position *epos, 2191 - struct kernel_lb_addr *eloc, uint32_t *elen, int inc) 2169 + /* 2170 + * Returns 1 on success, -errno on error, 0 on hit EOF. 2171 + */ 2172 + int udf_next_aext(struct inode *inode, struct extent_position *epos, 2173 + struct kernel_lb_addr *eloc, uint32_t *elen, int8_t *etype, 2174 + int inc) 2192 2175 { 2193 - int8_t etype; 2194 2176 unsigned int indirections = 0; 2195 2177 int ret = 0; 2178 + udf_pblk_t block; 2196 2179 2197 - while ((ret = udf_current_aext(inode, epos, eloc, elen, 2198 - &etype, inc)) > 0) { 2199 - if (etype != (EXT_NEXT_EXTENT_ALLOCDESCS >> 30)) 2200 - break; 2201 - udf_pblk_t block; 2180 + while (1) { 2181 + ret = udf_current_aext(inode, epos, eloc, elen, 2182 + etype, inc); 2183 + if (ret <= 0) 2184 + return ret; 2185 + if (*etype != (EXT_NEXT_EXTENT_ALLOCDESCS >> 30)) 2186 + return ret; 2202 2187 2203 2188 if (++indirections > UDF_MAX_INDIR_EXTS) { 2204 2189 udf_err(inode->i_sb, 2205 2190 "too many indirect extents in inode %lu\n", 2206 2191 inode->i_ino); 2207 - return -1; 2192 + return -EFSCORRUPTED; 2208 2193 } 2209 2194 2210 2195 epos->block = *eloc; ··· 2220 2193 epos->bh = sb_bread(inode->i_sb, block); 2221 2194 if (!epos->bh) { 2222 2195 udf_debug("reading block %u failed!\n", block); 2223 - return -1; 2196 + return -EIO; 2224 2197 } 2225 2198 } 2226 - 2227 - return ret > 0 ? etype : -1; 2228 2199 } 2229 2200 2230 2201 /* ··· 2288 2263 struct kernel_lb_addr oeloc; 2289 2264 uint32_t oelen; 2290 2265 int8_t etype; 2291 - int err; 2266 + int ret; 2292 2267 2293 2268 if (epos.bh) 2294 2269 get_bh(epos.bh); 2295 2270 2296 - while ((etype = udf_next_aext(inode, &epos, &oeloc, &oelen, 0)) != -1) { 2271 + while (1) { 2272 + ret = udf_next_aext(inode, &epos, &oeloc, &oelen, &etype, 0); 2273 + if (ret <= 0) 2274 + break; 2297 2275 udf_write_aext(inode, &epos, &neloc, nelen, 1); 2298 2276 neloc = oeloc; 2299 2277 nelen = (etype << 30) | oelen; 2300 2278 } 2301 - err = udf_add_aext(inode, &epos, &neloc, nelen, 1); 2279 + if (ret == 0) 2280 + ret = udf_add_aext(inode, &epos, &neloc, nelen, 1); 2302 2281 brelse(epos.bh); 2303 2282 2304 - return err; 2283 + return ret; 2305 2284 } 2306 2285 2307 2286 int8_t udf_delete_aext(struct inode *inode, struct extent_position epos) ··· 2317 2288 struct udf_inode_info *iinfo; 2318 2289 struct kernel_lb_addr eloc; 2319 2290 uint32_t elen; 2291 + int ret; 2320 2292 2321 2293 if (epos.bh) { 2322 2294 get_bh(epos.bh); ··· 2333 2303 adsize = 0; 2334 2304 2335 2305 oepos = epos; 2336 - if (udf_next_aext(inode, &epos, &eloc, &elen, 1) == -1) 2306 + if (udf_next_aext(inode, &epos, &eloc, &elen, &etype, 1) <= 0) 2337 2307 return -1; 2338 2308 2339 - while ((etype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) { 2309 + while (1) { 2310 + ret = udf_next_aext(inode, &epos, &eloc, &elen, &etype, 1); 2311 + if (ret < 0) { 2312 + brelse(epos.bh); 2313 + brelse(oepos.bh); 2314 + return -1; 2315 + } 2316 + if (ret == 0) 2317 + break; 2340 2318 udf_write_aext(inode, &oepos, &eloc, (etype << 30) | elen, 1); 2341 2319 if (oepos.bh != epos.bh) { 2342 2320 oepos.block = epos.block; ··· 2409 2371 loff_t lbcount = 0, bcount = (loff_t) block << blocksize_bits; 2410 2372 int8_t etype; 2411 2373 struct udf_inode_info *iinfo; 2374 + int err = 0; 2412 2375 2413 2376 iinfo = UDF_I(inode); 2414 2377 if (!udf_read_extent_cache(inode, bcount, &lbcount, pos)) { ··· 2419 2380 } 2420 2381 *elen = 0; 2421 2382 do { 2422 - etype = udf_next_aext(inode, pos, eloc, elen, 1); 2423 - if (etype == -1) { 2424 - *offset = (bcount - lbcount) >> blocksize_bits; 2425 - iinfo->i_lenExtents = lbcount; 2383 + err = udf_next_aext(inode, pos, eloc, elen, &etype, 1); 2384 + if (err <= 0) { 2385 + if (err == 0) { 2386 + *offset = (bcount - lbcount) >> blocksize_bits; 2387 + iinfo->i_lenExtents = lbcount; 2388 + } 2426 2389 return -1; 2427 2390 } 2428 2391 lbcount += *elen;
+2 -1
fs/udf/super.c
··· 2482 2482 uint32_t elen; 2483 2483 struct kernel_lb_addr eloc; 2484 2484 struct extent_position epos; 2485 + int8_t etype; 2485 2486 2486 2487 mutex_lock(&UDF_SB(sb)->s_alloc_mutex); 2487 2488 epos.block = UDF_I(table)->i_location; 2488 2489 epos.offset = sizeof(struct unallocSpaceEntry); 2489 2490 epos.bh = NULL; 2490 2491 2491 - while (udf_next_aext(table, &epos, &eloc, &elen, 1) != -1) 2492 + while (udf_next_aext(table, &epos, &eloc, &elen, &etype, 1) > 0) 2492 2493 accum += (elen >> table->i_sb->s_blocksize_bits); 2493 2494 2494 2495 brelse(epos.bh);
+22 -5
fs/udf/truncate.c
··· 69 69 int8_t etype = -1, netype; 70 70 int adsize; 71 71 struct udf_inode_info *iinfo = UDF_I(inode); 72 + int ret; 72 73 73 74 if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB || 74 75 inode->i_size == iinfo->i_lenExtents) ··· 86 85 BUG(); 87 86 88 87 /* Find the last extent in the file */ 89 - while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) { 88 + while (1) { 89 + ret = udf_next_aext(inode, &epos, &eloc, &elen, &netype, 1); 90 + if (ret <= 0) 91 + break; 90 92 etype = netype; 91 93 lbcount += elen; 92 94 if (lbcount > inode->i_size) { ··· 105 101 epos.offset -= adsize; 106 102 extent_trunc(inode, &epos, &eloc, etype, elen, nelen); 107 103 epos.offset += adsize; 108 - if (udf_next_aext(inode, &epos, &eloc, &elen, 1) != -1) 104 + if (udf_next_aext(inode, &epos, &eloc, &elen, 105 + &netype, 1) > 0) 109 106 udf_err(inode->i_sb, 110 107 "Extent after EOF in inode %u\n", 111 108 (unsigned)inode->i_ino); ··· 115 110 } 116 111 /* This inode entry is in-memory only and thus we don't have to mark 117 112 * the inode dirty */ 118 - iinfo->i_lenExtents = inode->i_size; 113 + if (ret == 0) 114 + iinfo->i_lenExtents = inode->i_size; 119 115 brelse(epos.bh); 120 116 } 121 117 ··· 130 124 int8_t etype = -1; 131 125 struct udf_inode_info *iinfo = UDF_I(inode); 132 126 int bsize = i_blocksize(inode); 127 + int8_t tmpetype = -1; 128 + int ret; 133 129 134 130 if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB || 135 131 ALIGN(inode->i_size, bsize) == ALIGN(iinfo->i_lenExtents, bsize)) ··· 140 132 epos.block = iinfo->i_location; 141 133 142 134 /* Find the last extent in the file */ 143 - while (udf_next_aext(inode, &epos, &eloc, &elen, 0) != -1) { 135 + while (1) { 136 + ret = udf_next_aext(inode, &epos, &eloc, &elen, &tmpetype, 0); 137 + if (ret < 0) 138 + goto out; 139 + if (ret == 0) 140 + break; 144 141 brelse(prev_epos.bh); 145 142 prev_epos = epos; 146 143 if (prev_epos.bh) 147 144 get_bh(prev_epos.bh); 148 145 149 - etype = udf_next_aext(inode, &epos, &eloc, &elen, 1); 146 + ret = udf_next_aext(inode, &epos, &eloc, &elen, &etype, 1); 147 + if (ret < 0) 148 + goto out; 150 149 lbcount += elen; 151 150 } 151 + 152 152 if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) { 153 153 lbcount -= elen; 154 154 udf_delete_aext(inode, prev_epos); ··· 166 150 /* This inode entry is in-memory only and thus we don't have to mark 167 151 * the inode dirty */ 168 152 iinfo->i_lenExtents = lbcount; 153 + out: 169 154 brelse(epos.bh); 170 155 brelse(prev_epos.bh); 171 156 }
+3 -2
fs/udf/udfdecl.h
··· 169 169 extern void udf_write_aext(struct inode *, struct extent_position *, 170 170 struct kernel_lb_addr *, uint32_t, int); 171 171 extern int8_t udf_delete_aext(struct inode *, struct extent_position); 172 - extern int8_t udf_next_aext(struct inode *, struct extent_position *, 173 - struct kernel_lb_addr *, uint32_t *, int); 172 + extern int udf_next_aext(struct inode *inode, struct extent_position *epos, 173 + struct kernel_lb_addr *eloc, uint32_t *elen, 174 + int8_t *etype, int inc); 174 175 extern int udf_current_aext(struct inode *inode, struct extent_position *epos, 175 176 struct kernel_lb_addr *eloc, uint32_t *elen, 176 177 int8_t *etype, int inc);