aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/gfs2/bmap.c2
-rw-r--r--fs/gfs2/ops_address.c2
-rw-r--r--fs/gfs2/page.c112
-rw-r--r--fs/gfs2/page.h4
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 192int gfs2_block_truncate_page(struct address_space *mapping)
194int 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
256unlock:
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
256void gfs2_page_add_databufs(struct gfs2_sbd *sdp, struct page *page, 262void 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
17int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, 17int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
18 uint64_t block, void *private); 18 uint64_t block, void *private);
19int gfs2_truncator_page(struct gfs2_inode *ip, uint64_t size); 19int gfs2_block_truncate_page(struct address_space *mapping);
20void gfs2_page_add_databufs(struct gfs2_sbd *sdp, struct page *page, 20void 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__ */