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/module.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
192 file = fget(fd);
193 if (file) {
194 ret = vfs_fsync(file, datasync);
195 fput(file);
196 }
197 return ret;
198}
199
200SYSCALL_DEFINE1(fsync, unsigned int, fd)
201{
202 return do_fsync(fd, 0);
203}
204
205SYSCALL_DEFINE1(fdatasync, unsigned int, fd)
206{
207 return do_fsync(fd, 1);
208}
209
210
211
212
213
214
215
216
217
218int generic_write_sync(struct file *file, loff_t pos, loff_t count)
219{
220 if (!(file->f_flags & O_DSYNC) && !IS_SYNC(file->f_mapping->host))
221 return 0;
222 return vfs_fsync_range(file, pos, pos + count - 1,
223 (file->f_flags & __O_SYNC) ? 0 : 1);
224}
225EXPORT_SYMBOL(generic_write_sync);
226
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
274SYSCALL_DEFINE(sync_file_range)(int fd, loff_t offset, loff_t nbytes,
275 unsigned int flags)
276{
277 int ret;
278 struct file *file;
279 struct address_space *mapping;
280 loff_t endbyte;
281 int fput_needed;
282 umode_t i_mode;
283
284 ret = -EINVAL;
285 if (flags & ~VALID_FLAGS)
286 goto out;
287
288 endbyte = offset + nbytes;
289
290 if ((s64)offset < 0)
291 goto out;
292 if ((s64)endbyte < 0)
293 goto out;
294 if (endbyte < offset)
295 goto out;
296
297 if (sizeof(pgoff_t) == 4) {
298 if (offset >= (0x100000000ULL << PAGE_CACHE_SHIFT)) {
299
300
301
302
303 ret = 0;
304 goto out;
305 }
306 if (endbyte >= (0x100000000ULL << PAGE_CACHE_SHIFT)) {
307
308
309
310 nbytes = 0;
311 }
312 }
313
314 if (nbytes == 0)
315 endbyte = LLONG_MAX;
316 else
317 endbyte--;
318
319 ret = -EBADF;
320 file = fget_light(fd, &fput_needed);
321 if (!file)
322 goto out;
323
324 i_mode = file->f_path.dentry->d_inode->i_mode;
325 ret = -ESPIPE;
326 if (!S_ISREG(i_mode) && !S_ISBLK(i_mode) && !S_ISDIR(i_mode) &&
327 !S_ISLNK(i_mode))
328 goto out_put;
329
330 mapping = file->f_mapping;
331 if (!mapping) {
332 ret = -EINVAL;
333 goto out_put;
334 }
335
336 ret = 0;
337 if (flags & SYNC_FILE_RANGE_WAIT_BEFORE) {
338 ret = filemap_fdatawait_range(mapping, offset, endbyte);
339 if (ret < 0)
340 goto out_put;
341 }
342
343 if (flags & SYNC_FILE_RANGE_WRITE) {
344 ret = filemap_fdatawrite_range(mapping, offset, endbyte);
345 if (ret < 0)
346 goto out_put;
347 }
348
349 if (flags & SYNC_FILE_RANGE_WAIT_AFTER)
350 ret = filemap_fdatawait_range(mapping, offset, endbyte);
351
352out_put:
353 fput_light(file, fput_needed);
354out:
355 return ret;
356}
357#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
358asmlinkage long SyS_sync_file_range(long fd, loff_t offset, loff_t nbytes,
359 long flags)
360{
361 return SYSC_sync_file_range((int) fd, offset, nbytes,
362 (unsigned int) flags);
363}
364SYSCALL_ALIAS(sys_sync_file_range, SyS_sync_file_range);
365#endif
366
367
368
369SYSCALL_DEFINE(sync_file_range2)(int fd, unsigned int flags,
370 loff_t offset, loff_t nbytes)
371{
372 return sys_sync_file_range(fd, offset, nbytes, flags);
373}
374#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
375asmlinkage long SyS_sync_file_range2(long fd, long flags,
376 loff_t offset, loff_t nbytes)
377{
378 return SYSC_sync_file_range2((int) fd, (unsigned int) flags,
379 offset, nbytes);
380}
381SYSCALL_ALIAS(sys_sync_file_range2, SyS_sync_file_range2);
382#endif
383