aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sync.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/sync.c')
-rw-r--r--fs/sync.c113
1 files changed, 113 insertions, 0 deletions
diff --git a/fs/sync.c b/fs/sync.c
index 955aef04da28..1de747b5ddb9 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -10,11 +10,124 @@
10#include <linux/syscalls.h> 10#include <linux/syscalls.h>
11#include <linux/linkage.h> 11#include <linux/linkage.h>
12#include <linux/pagemap.h> 12#include <linux/pagemap.h>
13#include <linux/quotaops.h>
14#include <linux/buffer_head.h>
13 15
14#define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ 16#define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \
15 SYNC_FILE_RANGE_WAIT_AFTER) 17 SYNC_FILE_RANGE_WAIT_AFTER)
16 18
17/* 19/*
20 * sync everything. Start out by waking pdflush, because that writes back
21 * all queues in parallel.
22 */
23static void do_sync(unsigned long wait)
24{
25 wakeup_pdflush(0);
26 sync_inodes(0); /* All mappings, inodes and their blockdevs */
27 DQUOT_SYNC(NULL);
28 sync_supers(); /* Write the superblocks */
29 sync_filesystems(0); /* Start syncing the filesystems */
30 sync_filesystems(wait); /* Waitingly sync the filesystems */
31 sync_inodes(wait); /* Mappings, inodes and blockdevs, again. */
32 if (!wait)
33 printk("Emergency Sync complete\n");
34 if (unlikely(laptop_mode))
35 laptop_sync_completion();
36}
37
38asmlinkage long sys_sync(void)
39{
40 do_sync(1);
41 return 0;
42}
43
44void emergency_sync(void)
45{
46 pdflush_operation(do_sync, 0);
47}
48
49/*
50 * Generic function to fsync a file.
51 *
52 * filp may be NULL if called via the msync of a vma.
53 */
54int file_fsync(struct file *filp, struct dentry *dentry, int datasync)
55{
56 struct inode * inode = dentry->d_inode;
57 struct super_block * sb;
58 int ret, err;
59
60 /* sync the inode to buffers */
61 ret = write_inode_now(inode, 0);
62
63 /* sync the superblock to buffers */
64 sb = inode->i_sb;
65 lock_super(sb);
66 if (sb->s_op->write_super)
67 sb->s_op->write_super(sb);
68 unlock_super(sb);
69
70 /* .. finally sync the buffers to disk */
71 err = sync_blockdev(sb->s_bdev);
72 if (!ret)
73 ret = err;
74 return ret;
75}
76
77long do_fsync(struct file *file, int datasync)
78{
79 int ret;
80 int err;
81 struct address_space *mapping = file->f_mapping;
82
83 if (!file->f_op || !file->f_op->fsync) {
84 /* Why? We can still call filemap_fdatawrite */
85 ret = -EINVAL;
86 goto out;
87 }
88
89 ret = filemap_fdatawrite(mapping);
90
91 /*
92 * We need to protect against concurrent writers, which could cause
93 * livelocks in fsync_buffers_list().
94 */
95 mutex_lock(&mapping->host->i_mutex);
96 err = file->f_op->fsync(file, file->f_dentry, datasync);
97 if (!ret)
98 ret = err;
99 mutex_unlock(&mapping->host->i_mutex);
100 err = filemap_fdatawait(mapping);
101 if (!ret)
102 ret = err;
103out:
104 return ret;
105}
106
107static long __do_fsync(unsigned int fd, int datasync)
108{
109 struct file *file;
110 int ret = -EBADF;
111
112 file = fget(fd);
113 if (file) {
114 ret = do_fsync(file, datasync);
115 fput(file);
116 }
117 return ret;
118}
119
120asmlinkage long sys_fsync(unsigned int fd)
121{
122 return __do_fsync(fd, 0);
123}
124
125asmlinkage long sys_fdatasync(unsigned int fd)
126{
127 return __do_fsync(fd, 1);
128}
129
130/*
18 * sys_sync_file_range() permits finely controlled syncing over a segment of 131 * sys_sync_file_range() permits finely controlled syncing over a segment of
19 * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is 132 * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is
20 * zero then sys_sync_file_range() will operate from offset out to EOF. 133 * zero then sys_sync_file_range() will operate from offset out to EOF.