From ef363cc49361c4afe21d5f4c16d77cb4ad4352f9 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 18 Aug 2008 03:12:10 -0500 Subject: [PATCH 23/23] libfc: RFC add frame pools 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 --- 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 #include +#include #include /* @@ -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 #include +#include #include #include @@ -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