udf: Handle error when adding extent to a file
authorJan Kara <jack@suse.cz>
Mon, 19 Dec 2022 19:10:35 +0000 (20:10 +0100)
committerJan Kara <jack@suse.cz>
Mon, 9 Jan 2023 09:39:53 +0000 (10:39 +0100)
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>
fs/udf/inode.c

index 5498365669eb639be6a44e149f40a51d6f70b7ae..6d99d130028922d14be5390185f91f6dd52f3f50 100644 (file)
@@ -57,15 +57,15 @@ static int udf_update_inode(struct inode *, int);
 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, udf_pblk_t,
                              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)
@@ -793,7 +793,9 @@ static sector_t inode_getblk(struct inode *inode, sector_t block,
        /* 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);
@@ -1061,21 +1063,30 @@ static void udf_merge_extents(struct inode *inode, struct kernel_long_ad *laarr,
        }
 }
 
-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++;
@@ -1087,6 +1098,7 @@ static void udf_update_extents(struct inode *inode, struct kernel_long_ad *laarr
                udf_write_aext(inode, epos, &laarr[i].extLocation,
                               laarr[i].extLength, 1);
        }
+       return 0;
 }
 
 struct buffer_head *udf_bread(struct inode *inode, udf_pblk_t block,
@@ -2105,12 +2117,13 @@ int8_t udf_current_aext(struct inode *inode, struct extent_position *epos,
        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);
@@ -2120,10 +2133,10 @@ static int8_t udf_insert_aext(struct inode *inode, struct extent_position epos,
                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)