Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 72a43d63 authored by Al Viro's avatar Al Viro Committed by Al Viro
Browse files

ext3/4 with synchronous writes gets wedged by Postfix



OK, that's probably the easiest way to do that, as much as I don't like it...
Since iget() et.al. will not accept I_FREEING (will wait to go away
and restart), and since we'd better have serialization between new/free
on fs data structures anyway, we can afford simply skipping I_FREEING
et.al. in insert_inode_locked().

We do that from new_inode, so it won't race with free_inode in any interesting
ways and it won't race with iget (of any origin; nfsd or in case of fs
corruption a lookup) since both still will wait for I_LOCK.

Reviewed-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
Acked-by: default avatarJan Kara <jack@suse.cz>
Tested-by: default avatarDavid Watson <dbwatson@ukfsn.org>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 460bcf57
Loading
Loading
Loading
Loading
+25 −6
Original line number Diff line number Diff line
@@ -1053,13 +1053,22 @@ int insert_inode_locked(struct inode *inode)
	struct super_block *sb = inode->i_sb;
	ino_t ino = inode->i_ino;
	struct hlist_head *head = inode_hashtable + hash(sb, ino);
	struct inode *old;

	inode->i_state |= I_LOCK|I_NEW;
	while (1) {
		struct hlist_node *node;
		struct inode *old = NULL;
		spin_lock(&inode_lock);
		old = find_inode_fast(sb, head, ino);
		if (likely(!old)) {
		hlist_for_each_entry(old, node, head, i_hash) {
			if (old->i_ino != ino)
				continue;
			if (old->i_sb != sb)
				continue;
			if (old->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE))
				continue;
			break;
		}
		if (likely(!node)) {
			hlist_add_head(&inode->i_hash, head);
			spin_unlock(&inode_lock);
			return 0;
@@ -1081,14 +1090,24 @@ int insert_inode_locked4(struct inode *inode, unsigned long hashval,
{
	struct super_block *sb = inode->i_sb;
	struct hlist_head *head = inode_hashtable + hash(sb, hashval);
	struct inode *old;

	inode->i_state |= I_LOCK|I_NEW;

	while (1) {
		struct hlist_node *node;
		struct inode *old = NULL;

		spin_lock(&inode_lock);
		old = find_inode(sb, head, test, data);
		if (likely(!old)) {
		hlist_for_each_entry(old, node, head, i_hash) {
			if (old->i_sb != sb)
				continue;
			if (!test(old, data))
				continue;
			if (old->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE))
				continue;
			break;
		}
		if (likely(!node)) {
			hlist_add_head(&inode->i_hash, head);
			spin_unlock(&inode_lock);
			return 0;