aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/page.c
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 /fs/gfs2/page.c
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>
Diffstat (limited to 'fs/gfs2/page.c')
-rw-r--r--fs/gfs2/page.c112
1 files changed, 59 insertions, 53 deletions
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