Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 790cf85

Browse files
PaulLawrenceGoogleTreehugger Robot
authored andcommitted
ANDROID: incremental fs: Fix race between truncate and write last block
Also fix race whereby multiple providers writinig the same block would actually write out the same block. Note that multiple_providers_test started failing when incfs was ported to 5.15, and these fixes are needed to make the test reliable Bug: 264703896 Test: incfs-test passes, specifically multiple_providers_test. Ran 100 times Change-Id: I05ad5b2b2f62cf218256222cecb79bbe9953bd97 Signed-off-by: Paul Lawrence <paullawrence@google.com>
1 parent d7d3997 commit 790cf85

File tree

3 files changed

+34
-19
lines changed

3 files changed

+34
-19
lines changed

fs/incfs/data_mgmt.c

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,7 +1381,8 @@ ssize_t incfs_read_merkle_tree_blocks(struct mem_range dst,
13811381
}
13821382

13831383
int incfs_process_new_data_block(struct data_file *df,
1384-
struct incfs_fill_block *block, u8 *data)
1384+
struct incfs_fill_block *block, u8 *data,
1385+
bool *complete)
13851386
{
13861387
struct mount_info *mi = NULL;
13871388
struct backing_file_context *bfc = NULL;
@@ -1420,27 +1421,42 @@ int incfs_process_new_data_block(struct data_file *df,
14201421

14211422
if (error)
14221423
return error;
1423-
if (is_data_block_present(&existing_block)) {
1424+
if (is_data_block_present(&existing_block))
14241425
/* Block is already present, nothing to do here */
14251426
return 0;
1426-
}
14271427

14281428
error = down_write_killable(&segment->rwsem);
14291429
if (error)
14301430
return error;
14311431

1432+
/* Recheck inside write lock */
1433+
error = get_data_file_block(df, block->block_index, &existing_block);
1434+
if (error)
1435+
goto out_up_write;
1436+
1437+
if (is_data_block_present(&existing_block))
1438+
goto out_up_write;
1439+
14321440
error = mutex_lock_interruptible(&bfc->bc_mutex);
1433-
if (!error) {
1434-
error = incfs_write_data_block_to_backing_file(
1435-
bfc, range(data, block->data_len), block->block_index,
1441+
if (error)
1442+
goto out_up_write;
1443+
1444+
error = incfs_write_data_block_to_backing_file(bfc,
1445+
range(data, block->data_len), block->block_index,
14361446
df->df_blockmap_off, flags);
1437-
mutex_unlock(&bfc->bc_mutex);
1438-
}
1439-
if (!error) {
1447+
if (error)
1448+
goto out_mutex_unlock;
1449+
1450+
if (atomic_inc_return(&df->df_data_blocks_written)
1451+
>= df->df_data_block_count)
1452+
*complete = true;
1453+
1454+
out_mutex_unlock:
1455+
mutex_unlock(&bfc->bc_mutex);
1456+
if (!error)
14401457
notify_pending_reads(mi, segment, block->block_index);
1441-
atomic_inc(&df->df_data_blocks_written);
1442-
}
14431458

1459+
out_up_write:
14441460
up_write(&segment->rwsem);
14451461

14461462
if (error)

fs/incfs/data_mgmt.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,8 @@ int incfs_get_filled_blocks(struct data_file *df,
441441
int incfs_read_file_signature(struct data_file *df, struct mem_range dst);
442442

443443
int incfs_process_new_data_block(struct data_file *df,
444-
struct incfs_fill_block *block, u8 *data);
444+
struct incfs_fill_block *block, u8 *data,
445+
bool *complete);
445446

446447
int incfs_process_new_hash_block(struct data_file *df,
447448
struct incfs_fill_block *block, u8 *data);

fs/incfs/vfs.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -669,8 +669,7 @@ static void notify_unlink(struct dentry *dentry, const char *file_id_str,
669669
dput(file);
670670
}
671671

672-
static void maybe_delete_incomplete_file(struct file *f,
673-
struct data_file *df)
672+
static void handle_file_completed(struct file *f, struct data_file *df)
674673
{
675674
struct backing_file_context *bfc;
676675
struct mount_info *mi = df->df_mount_info;
@@ -679,9 +678,6 @@ static void maybe_delete_incomplete_file(struct file *f,
679678
const struct cred *old_cred = override_creds(mi->mi_owner);
680679
int error;
681680

682-
if (atomic_read(&df->df_data_blocks_written) < df->df_data_block_count)
683-
goto out;
684-
685681
/* Truncate file to remove any preallocated space */
686682
bfc = df->df_backing_file_context;
687683
if (bfc) {
@@ -740,6 +736,7 @@ static long ioctl_fill_blocks(struct file *f, void __user *arg)
740736
u8 *data_buf = NULL;
741737
ssize_t error = 0;
742738
int i = 0;
739+
bool complete = false;
743740

744741
if (!df)
745742
return -EBADF;
@@ -781,7 +778,7 @@ static long ioctl_fill_blocks(struct file *f, void __user *arg)
781778
data_buf);
782779
} else {
783780
error = incfs_process_new_data_block(df, &fill_block,
784-
data_buf);
781+
data_buf, &complete);
785782
}
786783
if (error)
787784
break;
@@ -790,7 +787,8 @@ static long ioctl_fill_blocks(struct file *f, void __user *arg)
790787
if (data_buf)
791788
free_pages((unsigned long)data_buf, get_order(data_buf_size));
792789

793-
maybe_delete_incomplete_file(f, df);
790+
if (complete)
791+
handle_file_completed(f, df);
794792

795793
/*
796794
* Only report the error if no records were processed, otherwise

0 commit comments

Comments
 (0)