forked from mirrors/linux
		
	dm thin: stay in out-of-data-space mode once no_space_timeout expires
This fixes an issue where running out of data space would cause the thin-pool's metadata to become read-only. There was no reason to make metadata read-only -- calling set_pool_mode() with PM_READ_ONLY was a misguided way to error all queued and future write IOs. We can accomplish the same by degrading from PM_OUT_OF_DATA_SPACE to PM_OUT_OF_DATA_SPACE with error_if_no_space enabled. Otherwise, the use of PM_READ_ONLY could cause a race where commit() was started before the PM_READ_ONLY transition but dm_pool_commit_metadata() would go on to fail because the block manager had transitioned to read-only. The return of -EPERM from dm_pool_commit_metadata(), due to attempting to commit while in read-only mode, caused the thin-pool to set 'needs_check' because a metadata_operation_failed(). This needless cascade of failures makes life for users more difficult than needed. Reported-by: Vivek Goyal <vgoyal@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
This commit is contained in:
		
							parent
							
								
									b06075a98d
								
							
						
					
					
						commit
						bcc696fac1
					
				
					 1 changed files with 17 additions and 4 deletions
				
			
		|  | @ -2282,18 +2282,23 @@ static void do_waker(struct work_struct *ws) | |||
| 	queue_delayed_work(pool->wq, &pool->waker, COMMIT_PERIOD); | ||||
| } | ||||
| 
 | ||||
| static void notify_of_pool_mode_change_to_oods(struct pool *pool); | ||||
| 
 | ||||
| /*
 | ||||
|  * We're holding onto IO to allow userland time to react.  After the | ||||
|  * timeout either the pool will have been resized (and thus back in | ||||
|  * PM_WRITE mode), or we degrade to PM_READ_ONLY and start erroring IO. | ||||
|  * PM_WRITE mode), or we degrade to PM_OUT_OF_DATA_SPACE w/ error_if_no_space. | ||||
|  */ | ||||
| static void do_no_space_timeout(struct work_struct *ws) | ||||
| { | ||||
| 	struct pool *pool = container_of(to_delayed_work(ws), struct pool, | ||||
| 					 no_space_timeout); | ||||
| 
 | ||||
| 	if (get_pool_mode(pool) == PM_OUT_OF_DATA_SPACE && !pool->pf.error_if_no_space) | ||||
| 		set_pool_mode(pool, PM_READ_ONLY); | ||||
| 	if (get_pool_mode(pool) == PM_OUT_OF_DATA_SPACE && !pool->pf.error_if_no_space) { | ||||
| 		pool->pf.error_if_no_space = true; | ||||
| 		notify_of_pool_mode_change_to_oods(pool); | ||||
| 		error_retry_list(pool); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*----------------------------------------------------------------*/ | ||||
|  | @ -2371,6 +2376,14 @@ static void notify_of_pool_mode_change(struct pool *pool, const char *new_mode) | |||
| 	       dm_device_name(pool->pool_md), new_mode); | ||||
| } | ||||
| 
 | ||||
| static void notify_of_pool_mode_change_to_oods(struct pool *pool) | ||||
| { | ||||
| 	if (!pool->pf.error_if_no_space) | ||||
| 		notify_of_pool_mode_change(pool, "out-of-data-space (queue IO)"); | ||||
| 	else | ||||
| 		notify_of_pool_mode_change(pool, "out-of-data-space (error IO)"); | ||||
| } | ||||
| 
 | ||||
| static bool passdown_enabled(struct pool_c *pt) | ||||
| { | ||||
| 	return pt->adjusted_pf.discard_passdown; | ||||
|  | @ -2455,7 +2468,7 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode) | |||
| 		 * frequently seeing this mode. | ||||
| 		 */ | ||||
| 		if (old_mode != new_mode) | ||||
| 			notify_of_pool_mode_change(pool, "out-of-data-space"); | ||||
| 			notify_of_pool_mode_change_to_oods(pool); | ||||
| 		pool->process_bio = process_bio_read_only; | ||||
| 		pool->process_discard = process_discard_bio; | ||||
| 		pool->process_cell = process_cell_read_only; | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Mike Snitzer
						Mike Snitzer