]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
sdp: add ability to set a maximum memory usage for the entire module
authorEldad Zinger <eldadz@mellanox.co.il>
Wed, 20 Oct 2010 15:08:53 +0000 (17:08 +0200)
committerMukesh Kacker <mukesh.kacker@oracle.com>
Tue, 6 Oct 2015 12:05:30 +0000 (05:05 -0700)
use top_mem_usage module parameter for this.

Signed-off-by: Eldad Zinger <eldadz@mellanox.co.il>
drivers/infiniband/ulp/sdp/sdp.h
drivers/infiniband/ulp/sdp/sdp_main.c
drivers/infiniband/ulp/sdp/sdp_rx.c
drivers/infiniband/ulp/sdp/sdp_tx.c
drivers/infiniband/ulp/sdp/sdp_zcopy.c

index 14b21b0338f32a55cd2fe67dc4ab45acd8e02716..aecefb705affe511d3a34b0a10bba1380079577b 100644 (file)
@@ -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)
 {
index 423c20ff014502027632e06f753cec18f36bda13..fb47133cfdde9cfb696c6b950058ea6c43a152f5 100644 (file)
@@ -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;
 
index 48f4ab6eee241544d6f185bb1b12a01f3ac40dda..1c856c5adbe53923755cbf42f0f327d3e8acaac8 100644 (file)
@@ -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);
                }
        }
 }
index 61156d556d8024142b909d5df9692ea250714f7e..02210ac164a6fea17a3f5283c9df9985412aae49 100644 (file)
@@ -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);
        }
 }
 
index ca338446d74ad9b216df05b4f10a757dc6aa74b0..477e8a3d8f078b7e7bf8ae1a3ce3f0114678cfa1 100644 (file)
@@ -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;