aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2006-01-31 05:00:25 -0500
committerSteven Whitehouse <swhiteho@redhat.com>2006-01-31 05:00:25 -0500
commit257f9b4e97e9a6cceeb247cead92119a4396d37b (patch)
tree5bd94507046b09a9d6cc067c1dcc1124fbaa4016
parentf42faf4fa4eaf7e108dd60f3f2ca5c6e9b45352c (diff)
[GFS2] Update truncate function (shrinking partial blocks)
Update the function in GFS2 which deals with truncation of partial blocks. Some of the code is "borrowed" from ext3 since it appears to give a good model of how to do this operation. The function is renamed gfs2_block_truncate_page accordingly. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
-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__ */