diff --git a/fs/incfs/data_mgmt.c b/fs/incfs/data_mgmt.c index 1382becd10af..5dbfe93d65e9 100644 --- a/fs/incfs/data_mgmt.c +++ b/fs/incfs/data_mgmt.c @@ -1381,7 +1381,8 @@ ssize_t incfs_read_merkle_tree_blocks(struct mem_range dst, } int incfs_process_new_data_block(struct data_file *df, - struct incfs_fill_block *block, u8 *data) + struct incfs_fill_block *block, u8 *data, + bool *complete) { struct mount_info *mi = NULL; struct backing_file_context *bfc = NULL; @@ -1420,27 +1421,42 @@ int incfs_process_new_data_block(struct data_file *df, if (error) return error; - if (is_data_block_present(&existing_block)) { + if (is_data_block_present(&existing_block)) /* Block is already present, nothing to do here */ return 0; - } error = down_write_killable(&segment->rwsem); if (error) return error; - error = mutex_lock_interruptible(&bfc->bc_mutex); - if (!error) { - error = incfs_write_data_block_to_backing_file( - bfc, range(data, block->data_len), block->block_index, - df->df_blockmap_off, flags); - mutex_unlock(&bfc->bc_mutex); - } - if (!error) { - notify_pending_reads(mi, segment, block->block_index); - atomic_inc(&df->df_data_blocks_written); - } + /* Recheck inside write lock */ + error = get_data_file_block(df, block->block_index, &existing_block); + if (error) + goto out_up_write; + if (is_data_block_present(&existing_block)) + goto out_up_write; + + error = mutex_lock_interruptible(&bfc->bc_mutex); + if (error) + goto out_up_write; + + error = incfs_write_data_block_to_backing_file(bfc, + range(data, block->data_len), block->block_index, + df->df_blockmap_off, flags); + if (error) + goto out_mutex_unlock; + + if (atomic_inc_return(&df->df_data_blocks_written) + >= df->df_data_block_count) + *complete = true; + +out_mutex_unlock: + mutex_unlock(&bfc->bc_mutex); + if (!error) + notify_pending_reads(mi, segment, block->block_index); + +out_up_write: up_write(&segment->rwsem); if (error) diff --git a/fs/incfs/data_mgmt.h b/fs/incfs/data_mgmt.h index 2227913674a4..2b6121d6131f 100644 --- a/fs/incfs/data_mgmt.h +++ b/fs/incfs/data_mgmt.h @@ -441,7 +441,8 @@ int incfs_get_filled_blocks(struct data_file *df, int incfs_read_file_signature(struct data_file *df, struct mem_range dst); int incfs_process_new_data_block(struct data_file *df, - struct incfs_fill_block *block, u8 *data); + struct incfs_fill_block *block, u8 *data, + bool *complete); int incfs_process_new_hash_block(struct data_file *df, struct incfs_fill_block *block, u8 *data); diff --git a/fs/incfs/vfs.c b/fs/incfs/vfs.c index cde9fe992da2..4ac6e5e7851e 100644 --- a/fs/incfs/vfs.c +++ b/fs/incfs/vfs.c @@ -668,8 +668,7 @@ out: dput(file); } -static void maybe_delete_incomplete_file(struct file *f, - struct data_file *df) +static void handle_file_completed(struct file *f, struct data_file *df) { struct backing_file_context *bfc; struct mount_info *mi = df->df_mount_info; @@ -678,9 +677,6 @@ static void maybe_delete_incomplete_file(struct file *f, const struct cred *old_cred = override_creds(mi->mi_owner); int error; - if (atomic_read(&df->df_data_blocks_written) < df->df_data_block_count) - goto out; - /* Truncate file to remove any preallocated space */ bfc = df->df_backing_file_context; if (bfc) { @@ -739,6 +735,7 @@ static long ioctl_fill_blocks(struct file *f, void __user *arg) u8 *data_buf = NULL; ssize_t error = 0; int i = 0; + bool complete = false; if (!df) return -EBADF; @@ -780,7 +777,7 @@ static long ioctl_fill_blocks(struct file *f, void __user *arg) data_buf); } else { error = incfs_process_new_data_block(df, &fill_block, - data_buf); + data_buf, &complete); } if (error) break; @@ -789,7 +786,8 @@ static long ioctl_fill_blocks(struct file *f, void __user *arg) if (data_buf) free_pages((unsigned long)data_buf, get_order(data_buf_size)); - maybe_delete_incomplete_file(f, df); + if (complete) + handle_file_completed(f, df); /* * Only report the error if no records were processed, otherwise