udf: Convert udf_expand_dir_adinicb() to new directory iteration
authorJan Kara <jack@suse.cz>
Wed, 5 Oct 2022 15:59:12 +0000 (17:59 +0200)
committerJan Kara <jack@suse.cz>
Mon, 9 Jan 2023 09:39:51 +0000 (10:39 +0100)
Convert udf_expand_dir_adinicb() to new directory iteration code.

Signed-off-by: Jan Kara <jack@suse.cz>
fs/udf/inode.c

index 34e4163..4b27137 100644 (file)
@@ -326,14 +326,12 @@ struct buffer_head *udf_expand_dir_adinicb(struct inode *inode,
        udf_pblk_t newblock;
        struct buffer_head *dbh = NULL;
        struct kernel_lb_addr eloc;
-       uint8_t alloctype;
        struct extent_position epos;
-
-       struct udf_fileident_bh sfibh, dfibh;
-       loff_t f_pos = udf_ext0_offset(inode);
-       int size = udf_ext0_offset(inode) + inode->i_size;
-       struct fileIdentDesc cfi, *sfi, *dfi;
+       uint8_t alloctype;
        struct udf_inode_info *iinfo = UDF_I(inode);
+       struct udf_fileident_iter iter;
+       uint8_t *impuse;
+       int ret;
 
        if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
                alloctype = ICBTAG_FLAG_AD_SHORT;
@@ -361,38 +359,14 @@ struct buffer_head *udf_expand_dir_adinicb(struct inode *inode,
        if (!dbh)
                return NULL;
        lock_buffer(dbh);
-       memset(dbh->b_data, 0x00, inode->i_sb->s_blocksize);
+       memcpy(dbh->b_data, iinfo->i_data, inode->i_size);
+       memset(dbh->b_data + inode->i_size, 0,
+              inode->i_sb->s_blocksize - inode->i_size);
        set_buffer_uptodate(dbh);
        unlock_buffer(dbh);
-       mark_buffer_dirty_inode(dbh, inode);
-
-       sfibh.soffset = sfibh.eoffset =
-                       f_pos & (inode->i_sb->s_blocksize - 1);
-       sfibh.sbh = sfibh.ebh = NULL;
-       dfibh.soffset = dfibh.eoffset = 0;
-       dfibh.sbh = dfibh.ebh = dbh;
-       while (f_pos < size) {
-               iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB;
-               sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL,
-                                        NULL, NULL, NULL);
-               if (!sfi) {
-                       brelse(dbh);
-                       return NULL;
-               }
-               iinfo->i_alloc_type = alloctype;
-               sfi->descTag.tagLocation = cpu_to_le32(*block);
-               dfibh.soffset = dfibh.eoffset;
-               dfibh.eoffset += (sfibh.eoffset - sfibh.soffset);
-               dfi = (struct fileIdentDesc *)(dbh->b_data + dfibh.soffset);
-               if (udf_write_fi(inode, sfi, dfi, &dfibh, sfi->impUse,
-                                udf_get_fi_ident(sfi))) {
-                       iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB;
-                       brelse(dbh);
-                       return NULL;
-               }
-       }
-       mark_buffer_dirty_inode(dbh, inode);
 
+       /* Drop inline data, add block instead */
+       iinfo->i_alloc_type = alloctype;
        memset(iinfo->i_data + iinfo->i_lenEAttr, 0, iinfo->i_lenAlloc);
        iinfo->i_lenAlloc = 0;
        eloc.logicalBlockNum = *block;
@@ -403,10 +377,28 @@ struct buffer_head *udf_expand_dir_adinicb(struct inode *inode,
        epos.block = iinfo->i_location;
        epos.offset = udf_file_entry_alloc_offset(inode);
        udf_add_aext(inode, &epos, &eloc, inode->i_size, 0);
-       /* UniqueID stuff */
-
        brelse(epos.bh);
        mark_inode_dirty(inode);
+
+       /* Now fixup tags in moved directory entries */
+       for (ret = udf_fiiter_init(&iter, inode, 0);
+            !ret && iter.pos < inode->i_size;
+            ret = udf_fiiter_advance(&iter)) {
+               iter.fi.descTag.tagLocation = cpu_to_le32(*block);
+               if (iter.fi.lengthOfImpUse != cpu_to_le16(0))
+                       impuse = dbh->b_data + iter.pos +
+                                               sizeof(struct fileIdentDesc);
+               else
+                       impuse = NULL;
+               udf_fiiter_write_fi(&iter, impuse);
+       }
+       /*
+        * We don't expect the iteration to fail as the directory has been
+        * already verified to be correct
+        */
+       WARN_ON_ONCE(ret);
+       udf_fiiter_release(&iter);
+
        return dbh;
 }