1
2
3
4
5#include <linux/kernel.h>
6#include <linux/file.h>
7#include <linux/fs.h>
8#include <linux/slab.h>
9#include <linux/export.h>
10#include <linux/namei.h>
11#include <linux/sched.h>
12#include <linux/writeback.h>
13#include <linux/syscalls.h>
14#include <linux/linkage.h>
15#include <linux/pagemap.h>
16#include <linux/quotaops.h>
17#include <linux/backing-dev.h>
18#include "internal.h"
19
20#define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \
21 SYNC_FILE_RANGE_WAIT_AFTER)
22
23
24
25
26
27
28
29
30static int __sync_filesystem(struct super_block *sb, int wait)
31{
32
33
34
35
36 if (sb->s_bdi == &noop_backing_dev_info)
37 return 0;
38
39 if (sb->s_qcop && sb->s_qcop->quota_sync)
40 sb->s_qcop->quota_sync(sb, -1, wait);
41
42 if (wait)
43 sync_inodes_sb(sb);
44 else
45 writeback_inodes_sb(sb, WB_REASON_SYNC);
46
47 if (sb->s_op->sync_fs)
48 sb->s_op->sync_fs(sb, wait);
49 return __sync_blockdev(sb->s_bdev, wait);
50}
51
52
53
54
55
56
57int sync_filesystem(struct super_block *sb)
58{
59 int ret;
60
61
62
63
64
65 WARN_ON(!rwsem_is_locked(&sb->s_umount));
66
67
68
69
70 if (sb->s_flags & MS_RDONLY)
71 return 0;
72
73 ret = __sync_filesystem(sb, 0);
74 if (ret < 0)
75 return ret;
76 return __sync_filesystem(sb, 1);
77}
78EXPORT_SYMBOL_GPL(sync_filesystem);
79
80static void sync_one_sb(struct super_block *sb, void *arg)
81{
82 if (!(sb->s_flags & MS_RDONLY))
83 __sync_filesystem(sb, *(int *)arg);
84}
85
86
87
88
89static void sync_filesystems(int wait)
90{
91 iterate_supers(sync_one_sb, &wait);
92}
93
94
95
96
97
98SYSCALL_DEFINE0(sync)
99{
100 wakeup_flusher_threads(0, WB_REASON_SYNC);
101 sync_filesystems(0);
102 sync_filesystems(1);
103 if (unlikely(laptop_mode))
104 laptop_sync_completion();
105 return 0;
106}
107
108static void do_sync_work(struct work_struct *work)
109{
110
111
112
113
114 sync_filesystems(0);
115 sync_filesystems(0);
116 printk("Emergency Sync complete\n");
117 kfree(work);
118}
119
120void emergency_sync(void)
121{
122 struct work_struct *work;
123
124 work = kmalloc(sizeof(*work), GFP_ATOMIC);
125 if (work) {
126 INIT_WORK(work, do_sync_work);
127 schedule_work(work);
128 }
129}
130
131
132
133
134SYSCALL_DEFINE1(syncfs, int, fd)
135{
136 struct file *file;
137 struct super_block *sb;
138 int ret;
139 int fput_needed;
140
141 file = fget_light(fd, &fput_needed);
142 if (!file)
143 return -EBADF;
144 sb = file->f_dentry->d_sb;
145
146 down_read(&sb->s_umount);
147 ret = sync_filesystem(sb);
148 up_read(&sb->s_umount);
149
150 fput_light(file, fput_needed);
151 return ret;
152}
153
154
155
156
157
158
159
160
161
162
163
164
165int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync)
166{
167 if (!file->f_op || !file->f_op->fsync)
168 return -EINVAL;
169 return file->f_op->fsync(file, start, end, datasync);
170}
171EXPORT_SYMBOL(vfs_fsync_range);
172
173
174
175
176
177
178
179
180
181int vfs_fsync(struct file *file, int datasync)
182{
183 return vfs_fsync_range(file, 0, LLONG_MAX, datasync);
184}
185EXPORT_SYMBOL(vfs_fsync);
186
187static int do_fsync(unsigned int fd, int datasync)
188{
189 struct file *file;
190 int ret = -EBADF;
191 int fput_needed;
192
193 file = fget_light(fd, &fput_needed);
194 if (file) {
195 ret = vfs_fsync(file, datasync);
196 fput_light(file, fput_needed);
197 }
198 return ret;
199}
200
201SYSCALL_DEFINE1(fsync, unsigned int, fd)
202{
203 return do_fsync(fd, 0);
204}
205
206SYSCALL_DEFINE1(fdatasync, unsigned int, fd)
207{
208 return do_fsync(fd, 1);
209}
210
211
212
213
214
215
216
217
218
219int generic_write_sync(struct file *file, loff_t pos, loff_t count)
220{
221 if (!(file->f_flags & O_DSYNC) && !IS_SYNC(file->f_mapping->host))
222 return 0;
223 return vfs_fsync_range(file, pos, pos + count - 1,
224 (file->f_flags & __O_SYNC) ? 0 : 1);
225}
226EXPORT_SYMBOL(generic_write_sync);
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275SYSCALL_DEFINE(sync_file_range)(int fd, loff_t offset, loff_t nbytes,
276 unsigned int flags)
277{
278 int ret;
279 struct file *file;
280 struct address_space *mapping;
281 loff_t endbyte;
282 int fput_needed;
283 umode_t i_mode;
284
285 ret = -EINVAL;
286 if (flags & ~VALID_FLAGS)
287 goto out;
288
289 endbyte = offset + nbytes;
290
291 if ((s64)offset < 0)
292 goto out;
293 if ((s64)endbyte < 0)
294 goto out;
295 if (endbyte < offset)
296 goto out;
297
298 if (sizeof(pgoff_t) == 4) {
299 if (offset >= (0x100000000ULL << PAGE_CACHE_SHIFT)) {
300
301
302
303
304 ret = 0;
305 goto out;
306 }
307 if (endbyte >= (0x100000000ULL << PAGE_CACHE_SHIFT)) {
308
309
310
311 nbytes = 0;
312 }
313 }
314
315 if (nbytes == 0)
316 endbyte = LLONG_MAX;
317 else
318 endbyte--;
319
320 ret = -EBADF;
321 file = fget_light(fd, &fput_needed);
322 if (!file)
323 goto out;
324
325 i_mode = file->f_path.dentry->d_inode->i_mode;
326 ret = -ESPIPE;
327 if (!S_ISREG(i_mode) && !S_ISBLK(i_mode) && !S_ISDIR(i_mode) &&
328 !S_ISLNK(i_mode))
329 goto out_put;
330
331 mapping = file->f_mapping;
332 if (!mapping) {
333 ret = -EINVAL;
334 goto out_put;
335 }
336
337 ret = 0;
338 if (flags & SYNC_FILE_RANGE_WAIT_BEFORE) {
339 ret = filemap_fdatawait_range(mapping, offset, endbyte);
340 if (ret < 0)
341 goto out_put;
342 }
343
344 if (flags & SYNC_FILE_RANGE_WRITE) {
345 ret = filemap_fdatawrite_range(mapping, offset, endbyte);
346 if (ret < 0)
347 goto out_put;
348 }
349
350 if (flags & SYNC_FILE_RANGE_WAIT_AFTER)
351 ret = filemap_fdatawait_range(mapping, offset, endbyte);
352
353out_put:
354 fput_light(file, fput_needed);
355out:
356 return ret;
357}
358#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
359asmlinkage long SyS_sync_file_range(long fd, loff_t offset, loff_t nbytes,
360 long flags)
361{
362 return SYSC_sync_file_range((int) fd, offset, nbytes,
363 (unsigned int) flags);
364}
365SYSCALL_ALIAS(sys_sync_file_range, SyS_sync_file_range);
366#endif
367
368
369
370SYSCALL_DEFINE(sync_file_range2)(int fd, unsigned int flags,
371 loff_t offset, loff_t nbytes)
372{
373 return sys_sync_file_range(fd, offset, nbytes, flags);
374}
375#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
376asmlinkage long SyS_sync_file_range2(long fd, long flags,
377 loff_t offset, loff_t nbytes)
378{
379 return SYSC_sync_file_range2((int) fd, (unsigned int) flags,
380 offset, nbytes);
381}
382SYSCALL_ALIAS(sys_sync_file_range2, SyS_sync_file_range2);
383#endif
384