All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrei Borzenkov <arvidjaar@gmail.com>
To: grub-devel@gnu.org
Subject: Re: [PATCH 1/2] disk: Add support for device-specific malloc function
Date: Mon, 22 Feb 2016 19:56:25 +0300	[thread overview]
Message-ID: <56CB3DB9.4050102@gmail.com> (raw)
In-Reply-To: <20160222140255.GO1159@bivouac.eciton.net>

[-- Attachment #1: Type: text/plain, Size: 2021 bytes --]

22.02.2016 17:02, Leif Lindholm пишет:
> On Mon, Feb 22, 2016 at 10:57:24AM +0300, Andrei Borzenkov wrote:
>> 19.02.2016 19:18, Leif Lindholm пишет:
>>> Some disk types have allocation requirements beyond normal grub_malloc.
>>> Add a function pointer to grub_disk_t and a wrapper function in
>>> kern/disk.c making use of that function if available, to enable these
>>> disk drivers to implement their own malloc.
>>
>> The problem is not (only) grub_disk_read_small(), but this part in
>> grub_disk_read:
>>
>>       if (agglomerate)
>>         {
>>           grub_disk_addr_t i;
>>
>>           err = (disk->dev->read) (disk, transform_sector (disk, sector),
>>                                    agglomerate << (GRUB_DISK_CACHE_BITS
>>                                                    + GRUB_DISK_SECTOR_BITS
>>                                                    - disk->log_sector_size),
>>                                    buf);
>>
>> which reads directly into user supplied buffer. May be we can allocate
>> contiguous cache block here but put pointers to multiple chunks inside
>> it. Possible implementation is to have second layer of reference counted
>> memory blocks with cache entries containing pointer + offset into them.
> 
> Whoops!
> 
> Understood.
> 
> So how about merging the two concepts?
> Including a patch to go with (after) the previous two to catch any
> remaining unaligned accesses in grub_efidisk_readwrite().
> With this applied, I get no fixups from a normal Linux boot (linux +
> initrd), but see them when exploring filesystems from the command
> line.
> 
> Whilst a bit clunky, this seems much short-term preferable to going
> back and redesigning the disk subsystem to understand that alignment
> matters. Although given the number of exceptions we seem to be
> amassing, that does not sound like a bad idea for future.
> 

Could you test attached patch with your alignment fixes on top. This
implements my idea of using shared buffers. Seems to work in naive testing.



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: disk-direct-cache-read.patch --]
[-- Type: text/x-patch; name="disk-direct-cache-read.patch", Size: 6984 bytes --]

From: Andrei Borzenkov <arvidjaar@gmail.com>
Subject: [PATCH] disk: read into cache directly

<patch description>

---
 grub-core/kern/disk.c | 94 ++++++++++++++++++++++++++++++---------------------
 grub-core/lib/disk.c  |  6 ++--
 include/grub/disk.h   | 11 +++++-
 3 files changed, 69 insertions(+), 42 deletions(-)

diff --git a/grub-core/kern/disk.c b/grub-core/kern/disk.c
index 789f8c0..945c146 100644
--- a/grub-core/kern/disk.c
+++ b/grub-core/kern/disk.c
@@ -56,6 +56,20 @@ grub_err_t (*grub_disk_write_weak) (grub_disk_t disk,
 #include "disk_common.c"
 
 void
+grub_disk_cache_free (struct grub_cache_buffer *buf)
+{
+  if (!buf->count)
+    /* FIXME This means corruption; what can we do? */
+    return;
+
+  if (!--buf->count)
+    {
+      grub_free (buf->data);
+      grub_free (buf);
+    }
+}
+
+void
 grub_disk_cache_invalidate_all (void)
 {
   unsigned i;
@@ -64,10 +78,10 @@ grub_disk_cache_invalidate_all (void)
     {
       struct grub_disk_cache *cache = grub_disk_cache_table + i;
 
-      if (cache->data && ! cache->lock)
+      if (cache->buffer && ! cache->lock)
 	{
-	  grub_free (cache->data);
-	  cache->data = 0;
+	  grub_disk_cache_free (cache->buffer);
+	  cache->buffer = 0;
 	}
     }
 }
@@ -82,14 +96,14 @@ grub_disk_cache_fetch (unsigned long dev_id, unsigned long disk_id,
   cache_index = grub_disk_cache_get_index (dev_id, disk_id, sector);
   cache = grub_disk_cache_table + cache_index;
 
-  if (cache->dev_id == dev_id && cache->disk_id == disk_id
+  if (cache->buffer && cache->dev_id == dev_id && cache->disk_id == disk_id
       && cache->sector == sector)
     {
       cache->lock = 1;
 #if DISK_CACHE_STATS
       grub_disk_cache_hits++;
 #endif
-      return cache->data;
+      return cache->buffer->data + cache->offset;
     }
 
 #if DISK_CACHE_STATS
@@ -116,28 +130,35 @@ grub_disk_cache_unlock (unsigned long dev_id, unsigned long disk_id,
 
 static grub_err_t
 grub_disk_cache_store (unsigned long dev_id, unsigned long disk_id,
-		       grub_disk_addr_t sector, const char *data)
+		       grub_disk_addr_t sector, grub_disk_addr_t n, char *data)
 {
-  unsigned cache_index;
-  struct grub_disk_cache *cache;
+  struct grub_cache_buffer *buf;
+  grub_addr_t offset;
 
-  cache_index = grub_disk_cache_get_index (dev_id, disk_id, sector);
-  cache = grub_disk_cache_table + cache_index;
+  buf = grub_malloc (sizeof (*buf));
+  if (! buf)
+    return grub_errno;
+  buf->data = data;
+  buf->count = 0;
 
-  cache->lock = 1;
-  grub_free (cache->data);
-  cache->data = 0;
-  cache->lock = 0;
+  for (offset = 0 ; n > 0; sector += GRUB_DISK_CACHE_SIZE, offset += (GRUB_DISK_CACHE_SIZE * GRUB_DISK_SECTOR_SIZE), n--)
+    {
+      unsigned cache_index;
+      struct grub_disk_cache *cache;
 
-  cache->data = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
-  if (! cache->data)
-    return grub_errno;
+      cache_index = grub_disk_cache_get_index (dev_id, disk_id, sector);
+      cache = grub_disk_cache_table + cache_index;
 
-  grub_memcpy (cache->data, data,
-	       GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
-  cache->dev_id = dev_id;
-  cache->disk_id = disk_id;
-  cache->sector = sector;
+      cache->lock = 1;
+      grub_disk_cache_free (cache->buffer);
+      cache->buffer = buf;
+      cache->offset = offset;
+      buf->count++;
+      cache->lock = 0;
+      cache->dev_id = dev_id;
+      cache->disk_id = disk_id;
+      cache->sector = sector;
+    }
 
   return GRUB_ERR_NONE;
 }
@@ -350,13 +371,11 @@ grub_disk_read_small_real (grub_disk_t disk, grub_disk_addr_t sector,
 	  /* Copy it and store it in the disk cache.  */
 	  grub_memcpy (buf, tmp_buf + offset, size);
 	  grub_disk_cache_store (disk->dev->id, disk->id,
-				 sector, tmp_buf);
-	  grub_free (tmp_buf);
+				 sector, 1, tmp_buf);
 	  return GRUB_ERR_NONE;
 	}
     }
 
-  grub_free (tmp_buf);
   grub_errno = GRUB_ERR_NONE;
 
   {
@@ -373,10 +392,6 @@ grub_disk_read_small_real (grub_disk_t disk, grub_disk_addr_t sector,
     num = ((size + offset + (1ULL << (disk->log_sector_size))
 	    - 1) >> (disk->log_sector_size));
 
-    tmp_buf = grub_malloc (num << disk->log_sector_size);
-    if (!tmp_buf)
-      return grub_errno;
-    
     if ((disk->dev->read) (disk, transform_sector (disk, aligned_sector),
 			   num, tmp_buf))
       {
@@ -481,22 +496,25 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
 
       if (agglomerate)
 	{
-	  grub_disk_addr_t i;
+	  void *cache = grub_malloc (agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS));
+	  if (!cache)
+	    return grub_errno;
 
 	  err = (disk->dev->read) (disk, transform_sector (disk, sector),
 				   agglomerate << (GRUB_DISK_CACHE_BITS
 						   + GRUB_DISK_SECTOR_BITS
 						   - disk->log_sector_size),
-				   buf);
+				   cache);
 	  if (err)
-	    return err;
+	    {
+	      grub_free (cache);
+	      return err;
+	    }
 	  
-	  for (i = 0; i < agglomerate; i ++)
-	    grub_disk_cache_store (disk->dev->id, disk->id,
-				   sector + (i << GRUB_DISK_CACHE_BITS),
-				   (char *) buf
-				   + (i << (GRUB_DISK_CACHE_BITS
-					    + GRUB_DISK_SECTOR_BITS)));
+	  grub_memcpy (buf, cache,
+		       agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS));
+	  grub_disk_cache_store (disk->dev->id, disk->id,
+				 sector, agglomerate, cache);
 
 
 	  if (disk->read_hook)
diff --git a/grub-core/lib/disk.c b/grub-core/lib/disk.c
index 0f18688..07fb117 100644
--- a/grub-core/lib/disk.c
+++ b/grub-core/lib/disk.c
@@ -42,11 +42,11 @@ grub_disk_cache_invalidate (unsigned long dev_id, unsigned long disk_id,
   cache = grub_disk_cache_table + cache_index;
 
   if (cache->dev_id == dev_id && cache->disk_id == disk_id
-      && cache->sector == sector && cache->data)
+      && cache->sector == sector && cache->buffer)
     {
       cache->lock = 1;
-      grub_free (cache->data);
-      cache->data = 0;
+      grub_disk_cache_free (cache->buffer);
+      cache->buffer = 0;
       cache->lock = 0;
     }
 }
diff --git a/include/grub/disk.h b/include/grub/disk.h
index b385af8..9e60367 100644
--- a/include/grub/disk.h
+++ b/include/grub/disk.h
@@ -233,16 +233,25 @@ grub_stop_disk_firmware (void)
     }
 }
 
+struct grub_cache_buffer
+  {
+    char *data;
+    unsigned count;
+  };
+
 /* Disk cache.  */
 struct grub_disk_cache
 {
   enum grub_disk_dev_id dev_id;
   unsigned long disk_id;
   grub_disk_addr_t sector;
-  char *data;
+  struct grub_cache_buffer *buffer;
+  grub_addr_t offset;
   int lock;
 };
 
+void EXPORT_FUNC(grub_disk_cache_free) (struct grub_cache_buffer *buf);
+
 extern struct grub_disk_cache EXPORT_VAR(grub_disk_cache_table)[GRUB_DISK_CACHE_NUM];
 
 #if defined (GRUB_UTIL)
-- 
tg: (bc22096..) e/disk-cache-align (depends on: master)

  reply	other threads:[~2016-02-22 16:56 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-02-19 16:18 [PATCH 0/2] Alternative efidisk alignment resolution Leif Lindholm
2016-02-19 16:18 ` [PATCH 1/2] disk: Add support for device-specific malloc function Leif Lindholm
2016-02-22  7:57   ` Andrei Borzenkov
2016-02-22 14:02     ` Leif Lindholm
2016-02-22 16:56       ` Andrei Borzenkov [this message]
2016-02-24 11:59         ` Leif Lindholm
2016-02-24 12:09           ` Andrei Borzenkov
2016-02-24 13:57             ` Leif Lindholm
2016-02-24 17:40               ` Andrei Borzenkov
2016-02-24 19:04                 ` Andrei Borzenkov
2016-02-26 13:27                   ` Vladimir 'phcoder' Serbinenko
2016-02-26 13:48                     ` Andrei Borzenkov
2016-02-26 13:52                       ` Vladimir 'phcoder' Serbinenko
2016-03-01 17:11                 ` Leif Lindholm
2016-03-01 19:46                   ` Andrei Borzenkov
2016-03-01 20:19                     ` Leif Lindholm
2016-02-22 16:57   ` Andrei Borzenkov
2016-02-22 16:59     ` Vladimir 'phcoder' Serbinenko
2016-02-19 16:18 ` [PATCH 2/2] efidisk: respect block_io_protocol minimum buffer alignment Leif Lindholm

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=56CB3DB9.4050102@gmail.com \
    --to=arvidjaar@gmail.com \
    --cc=grub-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.