From: Greg Kroah-Hartman Date: Fri, 18 Oct 2024 06:43:43 +0000 (+0200) Subject: 5.15-stable patches X-Git-Tag: v5.10.228~76 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e8d24253fae173b29b8bab42011f949105bdd93b;p=thirdparty%2Fkernel%2Fstable-queue.git 5.15-stable patches 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-fix-bogus-checksum-computation-in-udf_rename.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 --- diff --git a/queue-5.15/series b/queue-5.15/series index 16d8fe2a4b4..0dfbf1d3c24 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -1 +1,21 @@ alsa-hda-conexant-fix-audio-routing-for-hp-eliteone-1000-g2.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 +udf-fix-bogus-checksum-computation-in-udf_rename.patch diff --git a/queue-5.15/udf-convert-empty_dir-to-new-directory-iteration-code.patch b/queue-5.15/udf-convert-empty_dir-to-new-directory-iteration-code.patch new file mode 100644 index 00000000000..3848d4ac5b5 --- /dev/null +++ b/queue-5.15/udf-convert-empty_dir-to-new-directory-iteration-code.patch @@ -0,0 +1,102 @@ +From stable+bounces-86699-greg=kroah.com@vger.kernel.org Thu Oct 17 22:20:52 2024 +From: Thadeu Lima de Souza Cascardo +Date: Thu, 17 Oct 2024 17:19:52 -0300 +Subject: udf: Convert empty_dir() to new directory iteration code +To: stable@vger.kernel.org +Cc: Jan Kara , kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo +Message-ID: <20241017202002.406428-11-cascardo@igalia.com> + +From: Jan Kara + +[ Upstream commit afb525f466f9fdc140b975221cb43fbb5c59314e ] + +Convert empty_dir() to new directory iteration code. + +Signed-off-by: Jan Kara +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + 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-5.15/udf-convert-udf_add_nondir-to-new-directory-iteration.patch b/queue-5.15/udf-convert-udf_add_nondir-to-new-directory-iteration.patch new file mode 100644 index 00000000000..18290578388 --- /dev/null +++ b/queue-5.15/udf-convert-udf_add_nondir-to-new-directory-iteration.patch @@ -0,0 +1,58 @@ +From stable+bounces-86703-greg=kroah.com@vger.kernel.org Thu Oct 17 22:20:56 2024 +From: Thadeu Lima de Souza Cascardo +Date: Thu, 17 Oct 2024 17:19:56 -0300 +Subject: udf: Convert udf_add_nondir() to new directory iteration +To: stable@vger.kernel.org +Cc: Jan Kara , kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo +Message-ID: <20241017202002.406428-15-cascardo@igalia.com> + +From: Jan Kara + +[ Upstream commit ef91f9998bece00cf7f82ad26177f910a7124b25 ] + +Convert udf_add_nondir() to new directory iteration code. + +Signed-off-by: Jan Kara +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + 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-5.15/udf-convert-udf_expand_dir_adinicb-to-new-directory-iteration.patch b/queue-5.15/udf-convert-udf_expand_dir_adinicb-to-new-directory-iteration.patch new file mode 100644 index 00000000000..fe850cc65c9 --- /dev/null +++ b/queue-5.15/udf-convert-udf_expand_dir_adinicb-to-new-directory-iteration.patch @@ -0,0 +1,117 @@ +From stable+bounces-86691-greg=kroah.com@vger.kernel.org Thu Oct 17 22:20:35 2024 +From: Thadeu Lima de Souza Cascardo +Date: Thu, 17 Oct 2024 17:19:44 -0300 +Subject: udf: Convert udf_expand_dir_adinicb() to new directory iteration +To: stable@vger.kernel.org +Cc: Jan Kara , kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo +Message-ID: <20241017202002.406428-3-cascardo@igalia.com> + +From: Jan Kara + +[ Upstream commit 57bda9fb169d689bff4108265a897d324b5fb8c3 ] + +Convert udf_expand_dir_adinicb() to new directory iteration code. + +Signed-off-by: Jan Kara +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + fs/udf/inode.c | 66 +++++++++++++++++++++++++-------------------------------- + 1 file changed, 29 insertions(+), 37 deletions(-) + +--- a/fs/udf/inode.c ++++ b/fs/udf/inode.c +@@ -330,14 +330,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; +@@ -365,38 +363,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; +@@ -407,10 +381,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-5.15/udf-convert-udf_get_parent-to-new-directory-iteration-code.patch b/queue-5.15/udf-convert-udf_get_parent-to-new-directory-iteration-code.patch new file mode 100644 index 00000000000..2a06261a558 --- /dev/null +++ b/queue-5.15/udf-convert-udf_get_parent-to-new-directory-iteration-code.patch @@ -0,0 +1,48 @@ +From stable+bounces-86697-greg=kroah.com@vger.kernel.org Thu Oct 17 22:20:49 2024 +From: Thadeu Lima de Souza Cascardo +Date: Thu, 17 Oct 2024 17:19:51 -0300 +Subject: udf: Convert udf_get_parent() to new directory iteration code +To: stable@vger.kernel.org +Cc: Jan Kara , kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo +Message-ID: <20241017202002.406428-10-cascardo@igalia.com> + +From: Jan Kara + +[ Upstream commit 9b06fbef4202363d74bba5459ddd231db6d3b1af ] + +Convert udf_get_parent() to use udf_fiiter_find_entry(). + +Signed-off-by: Jan Kara +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + fs/udf/namei.c | 16 +++++++--------- + 1 file changed, 7 insertions(+), 9 deletions(-) + +--- a/fs/udf/namei.c ++++ b/fs/udf/namei.c +@@ -1368,17 +1368,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-5.15/udf-convert-udf_link-to-new-directory-iteration-code.patch b/queue-5.15/udf-convert-udf_link-to-new-directory-iteration-code.patch new file mode 100644 index 00000000000..4cfd64b4ba8 --- /dev/null +++ b/queue-5.15/udf-convert-udf_link-to-new-directory-iteration-code.patch @@ -0,0 +1,60 @@ +From stable+bounces-86705-greg=kroah.com@vger.kernel.org Thu Oct 17 22:21:00 2024 +From: Thadeu Lima de Souza Cascardo +Date: Thu, 17 Oct 2024 17:19:58 -0300 +Subject: udf: Convert udf_link() to new directory iteration code +To: stable@vger.kernel.org +Cc: Jan Kara , kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo +Message-ID: <20241017202002.406428-17-cascardo@igalia.com> + +From: Jan Kara + +[ Upstream commit dbfb102d16fb780c84f41adbaeb7eac907c415dc ] + +Convert udf_link() to use new directory iteration code for adding entry +into the directory. + +Signed-off-by: Jan Kara +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + 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-5.15/udf-convert-udf_lookup-to-use-new-directory-iteration-code.patch b/queue-5.15/udf-convert-udf_lookup-to-use-new-directory-iteration-code.patch new file mode 100644 index 00000000000..d30f15370e9 --- /dev/null +++ b/queue-5.15/udf-convert-udf_lookup-to-use-new-directory-iteration-code.patch @@ -0,0 +1,58 @@ +From stable+bounces-86698-greg=kroah.com@vger.kernel.org Thu Oct 17 22:20:51 2024 +From: Thadeu Lima de Souza Cascardo +Date: Thu, 17 Oct 2024 17:19:50 -0300 +Subject: udf: Convert udf_lookup() to use new directory iteration code +To: stable@vger.kernel.org +Cc: Jan Kara , kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo +Message-ID: <20241017202002.406428-9-cascardo@igalia.com> + +From: Jan Kara + +[ Upstream commit 200918b34d158cdaee531db7e0c80b92c57e66f1 ] + +Convert udf_lookup() to use udf_fiiter_find_entry() for looking up +directory entries. + +Signed-off-by: Jan Kara +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + 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-5.15/udf-convert-udf_mkdir-to-new-directory-iteration-code.patch b/queue-5.15/udf-convert-udf_mkdir-to-new-directory-iteration-code.patch new file mode 100644 index 00000000000..36cc190ead4 --- /dev/null +++ b/queue-5.15/udf-convert-udf_mkdir-to-new-directory-iteration-code.patch @@ -0,0 +1,101 @@ +From stable+bounces-86704-greg=kroah.com@vger.kernel.org Thu Oct 17 22:20:55 2024 +From: Thadeu Lima de Souza Cascardo +Date: Thu, 17 Oct 2024 17:19:57 -0300 +Subject: udf: Convert udf_mkdir() to new directory iteration code +To: stable@vger.kernel.org +Cc: Jan Kara , kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo +Message-ID: <20241017202002.406428-16-cascardo@igalia.com> + +From: Jan Kara + +[ Upstream commit 00bce6f792caccefa73daeaf9bde82d24d50037f ] + +Convert udf_mkdir() to new directory iteration code. + +Signed-off-by: Jan Kara +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + 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-5.15/udf-convert-udf_readdir-to-new-directory-iteration.patch b/queue-5.15/udf-convert-udf_readdir-to-new-directory-iteration.patch new file mode 100644 index 00000000000..6da8b02c521 --- /dev/null +++ b/queue-5.15/udf-convert-udf_readdir-to-new-directory-iteration.patch @@ -0,0 +1,225 @@ +From stable+bounces-86696-greg=kroah.com@vger.kernel.org Thu Oct 17 22:20:48 2024 +From: Thadeu Lima de Souza Cascardo +Date: Thu, 17 Oct 2024 17:19:49 -0300 +Subject: udf: Convert udf_readdir() to new directory iteration +To: stable@vger.kernel.org +Cc: Jan Kara , kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo +Message-ID: <20241017202002.406428-8-cascardo@igalia.com> + +From: Jan Kara + +[ Upstream commit 7cd7a36ab44d3e8c1dee7185ef407b9831a8220b ] + +Convert udf_readdir() to new directory iteration functions. + +Signed-off-by: Jan Kara +[cascardo: conflict due to skipped 59a16786fa7a ("udf: replace ll_rw_block()")] +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + 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) { +- ll_rw_block(REQ_OP_READ, REQ_RAHEAD, num, bha); +- 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-5.15/udf-convert-udf_rename-to-new-directory-iteration-code.patch b/queue-5.15/udf-convert-udf_rename-to-new-directory-iteration-code.patch new file mode 100644 index 00000000000..5136bf64c31 --- /dev/null +++ b/queue-5.15/udf-convert-udf_rename-to-new-directory-iteration-code.patch @@ -0,0 +1,236 @@ +From stable+bounces-86695-greg=kroah.com@vger.kernel.org Thu Oct 17 22:20:46 2024 +From: Thadeu Lima de Souza Cascardo +Date: Thu, 17 Oct 2024 17:19:48 -0300 +Subject: udf: Convert udf_rename() to new directory iteration code +To: stable@vger.kernel.org +Cc: Jan Kara , kernel-dev@igalia.com, syzbot+0eaad3590d65102b9391@syzkaller.appspotmail.com, syzbot+b7fc73213bc2361ab650@syzkaller.appspotmail.com, Thadeu Lima de Souza Cascardo +Message-ID: <20241017202002.406428-7-cascardo@igalia.com> + +From: Jan Kara + +[ 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 +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + fs/udf/namei.c | 169 ++++++++++++++++++++++++++------------------------------- + 1 file changed, 80 insertions(+), 89 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,13 +1342,13 @@ 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); +- udf_update_tag((char *)dir_fi, udf_dir_entry_len(dir_fi)); +- 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_update_tag((char *)&diriter.fi, ++ udf_dir_entry_len(&diriter.fi)); ++ udf_fiiter_write_fi(&diriter, NULL); ++ udf_fiiter_release(&diriter); + + inode_dec_link_count(old_dir); + if (new_inode) +@@ -1356,22 +1358,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-5.15/udf-convert-udf_rmdir-to-new-directory-iteration-code.patch b/queue-5.15/udf-convert-udf_rmdir-to-new-directory-iteration-code.patch new file mode 100644 index 00000000000..676f6acc607 --- /dev/null +++ b/queue-5.15/udf-convert-udf_rmdir-to-new-directory-iteration-code.patch @@ -0,0 +1,80 @@ +From stable+bounces-86701-greg=kroah.com@vger.kernel.org Thu Oct 17 22:20:53 2024 +From: Thadeu Lima de Souza Cascardo +Date: Thu, 17 Oct 2024 17:19:53 -0300 +Subject: udf: Convert udf_rmdir() to new directory iteration code +To: stable@vger.kernel.org +Cc: Jan Kara , kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo +Message-ID: <20241017202002.406428-12-cascardo@igalia.com> + +From: Jan Kara + +[ Upstream commit d11ffa8d3ec11fdb665f12f95d58d74673051a93 ] + +Convert udf_rmdir() to use new directory iteration code. + +Signed-off-by: Jan Kara +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + 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-5.15/udf-convert-udf_unlink-to-new-directory-iteration-code.patch b/queue-5.15/udf-convert-udf_unlink-to-new-directory-iteration-code.patch new file mode 100644 index 00000000000..21a3be61b68 --- /dev/null +++ b/queue-5.15/udf-convert-udf_unlink-to-new-directory-iteration-code.patch @@ -0,0 +1,81 @@ +From stable+bounces-86700-greg=kroah.com@vger.kernel.org Thu Oct 17 22:20:55 2024 +From: Thadeu Lima de Souza Cascardo +Date: Thu, 17 Oct 2024 17:19:54 -0300 +Subject: udf: Convert udf_unlink() to new directory iteration code +To: stable@vger.kernel.org +Cc: Jan Kara , kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo +Message-ID: <20241017202002.406428-13-cascardo@igalia.com> + +From: Jan Kara + +[ Upstream commit 6ec01a8020b54e278fecd1efe8603f8eb38fed84 ] + +Convert udf_unlink() to new directory iteration code. + +Signed-off-by: Jan Kara +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + 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-5.15/udf-don-t-return-bh-from-udf_expand_dir_adinicb.patch b/queue-5.15/udf-don-t-return-bh-from-udf_expand_dir_adinicb.patch new file mode 100644 index 00000000000..5c6e461577e --- /dev/null +++ b/queue-5.15/udf-don-t-return-bh-from-udf_expand_dir_adinicb.patch @@ -0,0 +1,114 @@ +From stable+bounces-86708-greg=kroah.com@vger.kernel.org Thu Oct 17 22:21:04 2024 +From: Thadeu Lima de Souza Cascardo +Date: Thu, 17 Oct 2024 17:20:01 -0300 +Subject: udf: Don't return bh from udf_expand_dir_adinicb() +To: stable@vger.kernel.org +Cc: Jan Kara , kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo +Message-ID: <20241017202002.406428-20-cascardo@igalia.com> + +From: Jan Kara + +[ Upstream commit f386c802a6fda8f9fe4a5cf418c49aa84dfc52e4 ] + +Nobody uses the bh returned from udf_expand_dir_adinicb(). Don't return +it. + +Signed-off-by: Jan Kara +[cascardo: skip backport of 101ee137d32a ("udf: Drop VARCONV support")] +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + 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-5.15/udf-fix-bogus-checksum-computation-in-udf_rename.patch b/queue-5.15/udf-fix-bogus-checksum-computation-in-udf_rename.patch new file mode 100644 index 00000000000..b64adc46909 --- /dev/null +++ b/queue-5.15/udf-fix-bogus-checksum-computation-in-udf_rename.patch @@ -0,0 +1,44 @@ +From stable+bounces-86709-greg=kroah.com@vger.kernel.org Thu Oct 17 22:21:07 2024 +From: Thadeu Lima de Souza Cascardo +Date: Thu, 17 Oct 2024 17:20:02 -0300 +Subject: udf: Fix bogus checksum computation in udf_rename() +To: stable@vger.kernel.org +Cc: Jan Kara , kernel-dev@igalia.com, syzbot+d31185aa54170f7fc1f5@syzkaller.appspotmail.com, Thadeu Lima de Souza Cascardo +Message-ID: <20241017202002.406428-21-cascardo@igalia.com> + +From: Jan Kara + +[ Upstream commit 27ab33854873e6fb958cb074681a0107cc2ecc4c ] + +Syzbot reports uninitialized memory access in udf_rename() when updating +checksum of '..' directory entry of a moved directory. This is indeed +true as we pass on-stack diriter.fi to the udf_update_tag() and because +that has only struct fileIdentDesc included in it and not the impUse or +name fields, the checksumming function is going to checksum random stack +contents beyond the end of the structure. This is actually harmless +because the following udf_fiiter_write_fi() will recompute the checksum +from on-disk buffers where everything is properly included. So all that +is needed is just removing the bogus calculation. + +Fixes: e9109a92d2a9 ("udf: Convert udf_rename() to new directory iteration code") +Link: https://lore.kernel.org/all/000000000000cf405f060d8f75a9@google.com/T/ +Link: https://patch.msgid.link/20240617154201.29512-1-jack@suse.cz +Reported-by: syzbot+d31185aa54170f7fc1f5@syzkaller.appspotmail.com +Signed-off-by: Jan Kara +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + fs/udf/namei.c | 2 -- + 1 file changed, 2 deletions(-) + +--- a/fs/udf/namei.c ++++ b/fs/udf/namei.c +@@ -857,8 +857,6 @@ static int udf_rename(struct user_namesp + if (has_diriter) { + diriter.fi.icb.extLocation = + cpu_to_lelb(UDF_I(new_dir)->i_location); +- udf_update_tag((char *)&diriter.fi, +- udf_dir_entry_len(&diriter.fi)); + udf_fiiter_write_fi(&diriter, NULL); + udf_fiiter_release(&diriter); + diff --git a/queue-5.15/udf-handle-error-when-expanding-directory.patch b/queue-5.15/udf-handle-error-when-expanding-directory.patch new file mode 100644 index 00000000000..229c67cbce0 --- /dev/null +++ b/queue-5.15/udf-handle-error-when-expanding-directory.patch @@ -0,0 +1,40 @@ +From stable+bounces-86707-greg=kroah.com@vger.kernel.org Thu Oct 17 22:21:06 2024 +From: Thadeu Lima de Souza Cascardo +Date: Thu, 17 Oct 2024 17:20:00 -0300 +Subject: udf: Handle error when expanding directory +To: stable@vger.kernel.org +Cc: Jan Kara , kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo +Message-ID: <20241017202002.406428-19-cascardo@igalia.com> + +From: Jan Kara + +[ 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 +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + 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-5.15/udf-implement-adding-of-dir-entries-using-new-iteration-code.patch b/queue-5.15/udf-implement-adding-of-dir-entries-using-new-iteration-code.patch new file mode 100644 index 00000000000..69a312870df --- /dev/null +++ b/queue-5.15/udf-implement-adding-of-dir-entries-using-new-iteration-code.patch @@ -0,0 +1,220 @@ +From stable+bounces-86702-greg=kroah.com@vger.kernel.org Thu Oct 17 22:20:54 2024 +From: Thadeu Lima de Souza Cascardo +Date: Thu, 17 Oct 2024 17:19:55 -0300 +Subject: udf: Implement adding of dir entries using new iteration code +To: stable@vger.kernel.org +Cc: Jan Kara , kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo +Message-ID: <20241017202002.406428-14-cascardo@igalia.com> + +From: Jan Kara + +[ Upstream commit f2844803404d9729f893e279ddea12678710e7fb ] + +Implement function udf_fiiter_add_entry() adding new directory entries +using new directory iteration code. + +Signed-off-by: Jan Kara +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + 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-5.15/udf-implement-searching-for-directory-entry-using-new-iteration-code.patch b/queue-5.15/udf-implement-searching-for-directory-entry-using-new-iteration-code.patch new file mode 100644 index 00000000000..9d261e60b2a --- /dev/null +++ b/queue-5.15/udf-implement-searching-for-directory-entry-using-new-iteration-code.patch @@ -0,0 +1,99 @@ +From stable+bounces-86693-greg=kroah.com@vger.kernel.org Thu Oct 17 22:20:44 2024 +From: Thadeu Lima de Souza Cascardo +Date: Thu, 17 Oct 2024 17:19:46 -0300 +Subject: udf: Implement searching for directory entry using new iteration code +To: stable@vger.kernel.org +Cc: Jan Kara , kernel-dev@igalia.com, syzbot+69c9fdccc6dd08961d34@syzkaller.appspotmail.com, Thadeu Lima de Souza Cascardo +Message-ID: <20241017202002.406428-5-cascardo@igalia.com> + +From: Jan Kara + +[ 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 +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + 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-5.15/udf-move-udf_expand_dir_adinicb-to-its-callsite.patch b/queue-5.15/udf-move-udf_expand_dir_adinicb-to-its-callsite.patch new file mode 100644 index 00000000000..22acf0f52e3 --- /dev/null +++ b/queue-5.15/udf-move-udf_expand_dir_adinicb-to-its-callsite.patch @@ -0,0 +1,218 @@ +From stable+bounces-86692-greg=kroah.com@vger.kernel.org Thu Oct 17 22:20:41 2024 +From: Thadeu Lima de Souza Cascardo +Date: Thu, 17 Oct 2024 17:19:45 -0300 +Subject: udf: Move udf_expand_dir_adinicb() to its callsite +To: stable@vger.kernel.org +Cc: Jan Kara , kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo +Message-ID: <20241017202002.406428-4-cascardo@igalia.com> + +From: Jan Kara + +[ 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 +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -324,88 +324,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-5.15/udf-new-directory-iteration-code.patch b/queue-5.15/udf-new-directory-iteration-code.patch new file mode 100644 index 00000000000..9ade6a3f2ac --- /dev/null +++ b/queue-5.15/udf-new-directory-iteration-code.patch @@ -0,0 +1,468 @@ +From stable+bounces-86689-greg=kroah.com@vger.kernel.org Thu Oct 17 22:20:26 2024 +From: Thadeu Lima de Souza Cascardo +Date: Thu, 17 Oct 2024 17:19:43 -0300 +Subject: udf: New directory iteration code +To: stable@vger.kernel.org +Cc: Jan Kara , kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo +Message-ID: <20241017202002.406428-2-cascardo@igalia.com> + +From: Jan Kara + +[ 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 +[cascardo: use ll_rw_block instead of bh_readahead_batch] +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + #include ++#include ++#include ++ ++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) { ++ ll_rw_block(REQ_OP_READ, REQ_RAHEAD, num, bha); ++ 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-5.15/udf-provide-function-to-mark-entry-as-deleted-using-new-directory-iteration-code.patch b/queue-5.15/udf-provide-function-to-mark-entry-as-deleted-using-new-directory-iteration-code.patch new file mode 100644 index 00000000000..4386348763f --- /dev/null +++ b/queue-5.15/udf-provide-function-to-mark-entry-as-deleted-using-new-directory-iteration-code.patch @@ -0,0 +1,41 @@ +From stable+bounces-86694-greg=kroah.com@vger.kernel.org Thu Oct 17 22:20:42 2024 +From: Thadeu Lima de Souza Cascardo +Date: Thu, 17 Oct 2024 17:19:47 -0300 +Subject: udf: Provide function to mark entry as deleted using new directory iteration code +To: stable@vger.kernel.org +Cc: Jan Kara , kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo +Message-ID: <20241017202002.406428-6-cascardo@igalia.com> + +From: Jan Kara + +[ 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 +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + 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-5.15/udf-remove-old-directory-iteration-code.patch b/queue-5.15/udf-remove-old-directory-iteration-code.patch new file mode 100644 index 00000000000..4bfcb05a014 --- /dev/null +++ b/queue-5.15/udf-remove-old-directory-iteration-code.patch @@ -0,0 +1,796 @@ +From stable+bounces-86706-greg=kroah.com@vger.kernel.org Thu Oct 17 22:21:02 2024 +From: Thadeu Lima de Souza Cascardo +Date: Thu, 17 Oct 2024 17:19:59 -0300 +Subject: udf: Remove old directory iteration code +To: stable@vger.kernel.org +Cc: Jan Kara , kernel-dev@igalia.com, Thadeu Lima de Souza Cascardo +Message-ID: <20241017202002.406428-18-cascardo@igalia.com> + +From: Jan Kara + +[ Upstream commit 1e0290d61a870ed61a6510863029939bbf6b0006 ] + +Remove old directory iteration code that is now unused. + +Signed-off-by: Jan Kara +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + 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) { +- ll_rw_block(REQ_OP_READ, REQ_RAHEAD, num, bha); +- 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); +