diff options
Diffstat (limited to 'fs/verity/enable.c')
| -rw-r--r-- | fs/verity/enable.c | 45 |
1 files changed, 29 insertions, 16 deletions
diff --git a/fs/verity/enable.c b/fs/verity/enable.c index 95ec42b84797..42dfed1ce0ce 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); @@ -222,6 +223,8 @@ static int enable_verity(struct file *filp, if (err) goto out; + trace_fsverity_enable(inode, ¶ms); + /* * Start enabling verity on this file, serialized by the inode lock. * Fail if verity is already enabled or is already being enabled. @@ -264,9 +267,28 @@ static int enable_verity(struct file *filp, goto rollback; } + trace_fsverity_tree_done(inode, vi, ¶ms); + + /* + * 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 +296,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); |
