aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/ops_file.c
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2007-10-15 10:40:33 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2008-01-25 03:07:13 -0500
commit3cc3f710ce0effe397b830826a1a081fa81f11c7 (patch)
tree53f69f1b8d1cbc2849c6bac08ce7786f3ecd7447 /fs/gfs2/ops_file.c
parent51ff87bdd9f21a5d3672517b75d25ab5842d94a8 (diff)
[GFS2] Use ->page_mkwrite() for mmap()
This cleans up the mmap() code path for GFS2 by implementing the page_mkwrite function for GFS2. We are thus able to use the generic filemap_fault function for our ->fault() implementation. This now means that shared writable mappings will be much more efficiently shared across the cluster if there is a reasonable proportion of read activity (the greater proportion, the better). As a side effect, it also reduces the size of the code, removes special cases from readpage and readpages, and makes the code path easier to follow. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/ops_file.c')
-rw-r--r--fs/gfs2/ops_file.c131
1 files changed, 121 insertions, 10 deletions
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
index a729c86b8be1..6f3aeb059c61 100644
--- a/fs/gfs2/ops_file.c
+++ b/fs/gfs2/ops_file.c
@@ -33,7 +33,6 @@
33#include "lm.h" 33#include "lm.h"
34#include "log.h" 34#include "log.h"
35#include "meta_io.h" 35#include "meta_io.h"
36#include "ops_vm.h"
37#include "quota.h" 36#include "quota.h"
38#include "rgrp.h" 37#include "rgrp.h"
39#include "trans.h" 38#include "trans.h"
@@ -169,7 +168,7 @@ static int gfs2_get_flags(struct file *filp, u32 __user *ptr)
169 if (put_user(fsflags, ptr)) 168 if (put_user(fsflags, ptr))
170 error = -EFAULT; 169 error = -EFAULT;
171 170
172 gfs2_glock_dq_m(1, &gh); 171 gfs2_glock_dq(&gh);
173 gfs2_holder_uninit(&gh); 172 gfs2_holder_uninit(&gh);
174 return error; 173 return error;
175} 174}
@@ -293,6 +292,125 @@ static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
293 return -ENOTTY; 292 return -ENOTTY;
294} 293}
295 294
295/**
296 * gfs2_allocate_page_backing - Use bmap to allocate blocks
297 * @page: The (locked) page to allocate backing for
298 *
299 * We try to allocate all the blocks required for the page in
300 * one go. This might fail for various reasons, so we keep
301 * trying until all the blocks to back this page are allocated.
302 * If some of the blocks are already allocated, thats ok too.
303 */
304
305static int gfs2_allocate_page_backing(struct page *page)
306{
307 struct inode *inode = page->mapping->host;
308 struct buffer_head bh;
309 unsigned long size = PAGE_CACHE_SIZE;
310 u64 lblock = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
311
312 do {
313 bh.b_state = 0;
314 bh.b_size = size;
315 gfs2_block_map(inode, lblock, 1, &bh);
316 if (!buffer_mapped(&bh))
317 return -EIO;
318 size -= bh.b_size;
319 lblock += (bh.b_size >> inode->i_blkbits);
320 } while(size > 0);
321 return 0;
322}
323
324/**
325 * gfs2_page_mkwrite - Make a shared, mmap()ed, page writable
326 * @vma: The virtual memory area
327 * @page: The page which is about to become writable
328 *
329 * When the page becomes writable, we need to ensure that we have
330 * blocks allocated on disk to back that page.
331 */
332
333static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page)
334{
335 struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
336 struct gfs2_inode *ip = GFS2_I(inode);
337 struct gfs2_sbd *sdp = GFS2_SB(inode);
338 unsigned long last_index;
339 u64 pos = page->index << (PAGE_CACHE_SIZE - inode->i_blkbits);
340 unsigned int data_blocks, ind_blocks, rblocks;
341 int alloc_required = 0;
342 struct gfs2_holder gh;
343 struct gfs2_alloc *al;
344 int ret;
345
346 gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME, &gh);
347 ret = gfs2_glock_nq_atime(&gh);
348 if (ret)
349 goto out;
350
351 set_bit(GIF_SW_PAGED, &ip->i_flags);
352 gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks);
353 ret = gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE, &alloc_required);
354 if (ret || !alloc_required)
355 goto out_unlock;
356
357 ip->i_alloc.al_requested = 0;
358 al = gfs2_alloc_get(ip);
359 ret = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
360 if (ret)
361 goto out_alloc_put;
362 ret = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid);
363 if (ret)
364 goto out_quota_unlock;
365 al->al_requested = data_blocks + ind_blocks;
366 ret = gfs2_inplace_reserve(ip);
367 if (ret)
368 goto out_quota_unlock;
369
370 rblocks = RES_DINODE + ind_blocks;
371 if (gfs2_is_jdata(ip))
372 rblocks += data_blocks ? data_blocks : 1;
373 if (ind_blocks || data_blocks)
374 rblocks += RES_STATFS + RES_QUOTA;
375 ret = gfs2_trans_begin(sdp, rblocks, 0);
376 if (ret)
377 goto out_trans_fail;
378
379 lock_page(page);
380 ret = -EINVAL;
381 last_index = ip->i_inode.i_size >> PAGE_CACHE_SHIFT;
382 if (page->index > last_index)
383 goto out_unlock_page;
384 if (!PageUptodate(page) || page->mapping != ip->i_inode.i_mapping)
385 goto out_unlock_page;
386 if (gfs2_is_stuffed(ip)) {
387 ret = gfs2_unstuff_dinode(ip, page);
388 if (ret)
389 goto out_unlock_page;
390 }
391 ret = gfs2_allocate_page_backing(page);
392
393out_unlock_page:
394 unlock_page(page);
395 gfs2_trans_end(sdp);
396out_trans_fail:
397 gfs2_inplace_release(ip);
398out_quota_unlock:
399 gfs2_quota_unlock(ip);
400out_alloc_put:
401 gfs2_alloc_put(ip);
402out_unlock:
403 gfs2_glock_dq(&gh);
404out:
405 gfs2_holder_uninit(&gh);
406 return ret;
407}
408
409static struct vm_operations_struct gfs2_vm_ops = {
410 .fault = filemap_fault,
411 .page_mkwrite = gfs2_page_mkwrite,
412};
413
296 414
297/** 415/**
298 * gfs2_mmap - 416 * gfs2_mmap -
@@ -315,14 +433,7 @@ static int gfs2_mmap(struct file *file, struct vm_area_struct *vma)
315 return error; 433 return error;
316 } 434 }
317 435
318 /* This is VM_MAYWRITE instead of VM_WRITE because a call 436 vma->vm_ops = &gfs2_vm_ops;
319 to mprotect() can turn on VM_WRITE later. */
320
321 if ((vma->vm_flags & (VM_MAYSHARE | VM_MAYWRITE)) ==
322 (VM_MAYSHARE | VM_MAYWRITE))
323 vma->vm_ops = &gfs2_vm_ops_sharewrite;
324 else
325 vma->vm_ops = &gfs2_vm_ops_private;
326 437
327 gfs2_glock_dq_uninit(&i_gh); 438 gfs2_glock_dq_uninit(&i_gh);
328 439