mm: fix fault vs invalidate race for linear mappings
[deliverable/linux.git] / fs / gfs2 / ops_vm.c
CommitLineData
b3b94faa
DT
1/*
2 * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
3a8a9a10 3 * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
b3b94faa
DT
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
e9fc2aa0 7 * of the GNU General Public License version 2.
b3b94faa
DT
8 */
9
b3b94faa
DT
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>
5c676f6d 16#include <linux/gfs2_ondisk.h>
7d308590 17#include <linux/lm_interface.h>
b3b94faa
DT
18
19#include "gfs2.h"
5c676f6d 20#include "incore.h"
b3b94faa
DT
21#include "bmap.h"
22#include "glock.h"
23#include "inode.h"
24#include "ops_vm.h"
b3b94faa
DT
25#include "quota.h"
26#include "rgrp.h"
27#include "trans.h"
5c676f6d 28#include "util.h"
b3b94faa 29
b3b94faa
DT
30static struct page *gfs2_private_nopage(struct vm_area_struct *area,
31 unsigned long address, int *type)
32{
feaa7bba 33 struct gfs2_inode *ip = GFS2_I(area->vm_file->f_mapping->host);
b3b94faa
DT
34
35 set_bit(GIF_PAGED, &ip->i_flags);
e5dab552 36 return filemap_nopage(area, address, type);
b3b94faa
DT
37}
38
39static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
40{
feaa7bba 41 struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
b3b94faa 42 unsigned long index = page->index;
cd915493 43 u64 lblock = index << (PAGE_CACHE_SHIFT -
568f4c96 44 sdp->sd_sb.sb_bsize_shift);
b3b94faa
DT
45 unsigned int blocks = PAGE_CACHE_SIZE >> sdp->sd_sb.sb_bsize_shift;
46 struct gfs2_alloc *al;
47 unsigned int data_blocks, ind_blocks;
48 unsigned int x;
49 int error;
50
51 al = gfs2_alloc_get(ip);
52
53 error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
54 if (error)
55 goto out;
56
2933f925 57 error = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid);
b3b94faa
DT
58 if (error)
59 goto out_gunlock_q;
60
fd88de56 61 gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks);
b3b94faa
DT
62
63 al->al_requested = data_blocks + ind_blocks;
64
65 error = gfs2_inplace_reserve(ip);
66 if (error)
67 goto out_gunlock_q;
68
bb8d8a6f 69 error = gfs2_trans_begin(sdp, al->al_rgd->rd_length +
b3b94faa
DT
70 ind_blocks + RES_DINODE +
71 RES_STATFS + RES_QUOTA, 0);
72 if (error)
73 goto out_ipres;
74
75 if (gfs2_is_stuffed(ip)) {
f25ef0c1 76 error = gfs2_unstuff_dinode(ip, NULL);
b3b94faa
DT
77 if (error)
78 goto out_trans;
79 }
80
81 for (x = 0; x < blocks; ) {
cd915493 82 u64 dblock;
b3b94faa
DT
83 unsigned int extlen;
84 int new = 1;
85
feaa7bba 86 error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen);
b3b94faa
DT
87 if (error)
88 goto out_trans;
89
90 lblock += extlen;
91 x += extlen;
92 }
93
94 gfs2_assert_warn(sdp, al->al_alloced);
95
a91ea69f 96out_trans:
b3b94faa 97 gfs2_trans_end(sdp);
a91ea69f 98out_ipres:
b3b94faa 99 gfs2_inplace_release(ip);
a91ea69f 100out_gunlock_q:
b3b94faa 101 gfs2_quota_unlock(ip);
a91ea69f 102out:
b3b94faa 103 gfs2_alloc_put(ip);
b3b94faa
DT
104 return error;
105}
106
107static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area,
108 unsigned long address, int *type)
109{
59a1cc6b
SW
110 struct file *file = area->vm_file;
111 struct gfs2_file *gf = file->private_data;
112 struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
b3b94faa
DT
113 struct gfs2_holder i_gh;
114 struct page *result = NULL;
568f4c96
SW
115 unsigned long index = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) +
116 area->vm_pgoff;
b3b94faa
DT
117 int alloc_required;
118 int error;
119
b3b94faa
DT
120 error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
121 if (error)
122 return NULL;
123
b3b94faa
DT
124 set_bit(GIF_PAGED, &ip->i_flags);
125 set_bit(GIF_SW_PAGED, &ip->i_flags);
126
59a1cc6b 127 error = gfs2_write_alloc_required(ip, (u64)index << PAGE_CACHE_SHIFT,
b3b94faa
DT
128 PAGE_CACHE_SIZE, &alloc_required);
129 if (error)
130 goto out;
131
59a1cc6b 132 set_bit(GFF_EXLOCK, &gf->f_flags);
b3b94faa 133 result = filemap_nopage(area, address, type);
59a1cc6b 134 clear_bit(GFF_EXLOCK, &gf->f_flags);
b3b94faa
DT
135 if (!result || result == NOPAGE_OOM)
136 goto out;
137
138 if (alloc_required) {
139 error = alloc_page_backing(ip, result);
140 if (error) {
d00806b1
NP
141 if (area->vm_flags & VM_CAN_INVALIDATE)
142 unlock_page(result);
b3b94faa
DT
143 page_cache_release(result);
144 result = NULL;
145 goto out;
146 }
147 set_page_dirty(result);
148 }
149
59a1cc6b 150out:
b3b94faa
DT
151 gfs2_glock_dq_uninit(&i_gh);
152
153 return result;
154}
155
156struct vm_operations_struct gfs2_vm_ops_private = {
157 .nopage = gfs2_private_nopage,
158};
159
160struct vm_operations_struct gfs2_vm_ops_sharewrite = {
161 .nopage = gfs2_sharewrite_nopage,
162};
163
This page took 0.117812 seconds and 5 git commands to generate.