From: Mike Christie <[EMAIL PROTECTED]>

Do not merge this patch. It does not work. It is for example only.

I started thinking about how to preallocate skb/frames. I started with
this patch. A problem is that, mempools are nice when all the
structs are the same size. In this patch I used FC_MAX_PAYLOAD.
I do not think it will be that bad if we only have to reserve
a couple frames for that size for each lport. The problem is that I
am not sure how or if it is safe to modify the skb settings. If
we originally allocated a skb for FC_MAX_PAYLOAD, can I just
do a skb_put for the correct size in __fc_frame_alloc?

I was also not sure about some of the network layer behaviors.
With this current patch would I need to preallocate at least
enough frames to answer one ready to transfer? What is the max
and normal sizes we see for that? Can I partially answer it?
If the target had expected 64K can I only send 8K, because
we only have 8K reserved?

Signed-off-by: Mike Christie <[EMAIL PROTECTED]>
---
 drivers/scsi/libfc/fc_frame.c |   39 ++++++++++++++++++++++++++++++++++++---
 drivers/scsi/libfc/fc_lport.c |   13 +++++++++++++
 include/scsi/libfc/fc_frame.h |   11 ++++++++---
 include/scsi/libfc/libfc.h    |    1 +
 4 files changed, 58 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/libfc/fc_frame.c b/drivers/scsi/libfc/fc_frame.c
index 7ba241e..589c62e 100644
--- a/drivers/scsi/libfc/fc_frame.c
+++ b/drivers/scsi/libfc/fc_frame.c
@@ -25,6 +25,7 @@
 #include <linux/skbuff.h>
 #include <linux/crc32.h>
 
+#include <scsi/libfc/libfc.h>
 #include <scsi/libfc/fc_frame.h>
 
 /*
@@ -51,7 +52,7 @@ EXPORT_SYMBOL(fc_frame_crc_check);
  * Allocate a frame intended to be sent via fcoe_xmit.
  * Get an sk_buff for the frame and set the length.
  */
-struct fc_frame *__fc_frame_alloc(size_t len)
+static struct fc_frame *frame_alloc(size_t len)
 {
        struct fc_frame *fp;
        struct sk_buff *skb;
@@ -67,8 +68,24 @@ struct fc_frame *__fc_frame_alloc(size_t len)
        skb_put(skb, len);
        return fp;
 }
-EXPORT_SYMBOL(__fc_frame_alloc);
 
+/*
+ * Free the fc_frame structure and buffer.
+ */
+static void frame_free(struct fc_frame *fp)
+{
+       kfree_skb(fp_skb(fp));
+}
+
+/*
+ * Allocate a frame intended to be sent via fcoe_xmit.
+ * Get an sk_buff for the frame and set the length.
+ */
+struct fc_frame *__fc_frame_alloc(struct fc_lport *lp, size_t len)
+{
+       return mempool_alloc(lp->fr_pool, GFP_ATOMIC);
+}
+EXPORT_SYMBOL(__fc_frame_alloc);
 
 struct fc_frame *fc_frame_alloc_fill(struct fc_lport *lp, size_t payload_len)
 {
@@ -78,7 +95,7 @@ struct fc_frame *fc_frame_alloc_fill(struct fc_lport *lp, 
size_t payload_len)
        fill = payload_len % 4;
        if (fill != 0)
                fill = 4 - fill;
-       fp = __fc_frame_alloc(payload_len + fill);
+       fp = __fc_frame_alloc(lp, payload_len + fill);
        if (fp) {
                memset((char *) fr_hdr(fp) + payload_len, 0, fill);
                /* trim is OK, we just allocated it so there are no fragments */
@@ -86,3 +103,19 @@ struct fc_frame *fc_frame_alloc_fill(struct fc_lport *lp, 
size_t payload_len)
        }
        return fp;
 }
+
+void *fc_frame_pool_alloc(gfp_t gfp_mask, void *pool_data)
+{
+       /*
+        * this should be the max space we need for the frame.
+        *
+        * if the len is larger than what we want to send what problems
+        * is this going to make?
+        */
+       return frame_alloc(FC_MAX_PAYLOAD);
+}
+
+void fc_frame_pool_free(void *element, void *pool_data)
+{
+       frame_free(element);
+}
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index c0a3554..d1fed8f 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -908,6 +908,19 @@ EXPORT_SYMBOL(fc_lport_config);
 
 int fc_lport_init(struct fc_lport *lp)
 {
+       /*
+        * If the skb is released right after it is sent
+        * then we only need one and could reuse it.
+        *
+        * If the skb is not released until some time afterward
+        * then we may need to allocate enough skbs for an entire
+        * sequence. What is the normal size of this?
+        */
+       lp->fr_pool = mempool_create(2, fc_frame_pool_alloc,
+                                    fc_frame_pool_free, lp);
+       if (!lp->fr_pool)
+               return -ENOMEM;
+
        if (!lp->tt.lport_recv)
                lp->tt.lport_recv = fc_lport_recv;
 
diff --git a/include/scsi/libfc/fc_frame.h b/include/scsi/libfc/fc_frame.h
index c7a52bb..43f2cf9 100644
--- a/include/scsi/libfc/fc_frame.h
+++ b/include/scsi/libfc/fc_frame.h
@@ -22,6 +22,7 @@
 
 #include <linux/scatterlist.h>
 #include <linux/skbuff.h>
+#include <linux/mempool.h>
 
 #include <scsi/fc/fc_fs.h>
 #include <scsi/fc/fc_encaps.h>
@@ -93,7 +94,7 @@ static inline void fc_frame_init(struct fc_frame *fp)
 
 struct fc_frame *fc_frame_alloc_fill(struct fc_lport *, size_t payload_len);
 
-struct fc_frame *__fc_frame_alloc(size_t payload_len);
+struct fc_frame *__fc_frame_alloc(struct fc_lport *, size_t payload_len);
 
 /*
  * Get frame for sending via port.
@@ -101,7 +102,7 @@ struct fc_frame *__fc_frame_alloc(size_t payload_len);
 static inline struct fc_frame *_fc_frame_alloc(struct fc_lport *dev,
                                               size_t payload_len)
 {
-       return __fc_frame_alloc(payload_len);
+       return __fc_frame_alloc(dev, payload_len);
 }
 
 /*
@@ -128,7 +129,7 @@ static inline struct fc_frame *fc_frame_alloc(struct 
fc_lport *dev, size_t len)
  */
 static inline void fc_frame_free(struct fc_frame *fp)
 {
-       kfree_skb(fp_skb(fp));
+       mempool_free(fp, NULL);
 }
 
 static inline int fc_frame_is_linear(struct fc_frame *fp)
@@ -233,4 +234,8 @@ u32 fc_frame_crc_check(struct fc_frame *);
  */
 void fc_frame_leak_check(void);
 
+/* mempool allocator/destructors */
+void *fc_frame_pool_alloc(gfp_t gfp_mask, void *pool_data);
+void fc_frame_pool_free(void *element, void *pool_data);
+
 #endif /* _FC_FRAME_H_ */
diff --git a/include/scsi/libfc/libfc.h b/include/scsi/libfc/libfc.h
index de68c44..06abcca 100644
--- a/include/scsi/libfc/libfc.h
+++ b/include/scsi/libfc/libfc.h
@@ -428,6 +428,7 @@ struct fc_lport {
        struct fc_gpn_ft_resp   ns_disc_buf;    /* partial name buffer */
        struct timer_list       state_timer;    /* timer for state events */
        struct delayed_work     ns_disc_work;
+       mempool_t               *fr_pool;       /* pool of frames */
 
        void                    *drv_priv;
 };
-- 
1.5.4.1

_______________________________________________
devel mailing list
[email protected]
http://www.open-fcoe.org/mailman/listinfo/devel

Reply via email to