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

Commit a34eb503 authored by Theodore Ts'o's avatar Theodore Ts'o
Browse files

ext4: make sure group number is bumped after a inode allocation race



When we try to allocate an inode, and there is a race between two
CPU's trying to grab the same inode, _and_ this inode is the last free
inode in the block group, make sure the group number is bumped before
we continue searching the rest of the block groups.  Otherwise, we end
up searching the current block group twice, and we end up skipping
searching the last block group.  So in the unlikely situation where
almost all of the inodes are allocated, it's possible that we will
return ENOSPC even though there might be free inodes in that last
block group.

Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
Cc: stable@vger.kernel.org
parent 3b2f64d0
Loading
Loading
Loading
Loading
+5 −5
Original line number Original line Diff line number Diff line
@@ -734,11 +734,8 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
		ino = ext4_find_next_zero_bit((unsigned long *)
		ino = ext4_find_next_zero_bit((unsigned long *)
					      inode_bitmap_bh->b_data,
					      inode_bitmap_bh->b_data,
					      EXT4_INODES_PER_GROUP(sb), ino);
					      EXT4_INODES_PER_GROUP(sb), ino);
		if (ino >= EXT4_INODES_PER_GROUP(sb)) {
		if (ino >= EXT4_INODES_PER_GROUP(sb))
			if (++group == ngroups)
			goto next_group;
				group = 0;
			continue;
		}
		if (group == 0 && (ino+1) < EXT4_FIRST_INO(sb)) {
		if (group == 0 && (ino+1) < EXT4_FIRST_INO(sb)) {
			ext4_error(sb, "reserved inode found cleared - "
			ext4_error(sb, "reserved inode found cleared - "
				   "inode=%lu", ino + 1);
				   "inode=%lu", ino + 1);
@@ -769,6 +766,9 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
			goto got; /* we grabbed the inode! */
			goto got; /* we grabbed the inode! */
		if (ino < EXT4_INODES_PER_GROUP(sb))
		if (ino < EXT4_INODES_PER_GROUP(sb))
			goto repeat_in_this_group;
			goto repeat_in_this_group;
next_group:
		if (++group == ngroups)
			group = 0;
	}
	}
	err = -ENOSPC;
	err = -ENOSPC;
	goto out;
	goto out;