Unverified Commit 9a2058ed authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!12304 btrfs: fix race setting file private on concurrent lseek using same fd

parents 06f5a659 6e87b4b3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -84,6 +84,7 @@ struct btrfs_inode {
	 * the log or not (last_trans, last_sub_trans, last_log_commit,
	 * logged_trans), to access/update new_delalloc_bytes and to update the
	 * VFS' inode number of bytes used.
	 * Also protects setting struct file::private_data.
	 */
	spinlock_t lock;

+2 −0
Original line number Diff line number Diff line
@@ -445,6 +445,8 @@ struct btrfs_file_private {
	void *filldir_buf;
	u64 last_index;
	struct extent_state *llseek_cached_state;
	/* Task that allocated this structure. */
	struct task_struct *owner_task;
};

static inline u32 BTRFS_LEAF_DATA_SIZE(const struct btrfs_fs_info *info)
+31 −3
Original line number Diff line number Diff line
@@ -3481,7 +3481,7 @@ static bool find_desired_extent_in_hole(struct btrfs_inode *inode, int whence,
static loff_t find_desired_extent(struct file *file, loff_t offset, int whence)
{
	struct btrfs_inode *inode = BTRFS_I(file->f_mapping->host);
	struct btrfs_file_private *private = file->private_data;
	struct btrfs_file_private *private;
	struct btrfs_fs_info *fs_info = inode->root->fs_info;
	struct extent_state *cached_state = NULL;
	struct extent_state **delalloc_cached_state;
@@ -3509,7 +3509,19 @@ static loff_t find_desired_extent(struct file *file, loff_t offset, int whence)
	    inode_get_bytes(&inode->vfs_inode) == i_size)
		return i_size;

	if (!private) {
	spin_lock(&inode->lock);
	private = file->private_data;
	spin_unlock(&inode->lock);

	if (private && private->owner_task != current) {
		/*
		 * Not allocated by us, don't use it as its cached state is used
		 * by the task that allocated it and we don't want neither to
		 * mess with it nor get incorrect results because it reflects an
		 * invalid state for the current task.
		 */
		private = NULL;
	} else if (!private) {
		private = kzalloc(sizeof(*private), GFP_KERNEL);
		/*
		 * No worries if memory allocation failed.
@@ -3517,7 +3529,23 @@ static loff_t find_desired_extent(struct file *file, loff_t offset, int whence)
		 * lseek SEEK_HOLE/DATA calls to a file when there's delalloc,
		 * so everything will still be correct.
		 */
		if (private) {
			bool free = false;

			private->owner_task = current;

			spin_lock(&inode->lock);
			if (file->private_data)
				free = true;
			else
				file->private_data = private;
			spin_unlock(&inode->lock);

			if (free) {
				kfree(private);
				private = NULL;
			}
		}
	}

	if (private)