diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2007-10-15 10:40:33 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2008-01-25 03:07:13 -0500 |
commit | 3cc3f710ce0effe397b830826a1a081fa81f11c7 (patch) | |
tree | 53f69f1b8d1cbc2849c6bac08ce7786f3ecd7447 /fs | |
parent | 51ff87bdd9f21a5d3672517b75d25ab5842d94a8 (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')
-rw-r--r-- | fs/gfs2/Makefile | 2 | ||||
-rw-r--r-- | fs/gfs2/glops.c | 9 | ||||
-rw-r--r-- | fs/gfs2/incore.h | 8 | ||||
-rw-r--r-- | fs/gfs2/ops_address.c | 45 | ||||
-rw-r--r-- | fs/gfs2/ops_file.c | 131 | ||||
-rw-r--r-- | fs/gfs2/ops_vm.c | 169 | ||||
-rw-r--r-- | fs/gfs2/ops_vm.h | 18 |
7 files changed, 131 insertions, 251 deletions
diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile index 04ad0caebedb..8fff11058cee 100644 --- a/fs/gfs2/Makefile +++ b/fs/gfs2/Makefile | |||
@@ -2,7 +2,7 @@ obj-$(CONFIG_GFS2_FS) += gfs2.o | |||
2 | gfs2-y := acl.o bmap.o daemon.o dir.o eaops.o eattr.o glock.o \ | 2 | gfs2-y := acl.o bmap.o daemon.o dir.o eaops.o eattr.o glock.o \ |
3 | glops.o inode.o lm.o log.o lops.o locking.o main.o meta_io.o \ | 3 | glops.o inode.o lm.o log.o lops.o locking.o main.o meta_io.o \ |
4 | mount.o ops_address.o ops_dentry.o ops_export.o ops_file.o \ | 4 | mount.o ops_address.o ops_dentry.o ops_export.o ops_file.o \ |
5 | ops_fstype.o ops_inode.o ops_super.o ops_vm.o quota.o \ | 5 | ops_fstype.o ops_inode.o ops_super.o quota.o \ |
6 | recovery.o rgrp.o super.o sys.o trans.o util.o | 6 | recovery.o rgrp.o super.o sys.o trans.o util.o |
7 | 7 | ||
8 | obj-$(CONFIG_GFS2_FS_LOCKING_NOLOCK) += locking/nolock/ | 8 | obj-$(CONFIG_GFS2_FS_LOCKING_NOLOCK) += locking/nolock/ |
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 4670dcb2a877..110f03d66f4b 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c | |||
@@ -86,15 +86,10 @@ static void gfs2_pte_inval(struct gfs2_glock *gl) | |||
86 | if (!ip || !S_ISREG(inode->i_mode)) | 86 | if (!ip || !S_ISREG(inode->i_mode)) |
87 | return; | 87 | return; |
88 | 88 | ||
89 | if (!test_bit(GIF_PAGED, &ip->i_flags)) | ||
90 | return; | ||
91 | |||
92 | unmap_shared_mapping_range(inode->i_mapping, 0, 0); | 89 | unmap_shared_mapping_range(inode->i_mapping, 0, 0); |
93 | |||
94 | if (test_bit(GIF_SW_PAGED, &ip->i_flags)) | 90 | if (test_bit(GIF_SW_PAGED, &ip->i_flags)) |
95 | set_bit(GLF_DIRTY, &gl->gl_flags); | 91 | set_bit(GLF_DIRTY, &gl->gl_flags); |
96 | 92 | ||
97 | clear_bit(GIF_SW_PAGED, &ip->i_flags); | ||
98 | } | 93 | } |
99 | 94 | ||
100 | /** | 95 | /** |
@@ -234,10 +229,8 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags) | |||
234 | set_bit(GIF_INVALID, &ip->i_flags); | 229 | set_bit(GIF_INVALID, &ip->i_flags); |
235 | } | 230 | } |
236 | 231 | ||
237 | if (ip && S_ISREG(ip->i_inode.i_mode)) { | 232 | if (ip && S_ISREG(ip->i_inode.i_mode)) |
238 | truncate_inode_pages(ip->i_inode.i_mapping, 0); | 233 | truncate_inode_pages(ip->i_inode.i_mapping, 0); |
239 | clear_bit(GIF_PAGED, &ip->i_flags); | ||
240 | } | ||
241 | } | 234 | } |
242 | 235 | ||
243 | /** | 236 | /** |
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 662182bfbff7..55c72f01cf31 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
@@ -241,7 +241,6 @@ struct gfs2_alloc { | |||
241 | enum { | 241 | enum { |
242 | GIF_INVALID = 0, | 242 | GIF_INVALID = 0, |
243 | GIF_QD_LOCKED = 1, | 243 | GIF_QD_LOCKED = 1, |
244 | GIF_PAGED = 2, | ||
245 | GIF_SW_PAGED = 3, | 244 | GIF_SW_PAGED = 3, |
246 | }; | 245 | }; |
247 | 246 | ||
@@ -289,19 +288,12 @@ static inline struct gfs2_inode *GFS2_I(struct inode *inode) | |||
289 | return container_of(inode, struct gfs2_inode, i_inode); | 288 | return container_of(inode, struct gfs2_inode, i_inode); |
290 | } | 289 | } |
291 | 290 | ||
292 | /* To be removed? */ | ||
293 | static inline struct gfs2_sbd *GFS2_SB(struct inode *inode) | 291 | static inline struct gfs2_sbd *GFS2_SB(struct inode *inode) |
294 | { | 292 | { |
295 | return inode->i_sb->s_fs_info; | 293 | return inode->i_sb->s_fs_info; |
296 | } | 294 | } |
297 | 295 | ||
298 | enum { | ||
299 | GFF_DID_DIRECT_ALLOC = 0, | ||
300 | GFF_EXLOCK = 1, | ||
301 | }; | ||
302 | |||
303 | struct gfs2_file { | 296 | struct gfs2_file { |
304 | unsigned long f_flags; /* GFF_... */ | ||
305 | struct mutex f_fl_mutex; | 297 | struct mutex f_fl_mutex; |
306 | struct gfs2_holder f_fl_gh; | 298 | struct gfs2_holder f_fl_gh; |
307 | }; | 299 | }; |
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 9bb24b1d9c05..1696e5d9d112 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c | |||
@@ -265,9 +265,7 @@ static int __gfs2_readpage(void *file, struct page *page) | |||
265 | * @file: The file to read | 265 | * @file: The file to read |
266 | * @page: The page of the file | 266 | * @page: The page of the file |
267 | * | 267 | * |
268 | * This deals with the locking required. If the GFF_EXLOCK flags is set | 268 | * This deals with the locking required. We use a trylock in order to |
269 | * then we already hold the glock (due to page fault) and thus we call | ||
270 | * __gfs2_readpage() directly. Otherwise we use a trylock in order to | ||
271 | * avoid the page lock / glock ordering problems returning AOP_TRUNCATED_PAGE | 269 | * avoid the page lock / glock ordering problems returning AOP_TRUNCATED_PAGE |
272 | * in the event that we are unable to get the lock. | 270 | * in the event that we are unable to get the lock. |
273 | */ | 271 | */ |
@@ -278,12 +276,6 @@ static int gfs2_readpage(struct file *file, struct page *page) | |||
278 | struct gfs2_holder gh; | 276 | struct gfs2_holder gh; |
279 | int error; | 277 | int error; |
280 | 278 | ||
281 | if (file) { | ||
282 | struct gfs2_file *gf = file->private_data; | ||
283 | if (test_bit(GFF_EXLOCK, &gf->f_flags)) | ||
284 | return __gfs2_readpage(file, page); | ||
285 | } | ||
286 | |||
287 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh); | 279 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh); |
288 | error = gfs2_glock_nq_atime(&gh); | 280 | error = gfs2_glock_nq_atime(&gh); |
289 | if (unlikely(error)) { | 281 | if (unlikely(error)) { |
@@ -354,9 +346,8 @@ int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state, | |||
354 | * 2. We don't handle stuffed files here we let readpage do the honours. | 346 | * 2. We don't handle stuffed files here we let readpage do the honours. |
355 | * 3. mpage_readpages() does most of the heavy lifting in the common case. | 347 | * 3. mpage_readpages() does most of the heavy lifting in the common case. |
356 | * 4. gfs2_get_block() is relied upon to set BH_Boundary in the right places. | 348 | * 4. gfs2_get_block() is relied upon to set BH_Boundary in the right places. |
357 | * 5. We use LM_FLAG_TRY_1CB here, effectively we then have lock-ahead as | ||
358 | * well as read-ahead. | ||
359 | */ | 349 | */ |
350 | |||
360 | static int gfs2_readpages(struct file *file, struct address_space *mapping, | 351 | static int gfs2_readpages(struct file *file, struct address_space *mapping, |
361 | struct list_head *pages, unsigned nr_pages) | 352 | struct list_head *pages, unsigned nr_pages) |
362 | { | 353 | { |
@@ -364,40 +355,20 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping, | |||
364 | struct gfs2_inode *ip = GFS2_I(inode); | 355 | struct gfs2_inode *ip = GFS2_I(inode); |
365 | struct gfs2_sbd *sdp = GFS2_SB(inode); | 356 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
366 | struct gfs2_holder gh; | 357 | struct gfs2_holder gh; |
367 | int ret = 0; | 358 | int ret; |
368 | int do_unlock = 0; | ||
369 | 359 | ||
370 | if (file) { | 360 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); |
371 | struct gfs2_file *gf = file->private_data; | ||
372 | if (test_bit(GFF_EXLOCK, &gf->f_flags)) | ||
373 | goto skip_lock; | ||
374 | } | ||
375 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, | ||
376 | LM_FLAG_TRY_1CB|GL_ATIME, &gh); | ||
377 | do_unlock = 1; | ||
378 | ret = gfs2_glock_nq_atime(&gh); | 361 | ret = gfs2_glock_nq_atime(&gh); |
379 | if (ret == GLR_TRYFAILED) | ||
380 | goto out_noerror; | ||
381 | if (unlikely(ret)) | 362 | if (unlikely(ret)) |
382 | goto out_unlock; | 363 | goto out_uninit; |
383 | skip_lock: | ||
384 | if (!gfs2_is_stuffed(ip)) | 364 | if (!gfs2_is_stuffed(ip)) |
385 | ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block); | 365 | ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block); |
386 | 366 | gfs2_glock_dq(&gh); | |
387 | if (do_unlock) { | 367 | out_uninit: |
388 | gfs2_glock_dq_m(1, &gh); | 368 | gfs2_holder_uninit(&gh); |
389 | gfs2_holder_uninit(&gh); | ||
390 | } | ||
391 | out: | ||
392 | if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) | 369 | if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) |
393 | ret = -EIO; | 370 | ret = -EIO; |
394 | return ret; | 371 | return ret; |
395 | out_noerror: | ||
396 | ret = 0; | ||
397 | out_unlock: | ||
398 | if (do_unlock) | ||
399 | gfs2_holder_uninit(&gh); | ||
400 | goto out; | ||
401 | } | 372 | } |
402 | 373 | ||
403 | /** | 374 | /** |
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 | |||
305 | static 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 | |||
333 | static 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 | |||
393 | out_unlock_page: | ||
394 | unlock_page(page); | ||
395 | gfs2_trans_end(sdp); | ||
396 | out_trans_fail: | ||
397 | gfs2_inplace_release(ip); | ||
398 | out_quota_unlock: | ||
399 | gfs2_quota_unlock(ip); | ||
400 | out_alloc_put: | ||
401 | gfs2_alloc_put(ip); | ||
402 | out_unlock: | ||
403 | gfs2_glock_dq(&gh); | ||
404 | out: | ||
405 | gfs2_holder_uninit(&gh); | ||
406 | return ret; | ||
407 | } | ||
408 | |||
409 | static 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 | ||
diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c deleted file mode 100644 index 927d739d4685..000000000000 --- a/fs/gfs2/ops_vm.c +++ /dev/null | |||
@@ -1,169 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | ||
3 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. | ||
4 | * | ||
5 | * This copyrighted material is made available to anyone wishing to use, | ||
6 | * modify, copy, or redistribute it subject to the terms and conditions | ||
7 | * of the GNU General Public License version 2. | ||
8 | */ | ||
9 | |||
10 | #include <linux/slab.h> | ||
11 | #include <linux/spinlock.h> | ||
12 | #include <linux/completion.h> | ||
13 | #include <linux/buffer_head.h> | ||
14 | #include <linux/mm.h> | ||
15 | #include <linux/pagemap.h> | ||
16 | #include <linux/gfs2_ondisk.h> | ||
17 | #include <linux/lm_interface.h> | ||
18 | |||
19 | #include "gfs2.h" | ||
20 | #include "incore.h" | ||
21 | #include "bmap.h" | ||
22 | #include "glock.h" | ||
23 | #include "inode.h" | ||
24 | #include "ops_vm.h" | ||
25 | #include "quota.h" | ||
26 | #include "rgrp.h" | ||
27 | #include "trans.h" | ||
28 | #include "util.h" | ||
29 | |||
30 | static int gfs2_private_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | ||
31 | { | ||
32 | struct gfs2_inode *ip = GFS2_I(vma->vm_file->f_mapping->host); | ||
33 | |||
34 | set_bit(GIF_PAGED, &ip->i_flags); | ||
35 | return filemap_fault(vma, vmf); | ||
36 | } | ||
37 | |||
38 | static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) | ||
39 | { | ||
40 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | ||
41 | unsigned long index = page->index; | ||
42 | u64 lblock = index << (PAGE_CACHE_SHIFT - | ||
43 | sdp->sd_sb.sb_bsize_shift); | ||
44 | unsigned int blocks = PAGE_CACHE_SIZE >> sdp->sd_sb.sb_bsize_shift; | ||
45 | struct gfs2_alloc *al; | ||
46 | unsigned int data_blocks, ind_blocks; | ||
47 | unsigned int x; | ||
48 | int error; | ||
49 | |||
50 | al = gfs2_alloc_get(ip); | ||
51 | |||
52 | error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); | ||
53 | if (error) | ||
54 | goto out; | ||
55 | |||
56 | error = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid); | ||
57 | if (error) | ||
58 | goto out_gunlock_q; | ||
59 | |||
60 | gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks); | ||
61 | |||
62 | al->al_requested = data_blocks + ind_blocks; | ||
63 | |||
64 | error = gfs2_inplace_reserve(ip); | ||
65 | if (error) | ||
66 | goto out_gunlock_q; | ||
67 | |||
68 | error = gfs2_trans_begin(sdp, al->al_rgd->rd_length + | ||
69 | ind_blocks + RES_DINODE + | ||
70 | RES_STATFS + RES_QUOTA, 0); | ||
71 | if (error) | ||
72 | goto out_ipres; | ||
73 | |||
74 | if (gfs2_is_stuffed(ip)) { | ||
75 | error = gfs2_unstuff_dinode(ip, NULL); | ||
76 | if (error) | ||
77 | goto out_trans; | ||
78 | } | ||
79 | |||
80 | for (x = 0; x < blocks; ) { | ||
81 | u64 dblock; | ||
82 | unsigned int extlen; | ||
83 | int new = 1; | ||
84 | |||
85 | error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen); | ||
86 | if (error) | ||
87 | goto out_trans; | ||
88 | |||
89 | lblock += extlen; | ||
90 | x += extlen; | ||
91 | } | ||
92 | |||
93 | gfs2_assert_warn(sdp, al->al_alloced); | ||
94 | |||
95 | out_trans: | ||
96 | gfs2_trans_end(sdp); | ||
97 | out_ipres: | ||
98 | gfs2_inplace_release(ip); | ||
99 | out_gunlock_q: | ||
100 | gfs2_quota_unlock(ip); | ||
101 | out: | ||
102 | gfs2_alloc_put(ip); | ||
103 | return error; | ||
104 | } | ||
105 | |||
106 | static int gfs2_sharewrite_fault(struct vm_area_struct *vma, | ||
107 | struct vm_fault *vmf) | ||
108 | { | ||
109 | struct file *file = vma->vm_file; | ||
110 | struct gfs2_file *gf = file->private_data; | ||
111 | struct gfs2_inode *ip = GFS2_I(file->f_mapping->host); | ||
112 | struct gfs2_holder i_gh; | ||
113 | int alloc_required; | ||
114 | int error; | ||
115 | int ret = 0; | ||
116 | |||
117 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); | ||
118 | if (error) | ||
119 | goto out; | ||
120 | |||
121 | set_bit(GIF_PAGED, &ip->i_flags); | ||
122 | set_bit(GIF_SW_PAGED, &ip->i_flags); | ||
123 | |||
124 | error = gfs2_write_alloc_required(ip, | ||
125 | (u64)vmf->pgoff << PAGE_CACHE_SHIFT, | ||
126 | PAGE_CACHE_SIZE, &alloc_required); | ||
127 | if (error) { | ||
128 | ret = VM_FAULT_OOM; /* XXX: are these right? */ | ||
129 | goto out_unlock; | ||
130 | } | ||
131 | |||
132 | set_bit(GFF_EXLOCK, &gf->f_flags); | ||
133 | ret = filemap_fault(vma, vmf); | ||
134 | clear_bit(GFF_EXLOCK, &gf->f_flags); | ||
135 | if (ret & VM_FAULT_ERROR) | ||
136 | goto out_unlock; | ||
137 | |||
138 | if (alloc_required) { | ||
139 | /* XXX: do we need to drop page lock around alloc_page_backing?*/ | ||
140 | error = alloc_page_backing(ip, vmf->page); | ||
141 | if (error) { | ||
142 | /* | ||
143 | * VM_FAULT_LOCKED should always be the case for | ||
144 | * filemap_fault, but it may not be in a future | ||
145 | * implementation. | ||
146 | */ | ||
147 | if (ret & VM_FAULT_LOCKED) | ||
148 | unlock_page(vmf->page); | ||
149 | page_cache_release(vmf->page); | ||
150 | ret = VM_FAULT_OOM; | ||
151 | goto out_unlock; | ||
152 | } | ||
153 | set_page_dirty(vmf->page); | ||
154 | } | ||
155 | |||
156 | out_unlock: | ||
157 | gfs2_glock_dq_uninit(&i_gh); | ||
158 | out: | ||
159 | return ret; | ||
160 | } | ||
161 | |||
162 | struct vm_operations_struct gfs2_vm_ops_private = { | ||
163 | .fault = gfs2_private_fault, | ||
164 | }; | ||
165 | |||
166 | struct vm_operations_struct gfs2_vm_ops_sharewrite = { | ||
167 | .fault = gfs2_sharewrite_fault, | ||
168 | }; | ||
169 | |||
diff --git a/fs/gfs2/ops_vm.h b/fs/gfs2/ops_vm.h deleted file mode 100644 index 4ae8f43ed5e3..000000000000 --- a/fs/gfs2/ops_vm.h +++ /dev/null | |||
@@ -1,18 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | ||
3 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. | ||
4 | * | ||
5 | * This copyrighted material is made available to anyone wishing to use, | ||
6 | * modify, copy, or redistribute it subject to the terms and conditions | ||
7 | * of the GNU General Public License version 2. | ||
8 | */ | ||
9 | |||
10 | #ifndef __OPS_VM_DOT_H__ | ||
11 | #define __OPS_VM_DOT_H__ | ||
12 | |||
13 | #include <linux/mm.h> | ||
14 | |||
15 | extern struct vm_operations_struct gfs2_vm_ops_private; | ||
16 | extern struct vm_operations_struct gfs2_vm_ops_sharewrite; | ||
17 | |||
18 | #endif /* __OPS_VM_DOT_H__ */ | ||