From: Kirill Korotaev <dev@sw.ru>
To: mason@suse.com, linux-kernel@vger.kernel.org,
Andrew Morton <akpm@osdl.org>, Linus Torvalds <torvalds@osdl.org>
Subject: [PATCH] Fix of race in writeback_inodes()
Date: Tue, 14 Sep 2004 13:57:39 +0400 [thread overview]
Message-ID: <4146C093.3070904@sw.ru> (raw)
[-- Attachment #1: Type: text/plain, Size: 1532 bytes --]
This patch fixes race in writeback_inodes() described below:
writeback_inodes()
{
....
sb->s_count++;
spin_unlock(&sb_lock);
....
spin_lock(&sb_lock);
if (__put_super(sb)) <<< X
goto restart;
}
}
deactivate_super()
{
fs->kill_sb(s);
kill_block_super(sb)
generic_shutdown_super(sb)
spin_lock(&sb_lock);
list_del(&sb->s_list); <<< Y
spin_unlock(&sb_lock);
....
put_super(s);
spin_lock(&sb_lock);
__put_super(sb); <<< Z
spin_unlock(&sb_lock);
}
The problem with it is that writeback_inodes() supposes that if
__put_super() returns 0 then no super block was deleted from the list
and we can safely traverse sb list further.
But as it is obvious from the deactivate_super() it's not actually true.
because at point Y we delete super block from the list and drop the
lock. We do __put_super() very much later... So we can find sb with
poisoned sb->s_list at point X and we won't be the last sb reference
holders. The last reference will be dropped in point Z.
So in case of the following sequence of execution Y -> X -> Z we'll get
an oops after point X in writeback_inodes().
This patch introduces __put_super_and_need_restart() function which
allows safe traversing of sb list. I'll send a couple of patches later
which remove O(n^2) algos and using this function.
Signed-Off-By: Kirill Korotaev <dev@sw.ru>
Kirill
[-- Attachment #2: diff-sb-race --]
[-- Type: text/plain, Size: 2369 bytes --]
--- ./include/linux/fs.h.sbrace 2004-09-14 13:33:55.835241408 +0400
+++ ./include/linux/fs.h 2004-09-14 13:33:20.065679208 +0400
@@ -1129,6 +1129,7 @@ struct super_block *sget(struct file_sys
struct super_block *get_sb_pseudo(struct file_system_type *, char *,
struct super_operations *ops, unsigned long);
int __put_super(struct super_block *sb);
+int __put_super_and_need_restart(struct super_block *sb);
void unnamed_dev_init(void);
/* Alas, no aliases. Too much hassle with bringing module.h everywhere */
--- ./fs/super.c.sbrace 2004-08-14 14:55:22.000000000 +0400
+++ ./fs/super.c 2004-09-14 13:20:22.365907544 +0400
@@ -116,6 +116,27 @@ int __put_super(struct super_block *sb)
return ret;
}
+/*
+ * Drop a superblock's refcount.
+ * Returns non-zero if the superblock is about to be destroyed and
+ * at least is already removed from super_blocks list, so if we are
+ * making a loop through super blocks then we need to restart.
+ * The caller must hold sb_lock.
+ */
+int __put_super_and_need_restart(struct super_block *sb)
+{
+ /* check for race with generic_shutdown_super() */
+ if (list_empty(&sb->s_list)) {
+ /* super block is removed, need to restart... */
+ __put_super(sb);
+ return 1;
+ }
+ /* can't be the last, since s_list is still in use */
+ sb->s_count--;
+ BUG_ON(sb->s_count == 0);
+ return 0;
+}
+
/**
* put_super - drop a temporary reference to superblock
* @s: superblock in question
@@ -229,7 +250,8 @@ void generic_shutdown_super(struct super
unlock_super(sb);
}
spin_lock(&sb_lock);
- list_del(&sb->s_list);
+ /* should be initialized for __put_super_and_need_restart() */
+ list_del_init(&sb->s_list);
list_del(&sb->s_instances);
spin_unlock(&sb_lock);
up_write(&sb->s_umount);
@@ -282,7 +304,7 @@ retry:
}
s->s_type = type;
strlcpy(s->s_id, type->name, sizeof(s->s_id));
- list_add(&s->s_list, super_blocks.prev);
+ list_add_tail(&s->s_list, &super_blocks);
list_add(&s->s_instances, &type->fs_supers);
spin_unlock(&sb_lock);
get_filesystem(type);
--- ./fs/fs-writeback.c.sbrace 2004-08-14 14:56:24.000000000 +0400
+++ ./fs/fs-writeback.c 2004-09-14 13:53:44.258573600 +0400
@@ -412,7 +412,7 @@ restart:
up_read(&sb->s_umount);
}
spin_lock(&sb_lock);
- if (__put_super(sb))
+ if (__put_super_and_need_restart(sb))
goto restart;
}
if (wbc->nr_to_write <= 0)
reply other threads:[~2004-09-14 9:46 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4146C093.3070904@sw.ru \
--to=dev@sw.ru \
--cc=akpm@osdl.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mason@suse.com \
--cc=torvalds@osdl.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.