diff options
| -rw-r--r-- | fs/ext4/ext4.h | 1 | ||||
| -rw-r--r-- | fs/ext4/fsync.c | 83 | ||||
| -rw-r--r-- | fs/ext4/inode.c | 83 |
3 files changed, 83 insertions, 84 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index ac1afc148b36..c0570a68a2bc 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
| @@ -1721,7 +1721,6 @@ extern int ext4_block_truncate_page(handle_t *handle, | |||
| 1721 | struct address_space *mapping, loff_t from); | 1721 | struct address_space *mapping, loff_t from); |
| 1722 | extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf); | 1722 | extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf); |
| 1723 | extern qsize_t *ext4_get_reserved_space(struct inode *inode); | 1723 | extern qsize_t *ext4_get_reserved_space(struct inode *inode); |
| 1724 | extern int flush_completed_IO(struct inode *inode); | ||
| 1725 | extern void ext4_da_update_reserve_space(struct inode *inode, | 1724 | extern void ext4_da_update_reserve_space(struct inode *inode, |
| 1726 | int used, int quota_claim); | 1725 | int used, int quota_claim); |
| 1727 | /* ioctl.c */ | 1726 | /* ioctl.c */ |
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index 592adf2e546e..1c701f635961 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c | |||
| @@ -34,6 +34,89 @@ | |||
| 34 | 34 | ||
| 35 | #include <trace/events/ext4.h> | 35 | #include <trace/events/ext4.h> |
| 36 | 36 | ||
| 37 | static void dump_completed_IO(struct inode * inode) | ||
| 38 | { | ||
| 39 | #ifdef EXT4_DEBUG | ||
| 40 | struct list_head *cur, *before, *after; | ||
| 41 | ext4_io_end_t *io, *io0, *io1; | ||
| 42 | unsigned long flags; | ||
| 43 | |||
| 44 | if (list_empty(&EXT4_I(inode)->i_completed_io_list)){ | ||
| 45 | ext4_debug("inode %lu completed_io list is empty\n", inode->i_ino); | ||
| 46 | return; | ||
| 47 | } | ||
| 48 | |||
| 49 | ext4_debug("Dump inode %lu completed_io list \n", inode->i_ino); | ||
| 50 | spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags); | ||
| 51 | list_for_each_entry(io, &EXT4_I(inode)->i_completed_io_list, list){ | ||
| 52 | cur = &io->list; | ||
| 53 | before = cur->prev; | ||
| 54 | io0 = container_of(before, ext4_io_end_t, list); | ||
| 55 | after = cur->next; | ||
| 56 | io1 = container_of(after, ext4_io_end_t, list); | ||
| 57 | |||
| 58 | ext4_debug("io 0x%p from inode %lu,prev 0x%p,next 0x%p\n", | ||
| 59 | io, inode->i_ino, io0, io1); | ||
| 60 | } | ||
| 61 | spin_unlock_irqrestore(&EXT4_I(inode)->i_completed_io_lock, flags); | ||
| 62 | #endif | ||
| 63 | } | ||
| 64 | |||
| 65 | /* | ||
| 66 | * This function is called from ext4_sync_file(). | ||
| 67 | * | ||
| 68 | * When IO is completed, the work to convert unwritten extents to | ||
| 69 | * written is queued on workqueue but may not get immediately | ||
| 70 | * scheduled. When fsync is called, we need to ensure the | ||
| 71 | * conversion is complete before fsync returns. | ||
| 72 | * The inode keeps track of a list of pending/completed IO that | ||
| 73 | * might needs to do the conversion. This function walks through | ||
| 74 | * the list and convert the related unwritten extents for completed IO | ||
| 75 | * to written. | ||
| 76 | * The function return the number of pending IOs on success. | ||
| 77 | */ | ||
| 78 | static int flush_completed_IO(struct inode *inode) | ||
| 79 | { | ||
| 80 | ext4_io_end_t *io; | ||
| 81 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
| 82 | unsigned long flags; | ||
| 83 | int ret = 0; | ||
| 84 | int ret2 = 0; | ||
| 85 | |||
| 86 | if (list_empty(&ei->i_completed_io_list)) | ||
| 87 | return ret; | ||
| 88 | |||
| 89 | dump_completed_IO(inode); | ||
| 90 | spin_lock_irqsave(&ei->i_completed_io_lock, flags); | ||
| 91 | while (!list_empty(&ei->i_completed_io_list)){ | ||
| 92 | io = list_entry(ei->i_completed_io_list.next, | ||
| 93 | ext4_io_end_t, list); | ||
| 94 | /* | ||
| 95 | * Calling ext4_end_io_nolock() to convert completed | ||
| 96 | * IO to written. | ||
| 97 | * | ||
| 98 | * When ext4_sync_file() is called, run_queue() may already | ||
| 99 | * about to flush the work corresponding to this io structure. | ||
| 100 | * It will be upset if it founds the io structure related | ||
| 101 | * to the work-to-be schedule is freed. | ||
| 102 | * | ||
| 103 | * Thus we need to keep the io structure still valid here after | ||
| 104 | * convertion finished. The io structure has a flag to | ||
| 105 | * avoid double converting from both fsync and background work | ||
| 106 | * queue work. | ||
| 107 | */ | ||
| 108 | spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); | ||
| 109 | ret = ext4_end_io_nolock(io); | ||
| 110 | spin_lock_irqsave(&ei->i_completed_io_lock, flags); | ||
| 111 | if (ret < 0) | ||
| 112 | ret2 = ret; | ||
| 113 | else | ||
| 114 | list_del_init(&io->list); | ||
| 115 | } | ||
| 116 | spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); | ||
| 117 | return (ret2 < 0) ? ret2 : 0; | ||
| 118 | } | ||
| 119 | |||
| 37 | /* | 120 | /* |
| 38 | * If we're not journaling and this is a just-created file, we have to | 121 | * If we're not journaling and this is a just-created file, we have to |
| 39 | * sync our parent directory (if it was freshly created) since | 122 | * sync our parent directory (if it was freshly created) since |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 7a83c2793956..9e60d0b8fa75 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
| @@ -3626,89 +3626,6 @@ static int ext4_get_block_write(struct inode *inode, sector_t iblock, | |||
| 3626 | EXT4_GET_BLOCKS_IO_CREATE_EXT); | 3626 | EXT4_GET_BLOCKS_IO_CREATE_EXT); |
| 3627 | } | 3627 | } |
| 3628 | 3628 | ||
| 3629 | static void dump_completed_IO(struct inode * inode) | ||
| 3630 | { | ||
| 3631 | #ifdef EXT4_DEBUG | ||
| 3632 | struct list_head *cur, *before, *after; | ||
| 3633 | ext4_io_end_t *io, *io0, *io1; | ||
| 3634 | unsigned long flags; | ||
| 3635 | |||
| 3636 | if (list_empty(&EXT4_I(inode)->i_completed_io_list)){ | ||
| 3637 | ext4_debug("inode %lu completed_io list is empty\n", inode->i_ino); | ||
| 3638 | return; | ||
| 3639 | } | ||
| 3640 | |||
| 3641 | ext4_debug("Dump inode %lu completed_io list \n", inode->i_ino); | ||
| 3642 | spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags); | ||
| 3643 | list_for_each_entry(io, &EXT4_I(inode)->i_completed_io_list, list){ | ||
| 3644 | cur = &io->list; | ||
| 3645 | before = cur->prev; | ||
| 3646 | io0 = container_of(before, ext4_io_end_t, list); | ||
| 3647 | after = cur->next; | ||
| 3648 | io1 = container_of(after, ext4_io_end_t, list); | ||
| 3649 | |||
| 3650 | ext4_debug("io 0x%p from inode %lu,prev 0x%p,next 0x%p\n", | ||
| 3651 | io, inode->i_ino, io0, io1); | ||
| 3652 | } | ||
| 3653 | spin_unlock_irqrestore(&EXT4_I(inode)->i_completed_io_lock, flags); | ||
| 3654 | #endif | ||
| 3655 | } | ||
| 3656 | |||
| 3657 | /* | ||
| 3658 | * This function is called from ext4_sync_file(). | ||
| 3659 | * | ||
| 3660 | * When IO is completed, the work to convert unwritten extents to | ||
| 3661 | * written is queued on workqueue but may not get immediately | ||
| 3662 | * scheduled. When fsync is called, we need to ensure the | ||
| 3663 | * conversion is complete before fsync returns. | ||
| 3664 | * The inode keeps track of a list of pending/completed IO that | ||
| 3665 | * might needs to do the conversion. This function walks through | ||
| 3666 | * the list and convert the related unwritten extents for completed IO | ||
| 3667 | * to written. | ||
| 3668 | * The function return the number of pending IOs on success. | ||
| 3669 | */ | ||
| 3670 | int flush_completed_IO(struct inode *inode) | ||
| 3671 | { | ||
| 3672 | ext4_io_end_t *io; | ||
| 3673 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
| 3674 | unsigned long flags; | ||
| 3675 | int ret = 0; | ||
| 3676 | int ret2 = 0; | ||
| 3677 | |||
| 3678 | if (list_empty(&ei->i_completed_io_list)) | ||
| 3679 | return ret; | ||
| 3680 | |||
| 3681 | dump_completed_IO(inode); | ||
| 3682 | spin_lock_irqsave(&ei->i_completed_io_lock, flags); | ||
| 3683 | while (!list_empty(&ei->i_completed_io_list)){ | ||
| 3684 | io = list_entry(ei->i_completed_io_list.next, | ||
| 3685 | ext4_io_end_t, list); | ||
| 3686 | /* | ||
| 3687 | * Calling ext4_end_io_nolock() to convert completed | ||
| 3688 | * IO to written. | ||
| 3689 | * | ||
| 3690 | * When ext4_sync_file() is called, run_queue() may already | ||
| 3691 | * about to flush the work corresponding to this io structure. | ||
| 3692 | * It will be upset if it founds the io structure related | ||
| 3693 | * to the work-to-be schedule is freed. | ||
| 3694 | * | ||
| 3695 | * Thus we need to keep the io structure still valid here after | ||
| 3696 | * convertion finished. The io structure has a flag to | ||
| 3697 | * avoid double converting from both fsync and background work | ||
| 3698 | * queue work. | ||
| 3699 | */ | ||
| 3700 | spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); | ||
| 3701 | ret = ext4_end_io_nolock(io); | ||
| 3702 | spin_lock_irqsave(&ei->i_completed_io_lock, flags); | ||
| 3703 | if (ret < 0) | ||
| 3704 | ret2 = ret; | ||
| 3705 | else | ||
| 3706 | list_del_init(&io->list); | ||
| 3707 | } | ||
| 3708 | spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); | ||
| 3709 | return (ret2 < 0) ? ret2 : 0; | ||
| 3710 | } | ||
| 3711 | |||
| 3712 | static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, | 3629 | static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, |
| 3713 | ssize_t size, void *private, int ret, | 3630 | ssize_t size, void *private, int ret, |
| 3714 | bool is_async) | 3631 | bool is_async) |
