diff options
Diffstat (limited to 'fs/gfs2/ops_address.c')
-rw-r--r-- | fs/gfs2/ops_address.c | 151 |
1 files changed, 101 insertions, 50 deletions
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 9679f8b9870d..9bb24b1d9c05 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/swap.h> | 20 | #include <linux/swap.h> |
21 | #include <linux/gfs2_ondisk.h> | 21 | #include <linux/gfs2_ondisk.h> |
22 | #include <linux/lm_interface.h> | 22 | #include <linux/lm_interface.h> |
23 | #include <linux/swap.h> | ||
23 | 24 | ||
24 | #include "gfs2.h" | 25 | #include "gfs2.h" |
25 | #include "incore.h" | 26 | #include "incore.h" |
@@ -32,7 +33,6 @@ | |||
32 | #include "quota.h" | 33 | #include "quota.h" |
33 | #include "trans.h" | 34 | #include "trans.h" |
34 | #include "rgrp.h" | 35 | #include "rgrp.h" |
35 | #include "ops_file.h" | ||
36 | #include "super.h" | 36 | #include "super.h" |
37 | #include "util.h" | 37 | #include "util.h" |
38 | #include "glops.h" | 38 | #include "glops.h" |
@@ -231,62 +231,115 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page) | |||
231 | 231 | ||
232 | 232 | ||
233 | /** | 233 | /** |
234 | * gfs2_readpage - readpage with locking | 234 | * __gfs2_readpage - readpage |
235 | * @file: The file to read a page for. N.B. This may be NULL if we are | 235 | * @file: The file to read a page for |
236 | * reading an internal file. | ||
237 | * @page: The page to read | 236 | * @page: The page to read |
238 | * | 237 | * |
239 | * Returns: errno | 238 | * This is the core of gfs2's readpage. Its used by the internal file |
239 | * reading code as in that case we already hold the glock. Also its | ||
240 | * called by gfs2_readpage() once the required lock has been granted. | ||
241 | * | ||
240 | */ | 242 | */ |
241 | 243 | ||
242 | static int gfs2_readpage(struct file *file, struct page *page) | 244 | static int __gfs2_readpage(void *file, struct page *page) |
243 | { | 245 | { |
244 | struct gfs2_inode *ip = GFS2_I(page->mapping->host); | 246 | struct gfs2_inode *ip = GFS2_I(page->mapping->host); |
245 | struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); | 247 | struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); |
246 | struct gfs2_file *gf = NULL; | ||
247 | struct gfs2_holder gh; | ||
248 | int error; | 248 | int error; |
249 | int do_unlock = 0; | ||
250 | |||
251 | if (likely(file != &gfs2_internal_file_sentinel)) { | ||
252 | if (file) { | ||
253 | gf = file->private_data; | ||
254 | if (test_bit(GFF_EXLOCK, &gf->f_flags)) | ||
255 | /* gfs2_sharewrite_fault has grabbed the ip->i_gl already */ | ||
256 | goto skip_lock; | ||
257 | } | ||
258 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh); | ||
259 | do_unlock = 1; | ||
260 | error = gfs2_glock_nq_atime(&gh); | ||
261 | if (unlikely(error)) | ||
262 | goto out_unlock; | ||
263 | } | ||
264 | 249 | ||
265 | skip_lock: | ||
266 | if (gfs2_is_stuffed(ip)) { | 250 | if (gfs2_is_stuffed(ip)) { |
267 | error = stuffed_readpage(ip, page); | 251 | error = stuffed_readpage(ip, page); |
268 | unlock_page(page); | 252 | unlock_page(page); |
269 | } else | 253 | } else { |
270 | error = mpage_readpage(page, gfs2_get_block); | 254 | error = mpage_readpage(page, gfs2_get_block); |
255 | } | ||
271 | 256 | ||
272 | if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) | 257 | if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) |
273 | error = -EIO; | 258 | return -EIO; |
274 | 259 | ||
275 | if (do_unlock) { | 260 | return error; |
276 | gfs2_glock_dq_m(1, &gh); | 261 | } |
277 | gfs2_holder_uninit(&gh); | 262 | |
263 | /** | ||
264 | * gfs2_readpage - read a page of a file | ||
265 | * @file: The file to read | ||
266 | * @page: The page of the file | ||
267 | * | ||
268 | * This deals with the locking required. If the GFF_EXLOCK flags is set | ||
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 | ||
272 | * in the event that we are unable to get the lock. | ||
273 | */ | ||
274 | |||
275 | static int gfs2_readpage(struct file *file, struct page *page) | ||
276 | { | ||
277 | struct gfs2_inode *ip = GFS2_I(page->mapping->host); | ||
278 | struct gfs2_holder gh; | ||
279 | int error; | ||
280 | |||
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); | ||
278 | } | 285 | } |
286 | |||
287 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh); | ||
288 | error = gfs2_glock_nq_atime(&gh); | ||
289 | if (unlikely(error)) { | ||
290 | unlock_page(page); | ||
291 | goto out; | ||
292 | } | ||
293 | error = __gfs2_readpage(file, page); | ||
294 | gfs2_glock_dq(&gh); | ||
279 | out: | 295 | out: |
280 | return error; | 296 | gfs2_holder_uninit(&gh); |
281 | out_unlock: | ||
282 | unlock_page(page); | ||
283 | if (error == GLR_TRYFAILED) { | 297 | if (error == GLR_TRYFAILED) { |
284 | error = AOP_TRUNCATED_PAGE; | ||
285 | yield(); | 298 | yield(); |
299 | return AOP_TRUNCATED_PAGE; | ||
286 | } | 300 | } |
287 | if (do_unlock) | 301 | return error; |
288 | gfs2_holder_uninit(&gh); | 302 | } |
289 | goto out; | 303 | |
304 | /** | ||
305 | * gfs2_internal_read - read an internal file | ||
306 | * @ip: The gfs2 inode | ||
307 | * @ra_state: The readahead state (or NULL for no readahead) | ||
308 | * @buf: The buffer to fill | ||
309 | * @pos: The file position | ||
310 | * @size: The amount to read | ||
311 | * | ||
312 | */ | ||
313 | |||
314 | int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state, | ||
315 | char *buf, loff_t *pos, unsigned size) | ||
316 | { | ||
317 | struct address_space *mapping = ip->i_inode.i_mapping; | ||
318 | unsigned long index = *pos / PAGE_CACHE_SIZE; | ||
319 | unsigned offset = *pos & (PAGE_CACHE_SIZE - 1); | ||
320 | unsigned copied = 0; | ||
321 | unsigned amt; | ||
322 | struct page *page; | ||
323 | void *p; | ||
324 | |||
325 | do { | ||
326 | amt = size - copied; | ||
327 | if (offset + size > PAGE_CACHE_SIZE) | ||
328 | amt = PAGE_CACHE_SIZE - offset; | ||
329 | page = read_cache_page(mapping, index, __gfs2_readpage, NULL); | ||
330 | if (IS_ERR(page)) | ||
331 | return PTR_ERR(page); | ||
332 | p = kmap_atomic(page, KM_USER0); | ||
333 | memcpy(buf + copied, p + offset, amt); | ||
334 | kunmap_atomic(p, KM_USER0); | ||
335 | mark_page_accessed(page); | ||
336 | page_cache_release(page); | ||
337 | copied += amt; | ||
338 | index++; | ||
339 | offset = 0; | ||
340 | } while(copied < size); | ||
341 | (*pos) += size; | ||
342 | return size; | ||
290 | } | 343 | } |
291 | 344 | ||
292 | /** | 345 | /** |
@@ -314,21 +367,19 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping, | |||
314 | int ret = 0; | 367 | int ret = 0; |
315 | int do_unlock = 0; | 368 | int do_unlock = 0; |
316 | 369 | ||
317 | if (likely(file != &gfs2_internal_file_sentinel)) { | 370 | if (file) { |
318 | if (file) { | 371 | struct gfs2_file *gf = file->private_data; |
319 | struct gfs2_file *gf = file->private_data; | 372 | if (test_bit(GFF_EXLOCK, &gf->f_flags)) |
320 | if (test_bit(GFF_EXLOCK, &gf->f_flags)) | 373 | goto skip_lock; |
321 | goto skip_lock; | ||
322 | } | ||
323 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, | ||
324 | LM_FLAG_TRY_1CB|GL_ATIME, &gh); | ||
325 | do_unlock = 1; | ||
326 | ret = gfs2_glock_nq_atime(&gh); | ||
327 | if (ret == GLR_TRYFAILED) | ||
328 | goto out_noerror; | ||
329 | if (unlikely(ret)) | ||
330 | goto out_unlock; | ||
331 | } | 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); | ||
379 | if (ret == GLR_TRYFAILED) | ||
380 | goto out_noerror; | ||
381 | if (unlikely(ret)) | ||
382 | goto out_unlock; | ||
332 | skip_lock: | 383 | skip_lock: |
333 | if (!gfs2_is_stuffed(ip)) | 384 | if (!gfs2_is_stuffed(ip)) |
334 | ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block); | 385 | ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block); |