blob: b93caf294b9f49e7e6429bf2fcc3cb3e3d42acdb [file] [log] [blame]
David Teiglandb3b94fa2006-01-16 16:50:04 +00001/*
2 * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
Steven Whitehouse3a8a9a12006-05-18 15:09:15 -04003 * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
David Teiglandb3b94fa2006-01-16 16:50:04 +00004 *
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>
Steven Whitehouse5c676f62006-02-27 17:23:27 -050017#include <linux/gfs2_ondisk.h>
David Teiglandb3b94fa2006-01-16 16:50:04 +000018
19#include "gfs2.h"
Steven Whitehouse5c676f62006-02-27 17:23:27 -050020#include "lm_interface.h"
21#include "incore.h"
David Teiglandb3b94fa2006-01-16 16:50:04 +000022#include "bmap.h"
23#include "inode.h"
24#include "page.h"
25#include "trans.h"
Steven Whitehouse257f9b42006-01-31 10:00:25 +000026#include "ops_address.h"
Steven Whitehouse5c676f62006-02-27 17:23:27 -050027#include "util.h"
David Teiglandb3b94fa2006-01-16 16:50:04 +000028
29/**
30 * gfs2_pte_inval - Sync and invalidate all PTEs associated with a glock
31 * @gl: the glock
32 *
33 */
34
35void gfs2_pte_inval(struct gfs2_glock *gl)
36{
37 struct gfs2_inode *ip;
38 struct inode *inode;
39
Steven Whitehouse5c676f62006-02-27 17:23:27 -050040 ip = gl->gl_object;
Steven Whitehousefeaa7bb2006-06-14 15:32:57 -040041 inode = &ip->i_inode;
David Teiglandb3b94fa2006-01-16 16:50:04 +000042 if (!ip || !S_ISREG(ip->i_di.di_mode))
43 return;
44
45 if (!test_bit(GIF_PAGED, &ip->i_flags))
46 return;
47
Steven Whitehousefeaa7bb2006-06-14 15:32:57 -040048 unmap_shared_mapping_range(inode->i_mapping, 0, 0);
David Teiglandb3b94fa2006-01-16 16:50:04 +000049
Steven Whitehousefeaa7bb2006-06-14 15:32:57 -040050 if (test_bit(GIF_SW_PAGED, &ip->i_flags))
51 set_bit(GLF_DIRTY, &gl->gl_flags);
David Teiglandb3b94fa2006-01-16 16:50:04 +000052
53 clear_bit(GIF_SW_PAGED, &ip->i_flags);
54}
55
56/**
57 * gfs2_page_inval - Invalidate all pages associated with a glock
58 * @gl: the glock
59 *
60 */
61
62void gfs2_page_inval(struct gfs2_glock *gl)
63{
64 struct gfs2_inode *ip;
65 struct inode *inode;
66
Steven Whitehouse5c676f62006-02-27 17:23:27 -050067 ip = gl->gl_object;
Steven Whitehousefeaa7bb2006-06-14 15:32:57 -040068 inode = &ip->i_inode;
David Teiglandb3b94fa2006-01-16 16:50:04 +000069 if (!ip || !S_ISREG(ip->i_di.di_mode))
70 return;
71
Steven Whitehousefeaa7bb2006-06-14 15:32:57 -040072 truncate_inode_pages(inode->i_mapping, 0);
73 gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), !inode->i_mapping->nrpages);
David Teiglandb3b94fa2006-01-16 16:50:04 +000074 clear_bit(GIF_PAGED, &ip->i_flags);
75}
76
77/**
78 * gfs2_page_sync - Sync the data pages (not metadata) associated with a glock
79 * @gl: the glock
80 * @flags: DIO_START | DIO_WAIT
81 *
82 * Syncs data (not metadata) for a regular file.
83 * No-op for all other types.
84 */
85
86void gfs2_page_sync(struct gfs2_glock *gl, int flags)
87{
88 struct gfs2_inode *ip;
89 struct inode *inode;
Steven Whitehousefeaa7bb2006-06-14 15:32:57 -040090 struct address_space *mapping;
91 int error = 0;
David Teiglandb3b94fa2006-01-16 16:50:04 +000092
Steven Whitehouse5c676f62006-02-27 17:23:27 -050093 ip = gl->gl_object;
Steven Whitehousefeaa7bb2006-06-14 15:32:57 -040094 inode = &ip->i_inode;
David Teiglandb3b94fa2006-01-16 16:50:04 +000095 if (!ip || !S_ISREG(ip->i_di.di_mode))
96 return;
97
Steven Whitehousefeaa7bb2006-06-14 15:32:57 -040098 mapping = inode->i_mapping;
David Teiglandb3b94fa2006-01-16 16:50:04 +000099
Steven Whitehousefeaa7bb2006-06-14 15:32:57 -0400100 if (flags & DIO_START)
101 filemap_fdatawrite(mapping);
102 if (!error && (flags & DIO_WAIT))
103 error = filemap_fdatawait(mapping);
David Teiglandb3b94fa2006-01-16 16:50:04 +0000104
Steven Whitehousefeaa7bb2006-06-14 15:32:57 -0400105 /* Put back any errors cleared by filemap_fdatawait()
106 so they can be caught by someone who can pass them
107 up to user space. */
David Teiglandb3b94fa2006-01-16 16:50:04 +0000108
Steven Whitehousefeaa7bb2006-06-14 15:32:57 -0400109 if (error == -ENOSPC)
110 set_bit(AS_ENOSPC, &mapping->flags);
111 else if (error)
112 set_bit(AS_EIO, &mapping->flags);
David Teiglandb3b94fa2006-01-16 16:50:04 +0000113
David Teiglandb3b94fa2006-01-16 16:50:04 +0000114}
115
116/**
117 * gfs2_unstuffer_page - unstuff a stuffed inode into a block cached by a page
118 * @ip: the inode
119 * @dibh: the dinode buffer
120 * @block: the block number that was allocated
121 * @private: any locked page held by the caller process
122 *
123 * Returns: errno
124 */
125
126int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
127 uint64_t block, void *private)
128{
Steven Whitehousefeaa7bb2006-06-14 15:32:57 -0400129 struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
130 struct inode *inode = &ip->i_inode;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000131 struct page *page = (struct page *)private;
132 struct buffer_head *bh;
133 int release = 0;
134
135 if (!page || page->index) {
136 page = grab_cache_page(inode->i_mapping, 0);
137 if (!page)
138 return -ENOMEM;
139 release = 1;
140 }
141
142 if (!PageUptodate(page)) {
143 void *kaddr = kmap(page);
144
Steven Whitehouse1b502592006-05-18 14:10:52 -0400145 memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode),
David Teiglandb3b94fa2006-01-16 16:50:04 +0000146 ip->i_di.di_size);
Steven Whitehouse1b502592006-05-18 14:10:52 -0400147 memset(kaddr + ip->i_di.di_size, 0,
David Teiglandb3b94fa2006-01-16 16:50:04 +0000148 PAGE_CACHE_SIZE - ip->i_di.di_size);
149 kunmap(page);
150
151 SetPageUptodate(page);
152 }
153
154 if (!page_has_buffers(page))
155 create_empty_buffers(page, 1 << inode->i_blkbits,
156 (1 << BH_Uptodate));
157
158 bh = page_buffers(page);
159
160 if (!buffer_mapped(bh))
161 map_bh(bh, inode->i_sb, block);
162
163 set_buffer_uptodate(bh);
Steven Whitehouse18ec7d52006-02-08 11:50:51 +0000164 if ((sdp->sd_args.ar_data == GFS2_DATA_ORDERED) || gfs2_is_jdata(ip))
165 gfs2_trans_add_bh(ip->i_gl, bh, 0);
David Teiglandb3b94fa2006-01-16 16:50:04 +0000166 mark_buffer_dirty(bh);
167
168 if (release) {
169 unlock_page(page);
170 page_cache_release(page);
171 }
172
173 return 0;
174}
175
176/**
Steven Whitehouse257f9b42006-01-31 10:00:25 +0000177 * gfs2_block_truncate_page - Deal with zeroing out data for truncate
David Teiglandb3b94fa2006-01-16 16:50:04 +0000178 *
Steven Whitehouse257f9b42006-01-31 10:00:25 +0000179 * This is partly borrowed from ext3.
David Teiglandb3b94fa2006-01-16 16:50:04 +0000180 */
Steven Whitehouse257f9b42006-01-31 10:00:25 +0000181int gfs2_block_truncate_page(struct address_space *mapping)
David Teiglandb3b94fa2006-01-16 16:50:04 +0000182{
Steven Whitehouse257f9b42006-01-31 10:00:25 +0000183 struct inode *inode = mapping->host;
Steven Whitehousefeaa7bb2006-06-14 15:32:57 -0400184 struct gfs2_inode *ip = GFS2_I(inode);
185 struct gfs2_sbd *sdp = GFS2_SB(inode);
Steven Whitehouse257f9b42006-01-31 10:00:25 +0000186 loff_t from = inode->i_size;
187 unsigned long index = from >> PAGE_CACHE_SHIFT;
188 unsigned offset = from & (PAGE_CACHE_SIZE-1);
189 unsigned blocksize, iblock, length, pos;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000190 struct buffer_head *bh;
Steven Whitehouse257f9b42006-01-31 10:00:25 +0000191 struct page *page;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000192 void *kaddr;
Steven Whitehouse257f9b42006-01-31 10:00:25 +0000193 int err;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000194
Steven Whitehouse257f9b42006-01-31 10:00:25 +0000195 page = grab_cache_page(mapping, index);
196 if (!page)
197 return 0;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000198
Steven Whitehouse257f9b42006-01-31 10:00:25 +0000199 blocksize = inode->i_sb->s_blocksize;
200 length = blocksize - (offset & (blocksize - 1));
201 iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
David Teiglandb3b94fa2006-01-16 16:50:04 +0000202
203 if (!page_has_buffers(page))
Steven Whitehouse257f9b42006-01-31 10:00:25 +0000204 create_empty_buffers(page, blocksize, 0);
David Teiglandb3b94fa2006-01-16 16:50:04 +0000205
Steven Whitehouse257f9b42006-01-31 10:00:25 +0000206 /* Find the buffer that contains "offset" */
207 bh = page_buffers(page);
208 pos = blocksize;
209 while (offset >= pos) {
210 bh = bh->b_this_page;
211 iblock++;
212 pos += blocksize;
213 }
David Teiglandb3b94fa2006-01-16 16:50:04 +0000214
Steven Whitehouse257f9b42006-01-31 10:00:25 +0000215 err = 0;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000216
Steven Whitehouse257f9b42006-01-31 10:00:25 +0000217 if (!buffer_mapped(bh)) {
218 gfs2_get_block(inode, iblock, bh, 0);
219 /* unmapped? It's a hole - nothing to do */
220 if (!buffer_mapped(bh))
221 goto unlock;
222 }
223
224 /* Ok, it's mapped. Make sure it's up-to-date */
225 if (PageUptodate(page))
226 set_buffer_uptodate(bh);
227
228 if (!buffer_uptodate(bh)) {
229 err = -EIO;
230 ll_rw_block(READ, 1, &bh);
231 wait_on_buffer(bh);
232 /* Uhhuh. Read error. Complain and punt. */
233 if (!buffer_uptodate(bh))
234 goto unlock;
235 }
236
Steven Whitehouse18ec7d52006-02-08 11:50:51 +0000237 if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
238 gfs2_trans_add_bh(ip->i_gl, bh, 0);
David Teiglandb3b94fa2006-01-16 16:50:04 +0000239
Steven Whitehouse257f9b42006-01-31 10:00:25 +0000240 kaddr = kmap_atomic(page, KM_USER0);
241 memset(kaddr + offset, 0, length);
242 flush_dcache_page(page);
243 kunmap_atomic(kaddr, KM_USER0);
244
245unlock:
David Teiglandb3b94fa2006-01-16 16:50:04 +0000246 unlock_page(page);
247 page_cache_release(page);
Steven Whitehouse257f9b42006-01-31 10:00:25 +0000248 return err;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000249}
250
Steven Whitehouse257f9b42006-01-31 10:00:25 +0000251void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page,
David Teiglandb3b94fa2006-01-16 16:50:04 +0000252 unsigned int from, unsigned int to)
253{
254 struct buffer_head *head = page_buffers(page);
255 unsigned int bsize = head->b_size;
256 struct buffer_head *bh;
257 unsigned int start, end;
258
Steven Whitehouse29937ac2006-07-06 17:58:03 -0400259 for (bh = head, start = 0; bh != head || !start;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000260 bh = bh->b_this_page, start = end) {
261 end = start + bsize;
262 if (end <= from || start >= to)
263 continue;
Steven Whitehouse18ec7d52006-02-08 11:50:51 +0000264 gfs2_trans_add_bh(ip->i_gl, bh, 0);
David Teiglandb3b94fa2006-01-16 16:50:04 +0000265 }
266}
267