Commit 33244125 authored by Chris Mason's avatar Chris Mason Committed by Andy Grover

RDS/IB: Add caching of frags and incs

This patch is based heavily on an initial patch by Chris Mason.
Instead of freeing slab memory and pages, it keeps them, and
funnels them back to be reused.

The lock minimization strategy uses xchg and cmpxchg atomic ops
for manipulation of pointers to list heads. We anchor the lists with a
pointer to a list_head struct instead of a static list_head struct.
We just have to carefully use the existing primitives with
the difference between a pointer and a static head struct.

For example, 'list_empty()' means that our anchor pointer points to a list with
a single item instead of meaning that our static head element doesn't point to
any list items.

Original patch by Chris, with significant mods and fixes by Andy and Zach.
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
Signed-off-by: default avatarAndy Grover <andy.grover@oracle.com>
Signed-off-by: default avatarZach Brown <zach.brown@oracle.com>
parent fc24f780
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#define RDS_IB_SUPPORTED_PROTOCOLS 0x00000003 /* minor versions supported */ #define RDS_IB_SUPPORTED_PROTOCOLS 0x00000003 /* minor versions supported */
#define RDS_IB_RECYCLE_BATCH_COUNT 32
extern struct list_head rds_ib_devices; extern struct list_head rds_ib_devices;
/* /*
...@@ -30,14 +32,27 @@ extern struct list_head rds_ib_devices; ...@@ -30,14 +32,27 @@ extern struct list_head rds_ib_devices;
*/ */
struct rds_page_frag { struct rds_page_frag {
struct list_head f_item; struct list_head f_item;
struct list_head f_cache_entry;
struct scatterlist f_sg; struct scatterlist f_sg;
}; };
struct rds_ib_incoming { struct rds_ib_incoming {
struct list_head ii_frags; struct list_head ii_frags;
struct list_head ii_cache_entry;
struct rds_incoming ii_inc; struct rds_incoming ii_inc;
}; };
struct rds_ib_cache_head {
struct list_head *first;
unsigned long count;
};
struct rds_ib_refill_cache {
struct rds_ib_cache_head *percpu;
struct list_head *xfer;
struct list_head *ready;
};
struct rds_ib_connect_private { struct rds_ib_connect_private {
/* Add new fields at the end, and don't permute existing fields. */ /* Add new fields at the end, and don't permute existing fields. */
__be32 dp_saddr; __be32 dp_saddr;
...@@ -104,6 +119,8 @@ struct rds_ib_connection { ...@@ -104,6 +119,8 @@ struct rds_ib_connection {
u64 i_recv_hdrs_dma; u64 i_recv_hdrs_dma;
struct rds_ib_recv_work *i_recvs; struct rds_ib_recv_work *i_recvs;
u64 i_ack_recv; /* last ACK received */ u64 i_ack_recv; /* last ACK received */
struct rds_ib_refill_cache i_cache_incs;
struct rds_ib_refill_cache i_cache_frags;
/* sending acks */ /* sending acks */
unsigned long i_ack_flags; unsigned long i_ack_flags;
...@@ -304,6 +321,8 @@ void rds_ib_flush_mrs(void); ...@@ -304,6 +321,8 @@ void rds_ib_flush_mrs(void);
int __init rds_ib_recv_init(void); int __init rds_ib_recv_init(void);
void rds_ib_recv_exit(void); void rds_ib_recv_exit(void);
int rds_ib_recv(struct rds_connection *conn); int rds_ib_recv(struct rds_connection *conn);
int rds_ib_recv_alloc_caches(struct rds_ib_connection *ic);
void rds_ib_recv_free_caches(struct rds_ib_connection *ic);
int rds_ib_recv_refill(struct rds_connection *conn, int prefill); int rds_ib_recv_refill(struct rds_connection *conn, int prefill);
void rds_ib_inc_free(struct rds_incoming *inc); void rds_ib_inc_free(struct rds_incoming *inc);
int rds_ib_inc_copy_to_user(struct rds_incoming *inc, struct iovec *iov, int rds_ib_inc_copy_to_user(struct rds_incoming *inc, struct iovec *iov,
......
...@@ -709,12 +709,19 @@ int rds_ib_conn_alloc(struct rds_connection *conn, gfp_t gfp) ...@@ -709,12 +709,19 @@ int rds_ib_conn_alloc(struct rds_connection *conn, gfp_t gfp)
{ {
struct rds_ib_connection *ic; struct rds_ib_connection *ic;
unsigned long flags; unsigned long flags;
int ret;
/* XXX too lazy? */ /* XXX too lazy? */
ic = kzalloc(sizeof(struct rds_ib_connection), GFP_KERNEL); ic = kzalloc(sizeof(struct rds_ib_connection), GFP_KERNEL);
if (!ic) if (!ic)
return -ENOMEM; return -ENOMEM;
ret = rds_ib_recv_alloc_caches(ic);
if (ret) {
kfree(ic);
return ret;
}
INIT_LIST_HEAD(&ic->ib_node); INIT_LIST_HEAD(&ic->ib_node);
tasklet_init(&ic->i_recv_tasklet, rds_ib_recv_tasklet_fn, tasklet_init(&ic->i_recv_tasklet, rds_ib_recv_tasklet_fn,
(unsigned long) ic); (unsigned long) ic);
...@@ -763,6 +770,8 @@ void rds_ib_conn_free(void *arg) ...@@ -763,6 +770,8 @@ void rds_ib_conn_free(void *arg)
list_del(&ic->ib_node); list_del(&ic->ib_node);
spin_unlock_irq(lock_ptr); spin_unlock_irq(lock_ptr);
rds_ib_recv_free_caches(ic);
kfree(ic); kfree(ic);
} }
......
This diff is collapsed.
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