aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk.kim@samsung.com>2013-12-26 06:15:09 -0500
committerJaegeuk Kim <jaegeuk.kim@samsung.com>2013-12-26 06:33:07 -0500
commit944fcfc18445b22d7ad1953a6effcfbdc4ffec74 (patch)
treec8f222d972480a3750361e1702b716187318ee10
parent1ec79083b2d4614d9dbaea67b5f55b60d7137a2d (diff)
f2fs: check the blocksize before calling generic_direct_IO path
The f2fs supports 4KB block size. If user requests dwrite with under 4KB data, it allocates a new 4KB data block. However, f2fs doesn't add zero data into the untouched data area inside the newly allocated data block. This incurs an error during the xfstest #263 test as follow. 263 12s ... [failed, exit status 1] - output mismatch (see 263.out.bad) --- 263.out 2013-03-09 03:37:15.043967603 +0900 +++ 263.out.bad 2013-12-27 04:20:39.230203114 +0900 @@ -1,3 +1,976 @@ QA output created by 263 fsx -N 10000 -o 8192 -l 500000 -r PSIZE -t BSIZE -w BSIZE -Z -fsx -N 10000 -o 128000 -l 500000 -r PSIZE -t BSIZE -w BSIZE -Z +fsx -N 10000 -o 8192 -l 500000 -r PSIZE -t BSIZE -w BSIZE -Z +truncating to largest ever: 0x12a00 +truncating to largest ever: 0x75400 +fallocating to largest ever: 0x79cbf ... (Run 'diff -u 263.out 263.out.bad' to see the entire diff) Ran: 263 Failures: 263 Failed 1 of 1 tests It turns out that, when the test tries to write 2KB data with dio, the new dio path allocates 4KB data block without filling zero data inside the remained 2KB area. Finally, the output file contains a garbage data for that region. Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
-rw-r--r--fs/f2fs/data.c22
1 files changed, 22 insertions, 0 deletions
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 991e36835df8..e0965b43d16e 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -953,11 +953,33 @@ static int f2fs_write_end(struct file *file,
953 return copied; 953 return copied;
954} 954}
955 955
956static int check_direct_IO(struct inode *inode, int rw,
957 const struct iovec *iov, loff_t offset, unsigned long nr_segs)
958{
959 unsigned blocksize_mask = inode->i_sb->s_blocksize - 1;
960 int i;
961
962 if (rw == READ)
963 return 0;
964
965 if (offset & blocksize_mask)
966 return -EINVAL;
967
968 for (i = 0; i < nr_segs; i++)
969 if (iov[i].iov_len & blocksize_mask)
970 return -EINVAL;
971 return 0;
972}
973
956static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb, 974static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb,
957 const struct iovec *iov, loff_t offset, unsigned long nr_segs) 975 const struct iovec *iov, loff_t offset, unsigned long nr_segs)
958{ 976{
959 struct file *file = iocb->ki_filp; 977 struct file *file = iocb->ki_filp;
960 struct inode *inode = file->f_mapping->host; 978 struct inode *inode = file->f_mapping->host;
979
980 if (check_direct_IO(inode, rw, iov, offset, nr_segs))
981 return 0;
982
961 return blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, 983 return blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
962 get_data_block); 984 get_data_block);
963} 985}