diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2007-10-16 04:25:07 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 12:42:55 -0400 |
commit | 7765ec26ae1c01bb29bedf910e4efcced8cc81d2 (patch) | |
tree | 8ce0e877daf805e5e546f10b389cd1c686ec0365 /fs | |
parent | d79689c7038ea07182e8d7340786f7fcf8c77780 (diff) |
gfs2: convert to new aops
Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Cc: Steven Whitehouse <swhiteho@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/gfs2/ops_address.c | 211 |
1 files changed, 127 insertions, 84 deletions
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 873a511ef2be..9679f8b9870d 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/mpage.h> | 17 | #include <linux/mpage.h> |
18 | #include <linux/fs.h> | 18 | #include <linux/fs.h> |
19 | #include <linux/writeback.h> | 19 | #include <linux/writeback.h> |
20 | #include <linux/swap.h> | ||
20 | #include <linux/gfs2_ondisk.h> | 21 | #include <linux/gfs2_ondisk.h> |
21 | #include <linux/lm_interface.h> | 22 | #include <linux/lm_interface.h> |
22 | 23 | ||
@@ -349,45 +350,49 @@ out_unlock: | |||
349 | } | 350 | } |
350 | 351 | ||
351 | /** | 352 | /** |
352 | * gfs2_prepare_write - Prepare to write a page to a file | 353 | * gfs2_write_begin - Begin to write to a file |
353 | * @file: The file to write to | 354 | * @file: The file to write to |
354 | * @page: The page which is to be prepared for writing | 355 | * @mapping: The mapping in which to write |
355 | * @from: From (byte range within page) | 356 | * @pos: The file offset at which to start writing |
356 | * @to: To (byte range within page) | 357 | * @len: Length of the write |
358 | * @flags: Various flags | ||
359 | * @pagep: Pointer to return the page | ||
360 | * @fsdata: Pointer to return fs data (unused by GFS2) | ||
357 | * | 361 | * |
358 | * Returns: errno | 362 | * Returns: errno |
359 | */ | 363 | */ |
360 | 364 | ||
361 | static int gfs2_prepare_write(struct file *file, struct page *page, | 365 | static int gfs2_write_begin(struct file *file, struct address_space *mapping, |
362 | unsigned from, unsigned to) | 366 | loff_t pos, unsigned len, unsigned flags, |
367 | struct page **pagep, void **fsdata) | ||
363 | { | 368 | { |
364 | struct gfs2_inode *ip = GFS2_I(page->mapping->host); | 369 | struct gfs2_inode *ip = GFS2_I(mapping->host); |
365 | struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); | 370 | struct gfs2_sbd *sdp = GFS2_SB(mapping->host); |
366 | unsigned int data_blocks, ind_blocks, rblocks; | 371 | unsigned int data_blocks, ind_blocks, rblocks; |
367 | int alloc_required; | 372 | int alloc_required; |
368 | int error = 0; | 373 | int error = 0; |
369 | loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + from; | ||
370 | loff_t end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; | ||
371 | struct gfs2_alloc *al; | 374 | struct gfs2_alloc *al; |
372 | unsigned int write_len = to - from; | 375 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; |
376 | unsigned from = pos & (PAGE_CACHE_SIZE - 1); | ||
377 | unsigned to = from + len; | ||
378 | struct page *page; | ||
373 | 379 | ||
374 | 380 | gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME, &ip->i_gh); | |
375 | gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME|LM_FLAG_TRY_1CB, &ip->i_gh); | ||
376 | error = gfs2_glock_nq_atime(&ip->i_gh); | 381 | error = gfs2_glock_nq_atime(&ip->i_gh); |
377 | if (unlikely(error)) { | 382 | if (unlikely(error)) |
378 | if (error == GLR_TRYFAILED) { | ||
379 | unlock_page(page); | ||
380 | error = AOP_TRUNCATED_PAGE; | ||
381 | yield(); | ||
382 | } | ||
383 | goto out_uninit; | 383 | goto out_uninit; |
384 | } | ||
385 | 384 | ||
386 | gfs2_write_calc_reserv(ip, write_len, &data_blocks, &ind_blocks); | 385 | error = -ENOMEM; |
386 | page = __grab_cache_page(mapping, index); | ||
387 | *pagep = page; | ||
388 | if (!page) | ||
389 | goto out_unlock; | ||
390 | |||
391 | gfs2_write_calc_reserv(ip, len, &data_blocks, &ind_blocks); | ||
387 | 392 | ||
388 | error = gfs2_write_alloc_required(ip, pos, write_len, &alloc_required); | 393 | error = gfs2_write_alloc_required(ip, pos, len, &alloc_required); |
389 | if (error) | 394 | if (error) |
390 | goto out_unlock; | 395 | goto out_putpage; |
391 | 396 | ||
392 | 397 | ||
393 | ip->i_alloc.al_requested = 0; | 398 | ip->i_alloc.al_requested = 0; |
@@ -420,7 +425,7 @@ static int gfs2_prepare_write(struct file *file, struct page *page, | |||
420 | goto out_trans_fail; | 425 | goto out_trans_fail; |
421 | 426 | ||
422 | if (gfs2_is_stuffed(ip)) { | 427 | if (gfs2_is_stuffed(ip)) { |
423 | if (end > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) { | 428 | if (pos + len > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) { |
424 | error = gfs2_unstuff_dinode(ip, page); | 429 | error = gfs2_unstuff_dinode(ip, page); |
425 | if (error == 0) | 430 | if (error == 0) |
426 | goto prepare_write; | 431 | goto prepare_write; |
@@ -443,6 +448,10 @@ out_qunlock: | |||
443 | out_alloc_put: | 448 | out_alloc_put: |
444 | gfs2_alloc_put(ip); | 449 | gfs2_alloc_put(ip); |
445 | } | 450 | } |
451 | out_putpage: | ||
452 | page_cache_release(page); | ||
453 | if (pos + len > ip->i_inode.i_size) | ||
454 | vmtruncate(&ip->i_inode, ip->i_inode.i_size); | ||
446 | out_unlock: | 455 | out_unlock: |
447 | gfs2_glock_dq_m(1, &ip->i_gh); | 456 | gfs2_glock_dq_m(1, &ip->i_gh); |
448 | out_uninit: | 457 | out_uninit: |
@@ -478,65 +487,117 @@ static void adjust_fs_space(struct inode *inode) | |||
478 | } | 487 | } |
479 | 488 | ||
480 | /** | 489 | /** |
481 | * gfs2_commit_write - Commit write to a file | 490 | * gfs2_stuffed_write_end - Write end for stuffed files |
491 | * @inode: The inode | ||
492 | * @dibh: The buffer_head containing the on-disk inode | ||
493 | * @pos: The file position | ||
494 | * @len: The length of the write | ||
495 | * @copied: How much was actually copied by the VFS | ||
496 | * @page: The page | ||
497 | * | ||
498 | * This copies the data from the page into the inode block after | ||
499 | * the inode data structure itself. | ||
500 | * | ||
501 | * Returns: errno | ||
502 | */ | ||
503 | static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh, | ||
504 | loff_t pos, unsigned len, unsigned copied, | ||
505 | struct page *page) | ||
506 | { | ||
507 | struct gfs2_inode *ip = GFS2_I(inode); | ||
508 | struct gfs2_sbd *sdp = GFS2_SB(inode); | ||
509 | u64 to = pos + copied; | ||
510 | void *kaddr; | ||
511 | unsigned char *buf = dibh->b_data + sizeof(struct gfs2_dinode); | ||
512 | struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data; | ||
513 | |||
514 | BUG_ON((pos + len) > (dibh->b_size - sizeof(struct gfs2_dinode))); | ||
515 | kaddr = kmap_atomic(page, KM_USER0); | ||
516 | memcpy(buf + pos, kaddr + pos, copied); | ||
517 | memset(kaddr + pos + copied, 0, len - copied); | ||
518 | flush_dcache_page(page); | ||
519 | kunmap_atomic(kaddr, KM_USER0); | ||
520 | |||
521 | if (!PageUptodate(page)) | ||
522 | SetPageUptodate(page); | ||
523 | unlock_page(page); | ||
524 | page_cache_release(page); | ||
525 | |||
526 | if (inode->i_size < to) { | ||
527 | i_size_write(inode, to); | ||
528 | ip->i_di.di_size = inode->i_size; | ||
529 | di->di_size = cpu_to_be64(inode->i_size); | ||
530 | mark_inode_dirty(inode); | ||
531 | } | ||
532 | |||
533 | if (inode == sdp->sd_rindex) | ||
534 | adjust_fs_space(inode); | ||
535 | |||
536 | brelse(dibh); | ||
537 | gfs2_trans_end(sdp); | ||
538 | gfs2_glock_dq(&ip->i_gh); | ||
539 | gfs2_holder_uninit(&ip->i_gh); | ||
540 | return copied; | ||
541 | } | ||
542 | |||
543 | /** | ||
544 | * gfs2_write_end | ||
482 | * @file: The file to write to | 545 | * @file: The file to write to |
483 | * @page: The page containing the data | 546 | * @mapping: The address space to write to |
484 | * @from: From (byte range within page) | 547 | * @pos: The file position |
485 | * @to: To (byte range within page) | 548 | * @len: The length of the data |
549 | * @copied: | ||
550 | * @page: The page that has been written | ||
551 | * @fsdata: The fsdata (unused in GFS2) | ||
552 | * | ||
553 | * The main write_end function for GFS2. We have a separate one for | ||
554 | * stuffed files as they are slightly different, otherwise we just | ||
555 | * put our locking around the VFS provided functions. | ||
486 | * | 556 | * |
487 | * Returns: errno | 557 | * Returns: errno |
488 | */ | 558 | */ |
489 | 559 | ||
490 | static int gfs2_commit_write(struct file *file, struct page *page, | 560 | static int gfs2_write_end(struct file *file, struct address_space *mapping, |
491 | unsigned from, unsigned to) | 561 | loff_t pos, unsigned len, unsigned copied, |
562 | struct page *page, void *fsdata) | ||
492 | { | 563 | { |
493 | struct inode *inode = page->mapping->host; | 564 | struct inode *inode = page->mapping->host; |
494 | struct gfs2_inode *ip = GFS2_I(inode); | 565 | struct gfs2_inode *ip = GFS2_I(inode); |
495 | struct gfs2_sbd *sdp = GFS2_SB(inode); | 566 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
496 | int error = -EOPNOTSUPP; | ||
497 | struct buffer_head *dibh; | 567 | struct buffer_head *dibh; |
498 | struct gfs2_alloc *al = &ip->i_alloc; | 568 | struct gfs2_alloc *al = &ip->i_alloc; |
499 | struct gfs2_dinode *di; | 569 | struct gfs2_dinode *di; |
570 | unsigned int from = pos & (PAGE_CACHE_SIZE - 1); | ||
571 | unsigned int to = from + len; | ||
572 | int ret; | ||
500 | 573 | ||
501 | if (gfs2_assert_withdraw(sdp, gfs2_glock_is_locked_by_me(ip->i_gl))) | 574 | BUG_ON(gfs2_glock_is_locked_by_me(ip->i_gl) == 0); |
502 | goto fail_nounlock; | ||
503 | 575 | ||
504 | error = gfs2_meta_inode_buffer(ip, &dibh); | 576 | ret = gfs2_meta_inode_buffer(ip, &dibh); |
505 | if (error) | 577 | if (unlikely(ret)) { |
506 | goto fail_endtrans; | 578 | unlock_page(page); |
579 | page_cache_release(page); | ||
580 | goto failed; | ||
581 | } | ||
507 | 582 | ||
508 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | 583 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); |
509 | di = (struct gfs2_dinode *)dibh->b_data; | ||
510 | |||
511 | if (gfs2_is_stuffed(ip)) { | ||
512 | u64 file_size; | ||
513 | void *kaddr; | ||
514 | 584 | ||
515 | file_size = ((u64)page->index << PAGE_CACHE_SHIFT) + to; | 585 | if (gfs2_is_stuffed(ip)) |
586 | return gfs2_stuffed_write_end(inode, dibh, pos, len, copied, page); | ||
516 | 587 | ||
517 | kaddr = kmap_atomic(page, KM_USER0); | 588 | if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) |
518 | memcpy(dibh->b_data + sizeof(struct gfs2_dinode) + from, | 589 | gfs2_page_add_databufs(ip, page, from, to); |
519 | kaddr + from, to - from); | ||
520 | kunmap_atomic(kaddr, KM_USER0); | ||
521 | 590 | ||
522 | SetPageUptodate(page); | 591 | ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata); |
523 | 592 | ||
524 | if (inode->i_size < file_size) { | 593 | if (likely(ret >= 0)) { |
525 | i_size_write(inode, file_size); | 594 | copied = ret; |
595 | if ((pos + copied) > inode->i_size) { | ||
596 | di = (struct gfs2_dinode *)dibh->b_data; | ||
597 | ip->i_di.di_size = inode->i_size; | ||
598 | di->di_size = cpu_to_be64(inode->i_size); | ||
526 | mark_inode_dirty(inode); | 599 | mark_inode_dirty(inode); |
527 | } | 600 | } |
528 | } else { | ||
529 | if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || | ||
530 | gfs2_is_jdata(ip)) | ||
531 | gfs2_page_add_databufs(ip, page, from, to); | ||
532 | error = generic_commit_write(file, page, from, to); | ||
533 | if (error) | ||
534 | goto fail; | ||
535 | } | ||
536 | |||
537 | if (ip->i_di.di_size < inode->i_size) { | ||
538 | ip->i_di.di_size = inode->i_size; | ||
539 | di->di_size = cpu_to_be64(inode->i_size); | ||
540 | } | 601 | } |
541 | 602 | ||
542 | if (inode == sdp->sd_rindex) | 603 | if (inode == sdp->sd_rindex) |
@@ -544,33 +605,15 @@ static int gfs2_commit_write(struct file *file, struct page *page, | |||
544 | 605 | ||
545 | brelse(dibh); | 606 | brelse(dibh); |
546 | gfs2_trans_end(sdp); | 607 | gfs2_trans_end(sdp); |
608 | failed: | ||
547 | if (al->al_requested) { | 609 | if (al->al_requested) { |
548 | gfs2_inplace_release(ip); | 610 | gfs2_inplace_release(ip); |
549 | gfs2_quota_unlock(ip); | 611 | gfs2_quota_unlock(ip); |
550 | gfs2_alloc_put(ip); | 612 | gfs2_alloc_put(ip); |
551 | } | 613 | } |
552 | unlock_page(page); | 614 | gfs2_glock_dq(&ip->i_gh); |
553 | gfs2_glock_dq_m(1, &ip->i_gh); | ||
554 | lock_page(page); | ||
555 | gfs2_holder_uninit(&ip->i_gh); | 615 | gfs2_holder_uninit(&ip->i_gh); |
556 | return 0; | 616 | return ret; |
557 | |||
558 | fail: | ||
559 | brelse(dibh); | ||
560 | fail_endtrans: | ||
561 | gfs2_trans_end(sdp); | ||
562 | if (al->al_requested) { | ||
563 | gfs2_inplace_release(ip); | ||
564 | gfs2_quota_unlock(ip); | ||
565 | gfs2_alloc_put(ip); | ||
566 | } | ||
567 | unlock_page(page); | ||
568 | gfs2_glock_dq_m(1, &ip->i_gh); | ||
569 | lock_page(page); | ||
570 | gfs2_holder_uninit(&ip->i_gh); | ||
571 | fail_nounlock: | ||
572 | ClearPageUptodate(page); | ||
573 | return error; | ||
574 | } | 617 | } |
575 | 618 | ||
576 | /** | 619 | /** |
@@ -799,8 +842,8 @@ const struct address_space_operations gfs2_file_aops = { | |||
799 | .readpage = gfs2_readpage, | 842 | .readpage = gfs2_readpage, |
800 | .readpages = gfs2_readpages, | 843 | .readpages = gfs2_readpages, |
801 | .sync_page = block_sync_page, | 844 | .sync_page = block_sync_page, |
802 | .prepare_write = gfs2_prepare_write, | 845 | .write_begin = gfs2_write_begin, |
803 | .commit_write = gfs2_commit_write, | 846 | .write_end = gfs2_write_end, |
804 | .set_page_dirty = gfs2_set_page_dirty, | 847 | .set_page_dirty = gfs2_set_page_dirty, |
805 | .bmap = gfs2_bmap, | 848 | .bmap = gfs2_bmap, |
806 | .invalidatepage = gfs2_invalidatepage, | 849 | .invalidatepage = gfs2_invalidatepage, |