diff options
Diffstat (limited to 'fs/sync.c')
-rw-r--r-- | fs/sync.c | 117 |
1 files changed, 100 insertions, 17 deletions
@@ -13,38 +13,123 @@ | |||
13 | #include <linux/pagemap.h> | 13 | #include <linux/pagemap.h> |
14 | #include <linux/quotaops.h> | 14 | #include <linux/quotaops.h> |
15 | #include <linux/buffer_head.h> | 15 | #include <linux/buffer_head.h> |
16 | #include "internal.h" | ||
16 | 17 | ||
17 | #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ | 18 | #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ |
18 | SYNC_FILE_RANGE_WAIT_AFTER) | 19 | SYNC_FILE_RANGE_WAIT_AFTER) |
19 | 20 | ||
20 | /* | 21 | /* |
21 | * sync everything. Start out by waking pdflush, because that writes back | 22 | * Do the filesystem syncing work. For simple filesystems sync_inodes_sb(sb, 0) |
22 | * all queues in parallel. | 23 | * just dirties buffers with inodes so we have to submit IO for these buffers |
24 | * via __sync_blockdev(). This also speeds up the wait == 1 case since in that | ||
25 | * case write_inode() functions do sync_dirty_buffer() and thus effectively | ||
26 | * write one block at a time. | ||
23 | */ | 27 | */ |
24 | static void do_sync(unsigned long wait) | 28 | static int __sync_filesystem(struct super_block *sb, int wait) |
25 | { | 29 | { |
26 | wakeup_pdflush(0); | 30 | /* Avoid doing twice syncing and cache pruning for quota sync */ |
27 | sync_inodes(0); /* All mappings, inodes and their blockdevs */ | ||
28 | vfs_dq_sync(NULL); | ||
29 | sync_supers(); /* Write the superblocks */ | ||
30 | sync_filesystems(0); /* Start syncing the filesystems */ | ||
31 | sync_filesystems(wait); /* Waitingly sync the filesystems */ | ||
32 | sync_inodes(wait); /* Mappings, inodes and blockdevs, again. */ | ||
33 | if (!wait) | 31 | if (!wait) |
34 | printk("Emergency Sync complete\n"); | 32 | writeout_quota_sb(sb, -1); |
35 | if (unlikely(laptop_mode)) | 33 | else |
36 | laptop_sync_completion(); | 34 | sync_quota_sb(sb, -1); |
35 | sync_inodes_sb(sb, wait); | ||
36 | if (sb->s_op->sync_fs) | ||
37 | sb->s_op->sync_fs(sb, wait); | ||
38 | return __sync_blockdev(sb->s_bdev, wait); | ||
39 | } | ||
40 | |||
41 | /* | ||
42 | * Write out and wait upon all dirty data associated with this | ||
43 | * superblock. Filesystem data as well as the underlying block | ||
44 | * device. Takes the superblock lock. | ||
45 | */ | ||
46 | int sync_filesystem(struct super_block *sb) | ||
47 | { | ||
48 | int ret; | ||
49 | |||
50 | /* | ||
51 | * We need to be protected against the filesystem going from | ||
52 | * r/o to r/w or vice versa. | ||
53 | */ | ||
54 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); | ||
55 | |||
56 | /* | ||
57 | * No point in syncing out anything if the filesystem is read-only. | ||
58 | */ | ||
59 | if (sb->s_flags & MS_RDONLY) | ||
60 | return 0; | ||
61 | |||
62 | ret = __sync_filesystem(sb, 0); | ||
63 | if (ret < 0) | ||
64 | return ret; | ||
65 | return __sync_filesystem(sb, 1); | ||
66 | } | ||
67 | EXPORT_SYMBOL_GPL(sync_filesystem); | ||
68 | |||
69 | /* | ||
70 | * Sync all the data for all the filesystems (called by sys_sync() and | ||
71 | * emergency sync) | ||
72 | * | ||
73 | * This operation is careful to avoid the livelock which could easily happen | ||
74 | * if two or more filesystems are being continuously dirtied. s_need_sync | ||
75 | * is used only here. We set it against all filesystems and then clear it as | ||
76 | * we sync them. So redirtied filesystems are skipped. | ||
77 | * | ||
78 | * But if process A is currently running sync_filesystems and then process B | ||
79 | * calls sync_filesystems as well, process B will set all the s_need_sync | ||
80 | * flags again, which will cause process A to resync everything. Fix that with | ||
81 | * a local mutex. | ||
82 | */ | ||
83 | static void sync_filesystems(int wait) | ||
84 | { | ||
85 | struct super_block *sb; | ||
86 | static DEFINE_MUTEX(mutex); | ||
87 | |||
88 | mutex_lock(&mutex); /* Could be down_interruptible */ | ||
89 | spin_lock(&sb_lock); | ||
90 | list_for_each_entry(sb, &super_blocks, s_list) | ||
91 | sb->s_need_sync = 1; | ||
92 | |||
93 | restart: | ||
94 | list_for_each_entry(sb, &super_blocks, s_list) { | ||
95 | if (!sb->s_need_sync) | ||
96 | continue; | ||
97 | sb->s_need_sync = 0; | ||
98 | sb->s_count++; | ||
99 | spin_unlock(&sb_lock); | ||
100 | |||
101 | down_read(&sb->s_umount); | ||
102 | if (!(sb->s_flags & MS_RDONLY) && sb->s_root) | ||
103 | __sync_filesystem(sb, wait); | ||
104 | up_read(&sb->s_umount); | ||
105 | |||
106 | /* restart only when sb is no longer on the list */ | ||
107 | spin_lock(&sb_lock); | ||
108 | if (__put_super_and_need_restart(sb)) | ||
109 | goto restart; | ||
110 | } | ||
111 | spin_unlock(&sb_lock); | ||
112 | mutex_unlock(&mutex); | ||
37 | } | 113 | } |
38 | 114 | ||
39 | SYSCALL_DEFINE0(sync) | 115 | SYSCALL_DEFINE0(sync) |
40 | { | 116 | { |
41 | do_sync(1); | 117 | sync_filesystems(0); |
118 | sync_filesystems(1); | ||
119 | if (unlikely(laptop_mode)) | ||
120 | laptop_sync_completion(); | ||
42 | return 0; | 121 | return 0; |
43 | } | 122 | } |
44 | 123 | ||
45 | static void do_sync_work(struct work_struct *work) | 124 | static void do_sync_work(struct work_struct *work) |
46 | { | 125 | { |
47 | do_sync(0); | 126 | /* |
127 | * Sync twice to reduce the possibility we skipped some inodes / pages | ||
128 | * because they were temporarily locked | ||
129 | */ | ||
130 | sync_filesystems(0); | ||
131 | sync_filesystems(0); | ||
132 | printk("Emergency Sync complete\n"); | ||
48 | kfree(work); | 133 | kfree(work); |
49 | } | 134 | } |
50 | 135 | ||
@@ -75,10 +160,8 @@ int file_fsync(struct file *filp, struct dentry *dentry, int datasync) | |||
75 | 160 | ||
76 | /* sync the superblock to buffers */ | 161 | /* sync the superblock to buffers */ |
77 | sb = inode->i_sb; | 162 | sb = inode->i_sb; |
78 | lock_super(sb); | ||
79 | if (sb->s_dirt && sb->s_op->write_super) | 163 | if (sb->s_dirt && sb->s_op->write_super) |
80 | sb->s_op->write_super(sb); | 164 | sb->s_op->write_super(sb); |
81 | unlock_super(sb); | ||
82 | 165 | ||
83 | /* .. finally sync the buffers to disk */ | 166 | /* .. finally sync the buffers to disk */ |
84 | err = sync_blockdev(sb->s_bdev); | 167 | err = sync_blockdev(sb->s_bdev); |