diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/gfs2/bmap.c | 2 | ||||
-rw-r--r-- | fs/gfs2/ops_address.c | 2 | ||||
-rw-r--r-- | fs/gfs2/page.c | 112 | ||||
-rw-r--r-- | fs/gfs2/page.h | 4 |
4 files changed, 63 insertions, 57 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index ff4a9175b4e1..bd194f645c52 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c | |||
@@ -872,7 +872,7 @@ static int trunc_start(struct gfs2_inode *ip, uint64_t size) | |||
872 | if (do_div(junk, sdp->sd_jbsize)) | 872 | if (do_div(junk, sdp->sd_jbsize)) |
873 | error = truncator_journaled(ip, size); | 873 | error = truncator_journaled(ip, size); |
874 | } else if (size & (uint64_t)(sdp->sd_sb.sb_bsize - 1)) | 874 | } else if (size & (uint64_t)(sdp->sd_sb.sb_bsize - 1)) |
875 | error = gfs2_truncator_page(ip, size); | 875 | error = gfs2_block_truncate_page(ip->i_vnode->i_mapping); |
876 | 876 | ||
877 | if (!error) { | 877 | if (!error) { |
878 | ip->i_di.di_size = size; | 878 | ip->i_di.di_size = size; |
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index da5a0b445188..d611b2ad2e97 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c | |||
@@ -385,7 +385,7 @@ static int gfs2_commit_write(struct file *file, struct page *page, | |||
385 | i_size_write(inode, file_size); | 385 | i_size_write(inode, file_size); |
386 | } else { | 386 | } else { |
387 | if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED) | 387 | if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED) |
388 | gfs2_page_add_databufs(sdp, page, from, to); | 388 | gfs2_page_add_databufs(ip, page, from, to); |
389 | error = generic_commit_write(file, page, from, to); | 389 | error = generic_commit_write(file, page, from, to); |
390 | if (error) | 390 | if (error) |
391 | goto fail; | 391 | goto fail; |
diff --git a/fs/gfs2/page.c b/fs/gfs2/page.c index 05453c5a06f0..ea31bceac4f2 100644 --- a/fs/gfs2/page.c +++ b/fs/gfs2/page.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include "inode.h" | 21 | #include "inode.h" |
22 | #include "page.h" | 22 | #include "page.h" |
23 | #include "trans.h" | 23 | #include "trans.h" |
24 | #include "ops_address.h" | ||
24 | 25 | ||
25 | /** | 26 | /** |
26 | * gfs2_pte_inval - Sync and invalidate all PTEs associated with a glock | 27 | * gfs2_pte_inval - Sync and invalidate all PTEs associated with a glock |
@@ -184,76 +185,81 @@ int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, | |||
184 | } | 185 | } |
185 | 186 | ||
186 | /** | 187 | /** |
187 | * gfs2_truncator_page - truncate a partial data block in the page cache | 188 | * gfs2_block_truncate_page - Deal with zeroing out data for truncate |
188 | * @ip: the inode | ||
189 | * @size: the size the file should be | ||
190 | * | 189 | * |
191 | * Returns: errno | 190 | * This is partly borrowed from ext3. |
192 | */ | 191 | */ |
193 | 192 | int gfs2_block_truncate_page(struct address_space *mapping) | |
194 | int gfs2_truncator_page(struct gfs2_inode *ip, uint64_t size) | ||
195 | { | 193 | { |
194 | struct inode *inode = mapping->host; | ||
195 | struct gfs2_inode *ip = get_v2ip(inode); | ||
196 | struct gfs2_sbd *sdp = ip->i_sbd; | 196 | struct gfs2_sbd *sdp = ip->i_sbd; |
197 | struct inode *inode = ip->i_vnode; | 197 | loff_t from = inode->i_size; |
198 | struct page *page; | 198 | unsigned long index = from >> PAGE_CACHE_SHIFT; |
199 | unsigned offset = from & (PAGE_CACHE_SIZE-1); | ||
200 | unsigned blocksize, iblock, length, pos; | ||
199 | struct buffer_head *bh; | 201 | struct buffer_head *bh; |
202 | struct page *page; | ||
200 | void *kaddr; | 203 | void *kaddr; |
201 | uint64_t lbn, dbn; | 204 | int err; |
202 | unsigned long index; | 205 | |
203 | unsigned int offset; | 206 | page = grab_cache_page(mapping, index); |
204 | unsigned int bufnum; | 207 | if (!page) |
205 | int new = 0; | 208 | return 0; |
206 | int error; | ||
207 | |||
208 | lbn = size >> inode->i_blkbits; | ||
209 | error = gfs2_block_map(ip, lbn, &new, &dbn, NULL); | ||
210 | if (error || !dbn) | ||
211 | return error; | ||
212 | |||
213 | index = size >> PAGE_CACHE_SHIFT; | ||
214 | offset = size & (PAGE_CACHE_SIZE - 1); | ||
215 | bufnum = lbn - (index << (PAGE_CACHE_SHIFT - inode->i_blkbits)); | ||
216 | |||
217 | page = read_cache_page(inode->i_mapping, index, | ||
218 | (filler_t *)inode->i_mapping->a_ops->readpage, | ||
219 | NULL); | ||
220 | if (IS_ERR(page)) | ||
221 | return PTR_ERR(page); | ||
222 | |||
223 | lock_page(page); | ||
224 | |||
225 | if (!PageUptodate(page) || PageError(page)) { | ||
226 | error = -EIO; | ||
227 | goto out; | ||
228 | } | ||
229 | 209 | ||
230 | kaddr = kmap(page); | 210 | blocksize = inode->i_sb->s_blocksize; |
231 | memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); | 211 | length = blocksize - (offset & (blocksize - 1)); |
232 | kunmap(page); | 212 | iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); |
233 | 213 | ||
234 | if (!page_has_buffers(page)) | 214 | if (!page_has_buffers(page)) |
235 | create_empty_buffers(page, 1 << inode->i_blkbits, | 215 | create_empty_buffers(page, blocksize, 0); |
236 | (1 << BH_Uptodate)); | ||
237 | 216 | ||
238 | for (bh = page_buffers(page); bufnum--; bh = bh->b_this_page) | 217 | /* Find the buffer that contains "offset" */ |
239 | /* Do nothing */; | 218 | bh = page_buffers(page); |
219 | pos = blocksize; | ||
220 | while (offset >= pos) { | ||
221 | bh = bh->b_this_page; | ||
222 | iblock++; | ||
223 | pos += blocksize; | ||
224 | } | ||
240 | 225 | ||
241 | if (!buffer_mapped(bh)) | 226 | err = 0; |
242 | map_bh(bh, inode->i_sb, dbn); | ||
243 | 227 | ||
244 | set_buffer_uptodate(bh); | 228 | if (!buffer_mapped(bh)) { |
245 | if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED) | 229 | gfs2_get_block(inode, iblock, bh, 0); |
230 | /* unmapped? It's a hole - nothing to do */ | ||
231 | if (!buffer_mapped(bh)) | ||
232 | goto unlock; | ||
233 | } | ||
234 | |||
235 | /* Ok, it's mapped. Make sure it's up-to-date */ | ||
236 | if (PageUptodate(page)) | ||
237 | set_buffer_uptodate(bh); | ||
238 | |||
239 | if (!buffer_uptodate(bh)) { | ||
240 | err = -EIO; | ||
241 | ll_rw_block(READ, 1, &bh); | ||
242 | wait_on_buffer(bh); | ||
243 | /* Uhhuh. Read error. Complain and punt. */ | ||
244 | if (!buffer_uptodate(bh)) | ||
245 | goto unlock; | ||
246 | } | ||
247 | |||
248 | if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED/* || gfs2_is_jdata(ip)*/) | ||
246 | gfs2_trans_add_databuf(sdp, bh); | 249 | gfs2_trans_add_databuf(sdp, bh); |
247 | mark_buffer_dirty(bh); | ||
248 | 250 | ||
249 | out: | 251 | kaddr = kmap_atomic(page, KM_USER0); |
252 | memset(kaddr + offset, 0, length); | ||
253 | flush_dcache_page(page); | ||
254 | kunmap_atomic(kaddr, KM_USER0); | ||
255 | |||
256 | unlock: | ||
250 | unlock_page(page); | 257 | unlock_page(page); |
251 | page_cache_release(page); | 258 | page_cache_release(page); |
252 | 259 | return err; | |
253 | return error; | ||
254 | } | 260 | } |
255 | 261 | ||
256 | void gfs2_page_add_databufs(struct gfs2_sbd *sdp, struct page *page, | 262 | void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page, |
257 | unsigned int from, unsigned int to) | 263 | unsigned int from, unsigned int to) |
258 | { | 264 | { |
259 | struct buffer_head *head = page_buffers(page); | 265 | struct buffer_head *head = page_buffers(page); |
@@ -267,7 +273,7 @@ void gfs2_page_add_databufs(struct gfs2_sbd *sdp, struct page *page, | |||
267 | end = start + bsize; | 273 | end = start + bsize; |
268 | if (end <= from || start >= to) | 274 | if (end <= from || start >= to) |
269 | continue; | 275 | continue; |
270 | gfs2_trans_add_databuf(sdp, bh); | 276 | gfs2_trans_add_databuf(ip->i_sbd, bh); |
271 | } | 277 | } |
272 | } | 278 | } |
273 | 279 | ||
diff --git a/fs/gfs2/page.h b/fs/gfs2/page.h index 7ad8c99ee0ef..346e296420c6 100644 --- a/fs/gfs2/page.h +++ b/fs/gfs2/page.h | |||
@@ -16,8 +16,8 @@ void gfs2_page_sync(struct gfs2_glock *gl, int flags); | |||
16 | 16 | ||
17 | int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, | 17 | int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, |
18 | uint64_t block, void *private); | 18 | uint64_t block, void *private); |
19 | int gfs2_truncator_page(struct gfs2_inode *ip, uint64_t size); | 19 | int gfs2_block_truncate_page(struct address_space *mapping); |
20 | void gfs2_page_add_databufs(struct gfs2_sbd *sdp, struct page *page, | 20 | void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page, |
21 | unsigned int from, unsigned int to); | 21 | unsigned int from, unsigned int to); |
22 | 22 | ||
23 | #endif /* __PAGE_DOT_H__ */ | 23 | #endif /* __PAGE_DOT_H__ */ |