| From 19fd80de0a8b5170ef34704c8984cca920dffa59 Mon Sep 17 00:00:00 2001 |
| From: Jan Kara <jack@suse.cz> |
| Date: Mon, 19 Dec 2022 20:10:35 +0100 |
| Subject: udf: Handle error when adding extent to a file |
| |
| From: Jan Kara <jack@suse.cz> |
| |
| commit 19fd80de0a8b5170ef34704c8984cca920dffa59 upstream. |
| |
| When adding extent to a file fails, so far we've silently squelshed the |
| error. Make sure to propagate it up properly. |
| |
| Signed-off-by: Jan Kara <jack@suse.cz> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| fs/udf/inode.c | 41 +++++++++++++++++++++++++++-------------- |
| 1 file changed, 27 insertions(+), 14 deletions(-) |
| |
| --- a/fs/udf/inode.c |
| +++ b/fs/udf/inode.c |
| @@ -50,15 +50,15 @@ static int udf_update_inode(struct inode |
| static int udf_sync_inode(struct inode *inode); |
| static int udf_alloc_i_data(struct inode *inode, size_t size); |
| static sector_t inode_getblk(struct inode *, sector_t, int *, int *); |
| -static int8_t udf_insert_aext(struct inode *, struct extent_position, |
| - struct kernel_lb_addr, uint32_t); |
| +static int udf_insert_aext(struct inode *, struct extent_position, |
| + struct kernel_lb_addr, uint32_t); |
| static void udf_split_extents(struct inode *, int *, int, int, |
| struct kernel_long_ad *, int *); |
| static void udf_prealloc_extents(struct inode *, int, int, |
| struct kernel_long_ad *, int *); |
| static void udf_merge_extents(struct inode *, struct kernel_long_ad *, int *); |
| -static void udf_update_extents(struct inode *, struct kernel_long_ad *, int, |
| - int, struct extent_position *); |
| +static int udf_update_extents(struct inode *, struct kernel_long_ad *, int, |
| + int, struct extent_position *); |
| static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); |
| |
| static void __udf_clear_extent_cache(struct inode *inode) |
| @@ -883,7 +883,9 @@ static sector_t inode_getblk(struct inod |
| /* write back the new extents, inserting new extents if the new number |
| * of extents is greater than the old number, and deleting extents if |
| * the new number of extents is less than the old number */ |
| - udf_update_extents(inode, laarr, startnum, endnum, &prev_epos); |
| + *err = udf_update_extents(inode, laarr, startnum, endnum, &prev_epos); |
| + if (*err < 0) |
| + goto out_free; |
| |
| newblock = udf_get_pblock(inode->i_sb, newblocknum, |
| iinfo->i_location.partitionReferenceNum, 0); |
| @@ -1151,21 +1153,30 @@ static void udf_merge_extents(struct ino |
| } |
| } |
| |
| -static void udf_update_extents(struct inode *inode, struct kernel_long_ad *laarr, |
| - int startnum, int endnum, |
| - struct extent_position *epos) |
| +static int udf_update_extents(struct inode *inode, struct kernel_long_ad *laarr, |
| + int startnum, int endnum, |
| + struct extent_position *epos) |
| { |
| int start = 0, i; |
| struct kernel_lb_addr tmploc; |
| uint32_t tmplen; |
| + int err; |
| |
| if (startnum > endnum) { |
| for (i = 0; i < (startnum - endnum); i++) |
| udf_delete_aext(inode, *epos); |
| } else if (startnum < endnum) { |
| for (i = 0; i < (endnum - startnum); i++) { |
| - udf_insert_aext(inode, *epos, laarr[i].extLocation, |
| - laarr[i].extLength); |
| + err = udf_insert_aext(inode, *epos, |
| + laarr[i].extLocation, |
| + laarr[i].extLength); |
| + /* |
| + * If we fail here, we are likely corrupting the extent |
| + * list and leaking blocks. At least stop early to |
| + * limit the damage. |
| + */ |
| + if (err < 0) |
| + return err; |
| udf_next_aext(inode, epos, &laarr[i].extLocation, |
| &laarr[i].extLength, 1); |
| start++; |
| @@ -1177,6 +1188,7 @@ static void udf_update_extents(struct in |
| udf_write_aext(inode, epos, &laarr[i].extLocation, |
| laarr[i].extLength, 1); |
| } |
| + return 0; |
| } |
| |
| struct buffer_head *udf_bread(struct inode *inode, int block, |
| @@ -2172,12 +2184,13 @@ int8_t udf_current_aext(struct inode *in |
| return etype; |
| } |
| |
| -static int8_t udf_insert_aext(struct inode *inode, struct extent_position epos, |
| - struct kernel_lb_addr neloc, uint32_t nelen) |
| +static int udf_insert_aext(struct inode *inode, struct extent_position epos, |
| + struct kernel_lb_addr neloc, uint32_t nelen) |
| { |
| struct kernel_lb_addr oeloc; |
| uint32_t oelen; |
| int8_t etype; |
| + int err; |
| |
| if (epos.bh) |
| get_bh(epos.bh); |
| @@ -2187,10 +2200,10 @@ static int8_t udf_insert_aext(struct ino |
| neloc = oeloc; |
| nelen = (etype << 30) | oelen; |
| } |
| - udf_add_aext(inode, &epos, &neloc, nelen, 1); |
| + err = udf_add_aext(inode, &epos, &neloc, nelen, 1); |
| brelse(epos.bh); |
| |
| - return (nelen >> 30); |
| + return err; |
| } |
| |
| int8_t udf_delete_aext(struct inode *inode, struct extent_position epos) |