]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.1-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 18 Oct 2024 06:41:25 +0000 (08:41 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 18 Oct 2024 06:41:25 +0000 (08:41 +0200)
added patches:
udf-convert-empty_dir-to-new-directory-iteration-code.patch
udf-convert-udf_add_nondir-to-new-directory-iteration.patch
udf-convert-udf_expand_dir_adinicb-to-new-directory-iteration.patch
udf-convert-udf_get_parent-to-new-directory-iteration-code.patch
udf-convert-udf_link-to-new-directory-iteration-code.patch
udf-convert-udf_lookup-to-use-new-directory-iteration-code.patch
udf-convert-udf_mkdir-to-new-directory-iteration-code.patch
udf-convert-udf_readdir-to-new-directory-iteration.patch
udf-convert-udf_rename-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-don-t-return-bh-from-udf_expand_dir_adinicb.patch
udf-handle-error-when-expanding-directory.patch
udf-implement-adding-of-dir-entries-using-new-iteration-code.patch
udf-implement-searching-for-directory-entry-using-new-iteration-code.patch
udf-move-udf_expand_dir_adinicb-to-its-callsite.patch
udf-new-directory-iteration-code.patch
udf-provide-function-to-mark-entry-as-deleted-using-new-directory-iteration-code.patch
udf-remove-old-directory-iteration-code.patch

20 files changed:
queue-6.1/series
queue-6.1/udf-convert-empty_dir-to-new-directory-iteration-code.patch [new file with mode: 0644]
queue-6.1/udf-convert-udf_add_nondir-to-new-directory-iteration.patch [new file with mode: 0644]
queue-6.1/udf-convert-udf_expand_dir_adinicb-to-new-directory-iteration.patch [new file with mode: 0644]
queue-6.1/udf-convert-udf_get_parent-to-new-directory-iteration-code.patch [new file with mode: 0644]
queue-6.1/udf-convert-udf_link-to-new-directory-iteration-code.patch [new file with mode: 0644]
queue-6.1/udf-convert-udf_lookup-to-use-new-directory-iteration-code.patch [new file with mode: 0644]
queue-6.1/udf-convert-udf_mkdir-to-new-directory-iteration-code.patch [new file with mode: 0644]
queue-6.1/udf-convert-udf_readdir-to-new-directory-iteration.patch [new file with mode: 0644]
queue-6.1/udf-convert-udf_rename-to-new-directory-iteration-code.patch [new file with mode: 0644]
queue-6.1/udf-convert-udf_rmdir-to-new-directory-iteration-code.patch [new file with mode: 0644]
queue-6.1/udf-convert-udf_unlink-to-new-directory-iteration-code.patch [new file with mode: 0644]
queue-6.1/udf-don-t-return-bh-from-udf_expand_dir_adinicb.patch [new file with mode: 0644]
queue-6.1/udf-handle-error-when-expanding-directory.patch [new file with mode: 0644]
queue-6.1/udf-implement-adding-of-dir-entries-using-new-iteration-code.patch [new file with mode: 0644]
queue-6.1/udf-implement-searching-for-directory-entry-using-new-iteration-code.patch [new file with mode: 0644]
queue-6.1/udf-move-udf_expand_dir_adinicb-to-its-callsite.patch [new file with mode: 0644]
queue-6.1/udf-new-directory-iteration-code.patch [new file with mode: 0644]
queue-6.1/udf-provide-function-to-mark-entry-as-deleted-using-new-directory-iteration-code.patch [new file with mode: 0644]
queue-6.1/udf-remove-old-directory-iteration-code.patch [new file with mode: 0644]

index b2b2936c99c22a981b399d8f88142df54030a907..8b1cf985cf2087029498dd4b9f67368ea388a450 100644 (file)
@@ -3,3 +3,22 @@ btrfs-fix-uninitialized-pointer-free-on-read_alloc_one_name-error.patch
 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
diff --git a/queue-6.1/udf-convert-empty_dir-to-new-directory-iteration-code.patch b/queue-6.1/udf-convert-empty_dir-to-new-directory-iteration-code.patch
new file mode 100644 (file)
index 0000000..fa816ad
--- /dev/null
@@ -0,0 +1,102 @@
+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;
+ }
diff --git a/queue-6.1/udf-convert-udf_add_nondir-to-new-directory-iteration.patch b/queue-6.1/udf-convert-udf_add_nondir-to-new-directory-iteration.patch
new file mode 100644 (file)
index 0000000..2e89c16
--- /dev/null
@@ -0,0 +1,58 @@
+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;
diff --git a/queue-6.1/udf-convert-udf_expand_dir_adinicb-to-new-directory-iteration.patch b/queue-6.1/udf-convert-udf_expand_dir_adinicb-to-new-directory-iteration.patch
new file mode 100644 (file)
index 0000000..d506107
--- /dev/null
@@ -0,0 +1,117 @@
+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;
+ }
diff --git a/queue-6.1/udf-convert-udf_get_parent-to-new-directory-iteration-code.patch b/queue-6.1/udf-convert-udf_get_parent-to-new-directory-iteration-code.patch
new file mode 100644 (file)
index 0000000..f2b8bed
--- /dev/null
@@ -0,0 +1,48 @@
+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);
diff --git a/queue-6.1/udf-convert-udf_link-to-new-directory-iteration-code.patch b/queue-6.1/udf-convert-udf_link-to-new-directory-iteration-code.patch
new file mode 100644 (file)
index 0000000..37585d5
--- /dev/null
@@ -0,0 +1,60 @@
+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);
diff --git a/queue-6.1/udf-convert-udf_lookup-to-use-new-directory-iteration-code.patch b/queue-6.1/udf-convert-udf_lookup-to-use-new-directory-iteration-code.patch
new file mode 100644 (file)
index 0000000..017900a
--- /dev/null
@@ -0,0 +1,58 @@
+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);
diff --git a/queue-6.1/udf-convert-udf_mkdir-to-new-directory-iteration-code.patch b/queue-6.1/udf-convert-udf_mkdir-to-new-directory-iteration-code.patch
new file mode 100644 (file)
index 0000000..cb5c710
--- /dev/null
@@ -0,0 +1,101 @@
+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)
diff --git a/queue-6.1/udf-convert-udf_readdir-to-new-directory-iteration.patch b/queue-6.1/udf-convert-udf_readdir-to-new-directory-iteration.patch
new file mode 100644 (file)
index 0000000..8e0a61e
--- /dev/null
@@ -0,0 +1,224 @@
+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;
+ }
diff --git a/queue-6.1/udf-convert-udf_rename-to-new-directory-iteration-code.patch b/queue-6.1/udf-convert-udf_rename-to-new-directory-iteration-code.patch
new file mode 100644 (file)
index 0000000..d208c2d
--- /dev/null
@@ -0,0 +1,235 @@
+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;
+ }
diff --git a/queue-6.1/udf-convert-udf_rmdir-to-new-directory-iteration-code.patch b/queue-6.1/udf-convert-udf_rmdir-to-new-directory-iteration-code.patch
new file mode 100644 (file)
index 0000000..ba1a8ce
--- /dev/null
@@ -0,0 +1,80 @@
+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)
diff --git a/queue-6.1/udf-convert-udf_unlink-to-new-directory-iteration-code.patch b/queue-6.1/udf-convert-udf_unlink-to-new-directory-iteration-code.patch
new file mode 100644 (file)
index 0000000..3ce9fd9
--- /dev/null
@@ -0,0 +1,81 @@
+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,
diff --git a/queue-6.1/udf-don-t-return-bh-from-udf_expand_dir_adinicb.patch b/queue-6.1/udf-don-t-return-bh-from-udf_expand_dir_adinicb.patch
new file mode 100644 (file)
index 0000000..253a230
--- /dev/null
@@ -0,0 +1,114 @@
+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;
diff --git a/queue-6.1/udf-handle-error-when-expanding-directory.patch b/queue-6.1/udf-handle-error-when-expanding-directory.patch
new file mode 100644 (file)
index 0000000..1c49349
--- /dev/null
@@ -0,0 +1,40 @@
+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 */
diff --git a/queue-6.1/udf-implement-adding-of-dir-entries-using-new-iteration-code.patch b/queue-6.1/udf-implement-adding-of-dir-entries-using-new-iteration-code.patch
new file mode 100644 (file)
index 0000000..1b31d2d
--- /dev/null
@@ -0,0 +1,220 @@
+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 *,
diff --git a/queue-6.1/udf-implement-searching-for-directory-entry-using-new-iteration-code.patch b/queue-6.1/udf-implement-searching-for-directory-entry-using-new-iteration-code.patch
new file mode 100644 (file)
index 0000000..6d23886
--- /dev/null
@@ -0,0 +1,99 @@
+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
diff --git a/queue-6.1/udf-move-udf_expand_dir_adinicb-to-its-callsite.patch b/queue-6.1/udf-move-udf_expand_dir_adinicb-to-its-callsite.patch
new file mode 100644 (file)
index 0000000..b24cf47
--- /dev/null
@@ -0,0 +1,218 @@
+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);
diff --git a/queue-6.1/udf-new-directory-iteration-code.patch b/queue-6.1/udf-new-directory-iteration-code.patch
new file mode 100644 (file)
index 0000000..42797f7
--- /dev/null
@@ -0,0 +1,467 @@
+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 *,
diff --git a/queue-6.1/udf-provide-function-to-mark-entry-as-deleted-using-new-directory-iteration-code.patch b/queue-6.1/udf-provide-function-to-mark-entry-as-deleted-using-new-directory-iteration-code.patch
new file mode 100644 (file)
index 0000000..5015641
--- /dev/null
@@ -0,0 +1,41 @@
+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)
diff --git a/queue-6.1/udf-remove-old-directory-iteration-code.patch b/queue-6.1/udf-remove-old-directory-iteration-code.patch
new file mode 100644 (file)
index 0000000..e165660
--- /dev/null
@@ -0,0 +1,796 @@
+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);