diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-09-10 17:51:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-09-10 17:51:35 -0400 |
commit | 1b0a9069dec4168b431755ca89c6999d7c46a7de (patch) | |
tree | e39c5d34098071504a97740efa614fe404fcff4c /fs | |
parent | 6562271ae4ffb25a193995133c3d6d3b0b4f6730 (diff) | |
parent | 9c2fc0de1a6e638fe58c354a463f544f42a90a09 (diff) |
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull UDF and ext3 fixes from Jan Kara:
"One UDF data corruption fix and one ext3 fix where we didn't write
everything to disk on fsync in one corner case."
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
udf: Fix data corruption for files in ICB
ext3: Fix fdatasync() for files with only i_size changes
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext3/inode.c | 17 | ||||
-rw-r--r-- | fs/udf/file.c | 35 |
2 files changed, 43 insertions, 9 deletions
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index a07597307fd1..ff574b4e345e 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -3072,6 +3072,8 @@ static int ext3_do_update_inode(handle_t *handle, | |||
3072 | struct ext3_inode_info *ei = EXT3_I(inode); | 3072 | struct ext3_inode_info *ei = EXT3_I(inode); |
3073 | struct buffer_head *bh = iloc->bh; | 3073 | struct buffer_head *bh = iloc->bh; |
3074 | int err = 0, rc, block; | 3074 | int err = 0, rc, block; |
3075 | int need_datasync = 0; | ||
3076 | __le32 disksize; | ||
3075 | uid_t i_uid; | 3077 | uid_t i_uid; |
3076 | gid_t i_gid; | 3078 | gid_t i_gid; |
3077 | 3079 | ||
@@ -3113,7 +3115,11 @@ again: | |||
3113 | raw_inode->i_gid_high = 0; | 3115 | raw_inode->i_gid_high = 0; |
3114 | } | 3116 | } |
3115 | raw_inode->i_links_count = cpu_to_le16(inode->i_nlink); | 3117 | raw_inode->i_links_count = cpu_to_le16(inode->i_nlink); |
3116 | raw_inode->i_size = cpu_to_le32(ei->i_disksize); | 3118 | disksize = cpu_to_le32(ei->i_disksize); |
3119 | if (disksize != raw_inode->i_size) { | ||
3120 | need_datasync = 1; | ||
3121 | raw_inode->i_size = disksize; | ||
3122 | } | ||
3117 | raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec); | 3123 | raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec); |
3118 | raw_inode->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec); | 3124 | raw_inode->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec); |
3119 | raw_inode->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec); | 3125 | raw_inode->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec); |
@@ -3129,8 +3135,11 @@ again: | |||
3129 | if (!S_ISREG(inode->i_mode)) { | 3135 | if (!S_ISREG(inode->i_mode)) { |
3130 | raw_inode->i_dir_acl = cpu_to_le32(ei->i_dir_acl); | 3136 | raw_inode->i_dir_acl = cpu_to_le32(ei->i_dir_acl); |
3131 | } else { | 3137 | } else { |
3132 | raw_inode->i_size_high = | 3138 | disksize = cpu_to_le32(ei->i_disksize >> 32); |
3133 | cpu_to_le32(ei->i_disksize >> 32); | 3139 | if (disksize != raw_inode->i_size_high) { |
3140 | raw_inode->i_size_high = disksize; | ||
3141 | need_datasync = 1; | ||
3142 | } | ||
3134 | if (ei->i_disksize > 0x7fffffffULL) { | 3143 | if (ei->i_disksize > 0x7fffffffULL) { |
3135 | struct super_block *sb = inode->i_sb; | 3144 | struct super_block *sb = inode->i_sb; |
3136 | if (!EXT3_HAS_RO_COMPAT_FEATURE(sb, | 3145 | if (!EXT3_HAS_RO_COMPAT_FEATURE(sb, |
@@ -3183,6 +3192,8 @@ again: | |||
3183 | ext3_clear_inode_state(inode, EXT3_STATE_NEW); | 3192 | ext3_clear_inode_state(inode, EXT3_STATE_NEW); |
3184 | 3193 | ||
3185 | atomic_set(&ei->i_sync_tid, handle->h_transaction->t_tid); | 3194 | atomic_set(&ei->i_sync_tid, handle->h_transaction->t_tid); |
3195 | if (need_datasync) | ||
3196 | atomic_set(&ei->i_datasync_tid, handle->h_transaction->t_tid); | ||
3186 | out_brelse: | 3197 | out_brelse: |
3187 | brelse (bh); | 3198 | brelse (bh); |
3188 | ext3_std_error(inode->i_sb, err); | 3199 | ext3_std_error(inode->i_sb, err); |
diff --git a/fs/udf/file.c b/fs/udf/file.c index 7f3f7ba3df6e..d1c6093fd3d3 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c | |||
@@ -39,20 +39,24 @@ | |||
39 | #include "udf_i.h" | 39 | #include "udf_i.h" |
40 | #include "udf_sb.h" | 40 | #include "udf_sb.h" |
41 | 41 | ||
42 | static int udf_adinicb_readpage(struct file *file, struct page *page) | 42 | static void __udf_adinicb_readpage(struct page *page) |
43 | { | 43 | { |
44 | struct inode *inode = page->mapping->host; | 44 | struct inode *inode = page->mapping->host; |
45 | char *kaddr; | 45 | char *kaddr; |
46 | struct udf_inode_info *iinfo = UDF_I(inode); | 46 | struct udf_inode_info *iinfo = UDF_I(inode); |
47 | 47 | ||
48 | BUG_ON(!PageLocked(page)); | ||
49 | |||
50 | kaddr = kmap(page); | 48 | kaddr = kmap(page); |
51 | memset(kaddr, 0, PAGE_CACHE_SIZE); | ||
52 | memcpy(kaddr, iinfo->i_ext.i_data + iinfo->i_lenEAttr, inode->i_size); | 49 | memcpy(kaddr, iinfo->i_ext.i_data + iinfo->i_lenEAttr, inode->i_size); |
50 | memset(kaddr + inode->i_size, 0, PAGE_CACHE_SIZE - inode->i_size); | ||
53 | flush_dcache_page(page); | 51 | flush_dcache_page(page); |
54 | SetPageUptodate(page); | 52 | SetPageUptodate(page); |
55 | kunmap(page); | 53 | kunmap(page); |
54 | } | ||
55 | |||
56 | static int udf_adinicb_readpage(struct file *file, struct page *page) | ||
57 | { | ||
58 | BUG_ON(!PageLocked(page)); | ||
59 | __udf_adinicb_readpage(page); | ||
56 | unlock_page(page); | 60 | unlock_page(page); |
57 | 61 | ||
58 | return 0; | 62 | return 0; |
@@ -77,6 +81,25 @@ static int udf_adinicb_writepage(struct page *page, | |||
77 | return 0; | 81 | return 0; |
78 | } | 82 | } |
79 | 83 | ||
84 | static int udf_adinicb_write_begin(struct file *file, | ||
85 | struct address_space *mapping, loff_t pos, | ||
86 | unsigned len, unsigned flags, struct page **pagep, | ||
87 | void **fsdata) | ||
88 | { | ||
89 | struct page *page; | ||
90 | |||
91 | if (WARN_ON_ONCE(pos >= PAGE_CACHE_SIZE)) | ||
92 | return -EIO; | ||
93 | page = grab_cache_page_write_begin(mapping, 0, flags); | ||
94 | if (!page) | ||
95 | return -ENOMEM; | ||
96 | *pagep = page; | ||
97 | |||
98 | if (!PageUptodate(page) && len != PAGE_CACHE_SIZE) | ||
99 | __udf_adinicb_readpage(page); | ||
100 | return 0; | ||
101 | } | ||
102 | |||
80 | static int udf_adinicb_write_end(struct file *file, | 103 | static int udf_adinicb_write_end(struct file *file, |
81 | struct address_space *mapping, | 104 | struct address_space *mapping, |
82 | loff_t pos, unsigned len, unsigned copied, | 105 | loff_t pos, unsigned len, unsigned copied, |
@@ -98,8 +121,8 @@ static int udf_adinicb_write_end(struct file *file, | |||
98 | const struct address_space_operations udf_adinicb_aops = { | 121 | const struct address_space_operations udf_adinicb_aops = { |
99 | .readpage = udf_adinicb_readpage, | 122 | .readpage = udf_adinicb_readpage, |
100 | .writepage = udf_adinicb_writepage, | 123 | .writepage = udf_adinicb_writepage, |
101 | .write_begin = simple_write_begin, | 124 | .write_begin = udf_adinicb_write_begin, |
102 | .write_end = udf_adinicb_write_end, | 125 | .write_end = udf_adinicb_write_end, |
103 | }; | 126 | }; |
104 | 127 | ||
105 | static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | 128 | static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, |