Skip to content

Commit d4dd19e

Browse files
author
Jaegeuk Kim
committed
f2fs: do not expose unwritten blocks to user by DIO
DIO preallocates physical blocks before writing data, but if an error occurrs or power-cut happens, we can see block contents from the disk. This patch tries to fix it by 1) turning to buffered writes for DIO into holes, 2) truncating unwritten blocks from error or power-cut. Signed-off-by: Jaegeuk Kim <[email protected]>
1 parent b31bf0f commit d4dd19e

File tree

4 files changed

+35
-10
lines changed

4 files changed

+35
-10
lines changed

fs/f2fs/data.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1543,8 +1543,11 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
15431543
flag != F2FS_GET_BLOCK_DIO);
15441544
err = __allocate_data_block(&dn,
15451545
map->m_seg_type);
1546-
if (!err)
1546+
if (!err) {
1547+
if (flag == F2FS_GET_BLOCK_PRE_DIO)
1548+
file_need_truncate(inode);
15471549
set_inode_flag(inode, FI_APPEND_WRITE);
1550+
}
15481551
}
15491552
if (err)
15501553
goto sync_out;

fs/f2fs/f2fs.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,7 @@ enum {
654654
#define FADVISE_KEEP_SIZE_BIT 0x10
655655
#define FADVISE_HOT_BIT 0x20
656656
#define FADVISE_VERITY_BIT 0x40
657+
#define FADVISE_TRUNC_BIT 0x80
657658

658659
#define FADVISE_MODIFIABLE_BITS (FADVISE_COLD_BIT | FADVISE_HOT_BIT)
659660

@@ -681,6 +682,10 @@ enum {
681682
#define file_is_verity(inode) is_file(inode, FADVISE_VERITY_BIT)
682683
#define file_set_verity(inode) set_file(inode, FADVISE_VERITY_BIT)
683684

685+
#define file_should_truncate(inode) is_file(inode, FADVISE_TRUNC_BIT)
686+
#define file_need_truncate(inode) set_file(inode, FADVISE_TRUNC_BIT)
687+
#define file_dont_truncate(inode) clear_file(inode, FADVISE_TRUNC_BIT)
688+
684689
#define DEF_DIR_LEVEL 0
685690

686691
enum {

fs/f2fs/file.c

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1687,6 +1687,7 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
16871687

16881688
map.m_seg_type = CURSEG_COLD_DATA_PINNED;
16891689
err = f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_DIO);
1690+
file_dont_truncate(inode);
16901691

16911692
up_write(&sbi->pin_sem);
16921693

@@ -4257,6 +4258,13 @@ static int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *iter)
42574258
/* If it will be an out-of-place direct write, don't bother. */
42584259
if (dio && f2fs_lfs_mode(sbi))
42594260
return 0;
4261+
/*
4262+
* Don't preallocate holes aligned to DIO_SKIP_HOLES which turns into
4263+
* buffered IO, if DIO meets any holes.
4264+
*/
4265+
if (dio && i_size_read(inode) &&
4266+
(F2FS_BYTES_TO_BLK(pos) < F2FS_BLK_ALIGN(i_size_read(inode))))
4267+
return 0;
42604268

42614269
/* No-wait I/O can't allocate blocks. */
42624270
if (iocb->ki_flags & IOCB_NOWAIT)
@@ -4292,8 +4300,8 @@ static int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *iter)
42924300
}
42934301

42944302
ret = f2fs_map_blocks(inode, &map, 1, flag);
4295-
/* -ENOSPC is only a fatal error if no blocks could be allocated. */
4296-
if (ret < 0 && !(ret == -ENOSPC && map.m_len > 0))
4303+
/* -ENOSPC|-EDQUOT are fine to report the number of allocated blocks. */
4304+
if (ret < 0 && !((ret == -ENOSPC || ret == -EDQUOT) && map.m_len > 0))
42974305
return ret;
42984306
if (ret == 0)
42994307
set_inode_flag(inode, FI_PREALLOCATED_ALL);
@@ -4359,20 +4367,21 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
43594367
/* Possibly preallocate the blocks for the write. */
43604368
target_size = iocb->ki_pos + iov_iter_count(from);
43614369
preallocated = f2fs_preallocate_blocks(iocb, from);
4362-
if (preallocated < 0) {
4370+
if (preallocated < 0)
43634371
ret = preallocated;
4364-
goto out_unlock;
4365-
}
4366-
4367-
ret = __generic_file_write_iter(iocb, from);
4372+
else
4373+
ret = __generic_file_write_iter(iocb, from);
43684374

43694375
/* Don't leave any preallocated blocks around past i_size. */
4370-
if (preallocated > 0 && i_size_read(inode) < target_size) {
4376+
if (preallocated && i_size_read(inode) < target_size) {
43714377
down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
43724378
filemap_invalidate_lock(inode->i_mapping);
4373-
f2fs_truncate(inode);
4379+
if (!f2fs_truncate(inode))
4380+
file_dont_truncate(inode);
43744381
filemap_invalidate_unlock(inode->i_mapping);
43754382
up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
4383+
} else {
4384+
file_dont_truncate(inode);
43764385
}
43774386

43784387
clear_inode_flag(inode, FI_PREALLOCATED_ALL);

fs/f2fs/inode.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,14 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
544544
goto bad_inode;
545545
}
546546
f2fs_set_inode_flags(inode);
547+
548+
if (file_should_truncate(inode)) {
549+
ret = f2fs_truncate(inode);
550+
if (ret)
551+
goto bad_inode;
552+
file_dont_truncate(inode);
553+
}
554+
547555
unlock_new_inode(inode);
548556
trace_f2fs_iget(inode);
549557
return inode;

0 commit comments

Comments
 (0)