mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	mm/damon/sysfs-schemes: add timeout for update_schemes_tried_regions
If a scheme is set to not applied to any monitoring target region for any
reasons including the target access pattern, quota, filters, or
watermarks, writing 'update_schemes_tried_regions' to 'state' DAMON sysfs
file can indefinitely hang.  Fix the case by implementing a timeout for
the operation.  The time limit is two apply intervals of each scheme.
Link: https://lkml.kernel.org/r/20231124213840.39157-1-sj@kernel.org
Fixes: 4d4e41b682 ("mm/damon/sysfs-schemes: do not update tried regions more than one DAMON snapshot")
Signed-off-by: SeongJae Park <sj@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
			
			
This commit is contained in:
		
							parent
							
								
									854f2764b5
								
							
						
					
					
						commit
						7d6fa31a2f
					
				
					 1 changed files with 43 additions and 6 deletions
				
			
		| 
						 | 
					@ -139,6 +139,13 @@ static const struct kobj_type damon_sysfs_scheme_region_ktype = {
 | 
				
			||||||
 * damon_sysfs_before_damos_apply() understands the situation by showing the
 | 
					 * damon_sysfs_before_damos_apply() understands the situation by showing the
 | 
				
			||||||
 * 'finished' status and do nothing.
 | 
					 * 'finished' status and do nothing.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 | 
					 * If DAMOS is not applied to any region due to any reasons including the
 | 
				
			||||||
 | 
					 * access pattern, the watermarks, the quotas, and the filters,
 | 
				
			||||||
 | 
					 * ->before_damos_apply() will not be called back.  Until the situation is
 | 
				
			||||||
 | 
					 * changed, the update will not be finished.  To avoid this,
 | 
				
			||||||
 | 
					 * damon_sysfs_after_sampling() set the status as 'finished' if more than two
 | 
				
			||||||
 | 
					 * apply intervals of the scheme is passed while the state is 'idle'.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 *  Finally, the tried regions request handling finisher function
 | 
					 *  Finally, the tried regions request handling finisher function
 | 
				
			||||||
 *  (damon_sysfs_schemes_update_regions_stop()) unregisters the callbacks.
 | 
					 *  (damon_sysfs_schemes_update_regions_stop()) unregisters the callbacks.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -154,6 +161,7 @@ struct damon_sysfs_scheme_regions {
 | 
				
			||||||
	int nr_regions;
 | 
						int nr_regions;
 | 
				
			||||||
	unsigned long total_bytes;
 | 
						unsigned long total_bytes;
 | 
				
			||||||
	enum damos_sysfs_regions_upd_status upd_status;
 | 
						enum damos_sysfs_regions_upd_status upd_status;
 | 
				
			||||||
 | 
						unsigned long upd_timeout_jiffies;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct damon_sysfs_scheme_regions *
 | 
					static struct damon_sysfs_scheme_regions *
 | 
				
			||||||
| 
						 | 
					@ -1854,7 +1862,9 @@ static int damon_sysfs_after_sampling(struct damon_ctx *ctx)
 | 
				
			||||||
	for (i = 0; i < sysfs_schemes->nr; i++) {
 | 
						for (i = 0; i < sysfs_schemes->nr; i++) {
 | 
				
			||||||
		sysfs_regions = sysfs_schemes->schemes_arr[i]->tried_regions;
 | 
							sysfs_regions = sysfs_schemes->schemes_arr[i]->tried_regions;
 | 
				
			||||||
		if (sysfs_regions->upd_status ==
 | 
							if (sysfs_regions->upd_status ==
 | 
				
			||||||
				DAMOS_TRIED_REGIONS_UPD_STARTED)
 | 
									DAMOS_TRIED_REGIONS_UPD_STARTED ||
 | 
				
			||||||
 | 
									time_after(jiffies,
 | 
				
			||||||
 | 
										sysfs_regions->upd_timeout_jiffies))
 | 
				
			||||||
			sysfs_regions->upd_status =
 | 
								sysfs_regions->upd_status =
 | 
				
			||||||
				DAMOS_TRIED_REGIONS_UPD_FINISHED;
 | 
									DAMOS_TRIED_REGIONS_UPD_FINISHED;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1885,14 +1895,41 @@ int damon_sysfs_schemes_clear_regions(
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct damos *damos_sysfs_nth_scheme(int n, struct damon_ctx *ctx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct damos *scheme;
 | 
				
			||||||
 | 
						int i = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						damon_for_each_scheme(scheme, ctx) {
 | 
				
			||||||
 | 
							if (i == n)
 | 
				
			||||||
 | 
								return scheme;
 | 
				
			||||||
 | 
							i++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void damos_tried_regions_init_upd_status(
 | 
					static void damos_tried_regions_init_upd_status(
 | 
				
			||||||
		struct damon_sysfs_schemes *sysfs_schemes)
 | 
							struct damon_sysfs_schemes *sysfs_schemes,
 | 
				
			||||||
 | 
							struct damon_ctx *ctx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
						struct damos *scheme;
 | 
				
			||||||
 | 
						struct damon_sysfs_scheme_regions *sysfs_regions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < sysfs_schemes->nr; i++)
 | 
						for (i = 0; i < sysfs_schemes->nr; i++) {
 | 
				
			||||||
		sysfs_schemes->schemes_arr[i]->tried_regions->upd_status =
 | 
							sysfs_regions = sysfs_schemes->schemes_arr[i]->tried_regions;
 | 
				
			||||||
			DAMOS_TRIED_REGIONS_UPD_IDLE;
 | 
							scheme = damos_sysfs_nth_scheme(i, ctx);
 | 
				
			||||||
 | 
							if (!scheme) {
 | 
				
			||||||
 | 
								sysfs_regions->upd_status =
 | 
				
			||||||
 | 
									DAMOS_TRIED_REGIONS_UPD_FINISHED;
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							sysfs_regions->upd_status = DAMOS_TRIED_REGIONS_UPD_IDLE;
 | 
				
			||||||
 | 
							sysfs_regions->upd_timeout_jiffies = jiffies +
 | 
				
			||||||
 | 
								2 * usecs_to_jiffies(scheme->apply_interval_us ?
 | 
				
			||||||
 | 
										scheme->apply_interval_us :
 | 
				
			||||||
 | 
										ctx->attrs.sample_interval);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock */
 | 
					/* Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock */
 | 
				
			||||||
| 
						 | 
					@ -1902,7 +1939,7 @@ int damon_sysfs_schemes_update_regions_start(
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	damon_sysfs_schemes_clear_regions(sysfs_schemes, ctx);
 | 
						damon_sysfs_schemes_clear_regions(sysfs_schemes, ctx);
 | 
				
			||||||
	damon_sysfs_schemes_for_damos_callback = sysfs_schemes;
 | 
						damon_sysfs_schemes_for_damos_callback = sysfs_schemes;
 | 
				
			||||||
	damos_tried_regions_init_upd_status(sysfs_schemes);
 | 
						damos_tried_regions_init_upd_status(sysfs_schemes, ctx);
 | 
				
			||||||
	damos_regions_upd_total_bytes_only = total_bytes_only;
 | 
						damos_regions_upd_total_bytes_only = total_bytes_only;
 | 
				
			||||||
	ctx->callback.before_damos_apply = damon_sysfs_before_damos_apply;
 | 
						ctx->callback.before_damos_apply = damon_sysfs_before_damos_apply;
 | 
				
			||||||
	ctx->callback.after_sampling = damon_sysfs_after_sampling;
 | 
						ctx->callback.after_sampling = damon_sysfs_after_sampling;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue