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_dirt && 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
177
178asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
179 unsigned int flags)
180{
181 int ret;
182 struct file *file;
183 loff_t endbyte;
184 int fput_needed;
185 umode_t i_mode;
186
187 ret = -EINVAL;
188 if (flags & ~VALID_FLAGS)
189 goto out;
190
191 endbyte = offset + nbytes;
192
193 if ((s64)offset < 0)
194 goto out;
195 if ((s64)endbyte < 0)
196 goto out;
197 if (endbyte < offset)
198 goto out;
199
200 if (sizeof(pgoff_t) == 4) {
201 if (offset >= (0x100000000ULL << PAGE_CACHE_SHIFT)) {
202
203
204
205
206 ret = 0;
207 goto out;
208 }
209 if (endbyte >= (0x100000000ULL << PAGE_CACHE_SHIFT)) {
210
211
212
213 nbytes = 0;
214 }
215 }
216
217 if (nbytes == 0)
218 endbyte = LLONG_MAX;
219 else
220 endbyte--;
221
222 ret = -EBADF;
223 file = fget_light(fd, &fput_needed);
224 if (!file)
225 goto out;
226
227 i_mode = file->f_path.dentry->d_inode->i_mode;
228 ret = -ESPIPE;
229 if (!S_ISREG(i_mode) && !S_ISBLK(i_mode) && !S_ISDIR(i_mode) &&
230 !S_ISLNK(i_mode))
231 goto out_put;
232
233 ret = do_sync_mapping_range(file->f_mapping, offset, endbyte, flags);
234out_put:
235 fput_light(file, fput_needed);
236out:
237 return ret;
238}
239
240
241
242asmlinkage long sys_sync_file_range2(int fd, unsigned int flags,
243 loff_t offset, loff_t nbytes)
244{
245 return sys_sync_file_range(fd, offset, nbytes, flags);
246}
247
248
249
250
251int do_sync_mapping_range(struct address_space *mapping, loff_t offset,
252 loff_t endbyte, unsigned int flags)
253{
254 int ret;
255
256 if (!mapping) {
257 ret = -EINVAL;
258 goto out;
259 }
260
261 ret = 0;
262 if (flags & SYNC_FILE_RANGE_WAIT_BEFORE) {
263 ret = wait_on_page_writeback_range(mapping,
264 offset >> PAGE_CACHE_SHIFT,
265 endbyte >> PAGE_CACHE_SHIFT);
266 if (ret < 0)
267 goto out;
268 }
269
270 if (flags & SYNC_FILE_RANGE_WRITE) {
271 ret = __filemap_fdatawrite_range(mapping, offset, endbyte,
272 WB_SYNC_NONE);
273 if (ret < 0)
274 goto out;
275 }
276
277 if (flags & SYNC_FILE_RANGE_WAIT_AFTER) {
278 ret = wait_on_page_writeback_range(mapping,
279 offset >> PAGE_CACHE_SHIFT,
280 endbyte >> PAGE_CACHE_SHIFT);
281 }
282out:
283 return ret;
284}
285EXPORT_SYMBOL_GPL(do_sync_mapping_range);
286