123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- #include <linux/time.h>
- #include <linux/fs.h>
- #include <linux/sched.h>
- #include <linux/writeback.h>
- #include <linux/jbd2.h>
- #include <linux/blkdev.h>
- #include "ext4.h"
- #include "ext4_jbd2.h"
- #include <trace/events/ext4.h>
- static void dump_completed_IO(struct inode * inode)
- {
- #ifdef EXT4FS_DEBUG
- struct list_head *cur, *before, *after;
- ext4_io_end_t *io, *io0, *io1;
- unsigned long flags;
- if (list_empty(&EXT4_I(inode)->i_completed_io_list)){
- ext4_debug("inode %lu completed_io list is empty\n", inode->i_ino);
- return;
- }
- ext4_debug("Dump inode %lu completed_io list \n", inode->i_ino);
- spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags);
- list_for_each_entry(io, &EXT4_I(inode)->i_completed_io_list, list){
- cur = &io->list;
- before = cur->prev;
- io0 = container_of(before, ext4_io_end_t, list);
- after = cur->next;
- io1 = container_of(after, ext4_io_end_t, list);
- ext4_debug("io 0x%p from inode %lu,prev 0x%p,next 0x%p\n",
- io, inode->i_ino, io0, io1);
- }
- spin_unlock_irqrestore(&EXT4_I(inode)->i_completed_io_lock, flags);
- #endif
- }
- int ext4_flush_completed_IO(struct inode *inode)
- {
- ext4_io_end_t *io;
- struct ext4_inode_info *ei = EXT4_I(inode);
- unsigned long flags;
- int ret = 0;
- int ret2 = 0;
- dump_completed_IO(inode);
- spin_lock_irqsave(&ei->i_completed_io_lock, flags);
- while (!list_empty(&ei->i_completed_io_list)){
- io = list_entry(ei->i_completed_io_list.next,
- ext4_io_end_t, list);
- list_del_init(&io->list);
- io->flag |= EXT4_IO_END_IN_FSYNC;
-
- spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
- ret = ext4_end_io_nolock(io);
- if (ret < 0)
- ret2 = ret;
- spin_lock_irqsave(&ei->i_completed_io_lock, flags);
- io->flag &= ~EXT4_IO_END_IN_FSYNC;
- }
- spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
- return (ret2 < 0) ? ret2 : 0;
- }
- static int ext4_sync_parent(struct inode *inode)
- {
- struct writeback_control wbc;
- struct dentry *dentry = NULL;
- struct inode *next;
- int ret = 0;
- if (!ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY))
- return 0;
- inode = igrab(inode);
- while (ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) {
- ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY);
- dentry = d_find_any_alias(inode);
- if (!dentry)
- break;
- next = igrab(dentry->d_parent->d_inode);
- dput(dentry);
- if (!next)
- break;
- iput(inode);
- inode = next;
- ret = sync_mapping_buffers(inode->i_mapping);
- if (ret)
- break;
- memset(&wbc, 0, sizeof(wbc));
- wbc.sync_mode = WB_SYNC_ALL;
- wbc.nr_to_write = 0;
- ret = sync_inode(inode, &wbc);
- if (ret)
- break;
- }
- iput(inode);
- return ret;
- }
- static int __sync_inode(struct inode *inode, int datasync)
- {
- int err;
- int ret;
- ret = sync_mapping_buffers(inode->i_mapping);
- if (!(inode->i_state & I_DIRTY))
- return ret;
- if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
- return ret;
- err = sync_inode_metadata(inode, 1);
- if (ret == 0)
- ret = err;
- return ret;
- }
- int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
- {
- struct inode *inode = file->f_mapping->host;
- struct ext4_inode_info *ei = EXT4_I(inode);
- journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
- int ret;
- tid_t commit_tid;
- bool needs_barrier = false;
- J_ASSERT(ext4_journal_current_handle() == NULL);
- trace_ext4_sync_file_enter(file, datasync);
- ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
- if (ret)
- return ret;
- mutex_lock(&inode->i_mutex);
- if (inode->i_sb->s_flags & MS_RDONLY)
- goto out;
- ret = ext4_flush_completed_IO(inode);
- if (ret < 0)
- goto out;
- if (!journal) {
- ret = __sync_inode(inode, datasync);
- if (!ret && !list_empty(&inode->i_dentry))
- ret = ext4_sync_parent(inode);
- goto out;
- }
-
- if (ext4_should_journal_data(inode)) {
- ret = ext4_force_commit(inode->i_sb);
- goto out;
- }
- commit_tid = datasync ? ei->i_datasync_tid : ei->i_sync_tid;
- if (journal->j_flags & JBD2_BARRIER &&
- !jbd2_trans_will_send_data_barrier(journal, commit_tid))
- needs_barrier = true;
- ret = jbd2_complete_transaction(journal, commit_tid);
- if (needs_barrier)
- blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
- out:
- mutex_unlock(&inode->i_mutex);
- trace_ext4_sync_file_exit(inode, ret);
- return ret;
- }
|