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

Commit ece8e0b2 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-3.9-async' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq

Pull async changes from Tejun Heo:
 "These are followups for the earlier deadlock issue involving async
  ending up waiting for itself through block requesting module[1].  The
  following changes are made by these commits.

   - Instead of requesting default elevator on each request_queue init,
     block now requests it once early during boot.

   - Kmod triggers warning if invoked from an async worker.

   - Async synchronization implementation has been reimplemented.  It's
     a lot simpler now."

* 'for-3.9-async' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq:
  async: initialise list heads to fix crash
  async: replace list of active domains with global list of pending items
  async: keep pending tasks on async_domain and remove async_pending
  async: use ULLONG_MAX for infinity cookie value
  async: bring sanity to the use of words domain and running
  async, kmod: warn on synchronous request_module() from async workers
  block: don't request module during elevator init
  init, block: try to load default elevator module early during boot
parents 67cb104b a0327ff0
Loading
Loading
Loading
Loading
+28 −7
Original line number Diff line number Diff line
@@ -100,14 +100,14 @@ static void elevator_put(struct elevator_type *e)
	module_put(e->elevator_owner);
}

static struct elevator_type *elevator_get(const char *name)
static struct elevator_type *elevator_get(const char *name, bool try_loading)
{
	struct elevator_type *e;

	spin_lock(&elv_list_lock);

	e = elevator_find(name);
	if (!e) {
	if (!e && try_loading) {
		spin_unlock(&elv_list_lock);
		request_module("%s-iosched", name);
		spin_lock(&elv_list_lock);
@@ -136,6 +136,22 @@ static int __init elevator_setup(char *str)

__setup("elevator=", elevator_setup);

/* called during boot to load the elevator chosen by the elevator param */
void __init load_default_elevator_module(void)
{
	struct elevator_type *e;

	if (!chosen_elevator[0])
		return;

	spin_lock(&elv_list_lock);
	e = elevator_find(chosen_elevator);
	spin_unlock(&elv_list_lock);

	if (!e)
		request_module("%s-iosched", chosen_elevator);
}

static struct kobj_type elv_ktype;

static struct elevator_queue *elevator_alloc(struct request_queue *q,
@@ -191,25 +207,30 @@ int elevator_init(struct request_queue *q, char *name)
	q->boundary_rq = NULL;

	if (name) {
		e = elevator_get(name);
		e = elevator_get(name, true);
		if (!e)
			return -EINVAL;
	}

	/*
	 * Use the default elevator specified by config boot param or
	 * config option.  Don't try to load modules as we could be running
	 * off async and request_module() isn't allowed from async.
	 */
	if (!e && *chosen_elevator) {
		e = elevator_get(chosen_elevator);
		e = elevator_get(chosen_elevator, false);
		if (!e)
			printk(KERN_ERR "I/O scheduler %s not found\n",
							chosen_elevator);
	}

	if (!e) {
		e = elevator_get(CONFIG_DEFAULT_IOSCHED);
		e = elevator_get(CONFIG_DEFAULT_IOSCHED, false);
		if (!e) {
			printk(KERN_ERR
				"Default I/O scheduler not found. " \
				"Using noop.\n");
			e = elevator_get("noop");
			e = elevator_get("noop", false);
		}
	}

@@ -951,7 +972,7 @@ int elevator_change(struct request_queue *q, const char *name)
		return -ENXIO;

	strlcpy(elevator_name, name, sizeof(elevator_name));
	e = elevator_get(strstrip(elevator_name));
	e = elevator_get(strstrip(elevator_name), true);
	if (!e) {
		printk(KERN_ERR "elevator: type %s not found\n", elevator_name);
		return -EINVAL;
+3 −6
Original line number Diff line number Diff line
@@ -19,8 +19,7 @@ typedef u64 async_cookie_t;
typedef void (async_func_ptr) (void *data, async_cookie_t cookie);
struct async_domain {
	struct list_head node;
	struct list_head domain;
	int count;
	struct list_head pending;
	unsigned registered:1;
};

@@ -29,8 +28,7 @@ struct async_domain {
 */
#define ASYNC_DOMAIN(_name) \
	struct async_domain _name = { .node = LIST_HEAD_INIT(_name.node), \
				      .domain = LIST_HEAD_INIT(_name.domain), \
				      .count = 0, \
				      .pending = LIST_HEAD_INIT(_name.pending), \
				      .registered = 1 }

/*
@@ -39,8 +37,7 @@ struct async_domain {
 */
#define ASYNC_DOMAIN_EXCLUSIVE(_name) \
	struct async_domain _name = { .node = LIST_HEAD_INIT(_name.node), \
				      .domain = LIST_HEAD_INIT(_name.domain), \
				      .count = 0, \
				      .pending = LIST_HEAD_INIT(_name.pending), \
				      .registered = 0 }

extern async_cookie_t async_schedule(async_func_ptr *ptr, void *data);
+5 −0
Original line number Diff line number Diff line
@@ -138,6 +138,7 @@ extern void elv_drain_elevator(struct request_queue *);
/*
 * io scheduler registration
 */
extern void __init load_default_elevator_module(void);
extern int elv_register(struct elevator_type *);
extern void elv_unregister(struct elevator_type *);

@@ -206,5 +207,9 @@ enum {
	INIT_LIST_HEAD(&(rq)->csd.list);	\
	} while (0)

#else /* CONFIG_BLOCK */

static inline void load_default_elevator_module(void) { }

#endif /* CONFIG_BLOCK */
#endif
+1 −0
Original line number Diff line number Diff line
@@ -153,6 +153,7 @@ extern unsigned int reset_devices;
/* used by init/main.c */
void setup_arch(char **);
void prepare_namespace(void);
void __init load_default_modules(void);

extern void (*late_time_init)(void);

+3 −0
Original line number Diff line number Diff line
@@ -61,6 +61,9 @@ static void __init handle_initrd(void)
	sys_mkdir("/old", 0700);
	sys_chdir("/old");

	/* try loading default modules from initrd */
	load_default_modules();

	/*
	 * In case that a resume from disk is carried out by linuxrc or one of
	 * its children, we need to tell the freezer not to wait for us.
Loading