diff options
Diffstat (limited to 'fs/f2fs/inline.c')
| -rw-r--r-- | fs/f2fs/inline.c | 38 |
1 files changed, 31 insertions, 7 deletions
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index 0a1052d5ee62..aec06fb4fd76 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c @@ -9,6 +9,7 @@ #include <linux/fs.h> #include <linux/f2fs_fs.h> #include <linux/fiemap.h> +#include <linux/fserror.h> #include "f2fs.h" #include "node.h" @@ -176,9 +177,10 @@ int f2fs_convert_inline_folio(struct dnode_of_data *dn, struct folio *folio) if (unlikely(dn->data_blkaddr != NEW_ADDR)) { f2fs_put_dnode(dn); set_sbi_flag(fio.sbi, SBI_NEED_FSCK); - f2fs_warn(fio.sbi, "%s: corrupted inline inode ino=%lx, i_addr[0]:0x%x, run fsck to fix.", + f2fs_warn(fio.sbi, "%s: corrupted inline inode ino=%llu, i_addr[0]:0x%x, run fsck to fix.", __func__, dn->inode->i_ino, dn->data_blkaddr); f2fs_handle_error(fio.sbi, ERROR_INVALID_BLKADDR); + fserror_report_file_metadata(dn->inode, -EFSCORRUPTED, GFP_NOFS); return -EFSCORRUPTED; } @@ -431,10 +433,11 @@ static int f2fs_move_inline_dirents(struct inode *dir, struct folio *ifolio, if (unlikely(dn.data_blkaddr != NEW_ADDR)) { f2fs_put_dnode(&dn); set_sbi_flag(F2FS_F_SB(folio), SBI_NEED_FSCK); - f2fs_warn(F2FS_F_SB(folio), "%s: corrupted inline inode ino=%lx, i_addr[0]:0x%x, run fsck to fix.", + f2fs_warn(F2FS_F_SB(folio), "%s: corrupted inline inode ino=%llu, i_addr[0]:0x%x, run fsck to fix.", __func__, dir->i_ino, dn.data_blkaddr); f2fs_handle_error(F2FS_F_SB(folio), ERROR_INVALID_BLKADDR); err = -EFSCORRUPTED; + fserror_report_file_metadata(dn.inode, err, GFP_NOFS); goto out; } @@ -507,6 +510,12 @@ static int f2fs_add_inline_entries(struct inode *dir, void *inline_dentry) bit_pos++; continue; } + if (unlikely(le16_to_cpu(de->name_len) > F2FS_NAME_LEN || + bit_pos + GET_DENTRY_SLOTS(le16_to_cpu(de->name_len)) > + d.max)) { + err = -EFSCORRUPTED; + goto punch_dentry_pages; + } /* * We only need the disk_name and hash to move the dentry. @@ -527,6 +536,7 @@ static int f2fs_add_inline_entries(struct inode *dir, void *inline_dentry) bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len)); } return 0; + punch_dentry_pages: truncate_inode_pages(&dir->i_data, 0); f2fs_truncate_blocks(dir, 0, false); @@ -722,7 +732,7 @@ void f2fs_delete_inline_entry(struct f2fs_dir_entry *dentry, f2fs_folio_put(folio, true); inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir)); - f2fs_mark_inode_dirty_sync(dir, false); + f2fs_mark_inode_dirty_sync(dir, true); if (inode) f2fs_drop_nlink(dir, inode); @@ -792,7 +802,7 @@ int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx, int f2fs_inline_data_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, __u64 start, __u64 len) { - __u64 byteaddr, ilen; + __u64 byteaddr = 0, ilen; __u32 flags = FIEMAP_EXTENT_DATA_INLINE | FIEMAP_EXTENT_NOT_ALIGNED | FIEMAP_EXTENT_LAST; struct node_info ni; @@ -814,6 +824,15 @@ int f2fs_inline_data_fiemap(struct inode *inode, goto out; } + if (fieinfo->fi_flags & FIEMAP_FLAG_SYNC) { + err = f2fs_write_single_node_folio(ifolio, true, false, FS_NODE_IO); + if (err) + return err; + ifolio = f2fs_get_inode_folio(F2FS_I_SB(inode), inode->i_ino); + if (IS_ERR(ifolio)) + return PTR_ERR(ifolio); + f2fs_folio_wait_writeback(ifolio, NODE, true, true); + } ilen = min_t(size_t, MAX_INLINE_DATA(inode), i_size_read(inode)); if (start >= ilen) goto out; @@ -825,9 +844,14 @@ int f2fs_inline_data_fiemap(struct inode *inode, if (err) goto out; - byteaddr = (__u64)ni.blk_addr << inode->i_sb->s_blocksize_bits; - byteaddr += (char *)inline_data_addr(inode, ifolio) - - (char *)F2FS_INODE(ifolio); + if (__is_valid_data_blkaddr(ni.blk_addr)) { + byteaddr = (__u64)ni.blk_addr << inode->i_sb->s_blocksize_bits; + byteaddr += (char *)inline_data_addr(inode, ifolio) - + (char *)F2FS_INODE(ifolio); + } else { + f2fs_bug_on(F2FS_I_SB(inode), ni.blk_addr != NEW_ADDR); + flags |= FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN; + } err = fiemap_fill_next_extent(fieinfo, start, byteaddr, ilen, flags); trace_f2fs_fiemap(inode, start, byteaddr, ilen, flags, err); out: |
