summaryrefslogtreecommitdiff
path: root/fs/udf
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2022-10-05 17:59:12 +0200
committerJan Kara <jack@suse.cz>2023-01-09 10:39:51 +0100
commit57bda9fb169d689bff4108265a897d324b5fb8c3 (patch)
tree7719e27f43e64d803b289b35d46fd7671f284a74 /fs/udf
parent7cd7a36ab44d3e8c1dee7185ef407b9831a8220b (diff)
downloadlinux-57bda9fb169d689bff4108265a897d324b5fb8c3.tar.gz
udf: Convert udf_expand_dir_adinicb() to new directory iteration
Convert udf_expand_dir_adinicb() to new directory iteration code. Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/udf')
-rw-r--r--fs/udf/inode.c66
1 files changed, 29 insertions, 37 deletions
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 34e416327dd4..4b2713799589 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -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;
}