ksmbd-fix-user-after-free-from-session-log-off.patch
alsa-hda-conexant-fix-audio-routing-for-hp-eliteone-1000-g2.patch
mptcp-pm-fix-uaf-read-in-mptcp_pm_nl_rm_addr_or_subflow.patch
+udf-new-directory-iteration-code.patch
+udf-convert-udf_expand_dir_adinicb-to-new-directory-iteration.patch
+udf-move-udf_expand_dir_adinicb-to-its-callsite.patch
+udf-implement-searching-for-directory-entry-using-new-iteration-code.patch
+udf-provide-function-to-mark-entry-as-deleted-using-new-directory-iteration-code.patch
+udf-convert-udf_rename-to-new-directory-iteration-code.patch
+udf-convert-udf_readdir-to-new-directory-iteration.patch
+udf-convert-udf_lookup-to-use-new-directory-iteration-code.patch
+udf-convert-udf_get_parent-to-new-directory-iteration-code.patch
+udf-convert-empty_dir-to-new-directory-iteration-code.patch
+udf-convert-udf_rmdir-to-new-directory-iteration-code.patch
+udf-convert-udf_unlink-to-new-directory-iteration-code.patch
+udf-implement-adding-of-dir-entries-using-new-iteration-code.patch
+udf-convert-udf_add_nondir-to-new-directory-iteration.patch
+udf-convert-udf_mkdir-to-new-directory-iteration-code.patch
+udf-convert-udf_link-to-new-directory-iteration-code.patch
+udf-remove-old-directory-iteration-code.patch
+udf-handle-error-when-expanding-directory.patch
+udf-don-t-return-bh-from-udf_expand_dir_adinicb.patch
--- /dev/null
+From stable+bounces-86660-greg=kroah.com@vger.kernel.org Thu Oct 17 19:20:02 2024
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Date: Thu, 17 Oct 2024 14:19:06 -0300
+Subject: udf: Convert empty_dir() to new directory iteration code
+To: stable@vger.kernel.org
+Cc: Jan Kara <jack@suse.cz>, kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Message-ID: <20241017171915.311132-11-cascardo@igalia.com>
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit afb525f466f9fdc140b975221cb43fbb5c59314e ]
+
+Convert empty_dir() to new directory iteration code.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/namei.c | 68 +++++++--------------------------------------------------
+ 1 file changed, 9 insertions(+), 59 deletions(-)
+
+--- a/fs/udf/namei.c
++++ b/fs/udf/namei.c
+@@ -879,69 +879,19 @@ out:
+
+ static int empty_dir(struct inode *dir)
+ {
+- struct fileIdentDesc *fi, cfi;
+- struct udf_fileident_bh fibh;
+- loff_t f_pos;
+- loff_t size = udf_ext0_offset(dir) + dir->i_size;
+- udf_pblk_t block;
+- struct kernel_lb_addr eloc;
+- uint32_t elen;
+- sector_t offset;
+- struct extent_position epos = {};
+- struct udf_inode_info *dinfo = UDF_I(dir);
++ struct udf_fileident_iter iter;
++ int ret;
+
+- f_pos = udf_ext0_offset(dir);
+- fibh.soffset = fibh.eoffset = f_pos & (dir->i_sb->s_blocksize - 1);
+-
+- if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
+- fibh.sbh = fibh.ebh = NULL;
+- else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits,
+- &epos, &eloc, &elen, &offset) ==
+- (EXT_RECORDED_ALLOCATED >> 30)) {
+- block = udf_get_lb_pblock(dir->i_sb, &eloc, offset);
+- if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
+- if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+- epos.offset -= sizeof(struct short_ad);
+- else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+- epos.offset -= sizeof(struct long_ad);
+- } else
+- offset = 0;
+-
+- fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block);
+- if (!fibh.sbh) {
+- brelse(epos.bh);
+- return 0;
+- }
+- } else {
+- brelse(epos.bh);
+- return 0;
+- }
+-
+- while (f_pos < size) {
+- fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &epos, &eloc,
+- &elen, &offset);
+- if (!fi) {
+- if (fibh.sbh != fibh.ebh)
+- brelse(fibh.ebh);
+- brelse(fibh.sbh);
+- brelse(epos.bh);
+- return 0;
+- }
+-
+- if (cfi.lengthFileIdent &&
+- (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) == 0) {
+- if (fibh.sbh != fibh.ebh)
+- brelse(fibh.ebh);
+- brelse(fibh.sbh);
+- brelse(epos.bh);
++ for (ret = udf_fiiter_init(&iter, dir, 0);
++ !ret && iter.pos < dir->i_size;
++ ret = udf_fiiter_advance(&iter)) {
++ if (iter.fi.lengthFileIdent &&
++ !(iter.fi.fileCharacteristics & FID_FILE_CHAR_DELETED)) {
++ udf_fiiter_release(&iter);
+ return 0;
+ }
+ }
+-
+- if (fibh.sbh != fibh.ebh)
+- brelse(fibh.ebh);
+- brelse(fibh.sbh);
+- brelse(epos.bh);
++ udf_fiiter_release(&iter);
+
+ return 1;
+ }
--- /dev/null
+From stable+bounces-86665-greg=kroah.com@vger.kernel.org Thu Oct 17 19:28:29 2024
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Date: Thu, 17 Oct 2024 14:19:10 -0300
+Subject: udf: Convert udf_add_nondir() to new directory iteration
+To: stable@vger.kernel.org
+Cc: Jan Kara <jack@suse.cz>, kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Message-ID: <20241017171915.311132-15-cascardo@igalia.com>
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit ef91f9998bece00cf7f82ad26177f910a7124b25 ]
+
+Convert udf_add_nondir() to new directory iteration code.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/namei.c | 19 ++++++++-----------
+ 1 file changed, 8 insertions(+), 11 deletions(-)
+
+--- a/fs/udf/namei.c
++++ b/fs/udf/namei.c
+@@ -847,26 +847,23 @@ static int udf_add_nondir(struct dentry
+ {
+ struct udf_inode_info *iinfo = UDF_I(inode);
+ struct inode *dir = d_inode(dentry->d_parent);
+- struct udf_fileident_bh fibh;
+- struct fileIdentDesc cfi, *fi;
++ struct udf_fileident_iter iter;
+ int err;
+
+- fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
+- if (unlikely(!fi)) {
++ err = udf_fiiter_add_entry(dir, dentry, &iter);
++ if (err) {
+ inode_dec_link_count(inode);
+ discard_new_inode(inode);
+ return err;
+ }
+- cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
+- cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
+- *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
++ iter.fi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
++ iter.fi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
++ *(__le32 *)((struct allocDescImpUse *)iter.fi.icb.impUse)->impUse =
+ cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL);
+- udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
++ udf_fiiter_write_fi(&iter, NULL);
+ dir->i_ctime = dir->i_mtime = current_time(dir);
+ mark_inode_dirty(dir);
+- if (fibh.sbh != fibh.ebh)
+- brelse(fibh.ebh);
+- brelse(fibh.sbh);
++ udf_fiiter_release(&iter);
+ d_instantiate_new(dentry, inode);
+
+ return 0;
--- /dev/null
+From stable+bounces-86652-greg=kroah.com@vger.kernel.org Thu Oct 17 19:19:48 2024
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Date: Thu, 17 Oct 2024 14:18:58 -0300
+Subject: udf: Convert udf_expand_dir_adinicb() to new directory iteration
+To: stable@vger.kernel.org
+Cc: Jan Kara <jack@suse.cz>, kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Message-ID: <20241017171915.311132-3-cascardo@igalia.com>
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit 57bda9fb169d689bff4108265a897d324b5fb8c3 ]
+
+Convert udf_expand_dir_adinicb() to new directory iteration code.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/inode.c | 66 +++++++++++++++++++++++++--------------------------------
+ 1 file changed, 29 insertions(+), 37 deletions(-)
+
+--- a/fs/udf/inode.c
++++ b/fs/udf/inode.c
+@@ -331,14 +331,12 @@ struct buffer_head *udf_expand_dir_adini
+ 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;
+@@ -366,38 +364,14 @@ struct buffer_head *udf_expand_dir_adini
+ 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;
+@@ -408,10 +382,28 @@ struct buffer_head *udf_expand_dir_adini
+ 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;
+ }
+
--- /dev/null
+From stable+bounces-86659-greg=kroah.com@vger.kernel.org Thu Oct 17 19:19:57 2024
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Date: Thu, 17 Oct 2024 14:19:05 -0300
+Subject: udf: Convert udf_get_parent() to new directory iteration code
+To: stable@vger.kernel.org
+Cc: Jan Kara <jack@suse.cz>, kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Message-ID: <20241017171915.311132-10-cascardo@igalia.com>
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit 9b06fbef4202363d74bba5459ddd231db6d3b1af ]
+
+Convert udf_get_parent() to use udf_fiiter_find_entry().
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/namei.c | 16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+--- a/fs/udf/namei.c
++++ b/fs/udf/namei.c
+@@ -1366,17 +1366,15 @@ static struct dentry *udf_get_parent(str
+ {
+ struct kernel_lb_addr tloc;
+ struct inode *inode = NULL;
+- struct fileIdentDesc cfi;
+- struct udf_fileident_bh fibh;
++ struct udf_fileident_iter iter;
++ int err;
+
+- if (!udf_find_entry(d_inode(child), &dotdot_name, &fibh, &cfi))
+- return ERR_PTR(-EACCES);
++ err = udf_fiiter_find_entry(d_inode(child), &dotdot_name, &iter);
++ if (err)
++ return ERR_PTR(err);
+
+- if (fibh.sbh != fibh.ebh)
+- brelse(fibh.ebh);
+- brelse(fibh.sbh);
+-
+- tloc = lelb_to_cpu(cfi.icb.extLocation);
++ tloc = lelb_to_cpu(iter.fi.icb.extLocation);
++ udf_fiiter_release(&iter);
+ inode = udf_iget(child->d_sb, &tloc);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);
--- /dev/null
+From stable+bounces-86667-greg=kroah.com@vger.kernel.org Thu Oct 17 19:20:13 2024
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Date: Thu, 17 Oct 2024 14:19:12 -0300
+Subject: udf: Convert udf_link() to new directory iteration code
+To: stable@vger.kernel.org
+Cc: Jan Kara <jack@suse.cz>, kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Message-ID: <20241017171915.311132-17-cascardo@igalia.com>
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit dbfb102d16fb780c84f41adbaeb7eac907c415dc ]
+
+Convert udf_link() to use new directory iteration code for adding entry
+into the directory.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/namei.c | 22 ++++++++--------------
+ 1 file changed, 8 insertions(+), 14 deletions(-)
+
+--- a/fs/udf/namei.c
++++ b/fs/udf/namei.c
+@@ -1222,27 +1222,21 @@ static int udf_link(struct dentry *old_d
+ struct dentry *dentry)
+ {
+ struct inode *inode = d_inode(old_dentry);
+- struct udf_fileident_bh fibh;
+- struct fileIdentDesc cfi, *fi;
++ struct udf_fileident_iter iter;
+ int err;
+
+- fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
+- if (!fi) {
++ err = udf_fiiter_add_entry(dir, dentry, &iter);
++ if (err)
+ return err;
+- }
+- cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
+- cfi.icb.extLocation = cpu_to_lelb(UDF_I(inode)->i_location);
++ iter.fi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
++ iter.fi.icb.extLocation = cpu_to_lelb(UDF_I(inode)->i_location);
+ if (UDF_SB(inode->i_sb)->s_lvid_bh) {
+- *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
++ *(__le32 *)((struct allocDescImpUse *)iter.fi.icb.impUse)->impUse =
+ cpu_to_le32(lvid_get_unique_id(inode->i_sb));
+ }
+- udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
+- if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
+- mark_inode_dirty(dir);
++ udf_fiiter_write_fi(&iter, NULL);
++ udf_fiiter_release(&iter);
+
+- if (fibh.sbh != fibh.ebh)
+- brelse(fibh.ebh);
+- brelse(fibh.sbh);
+ inc_nlink(inode);
+ inode->i_ctime = current_time(inode);
+ mark_inode_dirty(inode);
--- /dev/null
+From stable+bounces-86658-greg=kroah.com@vger.kernel.org Thu Oct 17 19:19:55 2024
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Date: Thu, 17 Oct 2024 14:19:04 -0300
+Subject: udf: Convert udf_lookup() to use new directory iteration code
+To: stable@vger.kernel.org
+Cc: Jan Kara <jack@suse.cz>, kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Message-ID: <20241017171915.311132-9-cascardo@igalia.com>
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit 200918b34d158cdaee531db7e0c80b92c57e66f1 ]
+
+Convert udf_lookup() to use udf_fiiter_find_entry() for looking up
+directory entries.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/namei.c | 19 ++++++++-----------
+ 1 file changed, 8 insertions(+), 11 deletions(-)
+
+--- a/fs/udf/namei.c
++++ b/fs/udf/namei.c
+@@ -366,25 +366,22 @@ static struct dentry *udf_lookup(struct
+ unsigned int flags)
+ {
+ struct inode *inode = NULL;
+- struct fileIdentDesc cfi;
+- struct udf_fileident_bh fibh;
+- struct fileIdentDesc *fi;
++ struct udf_fileident_iter iter;
++ int err;
+
+ if (dentry->d_name.len > UDF_NAME_LEN)
+ return ERR_PTR(-ENAMETOOLONG);
+
+- fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
+- if (IS_ERR(fi))
+- return ERR_CAST(fi);
++ err = udf_fiiter_find_entry(dir, &dentry->d_name, &iter);
++ if (err < 0 && err != -ENOENT)
++ return ERR_PTR(err);
+
+- if (fi) {
++ if (err == 0) {
+ struct kernel_lb_addr loc;
+
+- if (fibh.sbh != fibh.ebh)
+- brelse(fibh.ebh);
+- brelse(fibh.sbh);
++ loc = lelb_to_cpu(iter.fi.icb.extLocation);
++ udf_fiiter_release(&iter);
+
+- loc = lelb_to_cpu(cfi.icb.extLocation);
+ inode = udf_iget(dir->i_sb, &loc);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);
--- /dev/null
+From stable+bounces-86666-greg=kroah.com@vger.kernel.org Thu Oct 17 19:20:11 2024
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Date: Thu, 17 Oct 2024 14:19:11 -0300
+Subject: udf: Convert udf_mkdir() to new directory iteration code
+To: stable@vger.kernel.org
+Cc: Jan Kara <jack@suse.cz>, kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Message-ID: <20241017171915.311132-16-cascardo@igalia.com>
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit 00bce6f792caccefa73daeaf9bde82d24d50037f ]
+
+Convert udf_mkdir() to new directory iteration code.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/namei.c | 48 +++++++++++++++++++++---------------------------
+ 1 file changed, 21 insertions(+), 27 deletions(-)
+
+--- a/fs/udf/namei.c
++++ b/fs/udf/namei.c
+@@ -928,8 +928,7 @@ static int udf_mkdir(struct user_namespa
+ struct dentry *dentry, umode_t mode)
+ {
+ struct inode *inode;
+- struct udf_fileident_bh fibh;
+- struct fileIdentDesc cfi, *fi;
++ struct udf_fileident_iter iter;
+ int err;
+ struct udf_inode_info *dinfo = UDF_I(dir);
+ struct udf_inode_info *iinfo;
+@@ -941,47 +940,42 @@ static int udf_mkdir(struct user_namespa
+ iinfo = UDF_I(inode);
+ inode->i_op = &udf_dir_inode_operations;
+ inode->i_fop = &udf_dir_operations;
+- fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err);
+- if (!fi) {
+- inode_dec_link_count(inode);
++ err = udf_fiiter_add_entry(inode, NULL, &iter);
++ if (err) {
++ clear_nlink(inode);
+ discard_new_inode(inode);
+- goto out;
++ return err;
+ }
+ set_nlink(inode, 2);
+- cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
+- cfi.icb.extLocation = cpu_to_lelb(dinfo->i_location);
+- *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
++ iter.fi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
++ iter.fi.icb.extLocation = cpu_to_lelb(dinfo->i_location);
++ *(__le32 *)((struct allocDescImpUse *)iter.fi.icb.impUse)->impUse =
+ cpu_to_le32(dinfo->i_unique & 0x00000000FFFFFFFFUL);
+- cfi.fileCharacteristics =
++ iter.fi.fileCharacteristics =
+ FID_FILE_CHAR_DIRECTORY | FID_FILE_CHAR_PARENT;
+- udf_write_fi(inode, &cfi, fi, &fibh, NULL, NULL);
+- brelse(fibh.sbh);
++ udf_fiiter_write_fi(&iter, NULL);
++ udf_fiiter_release(&iter);
+ mark_inode_dirty(inode);
+
+- fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
+- if (!fi) {
++ err = udf_fiiter_add_entry(dir, dentry, &iter);
++ if (err) {
+ clear_nlink(inode);
+- mark_inode_dirty(inode);
+ discard_new_inode(inode);
+- goto out;
++ return err;
+ }
+- cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
+- cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
+- *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
++ iter.fi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
++ iter.fi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
++ *(__le32 *)((struct allocDescImpUse *)iter.fi.icb.impUse)->impUse =
+ cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL);
+- cfi.fileCharacteristics |= FID_FILE_CHAR_DIRECTORY;
+- udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
++ iter.fi.fileCharacteristics |= FID_FILE_CHAR_DIRECTORY;
++ udf_fiiter_write_fi(&iter, NULL);
++ udf_fiiter_release(&iter);
+ inc_nlink(dir);
+ dir->i_ctime = dir->i_mtime = current_time(dir);
+ mark_inode_dirty(dir);
+ d_instantiate_new(dentry, inode);
+- if (fibh.sbh != fibh.ebh)
+- brelse(fibh.ebh);
+- brelse(fibh.sbh);
+- err = 0;
+
+-out:
+- return err;
++ return 0;
+ }
+
+ static int empty_dir(struct inode *dir)
--- /dev/null
+From stable+bounces-86657-greg=kroah.com@vger.kernel.org Thu Oct 17 19:19:55 2024
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Date: Thu, 17 Oct 2024 14:19:03 -0300
+Subject: udf: Convert udf_readdir() to new directory iteration
+To: stable@vger.kernel.org
+Cc: Jan Kara <jack@suse.cz>, kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Message-ID: <20241017171915.311132-8-cascardo@igalia.com>
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit 7cd7a36ab44d3e8c1dee7185ef407b9831a8220b ]
+
+Convert udf_readdir() to new directory iteration functions.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/dir.c | 148 ++++++++++-------------------------------------------------
+ 1 file changed, 27 insertions(+), 121 deletions(-)
+
+--- a/fs/udf/dir.c
++++ b/fs/udf/dir.c
+@@ -39,26 +39,13 @@
+ static int udf_readdir(struct file *file, struct dir_context *ctx)
+ {
+ struct inode *dir = file_inode(file);
+- struct udf_inode_info *iinfo = UDF_I(dir);
+- struct udf_fileident_bh fibh = { .sbh = NULL, .ebh = NULL};
+- struct fileIdentDesc *fi = NULL;
+- struct fileIdentDesc cfi;
+- udf_pblk_t block, iblock;
+ loff_t nf_pos, emit_pos = 0;
+ int flen;
+- unsigned char *fname = NULL, *copy_name = NULL;
+- unsigned char *nameptr;
+- uint16_t liu;
+- uint8_t lfi;
+- loff_t size = udf_ext0_offset(dir) + dir->i_size;
+- struct buffer_head *tmp, *bha[16];
+- struct kernel_lb_addr eloc;
+- uint32_t elen;
+- sector_t offset;
+- int i, num, ret = 0;
+- struct extent_position epos = { NULL, 0, {0, 0} };
++ unsigned char *fname = NULL;
++ int ret = 0;
+ struct super_block *sb = dir->i_sb;
+ bool pos_valid = false;
++ struct udf_fileident_iter iter;
+
+ if (ctx->pos == 0) {
+ if (!dir_emit_dot(file, ctx))
+@@ -66,7 +53,7 @@ static int udf_readdir(struct file *file
+ ctx->pos = 1;
+ }
+ nf_pos = (ctx->pos - 1) << 2;
+- if (nf_pos >= size)
++ if (nf_pos >= dir->i_size)
+ goto out;
+
+ /*
+@@ -90,138 +77,57 @@ static int udf_readdir(struct file *file
+ goto out;
+ }
+
+- if (nf_pos == 0)
+- nf_pos = udf_ext0_offset(dir);
+-
+- fibh.soffset = fibh.eoffset = nf_pos & (sb->s_blocksize - 1);
+- if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+- if (inode_bmap(dir, nf_pos >> sb->s_blocksize_bits,
+- &epos, &eloc, &elen, &offset)
+- != (EXT_RECORDED_ALLOCATED >> 30)) {
+- ret = -ENOENT;
+- goto out;
+- }
+- block = udf_get_lb_pblock(sb, &eloc, offset);
+- if ((++offset << sb->s_blocksize_bits) < elen) {
+- if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+- epos.offset -= sizeof(struct short_ad);
+- else if (iinfo->i_alloc_type ==
+- ICBTAG_FLAG_AD_LONG)
+- epos.offset -= sizeof(struct long_ad);
+- } else {
+- offset = 0;
+- }
+-
+- if (!(fibh.sbh = fibh.ebh = udf_tread(sb, block))) {
+- ret = -EIO;
+- goto out;
+- }
+-
+- if (!(offset & ((16 >> (sb->s_blocksize_bits - 9)) - 1))) {
+- i = 16 >> (sb->s_blocksize_bits - 9);
+- if (i + offset > (elen >> sb->s_blocksize_bits))
+- i = (elen >> sb->s_blocksize_bits) - offset;
+- for (num = 0; i > 0; i--) {
+- block = udf_get_lb_pblock(sb, &eloc, offset + i);
+- tmp = udf_tgetblk(sb, block);
+- if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
+- bha[num++] = tmp;
+- else
+- brelse(tmp);
+- }
+- if (num) {
+- bh_readahead_batch(num, bha, REQ_RAHEAD);
+- for (i = 0; i < num; i++)
+- brelse(bha[i]);
+- }
+- }
+- }
+-
+- while (nf_pos < size) {
++ for (ret = udf_fiiter_init(&iter, dir, nf_pos);
++ !ret && iter.pos < dir->i_size;
++ ret = udf_fiiter_advance(&iter)) {
+ struct kernel_lb_addr tloc;
+- loff_t cur_pos = nf_pos;
+-
+- /* Update file position only if we got past the current one */
+- if (nf_pos >= emit_pos) {
+- ctx->pos = (nf_pos >> 2) + 1;
+- pos_valid = true;
+- }
++ udf_pblk_t iblock;
+
+- fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc,
+- &elen, &offset);
+- if (!fi)
+- goto out;
+ /* Still not at offset where user asked us to read from? */
+- if (cur_pos < emit_pos)
++ if (iter.pos < emit_pos)
+ continue;
+
+- liu = le16_to_cpu(cfi.lengthOfImpUse);
+- lfi = cfi.lengthFileIdent;
+-
+- if (fibh.sbh == fibh.ebh) {
+- nameptr = udf_get_fi_ident(fi);
+- } else {
+- int poffset; /* Unpaded ending offset */
+-
+- poffset = fibh.soffset + sizeof(struct fileIdentDesc) + liu + lfi;
+-
+- if (poffset >= lfi) {
+- nameptr = (char *)(fibh.ebh->b_data + poffset - lfi);
+- } else {
+- if (!copy_name) {
+- copy_name = kmalloc(UDF_NAME_LEN,
+- GFP_NOFS);
+- if (!copy_name) {
+- ret = -ENOMEM;
+- goto out;
+- }
+- }
+- nameptr = copy_name;
+- memcpy(nameptr, udf_get_fi_ident(fi),
+- lfi - poffset);
+- memcpy(nameptr + lfi - poffset,
+- fibh.ebh->b_data, poffset);
+- }
+- }
++ /* Update file position only if we got past the current one */
++ pos_valid = true;
++ ctx->pos = (iter.pos >> 2) + 1;
+
+- if ((cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
++ if (iter.fi.fileCharacteristics & FID_FILE_CHAR_DELETED) {
+ if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE))
+ continue;
+ }
+
+- if ((cfi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) {
++ if (iter.fi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) {
+ if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE))
+ continue;
+ }
+
+- if (cfi.fileCharacteristics & FID_FILE_CHAR_PARENT) {
++ if (iter.fi.fileCharacteristics & FID_FILE_CHAR_PARENT) {
+ if (!dir_emit_dotdot(file, ctx))
+- goto out;
++ goto out_iter;
+ continue;
+ }
+
+- flen = udf_get_filename(sb, nameptr, lfi, fname, UDF_NAME_LEN);
++ flen = udf_get_filename(sb, iter.name,
++ iter.fi.lengthFileIdent, fname, UDF_NAME_LEN);
+ if (flen < 0)
+ continue;
+
+- tloc = lelb_to_cpu(cfi.icb.extLocation);
++ tloc = lelb_to_cpu(iter.fi.icb.extLocation);
+ iblock = udf_get_lb_pblock(sb, &tloc, 0);
+ if (!dir_emit(ctx, fname, flen, iblock, DT_UNKNOWN))
+- goto out;
+- } /* end while */
+-
+- ctx->pos = (nf_pos >> 2) + 1;
+- pos_valid = true;
++ goto out_iter;
++ }
+
++ if (!ret) {
++ ctx->pos = (iter.pos >> 2) + 1;
++ pos_valid = true;
++ }
++out_iter:
++ udf_fiiter_release(&iter);
+ out:
+ if (pos_valid)
+ file->f_version = inode_query_iversion(dir);
+- if (fibh.sbh != fibh.ebh)
+- brelse(fibh.ebh);
+- brelse(fibh.sbh);
+- brelse(epos.bh);
+ kfree(fname);
+- kfree(copy_name);
+
+ return ret;
+ }
--- /dev/null
+From stable+bounces-86656-greg=kroah.com@vger.kernel.org Thu Oct 17 19:19:54 2024
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Date: Thu, 17 Oct 2024 14:19:02 -0300
+Subject: udf: Convert udf_rename() to new directory iteration code
+To: stable@vger.kernel.org
+Cc: Jan Kara <jack@suse.cz>, kernel-dev@igalia.com, syzbot+0eaad3590d65102b9391@syzkaller.appspotmail.com, syzbot+b7fc73213bc2361ab650@syzkaller.appspotmail.com, Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Message-ID: <20241017171915.311132-7-cascardo@igalia.com>
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit e9109a92d2a95889498bed3719cd2318892171a2 ]
+
+Convert udf_rename() to use new directory iteration code.
+
+Reported-by: syzbot+0eaad3590d65102b9391@syzkaller.appspotmail.com
+Reported-by: syzbot+b7fc73213bc2361ab650@syzkaller.appspotmail.com
+Signed-off-by: Jan Kara <jack@suse.cz>
+[cascardo: remove the call to udf_rename_tag per commit
+ 27ab33854873 ("udf: Fix bogus checksum computation in udf_rename()")]
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/namei.c | 166 ++++++++++++++++++++++++++-------------------------------
+ 1 file changed, 78 insertions(+), 88 deletions(-)
+
+--- a/fs/udf/namei.c
++++ b/fs/udf/namei.c
+@@ -1238,78 +1238,68 @@ static int udf_rename(struct user_namesp
+ {
+ struct inode *old_inode = d_inode(old_dentry);
+ struct inode *new_inode = d_inode(new_dentry);
+- struct udf_fileident_bh ofibh, nfibh;
+- struct fileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi = NULL;
+- struct fileIdentDesc ocfi, ncfi;
+- struct buffer_head *dir_bh = NULL;
+- int retval = -ENOENT;
++ struct udf_fileident_iter oiter, niter, diriter;
++ bool has_diriter = false;
++ int retval;
+ struct kernel_lb_addr tloc;
+- struct udf_inode_info *old_iinfo = UDF_I(old_inode);
+
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
+- ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi);
+- if (!ofi || IS_ERR(ofi)) {
+- if (IS_ERR(ofi))
+- retval = PTR_ERR(ofi);
+- goto end_rename;
+- }
+-
+- if (ofibh.sbh != ofibh.ebh)
+- brelse(ofibh.ebh);
+-
+- brelse(ofibh.sbh);
+- tloc = lelb_to_cpu(ocfi.icb.extLocation);
+- if (udf_get_lb_pblock(old_dir->i_sb, &tloc, 0) != old_inode->i_ino)
+- goto end_rename;
+-
+- nfi = udf_find_entry(new_dir, &new_dentry->d_name, &nfibh, &ncfi);
+- if (IS_ERR(nfi)) {
+- retval = PTR_ERR(nfi);
+- goto end_rename;
+- }
+- if (nfi && !new_inode) {
+- if (nfibh.sbh != nfibh.ebh)
+- brelse(nfibh.ebh);
+- brelse(nfibh.sbh);
+- nfi = NULL;
++ retval = udf_fiiter_find_entry(old_dir, &old_dentry->d_name, &oiter);
++ if (retval)
++ return retval;
++
++ tloc = lelb_to_cpu(oiter.fi.icb.extLocation);
++ if (udf_get_lb_pblock(old_dir->i_sb, &tloc, 0) != old_inode->i_ino) {
++ retval = -ENOENT;
++ goto out_oiter;
+ }
+- if (S_ISDIR(old_inode->i_mode)) {
+- int offset = udf_ext0_offset(old_inode);
+
++ if (S_ISDIR(old_inode->i_mode)) {
+ if (new_inode) {
+ retval = -ENOTEMPTY;
+ if (!empty_dir(new_inode))
+- goto end_rename;
++ goto out_oiter;
+ }
+- retval = -EIO;
+- if (old_iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+- dir_fi = udf_get_fileident(
+- old_iinfo->i_data -
+- (old_iinfo->i_efe ?
+- sizeof(struct extendedFileEntry) :
+- sizeof(struct fileEntry)),
+- old_inode->i_sb->s_blocksize, &offset);
+- } else {
+- dir_bh = udf_bread(old_inode, 0, 0, &retval);
+- if (!dir_bh)
+- goto end_rename;
+- dir_fi = udf_get_fileident(dir_bh->b_data,
+- old_inode->i_sb->s_blocksize, &offset);
++ retval = udf_fiiter_find_entry(old_inode, &dotdot_name,
++ &diriter);
++ if (retval == -ENOENT) {
++ udf_err(old_inode->i_sb,
++ "directory (ino %lu) has no '..' entry\n",
++ old_inode->i_ino);
++ retval = -EFSCORRUPTED;
+ }
+- if (!dir_fi)
+- goto end_rename;
+- tloc = lelb_to_cpu(dir_fi->icb.extLocation);
++ if (retval)
++ goto out_oiter;
++ has_diriter = true;
++ tloc = lelb_to_cpu(diriter.fi.icb.extLocation);
+ if (udf_get_lb_pblock(old_inode->i_sb, &tloc, 0) !=
+- old_dir->i_ino)
+- goto end_rename;
++ old_dir->i_ino) {
++ retval = -EFSCORRUPTED;
++ udf_err(old_inode->i_sb,
++ "directory (ino %lu) has parent entry pointing to another inode (%lu != %u)\n",
++ old_inode->i_ino, old_dir->i_ino,
++ udf_get_lb_pblock(old_inode->i_sb, &tloc, 0));
++ goto out_oiter;
++ }
+ }
+- if (!nfi) {
+- nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi,
+- &retval);
+- if (!nfi)
+- goto end_rename;
++
++ retval = udf_fiiter_find_entry(new_dir, &new_dentry->d_name, &niter);
++ if (retval && retval != -ENOENT)
++ goto out_oiter;
++ /* Entry found but not passed by VFS? */
++ if (!retval && !new_inode) {
++ retval = -EFSCORRUPTED;
++ udf_fiiter_release(&niter);
++ goto out_oiter;
++ }
++ /* Entry not found? Need to add one... */
++ if (retval) {
++ udf_fiiter_release(&niter);
++ retval = udf_fiiter_add_entry(new_dir, new_dentry, &niter);
++ if (retval)
++ goto out_oiter;
+ }
+
+ /*
+@@ -1322,14 +1312,26 @@ static int udf_rename(struct user_namesp
+ /*
+ * ok, that's it
+ */
+- ncfi.fileVersionNum = ocfi.fileVersionNum;
+- ncfi.fileCharacteristics = ocfi.fileCharacteristics;
+- memcpy(&(ncfi.icb), &(ocfi.icb), sizeof(ocfi.icb));
+- udf_write_fi(new_dir, &ncfi, nfi, &nfibh, NULL, NULL);
+-
+- /* The old fid may have moved - find it again */
+- ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi);
+- udf_delete_entry(old_dir, ofi, &ofibh, &ocfi);
++ niter.fi.fileVersionNum = oiter.fi.fileVersionNum;
++ niter.fi.fileCharacteristics = oiter.fi.fileCharacteristics;
++ memcpy(&(niter.fi.icb), &(oiter.fi.icb), sizeof(oiter.fi.icb));
++ udf_fiiter_write_fi(&niter, NULL);
++ udf_fiiter_release(&niter);
++
++ /*
++ * The old entry may have moved due to new entry allocation. Find it
++ * again.
++ */
++ udf_fiiter_release(&oiter);
++ retval = udf_fiiter_find_entry(old_dir, &old_dentry->d_name, &oiter);
++ if (retval) {
++ udf_err(old_dir->i_sb,
++ "failed to find renamed entry again in directory (ino %lu)\n",
++ old_dir->i_ino);
++ } else {
++ udf_fiiter_delete_entry(&oiter);
++ udf_fiiter_release(&oiter);
++ }
+
+ if (new_inode) {
+ new_inode->i_ctime = current_time(new_inode);
+@@ -1340,12 +1342,11 @@ static int udf_rename(struct user_namesp
+ mark_inode_dirty(old_dir);
+ mark_inode_dirty(new_dir);
+
+- if (dir_fi) {
+- dir_fi->icb.extLocation = cpu_to_lelb(UDF_I(new_dir)->i_location);
+- if (old_iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
+- mark_inode_dirty(old_inode);
+- else
+- mark_buffer_dirty_inode(dir_bh, old_inode);
++ if (has_diriter) {
++ diriter.fi.icb.extLocation =
++ cpu_to_lelb(UDF_I(new_dir)->i_location);
++ udf_fiiter_write_fi(&diriter, NULL);
++ udf_fiiter_release(&diriter);
+
+ inode_dec_link_count(old_dir);
+ if (new_inode)
+@@ -1355,22 +1356,11 @@ static int udf_rename(struct user_namesp
+ mark_inode_dirty(new_dir);
+ }
+ }
+-
+- if (ofi) {
+- if (ofibh.sbh != ofibh.ebh)
+- brelse(ofibh.ebh);
+- brelse(ofibh.sbh);
+- }
+-
+- retval = 0;
+-
+-end_rename:
+- brelse(dir_bh);
+- if (nfi) {
+- if (nfibh.sbh != nfibh.ebh)
+- brelse(nfibh.ebh);
+- brelse(nfibh.sbh);
+- }
++ return 0;
++out_oiter:
++ if (has_diriter)
++ udf_fiiter_release(&diriter);
++ udf_fiiter_release(&oiter);
+
+ return retval;
+ }
--- /dev/null
+From stable+bounces-86661-greg=kroah.com@vger.kernel.org Thu Oct 17 19:30:42 2024
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Date: Thu, 17 Oct 2024 14:19:07 -0300
+Subject: udf: Convert udf_rmdir() to new directory iteration code
+To: stable@vger.kernel.org
+Cc: Jan Kara <jack@suse.cz>, kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Message-ID: <20241017171915.311132-12-cascardo@igalia.com>
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit d11ffa8d3ec11fdb665f12f95d58d74673051a93 ]
+
+Convert udf_rmdir() to use new directory iteration code.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/namei.c | 32 +++++++++++---------------------
+ 1 file changed, 11 insertions(+), 21 deletions(-)
+
+--- a/fs/udf/namei.c
++++ b/fs/udf/namei.c
+@@ -898,30 +898,23 @@ static int empty_dir(struct inode *dir)
+
+ static int udf_rmdir(struct inode *dir, struct dentry *dentry)
+ {
+- int retval;
++ int ret;
+ struct inode *inode = d_inode(dentry);
+- struct udf_fileident_bh fibh;
+- struct fileIdentDesc *fi, cfi;
++ struct udf_fileident_iter iter;
+ struct kernel_lb_addr tloc;
+
+- retval = -ENOENT;
+- fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
+- if (IS_ERR_OR_NULL(fi)) {
+- if (fi)
+- retval = PTR_ERR(fi);
++ ret = udf_fiiter_find_entry(dir, &dentry->d_name, &iter);
++ if (ret)
+ goto out;
+- }
+
+- retval = -EIO;
+- tloc = lelb_to_cpu(cfi.icb.extLocation);
++ ret = -EFSCORRUPTED;
++ tloc = lelb_to_cpu(iter.fi.icb.extLocation);
+ if (udf_get_lb_pblock(dir->i_sb, &tloc, 0) != inode->i_ino)
+ goto end_rmdir;
+- retval = -ENOTEMPTY;
++ ret = -ENOTEMPTY;
+ if (!empty_dir(inode))
+ goto end_rmdir;
+- retval = udf_delete_entry(dir, fi, &fibh, &cfi);
+- if (retval)
+- goto end_rmdir;
++ udf_fiiter_delete_entry(&iter);
+ if (inode->i_nlink != 2)
+ udf_warn(inode->i_sb, "empty directory has nlink != 2 (%u)\n",
+ inode->i_nlink);
+@@ -931,14 +924,11 @@ static int udf_rmdir(struct inode *dir,
+ inode->i_ctime = dir->i_ctime = dir->i_mtime =
+ current_time(inode);
+ mark_inode_dirty(dir);
+-
++ ret = 0;
+ end_rmdir:
+- if (fibh.sbh != fibh.ebh)
+- brelse(fibh.ebh);
+- brelse(fibh.sbh);
+-
++ udf_fiiter_release(&iter);
+ out:
+- return retval;
++ return ret;
+ }
+
+ static int udf_unlink(struct inode *dir, struct dentry *dentry)
--- /dev/null
+From stable+bounces-86662-greg=kroah.com@vger.kernel.org Thu Oct 17 19:25:26 2024
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Date: Thu, 17 Oct 2024 14:19:08 -0300
+Subject: udf: Convert udf_unlink() to new directory iteration code
+To: stable@vger.kernel.org
+Cc: Jan Kara <jack@suse.cz>, kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Message-ID: <20241017171915.311132-13-cascardo@igalia.com>
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit 6ec01a8020b54e278fecd1efe8603f8eb38fed84 ]
+
+Convert udf_unlink() to new directory iteration code.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/namei.c | 33 ++++++++++-----------------------
+ 1 file changed, 10 insertions(+), 23 deletions(-)
+
+--- a/fs/udf/namei.c
++++ b/fs/udf/namei.c
+@@ -933,24 +933,17 @@ out:
+
+ static int udf_unlink(struct inode *dir, struct dentry *dentry)
+ {
+- int retval;
++ int ret;
+ struct inode *inode = d_inode(dentry);
+- struct udf_fileident_bh fibh;
+- struct fileIdentDesc *fi;
+- struct fileIdentDesc cfi;
++ struct udf_fileident_iter iter;
+ struct kernel_lb_addr tloc;
+
+- retval = -ENOENT;
+- fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
+-
+- if (IS_ERR_OR_NULL(fi)) {
+- if (fi)
+- retval = PTR_ERR(fi);
++ ret = udf_fiiter_find_entry(dir, &dentry->d_name, &iter);
++ if (ret)
+ goto out;
+- }
+
+- retval = -EIO;
+- tloc = lelb_to_cpu(cfi.icb.extLocation);
++ ret = -EFSCORRUPTED;
++ tloc = lelb_to_cpu(iter.fi.icb.extLocation);
+ if (udf_get_lb_pblock(dir->i_sb, &tloc, 0) != inode->i_ino)
+ goto end_unlink;
+
+@@ -959,22 +952,16 @@ static int udf_unlink(struct inode *dir,
+ inode->i_ino, inode->i_nlink);
+ set_nlink(inode, 1);
+ }
+- retval = udf_delete_entry(dir, fi, &fibh, &cfi);
+- if (retval)
+- goto end_unlink;
++ udf_fiiter_delete_entry(&iter);
+ dir->i_ctime = dir->i_mtime = current_time(dir);
+ mark_inode_dirty(dir);
+ inode_dec_link_count(inode);
+ inode->i_ctime = dir->i_ctime;
+- retval = 0;
+-
++ ret = 0;
+ end_unlink:
+- if (fibh.sbh != fibh.ebh)
+- brelse(fibh.ebh);
+- brelse(fibh.sbh);
+-
++ udf_fiiter_release(&iter);
+ out:
+- return retval;
++ return ret;
+ }
+
+ static int udf_symlink(struct user_namespace *mnt_userns, struct inode *dir,
--- /dev/null
+From stable+bounces-86670-greg=kroah.com@vger.kernel.org Thu Oct 17 19:20:21 2024
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Date: Thu, 17 Oct 2024 14:19:15 -0300
+Subject: udf: Don't return bh from udf_expand_dir_adinicb()
+To: stable@vger.kernel.org
+Cc: Jan Kara <jack@suse.cz>, kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Message-ID: <20241017171915.311132-20-cascardo@igalia.com>
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit f386c802a6fda8f9fe4a5cf418c49aa84dfc52e4 ]
+
+Nobody uses the bh returned from udf_expand_dir_adinicb(). Don't return
+it.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+[cascardo: skip backport of 101ee137d32a ("udf: Drop VARCONV support")]
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/namei.c | 33 +++++++++++++--------------------
+ 1 file changed, 13 insertions(+), 20 deletions(-)
+
+--- a/fs/udf/namei.c
++++ b/fs/udf/namei.c
+@@ -136,8 +136,7 @@ static struct dentry *udf_lookup(struct
+ return d_splice_alias(inode, dentry);
+ }
+
+-static struct buffer_head *udf_expand_dir_adinicb(struct inode *inode,
+- udf_pblk_t *block, int *err)
++static int udf_expand_dir_adinicb(struct inode *inode, udf_pblk_t *block)
+ {
+ udf_pblk_t newblock;
+ struct buffer_head *dbh = NULL;
+@@ -157,23 +156,23 @@ static struct buffer_head *udf_expand_di
+ if (!inode->i_size) {
+ iinfo->i_alloc_type = alloctype;
+ mark_inode_dirty(inode);
+- return NULL;
++ return 0;
+ }
+
+ /* alloc block, and copy data to it */
+ *block = udf_new_block(inode->i_sb, inode,
+ iinfo->i_location.partitionReferenceNum,
+- iinfo->i_location.logicalBlockNum, err);
++ iinfo->i_location.logicalBlockNum, &ret);
+ if (!(*block))
+- return NULL;
++ return ret;
+ newblock = udf_get_pblock(inode->i_sb, *block,
+ iinfo->i_location.partitionReferenceNum,
+ 0);
+- if (!newblock)
+- return NULL;
++ if (newblock == 0xffffffff)
++ return -EFSCORRUPTED;
+ dbh = udf_tgetblk(inode->i_sb, newblock);
+ if (!dbh)
+- return NULL;
++ return -ENOMEM;
+ lock_buffer(dbh);
+ memcpy(dbh->b_data, iinfo->i_data, inode->i_size);
+ memset(dbh->b_data + inode->i_size, 0,
+@@ -195,9 +194,9 @@ static struct buffer_head *udf_expand_di
+ ret = udf_add_aext(inode, &epos, &eloc, inode->i_size, 0);
+ brelse(epos.bh);
+ if (ret < 0) {
+- *err = ret;
++ brelse(dbh);
+ udf_free_blocks(inode->i_sb, inode, &eloc, 0, 1);
+- return NULL;
++ return ret;
+ }
+ mark_inode_dirty(inode);
+
+@@ -213,6 +212,7 @@ static struct buffer_head *udf_expand_di
+ impuse = NULL;
+ udf_fiiter_write_fi(&iter, impuse);
+ }
++ brelse(dbh);
+ /*
+ * We don't expect the iteration to fail as the directory has been
+ * already verified to be correct
+@@ -220,7 +220,7 @@ static struct buffer_head *udf_expand_di
+ WARN_ON_ONCE(ret);
+ udf_fiiter_release(&iter);
+
+- return dbh;
++ return 0;
+ }
+
+ static int udf_fiiter_add_entry(struct inode *dir, struct dentry *dentry,
+@@ -266,17 +266,10 @@ static int udf_fiiter_add_entry(struct i
+ }
+ if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB &&
+ blksize - udf_ext0_offset(dir) - iter->pos < nfidlen) {
+- struct buffer_head *retbh;
+-
+ udf_fiiter_release(iter);
+- /*
+- * FIXME: udf_expand_dir_adinicb does not need to return bh
+- * once other users are gone
+- */
+- retbh = udf_expand_dir_adinicb(dir, &block, &ret);
+- if (!retbh)
++ ret = udf_expand_dir_adinicb(dir, &block);
++ if (ret)
+ return ret;
+- brelse(retbh);
+ ret = udf_fiiter_init(iter, dir, dir->i_size);
+ if (ret < 0)
+ return ret;
--- /dev/null
+From stable+bounces-86669-greg=kroah.com@vger.kernel.org Thu Oct 17 19:20:18 2024
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Date: Thu, 17 Oct 2024 14:19:14 -0300
+Subject: udf: Handle error when expanding directory
+To: stable@vger.kernel.org
+Cc: Jan Kara <jack@suse.cz>, kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Message-ID: <20241017171915.311132-19-cascardo@igalia.com>
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit 33e9a53cd9f099b138578f8e1a3d60775ff8cbba ]
+
+When there is an error when adding extent to the directory to expand it,
+make sure to propagate the error up properly. This is not expected to
+happen currently but let's make the code more futureproof.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/namei.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/fs/udf/namei.c
++++ b/fs/udf/namei.c
+@@ -192,8 +192,13 @@ static struct buffer_head *udf_expand_di
+ epos.bh = NULL;
+ epos.block = iinfo->i_location;
+ epos.offset = udf_file_entry_alloc_offset(inode);
+- udf_add_aext(inode, &epos, &eloc, inode->i_size, 0);
++ ret = udf_add_aext(inode, &epos, &eloc, inode->i_size, 0);
+ brelse(epos.bh);
++ if (ret < 0) {
++ *err = ret;
++ udf_free_blocks(inode->i_sb, inode, &eloc, 0, 1);
++ return NULL;
++ }
+ mark_inode_dirty(inode);
+
+ /* Now fixup tags in moved directory entries */
--- /dev/null
+From stable+bounces-86664-greg=kroah.com@vger.kernel.org Thu Oct 17 19:20:07 2024
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Date: Thu, 17 Oct 2024 14:19:09 -0300
+Subject: udf: Implement adding of dir entries using new iteration code
+To: stable@vger.kernel.org
+Cc: Jan Kara <jack@suse.cz>, kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Message-ID: <20241017171915.311132-14-cascardo@igalia.com>
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit f2844803404d9729f893e279ddea12678710e7fb ]
+
+Implement function udf_fiiter_add_entry() adding new directory entries
+using new directory iteration code.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/directory.c | 57 +++++++++++++++++++++++++++
+ fs/udf/namei.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ fs/udf/udfdecl.h | 2
+ 3 files changed, 169 insertions(+)
+
+--- a/fs/udf/directory.c
++++ b/fs/udf/directory.c
+@@ -413,6 +413,63 @@ void udf_fiiter_write_fi(struct udf_file
+ inode_inc_iversion(iter->dir);
+ }
+
++void udf_fiiter_update_elen(struct udf_fileident_iter *iter, uint32_t new_elen)
++{
++ struct udf_inode_info *iinfo = UDF_I(iter->dir);
++ int diff = new_elen - iter->elen;
++
++ /* Skip update when we already went past the last extent */
++ if (!iter->elen)
++ return;
++ iter->elen = new_elen;
++ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
++ iter->epos.offset -= sizeof(struct short_ad);
++ else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
++ iter->epos.offset -= sizeof(struct long_ad);
++ udf_write_aext(iter->dir, &iter->epos, &iter->eloc, iter->elen, 1);
++ iinfo->i_lenExtents += diff;
++ mark_inode_dirty(iter->dir);
++}
++
++/* Append new block to directory. @iter is expected to point at EOF */
++int udf_fiiter_append_blk(struct udf_fileident_iter *iter)
++{
++ struct udf_inode_info *iinfo = UDF_I(iter->dir);
++ int blksize = 1 << iter->dir->i_blkbits;
++ struct buffer_head *bh;
++ sector_t block;
++ uint32_t old_elen = iter->elen;
++ int err;
++
++ if (WARN_ON_ONCE(iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB))
++ return -EINVAL;
++
++ /* Round up last extent in the file */
++ udf_fiiter_update_elen(iter, ALIGN(iter->elen, blksize));
++
++ /* Allocate new block and refresh mapping information */
++ block = iinfo->i_lenExtents >> iter->dir->i_blkbits;
++ bh = udf_bread(iter->dir, block, 1, &err);
++ if (!bh) {
++ udf_fiiter_update_elen(iter, old_elen);
++ return err;
++ }
++ if (inode_bmap(iter->dir, block, &iter->epos, &iter->eloc, &iter->elen,
++ &iter->loffset) != (EXT_RECORDED_ALLOCATED >> 30)) {
++ udf_err(iter->dir->i_sb,
++ "block %llu not allocated in directory (ino %lu)\n",
++ (unsigned long long)block, iter->dir->i_ino);
++ return -EFSCORRUPTED;
++ }
++ if (!(iter->pos & (blksize - 1))) {
++ brelse(iter->bh[0]);
++ iter->bh[0] = bh;
++ } else {
++ iter->bh[1] = bh;
++ }
++ return 0;
++}
++
+ struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos,
+ struct udf_fileident_bh *fibh,
+ struct fileIdentDesc *cfi,
+--- a/fs/udf/namei.c
++++ b/fs/udf/namei.c
+@@ -472,6 +472,116 @@ static struct buffer_head *udf_expand_di
+ return dbh;
+ }
+
++static int udf_fiiter_add_entry(struct inode *dir, struct dentry *dentry,
++ struct udf_fileident_iter *iter)
++{
++ struct udf_inode_info *dinfo = UDF_I(dir);
++ int nfidlen, namelen = 0;
++ int ret;
++ int off, blksize = 1 << dir->i_blkbits;
++ udf_pblk_t block;
++ char name[UDF_NAME_LEN_CS0];
++
++ if (dentry) {
++ if (!dentry->d_name.len)
++ return -EINVAL;
++ namelen = udf_put_filename(dir->i_sb, dentry->d_name.name,
++ dentry->d_name.len,
++ name, UDF_NAME_LEN_CS0);
++ if (!namelen)
++ return -ENAMETOOLONG;
++ }
++ nfidlen = ALIGN(sizeof(struct fileIdentDesc) + namelen, UDF_NAME_PAD);
++
++ for (ret = udf_fiiter_init(iter, dir, 0);
++ !ret && iter->pos < dir->i_size;
++ ret = udf_fiiter_advance(iter)) {
++ if (iter->fi.fileCharacteristics & FID_FILE_CHAR_DELETED) {
++ if (udf_dir_entry_len(&iter->fi) == nfidlen) {
++ iter->fi.descTag.tagSerialNum = cpu_to_le16(1);
++ iter->fi.fileVersionNum = cpu_to_le16(1);
++ iter->fi.fileCharacteristics = 0;
++ iter->fi.lengthFileIdent = namelen;
++ iter->fi.lengthOfImpUse = cpu_to_le16(0);
++ memcpy(iter->namebuf, name, namelen);
++ iter->name = iter->namebuf;
++ return 0;
++ }
++ }
++ }
++ if (ret) {
++ udf_fiiter_release(iter);
++ return ret;
++ }
++ if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB &&
++ blksize - udf_ext0_offset(dir) - iter->pos < nfidlen) {
++ struct buffer_head *retbh;
++
++ udf_fiiter_release(iter);
++ /*
++ * FIXME: udf_expand_dir_adinicb does not need to return bh
++ * once other users are gone
++ */
++ retbh = udf_expand_dir_adinicb(dir, &block, &ret);
++ if (!retbh)
++ return ret;
++ brelse(retbh);
++ ret = udf_fiiter_init(iter, dir, dir->i_size);
++ if (ret < 0)
++ return ret;
++ }
++
++ /* Get blocknumber to use for entry tag */
++ if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
++ block = dinfo->i_location.logicalBlockNum;
++ } else {
++ block = iter->eloc.logicalBlockNum +
++ ((iter->elen - 1) >> dir->i_blkbits);
++ }
++ off = iter->pos & (blksize - 1);
++ if (!off)
++ off = blksize;
++ /* Entry fits into current block? */
++ if (blksize - udf_ext0_offset(dir) - off >= nfidlen)
++ goto store_fi;
++
++ ret = udf_fiiter_append_blk(iter);
++ if (ret) {
++ udf_fiiter_release(iter);
++ return ret;
++ }
++
++ /* Entry will be completely in the new block? Update tag location... */
++ if (!(iter->pos & (blksize - 1)))
++ block = iter->eloc.logicalBlockNum +
++ ((iter->elen - 1) >> dir->i_blkbits);
++store_fi:
++ memset(&iter->fi, 0, sizeof(struct fileIdentDesc));
++ if (UDF_SB(dir->i_sb)->s_udfrev >= 0x0200)
++ udf_new_tag((char *)(&iter->fi), TAG_IDENT_FID, 3, 1, block,
++ sizeof(struct tag));
++ else
++ udf_new_tag((char *)(&iter->fi), TAG_IDENT_FID, 2, 1, block,
++ sizeof(struct tag));
++ iter->fi.fileVersionNum = cpu_to_le16(1);
++ iter->fi.lengthFileIdent = namelen;
++ iter->fi.lengthOfImpUse = cpu_to_le16(0);
++ memcpy(iter->namebuf, name, namelen);
++ iter->name = iter->namebuf;
++
++ dir->i_size += nfidlen;
++ if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
++ dinfo->i_lenAlloc += nfidlen;
++ } else {
++ /* Truncate last extent to proper size */
++ udf_fiiter_update_elen(iter, iter->elen -
++ (dinfo->i_lenExtents - dir->i_size));
++ }
++ mark_inode_dirty(dir);
++
++ return 0;
++}
++
+ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
+ struct dentry *dentry,
+ struct udf_fileident_bh *fibh,
+--- a/fs/udf/udfdecl.h
++++ b/fs/udf/udfdecl.h
+@@ -264,6 +264,8 @@ int udf_fiiter_init(struct udf_fileident
+ int udf_fiiter_advance(struct udf_fileident_iter *iter);
+ void udf_fiiter_release(struct udf_fileident_iter *iter);
+ void udf_fiiter_write_fi(struct udf_fileident_iter *iter, uint8_t *impuse);
++void udf_fiiter_update_elen(struct udf_fileident_iter *iter, uint32_t new_elen);
++int udf_fiiter_append_blk(struct udf_fileident_iter *iter);
+ extern struct fileIdentDesc *udf_fileident_read(struct inode *, loff_t *,
+ struct udf_fileident_bh *,
+ struct fileIdentDesc *,
--- /dev/null
+From stable+bounces-86654-greg=kroah.com@vger.kernel.org Thu Oct 17 19:19:51 2024
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Date: Thu, 17 Oct 2024 14:19:00 -0300
+Subject: udf: Implement searching for directory entry using new iteration code
+To: stable@vger.kernel.org
+Cc: Jan Kara <jack@suse.cz>, kernel-dev@igalia.com, syzbot+69c9fdccc6dd08961d34@syzkaller.appspotmail.com, Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Message-ID: <20241017171915.311132-5-cascardo@igalia.com>
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit 1c80afa04db39c98aebea9aabfafa37a208cdfee ]
+
+Implement searching for directory entry - udf_fiiter_find_entry() -
+using new directory iteration code.
+
+Reported-by: syzbot+69c9fdccc6dd08961d34@syzkaller.appspotmail.com
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/namei.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 67 insertions(+)
+
+--- a/fs/udf/namei.c
++++ b/fs/udf/namei.c
+@@ -141,6 +141,73 @@ int udf_write_fi(struct inode *inode, st
+ }
+
+ /**
++ * udf_fiiter_find_entry - find entry in given directory.
++ *
++ * @dir: directory inode to search in
++ * @child: qstr of the name
++ * @iter: iter to use for searching
++ *
++ * This function searches in the directory @dir for a file name @child. When
++ * found, @iter points to the position in the directory with given entry.
++ *
++ * Returns 0 on success, < 0 on error (including -ENOENT).
++ */
++static int udf_fiiter_find_entry(struct inode *dir, const struct qstr *child,
++ struct udf_fileident_iter *iter)
++{
++ int flen;
++ unsigned char *fname = NULL;
++ struct super_block *sb = dir->i_sb;
++ int isdotdot = child->len == 2 &&
++ child->name[0] == '.' && child->name[1] == '.';
++ int ret;
++
++ fname = kmalloc(UDF_NAME_LEN, GFP_NOFS);
++ if (!fname)
++ return -ENOMEM;
++
++ for (ret = udf_fiiter_init(iter, dir, 0);
++ !ret && iter->pos < dir->i_size;
++ ret = udf_fiiter_advance(iter)) {
++ if (iter->fi.fileCharacteristics & FID_FILE_CHAR_DELETED) {
++ if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE))
++ continue;
++ }
++
++ if (iter->fi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) {
++ if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE))
++ continue;
++ }
++
++ if ((iter->fi.fileCharacteristics & FID_FILE_CHAR_PARENT) &&
++ isdotdot)
++ goto out_ok;
++
++ if (!iter->fi.lengthFileIdent)
++ continue;
++
++ flen = udf_get_filename(sb, iter->name,
++ iter->fi.lengthFileIdent, fname, UDF_NAME_LEN);
++ if (flen < 0) {
++ ret = flen;
++ goto out_err;
++ }
++
++ if (udf_match(flen, fname, child->len, child->name))
++ goto out_ok;
++ }
++ if (!ret)
++ ret = -ENOENT;
++
++out_err:
++ udf_fiiter_release(iter);
++out_ok:
++ kfree(fname);
++
++ return ret;
++}
++
++/**
+ * udf_find_entry - find entry in given directory.
+ *
+ * @dir: directory inode to search in
--- /dev/null
+From stable+bounces-86653-greg=kroah.com@vger.kernel.org Thu Oct 17 19:19:51 2024
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Date: Thu, 17 Oct 2024 14:18:59 -0300
+Subject: udf: Move udf_expand_dir_adinicb() to its callsite
+To: stable@vger.kernel.org
+Cc: Jan Kara <jack@suse.cz>, kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Message-ID: <20241017171915.311132-4-cascardo@igalia.com>
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit a27b2923de7efaa1da1e243fb80ff0fa432e4be0 ]
+
+There is just one caller of udf_expand_dir_adinicb(). Move the function
+to its caller into namei.c as it is more about directory handling than
+anything else anyway.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/inode.c | 82 -------------------------------------------------------
+ fs/udf/namei.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ fs/udf/udfdecl.h | 2 -
+ 3 files changed, 82 insertions(+), 84 deletions(-)
+
+--- a/fs/udf/inode.c
++++ b/fs/udf/inode.c
+@@ -325,88 +325,6 @@ int udf_expand_file_adinicb(struct inode
+ return err;
+ }
+
+-struct buffer_head *udf_expand_dir_adinicb(struct inode *inode,
+- udf_pblk_t *block, int *err)
+-{
+- udf_pblk_t newblock;
+- struct buffer_head *dbh = NULL;
+- struct kernel_lb_addr eloc;
+- struct extent_position epos;
+- 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;
+- else
+- alloctype = ICBTAG_FLAG_AD_LONG;
+-
+- if (!inode->i_size) {
+- iinfo->i_alloc_type = alloctype;
+- mark_inode_dirty(inode);
+- return NULL;
+- }
+-
+- /* alloc block, and copy data to it */
+- *block = udf_new_block(inode->i_sb, inode,
+- iinfo->i_location.partitionReferenceNum,
+- iinfo->i_location.logicalBlockNum, err);
+- if (!(*block))
+- return NULL;
+- newblock = udf_get_pblock(inode->i_sb, *block,
+- iinfo->i_location.partitionReferenceNum,
+- 0);
+- if (!newblock)
+- return NULL;
+- dbh = udf_tgetblk(inode->i_sb, newblock);
+- if (!dbh)
+- return NULL;
+- lock_buffer(dbh);
+- 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);
+-
+- /* 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;
+- eloc.partitionReferenceNum =
+- iinfo->i_location.partitionReferenceNum;
+- iinfo->i_lenExtents = inode->i_size;
+- epos.bh = NULL;
+- epos.block = iinfo->i_location;
+- epos.offset = udf_file_entry_alloc_offset(inode);
+- udf_add_aext(inode, &epos, &eloc, inode->i_size, 0);
+- 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;
+-}
+-
+ static int udf_get_block(struct inode *inode, sector_t block,
+ struct buffer_head *bh_result, int create)
+ {
+--- a/fs/udf/namei.c
++++ b/fs/udf/namei.c
+@@ -326,6 +326,88 @@ static struct dentry *udf_lookup(struct
+ return d_splice_alias(inode, dentry);
+ }
+
++static struct buffer_head *udf_expand_dir_adinicb(struct inode *inode,
++ udf_pblk_t *block, int *err)
++{
++ udf_pblk_t newblock;
++ struct buffer_head *dbh = NULL;
++ struct kernel_lb_addr eloc;
++ struct extent_position epos;
++ 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;
++ else
++ alloctype = ICBTAG_FLAG_AD_LONG;
++
++ if (!inode->i_size) {
++ iinfo->i_alloc_type = alloctype;
++ mark_inode_dirty(inode);
++ return NULL;
++ }
++
++ /* alloc block, and copy data to it */
++ *block = udf_new_block(inode->i_sb, inode,
++ iinfo->i_location.partitionReferenceNum,
++ iinfo->i_location.logicalBlockNum, err);
++ if (!(*block))
++ return NULL;
++ newblock = udf_get_pblock(inode->i_sb, *block,
++ iinfo->i_location.partitionReferenceNum,
++ 0);
++ if (!newblock)
++ return NULL;
++ dbh = udf_tgetblk(inode->i_sb, newblock);
++ if (!dbh)
++ return NULL;
++ lock_buffer(dbh);
++ 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);
++
++ /* 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;
++ eloc.partitionReferenceNum =
++ iinfo->i_location.partitionReferenceNum;
++ iinfo->i_lenExtents = inode->i_size;
++ epos.bh = NULL;
++ epos.block = iinfo->i_location;
++ epos.offset = udf_file_entry_alloc_offset(inode);
++ udf_add_aext(inode, &epos, &eloc, inode->i_size, 0);
++ 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;
++}
++
+ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
+ struct dentry *dentry,
+ struct udf_fileident_bh *fibh,
+--- a/fs/udf/udfdecl.h
++++ b/fs/udf/udfdecl.h
+@@ -169,8 +169,6 @@ static inline struct inode *udf_iget(str
+ return __udf_iget(sb, ino, false);
+ }
+ extern int udf_expand_file_adinicb(struct inode *);
+-extern struct buffer_head *udf_expand_dir_adinicb(struct inode *inode,
+- udf_pblk_t *block, int *err);
+ extern struct buffer_head *udf_bread(struct inode *inode, udf_pblk_t block,
+ int create, int *err);
+ extern int udf_setsize(struct inode *, loff_t);
--- /dev/null
+From stable+bounces-86651-greg=kroah.com@vger.kernel.org Thu Oct 17 19:19:49 2024
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Date: Thu, 17 Oct 2024 14:18:57 -0300
+Subject: udf: New directory iteration code
+To: stable@vger.kernel.org
+Cc: Jan Kara <jack@suse.cz>, kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Message-ID: <20241017171915.311132-2-cascardo@igalia.com>
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit d16076d9b684b7c8d3ccbe9c33d5ea9fe8fcca09 ]
+
+Add new support code for iterating directory entries. The code is also
+more carefully verifying validity of on-disk directory entries to avoid
+crashes on malicious media.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/directory.c | 395 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ fs/udf/udfdecl.h | 23 +++
+ 2 files changed, 418 insertions(+)
+
+--- a/fs/udf/directory.c
++++ b/fs/udf/directory.c
+@@ -17,6 +17,401 @@
+ #include <linux/fs.h>
+ #include <linux/string.h>
+ #include <linux/bio.h>
++#include <linux/crc-itu-t.h>
++#include <linux/iversion.h>
++
++static int udf_verify_fi(struct udf_fileident_iter *iter)
++{
++ unsigned int len;
++
++ if (iter->fi.descTag.tagIdent != cpu_to_le16(TAG_IDENT_FID)) {
++ udf_err(iter->dir->i_sb,
++ "directory (ino %lu) has entry at pos %llu with incorrect tag %x\n",
++ iter->dir->i_ino, (unsigned long long)iter->pos,
++ le16_to_cpu(iter->fi.descTag.tagIdent));
++ return -EFSCORRUPTED;
++ }
++ len = udf_dir_entry_len(&iter->fi);
++ if (le16_to_cpu(iter->fi.lengthOfImpUse) & 3) {
++ udf_err(iter->dir->i_sb,
++ "directory (ino %lu) has entry at pos %llu with unaligned lenght of impUse field\n",
++ iter->dir->i_ino, (unsigned long long)iter->pos);
++ return -EFSCORRUPTED;
++ }
++ /*
++ * This is in fact allowed by the spec due to long impUse field but
++ * we don't support it. If there is real media with this large impUse
++ * field, support can be added.
++ */
++ if (len > 1 << iter->dir->i_blkbits) {
++ udf_err(iter->dir->i_sb,
++ "directory (ino %lu) has too big (%u) entry at pos %llu\n",
++ iter->dir->i_ino, len, (unsigned long long)iter->pos);
++ return -EFSCORRUPTED;
++ }
++ if (iter->pos + len > iter->dir->i_size) {
++ udf_err(iter->dir->i_sb,
++ "directory (ino %lu) has entry past directory size at pos %llu\n",
++ iter->dir->i_ino, (unsigned long long)iter->pos);
++ return -EFSCORRUPTED;
++ }
++ if (udf_dir_entry_len(&iter->fi) !=
++ sizeof(struct tag) + le16_to_cpu(iter->fi.descTag.descCRCLength)) {
++ udf_err(iter->dir->i_sb,
++ "directory (ino %lu) has entry where CRC length (%u) does not match entry length (%u)\n",
++ iter->dir->i_ino,
++ (unsigned)le16_to_cpu(iter->fi.descTag.descCRCLength),
++ (unsigned)(udf_dir_entry_len(&iter->fi) -
++ sizeof(struct tag)));
++ return -EFSCORRUPTED;
++ }
++ return 0;
++}
++
++static int udf_copy_fi(struct udf_fileident_iter *iter)
++{
++ struct udf_inode_info *iinfo = UDF_I(iter->dir);
++ int blksize = 1 << iter->dir->i_blkbits;
++ int err, off, len, nameoff;
++
++ /* Skip copying when we are at EOF */
++ if (iter->pos >= iter->dir->i_size) {
++ iter->name = NULL;
++ return 0;
++ }
++ if (iter->dir->i_size < iter->pos + sizeof(struct fileIdentDesc)) {
++ udf_err(iter->dir->i_sb,
++ "directory (ino %lu) has entry straddling EOF\n",
++ iter->dir->i_ino);
++ return -EFSCORRUPTED;
++ }
++ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
++ memcpy(&iter->fi, iinfo->i_data + iinfo->i_lenEAttr + iter->pos,
++ sizeof(struct fileIdentDesc));
++ err = udf_verify_fi(iter);
++ if (err < 0)
++ return err;
++ iter->name = iinfo->i_data + iinfo->i_lenEAttr + iter->pos +
++ sizeof(struct fileIdentDesc) +
++ le16_to_cpu(iter->fi.lengthOfImpUse);
++ return 0;
++ }
++
++ off = iter->pos & (blksize - 1);
++ len = min_t(int, sizeof(struct fileIdentDesc), blksize - off);
++ memcpy(&iter->fi, iter->bh[0]->b_data + off, len);
++ if (len < sizeof(struct fileIdentDesc))
++ memcpy((char *)(&iter->fi) + len, iter->bh[1]->b_data,
++ sizeof(struct fileIdentDesc) - len);
++ err = udf_verify_fi(iter);
++ if (err < 0)
++ return err;
++
++ /* Handle directory entry name */
++ nameoff = off + sizeof(struct fileIdentDesc) +
++ le16_to_cpu(iter->fi.lengthOfImpUse);
++ if (off + udf_dir_entry_len(&iter->fi) <= blksize) {
++ iter->name = iter->bh[0]->b_data + nameoff;
++ } else if (nameoff >= blksize) {
++ iter->name = iter->bh[1]->b_data + (nameoff - blksize);
++ } else {
++ iter->name = iter->namebuf;
++ len = blksize - nameoff;
++ memcpy(iter->name, iter->bh[0]->b_data + nameoff, len);
++ memcpy(iter->name + len, iter->bh[1]->b_data,
++ iter->fi.lengthFileIdent - len);
++ }
++ return 0;
++}
++
++/* Readahead 8k once we are at 8k boundary */
++static void udf_readahead_dir(struct udf_fileident_iter *iter)
++{
++ unsigned int ralen = 16 >> (iter->dir->i_blkbits - 9);
++ struct buffer_head *tmp, *bha[16];
++ int i, num;
++ udf_pblk_t blk;
++
++ if (iter->loffset & (ralen - 1))
++ return;
++
++ if (iter->loffset + ralen > (iter->elen >> iter->dir->i_blkbits))
++ ralen = (iter->elen >> iter->dir->i_blkbits) - iter->loffset;
++ num = 0;
++ for (i = 0; i < ralen; i++) {
++ blk = udf_get_lb_pblock(iter->dir->i_sb, &iter->eloc,
++ iter->loffset + i);
++ tmp = udf_tgetblk(iter->dir->i_sb, blk);
++ if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
++ bha[num++] = tmp;
++ else
++ brelse(tmp);
++ }
++ if (num) {
++ bh_readahead_batch(num, bha, REQ_RAHEAD);
++ for (i = 0; i < num; i++)
++ brelse(bha[i]);
++ }
++}
++
++static struct buffer_head *udf_fiiter_bread_blk(struct udf_fileident_iter *iter)
++{
++ udf_pblk_t blk;
++
++ udf_readahead_dir(iter);
++ blk = udf_get_lb_pblock(iter->dir->i_sb, &iter->eloc, iter->loffset);
++ return udf_tread(iter->dir->i_sb, blk);
++}
++
++/*
++ * Updates loffset to point to next directory block; eloc, elen & epos are
++ * updated if we need to traverse to the next extent as well.
++ */
++static int udf_fiiter_advance_blk(struct udf_fileident_iter *iter)
++{
++ iter->loffset++;
++ if (iter->loffset < iter->elen >> iter->dir->i_blkbits)
++ return 0;
++
++ iter->loffset = 0;
++ if (udf_next_aext(iter->dir, &iter->epos, &iter->eloc, &iter->elen, 1)
++ != (EXT_RECORDED_ALLOCATED >> 30)) {
++ if (iter->pos == iter->dir->i_size) {
++ iter->elen = 0;
++ return 0;
++ }
++ udf_err(iter->dir->i_sb,
++ "extent after position %llu not allocated in directory (ino %lu)\n",
++ (unsigned long long)iter->pos, iter->dir->i_ino);
++ return -EFSCORRUPTED;
++ }
++ return 0;
++}
++
++static int udf_fiiter_load_bhs(struct udf_fileident_iter *iter)
++{
++ int blksize = 1 << iter->dir->i_blkbits;
++ int off = iter->pos & (blksize - 1);
++ int err;
++ struct fileIdentDesc *fi;
++
++ /* Is there any further extent we can map from? */
++ if (!iter->bh[0] && iter->elen) {
++ iter->bh[0] = udf_fiiter_bread_blk(iter);
++ if (!iter->bh[0]) {
++ err = -ENOMEM;
++ goto out_brelse;
++ }
++ if (!buffer_uptodate(iter->bh[0])) {
++ err = -EIO;
++ goto out_brelse;
++ }
++ }
++ /* There's no next block so we are done */
++ if (iter->pos >= iter->dir->i_size)
++ return 0;
++ /* Need to fetch next block as well? */
++ if (off + sizeof(struct fileIdentDesc) > blksize)
++ goto fetch_next;
++ fi = (struct fileIdentDesc *)(iter->bh[0]->b_data + off);
++ /* Need to fetch next block to get name? */
++ if (off + udf_dir_entry_len(fi) > blksize) {
++fetch_next:
++ udf_fiiter_advance_blk(iter);
++ iter->bh[1] = udf_fiiter_bread_blk(iter);
++ if (!iter->bh[1]) {
++ err = -ENOMEM;
++ goto out_brelse;
++ }
++ if (!buffer_uptodate(iter->bh[1])) {
++ err = -EIO;
++ goto out_brelse;
++ }
++ }
++ return 0;
++out_brelse:
++ brelse(iter->bh[0]);
++ brelse(iter->bh[1]);
++ iter->bh[0] = iter->bh[1] = NULL;
++ return err;
++}
++
++int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir,
++ loff_t pos)
++{
++ struct udf_inode_info *iinfo = UDF_I(dir);
++ int err = 0;
++
++ iter->dir = dir;
++ iter->bh[0] = iter->bh[1] = NULL;
++ iter->pos = pos;
++ iter->elen = 0;
++ iter->epos.bh = NULL;
++ iter->name = NULL;
++
++ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
++ return udf_copy_fi(iter);
++
++ if (inode_bmap(dir, iter->pos >> dir->i_blkbits, &iter->epos,
++ &iter->eloc, &iter->elen, &iter->loffset) !=
++ (EXT_RECORDED_ALLOCATED >> 30)) {
++ if (pos == dir->i_size)
++ return 0;
++ udf_err(dir->i_sb,
++ "position %llu not allocated in directory (ino %lu)\n",
++ (unsigned long long)pos, dir->i_ino);
++ return -EFSCORRUPTED;
++ }
++ err = udf_fiiter_load_bhs(iter);
++ if (err < 0)
++ return err;
++ err = udf_copy_fi(iter);
++ if (err < 0) {
++ udf_fiiter_release(iter);
++ return err;
++ }
++ return 0;
++}
++
++int udf_fiiter_advance(struct udf_fileident_iter *iter)
++{
++ unsigned int oldoff, len;
++ int blksize = 1 << iter->dir->i_blkbits;
++ int err;
++
++ oldoff = iter->pos & (blksize - 1);
++ len = udf_dir_entry_len(&iter->fi);
++ iter->pos += len;
++ if (UDF_I(iter->dir)->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
++ if (oldoff + len >= blksize) {
++ brelse(iter->bh[0]);
++ iter->bh[0] = NULL;
++ /* Next block already loaded? */
++ if (iter->bh[1]) {
++ iter->bh[0] = iter->bh[1];
++ iter->bh[1] = NULL;
++ } else {
++ udf_fiiter_advance_blk(iter);
++ }
++ }
++ err = udf_fiiter_load_bhs(iter);
++ if (err < 0)
++ return err;
++ }
++ return udf_copy_fi(iter);
++}
++
++void udf_fiiter_release(struct udf_fileident_iter *iter)
++{
++ iter->dir = NULL;
++ brelse(iter->bh[0]);
++ brelse(iter->bh[1]);
++ iter->bh[0] = iter->bh[1] = NULL;
++}
++
++static void udf_copy_to_bufs(void *buf1, int len1, void *buf2, int len2,
++ int off, void *src, int len)
++{
++ int copy;
++
++ if (off >= len1) {
++ off -= len1;
++ } else {
++ copy = min(off + len, len1) - off;
++ memcpy(buf1 + off, src, copy);
++ src += copy;
++ len -= copy;
++ off = 0;
++ }
++ if (len > 0) {
++ if (WARN_ON_ONCE(off + len > len2 || !buf2))
++ return;
++ memcpy(buf2 + off, src, len);
++ }
++}
++
++static uint16_t udf_crc_fi_bufs(void *buf1, int len1, void *buf2, int len2,
++ int off, int len)
++{
++ int copy;
++ uint16_t crc = 0;
++
++ if (off >= len1) {
++ off -= len1;
++ } else {
++ copy = min(off + len, len1) - off;
++ crc = crc_itu_t(crc, buf1 + off, copy);
++ len -= copy;
++ off = 0;
++ }
++ if (len > 0) {
++ if (WARN_ON_ONCE(off + len > len2 || !buf2))
++ return 0;
++ crc = crc_itu_t(crc, buf2 + off, len);
++ }
++ return crc;
++}
++
++static void udf_copy_fi_to_bufs(char *buf1, int len1, char *buf2, int len2,
++ int off, struct fileIdentDesc *fi,
++ uint8_t *impuse, uint8_t *name)
++{
++ uint16_t crc;
++ int fioff = off;
++ int crcoff = off + sizeof(struct tag);
++ unsigned int crclen = udf_dir_entry_len(fi) - sizeof(struct tag);
++
++ udf_copy_to_bufs(buf1, len1, buf2, len2, off, fi,
++ sizeof(struct fileIdentDesc));
++ off += sizeof(struct fileIdentDesc);
++ if (impuse)
++ udf_copy_to_bufs(buf1, len1, buf2, len2, off, impuse,
++ le16_to_cpu(fi->lengthOfImpUse));
++ off += le16_to_cpu(fi->lengthOfImpUse);
++ if (name)
++ udf_copy_to_bufs(buf1, len1, buf2, len2, off, name,
++ fi->lengthFileIdent);
++
++ crc = udf_crc_fi_bufs(buf1, len1, buf2, len2, crcoff, crclen);
++ fi->descTag.descCRC = cpu_to_le16(crc);
++ fi->descTag.descCRCLength = cpu_to_le16(crclen);
++ fi->descTag.tagChecksum = udf_tag_checksum(&fi->descTag);
++
++ udf_copy_to_bufs(buf1, len1, buf2, len2, fioff, fi, sizeof(struct tag));
++}
++
++void udf_fiiter_write_fi(struct udf_fileident_iter *iter, uint8_t *impuse)
++{
++ struct udf_inode_info *iinfo = UDF_I(iter->dir);
++ void *buf1, *buf2 = NULL;
++ int len1, len2 = 0, off;
++ int blksize = 1 << iter->dir->i_blkbits;
++
++ off = iter->pos & (blksize - 1);
++ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
++ buf1 = iinfo->i_data + iinfo->i_lenEAttr;
++ len1 = iter->dir->i_size;
++ } else {
++ buf1 = iter->bh[0]->b_data;
++ len1 = blksize;
++ if (iter->bh[1]) {
++ buf2 = iter->bh[1]->b_data;
++ len2 = blksize;
++ }
++ }
++
++ udf_copy_fi_to_bufs(buf1, len1, buf2, len2, off, &iter->fi, impuse,
++ iter->name == iter->namebuf ? iter->name : NULL);
++
++ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
++ mark_inode_dirty(iter->dir);
++ } else {
++ mark_buffer_dirty_inode(iter->bh[0], iter->dir);
++ if (iter->bh[1])
++ mark_buffer_dirty_inode(iter->bh[1], iter->dir);
++ }
++ inode_inc_iversion(iter->dir);
++}
+
+ struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos,
+ struct udf_fileident_bh *fibh,
+--- a/fs/udf/udfdecl.h
++++ b/fs/udf/udfdecl.h
+@@ -86,6 +86,24 @@ extern const struct address_space_operat
+ extern const struct address_space_operations udf_adinicb_aops;
+ extern const struct address_space_operations udf_symlink_aops;
+
++struct udf_fileident_iter {
++ struct inode *dir; /* Directory we are working with */
++ loff_t pos; /* Logical position in a dir */
++ struct buffer_head *bh[2]; /* Buffer containing 'pos' and possibly
++ * next buffer if entry straddles
++ * blocks */
++ struct kernel_lb_addr eloc; /* Start of extent containing 'pos' */
++ uint32_t elen; /* Length of extent containing 'pos' */
++ sector_t loffset; /* Block offset of 'pos' within above
++ * extent */
++ struct extent_position epos; /* Position after the above extent */
++ struct fileIdentDesc fi; /* Copied directory entry */
++ uint8_t *name; /* Pointer to entry name */
++ uint8_t namebuf[UDF_NAME_LEN_CS0]; /* Storage for entry name in case
++ * the name is split between two blocks
++ */
++};
++
+ struct udf_fileident_bh {
+ struct buffer_head *sbh;
+ struct buffer_head *ebh;
+@@ -243,6 +261,11 @@ extern udf_pblk_t udf_new_block(struct s
+ uint16_t partition, uint32_t goal, int *err);
+
+ /* directory.c */
++int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir,
++ loff_t pos);
++int udf_fiiter_advance(struct udf_fileident_iter *iter);
++void udf_fiiter_release(struct udf_fileident_iter *iter);
++void udf_fiiter_write_fi(struct udf_fileident_iter *iter, uint8_t *impuse);
+ extern struct fileIdentDesc *udf_fileident_read(struct inode *, loff_t *,
+ struct udf_fileident_bh *,
+ struct fileIdentDesc *,
--- /dev/null
+From stable+bounces-86655-greg=kroah.com@vger.kernel.org Thu Oct 17 19:19:52 2024
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Date: Thu, 17 Oct 2024 14:19:01 -0300
+Subject: udf: Provide function to mark entry as deleted using new directory iteration code
+To: stable@vger.kernel.org
+Cc: Jan Kara <jack@suse.cz>, kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Message-ID: <20241017171915.311132-6-cascardo@igalia.com>
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit 4cca7e3df7bea8661a0c2a70c0d250e9aa5cedb4 ]
+
+Provide function udf_fiiter_delete_entry() to mark directory entry as
+deleted using new directory iteration code.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/namei.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/fs/udf/namei.c
++++ b/fs/udf/namei.c
+@@ -714,6 +714,16 @@ out_ok:
+ return fi;
+ }
+
++static void udf_fiiter_delete_entry(struct udf_fileident_iter *iter)
++{
++ iter->fi.fileCharacteristics |= FID_FILE_CHAR_DELETED;
++
++ if (UDF_QUERY_FLAG(iter->dir->i_sb, UDF_FLAG_STRICT))
++ memset(&iter->fi.icb, 0x00, sizeof(struct long_ad));
++
++ udf_fiiter_write_fi(iter, NULL);
++}
++
+ static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi,
+ struct udf_fileident_bh *fibh,
+ struct fileIdentDesc *cfi)
--- /dev/null
+From stable+bounces-86668-greg=kroah.com@vger.kernel.org Thu Oct 17 19:20:19 2024
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Date: Thu, 17 Oct 2024 14:19:13 -0300
+Subject: udf: Remove old directory iteration code
+To: stable@vger.kernel.org
+Cc: Jan Kara <jack@suse.cz>, kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Message-ID: <20241017171915.311132-18-cascardo@igalia.com>
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit 1e0290d61a870ed61a6510863029939bbf6b0006 ]
+
+Remove old directory iteration code that is now unused.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/directory.c | 178 ------------------
+ fs/udf/namei.c | 505 -----------------------------------------------------
+ fs/udf/udfdecl.h | 22 --
+ 3 files changed, 705 deletions(-)
+
+--- a/fs/udf/directory.c
++++ b/fs/udf/directory.c
+@@ -470,184 +470,6 @@ int udf_fiiter_append_blk(struct udf_fil
+ return 0;
+ }
+
+-struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos,
+- struct udf_fileident_bh *fibh,
+- struct fileIdentDesc *cfi,
+- struct extent_position *epos,
+- struct kernel_lb_addr *eloc, uint32_t *elen,
+- sector_t *offset)
+-{
+- struct fileIdentDesc *fi;
+- int i, num;
+- udf_pblk_t block;
+- struct buffer_head *tmp, *bha[16];
+- struct udf_inode_info *iinfo = UDF_I(dir);
+-
+- fibh->soffset = fibh->eoffset;
+-
+- if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+- fi = udf_get_fileident(iinfo->i_data -
+- (iinfo->i_efe ?
+- sizeof(struct extendedFileEntry) :
+- sizeof(struct fileEntry)),
+- dir->i_sb->s_blocksize,
+- &(fibh->eoffset));
+- if (!fi)
+- return NULL;
+-
+- *nf_pos += fibh->eoffset - fibh->soffset;
+-
+- memcpy((uint8_t *)cfi, (uint8_t *)fi,
+- sizeof(struct fileIdentDesc));
+-
+- return fi;
+- }
+-
+- if (fibh->eoffset == dir->i_sb->s_blocksize) {
+- uint32_t lextoffset = epos->offset;
+- unsigned char blocksize_bits = dir->i_sb->s_blocksize_bits;
+-
+- if (udf_next_aext(dir, epos, eloc, elen, 1) !=
+- (EXT_RECORDED_ALLOCATED >> 30))
+- return NULL;
+-
+- block = udf_get_lb_pblock(dir->i_sb, eloc, *offset);
+-
+- (*offset)++;
+-
+- if ((*offset << blocksize_bits) >= *elen)
+- *offset = 0;
+- else
+- epos->offset = lextoffset;
+-
+- brelse(fibh->sbh);
+- fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
+- if (!fibh->sbh)
+- return NULL;
+- fibh->soffset = fibh->eoffset = 0;
+-
+- if (!(*offset & ((16 >> (blocksize_bits - 9)) - 1))) {
+- i = 16 >> (blocksize_bits - 9);
+- if (i + *offset > (*elen >> blocksize_bits))
+- i = (*elen >> blocksize_bits)-*offset;
+- for (num = 0; i > 0; i--) {
+- block = udf_get_lb_pblock(dir->i_sb, eloc,
+- *offset + i);
+- tmp = udf_tgetblk(dir->i_sb, block);
+- if (tmp && !buffer_uptodate(tmp) &&
+- !buffer_locked(tmp))
+- bha[num++] = tmp;
+- else
+- brelse(tmp);
+- }
+- if (num) {
+- bh_readahead_batch(num, bha, REQ_RAHEAD);
+- for (i = 0; i < num; i++)
+- brelse(bha[i]);
+- }
+- }
+- } else if (fibh->sbh != fibh->ebh) {
+- brelse(fibh->sbh);
+- fibh->sbh = fibh->ebh;
+- }
+-
+- fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize,
+- &(fibh->eoffset));
+-
+- if (!fi)
+- return NULL;
+-
+- *nf_pos += fibh->eoffset - fibh->soffset;
+-
+- if (fibh->eoffset <= dir->i_sb->s_blocksize) {
+- memcpy((uint8_t *)cfi, (uint8_t *)fi,
+- sizeof(struct fileIdentDesc));
+- } else if (fibh->eoffset > dir->i_sb->s_blocksize) {
+- uint32_t lextoffset = epos->offset;
+-
+- if (udf_next_aext(dir, epos, eloc, elen, 1) !=
+- (EXT_RECORDED_ALLOCATED >> 30))
+- return NULL;
+-
+- block = udf_get_lb_pblock(dir->i_sb, eloc, *offset);
+-
+- (*offset)++;
+-
+- if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen)
+- *offset = 0;
+- else
+- epos->offset = lextoffset;
+-
+- fibh->soffset -= dir->i_sb->s_blocksize;
+- fibh->eoffset -= dir->i_sb->s_blocksize;
+-
+- fibh->ebh = udf_tread(dir->i_sb, block);
+- if (!fibh->ebh)
+- return NULL;
+-
+- if (sizeof(struct fileIdentDesc) > -fibh->soffset) {
+- int fi_len;
+-
+- memcpy((uint8_t *)cfi, (uint8_t *)fi, -fibh->soffset);
+- memcpy((uint8_t *)cfi - fibh->soffset,
+- fibh->ebh->b_data,
+- sizeof(struct fileIdentDesc) + fibh->soffset);
+-
+- fi_len = udf_dir_entry_len(cfi);
+- *nf_pos += fi_len - (fibh->eoffset - fibh->soffset);
+- fibh->eoffset = fibh->soffset + fi_len;
+- } else {
+- memcpy((uint8_t *)cfi, (uint8_t *)fi,
+- sizeof(struct fileIdentDesc));
+- }
+- }
+- /* Got last entry outside of dir size - fs is corrupted! */
+- if (*nf_pos > dir->i_size)
+- return NULL;
+- return fi;
+-}
+-
+-struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize, int *offset)
+-{
+- struct fileIdentDesc *fi;
+- int lengthThisIdent;
+- uint8_t *ptr;
+- int padlen;
+-
+- if ((!buffer) || (!offset)) {
+- udf_debug("invalidparms, buffer=%p, offset=%p\n",
+- buffer, offset);
+- return NULL;
+- }
+-
+- ptr = buffer;
+-
+- if ((*offset > 0) && (*offset < bufsize))
+- ptr += *offset;
+- fi = (struct fileIdentDesc *)ptr;
+- if (fi->descTag.tagIdent != cpu_to_le16(TAG_IDENT_FID)) {
+- udf_debug("0x%x != TAG_IDENT_FID\n",
+- le16_to_cpu(fi->descTag.tagIdent));
+- udf_debug("offset: %d sizeof: %lu bufsize: %d\n",
+- *offset, (unsigned long)sizeof(struct fileIdentDesc),
+- bufsize);
+- return NULL;
+- }
+- if ((*offset + sizeof(struct fileIdentDesc)) > bufsize)
+- lengthThisIdent = sizeof(struct fileIdentDesc);
+- else
+- lengthThisIdent = sizeof(struct fileIdentDesc) +
+- fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse);
+-
+- /* we need to figure padding, too! */
+- padlen = lengthThisIdent % UDF_NAME_PAD;
+- if (padlen)
+- lengthThisIdent += (UDF_NAME_PAD - padlen);
+- *offset = *offset + lengthThisIdent;
+-
+- return fi;
+-}
+-
+ struct short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, uint32_t *offset,
+ int inc)
+ {
+--- a/fs/udf/namei.c
++++ b/fs/udf/namei.c
+@@ -41,105 +41,6 @@ static inline int udf_match(int len1, co
+ return !memcmp(name1, name2, len1);
+ }
+
+-int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
+- struct fileIdentDesc *sfi, struct udf_fileident_bh *fibh,
+- uint8_t *impuse, uint8_t *fileident)
+-{
+- uint16_t crclen = fibh->eoffset - fibh->soffset - sizeof(struct tag);
+- uint16_t crc;
+- int offset;
+- uint16_t liu = le16_to_cpu(cfi->lengthOfImpUse);
+- uint8_t lfi = cfi->lengthFileIdent;
+- int padlen = fibh->eoffset - fibh->soffset - liu - lfi -
+- sizeof(struct fileIdentDesc);
+- int adinicb = 0;
+-
+- if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
+- adinicb = 1;
+-
+- offset = fibh->soffset + sizeof(struct fileIdentDesc);
+-
+- if (impuse) {
+- if (adinicb || (offset + liu < 0)) {
+- memcpy((uint8_t *)sfi->impUse, impuse, liu);
+- } else if (offset >= 0) {
+- memcpy(fibh->ebh->b_data + offset, impuse, liu);
+- } else {
+- memcpy((uint8_t *)sfi->impUse, impuse, -offset);
+- memcpy(fibh->ebh->b_data, impuse - offset,
+- liu + offset);
+- }
+- }
+-
+- offset += liu;
+-
+- if (fileident) {
+- if (adinicb || (offset + lfi < 0)) {
+- memcpy(sfi->impUse + liu, fileident, lfi);
+- } else if (offset >= 0) {
+- memcpy(fibh->ebh->b_data + offset, fileident, lfi);
+- } else {
+- memcpy(sfi->impUse + liu, fileident, -offset);
+- memcpy(fibh->ebh->b_data, fileident - offset,
+- lfi + offset);
+- }
+- }
+-
+- offset += lfi;
+-
+- if (adinicb || (offset + padlen < 0)) {
+- memset(sfi->impUse + liu + lfi, 0x00, padlen);
+- } else if (offset >= 0) {
+- memset(fibh->ebh->b_data + offset, 0x00, padlen);
+- } else {
+- memset(sfi->impUse + liu + lfi, 0x00, -offset);
+- memset(fibh->ebh->b_data, 0x00, padlen + offset);
+- }
+-
+- crc = crc_itu_t(0, (uint8_t *)cfi + sizeof(struct tag),
+- sizeof(struct fileIdentDesc) - sizeof(struct tag));
+-
+- if (fibh->sbh == fibh->ebh) {
+- crc = crc_itu_t(crc, (uint8_t *)sfi->impUse,
+- crclen + sizeof(struct tag) -
+- sizeof(struct fileIdentDesc));
+- } else if (sizeof(struct fileIdentDesc) >= -fibh->soffset) {
+- crc = crc_itu_t(crc, fibh->ebh->b_data +
+- sizeof(struct fileIdentDesc) +
+- fibh->soffset,
+- crclen + sizeof(struct tag) -
+- sizeof(struct fileIdentDesc));
+- } else {
+- crc = crc_itu_t(crc, (uint8_t *)sfi->impUse,
+- -fibh->soffset - sizeof(struct fileIdentDesc));
+- crc = crc_itu_t(crc, fibh->ebh->b_data, fibh->eoffset);
+- }
+-
+- cfi->descTag.descCRC = cpu_to_le16(crc);
+- cfi->descTag.descCRCLength = cpu_to_le16(crclen);
+- cfi->descTag.tagChecksum = udf_tag_checksum(&cfi->descTag);
+-
+- if (adinicb || (sizeof(struct fileIdentDesc) <= -fibh->soffset)) {
+- memcpy((uint8_t *)sfi, (uint8_t *)cfi,
+- sizeof(struct fileIdentDesc));
+- } else {
+- memcpy((uint8_t *)sfi, (uint8_t *)cfi, -fibh->soffset);
+- memcpy(fibh->ebh->b_data, (uint8_t *)cfi - fibh->soffset,
+- sizeof(struct fileIdentDesc) + fibh->soffset);
+- }
+-
+- if (adinicb) {
+- mark_inode_dirty(inode);
+- } else {
+- if (fibh->sbh != fibh->ebh)
+- mark_buffer_dirty_inode(fibh->ebh, inode);
+- mark_buffer_dirty_inode(fibh->sbh, inode);
+- }
+- inode_inc_iversion(inode);
+-
+- return 0;
+-}
+-
+ /**
+ * udf_fiiter_find_entry - find entry in given directory.
+ *
+@@ -207,161 +108,6 @@ out_ok:
+ return ret;
+ }
+
+-/**
+- * udf_find_entry - find entry in given directory.
+- *
+- * @dir: directory inode to search in
+- * @child: qstr of the name
+- * @fibh: buffer head / inode with file identifier descriptor we found
+- * @cfi: found file identifier descriptor with given name
+- *
+- * This function searches in the directory @dir for a file name @child. When
+- * found, @fibh points to the buffer head(s) (bh is NULL for in ICB
+- * directories) containing the file identifier descriptor (FID). In that case
+- * the function returns pointer to the FID in the buffer or inode - but note
+- * that FID may be split among two buffers (blocks) so accessing it via that
+- * pointer isn't easily possible. This pointer can be used only as an iterator
+- * for other directory manipulation functions. For inspection of the FID @cfi
+- * can be used - the found FID is copied there.
+- *
+- * Returns pointer to FID, NULL when nothing found, or error code.
+- */
+-static struct fileIdentDesc *udf_find_entry(struct inode *dir,
+- const struct qstr *child,
+- struct udf_fileident_bh *fibh,
+- struct fileIdentDesc *cfi)
+-{
+- struct fileIdentDesc *fi = NULL;
+- loff_t f_pos;
+- udf_pblk_t block;
+- int flen;
+- unsigned char *fname = NULL, *copy_name = NULL;
+- unsigned char *nameptr;
+- uint8_t lfi;
+- uint16_t liu;
+- loff_t size;
+- struct kernel_lb_addr eloc;
+- uint32_t elen;
+- sector_t offset;
+- struct extent_position epos = {};
+- struct udf_inode_info *dinfo = UDF_I(dir);
+- int isdotdot = child->len == 2 &&
+- child->name[0] == '.' && child->name[1] == '.';
+- struct super_block *sb = dir->i_sb;
+-
+- size = udf_ext0_offset(dir) + dir->i_size;
+- f_pos = udf_ext0_offset(dir);
+-
+- fibh->sbh = fibh->ebh = NULL;
+- fibh->soffset = fibh->eoffset = f_pos & (sb->s_blocksize - 1);
+- if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+- if (inode_bmap(dir, f_pos >> sb->s_blocksize_bits, &epos,
+- &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) {
+- fi = ERR_PTR(-EIO);
+- goto out_err;
+- }
+-
+- block = udf_get_lb_pblock(sb, &eloc, offset);
+- if ((++offset << sb->s_blocksize_bits) < elen) {
+- if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+- epos.offset -= sizeof(struct short_ad);
+- else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+- epos.offset -= sizeof(struct long_ad);
+- } else
+- offset = 0;
+-
+- fibh->sbh = fibh->ebh = udf_tread(sb, block);
+- if (!fibh->sbh) {
+- fi = ERR_PTR(-EIO);
+- goto out_err;
+- }
+- }
+-
+- fname = kmalloc(UDF_NAME_LEN, GFP_NOFS);
+- if (!fname) {
+- fi = ERR_PTR(-ENOMEM);
+- goto out_err;
+- }
+-
+- while (f_pos < size) {
+- fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc,
+- &elen, &offset);
+- if (!fi) {
+- fi = ERR_PTR(-EIO);
+- goto out_err;
+- }
+-
+- liu = le16_to_cpu(cfi->lengthOfImpUse);
+- lfi = cfi->lengthFileIdent;
+-
+- if (fibh->sbh == fibh->ebh) {
+- nameptr = udf_get_fi_ident(fi);
+- } else {
+- int poffset; /* Unpaded ending offset */
+-
+- poffset = fibh->soffset + sizeof(struct fileIdentDesc) +
+- liu + lfi;
+-
+- if (poffset >= lfi)
+- nameptr = (uint8_t *)(fibh->ebh->b_data +
+- poffset - lfi);
+- else {
+- if (!copy_name) {
+- copy_name = kmalloc(UDF_NAME_LEN_CS0,
+- GFP_NOFS);
+- if (!copy_name) {
+- fi = ERR_PTR(-ENOMEM);
+- goto out_err;
+- }
+- }
+- nameptr = copy_name;
+- memcpy(nameptr, udf_get_fi_ident(fi),
+- lfi - poffset);
+- memcpy(nameptr + lfi - poffset,
+- fibh->ebh->b_data, poffset);
+- }
+- }
+-
+- if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
+- if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE))
+- continue;
+- }
+-
+- if ((cfi->fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) {
+- if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE))
+- continue;
+- }
+-
+- if ((cfi->fileCharacteristics & FID_FILE_CHAR_PARENT) &&
+- isdotdot)
+- goto out_ok;
+-
+- if (!lfi)
+- continue;
+-
+- flen = udf_get_filename(sb, nameptr, lfi, fname, UDF_NAME_LEN);
+- if (flen < 0) {
+- fi = ERR_PTR(flen);
+- goto out_err;
+- }
+-
+- if (udf_match(flen, fname, child->len, child->name))
+- goto out_ok;
+- }
+-
+- fi = NULL;
+-out_err:
+- if (fibh->sbh != fibh->ebh)
+- brelse(fibh->ebh);
+- brelse(fibh->sbh);
+-out_ok:
+- brelse(epos.bh);
+- kfree(fname);
+- kfree(copy_name);
+-
+- return fi;
+-}
+-
+ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
+ {
+@@ -582,245 +328,6 @@ store_fi:
+ return 0;
+ }
+
+-static struct fileIdentDesc *udf_add_entry(struct inode *dir,
+- struct dentry *dentry,
+- struct udf_fileident_bh *fibh,
+- struct fileIdentDesc *cfi, int *err)
+-{
+- struct super_block *sb = dir->i_sb;
+- struct fileIdentDesc *fi = NULL;
+- unsigned char *name = NULL;
+- int namelen;
+- loff_t f_pos;
+- loff_t size = udf_ext0_offset(dir) + dir->i_size;
+- int nfidlen;
+- udf_pblk_t block;
+- struct kernel_lb_addr eloc;
+- uint32_t elen = 0;
+- sector_t offset;
+- struct extent_position epos = {};
+- struct udf_inode_info *dinfo;
+-
+- fibh->sbh = fibh->ebh = NULL;
+- name = kmalloc(UDF_NAME_LEN_CS0, GFP_NOFS);
+- if (!name) {
+- *err = -ENOMEM;
+- goto out_err;
+- }
+-
+- if (dentry) {
+- if (!dentry->d_name.len) {
+- *err = -EINVAL;
+- goto out_err;
+- }
+- namelen = udf_put_filename(sb, dentry->d_name.name,
+- dentry->d_name.len,
+- name, UDF_NAME_LEN_CS0);
+- if (!namelen) {
+- *err = -ENAMETOOLONG;
+- goto out_err;
+- }
+- } else {
+- namelen = 0;
+- }
+-
+- nfidlen = ALIGN(sizeof(struct fileIdentDesc) + namelen, UDF_NAME_PAD);
+-
+- f_pos = udf_ext0_offset(dir);
+-
+- fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1);
+- dinfo = UDF_I(dir);
+- if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+- if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos,
+- &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) {
+- block = udf_get_lb_pblock(dir->i_sb,
+- &dinfo->i_location, 0);
+- fibh->soffset = fibh->eoffset = sb->s_blocksize;
+- goto add;
+- }
+- block = udf_get_lb_pblock(dir->i_sb, &eloc, offset);
+- if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
+- if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+- epos.offset -= sizeof(struct short_ad);
+- else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+- epos.offset -= sizeof(struct long_ad);
+- } else
+- offset = 0;
+-
+- fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
+- if (!fibh->sbh) {
+- *err = -EIO;
+- goto out_err;
+- }
+-
+- block = dinfo->i_location.logicalBlockNum;
+- }
+-
+- while (f_pos < size) {
+- fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc,
+- &elen, &offset);
+-
+- if (!fi) {
+- *err = -EIO;
+- goto out_err;
+- }
+-
+- if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
+- if (udf_dir_entry_len(cfi) == nfidlen) {
+- cfi->descTag.tagSerialNum = cpu_to_le16(1);
+- cfi->fileVersionNum = cpu_to_le16(1);
+- cfi->fileCharacteristics = 0;
+- cfi->lengthFileIdent = namelen;
+- cfi->lengthOfImpUse = cpu_to_le16(0);
+- if (!udf_write_fi(dir, cfi, fi, fibh, NULL,
+- name))
+- goto out_ok;
+- else {
+- *err = -EIO;
+- goto out_err;
+- }
+- }
+- }
+- }
+-
+-add:
+- f_pos += nfidlen;
+-
+- if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB &&
+- sb->s_blocksize - fibh->eoffset < nfidlen) {
+- brelse(epos.bh);
+- epos.bh = NULL;
+- fibh->soffset -= udf_ext0_offset(dir);
+- fibh->eoffset -= udf_ext0_offset(dir);
+- f_pos -= udf_ext0_offset(dir);
+- if (fibh->sbh != fibh->ebh)
+- brelse(fibh->ebh);
+- brelse(fibh->sbh);
+- fibh->sbh = fibh->ebh =
+- udf_expand_dir_adinicb(dir, &block, err);
+- if (!fibh->sbh)
+- goto out_err;
+- epos.block = dinfo->i_location;
+- epos.offset = udf_file_entry_alloc_offset(dir);
+- /* Load extent udf_expand_dir_adinicb() has created */
+- udf_current_aext(dir, &epos, &eloc, &elen, 1);
+- }
+-
+- /* Entry fits into current block? */
+- if (sb->s_blocksize - fibh->eoffset >= nfidlen) {
+- fibh->soffset = fibh->eoffset;
+- fibh->eoffset += nfidlen;
+- if (fibh->sbh != fibh->ebh) {
+- brelse(fibh->sbh);
+- fibh->sbh = fibh->ebh;
+- }
+-
+- if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+- block = dinfo->i_location.logicalBlockNum;
+- fi = (struct fileIdentDesc *)
+- (dinfo->i_data + fibh->soffset -
+- udf_ext0_offset(dir) +
+- dinfo->i_lenEAttr);
+- } else {
+- block = eloc.logicalBlockNum +
+- ((elen - 1) >>
+- dir->i_sb->s_blocksize_bits);
+- fi = (struct fileIdentDesc *)
+- (fibh->sbh->b_data + fibh->soffset);
+- }
+- } else {
+- /* Round up last extent in the file */
+- elen = (elen + sb->s_blocksize - 1) & ~(sb->s_blocksize - 1);
+- if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+- epos.offset -= sizeof(struct short_ad);
+- else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+- epos.offset -= sizeof(struct long_ad);
+- udf_write_aext(dir, &epos, &eloc, elen, 1);
+- dinfo->i_lenExtents = (dinfo->i_lenExtents + sb->s_blocksize
+- - 1) & ~(sb->s_blocksize - 1);
+-
+- fibh->soffset = fibh->eoffset - sb->s_blocksize;
+- fibh->eoffset += nfidlen - sb->s_blocksize;
+- if (fibh->sbh != fibh->ebh) {
+- brelse(fibh->sbh);
+- fibh->sbh = fibh->ebh;
+- }
+-
+- block = eloc.logicalBlockNum + ((elen - 1) >>
+- dir->i_sb->s_blocksize_bits);
+- fibh->ebh = udf_bread(dir,
+- f_pos >> dir->i_sb->s_blocksize_bits, 1, err);
+- if (!fibh->ebh)
+- goto out_err;
+- /* Extents could have been merged, invalidate our position */
+- brelse(epos.bh);
+- epos.bh = NULL;
+- epos.block = dinfo->i_location;
+- epos.offset = udf_file_entry_alloc_offset(dir);
+-
+- if (!fibh->soffset) {
+- /* Find the freshly allocated block */
+- while (udf_next_aext(dir, &epos, &eloc, &elen, 1) ==
+- (EXT_RECORDED_ALLOCATED >> 30))
+- ;
+- block = eloc.logicalBlockNum + ((elen - 1) >>
+- dir->i_sb->s_blocksize_bits);
+- brelse(fibh->sbh);
+- fibh->sbh = fibh->ebh;
+- fi = (struct fileIdentDesc *)(fibh->sbh->b_data);
+- } else {
+- fi = (struct fileIdentDesc *)
+- (fibh->sbh->b_data + sb->s_blocksize +
+- fibh->soffset);
+- }
+- }
+-
+- memset(cfi, 0, sizeof(struct fileIdentDesc));
+- if (UDF_SB(sb)->s_udfrev >= 0x0200)
+- udf_new_tag((char *)cfi, TAG_IDENT_FID, 3, 1, block,
+- sizeof(struct tag));
+- else
+- udf_new_tag((char *)cfi, TAG_IDENT_FID, 2, 1, block,
+- sizeof(struct tag));
+- cfi->fileVersionNum = cpu_to_le16(1);
+- cfi->lengthFileIdent = namelen;
+- cfi->lengthOfImpUse = cpu_to_le16(0);
+- if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) {
+- dir->i_size += nfidlen;
+- if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
+- dinfo->i_lenAlloc += nfidlen;
+- else {
+- /* Find the last extent and truncate it to proper size */
+- while (udf_next_aext(dir, &epos, &eloc, &elen, 1) ==
+- (EXT_RECORDED_ALLOCATED >> 30))
+- ;
+- elen -= dinfo->i_lenExtents - dir->i_size;
+- if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+- epos.offset -= sizeof(struct short_ad);
+- else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+- epos.offset -= sizeof(struct long_ad);
+- udf_write_aext(dir, &epos, &eloc, elen, 1);
+- dinfo->i_lenExtents = dir->i_size;
+- }
+-
+- mark_inode_dirty(dir);
+- goto out_ok;
+- } else {
+- *err = -EIO;
+- goto out_err;
+- }
+-
+-out_err:
+- fi = NULL;
+- if (fibh->sbh != fibh->ebh)
+- brelse(fibh->ebh);
+- brelse(fibh->sbh);
+-out_ok:
+- brelse(epos.bh);
+- kfree(name);
+- return fi;
+-}
+-
+ static void udf_fiiter_delete_entry(struct udf_fileident_iter *iter)
+ {
+ iter->fi.fileCharacteristics |= FID_FILE_CHAR_DELETED;
+@@ -831,18 +338,6 @@ static void udf_fiiter_delete_entry(stru
+ udf_fiiter_write_fi(iter, NULL);
+ }
+
+-static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi,
+- struct udf_fileident_bh *fibh,
+- struct fileIdentDesc *cfi)
+-{
+- cfi->fileCharacteristics |= FID_FILE_CHAR_DELETED;
+-
+- if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
+- memset(&(cfi->icb), 0x00, sizeof(struct long_ad));
+-
+- return udf_write_fi(inode, cfi, fi, fibh, NULL, NULL);
+-}
+-
+ static int udf_add_nondir(struct dentry *dentry, struct inode *inode)
+ {
+ struct udf_inode_info *iinfo = UDF_I(inode);
+--- a/fs/udf/udfdecl.h
++++ b/fs/udf/udfdecl.h
+@@ -104,13 +104,6 @@ struct udf_fileident_iter {
+ */
+ };
+
+-struct udf_fileident_bh {
+- struct buffer_head *sbh;
+- struct buffer_head *ebh;
+- int soffset;
+- int eoffset;
+-};
+-
+ struct udf_vds_record {
+ uint32_t block;
+ uint32_t volDescSeqNum;
+@@ -139,19 +132,12 @@ struct inode *udf_find_metadata_inode_ef
+ u32 meta_file_loc, u32 partition_num);
+
+ /* namei.c */
+-extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *,
+- struct fileIdentDesc *, struct udf_fileident_bh *,
+- uint8_t *, uint8_t *);
+ static inline unsigned int udf_dir_entry_len(struct fileIdentDesc *cfi)
+ {
+ return ALIGN(sizeof(struct fileIdentDesc) +
+ le16_to_cpu(cfi->lengthOfImpUse) + cfi->lengthFileIdent,
+ UDF_NAME_PAD);
+ }
+-static inline uint8_t *udf_get_fi_ident(struct fileIdentDesc *fi)
+-{
+- return ((uint8_t *)(fi + 1)) + le16_to_cpu(fi->lengthOfImpUse);
+-}
+
+ /* file.c */
+ extern long udf_ioctl(struct file *, unsigned int, unsigned long);
+@@ -266,14 +252,6 @@ void udf_fiiter_release(struct udf_filei
+ void udf_fiiter_write_fi(struct udf_fileident_iter *iter, uint8_t *impuse);
+ void udf_fiiter_update_elen(struct udf_fileident_iter *iter, uint32_t new_elen);
+ int udf_fiiter_append_blk(struct udf_fileident_iter *iter);
+-extern struct fileIdentDesc *udf_fileident_read(struct inode *, loff_t *,
+- struct udf_fileident_bh *,
+- struct fileIdentDesc *,
+- struct extent_position *,
+- struct kernel_lb_addr *, uint32_t *,
+- sector_t *);
+-extern struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize,
+- int *offset);
+ extern struct long_ad *udf_get_filelongad(uint8_t *, int, uint32_t *, int);
+ extern struct short_ad *udf_get_fileshortad(uint8_t *, int, uint32_t *, int);
+