⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cfq-iosched.c

📁 Linux块设备驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
			return crq;		}	}	return NULL;}/* * Scale schedule slice based on io priority. Use the sync time slice only * if a queue is marked sync and has sync io queued. A sync queue with async * io only, should not get full sync slice length. */static inline intcfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq){	const int base_slice = cfqd->cfq_slice[cfq_cfqq_sync(cfqq)];	WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR);	return base_slice + (base_slice/CFQ_SLICE_SCALE * (4 - cfqq->ioprio));}static inline voidcfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq){	cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies;}static inline intcfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq){	const int base_rq = cfqd->cfq_slice_async_rq;	WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR);	return 2 * (base_rq + base_rq * (CFQ_PRIO_LISTS - 1 - cfqq->ioprio));}/* * get next queue for service */static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd, int force){	unsigned long now = jiffies;	struct cfq_queue *cfqq;	cfqq = cfqd->active_queue;	if (!cfqq)		goto new_queue;	if (cfq_cfqq_expired(cfqq))		goto new_queue;	/*	 * slice has expired	 */	if (!cfq_cfqq_must_dispatch(cfqq) && time_after(now, cfqq->slice_end))		goto expire;	/*	 * if queue has requests, dispatch one. if not, check if	 * enough slice is left to wait for one	 */	if (!RB_EMPTY(&cfqq->sort_list))		goto keep_queue;	else if (!force && cfq_cfqq_class_sync(cfqq) &&		 time_before(now, cfqq->slice_end)) {		if (cfq_arm_slice_timer(cfqd, cfqq))			return NULL;	}expire:	cfq_slice_expired(cfqd, 0);new_queue:	cfqq = cfq_set_active_queue(cfqd);keep_queue:	return cfqq;}static int__cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,			int max_dispatch){	int dispatched = 0;	BUG_ON(RB_EMPTY(&cfqq->sort_list));	do {		struct cfq_rq *crq;		/*		 * follow expired path, else get first next available		 */		if ((crq = cfq_check_fifo(cfqq)) == NULL)			crq = cfqq->next_crq;		/*		 * finally, insert request into driver dispatch list		 */		cfq_dispatch_sort(cfqd->queue, crq);		cfqd->dispatch_slice++;		dispatched++;		if (!cfqd->active_cic) {			atomic_inc(&crq->io_context->ioc->refcount);			cfqd->active_cic = crq->io_context;		}		if (RB_EMPTY(&cfqq->sort_list))			break;	} while (dispatched < max_dispatch);	/*	 * if slice end isn't set yet, set it. if at least one request was	 * sync, use the sync time slice value	 */	if (!cfqq->slice_end)		cfq_set_prio_slice(cfqd, cfqq);	/*	 * expire an async queue immediately if it has used up its slice. idle	 * queue always expire after 1 dispatch round.	 */	if ((!cfq_cfqq_sync(cfqq) &&	    cfqd->dispatch_slice >= cfq_prio_to_maxrq(cfqd, cfqq)) ||	    cfq_class_idle(cfqq))		cfq_slice_expired(cfqd, 0);	return dispatched;}static intcfq_dispatch_requests(request_queue_t *q, int max_dispatch, int force){	struct cfq_data *cfqd = q->elevator->elevator_data;	struct cfq_queue *cfqq;	if (!cfqd->busy_queues)		return 0;	cfqq = cfq_select_queue(cfqd, force);	if (cfqq) {		cfq_clear_cfqq_must_dispatch(cfqq);		cfq_clear_cfqq_wait_request(cfqq);		del_timer(&cfqd->idle_slice_timer);		if (cfq_class_idle(cfqq))			max_dispatch = 1;		return __cfq_dispatch_requests(cfqd, cfqq, max_dispatch);	}	return 0;}static inline void cfq_account_dispatch(struct cfq_rq *crq){	struct cfq_queue *cfqq = crq->cfq_queue;	struct cfq_data *cfqd = cfqq->cfqd;	if (unlikely(!blk_fs_request(crq->request)))		return;	/*	 * accounted bit is necessary since some drivers will call	 * elv_next_request() many times for the same request (eg ide)	 */	if (cfq_crq_in_driver(crq))		return;	cfq_mark_crq_in_driver(crq);	cfqd->rq_in_driver++;}static inline voidcfq_account_completion(struct cfq_queue *cfqq, struct cfq_rq *crq){	struct cfq_data *cfqd = cfqq->cfqd;	unsigned long now;	if (!cfq_crq_in_driver(crq))		return;	now = jiffies;	WARN_ON(!cfqd->rq_in_driver);	cfqd->rq_in_driver--;	if (!cfq_class_idle(cfqq))		cfqd->last_end_request = now;	if (!cfq_cfqq_dispatched(cfqq)) {		if (cfq_cfqq_on_rr(cfqq)) {			cfqq->service_last = now;			cfq_resort_rr_list(cfqq, 0);		}		if (cfq_cfqq_expired(cfqq)) {			__cfq_slice_expired(cfqd, cfqq, 0);			cfq_schedule_dispatch(cfqd);		}	}	if (cfq_crq_is_sync(crq))		crq->io_context->last_end_request = now;}static struct request *cfq_next_request(request_queue_t *q){	struct cfq_data *cfqd = q->elevator->elevator_data;	struct request *rq;	if (!list_empty(&q->queue_head)) {		struct cfq_rq *crq;dispatch:		rq = list_entry_rq(q->queue_head.next);		crq = RQ_DATA(rq);		if (crq) {			struct cfq_queue *cfqq = crq->cfq_queue;			/*			 * if idle window is disabled, allow queue buildup			 */			if (!cfq_crq_in_driver(crq) &&			    !cfq_cfqq_idle_window(cfqq) &&			    !blk_barrier_rq(rq) &&			    cfqd->rq_in_driver >= cfqd->cfq_max_depth)				return NULL;			cfq_remove_merge_hints(q, crq);			cfq_account_dispatch(crq);		}		return rq;	}	if (cfq_dispatch_requests(q, cfqd->cfq_quantum, 0))		goto dispatch;	return NULL;}/* * task holds one reference to the queue, dropped when task exits. each crq * in-flight on this queue also holds a reference, dropped when crq is freed. * * queue lock must be held here. */static void cfq_put_queue(struct cfq_queue *cfqq){	struct cfq_data *cfqd = cfqq->cfqd;	BUG_ON(atomic_read(&cfqq->ref) <= 0);	if (!atomic_dec_and_test(&cfqq->ref))		return;	BUG_ON(rb_first(&cfqq->sort_list));	BUG_ON(cfqq->allocated[READ] + cfqq->allocated[WRITE]);	BUG_ON(cfq_cfqq_on_rr(cfqq));	if (unlikely(cfqd->active_queue == cfqq)) {		__cfq_slice_expired(cfqd, cfqq, 0);		cfq_schedule_dispatch(cfqd);	}	cfq_put_cfqd(cfqq->cfqd);	/*	 * it's on the empty list and still hashed	 */	list_del(&cfqq->cfq_list);	hlist_del(&cfqq->cfq_hash);	kmem_cache_free(cfq_pool, cfqq);}static inline struct cfq_queue *__cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned int prio,		    const int hashval){	struct hlist_head *hash_list = &cfqd->cfq_hash[hashval];	struct hlist_node *entry, *next;	hlist_for_each_safe(entry, next, hash_list) {		struct cfq_queue *__cfqq = list_entry_qhash(entry);		const unsigned short __p = IOPRIO_PRIO_VALUE(__cfqq->ioprio_class, __cfqq->ioprio);		if (__cfqq->key == key && (__p == prio || prio == CFQ_KEY_ANY))			return __cfqq;	}	return NULL;}static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned short prio){	return __cfq_find_cfq_hash(cfqd, key, prio, hash_long(key, CFQ_QHASH_SHIFT));}static void cfq_free_io_context(struct cfq_io_context *cic){	struct cfq_io_context *__cic;	struct list_head *entry, *next;	list_for_each_safe(entry, next, &cic->list) {		__cic = list_entry(entry, struct cfq_io_context, list);		kmem_cache_free(cfq_ioc_pool, __cic);	}	kmem_cache_free(cfq_ioc_pool, cic);}/* * Called with interrupts disabled */static void cfq_exit_single_io_context(struct cfq_io_context *cic){	struct cfq_data *cfqd = cic->cfqq->cfqd;	request_queue_t *q = cfqd->queue;	WARN_ON(!irqs_disabled());	spin_lock(q->queue_lock);	if (unlikely(cic->cfqq == cfqd->active_queue)) {		__cfq_slice_expired(cfqd, cic->cfqq, 0);		cfq_schedule_dispatch(cfqd);	}	cfq_put_queue(cic->cfqq);	cic->cfqq = NULL;	spin_unlock(q->queue_lock);}/* * Another task may update the task cic list, if it is doing a queue lookup * on its behalf. cfq_cic_lock excludes such concurrent updates */static void cfq_exit_io_context(struct cfq_io_context *cic){	struct cfq_io_context *__cic;	struct list_head *entry;	unsigned long flags;	local_irq_save(flags);	/*	 * put the reference this task is holding to the various queues	 */	list_for_each(entry, &cic->list) {		__cic = list_entry(entry, struct cfq_io_context, list);		cfq_exit_single_io_context(__cic);	}	cfq_exit_single_io_context(cic);	local_irq_restore(flags);}static struct cfq_io_context *cfq_alloc_io_context(struct cfq_data *cfqd, int gfp_mask){	struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask);	if (cic) {		INIT_LIST_HEAD(&cic->list);		cic->cfqq = NULL;		cic->key = NULL;		cic->last_end_request = jiffies;		cic->ttime_total = 0;		cic->ttime_samples = 0;		cic->ttime_mean = 0;		cic->dtor = cfq_free_io_context;		cic->exit = cfq_exit_io_context;	}	return cic;}static void cfq_init_prio_data(struct cfq_queue *cfqq){	struct task_struct *tsk = current;	int ioprio_class;	if (!cfq_cfqq_prio_changed(cfqq))		return;	ioprio_class = IOPRIO_PRIO_CLASS(tsk->ioprio);	switch (ioprio_class) {		default:			printk(KERN_ERR "cfq: bad prio %x\n", ioprio_class);		case IOPRIO_CLASS_NONE:			/*			 * no prio set, place us in the middle of the BE classes			 */			cfqq->ioprio = task_nice_ioprio(tsk);			cfqq->ioprio_class = IOPRIO_CLASS_BE;			break;		case IOPRIO_CLASS_RT:			cfqq->ioprio = task_ioprio(tsk);			cfqq->ioprio_class = IOPRIO_CLASS_RT;			break;		case IOPRIO_CLASS_BE:			cfqq->ioprio = task_ioprio(tsk);			cfqq->ioprio_class = IOPRIO_CLASS_BE;			break;		case IOPRIO_CLASS_IDLE:			cfqq->ioprio_class = IOPRIO_CLASS_IDLE;			cfqq->ioprio = 7;			cfq_clear_cfqq_idle_window(cfqq);			break;	}	/*	 * keep track of original prio settings in case we have to temporarily	 * elevate the priority of this queue	 */	cfqq->org_ioprio = cfqq->ioprio;	cfqq->org_ioprio_class = cfqq->ioprio_class;	if (cfq_cfqq_on_rr(cfqq))		cfq_resort_rr_list(cfqq, 0);	cfq_clear_cfqq_prio_changed(cfqq);}static inline void changed_ioprio(struct cfq_queue *cfqq){	if (cfqq) {		struct cfq_data *cfqd = cfqq->cfqd;		spin_lock(cfqd->queue->queue_lock);		cfq_mark_cfqq_prio_changed(cfqq);		cfq_init_prio_data(cfqq);		spin_unlock(cfqd->queue->queue_lock);	}}/* * callback from sys_ioprio_set, irqs are disabled */static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio){	struct cfq_io_context *cic = ioc->cic;	changed_ioprio(cic->cfqq);	list_for_each_entry(cic, &cic->list, list)		changed_ioprio(cic->cfqq);	return 0;}static struct cfq_queue *cfq_get_queue(struct cfq_data *cfqd, unsigned int key, unsigned short ioprio,	      int gfp_mask){	const int hashval = hash_long(key, CFQ_QHASH_SHIFT);	struct cfq_queue *cfqq, *new_cfqq = NULL;retry:	cfqq = __cfq_find_cfq_hash(cfqd, key, ioprio, hashval);	if (!cfqq) {		if (new_cfqq) {			cfqq = new_cfqq;			new_cfqq = NULL;		} else if (gfp_mask & __GFP_WAIT) {			spin_unlock_irq(cfqd->queue->queue_lock);			new_cfqq = kmem_cache_alloc(cfq_pool, gfp_mask);			spin_lock_irq(cfqd->queue->queue_lock);			goto retry;		} else {			cfqq = kmem_cache_alloc(cfq_pool, gfp_mask);			if (!cfqq)				goto out;		}		memset(cfqq, 0, sizeof(*cfqq));		INIT_HLIST_NODE(&cfqq->cfq_hash);		INIT_LIST_HEAD(&cfqq->cfq_list);		RB_CLEAR_ROOT(&cfqq->sort_list);		INIT_LIST_HEAD(&cfqq->fifo);		cfqq->key = key;		hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);		atomic_set(&cfqq->ref, 0);		cfqq->cfqd = cfqd;		atomic_inc(&cfqd->ref);		cfqq->service_last = 0;		/*		 * set ->slice_left to allow preemption for a new process		 */		cfqq->slice_left = 2 * cfqd->cfq_slice_idle;		cfq_mark_cfqq_idle_window(cfqq);		cfq_mark_cfqq_prio_changed(cfqq);		cfq_init_prio_data(cfqq);	}	if (new_cfqq)		kmem_cache_free(cfq_pool, new_cfqq);	atomic_inc(&cfqq->ref);out:	WARN_ON((gfp_mask & __GFP_WAIT) && !cfqq);	return cfqq;}/* * Setup general io context and cfq io context. There can be several cfq * io contexts per general io context, if this process is doing io to more * than one device managed by cfq. Note that caller is holding a reference to * cfqq, so we don't need to worry about it disappearing */static struct cfq_io_context *cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, int gfp_mask){	struct io_context *ioc = NULL;	struct cfq_io_context *cic;	might_sleep_if(gfp_mask & __GFP_WAIT);	ioc = get_io_context(gfp_mask);	if (!ioc)		return NULL;	if ((cic = ioc->cic) == NULL) {		cic = cfq_alloc_io_context(cfqd, gfp_mask);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -