grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 2/2] ofnet: implement a receive buffer


From: Stanislav Kholmanskikh
Subject: Re: [PATCH 2/2] ofnet: implement a receive buffer
Date: Wed, 30 Nov 2016 18:27:44 +0300
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.2.0


On 11/23/2016 06:09 PM, Stanislav Kholmanskikh wrote:
> 
> 
> On 11/23/2016 02:16 PM, Daniel Kiper wrote:
>> On Tue, Nov 22, 2016 at 05:08:25PM +0300, Stanislav Kholmanskikh wrote:
>>> On 11/22/2016 12:48 AM, Daniel Kiper wrote:
>>>> On Fri, Nov 18, 2016 at 04:29:24PM +0300, Stanislav Kholmanskikh wrote:
>>>>> On 11/16/2016 01:34 AM, Daniel Kiper wrote:
>>>>>> On Tue, Apr 12, 2016 at 03:39:56PM +0300, Stanislav Kholmanskikh wrote:
>>>>>>> get_card_packet() from ofnet.c allocates a netbuff based on the 
>>>>>>> device's MTU:
>>>>>>>
>>>>>>>   nb = grub_netbuff_alloc (dev->mtu + 64 + 2);
>>>>>>>
>>>>>>> In the case when the MTU is large, and the received packet is
>>>>>>> relatively small, this leads to allocation of significantly more memory,
>>>>>>> than it's required. An example could be transmission of TFTP packets
>>>>>>> with 0x400 blksize via a network card with 0x10000 MTU.
>>>>>>>
>>>>>>> This patch implements a per-card receive buffer in a way similar to 
>>>>>>> efinet.c,
>>>>>>> and makes get_card_packet() allocate a netbuff of the received data 
>>>>>>> size.
>>>>>>
>>>>>> Have you checked performance impact of this patch? It should not be
>>>>>> meaningful but it is good to know.
>>>>>
>>>>> No. I didn't do performance testing.
>>>>
>>>> Please do.
>>>
>>> Ok. I'll check what I can do here.
>>
>> Great! Thnaks!
>>
>>>>>>> Signed-off-by: Stanislav Kholmanskikh <address@hidden>
>>>>>>> ---
>>>>>>>  grub-core/net/drivers/ieee1275/ofnet.c |  100 
>>>>>>> ++++++++++++++++++-------------
>>>>>>>  1 files changed, 58 insertions(+), 42 deletions(-)
>>>>>>>
>>>>>>> diff --git a/grub-core/net/drivers/ieee1275/ofnet.c 
>>>>>>> b/grub-core/net/drivers/ieee1275/ofnet.c
>>>>>>> index 6bd3b92..09ec77e 100644
>>>>>>> --- a/grub-core/net/drivers/ieee1275/ofnet.c
>>>>>>> +++ b/grub-core/net/drivers/ieee1275/ofnet.c
>>>>>>> @@ -85,24 +85,35 @@ get_card_packet (struct grub_net_card *dev)
>>>>>>>    grub_uint64_t start_time;
>>>>>>>    struct grub_net_buff *nb;
>>>>>>>
>>>>>>> -  nb = grub_netbuff_alloc (dev->mtu + 64 + 2);
>>>>>>> +  start_time = grub_get_time_ms ();
>>>>>>> +  do
>>>>>>> +    rc = grub_ieee1275_read (data->handle, dev->rcvbuf, 
>>>>>>> dev->rcvbufsize, &actual);
>>>>>>> +  while ((actual <= 0 || rc < 0) && (grub_get_time_ms () - start_time 
>>>>>>> < 200));
>>>>>>
>>>>>> Why 200? Please avoid using plain numbers if possible. Use constants. If 
>>>>>> it does
>>>>>> not make sense then put comment which explains why this figure not 
>>>>>> another.
>>>>>
>>>>> The whole 'do while' construction is from the existing code, I only
>>>>> modify the destination for the grub_ieee1275_read() call.
>>>>
>>>> OK but if you move such code around anyway do not leave it unreadable. 
>>>> Improve it
>>>> by constants or comments.
>>>
>>> May I use a macro for this
>>>
>>> #define READ_TIMEOUT 200
>>>
>>> ?
>>
>> It seems to me that it appears in one place, so, comment would be better 
>> here.
>> Unfortunately, it looks that there is no explanation for that value in commit
>> message... Ehhh... Could you check mail archive? If there is no such thing 
>> there
>> then let's leave it as it. Though I do not like it.
> 
> Ok. I'll check the mail archive as well.

What I found is that this timeout of 200 ms was introduced by commit:

commit 0f231af8ae44b6e4efe6b25794db21fbfd270718
Author: Manoel Rebelo Abranches <address@hidden>
Date:   Tue May 10 09:50:18 2011 -0300

    Implement timeout when receiving packets.

It seems this commit has roots here:

http://lists.gnu.org/archive/html/grub-devel/2011-05/msg00041.html

where my search stops.


> 
>>
>>>>>> Additionally, are we sure that whole packet can be always stored in 
>>>>>> dev->rcvbuf?
>>>>>
>>>>> Code in search_net_devices() allocates the buffer to be of size:
>>>>>
>>>>> ALIGN_UP (card->mtu, 64) + 256;
>>>>>
>>>>> so, yes, it's capable to handle any valid packet size.
>>>>
>>>> Great but why this numbers?
>>>
>>> I have to admit that I can't answer to your question. :( I copied this
>>> stuff from efi (for the receive buffer). The transmit buffer was already
>>> of this size.
>>
>> Ugh... Same as above...

It seems that commit:

commit 3e7472395127dc231c0f7139600b0465f68d0095
Author: Vladimir 'phcoder' Serbinenko <address@hidden>
Date:   Sat Jun 9 11:00:18 2012 +0200

        Keep TX and RX buffers on EFI rather than always allocate new ones.

        * include/grub/net.h (grub_net_card_driver): Allow driver to modify
        card. All users updated.
        (grub_net_card): New members txbuf, rcvbuf, rcvbufsize and txbusy.
        * grub-core/net/drivers/efi/efinet.c (send_card_buffer): Reuse
buffer.
        (get_card_packet): Likewise.
        (grub_efinet_findcards): Init new fields.


was the first one to use ALIGN_UP (card->mtu, 64) + 256 for the receive
buffer. Before that the buffer size was hard coded to 1536.

I could not find an email message describing this change...


>>
>> [...]
>>
>>>>>>>  static struct grub_net_card_driver ofdriver =
>>>>>>> @@ -294,6 +305,24 @@ grub_ieee1275_net_config_real (const char 
>>>>>>> *devpath, char **device, char **path,
>>>>>>>    }
>>>>>>>  }
>>>>>>>
>>>>>>> +static void *
>>>>>>> +ofnet_alloc_netbuf (grub_size_t len)
>>>>>>> +{
>>>>>>> +  if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_VIRT_TO_REAL_BROKEN))
>>>>>>> +    return grub_ieee1275_alloc_mem (len);
>>>>>>> +  else
>>>>>>> +    return grub_malloc (len);
>>>>
>>>> It looks that it should be grub_zalloc() instead of grub_malloc() here.
>>>
>>> I have two reasons why I don't use grub_zalloc() here:
>>>
>>> 1. The buffer allocated with this function is written/read many times
>>> while grub is working. We write some amount of bytes to the buffer, and
>>> then read this amount of bytes. So I don't see why zeroing the buffer on
>>
>> I suppose that "this" == "same" here...
>>
>>> allocation should matter.
>>>
>>> 2. In IEEE1275-1994 I do not see an explicit notice that memory
>>> allocated with alloc-mem is zeroed. So for consistence of
>>> ofnet_alloc_netbuf() I do not call grub_zalloc() there.
>>
>> Yep, I am aware of that. However, I am asking because you change
>> currently exiting code behavior which uses grub_zalloc(). Maybe
>> we should leave it as is (I am thinking about grub_zalloc()) but
>> it is not very strong must. If you choose grub_malloc() please
>> explain in commit message why you did it and why it is safe here.
> 
> Well, let it be grub_zalloc() then.
> 
>>
>>>>>>> +}
>>>>>>> +
>>>>>>> +static void
>>>>>>> +ofnet_free_netbuf (void *addr, grub_size_t len)
>>>>>>> +{
>>>>>>> +  if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_VIRT_TO_REAL_BROKEN))
>>>>>>> +    grub_ieee1275_free_mem (addr, len);
>>>>>>> +  else
>>>>>>> +    grub_free (addr);
>>>>>>> +}
>>>>>>> +
>>>>>>>  static int
>>>>>>>  search_net_devices (struct grub_ieee1275_devalias *alias)
>>>>>>>  {
>>>>>>> @@ -409,41 +438,21 @@ search_net_devices (struct grub_ieee1275_devalias 
>>>>>>> *alias)
>>>>>>>    card->default_address = lla;
>>>>>>>
>>>>>>>    card->txbufsize = ALIGN_UP (card->mtu, 64) + 256;
>>>>>>> +  card->rcvbufsize = ALIGN_UP (card->mtu, 64) + 256;
>>>>>>>
>>>>>>> -  if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_VIRT_TO_REAL_BROKEN))
>>>>>>> -    {
>>>>>>> -      struct alloc_args
>>>>>>> -      {
>>>>>>> -       struct grub_ieee1275_common_hdr common;
>>>>>>> -       grub_ieee1275_cell_t method;
>>>>>>> -       grub_ieee1275_cell_t len;
>>>>>>> -       grub_ieee1275_cell_t catch;
>>>>>>> -       grub_ieee1275_cell_t result;
>>>>>>> -      }
>>>>>>> -      args;
>>>>>>> -      INIT_IEEE1275_COMMON (&args.common, "interpret", 2, 2);
>>>>>>> -      args.len = card->txbufsize;
>>>>>>> -      args.method = (grub_ieee1275_cell_t) "alloc-mem";
>>>>>>> -
>>>>>>> -      if (IEEE1275_CALL_ENTRY_FN (&args) == -1
>>>>>>> -         || args.catch)
>>>>>>> -       {
>>>>>>> -         card->txbuf = 0;
>>>>>>> -         grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
>>>>>>> -       }
>>>>>>> -      else
>>>>>>> -       card->txbuf = (void *) args.result;
>>>>>>> -    }
>>>>>>> -  else
>>>>>>> -    card->txbuf = grub_zalloc (card->txbufsize);
>>>>>>> +  card->txbuf = ofnet_alloc_netbuf (card->txbufsize);
>>>>>>>    if (!card->txbuf)
>>>>>>> +    goto fail;
>>>>>>> +
>>>>>>> +  card->rcvbuf = ofnet_alloc_netbuf (card->rcvbufsize);
>>>>>>> +  if (!card->rcvbuf)
>>>>>>>      {
>>>>>>> -      grub_free (ofdata->path);
>>>>>>> -      grub_free (ofdata);
>>>>>>> -      grub_free (card);
>>>>>>> -      grub_print_error ();
>>>>>>> -      return 0;
>>>>>>> +      grub_error_push ();
>>>>>>> +      ofnet_free_netbuf(card->txbuf, card->txbufsize);
>>>>>>> +      grub_error_pop ();
>>>>>>> +      goto fail;
>>>>>>>      }
>>>>
>>>> Should not we free card->rcvbuf and/or card->txbuf if module is
>>>> unloaded or something like that?
>>>
>>> Yes, I think so. Thanks for pointing at this.
>>>
>>> It's interesting that none of uboot, efi, ieee1275 drivers seems to care
>>> of freeing the card data structure on module unload. All they do is
>>> similar to:
>>>
>>> FOR_NET_CARDS_SAFE (card, next)
>>>   if (the card is handled by us)
>>>     grub_net_card_unregister (card);
>>>
>>> whereas from grub-core/net/net.c I don't see that
>>> grub_net_card_unregister() frees memory.
>>>
>>> It seems that the job of freeing card's memory is expected to be handled
>>> in drivers and none of the drivers care about it, excluding pxe, where
>>> 'grub_pxe_card' is statically allocated. Or am I missing something?
>>>
>>> As for ieee1275 I'm thinking about something like:
>>>
>>> diff --git a/grub-core/net/drivers/ieee1275/ofnet.c
>>> b/grub-core/net/drivers/ieee1275/ofnet.c
>>> index 6bd3b92..12a4289 100644
>>> --- a/grub-core/net/drivers/ieee1275/ofnet.c
>>> +++ b/grub-core/net/drivers/ieee1275/ofnet.c
>>> @@ -473,9 +473,28 @@ GRUB_MOD_INIT(ofnet)
>>>  GRUB_MOD_FINI(ofnet)
>>>  {
>>>    struct grub_net_card *card, *next;
>>> +  struct grub_ofnetcard_data *ofdata;
>>>
>>>    FOR_NET_CARDS_SAFE (card, next)
>>>      if (card->driver && grub_strcmp (card->driver->name, "ofnet") == 0)
>>> -      grub_net_card_unregister (card);
>>> +      {
>>> +       grub_net_card_unregister (card);
>>> +
>>> +       /*
>>> +        * The fact that we are here means the card was successfully
>>> +        * initialized in the past, so all the below pointers are valid,
>>> +        * and we may free associated memory without checks.
>>> +        */
>>> +
>>> +       ofdata = (struct grub_ofnetcard_data *) card->data;
>>> +       grub_free (ofdata->path);
>>> +       grub_free (ofdata->suffix);
>>> +       grub_free (ofdata);
>>> +
>>> +       ofnet_free_netbuf (card->txbuf, card->txbufsize);
>>> +       ofnet_free_netbuf (card->rcvbuf, card->rcvbufsize);
>>> +
>>> +       grub_free (card);
>>> +      }
>>>    grub_ieee1275_net_config = 0;
>>>  }
>>>
>>> (not tested)
>>>
>>> I think it deserves a separate patch. In one patch we are adding the
>>> receive buffer, and in another we are making the ieee1275 driver to free
>>> all card resources on unload.
>>
>> Make sense for me. Could you do the same thing for other modules (at
>> least for those mentioned by you) too? Of course in separate patches.
> 
> I'll do this for ieee1275. As for efi/uboot, I think I can also do this,
> but later, since testing this may take some time. I'd prefer to play
> with efi/uboot after finishing with this series :)
> 
> Regarding this series. It seems we have all questions answered and the
> ball is on my side. I'll try to come up with V2 someday next week.
> 
> Thank you for your time reviewing this!
> 
>>
>> Daniel
>>
>> _______________________________________________
>> Grub-devel mailing list
>> address@hidden
>> https://lists.gnu.org/mailman/listinfo/grub-devel
>>
> 
> _______________________________________________
> Grub-devel mailing list
> address@hidden
> https://lists.gnu.org/mailman/listinfo/grub-devel
> 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]