summaryrefslogtreecommitdiff
path: root/fs/verity/enable.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/verity/enable.c')
-rw-r--r--fs/verity/enable.c41
1 files changed, 25 insertions, 16 deletions
diff --git a/fs/verity/enable.c b/fs/verity/enable.c
index 95ec42b84797..c9448074cce1 100644
--- a/fs/verity/enable.c
+++ b/fs/verity/enable.c
@@ -41,14 +41,15 @@ static int hash_one_block(const struct merkle_tree_params *params,
return 0;
}
-static int write_merkle_tree_block(struct inode *inode, const u8 *buf,
+static int write_merkle_tree_block(struct file *file, const u8 *buf,
unsigned long index,
const struct merkle_tree_params *params)
{
+ struct inode *inode = file_inode(file);
u64 pos = (u64)index << params->log_blocksize;
int err;
- err = inode->i_sb->s_vop->write_merkle_tree_block(inode, buf, pos,
+ err = inode->i_sb->s_vop->write_merkle_tree_block(file, buf, pos,
params->block_size);
if (err)
fsverity_err(inode, "Error %d writing Merkle tree block %lu",
@@ -135,7 +136,7 @@ static int build_merkle_tree(struct file *filp,
err = hash_one_block(params, &buffers[level]);
if (err)
goto out;
- err = write_merkle_tree_block(inode,
+ err = write_merkle_tree_block(filp,
buffers[level].data,
level_offset[level],
params);
@@ -155,7 +156,7 @@ static int build_merkle_tree(struct file *filp,
err = hash_one_block(params, &buffers[level]);
if (err)
goto out;
- err = write_merkle_tree_block(inode,
+ err = write_merkle_tree_block(filp,
buffers[level].data,
level_offset[level],
params);
@@ -265,8 +266,25 @@ static int enable_verity(struct file *filp,
}
/*
+ * Add the fsverity_info into the hash table before finishing the
+ * initialization so that we don't have to undo the enabling when memory
+ * allocation for the hash table fails. This is safe because looking up
+ * the fsverity_info always first checks the S_VERITY flag on the inode,
+ * which will only be set at the very end of the ->end_enable_verity
+ * method.
+ */
+ err = fsverity_set_info(vi);
+ if (err) {
+ fsverity_free_info(vi);
+ goto rollback;
+ }
+
+ /*
* Tell the filesystem to finish enabling verity on the file.
- * Serialized with ->begin_enable_verity() by the inode lock.
+ * Serialized with ->begin_enable_verity() by the inode lock. The file
+ * system needs to set the S_VERITY flag on the inode at the very end of
+ * the method, at which point the fsverity information can be accessed
+ * by other threads.
*/
inode_lock(inode);
err = vops->end_enable_verity(filp, desc, desc_size, params.tree_size);
@@ -274,19 +292,10 @@ static int enable_verity(struct file *filp,
if (err) {
fsverity_err(inode, "%ps() failed with err %d",
vops->end_enable_verity, err);
- fsverity_free_info(vi);
+ fsverity_remove_info(vi);
} else if (WARN_ON_ONCE(!IS_VERITY(inode))) {
+ fsverity_remove_info(vi);
err = -EINVAL;
- fsverity_free_info(vi);
- } else {
- /* Successfully enabled verity */
-
- /*
- * Readers can start using the inode's verity info immediately,
- * so it can't be rolled back once set. So don't set it until
- * just after the filesystem has successfully enabled verity.
- */
- fsverity_set_info(inode, vi);
}
out:
kfree(params.hashstate);