From: Eldad Zinger Date: Wed, 20 Oct 2010 15:08:53 +0000 (+0200) Subject: sdp: add ability to set a maximum memory usage for the entire module X-Git-Tag: v4.1.12-92~264^2~5^2~76 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=2cbe8a478a18d64388bcb10bba0d4cd1e7a04411;p=users%2Fjedix%2Flinux-maple.git sdp: add ability to set a maximum memory usage for the entire module use top_mem_usage module parameter for this. Signed-off-by: Eldad Zinger --- diff --git a/drivers/infiniband/ulp/sdp/sdp.h b/drivers/infiniband/ulp/sdp/sdp.h index 14b21b0338f32..aecefb705affe 100644 --- a/drivers/infiniband/ulp/sdp/sdp.h +++ b/drivers/infiniband/ulp/sdp/sdp.h @@ -129,6 +129,7 @@ extern int rcvbuf_initial_size; extern struct proto sdp_proto; extern struct workqueue_struct *rx_comp_wq; extern atomic_t sdp_current_mem_usage; +extern int top_mem_usage; extern spinlock_t sdp_large_sockets_lock; extern struct ib_client sdp_client; #ifdef SDPSTATS_ON @@ -692,6 +693,14 @@ static inline unsigned sdp_cycles_to_usecs(unsigned long c) #endif } +static inline int sdp_has_free_mem(void) +{ + /* TODO: count also kmalloc's and skb's allocations. */ + + return !top_mem_usage || atomic_read(&sdp_current_mem_usage) < + top_mem_usage << (20 - PAGE_SHIFT); +} + /* utilities */ static inline char *mid2str(int mid) { @@ -719,6 +728,14 @@ static inline char *mid2str(int mid) return mid2str[mid]; } +static inline void sdp_free_skb(struct sk_buff *skb) +{ + if (unlikely(skb_shinfo(skb)->nr_frags)) + atomic_sub(skb_shinfo(skb)->nr_frags, &sdp_current_mem_usage); + + __kfree_skb(skb); +} + static inline struct sk_buff *sdp_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp) { diff --git a/drivers/infiniband/ulp/sdp/sdp_main.c b/drivers/infiniband/ulp/sdp/sdp_main.c index 423c20ff01450..fb47133cfdde9 100644 --- a/drivers/infiniband/ulp/sdp/sdp_main.c +++ b/drivers/infiniband/ulp/sdp/sdp_main.c @@ -484,6 +484,7 @@ static void sdp_destroy_resources(struct sock *sk) if (sk->sk_sndmsg_page) { __free_page(sk->sk_sndmsg_page); sk->sk_sndmsg_page = NULL; + atomic_dec(&sdp_current_mem_usage); } id = ssk->id; @@ -704,7 +705,7 @@ static void sdp_close(struct sock *sk, long timeout) sdp_dbg(sk, "Data was unread. skb: %p\n", skb); data_was_unread = 1; } - __kfree_skb(skb); + sdp_free_skb(skb); } sk_mem_reclaim(sk); @@ -1706,7 +1707,12 @@ static inline int sdp_bcopy_get(struct sock *sk, struct sk_buff *skb, if (!page) { /* Allocate new cache page. */ - if (!(page = sk_stream_alloc_page(sk))) + if (sdp_has_free_mem()) { + page = sk_stream_alloc_page(sk); + if (!page) + return SDP_DO_WAIT_MEM; + atomic_inc(&sdp_current_mem_usage); + } else return SDP_DO_WAIT_MEM; } @@ -2430,7 +2436,7 @@ sdp_mid_data: goto skb_cleanup; sdp_warn(sk, "err from rdma %d - sendSM\n", err); skb_unlink(skb, &sk->sk_receive_queue); - __kfree_skb(skb); + sdp_free_skb(skb); } } else { sdp_dbg_data(sk, "memcpy 0x%lx bytes +0x%x -> %p\n", @@ -2501,14 +2507,14 @@ skb_cleanup: force_skb_cleanup: sdp_dbg_data(sk, "unlinking skb %p\n", skb); skb_unlink(skb, &sk->sk_receive_queue); - __kfree_skb(skb); + sdp_free_skb(skb); } continue; found_fin_ok: ++*seq; if (!(flags & MSG_PEEK)) { skb_unlink(skb, &sk->sk_receive_queue); - __kfree_skb(skb); + sdp_free_skb(skb); } break; diff --git a/drivers/infiniband/ulp/sdp/sdp_rx.c b/drivers/infiniband/ulp/sdp/sdp_rx.c index 48f4ab6eee241..1c856c5adbe53 100644 --- a/drivers/infiniband/ulp/sdp/sdp_rx.c +++ b/drivers/infiniband/ulp/sdp/sdp_rx.c @@ -39,7 +39,7 @@ SDP_MODPARAM_INT(rcvbuf_initial_size, 32 * 1024, "Receive buffer initial size in bytes."); SDP_MODPARAM_SINT(rcvbuf_scale, 0x10, "Receive buffer size scale factor."); -SDP_MODPARAM_SINT(top_mem_usage, 0, +SDP_MODPARAM_INT(top_mem_usage, 0, "Top system wide sdp memory usage for recv (in MB)."); #ifdef CONFIG_PPC @@ -186,6 +186,8 @@ static int sdp_post_recv(struct sdp_sock *ssk) if (rx_req->mapping[i + 1]) page = rx_req->pages[i]; else { + if (unlikely(!sdp_has_free_mem())) + goto err; rx_req->pages[i] = page = alloc_pages(gfp_page, 0); if (unlikely(!page)) goto err; @@ -244,8 +246,9 @@ static int sdp_post_recv(struct sdp_sock *ssk) return 0; err: + atomic_add(pages_alloced, &sdp_current_mem_usage); sdp_cleanup_sdp_buf(ssk, rx_req, SDP_SKB_HEAD_SIZE, DMA_FROM_DEVICE); - __kfree_skb(skb); + sdp_free_skb(skb); sdp_reset(&ssk->isk.sk); return -1; } @@ -254,11 +257,11 @@ static inline int sdp_post_recvs_needed(struct sdp_sock *ssk) { struct sock *sk = &ssk->isk.sk; int buffer_size = SDP_SKB_HEAD_SIZE + ssk->recv_frags * PAGE_SIZE; - unsigned long max_bytes; + unsigned long max_bytes = ssk->rcvbuf_scale; unsigned long bytes_in_process; int posted = rx_ring_posted(ssk); - if (unlikely(!ssk->qp_active)) + if (unlikely(!ssk->qp_active || !sdp_has_free_mem())) return 0; if (likely(posted >= SDP_RX_SIZE)) @@ -269,12 +272,7 @@ static inline int sdp_post_recvs_needed(struct sdp_sock *ssk) /* If rcvbuf is very small, must leave at least 1 skb for data, * in addition to SDP_MIN_TX_CREDITS */ - max_bytes = max(sk->sk_rcvbuf, (1 + SDP_MIN_TX_CREDITS) * buffer_size); - - if (!top_mem_usage || (top_mem_usage * 0x100000) >= - atomic_read(&sdp_current_mem_usage) * PAGE_SIZE) { - max_bytes *= ssk->rcvbuf_scale; - } + max_bytes *= max(sk->sk_rcvbuf, (1 + SDP_MIN_TX_CREDITS) * buffer_size); /* Bytes posted to HW */ bytes_in_process = (posted - SDP_MIN_TX_CREDITS) * buffer_size; @@ -536,7 +534,7 @@ static int sdp_process_rx_ctl_skb(struct sdp_sock *ssk, struct sk_buff *skb) sdp_warn(sk, "SDP: FIXME MID %d\n", h->mid); } - __kfree_skb(skb); + sdp_free_skb(skb); return 0; } @@ -583,7 +581,7 @@ static int sdp_process_rx_skb(struct sdp_sock *ssk, struct sk_buff *skb) if (unlikely(h->mid == SDP_MID_DATA && skb->len == 0)) { /* Credit update is valid even after RCV_SHUTDOWN */ - __kfree_skb(skb); + sdp_free_skb(skb); return 0; } @@ -606,7 +604,7 @@ static int sdp_process_rx_skb(struct sdp_sock *ssk, struct sk_buff *skb) sdp_dbg_data(sk, "RdmaRdCompl message arrived\n"); sdp_handle_rdma_read_compl(ssk, ntohl(h->mseq_ack), ntohl(rrch->len)); - __kfree_skb(skb); + sdp_free_skb(skb); } else skb_queue_tail(&ssk->rx_ctl_q, skb); @@ -631,9 +629,6 @@ static struct sk_buff *sdp_process_rx_wc(struct sdp_sock *ssk, if (unlikely(!skb)) return NULL; - if (unlikely(skb_shinfo(skb)->nr_frags)) - atomic_sub(skb_shinfo(skb)->nr_frags, &sdp_current_mem_usage); - if (unlikely(wc->status)) { if (ssk->qp_active) { sdp_dbg(sk, "Recv completion with error. " @@ -642,7 +637,7 @@ static struct sk_buff *sdp_process_rx_wc(struct sdp_sock *ssk, sdp_reset(sk); ssk->qp_active = 0; } - __kfree_skb(skb); + sdp_free_skb(skb); return NULL; } @@ -651,7 +646,7 @@ static struct sk_buff *sdp_process_rx_wc(struct sdp_sock *ssk, if (unlikely(wc->byte_len < sizeof(struct sdp_bsdh))) { sdp_warn(sk, "SDP BUG! byte_len %d < %zd\n", wc->byte_len, sizeof(struct sdp_bsdh)); - __kfree_skb(skb); + sdp_free_skb(skb); return NULL; } skb->len = wc->byte_len; @@ -853,8 +848,7 @@ static void sdp_rx_ring_purge(struct sdp_sock *ssk) skb = sdp_recv_completion(ssk, ring_tail(ssk->rx_ring), INT_MAX); if (!skb) break; - atomic_sub(skb_shinfo(skb)->nr_frags, &sdp_current_mem_usage); - __kfree_skb(skb); + sdp_free_skb(skb); } for (id = 0; id < SDP_RX_SIZE; id++) { @@ -869,7 +863,7 @@ static void sdp_rx_ring_purge(struct sdp_sock *ssk) DMA_FROM_DEVICE); sbuf->mapping[i] = 0; put_page(sbuf->pages[i - 1]); - atomic_sub(1, &sdp_current_mem_usage); + atomic_dec(&sdp_current_mem_usage); } } } diff --git a/drivers/infiniband/ulp/sdp/sdp_tx.c b/drivers/infiniband/ulp/sdp/sdp_tx.c index 61156d556d802..02210ac164a6f 100644 --- a/drivers/infiniband/ulp/sdp/sdp_tx.c +++ b/drivers/infiniband/ulp/sdp/sdp_tx.c @@ -92,7 +92,7 @@ void sdp_post_send(struct sdp_sock *ssk, struct sk_buff *skb) sdp_dbg_data(&ssk->isk.sk, "SrcAvail cancelled " "before being sent!\n"); SDP_WARN_ON(1); - __kfree_skb(skb); + sdp_free_skb(skb); return; } TX_SRCAVAIL_STATE(skb)->mseq = mseq; @@ -169,7 +169,7 @@ void sdp_post_send(struct sdp_sock *ssk, struct sk_buff *skb) return; err: - __kfree_skb(skb); + sdp_free_skb(skb); } static struct sk_buff *sdp_send_completion(struct sdp_sock *ssk, int mseq) @@ -395,7 +395,7 @@ static void sdp_tx_ring_purge(struct sdp_sock *ssk) skb = sdp_send_completion(ssk, ring_tail(ssk->tx_ring)); if (!skb) break; - __kfree_skb(skb); + sdp_free_skb(skb); } } diff --git a/drivers/infiniband/ulp/sdp/sdp_zcopy.c b/drivers/infiniband/ulp/sdp/sdp_zcopy.c index ca338446d74ad..477e8a3d8f078 100644 --- a/drivers/infiniband/ulp/sdp/sdp_zcopy.c +++ b/drivers/infiniband/ulp/sdp/sdp_zcopy.c @@ -101,6 +101,13 @@ static int sdp_post_srcavail(struct sock *sk, struct tx_srcavail_state *tx_sa) skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, payload_pg, off, payload_len); + /* Need to increase mem_usage counter even thought this page was not + * allocated. + * The reason is that when freeing this skb, we are decreasing the same + * counter according to nr_frags. we don't want to check h->mid since + * h->mid is not always a valid value. + */ + atomic_add(skb_shinfo(skb)->nr_frags, &sdp_current_mem_usage); skb->len += payload_len; skb->data_len = payload_len;