aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/page.c
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2006-01-16 11:50:04 -0500
committerSteven Whitehouse <swhiteho@redhat.com>2006-01-16 11:50:04 -0500
commitb3b94faa5fe5968827ba0640ee9fba4b3e7f736e (patch)
tree70bd6068b050d2c46e338484f8b03fae4365c6c3 /fs/gfs2/page.c
parentf7825dcf8c7301cfd3724eb40c5b443cc85ab7b8 (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/page.c')
-rw-r--r--fs/gfs2/page.c273
1 files changed, 273 insertions, 0 deletions
diff --git a/fs/gfs2/page.c b/fs/gfs2/page.c
new file mode 100644
index 000000000000..05453c5a06f0
--- /dev/null
+++ b/fs/gfs2/page.c
@@ -0,0 +1,273 @@
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/pagemap.h>
16#include <linux/mm.h>
17#include <asm/semaphore.h>
18
19#include "gfs2.h"
20#include "bmap.h"
21#include "inode.h"
22#include "page.h"
23#include "trans.h"
24
25/**
26 * gfs2_pte_inval - Sync and invalidate all PTEs associated with a glock
27 * @gl: the glock
28 *
29 */
30
31void gfs2_pte_inval(struct gfs2_glock *gl)
32{
33 struct gfs2_inode *ip;
34 struct inode *inode;
35
36 ip = get_gl2ip(gl);
37 if (!ip || !S_ISREG(ip->i_di.di_mode))
38 return;
39
40 if (!test_bit(GIF_PAGED, &ip->i_flags))
41 return;
42
43 inode = gfs2_ip2v_lookup(ip);
44 if (inode) {
45 unmap_shared_mapping_range(inode->i_mapping, 0, 0);
46 iput(inode);
47
48 if (test_bit(GIF_SW_PAGED, &ip->i_flags))
49 set_bit(GLF_DIRTY, &gl->gl_flags);
50 }
51
52 clear_bit(GIF_SW_PAGED, &ip->i_flags);
53}
54
55/**
56 * gfs2_page_inval - Invalidate all pages associated with a glock
57 * @gl: the glock
58 *
59 */
60
61void gfs2_page_inval(struct gfs2_glock *gl)
62{
63 struct gfs2_inode *ip;
64 struct inode *inode;
65
66 ip = get_gl2ip(gl);
67 if (!ip || !S_ISREG(ip->i_di.di_mode))
68 return;
69
70 inode = gfs2_ip2v_lookup(ip);
71 if (inode) {
72 struct address_space *mapping = inode->i_mapping;
73
74 truncate_inode_pages(mapping, 0);
75 gfs2_assert_withdraw(ip->i_sbd, !mapping->nrpages);
76
77 iput(inode);
78 }
79
80 clear_bit(GIF_PAGED, &ip->i_flags);
81}
82
83/**
84 * gfs2_page_sync - Sync the data pages (not metadata) associated with a glock
85 * @gl: the glock
86 * @flags: DIO_START | DIO_WAIT
87 *
88 * Syncs data (not metadata) for a regular file.
89 * No-op for all other types.
90 */
91
92void gfs2_page_sync(struct gfs2_glock *gl, int flags)
93{
94 struct gfs2_inode *ip;
95 struct inode *inode;
96
97 ip = get_gl2ip(gl);
98 if (!ip || !S_ISREG(ip->i_di.di_mode))
99 return;
100
101 inode = gfs2_ip2v_lookup(ip);
102 if (inode) {
103 struct address_space *mapping = inode->i_mapping;
104 int error = 0;
105
106 if (flags & DIO_START)
107 filemap_fdatawrite(mapping);
108 if (!error && (flags & DIO_WAIT))
109 error = filemap_fdatawait(mapping);
110
111 /* Put back any errors cleared by filemap_fdatawait()
112 so they can be caught by someone who can pass them
113 up to user space. */
114
115 if (error == -ENOSPC)
116 set_bit(AS_ENOSPC, &mapping->flags);
117 else if (error)
118 set_bit(AS_EIO, &mapping->flags);
119
120 iput(inode);
121 }
122}
123
124/**
125 * gfs2_unstuffer_page - unstuff a stuffed inode into a block cached by a page
126 * @ip: the inode
127 * @dibh: the dinode buffer
128 * @block: the block number that was allocated
129 * @private: any locked page held by the caller process
130 *
131 * Returns: errno
132 */
133
134int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
135 uint64_t block, void *private)
136{
137 struct gfs2_sbd *sdp = ip->i_sbd;
138 struct inode *inode = ip->i_vnode;
139 struct page *page = (struct page *)private;
140 struct buffer_head *bh;
141 int release = 0;
142
143 if (!page || page->index) {
144 page = grab_cache_page(inode->i_mapping, 0);
145 if (!page)
146 return -ENOMEM;
147 release = 1;
148 }
149
150 if (!PageUptodate(page)) {
151 void *kaddr = kmap(page);
152
153 memcpy(kaddr,
154 dibh->b_data + sizeof(struct gfs2_dinode),
155 ip->i_di.di_size);
156 memset(kaddr + ip->i_di.di_size,
157 0,
158 PAGE_CACHE_SIZE - ip->i_di.di_size);
159 kunmap(page);
160
161 SetPageUptodate(page);
162 }
163
164 if (!page_has_buffers(page))
165 create_empty_buffers(page, 1 << inode->i_blkbits,
166 (1 << BH_Uptodate));
167
168 bh = page_buffers(page);
169
170 if (!buffer_mapped(bh))
171 map_bh(bh, inode->i_sb, block);
172
173 set_buffer_uptodate(bh);
174 if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED)
175 gfs2_trans_add_databuf(sdp, bh);
176 mark_buffer_dirty(bh);
177
178 if (release) {
179 unlock_page(page);
180 page_cache_release(page);
181 }
182
183 return 0;
184}
185
186/**
187 * gfs2_truncator_page - truncate a partial data block in the page cache
188 * @ip: the inode
189 * @size: the size the file should be
190 *
191 * Returns: errno
192 */
193
194int gfs2_truncator_page(struct gfs2_inode *ip, uint64_t size)
195{
196 struct gfs2_sbd *sdp = ip->i_sbd;
197 struct inode *inode = ip->i_vnode;
198 struct page *page;
199 struct buffer_head *bh;
200 void *kaddr;
201 uint64_t lbn, dbn;
202 unsigned long index;
203 unsigned int offset;
204 unsigned int bufnum;
205 int new = 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
230 kaddr = kmap(page);
231 memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
232 kunmap(page);
233
234 if (!page_has_buffers(page))
235 create_empty_buffers(page, 1 << inode->i_blkbits,
236 (1 << BH_Uptodate));
237
238 for (bh = page_buffers(page); bufnum--; bh = bh->b_this_page)
239 /* Do nothing */;
240
241 if (!buffer_mapped(bh))
242 map_bh(bh, inode->i_sb, dbn);
243
244 set_buffer_uptodate(bh);
245 if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED)
246 gfs2_trans_add_databuf(sdp, bh);
247 mark_buffer_dirty(bh);
248
249 out:
250 unlock_page(page);
251 page_cache_release(page);
252
253 return error;
254}
255
256void gfs2_page_add_databufs(struct gfs2_sbd *sdp, struct page *page,
257 unsigned int from, unsigned int to)
258{
259 struct buffer_head *head = page_buffers(page);
260 unsigned int bsize = head->b_size;
261 struct buffer_head *bh;
262 unsigned int start, end;
263
264 for (bh = head, start = 0;
265 bh != head || !start;
266 bh = bh->b_this_page, start = end) {
267 end = start + bsize;
268 if (end <= from || start >= to)
269 continue;
270 gfs2_trans_add_databuf(sdp, bh);
271 }
272}
273