]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 23 Sep 2023 08:46:54 +0000 (10:46 +0200)
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

index c47b9c3a97ef6b4a234dbddae29fc79886760f33..a9fef5bb9d256310f39a4825920211a2212c66b7 100644 (file)
@@ -50,15 +50,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, 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 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);
@@ -1151,21 +1153,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++;
@@ -1177,6 +1188,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, int block,
@@ -2172,12 +2184,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);
@@ -2187,10 +2200,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)