aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2012-06-12 10:20:34 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-07-31 01:30:13 -0400
commit5accdf82ba25cacefd6c1867f1704beb4d244cdd (patch)
tree7125b01d9bf0f23d5c5eaed0cbafa9a1cbe544d5
parentd87aae2f3c8e90bd0fe03f5309b4d066b712b8ec (diff)
fs: Improve filesystem freezing handling
vfs_check_frozen() tests are racy since the filesystem can be frozen just after the test is performed. Thus in write paths we can end up marking some pages or inodes dirty even though the file system is already frozen. This creates problems with flusher thread hanging on frozen filesystem. Another problem is that exclusion between ->page_mkwrite() and filesystem freezing has been handled by setting page dirty and then verifying s_frozen. This guaranteed that either the freezing code sees the faulted page, writes it, and writeprotects it again or we see s_frozen set and bail out of page fault. This works to protect from page being marked writeable while filesystem freezing is running but has an unpleasant artefact of leaving dirty (although unmodified and writeprotected) pages on frozen filesystem resulting in similar problems with flusher thread as the first problem. This patch aims at providing exclusion between write paths and filesystem freezing. We implement a writer-freeze read-write semaphore in the superblock. Actually, there are three such semaphores because of lock ranking reasons - one for page fault handlers (->page_mkwrite), one for all other writers, and one of internal filesystem purposes (used e.g. to track running transactions). Write paths which should block freezing (e.g. directory operations, ->aio_write(), ->page_mkwrite) hold reader side of the semaphore. Code freezing the filesystem takes the writer side. Only that we don't really want to bounce cachelines of the semaphores between CPUs for each write happening. So we implement the reader side of the semaphore as a per-cpu counter and the writer side is implemented using s_writers.frozen superblock field. [AV: microoptimize sb_start_write(); we want it fast in normal case] BugLink: https://bugs.launchpad.net/bugs/897421 Tested-by: Kamal Mostafa <kamal@canonical.com> Tested-by: Peter M. Petrakis <peter.petrakis@canonical.com> Tested-by: Dann Frazier <dann.frazier@canonical.com> Tested-by: Massimo Morana <massimo.morana@canonical.com> Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/super.c251
-rw-r--r--include/linux/fs.h150
2 files changed, 373 insertions, 28 deletions
diff --git a/fs/super.c b/fs/super.c
index c743fb3be4b8..0f64ecb7b1bf 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -33,12 +33,19 @@
33#include <linux/rculist_bl.h> 33#include <linux/rculist_bl.h>
34#include <linux/cleancache.h> 34#include <linux/cleancache.h>
35#include <linux/fsnotify.h> 35#include <linux/fsnotify.h>
36#include <linux/lockdep.h>
36#include "internal.h" 37#include "internal.h"
37 38
38 39
39LIST_HEAD(super_blocks); 40LIST_HEAD(super_blocks);
40DEFINE_SPINLOCK(sb_lock); 41DEFINE_SPINLOCK(sb_lock);
41 42
43static char *sb_writers_name[SB_FREEZE_LEVELS] = {
44 "sb_writers",
45 "sb_pagefaults",
46 "sb_internal",
47};
48
42/* 49/*
43 * One thing we have to be careful of with a per-sb shrinker is that we don't 50 * One thing we have to be careful of with a per-sb shrinker is that we don't
44 * drop the last active reference to the superblock from within the shrinker. 51 * drop the last active reference to the superblock from within the shrinker.
@@ -102,6 +109,35 @@ static int prune_super(struct shrinker *shrink, struct shrink_control *sc)
102 return total_objects; 109 return total_objects;
103} 110}
104 111
112static int init_sb_writers(struct super_block *s, struct file_system_type *type)
113{
114 int err;
115 int i;
116
117 for (i = 0; i < SB_FREEZE_LEVELS; i++) {
118 err = percpu_counter_init(&s->s_writers.counter[i], 0);
119 if (err < 0)
120 goto err_out;
121 lockdep_init_map(&s->s_writers.lock_map[i], sb_writers_name[i],
122 &type->s_writers_key[i], 0);
123 }
124 init_waitqueue_head(&s->s_writers.wait);
125 init_waitqueue_head(&s->s_writers.wait_unfrozen);
126 return 0;
127err_out:
128 while (--i >= 0)
129 percpu_counter_destroy(&s->s_writers.counter[i]);
130 return err;
131}
132
133static void destroy_sb_writers(struct super_block *s)
134{
135 int i;
136
137 for (i = 0; i < SB_FREEZE_LEVELS; i++)
138 percpu_counter_destroy(&s->s_writers.counter[i]);
139}
140
105/** 141/**
106 * alloc_super - create new superblock 142 * alloc_super - create new superblock
107 * @type: filesystem type superblock should belong to 143 * @type: filesystem type superblock should belong to
@@ -117,18 +153,19 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags)
117 153
118 if (s) { 154 if (s) {
119 if (security_sb_alloc(s)) { 155 if (security_sb_alloc(s)) {
156 /*
157 * We cannot call security_sb_free() without
158 * security_sb_alloc() succeeding. So bail out manually
159 */
120 kfree(s); 160 kfree(s);
121 s = NULL; 161 s = NULL;
122 goto out; 162 goto out;
123 } 163 }
124#ifdef CONFIG_SMP 164#ifdef CONFIG_SMP
125 s->s_files = alloc_percpu(struct list_head); 165 s->s_files = alloc_percpu(struct list_head);
126 if (!s->s_files) { 166 if (!s->s_files)
127 security_sb_free(s); 167 goto err_out;
128 kfree(s); 168 else {
129 s = NULL;
130 goto out;
131 } else {
132 int i; 169 int i;
133 170
134 for_each_possible_cpu(i) 171 for_each_possible_cpu(i)
@@ -137,6 +174,8 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags)
137#else 174#else
138 INIT_LIST_HEAD(&s->s_files); 175 INIT_LIST_HEAD(&s->s_files);
139#endif 176#endif
177 if (init_sb_writers(s, type))
178 goto err_out;
140 s->s_flags = flags; 179 s->s_flags = flags;
141 s->s_bdi = &default_backing_dev_info; 180 s->s_bdi = &default_backing_dev_info;
142 INIT_HLIST_NODE(&s->s_instances); 181 INIT_HLIST_NODE(&s->s_instances);
@@ -190,6 +229,16 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags)
190 } 229 }
191out: 230out:
192 return s; 231 return s;
232err_out:
233 security_sb_free(s);
234#ifdef CONFIG_SMP
235 if (s->s_files)
236 free_percpu(s->s_files);
237#endif
238 destroy_sb_writers(s);
239 kfree(s);
240 s = NULL;
241 goto out;
193} 242}
194 243
195/** 244/**
@@ -203,6 +252,7 @@ static inline void destroy_super(struct super_block *s)
203#ifdef CONFIG_SMP 252#ifdef CONFIG_SMP
204 free_percpu(s->s_files); 253 free_percpu(s->s_files);
205#endif 254#endif
255 destroy_sb_writers(s);
206 security_sb_free(s); 256 security_sb_free(s);
207 WARN_ON(!list_empty(&s->s_mounts)); 257 WARN_ON(!list_empty(&s->s_mounts));
208 kfree(s->s_subtype); 258 kfree(s->s_subtype);
@@ -651,10 +701,11 @@ struct super_block *get_super_thawed(struct block_device *bdev)
651{ 701{
652 while (1) { 702 while (1) {
653 struct super_block *s = get_super(bdev); 703 struct super_block *s = get_super(bdev);
654 if (!s || s->s_frozen == SB_UNFROZEN) 704 if (!s || s->s_writers.frozen == SB_UNFROZEN)
655 return s; 705 return s;
656 up_read(&s->s_umount); 706 up_read(&s->s_umount);
657 vfs_check_frozen(s, SB_FREEZE_WRITE); 707 wait_event(s->s_writers.wait_unfrozen,
708 s->s_writers.frozen == SB_UNFROZEN);
658 put_super(s); 709 put_super(s);
659 } 710 }
660} 711}
@@ -732,7 +783,7 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
732 int retval; 783 int retval;
733 int remount_ro; 784 int remount_ro;
734 785
735 if (sb->s_frozen != SB_UNFROZEN) 786 if (sb->s_writers.frozen != SB_UNFROZEN)
736 return -EBUSY; 787 return -EBUSY;
737 788
738#ifdef CONFIG_BLOCK 789#ifdef CONFIG_BLOCK
@@ -1163,6 +1214,120 @@ out:
1163 return ERR_PTR(error); 1214 return ERR_PTR(error);
1164} 1215}
1165 1216
1217/*
1218 * This is an internal function, please use sb_end_{write,pagefault,intwrite}
1219 * instead.
1220 */
1221void __sb_end_write(struct super_block *sb, int level)
1222{
1223 percpu_counter_dec(&sb->s_writers.counter[level-1]);
1224 /*
1225 * Make sure s_writers are updated before we wake up waiters in
1226 * freeze_super().
1227 */
1228 smp_mb();
1229 if (waitqueue_active(&sb->s_writers.wait))
1230 wake_up(&sb->s_writers.wait);
1231 rwsem_release(&sb->s_writers.lock_map[level-1], 1, _RET_IP_);
1232}
1233EXPORT_SYMBOL(__sb_end_write);
1234
1235#ifdef CONFIG_LOCKDEP
1236/*
1237 * We want lockdep to tell us about possible deadlocks with freezing but
1238 * it's it bit tricky to properly instrument it. Getting a freeze protection
1239 * works as getting a read lock but there are subtle problems. XFS for example
1240 * gets freeze protection on internal level twice in some cases, which is OK
1241 * only because we already hold a freeze protection also on higher level. Due
1242 * to these cases we have to tell lockdep we are doing trylock when we
1243 * already hold a freeze protection for a higher freeze level.
1244 */
1245static void acquire_freeze_lock(struct super_block *sb, int level, bool trylock,
1246 unsigned long ip)
1247{
1248 int i;
1249
</