Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 334e94de authored by Al Viro's avatar Al Viro
Browse files

[PATCH] deal with rmmod/put_io_context() races



Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent e17a9489
Loading
Loading
Loading
Loading
+14 −1
Original line number Original line Diff line number Diff line
@@ -182,6 +182,9 @@ struct as_rq {


static kmem_cache_t *arq_pool;
static kmem_cache_t *arq_pool;


static atomic_t ioc_count = ATOMIC_INIT(0);
static struct completion *ioc_gone;

static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq);
static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq);
static void as_antic_stop(struct as_data *ad);
static void as_antic_stop(struct as_data *ad);


@@ -193,11 +196,14 @@ static void as_antic_stop(struct as_data *ad);
static void free_as_io_context(struct as_io_context *aic)
static void free_as_io_context(struct as_io_context *aic)
{
{
	kfree(aic);
	kfree(aic);
	if (atomic_dec_and_test(&ioc_count) && ioc_gone)
		complete(ioc_gone);
}
}


static void as_trim(struct io_context *ioc)
static void as_trim(struct io_context *ioc)
{
{
	kfree(ioc->aic);
	if (ioc->aic)
		free_as_io_context(ioc->aic);
	ioc->aic = NULL;
	ioc->aic = NULL;
}
}


@@ -226,6 +232,7 @@ static struct as_io_context *alloc_as_io_context(void)
		ret->seek_total = 0;
		ret->seek_total = 0;
		ret->seek_samples = 0;
		ret->seek_samples = 0;
		ret->seek_mean = 0;
		ret->seek_mean = 0;
		atomic_inc(&ioc_count);
	}
	}


	return ret;
	return ret;
@@ -1900,7 +1907,13 @@ static int __init as_init(void)


static void __exit as_exit(void)
static void __exit as_exit(void)
{
{
	DECLARE_COMPLETION(all_gone);
	elv_unregister(&iosched_as);
	elv_unregister(&iosched_as);
	ioc_gone = &all_gone;
	barrier();
	if (atomic_read(&ioc_count))
		complete(ioc_gone);
	synchronize_rcu();
	kmem_cache_destroy(arq_pool);
	kmem_cache_destroy(arq_pool);
}
}


+16 −0
Original line number Original line Diff line number Diff line
@@ -91,6 +91,9 @@ static kmem_cache_t *crq_pool;
static kmem_cache_t *cfq_pool;
static kmem_cache_t *cfq_pool;
static kmem_cache_t *cfq_ioc_pool;
static kmem_cache_t *cfq_ioc_pool;


static atomic_t ioc_count = ATOMIC_INIT(0);
static struct completion *ioc_gone;

#define CFQ_PRIO_LISTS		IOPRIO_BE_NR
#define CFQ_PRIO_LISTS		IOPRIO_BE_NR
#define cfq_class_idle(cfqq)	((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE)
#define cfq_class_idle(cfqq)	((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE)
#define cfq_class_be(cfqq)	((cfqq)->ioprio_class == IOPRIO_CLASS_BE)
#define cfq_class_be(cfqq)	((cfqq)->ioprio_class == IOPRIO_CLASS_BE)
@@ -1202,13 +1205,17 @@ static void cfq_free_io_context(struct cfq_io_context *cic)
{
{
	struct cfq_io_context *__cic;
	struct cfq_io_context *__cic;
	struct list_head *entry, *next;
	struct list_head *entry, *next;
	int freed = 1;


	list_for_each_safe(entry, next, &cic->list) {
	list_for_each_safe(entry, next, &cic->list) {
		__cic = list_entry(entry, struct cfq_io_context, list);
		__cic = list_entry(entry, struct cfq_io_context, list);
		kmem_cache_free(cfq_ioc_pool, __cic);
		kmem_cache_free(cfq_ioc_pool, __cic);
		freed++;
	}
	}


	kmem_cache_free(cfq_ioc_pool, cic);
	kmem_cache_free(cfq_ioc_pool, cic);
	if (atomic_sub_and_test(freed, &ioc_count) && ioc_gone)
		complete(ioc_gone);
}
}


static void cfq_trim(struct io_context *ioc)
static void cfq_trim(struct io_context *ioc)
@@ -1297,6 +1304,7 @@ cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
		cic->dtor = cfq_free_io_context;
		cic->dtor = cfq_free_io_context;
		cic->exit = cfq_exit_io_context;
		cic->exit = cfq_exit_io_context;
		INIT_LIST_HEAD(&cic->queue_list);
		INIT_LIST_HEAD(&cic->queue_list);
		atomic_inc(&ioc_count);
	}
	}


	return cic;
	return cic;
@@ -1501,6 +1509,7 @@ cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask)
						      list);
						      list);
			read_unlock(&cfq_exit_lock);
			read_unlock(&cfq_exit_lock);
			kmem_cache_free(cfq_ioc_pool, cic);
			kmem_cache_free(cfq_ioc_pool, cic);
			atomic_dec(&ioc_count);
			goto restart;
			goto restart;
		}
		}


@@ -1523,6 +1532,7 @@ cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask)
				list_del(&__cic->list);
				list_del(&__cic->list);
				read_unlock(&cfq_exit_lock);
				read_unlock(&cfq_exit_lock);
				kmem_cache_free(cfq_ioc_pool, __cic);
				kmem_cache_free(cfq_ioc_pool, __cic);
				atomic_dec(&ioc_count);
				goto restart;
				goto restart;
			}
			}
		}
		}
@@ -2510,7 +2520,13 @@ static int __init cfq_init(void)


static void __exit cfq_exit(void)
static void __exit cfq_exit(void)
{
{
	DECLARE_COMPLETION(all_gone);
	elv_unregister(&iosched_cfq);
	elv_unregister(&iosched_cfq);
	ioc_gone = &all_gone;
	barrier();
	if (atomic_read(&ioc_count))
		complete(ioc_gone);
	synchronize_rcu();
	cfq_slab_kill();
	cfq_slab_kill();
}
}


+2 −0
Original line number Original line Diff line number Diff line
@@ -3477,10 +3477,12 @@ void put_io_context(struct io_context *ioc)
	BUG_ON(atomic_read(&ioc->refcount) == 0);
	BUG_ON(atomic_read(&ioc->refcount) == 0);


	if (atomic_dec_and_test(&ioc->refcount)) {
	if (atomic_dec_and_test(&ioc->refcount)) {
		rcu_read_lock();
		if (ioc->aic && ioc->aic->dtor)
		if (ioc->aic && ioc->aic->dtor)
			ioc->aic->dtor(ioc->aic);
			ioc->aic->dtor(ioc->aic);
		if (ioc->cic && ioc->cic->dtor)
		if (ioc->cic && ioc->cic->dtor)
			ioc->cic->dtor(ioc->cic);
			ioc->cic->dtor(ioc->cic);
		rcu_read_unlock();


		kmem_cache_free(iocontext_cachep, ioc);
		kmem_cache_free(iocontext_cachep, ioc);
	}
	}