1
2
3
4
5#include <linux/kernel.h>
6#include <linux/file.h>
7#include <linux/fs.h>
8#include <linux/module.h>
9#include <linux/sched.h>
10#include <linux/writeback.h>
11#include <linux/syscalls.h>
12#include <linux/linkage.h>
13#include <linux/pagemap.h>
14#include <linux/quotaops.h>
15#include <linux/buffer_head.h>
16
17#define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \
18 SYNC_FILE_RANGE_WAIT_AFTER)
19
20
21
22
23
24static void do_sync(unsigned long wait)
25{
26 wakeup_pdflush(0);
27 sync_inodes(0);
28 DQUOT_SYNC(NULL);
29 sync_supers();
30 sync_filesystems(0);
31 sync_filesystems(wait);
32 sync_inodes(wait);
33 if (!wait)
34 printk("Emergency Sync complete\n");
35 if (unlikely(laptop_mode))
36 laptop_sync_completion();
37}
38
39asmlinkage long sys_sync(void)
40{
41 do_sync(1);
42 return 0;
43}
44
45void emergency_sync(void)
46{
47 pdflush_operation(do_sync, 0);
48}
49
50
51
52
53
54
55int file_fsync(struct file *filp, struct dentry *dentry, int datasync)
56{
57 struct inode * inode = dentry->d_inode;
58 struct super_block * sb;
59 int ret, err;
60
61
62 ret = write_inode_now(inode, 0);
63
64
65 sb = inode->i_sb;
66 lock_super(sb);
67 if (sb->s_op->write_super)
68 sb->s_op->write_super(sb);
69 unlock_super(sb);
70
71
72 err = sync_blockdev(sb->s_bdev);
73 if (!ret)
74 ret = err;
75 return ret;
76}
77
78long do_fsync(struct file *file, int datasync)
79{
80 int ret;
81 int err;
82 struct address_space *mapping = file->f_mapping;
83
84 if (!file->f_op || !file->f_op->fsync) {
85
86 ret = -EINVAL;
87 goto out;
88 }
89
90 ret = filemap_fdatawrite(mapping);
91
92
93
94
95
96 mutex_lock(&mapping->host->i_mutex);
97 err = file->f_op->fsync(file, file->f_path.dentry, datasync);
98 if (!ret)
99 ret = err;
100 mutex_unlock(&mapping->host->i_mutex);
101 err = filemap_fdatawait(mapping);
102 if (!ret)
103 ret = err;
104out:
105 return ret;
106}
107
108static long __do_fsync(unsigned int fd, int datasync)
109{
110 struct file *file;
111 int ret = -EBADF;
112
113 file = fget(fd);
114 if (file) {
115 ret = do_fsync(file, datasync);
116 fput(file);
117 }
118 return ret;
119}
120
121asmlinkage long sys_fsync(unsigned int fd)
122{
123 return __do_fsync(fd, 0);
124}
125
126asmlinkage long sys_fdatasync(unsigned int fd)
127{
128 return __do_fsync(fd, 1);
129}
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
178 unsigned int flags)
179{
180 int ret;
181 struct file *file;
182 loff_t endbyte;
183 int fput_needed;
184 umode_t i_mode;
185
186 ret = -EINVAL;
187 if (flags & ~VALID_FLAGS)
188 goto out;
189
190 endbyte = offset + nbytes;
191
192 if ((s64)offset < 0)
193 goto out;
194 if ((s64)endbyte < 0)
195 goto out;
196 if (endbyte < offset)
197 goto out;
198
199 if (sizeof(pgoff_t) == 4) {
200 if (offset >= (0x100000000ULL << PAGE_CACHE_SHIFT)) {
201
202
203
204
205 ret = 0;
206 goto out;
207 }
208 if (endbyte >= (0x100000000ULL << PAGE_CACHE_SHIFT)) {
209
210
211
212 nbytes = 0;
213 }
214 }
215
216 if (nbytes == 0)
217 endbyte = LLONG_MAX;
218 else
219 endbyte--;
220
221 ret = -EBADF;
222 file = fget_light(fd, &fput_needed);
223 if (!file)
224 goto out;
225
226 i_mode = file->f_path.dentry->d_inode->i_mode;
227 ret = -ESPIPE;
228 if (!S_ISREG(i_mode) && !S_ISBLK(i_mode) && !S_ISDIR(i_mode) &&
229 !S_ISLNK(i_mode))
230 goto out_put;
231
232 ret = do_sync_mapping_range(file->f_mapping, offset, endbyte, flags);
233out_put:
234 fput_light(file, fput_needed);
235out:
236 return ret;
237}
238
239
240
241asmlinkage long sys_sync_file_range2(int fd, unsigned int flags,
242 loff_t offset, loff_t nbytes)
243{
244 return sys_sync_file_range(fd, offset, nbytes, flags);
245}
246
247
248
249
250int do_sync_mapping_range(struct address_space *mapping, loff_t offset,
251 loff_t endbyte, unsigned int flags)
252{
253 int ret;
254
255 if (!mapping) {
256 ret = -EINVAL;
257 goto out;
258 }
259
260 ret = 0;
261 if (flags & SYNC_FILE_RANGE_WAIT_BEFORE) {
262 ret = wait_on_page_writeback_range(mapping,
263 offset >> PAGE_CACHE_SHIFT,
264 endbyte >> PAGE_CACHE_SHIFT);
265 if (ret < 0)
266 goto out;
267 }
268
269 if (flags & SYNC_FILE_RANGE_WRITE) {
270 ret = __filemap_fdatawrite_range(mapping, offset, endbyte,
271 WB_SYNC_NONE);
272 if (ret < 0)
273 goto out;
274 }
275
276 if (flags & SYNC_FILE_RANGE_WAIT_AFTER) {
277 ret = wait_on_page_writeback_range(mapping,
278 offset >> PAGE_CACHE_SHIFT,
279 endbyte >> PAGE_CACHE_SHIFT);
280 }
281out:
282 return ret;
283}
284EXPORT_SYMBOL_GPL(do_sync_mapping_range);
285