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

Commit 2034c19c authored by Hillf Danton's avatar Hillf Danton Committed by James Bottomley
Browse files

[SCSI] libfc: tune fc_exch_em_alloc() to be O(2)



For allocating new exch from pool,  scanning for free slot in exch
array fluctuates when exch pool is close to exhaustion.

The fluctuation is smoothed, and the scan looks to be O(2).

Signed-off-by: default avatarHillf Danton <dhillf@gmail.com>
Signed-off-by: default avatarRobert Love <robert.w.love@intel.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 8236554a
Loading
Loading
Loading
Loading
+33 −3
Original line number Diff line number Diff line
@@ -67,6 +67,11 @@ struct workqueue_struct *fc_exch_workqueue;
struct fc_exch_pool {
	u16		 next_index;
	u16		 total_exches;

	/* two cache of free slot in exch array */
	u16		 left;
	u16		 right;

	spinlock_t	 lock;
	struct list_head ex_list;
};
@@ -396,13 +401,23 @@ static inline void fc_exch_ptr_set(struct fc_exch_pool *pool, u16 index,
static void fc_exch_delete(struct fc_exch *ep)
{
	struct fc_exch_pool *pool;
	u16 index;

	pool = ep->pool;
	spin_lock_bh(&pool->lock);
	WARN_ON(pool->total_exches <= 0);
	pool->total_exches--;
	fc_exch_ptr_set(pool, (ep->xid - ep->em->min_xid) >> fc_cpu_order,
			NULL);

	/* update cache of free slot */
	index = (ep->xid - ep->em->min_xid) >> fc_cpu_order;
	if (pool->left == FC_XID_UNKNOWN)
		pool->left = index;
	else if (pool->right == FC_XID_UNKNOWN)
		pool->right = index;
	else
		pool->next_index = index;

	fc_exch_ptr_set(pool, index, NULL);
	list_del(&ep->ex_list);
	spin_unlock_bh(&pool->lock);
	fc_exch_release(ep);	/* drop hold for exch in mp */
@@ -678,6 +693,19 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport,
	pool = per_cpu_ptr(mp->pool, cpu);
	spin_lock_bh(&pool->lock);
	put_cpu();

	/* peek cache of free slot */
	if (pool->left != FC_XID_UNKNOWN) {
		index = pool->left;
		pool->left = FC_XID_UNKNOWN;
		goto hit;
	}
	if (pool->right != FC_XID_UNKNOWN) {
		index = pool->right;
		pool->right = FC_XID_UNKNOWN;
		goto hit;
	}

	index = pool->next_index;
	/* allocate new exch from pool */
	while (fc_exch_ptr_get(pool, index)) {
@@ -686,7 +714,7 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport,
			goto err;
	}
	pool->next_index = index == mp->pool_max_index ? 0 : index + 1;

hit:
	fc_exch_hold(ep);	/* hold for exch in mp */
	spin_lock_init(&ep->ex_lock);
	/*
@@ -2180,6 +2208,8 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lport,
		goto free_mempool;
	for_each_possible_cpu(cpu) {
		pool = per_cpu_ptr(mp->pool, cpu);
		pool->left = FC_XID_UNKNOWN;
		pool->right = FC_XID_UNKNOWN;
		spin_lock_init(&pool->lock);
		INIT_LIST_HEAD(&pool->ex_list);
	}