diff options
-rw-r--r-- | fs/gfs2/file.c | 64 |
1 files changed, 46 insertions, 18 deletions
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 3b65f67bb38e..aa3a4ddb834e 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c | |||
@@ -366,8 +366,15 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
366 | unsigned int data_blocks, ind_blocks, rblocks; | 366 | unsigned int data_blocks, ind_blocks, rblocks; |
367 | struct gfs2_holder gh; | 367 | struct gfs2_holder gh; |
368 | struct gfs2_alloc *al; | 368 | struct gfs2_alloc *al; |
369 | loff_t size; | ||
369 | int ret; | 370 | int ret; |
370 | 371 | ||
372 | /* Wait if fs is frozen. This is racy so we check again later on | ||
373 | * and retry if the fs has been frozen after the page lock has | ||
374 | * been acquired | ||
375 | */ | ||
376 | vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); | ||
377 | |||
371 | gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); | 378 | gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); |
372 | ret = gfs2_glock_nq(&gh); | 379 | ret = gfs2_glock_nq(&gh); |
373 | if (ret) | 380 | if (ret) |
@@ -376,8 +383,15 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
376 | set_bit(GLF_DIRTY, &ip->i_gl->gl_flags); | 383 | set_bit(GLF_DIRTY, &ip->i_gl->gl_flags); |
377 | set_bit(GIF_SW_PAGED, &ip->i_flags); | 384 | set_bit(GIF_SW_PAGED, &ip->i_flags); |
378 | 385 | ||
379 | if (!gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE)) | 386 | if (!gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE)) { |
387 | lock_page(page); | ||
388 | if (!PageUptodate(page) || page->mapping != inode->i_mapping) { | ||
389 | ret = -EAGAIN; | ||
390 | unlock_page(page); | ||
391 | } | ||
380 | goto out_unlock; | 392 | goto out_unlock; |
393 | } | ||
394 | |||
381 | ret = -ENOMEM; | 395 | ret = -ENOMEM; |
382 | al = gfs2_alloc_get(ip); | 396 | al = gfs2_alloc_get(ip); |
383 | if (al == NULL) | 397 | if (al == NULL) |
@@ -405,21 +419,29 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
405 | 419 | ||
406 | lock_page(page); | 420 | lock_page(page); |
407 | ret = -EINVAL; | 421 | ret = -EINVAL; |
408 | last_index = ip->i_inode.i_size >> PAGE_CACHE_SHIFT; | 422 | size = i_size_read(inode); |
409 | if (page->index > last_index) | 423 | last_index = (size - 1) >> PAGE_CACHE_SHIFT; |
410 | goto out_unlock_page; | 424 | /* Check page index against inode size */ |
425 | if (size == 0 || (page->index > last_index)) | ||
426 | goto out_trans_end; | ||
427 | |||
428 | ret = -EAGAIN; | ||
429 | /* If truncated, we must retry the operation, we may have raced | ||
430 | * with the glock demotion code. | ||
431 | */ | ||
432 | if (!PageUptodate(page) || page->mapping != inode->i_mapping) | ||
433 | goto out_trans_end; | ||
434 | |||
435 | /* Unstuff, if required, and allocate backing blocks for page */ | ||
411 | ret = 0; | 436 | ret = 0; |
412 | if (!PageUptodate(page) || page->mapping != ip->i_inode.i_mapping) | 437 | if (gfs2_is_stuffed(ip)) |
413 | goto out_unlock_page; | ||
414 | if (gfs2_is_stuffed(ip)) { | ||
415 | ret = gfs2_unstuff_dinode(ip, page); | 438 | ret = gfs2_unstuff_dinode(ip, page); |
416 | if (ret) | 439 | if (ret == 0) |
417 | goto out_unlock_page; | 440 | ret = gfs2_allocate_page_backing(page); |
418 | } | ||
419 | ret = gfs2_allocate_page_backing(page); | ||
420 | 441 | ||
421 | out_unlock_page: | 442 | out_trans_end: |
422 | unlock_page(page); | 443 | if (ret) |
444 | unlock_page(page); | ||
423 | gfs2_trans_end(sdp); | 445 | gfs2_trans_end(sdp); |
424 | out_trans_fail: | 446 | out_trans_fail: |
425 | gfs2_inplace_release(ip); | 447 | gfs2_inplace_release(ip); |
@@ -431,11 +453,17 @@ out_unlock: | |||
431 | gfs2_glock_dq(&gh); | 453 | gfs2_glock_dq(&gh); |
432 | out: | 454 | out: |
433 | gfs2_holder_uninit(&gh); | 455 | gfs2_holder_uninit(&gh); |
434 | if (ret == -ENOMEM) | 456 | if (ret == 0) { |
435 | ret = VM_FAULT_OOM; | 457 | set_page_dirty(page); |
436 | else if (ret) | 458 | /* This check must be post dropping of transaction lock */ |
437 | ret = VM_FAULT_SIGBUS; | 459 | if (inode->i_sb->s_frozen == SB_UNFROZEN) { |
438 | return ret; | 460 | wait_on_page_writeback(page); |
461 | } else { | ||
462 | ret = -EAGAIN; | ||
463 | unlock_page(page); | ||
464 | } | ||
465 | } | ||
466 | return block_page_mkwrite_return(ret); | ||
439 | } | 467 | } |
440 | 468 | ||
441 | static const struct vm_operations_struct gfs2_vm_ops = { | 469 | static const struct vm_operations_struct gfs2_vm_ops = { |