Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

udf: Do not update file length for failed writes to inline files

When write to inline file fails (or happens only partly), we still
updated length of inline data as if the whole write succeeded. Fix the
update of length of inline data to happen only if the write succeeds.

Reported-by: syzbot+0937935b993956ba28ab@syzkaller.appspotmail.com
CC: stable@vger.kernel.org
Signed-off-by: Jan Kara <jack@suse.cz>

Jan Kara 256fe416 02113fea

+12 -14
+12 -14
fs/udf/file.c
··· 149 149 goto out; 150 150 151 151 down_write(&iinfo->i_data_sem); 152 - if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 153 - loff_t end = iocb->ki_pos + iov_iter_count(from); 154 - 155 - if (inode->i_sb->s_blocksize < 156 - (udf_file_entry_alloc_offset(inode) + end)) { 157 - err = udf_expand_file_adinicb(inode); 158 - if (err) { 159 - inode_unlock(inode); 160 - udf_debug("udf_expand_adinicb: err=%d\n", err); 161 - return err; 162 - } 163 - } else { 164 - iinfo->i_lenAlloc = max(end, inode->i_size); 165 - up_write(&iinfo->i_data_sem); 152 + if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB && 153 + inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) + 154 + iocb->ki_pos + iov_iter_count(from))) { 155 + err = udf_expand_file_adinicb(inode); 156 + if (err) { 157 + inode_unlock(inode); 158 + udf_debug("udf_expand_adinicb: err=%d\n", err); 159 + return err; 166 160 } 167 161 } else 168 162 up_write(&iinfo->i_data_sem); 169 163 170 164 retval = __generic_file_write_iter(iocb, from); 171 165 out: 166 + down_write(&iinfo->i_data_sem); 167 + if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB && retval > 0) 168 + iinfo->i_lenAlloc = inode->i_size; 169 + up_write(&iinfo->i_data_sem); 172 170 inode_unlock(inode); 173 171 174 172 if (retval > 0) {