diff options
author | David Teigland <teigland@redhat.com> | 2006-01-16 11:50:04 -0500 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2006-01-16 11:50:04 -0500 |
commit | b3b94faa5fe5968827ba0640ee9fba4b3e7f736e (patch) | |
tree | 70bd6068b050d2c46e338484f8b03fae4365c6c3 /fs/gfs2/ops_vm.c | |
parent | f7825dcf8c7301cfd3724eb40c5b443cc85ab7b8 (diff) |
[GFS2] The core of GFS2
This patch contains all the core files for GFS2.
Signed-off-by: David Teigland <teigland@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/ops_vm.c')
-rw-r--r-- | fs/gfs2/ops_vm.c | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c new file mode 100644 index 000000000000..a1b409ce75e1 --- /dev/null +++ b/fs/gfs2/ops_vm.c | |||
@@ -0,0 +1,199 @@ | |||
1 | /* | ||
2 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | ||
3 | * Copyright (C) 2004-2005 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 v.2. | ||
8 | */ | ||
9 | |||
10 | #include <linux/sched.h> | ||
11 | #include <linux/slab.h> | ||
12 | #include <linux/spinlock.h> | ||
13 | #include <linux/completion.h> | ||
14 | #include <linux/buffer_head.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/pagemap.h> | ||
17 | #include <asm/semaphore.h> | ||
18 | |||
19 | #include "gfs2.h" | ||
20 | #include "bmap.h" | ||
21 | #include "glock.h" | ||
22 | #include "inode.h" | ||
23 | #include "ops_vm.h" | ||
24 | #include "page.h" | ||
25 | #include "quota.h" | ||
26 | #include "rgrp.h" | ||
27 | #include "trans.h" | ||
28 | |||
29 | static void pfault_be_greedy(struct gfs2_inode *ip) | ||
30 | { | ||
31 | unsigned int time; | ||
32 | |||
33 | spin_lock(&ip->i_spin); | ||
34 | time = ip->i_greedy; | ||
35 | ip->i_last_pfault = jiffies; | ||
36 | spin_unlock(&ip->i_spin); | ||
37 | |||
38 | gfs2_inode_hold(ip); | ||
39 | if (gfs2_glock_be_greedy(ip->i_gl, time)) | ||
40 | gfs2_inode_put(ip); | ||
41 | } | ||
42 | |||
43 | static struct page *gfs2_private_nopage(struct vm_area_struct *area, | ||
44 | unsigned long address, int *type) | ||
45 | { | ||
46 | struct gfs2_inode *ip = get_v2ip(area->vm_file->f_mapping->host); | ||
47 | struct gfs2_holder i_gh; | ||
48 | struct page *result; | ||
49 | int error; | ||
50 | |||
51 | atomic_inc(&ip->i_sbd->sd_ops_vm); | ||
52 | |||
53 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh); | ||
54 | if (error) | ||
55 | return NULL; | ||
56 | |||
57 | set_bit(GIF_PAGED, &ip->i_flags); | ||
58 | |||
59 | result = filemap_nopage(area, address, type); | ||
60 | |||
61 | if (result && result != NOPAGE_OOM) | ||
62 | pfault_be_greedy(ip); | ||
63 | |||
64 | gfs2_glock_dq_uninit(&i_gh); | ||
65 | |||
66 | return result; | ||
67 | } | ||
68 | |||
69 | static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) | ||
70 | { | ||
71 | struct gfs2_sbd *sdp = ip->i_sbd; | ||
72 | unsigned long index = page->index; | ||
73 | uint64_t lblock = index << (PAGE_CACHE_SHIFT - sdp->sd_sb.sb_bsize_shift); | ||
74 | unsigned int blocks = PAGE_CACHE_SIZE >> sdp->sd_sb.sb_bsize_shift; | ||
75 | struct gfs2_alloc *al; | ||
76 | unsigned int data_blocks, ind_blocks; | ||
77 | unsigned int x; | ||
78 | int error; | ||
79 | |||
80 | al = gfs2_alloc_get(ip); | ||
81 | |||
82 | error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); | ||
83 | if (error) | ||
84 | goto out; | ||
85 | |||
86 | error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid); | ||
87 | if (error) | ||
88 | goto out_gunlock_q; | ||
89 | |||
90 | gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, | ||
91 | &data_blocks, &ind_blocks); | ||
92 | |||
93 | al->al_requested = data_blocks + ind_blocks; | ||
94 | |||
95 | error = gfs2_inplace_reserve(ip); | ||
96 | if (error) | ||
97 | goto out_gunlock_q; | ||
98 | |||
99 | error = gfs2_trans_begin(sdp, | ||
100 | al->al_rgd->rd_ri.ri_length + | ||
101 | ind_blocks + RES_DINODE + | ||
102 | RES_STATFS + RES_QUOTA, 0); | ||
103 | if (error) | ||
104 | goto out_ipres; | ||
105 | |||
106 | if (gfs2_is_stuffed(ip)) { | ||
107 | error = gfs2_unstuff_dinode(ip, gfs2_unstuffer_page, NULL); | ||
108 | if (error) | ||
109 | goto out_trans; | ||
110 | } | ||
111 | |||
112 | for (x = 0; x < blocks; ) { | ||
113 | uint64_t dblock; | ||
114 | unsigned int extlen; | ||
115 | int new = 1; | ||
116 | |||
117 | error = gfs2_block_map(ip, lblock, &new, &dblock, &extlen); | ||
118 | if (error) | ||
119 | goto out_trans; | ||
120 | |||
121 | lblock += extlen; | ||
122 | x += extlen; | ||
123 | } | ||
124 | |||
125 | gfs2_assert_warn(sdp, al->al_alloced); | ||
126 | |||
127 | out_trans: | ||
128 | gfs2_trans_end(sdp); | ||
129 | |||
130 | out_ipres: | ||
131 | gfs2_inplace_release(ip); | ||
132 | |||
133 | out_gunlock_q: | ||
134 | gfs2_quota_unlock(ip); | ||
135 | |||
136 | out: | ||
137 | gfs2_alloc_put(ip); | ||
138 | |||
139 | return error; | ||
140 | } | ||
141 | |||
142 | static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area, | ||
143 | unsigned long address, int *type) | ||
144 | { | ||
145 | struct gfs2_inode *ip = get_v2ip(area->vm_file->f_mapping->host); | ||
146 | struct gfs2_holder i_gh; | ||
147 | struct page *result = NULL; | ||
148 | unsigned long index = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff; | ||
149 | int alloc_required; | ||
150 | int error; | ||
151 | |||
152 | atomic_inc(&ip->i_sbd->sd_ops_vm); | ||
153 | |||
154 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); | ||
155 | if (error) | ||
156 | return NULL; | ||
157 | |||
158 | if (gfs2_is_jdata(ip)) | ||
159 | goto out; | ||
160 | |||
161 | set_bit(GIF_PAGED, &ip->i_flags); | ||
162 | set_bit(GIF_SW_PAGED, &ip->i_flags); | ||
163 | |||
164 | error = gfs2_write_alloc_required(ip, | ||
165 | (uint64_t)index << PAGE_CACHE_SHIFT, | ||
166 | PAGE_CACHE_SIZE, &alloc_required); | ||
167 | if (error) | ||
168 | goto out; | ||
169 | |||
170 | result = filemap_nopage(area, address, type); | ||
171 | if (!result || result == NOPAGE_OOM) | ||
172 | goto out; | ||
173 | |||
174 | if (alloc_required) { | ||
175 | error = alloc_page_backing(ip, result); | ||
176 | if (error) { | ||
177 | page_cache_release(result); | ||
178 | result = NULL; | ||
179 | goto out; | ||
180 | } | ||
181 | set_page_dirty(result); | ||
182 | } | ||
183 | |||
184 | pfault_be_greedy(ip); | ||
185 | |||
186 | out: | ||
187 | gfs2_glock_dq_uninit(&i_gh); | ||
188 | |||
189 | return result; | ||
190 | } | ||
191 | |||
192 | struct vm_operations_struct gfs2_vm_ops_private = { | ||
193 | .nopage = gfs2_private_nopage, | ||
194 | }; | ||
195 | |||
196 | struct vm_operations_struct gfs2_vm_ops_sharewrite = { | ||
197 | .nopage = gfs2_sharewrite_nopage, | ||
198 | }; | ||
199 | |||