Commit 1bc144b6 authored by Huang Ying's avatar Huang Ying Committed by David S. Miller

net, rds, Replace xlist in net/rds/xlist.h with llist

The functionality of xlist and llist is almost same.  This patch
replace xlist with llist to avoid code duplication.

Known issues: don't know how to test this, need special hardware?
Signed-off-by: default avatarHuang Ying <ying.huang@intel.com>
Cc: Chris Mason <chris.mason@oracle.com>
Cc: Andy Grover <andy.grover@oracle.com>
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent dc00fd44
...@@ -9,6 +9,7 @@ config RDS ...@@ -9,6 +9,7 @@ config RDS
config RDS_RDMA config RDS_RDMA
tristate "RDS over Infiniband and iWARP" tristate "RDS over Infiniband and iWARP"
select LLIST
depends on RDS && INFINIBAND && INFINIBAND_ADDR_TRANS depends on RDS && INFINIBAND && INFINIBAND_ADDR_TRANS
---help--- ---help---
Allow RDS to use Infiniband and iWARP as a transport. Allow RDS to use Infiniband and iWARP as a transport.
......
...@@ -33,10 +33,10 @@ ...@@ -33,10 +33,10 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/rculist.h> #include <linux/rculist.h>
#include <linux/llist.h>
#include "rds.h" #include "rds.h"
#include "ib.h" #include "ib.h"
#include "xlist.h"
static DEFINE_PER_CPU(unsigned long, clean_list_grace); static DEFINE_PER_CPU(unsigned long, clean_list_grace);
#define CLEAN_LIST_BUSY_BIT 0 #define CLEAN_LIST_BUSY_BIT 0
...@@ -49,7 +49,7 @@ struct rds_ib_mr { ...@@ -49,7 +49,7 @@ struct rds_ib_mr {
struct rds_ib_mr_pool *pool; struct rds_ib_mr_pool *pool;
struct ib_fmr *fmr; struct ib_fmr *fmr;
struct xlist_head xlist; struct llist_node llnode;
/* unmap_list is for freeing */ /* unmap_list is for freeing */
struct list_head unmap_list; struct list_head unmap_list;
...@@ -71,9 +71,9 @@ struct rds_ib_mr_pool { ...@@ -71,9 +71,9 @@ struct rds_ib_mr_pool {
atomic_t item_count; /* total # of MRs */ atomic_t item_count; /* total # of MRs */
atomic_t dirty_count; /* # dirty of MRs */ atomic_t dirty_count; /* # dirty of MRs */
struct xlist_head drop_list; /* MRs that have reached their max_maps limit */ struct llist_head drop_list; /* MRs that have reached their max_maps limit */
struct xlist_head free_list; /* unused MRs */ struct llist_head free_list; /* unused MRs */
struct xlist_head clean_list; /* global unused & unamapped MRs */ struct llist_head clean_list; /* global unused & unamapped MRs */
wait_queue_head_t flush_wait; wait_queue_head_t flush_wait;
atomic_t free_pinned; /* memory pinned by free MRs */ atomic_t free_pinned; /* memory pinned by free MRs */
...@@ -220,9 +220,9 @@ struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *rds_ibdev) ...@@ -220,9 +220,9 @@ struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *rds_ibdev)
if (!pool) if (!pool)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
INIT_XLIST_HEAD(&pool->free_list); init_llist_head(&pool->free_list);
INIT_XLIST_HEAD(&pool->drop_list); init_llist_head(&pool->drop_list);
INIT_XLIST_HEAD(&pool->clean_list); init_llist_head(&pool->clean_list);
mutex_init(&pool->flush_lock); mutex_init(&pool->flush_lock);
init_waitqueue_head(&pool->flush_wait); init_waitqueue_head(&pool->flush_wait);
INIT_DELAYED_WORK(&pool->flush_worker, rds_ib_mr_pool_flush_worker); INIT_DELAYED_WORK(&pool->flush_worker, rds_ib_mr_pool_flush_worker);
...@@ -260,26 +260,18 @@ void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *pool) ...@@ -260,26 +260,18 @@ void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *pool)
kfree(pool); kfree(pool);
} }
static void refill_local(struct rds_ib_mr_pool *pool, struct xlist_head *xl,
struct rds_ib_mr **ibmr_ret)
{
struct xlist_head *ibmr_xl;
ibmr_xl = xlist_del_head_fast(xl);
*ibmr_ret = list_entry(ibmr_xl, struct rds_ib_mr, xlist);
}
static inline struct rds_ib_mr *rds_ib_reuse_fmr(struct rds_ib_mr_pool *pool) static inline struct rds_ib_mr *rds_ib_reuse_fmr(struct rds_ib_mr_pool *pool)
{ {
struct rds_ib_mr *ibmr = NULL; struct rds_ib_mr *ibmr = NULL;
struct xlist_head *ret; struct llist_node *ret;
unsigned long *flag; unsigned long *flag;
preempt_disable(); preempt_disable();
flag = &__get_cpu_var(clean_list_grace); flag = &__get_cpu_var(clean_list_grace);
set_bit(CLEAN_LIST_BUSY_BIT, flag); set_bit(CLEAN_LIST_BUSY_BIT, flag);
ret = xlist_del_head(&pool->clean_list); ret = llist_del_first(&pool->clean_list);
if (ret) if (ret)
ibmr = list_entry(ret, struct rds_ib_mr, xlist); ibmr = llist_entry(ret, struct rds_ib_mr, llnode);
clear_bit(CLEAN_LIST_BUSY_BIT, flag); clear_bit(CLEAN_LIST_BUSY_BIT, flag);
preempt_enable(); preempt_enable();
...@@ -529,46 +521,44 @@ static inline unsigned int rds_ib_flush_goal(struct rds_ib_mr_pool *pool, int fr ...@@ -529,46 +521,44 @@ static inline unsigned int rds_ib_flush_goal(struct rds_ib_mr_pool *pool, int fr
} }
/* /*
* given an xlist of mrs, put them all into the list_head for more processing * given an llist of mrs, put them all into the list_head for more processing
*/ */
static void xlist_append_to_list(struct xlist_head *xlist, struct list_head *list) static void llist_append_to_list(struct llist_head *llist, struct list_head *list)
{ {
struct rds_ib_mr *ibmr; struct rds_ib_mr *ibmr;
struct xlist_head splice; struct llist_node *node;
struct xlist_head *cur; struct llist_node *next;
struct xlist_head *next;
node = llist_del_all(llist);
splice.next = NULL; while (node) {
xlist_splice(xlist, &splice); next = node->next;
cur = splice.next; ibmr = llist_entry(node, struct rds_ib_mr, llnode);
while (cur) {
next = cur->next;
ibmr = list_entry(cur, struct rds_ib_mr, xlist);
list_add_tail(&ibmr->unmap_list, list); list_add_tail(&ibmr->unmap_list, list);
cur = next; node = next;
} }
} }
/* /*
* this takes a list head of mrs and turns it into an xlist of clusters. * this takes a list head of mrs and turns it into linked llist nodes
* each cluster has an xlist of MR_CLUSTER_SIZE mrs that are ready for * of clusters. Each cluster has linked llist nodes of
* reuse. * MR_CLUSTER_SIZE mrs that are ready for reuse.
*/ */
static void list_append_to_xlist(struct rds_ib_mr_pool *pool, static void list_to_llist_nodes(struct rds_ib_mr_pool *pool,
struct list_head *list, struct xlist_head *xlist, struct list_head *list,
struct xlist_head **tail_ret) struct llist_node **nodes_head,
struct llist_node **nodes_tail)
{ {
struct rds_ib_mr *ibmr; struct rds_ib_mr *ibmr;
struct xlist_head *cur_mr = xlist; struct llist_node *cur = NULL;
struct xlist_head *tail_mr = NULL; struct llist_node **next = nodes_head;
list_for_each_entry(ibmr, list, unmap_list) { list_for_each_entry(ibmr, list, unmap_list) {
tail_mr = &ibmr->xlist; cur = &ibmr->llnode;
tail_mr->next = NULL; *next = cur;
cur_mr->next = tail_mr; next = &cur->next;
cur_mr = tail_mr;
} }
*tail_ret = tail_mr; *next = NULL;
*nodes_tail = cur;
} }
/* /*
...@@ -581,8 +571,8 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, ...@@ -581,8 +571,8 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool,
int free_all, struct rds_ib_mr **ibmr_ret) int free_all, struct rds_ib_mr **ibmr_ret)
{ {
struct rds_ib_mr *ibmr, *next; struct rds_ib_mr *ibmr, *next;
struct xlist_head clean_xlist; struct llist_node *clean_nodes;
struct xlist_head *clean_tail; struct llist_node *clean_tail;
LIST_HEAD(unmap_list); LIST_HEAD(unmap_list);
LIST_HEAD(fmr_list); LIST_HEAD(fmr_list);
unsigned long unpinned = 0; unsigned long unpinned = 0;
...@@ -603,7 +593,7 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, ...@@ -603,7 +593,7 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool,
prepare_to_wait(&pool->flush_wait, &wait, prepare_to_wait(&pool->flush_wait, &wait,
TASK_UNINTERRUPTIBLE); TASK_UNINTERRUPTIBLE);
if (xlist_empty(&pool->clean_list)) if (llist_empty(&pool->clean_list))
schedule(); schedule();
ibmr = rds_ib_reuse_fmr(pool); ibmr = rds_ib_reuse_fmr(pool);
...@@ -628,10 +618,10 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, ...@@ -628,10 +618,10 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool,
/* Get the list of all MRs to be dropped. Ordering matters - /* Get the list of all MRs to be dropped. Ordering matters -
* we want to put drop_list ahead of free_list. * we want to put drop_list ahead of free_list.
*/ */
xlist_append_to_list(&pool->drop_list, &unmap_list); llist_append_to_list(&pool->drop_list, &unmap_list);
xlist_append_to_list(&pool->free_list, &unmap_list); llist_append_to_list(&pool->free_list, &unmap_list);
if (free_all) if (free_all)
xlist_append_to_list(&pool->clean_list, &unmap_list); llist_append_to_list(&pool->clean_list, &unmap_list);
free_goal = rds_ib_flush_goal(pool, free_all); free_goal = rds_ib_flush_goal(pool, free_all);
...@@ -663,22 +653,22 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, ...@@ -663,22 +653,22 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool,
if (!list_empty(&unmap_list)) { if (!list_empty(&unmap_list)) {
/* we have to make sure that none of the things we're about /* we have to make sure that none of the things we're about
* to put on the clean list would race with other cpus trying * to put on the clean list would race with other cpus trying
* to pull items off. The xlist would explode if we managed to * to pull items off. The llist would explode if we managed to
* remove something from the clean list and then add it back again * remove something from the clean list and then add it back again
* while another CPU was spinning on that same item in xlist_del_head. * while another CPU was spinning on that same item in llist_del_first.
* *
* This is pretty unlikely, but just in case wait for an xlist grace period * This is pretty unlikely, but just in case wait for an llist grace period
* here before adding anything back into the clean list. * here before adding anything back into the clean list.
*/ */
wait_clean_list_grace(); wait_clean_list_grace();
list_append_to_xlist(pool, &unmap_list, &clean_xlist, &clean_tail); list_to_llist_nodes(pool, &unmap_list, &clean_nodes, &clean_tail);
if (ibmr_ret) if (ibmr_ret)
refill_local(pool, &clean_xlist, ibmr_ret); *ibmr_ret = llist_entry(clean_nodes, struct rds_ib_mr, llnode);
/* refill_local may have emptied our list */ /* more than one entry in llist nodes */
if (!xlist_empty(&clean_xlist)) if (clean_nodes->next)
xlist_add(clean_xlist.next, clean_tail, &pool->clean_list); llist_add_batch(clean_nodes->next, clean_tail, &pool->clean_list);
} }
...@@ -711,9 +701,9 @@ void rds_ib_free_mr(void *trans_private, int invalidate) ...@@ -711,9 +701,9 @@ void rds_ib_free_mr(void *trans_private, int invalidate)
/* Return it to the pool's free list */ /* Return it to the pool's free list */
if (ibmr->remap_count >= pool->fmr_attr.max_maps) if (ibmr->remap_count >= pool->fmr_attr.max_maps)
xlist_add(&ibmr->xlist, &ibmr->xlist, &pool->drop_list); llist_add(&ibmr->llnode, &pool->drop_list);
else else
xlist_add(&ibmr->xlist, &ibmr->xlist, &pool->free_list); llist_add(&ibmr->llnode, &pool->free_list);
atomic_add(ibmr->sg_len, &pool->free_pinned); atomic_add(ibmr->sg_len, &pool->free_pinned);
atomic_inc(&pool->dirty_count); atomic_inc(&pool->dirty_count);
......
#ifndef _LINUX_XLIST_H
#define _LINUX_XLIST_H
#include <linux/stddef.h>
#include <linux/poison.h>
#include <linux/prefetch.h>
#include <asm/system.h>
struct xlist_head {
struct xlist_head *next;
};
static inline void INIT_XLIST_HEAD(struct xlist_head *list)
{
list->next = NULL;
}
static inline int xlist_empty(struct xlist_head *head)
{
return head->next == NULL;
}
static inline void xlist_add(struct xlist_head *new, struct xlist_head *tail,
struct xlist_head *head)
{
struct xlist_head *cur;
struct xlist_head *check;
while (1) {
cur = head->next;
tail->next = cur;
check = cmpxchg(&head->next, cur, new);
if (check == cur)
break;
}
}
static inline struct xlist_head *xlist_del_head(struct xlist_head *head)
{
struct xlist_head *cur;
struct xlist_head *check;
struct xlist_head *next;
while (1) {
cur = head->next;
if (!cur)
goto out;
next = cur->next;
check = cmpxchg(&head->next, cur, next);
if (check == cur)
goto out;
}
out:
return cur;
}
static inline struct xlist_head *xlist_del_head_fast(struct xlist_head *head)
{
struct xlist_head *cur;
cur = head->next;
if (!cur)
return NULL;
head->next = cur->next;
return cur;
}
static inline void xlist_splice(struct xlist_head *list,
struct xlist_head *head)
{
struct xlist_head *cur;
WARN_ON(head->next);
cur = xchg(&list->next, NULL);
head->next = cur;
}
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment