1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include <linux/time.h>
26#include <linux/fs.h>
27#include <linux/sched.h>
28#include <linux/writeback.h>
29#include <linux/blkdev.h>
30
31#include "ext4.h"
32#include "ext4_jbd2.h"
33
34#include <trace/events/ext4.h>
35
36
37
38
39
40
41
42
43
44static int ext4_sync_parent(struct inode *inode)
45{
46 struct dentry *dentry = NULL;
47 struct inode *next;
48 int ret = 0;
49
50 if (!ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY))
51 return 0;
52 inode = igrab(inode);
53 while (ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) {
54 ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY);
55 dentry = d_find_any_alias(inode);
56 if (!dentry)
57 break;
58 next = igrab(d_inode(dentry->d_parent));
59 dput(dentry);
60 if (!next)
61 break;
62 iput(inode);
63 inode = next;
64 ret = sync_mapping_buffers(inode->i_mapping);
65 if (ret)
66 break;
67 ret = sync_inode_metadata(inode, 1);
68 if (ret)
69 break;
70 }
71 iput(inode);
72 return ret;
73}
74
75
76
77
78
79
80
81
82
83
84
85
86
87int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
88{
89 struct inode *inode = file->f_mapping->host;
90 struct ext4_inode_info *ei = EXT4_I(inode);
91 journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
92 int ret = 0, err;
93 tid_t commit_tid;
94 bool needs_barrier = false;
95
96 J_ASSERT(ext4_journal_current_handle() == NULL);
97
98 trace_ext4_sync_file_enter(file, datasync);
99
100 if (inode->i_sb->s_flags & MS_RDONLY) {
101
102 smp_rmb();
103 if (EXT4_SB(inode->i_sb)->s_mount_flags & EXT4_MF_FS_ABORTED)
104 ret = -EROFS;
105 goto out;
106 }
107
108 if (!journal) {
109 ret = generic_file_fsync(file, start, end, datasync);
110 if (!ret && !hlist_empty(&inode->i_dentry))
111 ret = ext4_sync_parent(inode);
112 goto out;
113 }
114
115 ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
116 if (ret)
117 return ret;
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132 if (ext4_should_journal_data(inode)) {
133 ret = ext4_force_commit(inode->i_sb);
134 goto out;
135 }
136
137 commit_tid = datasync ? ei->i_datasync_tid : ei->i_sync_tid;
138 if (journal->j_flags & JBD2_BARRIER &&
139 !jbd2_trans_will_send_data_barrier(journal, commit_tid))
140 needs_barrier = true;
141 ret = jbd2_complete_transaction(journal, commit_tid);
142 if (needs_barrier) {
143 err = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
144 if (!ret)
145 ret = err;
146 }
147out:
148 trace_ext4_sync_file_exit(inode, ret);
149 return ret;
150}
151