Re: [PATCH v3 0/2] btrfs: Add zstd support to grub btrfs

2018-10-11 Thread Nick Terrell



> On Oct 11, 2018, at 11:15 AM, Daniel Kiper  wrote:
> 
> Hi Nick,
> 
> CC-ing Goffredo.
> 
> On Tue, Oct 09, 2018 at 04:21:35PM -0700, Nick Terrell wrote:
>> Hi all,
>> 
>> This patch set imports the upstream zstd library, adds zstd support to the
>> btrfs module, and adds a test case. I've also tested the patch set by storing
>> my boot partition in btrfs with and without zstd compression and rebooting.
>> 
>> The fist patch imports the files needed to support zstd decompression from
>> zstd-1.3.6 as-is. It is a very large patch. In case it doesn't make it,
>> I've included the commit hash and the script I used to download the files.
>> 
>> Upstream zstd commit hash: 4fa456d7f12f8b27bd3b2f5dfd4f46898cb31c24
>> Upstream zstd commit name: Merge pull request #1354 from facebook/dev
> 
> In general I am happy with the patches. If everything is done what
> I have asked for then I will get them. However, there is one problem.
> Another big btrfs (RAID) patchset is lurking around for months. It is
> almost ready. Goffredo, I am looking at you... So, I would like to take
> RAID patchset first. If it is in the tree then I will ask you to rebase
> zstd patchset on top of RAID patchset and I will take it. Nick, are you
> OK with that?

That works for me, thanks!

> Daniel


___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


[PATCH 9/9] btrfs: Add RAID 6 recovery for a btrfs filesystem.

2018-10-11 Thread Goffredo Baroncelli
From: Goffredo Baroncelli 

Add the RAID 6 recovery, in order to use a RAID 6 filesystem even if some
disks (up to two) are missing. This code use the md RAID 6 code already
present in grub.

Signed-off-by: Goffredo Baroncelli 
Reviewed-by: Daniel Kiper 
---
 grub-core/fs/btrfs.c | 60 +++-
 1 file changed, 54 insertions(+), 6 deletions(-)

diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
index d066d54cc..d20ee09e4 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -30,6 +30,7 @@
 #include 
 #include 
 #include 
+#include 
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -702,11 +703,36 @@ rebuild_raid5 (char *dest, struct raid56_buffer *buffers,
 }
 }
 
+static grub_err_t
+raid6_recover_read_buffer (void *data, int disk_nr,
+  grub_uint64_t addr __attribute__ ((unused)),
+  void *dest, grub_size_t size)
+{
+struct raid56_buffer *buffers = data;
+
+if (!buffers[disk_nr].data_is_valid)
+   return grub_errno = GRUB_ERR_READ_ERROR;
+
+grub_memcpy(dest, buffers[disk_nr].buf, size);
+
+return grub_errno = GRUB_ERR_NONE;
+}
+
+static void
+rebuild_raid6 (struct raid56_buffer *buffers, grub_uint64_t nstripes,
+   grub_uint64_t csize, grub_uint64_t parities_pos, void *dest,
+   grub_uint64_t stripen)
+
+{
+  grub_raid6_recover_gen (buffers, nstripes, stripen, parities_pos,
+  dest, 0, csize, 0, raid6_recover_read_buffer);
+}
+
 static grub_err_t
 raid56_read_retry (struct grub_btrfs_data *data,
   struct grub_btrfs_chunk_item *chunk,
-  grub_uint64_t stripe_offset,
-  grub_uint64_t csize, void *buf)
+  grub_uint64_t stripe_offset, grub_uint64_t stripen,
+  grub_uint64_t csize, void *buf, grub_uint64_t parities_pos)
 {
   struct raid56_buffer *buffers;
   grub_uint64_t nstripes = grub_le_to_cpu16 (chunk->nstripes);
@@ -779,6 +805,15 @@ raid56_read_retry (struct grub_btrfs_data *data,
   ret = GRUB_ERR_READ_ERROR;
   goto cleanup;
 }
+  else if (failed_devices > 2 && (chunk_type & GRUB_BTRFS_CHUNK_TYPE_RAID6))
+{
+  grub_dprintf ("btrfs",
+   "not enough disks for raid6: total %" PRIuGRUB_UINT64_T
+   ", missing %" PRIuGRUB_UINT64_T "\n",
+   nstripes, failed_devices);
+  ret = GRUB_ERR_READ_ERROR;
+  goto cleanup;
+}
   else
 grub_dprintf ("btrfs",
  "enough disks for RAID 5 rebuilding: total %"
@@ -789,7 +824,7 @@ raid56_read_retry (struct grub_btrfs_data *data,
   if (chunk_type & GRUB_BTRFS_CHUNK_TYPE_RAID5)
 rebuild_raid5 (buf, buffers, nstripes, csize);
   else
-grub_dprintf ("btrfs", "called rebuild_raid6(), NOT IMPLEMENTED\n");
+rebuild_raid6 (buffers, nstripes, csize, parities_pos, buf, stripen);
 
   ret = GRUB_ERR_NONE;
  cleanup:
@@ -879,9 +914,11 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, 
grub_disk_addr_t addr,
unsigned redundancy = 1;
unsigned i, j;
int is_raid56;
+   grub_uint64_t parities_pos = 0;
 
-   is_raid56 = !!(grub_le_to_cpu64 (chunk->type) &
-  GRUB_BTRFS_CHUNK_TYPE_RAID5);
+is_raid56 = !!(grub_le_to_cpu64 (chunk->type) &
+  (GRUB_BTRFS_CHUNK_TYPE_RAID5 |
+   GRUB_BTRFS_CHUNK_TYPE_RAID6));
 
if (grub_le_to_cpu64 (chunk->size) <= off)
  {
@@ -1030,6 +1067,17 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, 
grub_disk_addr_t addr,
   */
  grub_divmod64 (high + stripen, nstripes, );
 
+ /*
+  * parities_pos is equal to "(high - nparities) % nstripes"
+  * (see the diagram above).
+  * However "high - nparities" might be negative (eg when high
+  * == 0) leading to an incorrect computation.
+  * Instead "high + nstripes - nparities" is always positive and
+  * in modulo nstripes is equal to "(high - nparities) % nstripes"
+  */
+ grub_divmod64 (high + nstripes - nparities, nstripes,
+_pos);
+
  stripe_offset = low + chunk_stripe_length * high;
  csize = chunk_stripe_length - low;
 
@@ -1081,7 +1129,7 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, 
grub_disk_addr_t addr,
grub_errno = GRUB_ERR_NONE;
if (err)
  err = raid56_read_retry (data, chunk, stripe_offset,
-  csize, buf);
+  stripen, csize, buf, parities_pos);
  }
if (!err)
  break;
-- 
2.19.1


___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


[PATCH 6/9] btrfs: Refactor the code that read from disk

2018-10-11 Thread Goffredo Baroncelli
From: Goffredo Baroncelli 

Move the code in charge to read the data from disk into a separate
function. This helps to separate the error handling logic (which depends on
the different raid profiles) from the read from disk logic.
Refactoring this code increases the general readability too.

This is a preparatory patch, to help the adding of the RAID 5/6 recovery
code.

Signed-off-by: Goffredo Baroncelli 
Reviewed-by: Daniel Kiper 
---
 grub-core/fs/btrfs.c | 75 ++--
 1 file changed, 44 insertions(+), 31 deletions(-)

diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
index a82211ccc..899dc32b7 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -625,6 +625,46 @@ find_device (struct grub_btrfs_data *data, grub_uint64_t 
id)
   return ctx.dev_found;
 }
 
+static grub_err_t
+btrfs_read_from_chunk (struct grub_btrfs_data *data,
+  struct grub_btrfs_chunk_item *chunk,
+  grub_uint64_t stripen, grub_uint64_t stripe_offset,
+  int redundancy, grub_uint64_t csize,
+  void *buf)
+{
+struct grub_btrfs_chunk_stripe *stripe;
+grub_disk_addr_t paddr;
+grub_device_t dev;
+grub_err_t err;
+
+stripe = (struct grub_btrfs_chunk_stripe *) (chunk + 1);
+/* Right now the redundancy handling is easy.
+   With RAID5-like it will be more difficult.  */
+stripe += stripen + redundancy;
+
+paddr = grub_le_to_cpu64 (stripe->offset) + stripe_offset;
+
+grub_dprintf ("btrfs", "stripe %" PRIxGRUB_UINT64_T
+ " maps to 0x%" PRIxGRUB_UINT64_T
+ ". Reading paddr 0x%" PRIxGRUB_UINT64_T "\n",
+ stripen, stripe->offset, paddr);
+
+dev = find_device (data, stripe->device_id);
+if (!dev)
+  {
+   grub_dprintf ("btrfs",
+ "couldn't find a necessary member device "
+ "of multi-device filesystem\n");
+   grub_errno = GRUB_ERR_NONE;
+   return GRUB_ERR_READ_ERROR;
+  }
+
+err = grub_disk_read (dev->disk, paddr >> GRUB_DISK_SECTOR_BITS,
+ paddr & (GRUB_DISK_SECTOR_SIZE - 1),
+ csize, buf);
+return err;
+}
+
 static grub_err_t
 grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
 void *buf, grub_size_t size, int recursion_depth)
@@ -638,7 +678,6 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, 
grub_disk_addr_t addr,
   grub_err_t err = 0;
   struct grub_btrfs_key key_out;
   int challoc = 0;
-  grub_device_t dev;
   struct grub_btrfs_key key_in;
   grub_size_t chsize;
   grub_disk_addr_t chaddr;
@@ -884,36 +923,10 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, 
grub_disk_addr_t addr,
 
for (i = 0; i < redundancy; i++)
  {
-   struct grub_btrfs_chunk_stripe *stripe;
-   grub_disk_addr_t paddr;
-
-   stripe = (struct grub_btrfs_chunk_stripe *) (chunk + 1);
-   /* Right now the redundancy handling is easy.
-  With RAID5-like it will be more difficult.  */
-   stripe += stripen + i;
-
-   paddr = grub_le_to_cpu64 (stripe->offset) + stripe_offset;
-
-   grub_dprintf ("btrfs", "stripe %" PRIxGRUB_UINT64_T
- " maps to 0x%" PRIxGRUB_UINT64_T "\n",
- stripen, stripe->offset);
-   grub_dprintf ("btrfs", "reading paddr 0x%" PRIxGRUB_UINT64_T
- "\n", paddr);
-
-   dev = find_device (data, stripe->device_id);
-   if (!dev)
- {
-   grub_dprintf ("btrfs",
- "couldn't find a necessary member device "
- "of multi-device filesystem\n");
-   err = grub_errno;
-   grub_errno = GRUB_ERR_NONE;
-   continue;
- }
-
-   err = grub_disk_read (dev->disk, paddr >> GRUB_DISK_SECTOR_BITS,
- paddr & (GRUB_DISK_SECTOR_SIZE - 1),
- csize, buf);
+   err = btrfs_read_from_chunk (data, chunk, stripen,
+stripe_offset,
+i, /* redundancy */
+csize, buf);
if (!err)
  break;
grub_errno = GRUB_ERR_NONE;
-- 
2.19.1


___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


[PATCH 5/9] btrfs: Move logging code in grub_btrfs_read_logical()

2018-10-11 Thread Goffredo Baroncelli
From: Goffredo Baroncelli 

A portion of the logging code is moved outside of internal for(;;). The part
that is left inside is the one which depends on the internal for(;;) index.

This is a preparatory patch. The next one will refactor the code inside
the for(;;) into an another function.

Signed-off-by: Goffredo Baroncelli 
Reviewed-by: Daniel Kiper 
---
 grub-core/fs/btrfs.c | 25 ++---
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
index b2be80c33..a82211ccc 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -870,6 +870,18 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, 
grub_disk_addr_t addr,
 
for (j = 0; j < 2; j++)
  {
+   grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T
+ "+0x%" PRIxGRUB_UINT64_T
+ " (%d stripes (%d substripes) of %"
+ PRIxGRUB_UINT64_T ")\n",
+ grub_le_to_cpu64 (key->offset),
+ grub_le_to_cpu64 (chunk->size),
+ grub_le_to_cpu16 (chunk->nstripes),
+ grub_le_to_cpu16 (chunk->nsubstripes),
+ grub_le_to_cpu64 (chunk->stripe_length));
+   grub_dprintf ("btrfs", "reading laddr 0x%" PRIxGRUB_UINT64_T "\n",
+ addr);
+
for (i = 0; i < redundancy; i++)
  {
struct grub_btrfs_chunk_stripe *stripe;
@@ -882,20 +894,11 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, 
grub_disk_addr_t addr,
 
paddr = grub_le_to_cpu64 (stripe->offset) + stripe_offset;
 
-   grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T
- "+0x%" PRIxGRUB_UINT64_T
- " (%d stripes (%d substripes) of %"
- PRIxGRUB_UINT64_T ") stripe %" PRIxGRUB_UINT64_T
+   grub_dprintf ("btrfs", "stripe %" PRIxGRUB_UINT64_T
  " maps to 0x%" PRIxGRUB_UINT64_T "\n",
- grub_le_to_cpu64 (key->offset),
- grub_le_to_cpu64 (chunk->size),
- grub_le_to_cpu16 (chunk->nstripes),
- grub_le_to_cpu16 (chunk->nsubstripes),
- grub_le_to_cpu64 (chunk->stripe_length),
  stripen, stripe->offset);
grub_dprintf ("btrfs", "reading paddr 0x%" PRIxGRUB_UINT64_T
- " for laddr 0x%" PRIxGRUB_UINT64_T "\n", paddr,
- addr);
+ "\n", paddr);
 
dev = find_device (data, stripe->device_id);
if (!dev)
-- 
2.19.1


___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


[PATCH V9] Add support for BTRFS raid5/6 to GRUB

2018-10-11 Thread Goffredo Baroncelli


Hi All,

the aim of this patches set is to provide support for a BTRFS raid5/6
filesystem in GRUB.

The first patch, implements the basic support for raid5/6. I.e this works when
all the disks are present.

The next 5 patches, are preparatory ones.

The 7th patch implements the raid5 recovery for btrfs (i.e. handling the
disappearing of 1 disk).
The 8th patch makes the code for handling the raid6 recovery more generic.
The last one implements the raid6 recovery for btrfs (i.e. handling the
disappearing up to two disks).

I tested the code in grub-emu, and it works both with all the disks,
and with some disks missing. I checked the crc32 calculated from grub and
from linux and these matched. Finally I checked if the support for md raid6
still works properly, and it does (with all drives and with up to 2 drives
missing)

Comments are welcome.

Changelog
v1: initial support for btrfs raid5/6. No recovery allowed
v2: full support for btrfs raid5/6. Recovery allowed
v3: some minor cleanup suggested by Daniel Kiper; reusing the
original raid6 recovery code of grub
v4: Several spell fix; better description of the RAID layout
in btrfs, and the variables which describes the stripe
positioning; split the patch #5 in two (#5 and #6)
v5: Several spell fix; improved code comment in patch #1, small
clean up in the code
v6: Small cleanup; improved the wording in the RAID6 layout
description; in the function raid6_recover_read_buffer() avoid
a unnecessary memcpy in case of invalid data;
v7: - patch 2,3,5,6,8 received an Review-by Daniel, and were unchanged from
the last time (only minor cleanup in the commit description requested by
Daniel)
- patch 7 received some small update rearranging a for(), and some
bracket around if()
- patch 4, received an update message which explains better why NULL
is stored in data->devices_attached[]
- patch 9, received a blank line to separate better a code line from
a previous comment. A description of 'parities_pos' was added
- patch 1, received a major update about the variable meaning description
in the comment. However I suspect that we need some further review to reach
a fully agreement about this text. NB: the update are relate only to 
comments
v8: - patch 2,5,6,8 received an Review-by Daniel, and were unchanged from
the last time (only minor cleanup in the commit description requested by
Daniel)
- patch 1 received some adjustement to the variables description due to
  the different terminology between BTRFS and other RAID implementatio.
  Added a description for the "nparities" variable.
- patch 3 removed some unnecessary curly brackets (change request by Daniel)
- patch 4 received an improved commit description about why and how 
  the function find_device() is changed
- patch 7 received an update which transforms a i = 0; while(i..) i++; in
  for( i = 0. ; i++);
- patch 9 received an update to the comment
v9: - patch 1: update comments
- patch 4: update commit messages
- patch 7: added a comment about accessing an array of structs
  after another structs; changed if(err == GRUB_ERR_NONE) in if(!err)
  changed if(err != GRUB_ERR_NONE) in if(err)



BR
G.Baroncelli

--
gpg @keyserver.linux.it: Goffredo Baroncelli 
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5






___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


[PATCH 8/9] btrfs: Make more generic the code for RAID 6 rebuilding

2018-10-11 Thread Goffredo Baroncelli
From: Goffredo Baroncelli 

The original code which handles the recovery of a RAID 6 disks array
assumes that all reads are multiple of 1 << GRUB_DISK_SECTOR_BITS and it
assumes that all the I/O is done via the struct grub_diskfilter_segment.
This is not true for the btrfs code. In order to reuse the native
grub_raid6_recover() code, it is modified to not call
grub_diskfilter_read_node() directly, but to call an handler passed
as an argument.

Signed-off-by: Goffredo Baroncelli 
Reviewed-by: Daniel Kiper 
---
 grub-core/disk/raid6_recover.c | 52 ++
 include/grub/diskfilter.h  |  9 ++
 2 files changed, 43 insertions(+), 18 deletions(-)

diff --git a/grub-core/disk/raid6_recover.c b/grub-core/disk/raid6_recover.c
index aa674f6ca..0cf691ddf 100644
--- a/grub-core/disk/raid6_recover.c
+++ b/grub-core/disk/raid6_recover.c
@@ -74,14 +74,26 @@ mod_255 (unsigned x)
 }
 
 static grub_err_t
-grub_raid6_recover (struct grub_diskfilter_segment *array, int disknr, int p,
-char *buf, grub_disk_addr_t sector, grub_size_t size)
+raid6_recover_read_node (void *data, int disknr,
+   grub_uint64_t sector,
+   void *buf, grub_size_t size)
+{
+struct grub_diskfilter_segment *array = data;
+
+return grub_diskfilter_read_node (>nodes[disknr],
+ (grub_disk_addr_t)sector,
+ size >> GRUB_DISK_SECTOR_BITS, buf);
+}
+
+grub_err_t
+grub_raid6_recover_gen (void *data, grub_uint64_t nstripes, int disknr, int p,
+   char *buf, grub_uint64_t sector, grub_size_t size,
+   int layout, raid_recover_read_t read_func)
 {
   int i, q, pos;
   int bad1 = -1, bad2 = -1;
   char *pbuf = 0, *qbuf = 0;
 
-  size <<= GRUB_DISK_SECTOR_BITS;
   pbuf = grub_zalloc (size);
   if (!pbuf)
 goto quit;
@@ -91,17 +103,17 @@ grub_raid6_recover (struct grub_diskfilter_segment *array, 
int disknr, int p,
 goto quit;
 
   q = p + 1;
-  if (q == (int) array->node_count)
+  if (q == (int) nstripes)
 q = 0;
 
   pos = q + 1;
-  if (pos == (int) array->node_count)
+  if (pos == (int) nstripes)
 pos = 0;
 
-  for (i = 0; i < (int) array->node_count - 2; i++)
+  for (i = 0; i < (int) nstripes - 2; i++)
 {
   int c;
-  if (array->layout & GRUB_RAID_LAYOUT_MUL_FROM_POS)
+  if (layout & GRUB_RAID_LAYOUT_MUL_FROM_POS)
c = pos;
   else
c = i;
@@ -109,8 +121,7 @@ grub_raid6_recover (struct grub_diskfilter_segment *array, 
int disknr, int p,
 bad1 = c;
   else
 {
-  if (! grub_diskfilter_read_node (>nodes[pos], sector,
-  size >> GRUB_DISK_SECTOR_BITS, buf))
+ if (!read_func(data, pos, sector, buf, size))
 {
   grub_crypto_xor (pbuf, pbuf, buf, size);
   grub_raid_block_mulx (c, buf, size);
@@ -128,7 +139,7 @@ grub_raid6_recover (struct grub_diskfilter_segment *array, 
int disknr, int p,
 }
 
   pos++;
-  if (pos == (int) array->node_count)
+  if (pos == (int) nstripes)
 pos = 0;
 }
 
@@ -139,16 +150,14 @@ grub_raid6_recover (struct grub_diskfilter_segment 
*array, int disknr, int p,
   if (bad2 < 0)
 {
   /* One bad device */
-  if ((! grub_diskfilter_read_node (>nodes[p], sector,
-   size >> GRUB_DISK_SECTOR_BITS, buf)))
+  if (!read_func(data, p, sector, buf, size))
 {
   grub_crypto_xor (buf, buf, pbuf, size);
   goto quit;
 }
 
   grub_errno = GRUB_ERR_NONE;
-  if (grub_diskfilter_read_node (>nodes[q], sector,
-size >> GRUB_DISK_SECTOR_BITS, buf))
+  if (read_func(data, q, sector, buf, size))
 goto quit;
 
   grub_crypto_xor (buf, buf, qbuf, size);
@@ -160,14 +169,12 @@ grub_raid6_recover (struct grub_diskfilter_segment 
*array, int disknr, int p,
   /* Two bad devices */
   unsigned c;
 
-  if (grub_diskfilter_read_node (>nodes[p], sector,
-size >> GRUB_DISK_SECTOR_BITS, buf))
+  if (read_func(data, p, sector, buf, size))
 goto quit;
 
   grub_crypto_xor (pbuf, pbuf, buf, size);
 
-  if (grub_diskfilter_read_node (>nodes[q], sector,
-size >> GRUB_DISK_SECTOR_BITS, buf))
+  if (read_func(data, q, sector, buf, size))
 goto quit;
 
   grub_crypto_xor (qbuf, qbuf, buf, size);
@@ -190,6 +197,15 @@ quit:
   return grub_errno;
 }
 
+static grub_err_t
+grub_raid6_recover (struct grub_diskfilter_segment *array, int disknr, int p,
+char *buf, grub_disk_addr_t sector, grub_size_t size)
+{
+  return grub_raid6_recover_gen (array, array->node_count, disknr, p, buf,
+sector, size << GRUB_DISK_SECTOR_BITS,
+

[PATCH 7/9] btrfs: Add support for recovery for a RAID 5 btrfs profiles.

2018-10-11 Thread Goffredo Baroncelli
From: Goffredo Baroncelli 

Add support for recovery for a RAID 5 btrfs profile. In addition
it is added some code as preparatory work for RAID 6 recovery code.

Signed-off-by: Goffredo Baroncelli 
---
 grub-core/fs/btrfs.c | 162 +--
 1 file changed, 157 insertions(+), 5 deletions(-)

diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
index 899dc32b7..d066d54cc 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -29,6 +29,7 @@
 #include 
 #include 
 #include 
+#include 
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -665,6 +666,141 @@ btrfs_read_from_chunk (struct grub_btrfs_data *data,
 return err;
 }
 
+struct raid56_buffer {
+  void *buf;
+  int  data_is_valid;
+};
+
+static void
+rebuild_raid5 (char *dest, struct raid56_buffer *buffers,
+  grub_uint64_t nstripes, grub_uint64_t csize)
+{
+  grub_uint64_t i;
+  int first;
+
+  for(i = 0; buffers[i].data_is_valid && i < nstripes; i++);
+
+  if (i == nstripes)
+{
+  grub_dprintf ("btrfs", "called rebuild_raid5(), but all disks are OK\n");
+  return;
+}
+
+  grub_dprintf ("btrfs", "rebuilding RAID 5 stripe #%" PRIuGRUB_UINT64_T "\n", 
i);
+
+  for (i = 0, first = 1; i < nstripes; i++)
+{
+  if (!buffers[i].data_is_valid)
+   continue;
+
+  if (first) {
+   grub_memcpy(dest, buffers[i].buf, csize);
+   first = 0;
+  } else
+   grub_crypto_xor (dest, dest, buffers[i].buf, csize);
+
+}
+}
+
+static grub_err_t
+raid56_read_retry (struct grub_btrfs_data *data,
+  struct grub_btrfs_chunk_item *chunk,
+  grub_uint64_t stripe_offset,
+  grub_uint64_t csize, void *buf)
+{
+  struct raid56_buffer *buffers;
+  grub_uint64_t nstripes = grub_le_to_cpu16 (chunk->nstripes);
+  grub_uint64_t chunk_type = grub_le_to_cpu64 (chunk->type);
+  grub_err_t ret = GRUB_ERR_OUT_OF_MEMORY;
+  grub_uint64_t i, failed_devices;
+
+  buffers = grub_zalloc (sizeof(*buffers) * nstripes);
+  if (!buffers)
+goto cleanup;
+
+  for (i = 0; i < nstripes; i++)
+{
+  buffers[i].buf = grub_zalloc (csize);
+  if (!buffers[i].buf)
+   goto cleanup;
+}
+
+  for (failed_devices = 0, i = 0; i < nstripes; i++)
+{
+  struct grub_btrfs_chunk_stripe *stripe;
+  grub_disk_addr_t paddr;
+  grub_device_t dev;
+  grub_err_t err;
+
+  /* after the struct grub_btrfs_chunk_item, there is an array of
+ struct grub_btrfs_chunk_stripe */
+  stripe = (struct grub_btrfs_chunk_stripe *) (chunk + 1) + i;
+
+  paddr = grub_le_to_cpu64 (stripe->offset) + stripe_offset;
+  grub_dprintf ("btrfs", "reading paddr %" PRIxGRUB_UINT64_T
+" from stripe ID %" PRIxGRUB_UINT64_T "\n", paddr,
+stripe->device_id);
+
+  dev = find_device (data, stripe->device_id);
+  if (!dev)
+   {
+ buffers[i].data_is_valid = 0;
+ grub_dprintf ("btrfs", "stripe %" PRIuGRUB_UINT64_T " FAILED (dev ID 
%"
+   PRIxGRUB_UINT64_T ")\n", i, stripe->device_id);
+ failed_devices++;
+ continue;
+   }
+
+  err = grub_disk_read (dev->disk, paddr >> GRUB_DISK_SECTOR_BITS,
+   paddr & (GRUB_DISK_SECTOR_SIZE - 1),
+   csize, buffers[i].buf);
+  if (err == GRUB_ERR_NONE)
+   {
+ buffers[i].data_is_valid = 1;
+ grub_dprintf ("btrfs", "stripe %" PRIuGRUB_UINT64_T " Ok (dev ID %"
+   PRIxGRUB_UINT64_T ")\n", i, stripe->device_id);
+   }
+  else
+   {
+ buffers[i].data_is_valid = 0;
+ grub_dprintf ("btrfs", "stripe %" PRIuGRUB_UINT64_T
+   " FAILED (dev ID %" PRIxGRUB_UINT64_T ")\n", i,
+   stripe->device_id);
+ failed_devices++;
+   }
+}
+
+  if (failed_devices > 1 && (chunk_type & GRUB_BTRFS_CHUNK_TYPE_RAID5))
+{
+  grub_dprintf ("btrfs",
+   "not enough disks for RAID 5: total %" PRIuGRUB_UINT64_T
+   ", missing %" PRIuGRUB_UINT64_T "\n",
+   nstripes, failed_devices);
+  ret = GRUB_ERR_READ_ERROR;
+  goto cleanup;
+}
+  else
+grub_dprintf ("btrfs",
+ "enough disks for RAID 5 rebuilding: total %"
+ PRIuGRUB_UINT64_T ", missing %" PRIuGRUB_UINT64_T "\n",
+ nstripes, failed_devices);
+
+  /* if these are enough, try to rebuild the data */
+  if (chunk_type & GRUB_BTRFS_CHUNK_TYPE_RAID5)
+rebuild_raid5 (buf, buffers, nstripes, csize);
+  else
+grub_dprintf ("btrfs", "called rebuild_raid6(), NOT IMPLEMENTED\n");
+
+  ret = GRUB_ERR_NONE;
+ cleanup:
+  if (buffers)
+for (i = 0; i < nstripes; i++)
+   grub_free(buffers[i].buf);
+  grub_free(buffers);
+
+  return ret;
+}
+
 static grub_err_t
 grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
 void *buf, grub_size_t size, int 

[PATCH 1/9] btrfs: Add support for reading a filesystem with a RAID 5 or RAID 6 profile.

2018-10-11 Thread Goffredo Baroncelli
From: Goffredo Baroncelli 

Signed-off-by: Goffredo Baroncelli 
Signed-off-by: Daniel Kiper 
---
 grub-core/fs/btrfs.c | 73 
 1 file changed, 73 insertions(+)

diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
index be195448d..933a57d3b 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -119,6 +119,8 @@ struct grub_btrfs_chunk_item
 #define GRUB_BTRFS_CHUNK_TYPE_RAID1 0x10
 #define GRUB_BTRFS_CHUNK_TYPE_DUPLICATED0x20
 #define GRUB_BTRFS_CHUNK_TYPE_RAID100x40
+#define GRUB_BTRFS_CHUNK_TYPE_RAID5 0x80
+#define GRUB_BTRFS_CHUNK_TYPE_RAID6 0x100
   grub_uint8_t dummy2[0xc];
   grub_uint16_t nstripes;
   grub_uint16_t nsubstripes;
@@ -764,6 +766,77 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, 
grub_disk_addr_t addr,
  stripe_offset = low + chunk_stripe_length
* high;
  csize = chunk_stripe_length - low;
+ break;
+   }
+ case GRUB_BTRFS_CHUNK_TYPE_RAID5:
+ case GRUB_BTRFS_CHUNK_TYPE_RAID6:
+   {
+ grub_uint64_t nparities, stripe_nr, high, low;
+
+ redundancy = 1;   /* no redundancy for now */
+
+ if (grub_le_to_cpu64 (chunk->type) & GRUB_BTRFS_CHUNK_TYPE_RAID5)
+   {
+ grub_dprintf ("btrfs", "RAID5\n");
+ nparities = 1;
+   }
+ else
+   {
+ grub_dprintf ("btrfs", "RAID6\n");
+ nparities = 2;
+   }
+
+ /*
+  * RAID 6 layout consists of several stripes spread over
+  * the disks, e.g.:
+  *
+  *   Disk_0  Disk_1  Disk_2  Disk_3
+  * A0  B0  P0  Q0
+  * Q1  A1  B1  P1
+  * P2  Q2  A2  B2
+  *
+  * Note: placement of the parities depend on row number.
+  *
+  * Pay attention that the btrfs terminology may differ from
+  * terminology used in other RAID implementations, e.g. LVM,
+  * dm or md. The main difference is that btrfs calls contiguous
+  * block of data on a given disk, e.g. A0, stripe instead of 
chunk.
+  *
+  * The variables listed below have following meaning:
+  *   - stripe_nr is the stripe number excluding the parities
+  * (A0 = 0, B0 = 1, A1 = 2, B1 = 3, etc.),
+  *   - high is the row number (0 for A0...Q0, 1 for Q1...P1, 
etc.),
+  *   - stripen is the disk number in a row (0 for A0, Q1, P2,
+  * 1 for B0, A1, Q2, etc.),
+  *   - off is the logical address to read,
+  *   - chunk_stripe_length is the size of a stripe (typically 64 
KiB),
+  *   - nstripes is the number of disks in a row,
+  *   - low is the offset of the data inside a stripe,
+  *   - stripe_offset is the data offset in an array,
+  *   - csize is the "potential" data to read; it will be reduced
+  * to size if the latter is smaller,
+  *   - nparities is the number of parities (1 for RAID 5, 2 for
+  * RAID 6); used only in RAID 5/6 code.
+  */
+ stripe_nr = grub_divmod64 (off, chunk_stripe_length, );
+
+ /*
+  * stripen is computed without the parities
+  * (0 for A0, A1, A2, 1 for B0, B1, B2, etc.).
+  */
+ high = grub_divmod64 (stripe_nr, nstripes - nparities, );
+
+ /*
+  * The stripes are spread over the disks. Every each row their
+  * positions are shifted by 1 place. So, the real disks number
+  * change. Hence, we have to take current row number modulo
+  * nstripes into account (0 for A0, 1 for A1, 2 for A2, etc.).
+  */
+ grub_divmod64 (high + stripen, nstripes, );
+
+ stripe_offset = low + chunk_stripe_length * high;
+ csize = chunk_stripe_length - low;
+
  break;
}
  default:
-- 
2.19.1


___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


[PATCH 4/9] btrfs: Avoid a rescan for a device which was already not found.

2018-10-11 Thread Goffredo Baroncelli
From: Goffredo Baroncelli 

Currently read from missing device triggers rescan. However, it is never
recorded that the device is missing. So, each read of a missing device
triggers rescan again and again. This behavior causes a lot of unneeded
rescans leading to huge slowdowns.

This patch fixes above mentioned issue. Information about missing devices
is stored in the data->devices_attached[] array as NULL value in dev
member. Rescan is triggered only if no information is found for a given
device. This means that only first time read triggers rescan.

The patch drops premature return. This way data->devices_attached[] is
filled even when a given device is missing.

Signed-off-by: Goffredo Baroncelli 
---
 grub-core/fs/btrfs.c | 17 +
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
index 2a87eb103..b2be80c33 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -588,7 +588,7 @@ find_device_iter (const char *name, void *data)
 }
 
 static grub_device_t
-find_device (struct grub_btrfs_data *data, grub_uint64_t id, int do_rescan)
+find_device (struct grub_btrfs_data *data, grub_uint64_t id)
 {
   struct find_device_ctx ctx = {
 .data = data,
@@ -600,10 +600,9 @@ find_device (struct grub_btrfs_data *data, grub_uint64_t 
id, int do_rescan)
   for (i = 0; i < data->n_devices_attached; i++)
 if (id == data->devices_attached[i].id)
   return data->devices_attached[i].dev;
-  if (do_rescan)
-grub_device_iterate (find_device_iter, );
-  if (!ctx.dev_found)
-return NULL;
+
+  grub_device_iterate (find_device_iter, );
+
   data->n_devices_attached++;
   if (data->n_devices_attached > data->n_devices_allocated)
 {
@@ -615,7 +614,8 @@ find_device (struct grub_btrfs_data *data, grub_uint64_t 
id, int do_rescan)
* sizeof (data->devices_attached[0]));
   if (!data->devices_attached)
{
- grub_device_close (ctx.dev_found);
+ if (ctx.dev_found)
+   grub_device_close (ctx.dev_found);
  data->devices_attached = tmp;
  return NULL;
}
@@ -897,7 +897,7 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, 
grub_disk_addr_t addr,
  " for laddr 0x%" PRIxGRUB_UINT64_T "\n", paddr,
  addr);
 
-   dev = find_device (data, stripe->device_id, j);
+   dev = find_device (data, stripe->device_id);
if (!dev)
  {
grub_dprintf ("btrfs",
@@ -974,7 +974,8 @@ grub_btrfs_unmount (struct grub_btrfs_data *data)
   unsigned i;
   /* The device 0 is closed one layer upper.  */
   for (i = 1; i < data->n_devices_attached; i++)
-grub_device_close (data->devices_attached[i].dev);
+if (data->devices_attached[i].dev)
+grub_device_close (data->devices_attached[i].dev);
   grub_free (data->devices_attached);
   grub_free (data->extent);
   grub_free (data);
-- 
2.19.1


___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


[PATCH 3/9] btrfs: Move the error logging from find_device() to its caller.

2018-10-11 Thread Goffredo Baroncelli
From: Goffredo Baroncelli 

The caller knows better if this error is fatal or not, i.e. another disk is
available or not.

This is a preparatory patch.

Signed-off-by: Goffredo Baroncelli 
Reviewed-by: Daniel Kiper 
---
 grub-core/fs/btrfs.c | 10 --
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
index c9f0c4193..2a87eb103 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -603,12 +603,7 @@ find_device (struct grub_btrfs_data *data, grub_uint64_t 
id, int do_rescan)
   if (do_rescan)
 grub_device_iterate (find_device_iter, );
   if (!ctx.dev_found)
-{
-  grub_error (GRUB_ERR_BAD_FS,
- N_("couldn't find a necessary member device "
-"of multi-device filesystem"));
-  return NULL;
-}
+return NULL;
   data->n_devices_attached++;
   if (data->n_devices_attached > data->n_devices_allocated)
 {
@@ -905,6 +900,9 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, 
grub_disk_addr_t addr,
dev = find_device (data, stripe->device_id, j);
if (!dev)
  {
+   grub_dprintf ("btrfs",
+ "couldn't find a necessary member device "
+ "of multi-device filesystem\n");
err = grub_errno;
grub_errno = GRUB_ERR_NONE;
continue;
-- 
2.19.1


___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


[PATCH 2/9] btrfs: Add helper to check the btrfs header.

2018-10-11 Thread Goffredo Baroncelli
From: Goffredo Baroncelli 

This helper is used in a few places to help the debugging. As
conservative approach the error is only logged.
This does not impact the error handling.

Signed-off-by: Goffredo Baroncelli 
Reviewed-by: Daniel Kiper 
---
 grub-core/fs/btrfs.c | 24 +++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
index 933a57d3b..c9f0c4193 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -77,7 +77,8 @@ struct btrfs_header
 {
   grub_btrfs_checksum_t checksum;
   grub_btrfs_uuid_t uuid;
-  grub_uint8_t dummy[0x30];
+  grub_uint64_t bytenr;
+  grub_uint8_t dummy[0x28];
   grub_uint32_t nitems;
   grub_uint8_t level;
 } GRUB_PACKED;
@@ -286,6 +287,25 @@ free_iterator (struct grub_btrfs_leaf_descriptor *desc)
   grub_free (desc->data);
 }
 
+static grub_err_t
+check_btrfs_header (struct grub_btrfs_data *data, struct btrfs_header *header,
+grub_disk_addr_t addr)
+{
+  if (grub_le_to_cpu64 (header->bytenr) != addr)
+{
+  grub_dprintf ("btrfs", "btrfs_header.bytenr is not equal node addr\n");
+  return grub_error (GRUB_ERR_BAD_FS,
+"header bytenr is not equal node addr");
+}
+  if (grub_memcmp (data->sblock.uuid, header->uuid, sizeof(grub_btrfs_uuid_t)))
+{
+  grub_dprintf ("btrfs", "btrfs_header.uuid doesn't match sblock uuid\n");
+  return grub_error (GRUB_ERR_BAD_FS,
+"header uuid doesn't match sblock uuid");
+}
+  return GRUB_ERR_NONE;
+}
+
 static grub_err_t
 save_ref (struct grub_btrfs_leaf_descriptor *desc,
  grub_disk_addr_t addr, unsigned i, unsigned m, int l)
@@ -341,6 +361,7 @@ next (struct grub_btrfs_data *data,
 
   err = grub_btrfs_read_logical (data, grub_le_to_cpu64 (node.addr),
 , sizeof (head), 0);
+  check_btrfs_header (data, , grub_le_to_cpu64 (node.addr));
   if (err)
return -err;
 
@@ -402,6 +423,7 @@ lower_bound (struct grub_btrfs_data *data,
   /* FIXME: preread few nodes into buffer. */
   err = grub_btrfs_read_logical (data, addr, , sizeof (head),
 recursion_depth + 1);
+  check_btrfs_header (data, , addr);
   if (err)
return err;
   addr += sizeof (head);
-- 
2.19.1


___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


Re: [PATCH v3 0/2] btrfs: Add zstd support to grub btrfs

2018-10-11 Thread Daniel Kiper
Hi Nick,

CC-ing Goffredo.

On Tue, Oct 09, 2018 at 04:21:35PM -0700, Nick Terrell wrote:
> Hi all,
>
> This patch set imports the upstream zstd library, adds zstd support to the
> btrfs module, and adds a test case. I've also tested the patch set by storing
> my boot partition in btrfs with and without zstd compression and rebooting.
>
> The fist patch imports the files needed to support zstd decompression from
> zstd-1.3.6 as-is. It is a very large patch. In case it doesn't make it,
> I've included the commit hash and the script I used to download the files.
>
> Upstream zstd commit hash: 4fa456d7f12f8b27bd3b2f5dfd4f46898cb31c24
> Upstream zstd commit name: Merge pull request #1354 from facebook/dev

In general I am happy with the patches. If everything is done what
I have asked for then I will get them. However, there is one problem.
Another big btrfs (RAID) patchset is lurking around for months. It is
almost ready. Goffredo, I am looking at you... So, I would like to take
RAID patchset first. If it is in the tree then I will ask you to rebase
zstd patchset on top of RAID patchset and I will take it. Nick, are you
OK with that?

Daniel

___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


Re: [PATCH v3 2/2] btrfs: Add zstd support to grub btrfs

2018-10-11 Thread Nick Terrell



> On Oct 11, 2018, at 10:55 AM, Daniel Kiper  wrote:
> 
> On Tue, Oct 09, 2018 at 04:21:37PM -0700, Nick Terrell wrote:
>> Adds zstd support to the btrfs module.
>> 
>> Tested on Ubuntu-18.04 with a btrfs /boot partition with and without zstd
>> compression. A test case was also added to the test suite that fails before
>> the patch, and passes after.
>> 
>> Signed-off-by: Nick Terrell 
>> ---
>> v1 -> v2:
>> - Fix comments from Daniel Kiper.
>> 
>> v2 -> v3:
>> - Use grub_error() to set grub_errno in grub_btrfs_zstd_decompress().
>> - Fix style and formatting comments.
>> 
>> Makefile.util.def|  10 +++-
>> grub-core/Makefile.core.def  |  10 +++-
>> grub-core/fs/btrfs.c | 112 ++-
>> tests/btrfs_test.in  |   1 +
>> tests/util/grub-fs-tester.in |   2 +-
>> 5 files changed, 131 insertions(+), 4 deletions(-)
>> 
>> diff --git a/Makefile.util.def b/Makefile.util.def
>> index f9caccb97..27c5e9903 100644
>> --- a/Makefile.util.def
>> +++ b/Makefile.util.def
>> @@ -54,7 +54,7 @@ library = {
>> library = {
>>   name = libgrubmods.a;
>>   cflags = '-fno-builtin -Wno-undef';
>> -  cppflags = '-I$(top_srcdir)/grub-core/lib/minilzo 
>> -I$(srcdir)/grub-core/lib/xzembed -DMINILZO_HAVE_CONFIG_H';
>> +  cppflags = '-I$(srcdir)/grub-core/lib/minilzo 
>> -I$(srcdir)/grub-core/lib/xzembed -I$(srcdir)/grub-core/lib/zstd 
>> -DMINILZO_HAVE_CONFIG_H';
>> 
>>   common_nodist = grub_script.tab.c;
>>   common_nodist = grub_script.yy.c;
>> @@ -164,6 +164,14 @@ library = {
>>   common = grub-core/lib/xzembed/xz_dec_bcj.c;
>>   common = grub-core/lib/xzembed/xz_dec_lzma2.c;
>>   common = grub-core/lib/xzembed/xz_dec_stream.c;
>> +  common = grub-core/lib/zstd/debug.c;
>> +  common = grub-core/lib/zstd/entropy_common.c;
>> +  common = grub-core/lib/zstd/error_private.c;
>> +  common = grub-core/lib/zstd/fse_decompress.c;
>> +  common = grub-core/lib/zstd/huf_decompress.c;
>> +  common = grub-core/lib/zstd/xxhash.c;
>> +  common = grub-core/lib/zstd/zstd_common.c;
>> +  common = grub-core/lib/zstd/zstd_decompress.c;
>> };
>> 
>> program = {
>> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
>> index 2c1d62cee..f818f58bc 100644
>> --- a/grub-core/Makefile.core.def
>> +++ b/grub-core/Makefile.core.def
>> @@ -1265,8 +1265,16 @@ module = {
>>   name = btrfs;
>>   common = fs/btrfs.c;
>>   common = lib/crc.c;
>> +  common = lib/zstd/debug.c;
>> +  common = lib/zstd/entropy_common.c;
>> +  common = lib/zstd/error_private.c;
>> +  common = lib/zstd/fse_decompress.c;
>> +  common = lib/zstd/huf_decompress.c;
>> +  common = lib/zstd/xxhash.c;
>> +  common = lib/zstd/zstd_common.c;
>> +  common = lib/zstd/zstd_decompress.c;
>>   cflags = '$(CFLAGS_POSIX) -Wno-undef';
>> -  cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/minilzo 
>> -DMINILZO_HAVE_CONFIG_H';
>> +  cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/minilzo 
>> -I$(srcdir)/lib/zstd -DMINILZO_HAVE_CONFIG_H';
>> };
> 
> Please do not embed zstd lib into btrfs module here.
> I would like to see zstd lib as separate module if possible.

Sure, I'm not exactly sure how the build system works. I haven't been able to
find any documentation, if there is some can you point me to it? I think the 
zstd
module should look like:

module = {
  name = zstd;
  common = lib/zstd/debug.c;
  common = lib/zstd/entropy_common.c;
  common = lib/zstd/error_private.c;
  common = lib/zstd/fse_decompress.c;
  common = lib/zstd/huf_decompress.c;
  common = lib/zstd/xxhash.c;
  common = lib/zstd/zstd_common.c;
  common = lib/zstd/zstd_decompress.c;
  cflags = '$(CFLAGS_POSIX) -Wno-undef';
  cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/zstd';
};

Then how do I add a dependency on it in btrfs?


>> +static grub_ssize_t
>> +grub_btrfs_zstd_decompress (char *ibuf, grub_size_t isize, grub_off_t off,
>> +char *obuf, grub_size_t osize)
>> +{
>> +void *allocated = NULL;
>> +char *otmpbuf = obuf;
>> +grub_size_t otmpsize = osize;
>> +ZSTD_DCtx *dctx = NULL;
>> +grub_size_t zstd_ret;
>> +grub_ssize_t ret = -1;
>> +
>> +/*
>> + * Zstd will fail if it can't fit the entire output in the destination
>> + * buffer, so if osize isn't large enough, allocate a temporary buffer.
>> + */
>> +if (otmpsize < ZSTD_BTRFS_MAX_INPUT) {
>> +allocated = grub_malloc (ZSTD_BTRFS_MAX_INPUT);
>> +if (!allocated) {
> 
> Hmmm... Should not we say something here? Like grub_error() call below?
> It seems to me that failing silently is bad idea here.

grub_malloc() already calls grub_error with the message "Out of memory".

Thanks,
Nick


___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


Re: [PATCH v3 2/2] btrfs: Add zstd support to grub btrfs

2018-10-11 Thread Daniel Kiper
On Tue, Oct 09, 2018 at 04:21:37PM -0700, Nick Terrell wrote:
> Adds zstd support to the btrfs module.
>
> Tested on Ubuntu-18.04 with a btrfs /boot partition with and without zstd
> compression. A test case was also added to the test suite that fails before
> the patch, and passes after.
>
> Signed-off-by: Nick Terrell 
> ---
> v1 -> v2:
> - Fix comments from Daniel Kiper.
>
> v2 -> v3:
> - Use grub_error() to set grub_errno in grub_btrfs_zstd_decompress().
> - Fix style and formatting comments.
>
>  Makefile.util.def|  10 +++-
>  grub-core/Makefile.core.def  |  10 +++-
>  grub-core/fs/btrfs.c | 112 ++-
>  tests/btrfs_test.in  |   1 +
>  tests/util/grub-fs-tester.in |   2 +-
>  5 files changed, 131 insertions(+), 4 deletions(-)
>
> diff --git a/Makefile.util.def b/Makefile.util.def
> index f9caccb97..27c5e9903 100644
> --- a/Makefile.util.def
> +++ b/Makefile.util.def
> @@ -54,7 +54,7 @@ library = {
>  library = {
>name = libgrubmods.a;
>cflags = '-fno-builtin -Wno-undef';
> -  cppflags = '-I$(top_srcdir)/grub-core/lib/minilzo 
> -I$(srcdir)/grub-core/lib/xzembed -DMINILZO_HAVE_CONFIG_H';
> +  cppflags = '-I$(srcdir)/grub-core/lib/minilzo 
> -I$(srcdir)/grub-core/lib/xzembed -I$(srcdir)/grub-core/lib/zstd 
> -DMINILZO_HAVE_CONFIG_H';
>
>common_nodist = grub_script.tab.c;
>common_nodist = grub_script.yy.c;
> @@ -164,6 +164,14 @@ library = {
>common = grub-core/lib/xzembed/xz_dec_bcj.c;
>common = grub-core/lib/xzembed/xz_dec_lzma2.c;
>common = grub-core/lib/xzembed/xz_dec_stream.c;
> +  common = grub-core/lib/zstd/debug.c;
> +  common = grub-core/lib/zstd/entropy_common.c;
> +  common = grub-core/lib/zstd/error_private.c;
> +  common = grub-core/lib/zstd/fse_decompress.c;
> +  common = grub-core/lib/zstd/huf_decompress.c;
> +  common = grub-core/lib/zstd/xxhash.c;
> +  common = grub-core/lib/zstd/zstd_common.c;
> +  common = grub-core/lib/zstd/zstd_decompress.c;
>  };
>
>  program = {
> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
> index 2c1d62cee..f818f58bc 100644
> --- a/grub-core/Makefile.core.def
> +++ b/grub-core/Makefile.core.def
> @@ -1265,8 +1265,16 @@ module = {
>name = btrfs;
>common = fs/btrfs.c;
>common = lib/crc.c;
> +  common = lib/zstd/debug.c;
> +  common = lib/zstd/entropy_common.c;
> +  common = lib/zstd/error_private.c;
> +  common = lib/zstd/fse_decompress.c;
> +  common = lib/zstd/huf_decompress.c;
> +  common = lib/zstd/xxhash.c;
> +  common = lib/zstd/zstd_common.c;
> +  common = lib/zstd/zstd_decompress.c;
>cflags = '$(CFLAGS_POSIX) -Wno-undef';
> -  cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/minilzo 
> -DMINILZO_HAVE_CONFIG_H';
> +  cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/minilzo 
> -I$(srcdir)/lib/zstd -DMINILZO_HAVE_CONFIG_H';
>  };

Please do not embed zstd lib into btrfs module here.
I would like to see zstd lib as separate module if possible.

>  module = {
> diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
> index 4849c1ceb..c44fe8029 100644
> --- a/grub-core/fs/btrfs.c
> +++ b/grub-core/fs/btrfs.c
> @@ -17,6 +17,8 @@
>   *  along with GRUB.  If not, see .
>   */
>
> +#define ZSTD_STATIC_LINKING_ONLY
> +
>  #include 
>  #include 
>  #include 
> @@ -27,6 +29,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>
> @@ -45,6 +48,9 @@ GRUB_MOD_LICENSE ("GPLv3+");
>  #define GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE (GRUB_BTRFS_LZO_BLOCK_SIZE + \
>(GRUB_BTRFS_LZO_BLOCK_SIZE / 16) + 64 + 3)
>
> +#define ZSTD_BTRFS_MAX_WINDOWLOG 17
> +#define ZSTD_BTRFS_MAX_INPUT (1 << ZSTD_BTRFS_MAX_WINDOWLOG)
> +
>  typedef grub_uint8_t grub_btrfs_checksum_t[0x20];
>  typedef grub_uint16_t grub_btrfs_uuid_t[8];
>
> @@ -212,6 +218,7 @@ struct grub_btrfs_extent_data
>  #define GRUB_BTRFS_COMPRESSION_NONE 0
>  #define GRUB_BTRFS_COMPRESSION_ZLIB 1
>  #define GRUB_BTRFS_COMPRESSION_LZO  2
> +#define GRUB_BTRFS_COMPRESSION_ZSTD 3
>
>  #define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100
>
> @@ -912,6 +919,95 @@ grub_btrfs_read_inode (struct grub_btrfs_data *data,
>return grub_btrfs_read_logical (data, elemaddr, inode, sizeof (*inode), 0);
>  }
>
> +static void* grub_zstd_malloc (void* state, size_t size)
> +{
> + (void)state;

Please drop this and use "__attribute__ ((unused))" in function prototype.

> + return grub_malloc (size);
> +}
> +
> +static void grub_zstd_free (void* state, void* address)
> +{
> + (void)state;

Ditto.

> + return grub_free (address);
> +}
> +
> +static ZSTD_customMem grub_zstd_allocator (void)
> +{
> + ZSTD_customMem allocator;
> +
> + allocator.customAlloc = _zstd_malloc;
> + allocator.customFree = _zstd_free;
> + allocator.opaque = NULL;
> +
> + return allocator;
> +}
> +
> +static grub_ssize_t
> +grub_btrfs_zstd_decompress (char *ibuf, grub_size_t isize, grub_off_t off,
> +   

Re: [PATCH v3 1/2] Import upstream zstd-1.3.6

2018-10-11 Thread Daniel Kiper
On Tue, Oct 09, 2018 at 04:21:36PM -0700, Nick Terrell wrote:
> Import zstd-1.3.6 from upstream [1]. Only the files need for decompression
> are imported.
>
> I used the latest zstd release, which includes patches [2] to build cleanly
> in GRUB.
>
> Upstream zstd commit hash: 4fa456d7f12f8b27bd3b2f5dfd4f46898cb31c24
> Upstream zstd commit name: Merge pull request #1354 from facebook/dev
>
> I've included the script used to import zstd-1.3.6 below.
>
> [1] https://github.com/facebook/zstd/releases/tag/v1.3.6
> [2] https://github.com/facebook/zstd/pull/1344
>
> ---

I think that you should replace the dashes with something different
here. Otherwise "git am" may tear off the rest of commit message
starting from here.

> #!/bin/sh -e
>
> curl -L -O 
> https://github.com/facebook/zstd/releases/download/v1.3.6/zstd-1.3.6.tar.gz
> curl -L -O 
> https://github.com/facebook/zstd/releases/download/v1.3.6/zstd-1.3.6.tar.gz.sha256
> sha256sum --check zstd-1.3.6.tar.gz.sha256
> tar xzf zstd-1.3.6.tar.gz
>
> SRC_LIB="zstd-1.3.6/lib"
> DST_LIB="grub-core/lib/zstd"
> rm -rf $DST_LIB
> mkdir -p $DST_LIB
> cp $SRC_LIB/zstd.h $DST_LIB/
> cp $SRC_LIB/common/*.[hc] $DST_LIB/
> cp $SRC_LIB/decompress/*.[hc] $DST_LIB/
> rm $DST_LIB/{pool.[hc],threading.[hc]}
> rm -rf zstd-1.3.6*
> echo SUCCESS!
> ---

Ditto.

> Signed-off-by: Nick Terrell 

If you fix things above you can add
  Reviewed-by: Daniel Kiper 

Daniel

___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


Re: [PATCH v3 0/2] btrfs: Add zstd support to grub btrfs

2018-10-11 Thread Daniel Kiper
On Wed, Oct 10, 2018 at 08:28:27PM +, Nick Terrell wrote:
> > On Oct 10, 2018, at 12:34 AM, Paul Menzel  wrote:
> >
> > Sorry for being ignorant, but you explain, why the library needs to be 
> > imported and it is not enough to use that library as an external dependency?
> >
> > Importing the library means, it has to be maintained in the GRUB 
> > repository, which will result in some maintenance burden.
>
> I've imported zstd because thats the way the rest of the decompressors are 
> imported.
>
> We could potentially use libzstd as an external dependency, since its only 
> dependency is libc
> and GRUB provides the definitions of the libc functions that zstd needs to 
> decompress
> (memcpy, and memmove). Theres some other stuff in the library that requires 
> libc functionality
> that GRUB doesn't provide, but that isn't used during decompression. We strip 
> those files
> out in the import.
>
> Let me know if you want me to switch to an external dependency.

I do not think it is possible. Or it can be at least difficult. Even if
it is possible it would require a major rework of GRUB build machine.
So, even if current solution is not perfect I would like to stick to it.
And zstd library integration is not very difficult. So, I do not think
it will add a lot of burden in the future.

Daniel

___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


Re: [PATCH V8] Add support for BTRFS raid5/6 to GRUB

2018-10-11 Thread Daniel Kiper
On Thu, Sep 27, 2018 at 08:34:55PM +0200, Goffredo Baroncelli wrote:
>
> i All,
>
> the aim of this patches set is to provide support for a BTRFS raid5/6
> filesystem in GRUB.

I have sent you updated comment and commit message. Please double check it.
If everything is OK please repost whole series.

Daniel

___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


Re: [PATCH 4/9] btrfs: Avoid a rescan for a device which was already not found.

2018-10-11 Thread Daniel Kiper
On Tue, Oct 09, 2018 at 07:56:43PM +0200, Daniel Kiper wrote:
> On Thu, Sep 27, 2018 at 08:34:59PM +0200, Goffredo Baroncelli wrote:
> > From: Goffredo Baroncelli 
> >
> > Change the behavior of find_device(): before the patch, a read of a missed
> > device may trigger a rescan. However, it is never recorded that a device
> > is missed, so each single read of a missed device may triggers a rescan.
> > It is the caller who decides if a rescan is performed in case of a missed
> > device. And it does quite often, without considering if in the past a
> > devices was already found as "missed"
> > This behavior causes a lot of unneeded rescan, causing a huge slowdown in
> > case of a missed device.
> >
> > After the patch, the "missed device" information is stored in the
> > data->devices_attached[] array (as a NULL value in the field dev). A rescan
> > is triggered only if no information at all is found. This means that only
> > the first time a read of a missed device triggers a rescan.
> >
> > The change in the code is done removing "return NULL" when the disk is not
> > found. So it is always executed the code which stores in the
> > data->devices_attached[] array the value returned by grub_device_iterate():
> > NULL if the device is missed, or a valid data otherwise.
> >
> > Signed-off-by: Goffredo Baroncelli 
>
> Commit message still begs for improvement. I will send you a proposal shortly.

Below you can find updated commit message. Please verify it is OK.

Currently read from missing device triggers rescan. However, it is never
recorded that the device is missing. So, each read of a missing device
triggers rescan again and again. This behavior causes a lot of unneeded
rescans leading to huge slowdowns.

This patch fixes above mentioned issue. Information about missing devices
is stored in the data->devices_attached[] array as NULL value in dev
member. Rescan is triggered only if no information is found for a given
device. This means that only first time read triggers rescan.

The patch drops premature return. This way data->devices_attached[] is
filled even when a given device is missing.

Daniel

___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


Re: [PATCH 1/9] btrfs: Add support for reading a filesystem with a RAID 5 or RAID 6 profile.

2018-10-11 Thread Daniel Kiper
On Tue, Oct 09, 2018 at 07:51:01PM +0200, Daniel Kiper wrote:
> On Thu, Sep 27, 2018 at 08:34:56PM +0200, Goffredo Baroncelli wrote:
> > From: Goffredo Baroncelli 
> >
> > Signed-off-by: Goffredo Baroncelli 
> 
> Code LGTM. Though comment begs improvement. I will send you updated
> comment for approval shortly.

Below you can find updated patch. Please check I have not messed up something.

Daniel

>From ecefb12a10d39bdd09e1d2b8fbbcbdb1b35274f8 Mon Sep 17 00:00:00 2001
From: Goffredo Baroncelli 
Date: Thu, 27 Sep 2018 20:34:56 +0200
Subject: [PATCH 1/1] btrfs: Add support for reading a filesystem with a RAID
 5 or RAID 6 profile.

Signed-off-by: Goffredo Baroncelli 
Signed-off-by: Daniel Kiper 
---
 grub-core/fs/btrfs.c |   73 ++
 1 file changed, 73 insertions(+)

diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
index be19544..933a57d 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -119,6 +119,8 @@ struct grub_btrfs_chunk_item
 #define GRUB_BTRFS_CHUNK_TYPE_RAID1 0x10
 #define GRUB_BTRFS_CHUNK_TYPE_DUPLICATED0x20
 #define GRUB_BTRFS_CHUNK_TYPE_RAID100x40
+#define GRUB_BTRFS_CHUNK_TYPE_RAID5 0x80
+#define GRUB_BTRFS_CHUNK_TYPE_RAID6 0x100
   grub_uint8_t dummy2[0xc];
   grub_uint16_t nstripes;
   grub_uint16_t nsubstripes;
@@ -766,6 +768,77 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, 
grub_disk_addr_t addr,
  csize = chunk_stripe_length - low;
  break;
}
+ case GRUB_BTRFS_CHUNK_TYPE_RAID5:
+ case GRUB_BTRFS_CHUNK_TYPE_RAID6:
+   {
+ grub_uint64_t nparities, stripe_nr, high, low;
+
+ redundancy = 1;   /* no redundancy for now */
+
+ if (grub_le_to_cpu64 (chunk->type) & GRUB_BTRFS_CHUNK_TYPE_RAID5)
+   {
+ grub_dprintf ("btrfs", "RAID5\n");
+ nparities = 1;
+   }
+ else
+   {
+ grub_dprintf ("btrfs", "RAID6\n");
+ nparities = 2;
+   }
+
+ /*
+  * RAID 6 layout consists of several stripes spread over
+  * the disks, e.g.:
+  *
+  *   Disk_0  Disk_1  Disk_2  Disk_3
+  * A0  B0  P0  Q0
+  * Q1  A1  B1  P1
+  * P2  Q2  A2  B2
+  *
+  * Note: placement of the parities depend on row number.
+  *
+  * Pay attention that the btrfs terminology may differ from
+  * terminology used in other RAID implementations, e.g. LVM,
+  * dm or md. The main difference is that btrfs calls contiguous
+  * block of data on a given disk, e.g. A0, stripe instead of 
chunk.
+  *
+  * The variables listed below have following meaning:
+  *   - stripe_nr is the stripe number excluding the parities
+  * (A0 = 0, B0 = 1, A1 = 2, B1 = 3, etc.),
+  *   - high is the row number (0 for A0...Q0, 1 for Q1...P1, 
etc.),
+  *   - stripen is the disk number in a row (0 for A0, Q1, P2,
+  * 1 for B0, A1, Q2, etc.),
+  *   - off is the logical address to read,
+  *   - chunk_stripe_length is the size of a stripe (typically 64 
KiB),
+  *   - nstripes is the number of disks in a row,
+  *   - low is the offset of the data inside a stripe,
+  *   - stripe_offset is the data offset in an array,
+  *   - csize is the "potential" data to read; it will be reduced
+  * to size if the latter is smaller,
+  *   - nparities is the number of parities (1 for RAID 5, 2 for
+  * RAID 6); used only in RAID 5/6 code.
+  */
+ stripe_nr = grub_divmod64 (off, chunk_stripe_length, );
+
+ /*
+  * stripen is computed without the parities
+  * (0 for A0, A1, A2, 1 for B0, B1, B2, etc.).
+  */
+ high = grub_divmod64 (stripe_nr, nstripes - nparities, );
+
+ /*
+  * The stripes are spread over the disks. Every each row their
+  * positions are shifted by 1 place. So, the real disks number
+  * change. Hence, we have to take current row number modulo
+  * nstripes into account (0 for A0, 1 for A1, 2 for A2, etc.).
+  */
+ grub_divmod64 (high + stripen, nstripes, );
+
+ stripe_offset = low + chunk_stripe_length * high;
+ csize = chunk_stripe_length - low;
+
+ break;
+   }
  default:
grub_dprintf ("btrfs", "unsupported RAID\n");
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
-- 
1.7.10.4

___
Grub-devel mailing list

Re: [PATCH v3 0/2] btrfs: Add zstd support to grub btrfs

2018-10-11 Thread Paul Menzel

Dear Nick,


Am 10.10.2018 um 22:28 schrieb Nick Terrell:


On Oct 10, 2018, at 12:34 AM, Paul Menzel wrote:

Sorry for being ignorant, but you explain, why the library needs to
be imported and it is not enough to use that library as an external
dependency?

Importing the library means, it has to be maintained in the GRUB
repository, which will result in some maintenance burden.


I've imported zstd because thats the way the rest of the
decompressors are imported.

We could potentially use libzstd as an external dependency, since its
only dependency is libc and GRUB provides the definitions of the libc
functions that zstd needs to decompress (memcpy, and memmove). Theres
some other stuff in the library that requires libc functionality that
GRUB doesn't provide, but that isn't used during decompression. We
strip those files out in the import.


Thank you for the explanation.


Let me know if you want me to switch to an external dependency.


I cannot make that decision. The main developers and the distribution
folks should comment on that.


Kind regards,

Paul

___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel