diff options
Diffstat (limited to 'fs/verity/verify.c')
| -rw-r--r-- | fs/verity/verify.c | 48 | 
1 files changed, 24 insertions, 24 deletions
diff --git a/fs/verity/verify.c b/fs/verity/verify.c index 904ccd7e8e16..4fcad0825a12 100644 --- a/fs/verity/verify.c +++ b/fs/verity/verify.c @@ -19,7 +19,6 @@ static struct workqueue_struct *fsverity_read_workqueue;  static bool is_hash_block_verified(struct fsverity_info *vi, struct page *hpage,  				   unsigned long hblock_idx)  { -	bool verified;  	unsigned int blocks_per_page;  	unsigned int i; @@ -43,12 +42,20 @@ static bool is_hash_block_verified(struct fsverity_info *vi, struct page *hpage,  	 * re-instantiated from the backing storage are re-verified.  To do  	 * this, we use PG_checked again, but now it doesn't really mean  	 * "checked".  Instead, now it just serves as an indicator for whether -	 * the hash page is newly instantiated or not. +	 * the hash page is newly instantiated or not.  If the page is new, as +	 * indicated by PG_checked=0, we clear the bitmap bits for the page's +	 * blocks since they are untrustworthy, then set PG_checked=1. +	 * Otherwise we return the bitmap bit for the requested block.  	 * -	 * The first thread that sees PG_checked=0 must clear the corresponding -	 * bitmap bits, then set PG_checked=1.  This requires a spinlock.  To -	 * avoid having to take this spinlock in the common case of -	 * PG_checked=1, we start with an opportunistic lockless read. +	 * Multiple threads may execute this code concurrently on the same page. +	 * This is safe because we use memory barriers to ensure that if a +	 * thread sees PG_checked=1, then it also sees the associated bitmap +	 * clearing to have occurred.  Also, all writes and their corresponding +	 * reads are atomic, and all writes are safe to repeat in the event that +	 * multiple threads get into the PG_checked=0 section.  (Clearing a +	 * bitmap bit again at worst causes a hash block to be verified +	 * redundantly.  That event should be very rare, so it's not worth using +	 * a lock to avoid.  Setting PG_checked again has no effect.)  	 */  	if (PageChecked(hpage)) {  		/* @@ -58,24 +65,17 @@ static bool is_hash_block_verified(struct fsverity_info *vi, struct page *hpage,  		smp_rmb();  		return test_bit(hblock_idx, vi->hash_block_verified);  	} -	spin_lock(&vi->hash_page_init_lock); -	if (PageChecked(hpage)) { -		verified = test_bit(hblock_idx, vi->hash_block_verified); -	} else { -		blocks_per_page = vi->tree_params.blocks_per_page; -		hblock_idx = round_down(hblock_idx, blocks_per_page); -		for (i = 0; i < blocks_per_page; i++) -			clear_bit(hblock_idx + i, vi->hash_block_verified); -		/* -		 * A write memory barrier is needed here to give RELEASE -		 * semantics to the below SetPageChecked() operation. -		 */ -		smp_wmb(); -		SetPageChecked(hpage); -		verified = false; -	} -	spin_unlock(&vi->hash_page_init_lock); -	return verified; +	blocks_per_page = vi->tree_params.blocks_per_page; +	hblock_idx = round_down(hblock_idx, blocks_per_page); +	for (i = 0; i < blocks_per_page; i++) +		clear_bit(hblock_idx + i, vi->hash_block_verified); +	/* +	 * A write memory barrier is needed here to give RELEASE semantics to +	 * the below SetPageChecked() operation. +	 */ +	smp_wmb(); +	SetPageChecked(hpage); +	return false;  }  /*  |