From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.71) id 1ZFUWq-00026y-It for mharc-grub-devel@gnu.org; Wed, 15 Jul 2015 17:47:48 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:34641) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZFUWm-000260-Ib for grub-devel@gnu.org; Wed, 15 Jul 2015 17:47:46 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZFUWk-0005G1-5q for grub-devel@gnu.org; Wed, 15 Jul 2015 17:47:44 -0400 Received: from mail-wi0-x232.google.com ([2a00:1450:400c:c05::232]:36300) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZFUWj-0005FT-J8 for grub-devel@gnu.org; Wed, 15 Jul 2015 17:47:42 -0400 Received: by widjy10 with SMTP id jy10so12079988wid.1 for ; Wed, 15 Jul 2015 14:47:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=message-id:date:from:user-agent:mime-version:to:subject:references :in-reply-to:content-type; bh=AAe5F/sWOnFt4t4ezFj09hubTwLWtfYOuCrf0K6KrkI=; b=xjBUNLSVPgM6Z+4ysl5K/E0Gad6btEGnKG9mSqC9hKo6cTS5dRgj7GkP1YmEPJWpXv wXC/uQFJKNKthflZ5raM1Ihi7abm2O9Dz1Vg6BfKf6Fa7XLTPQ5tv64i6qufFHsCmEf7 1neXLnslO5L7grVAp1zPu75tAP0xZI06BeY8qnmMtslkrGDhIGSsnRr9ld4zM4spD7WD ec889V3CxVPZ4WsBIltGnwgzt2sfbVxuzDDY6aqG4qyDFlI7oLVmWCjqq9DeUr7kAjZo l54Czr/mI1VMQSksQBSv/q+yzk4J4gK8GpxoF+T93P4iaXkkO6pnWipi2dktwzbav0Dh FZpg== X-Received: by 10.194.206.65 with SMTP id lm1mr12471531wjc.117.1436996860284; Wed, 15 Jul 2015 14:47:40 -0700 (PDT) Received: from ?IPv6:2a02:1205:34c8:dc00:863a:4bff:fe50:abc4? ([2a02:1205:34c8:dc00:863a:4bff:fe50:abc4]) by smtp.gmail.com with ESMTPSA id q3sm9786383wjr.38.2015.07.15.14.47.38 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 15 Jul 2015 14:47:39 -0700 (PDT) Message-ID: <55A6D4FA.7000400@gmail.com> Date: Wed, 15 Jul 2015 23:47:38 +0200 From: =?UTF-8?B?VmxhZGltaXIgJ8+GLWNvZGVyL3BoY29kZXInIFNlcmJpbmVua28=?= User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Icedove/31.7.0 MIME-Version: 1.0 To: The development of GNU GRUB Subject: Re: [RFD] diskfilter stale RAID member detection vs. lazy scanning References: <20150628210655.6dfdbd9a@opensuse.site> <55A6A104.6060407@gmail.com> In-Reply-To: <55A6A104.6060407@gmail.com> Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="gd5eo4ob5oKXs6IE6ecm0FmJUneElK9od" X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:400c:c05::232 X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: The development of GNU GRUB List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 15 Jul 2015 21:47:47 -0000 This is an OpenPGP/MIME signed message (RFC 4880 and 3156) --gd5eo4ob5oKXs6IE6ecm0FmJUneElK9od Content-Type: multipart/mixed; boundary="------------020503070108040807030506" This is a multi-part message in MIME format. --------------020503070108040807030506 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On 15.07.2015 20:05, Vladimir '=CF=86-coder/phcoder' Serbinenko wrote: > On 28.06.2015 20:06, Andrei Borzenkov wrote: >> I was looking at implementing detection of outdated RAID members. >> Unfortunately it appears to be fundamentally incompatible with lazy >> scanning as implemented currently by GRUB. We simply cannot stop >> scanning for other copies of metadata once "enough" was seen. Because >> any other disk may contain more actual copy which invalidates >> everything seen up to this point. >> >> So basically either we officially admit that GRUB is not able to detec= t >> stale members or we drop lazy scanning. >> >> Comments, ideas? >> > We don't need to see all disks to decide that there is no staleness. If= > you have an array with N devices and you can lose at most K of them, > then you can check for staleness after you have seen max(K+1, N-K) > drives. Why? >=20 > Let those disks have generation numbers g_0,...,g_{N-1}. Our goal is to= > find the largest number G s.t. number of indices with > g_i >=3D G is at least N-K. > In most common case when you have seen K+1 disks all of them will have > the same generation number > g_0=3Dg_1=3D...=3Dg_{K} > Then we know that > G<=3Dg_0 > Suppose not then all of 0,...,K are stale and we have lost K+1 drives > which contradicts our goal. > On the other hand when we have seen N-K devices we know that > G>=3Dmin(g_0,...,g_{N-K-1}) > as with G=3Dmin(g_0,...,g_{N-K-1}) we already have N-K disks. >=20 > In cases other than mirror usually K+1<=3DN-K and so we don't even need= to > scan for more disks to detect staleness. > The code will be slightly tricky as it has to handle tolerating > staleness if there are too little disks but it's totally feasible. Let > me figure out the rest of math and write a prototype. Untested patch implementing these ideas, just to illustrate >> _______________________________________________ >> Grub-devel mailing list >> Grub-devel@gnu.org >> https://lists.gnu.org/mailman/listinfo/grub-devel >> >=20 >=20 --------------020503070108040807030506 Content-Type: text/x-diff; name="diskfilter_gen.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="diskfilter_gen.diff" diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c index c4f6678..850046e 100644 --- a/grub-core/disk/diskfilter.c +++ b/grub-core/disk/diskfilter.c @@ -41,77 +41,201 @@ static int lv_num =3D 0; =20 static struct grub_diskfilter_lv * find_lv (const char *name); -static int is_lv_readable (struct grub_diskfilter_lv *lv, int easily); +static void +recompute_lv_readable (struct grub_diskfilter_lv *lv); =20 =0C =20 -static grub_err_t -is_node_readable (const struct grub_diskfilter_node *node, int easily) +static int +get_number_needed_nodes(struct grub_diskfilter_segment *seg, int easily)= +{ + int need =3D seg->node_count; + + switch (seg->type) + { + case GRUB_DISKFILTER_RAID6: + if (!easily) + need--; + /* Fallthrough. */ + case GRUB_DISKFILTER_RAID4: + case GRUB_DISKFILTER_RAID5: + if (!easily) + need--; + /* Fallthrough. */ + case GRUB_DISKFILTER_STRIPED: + break; + =20 + case GRUB_DISKFILTER_MIRROR: + need =3D 1; + break; + + case GRUB_DISKFILTER_RAID10: + { + unsigned int n; + n =3D seg->layout & 0xFF; + if (n =3D=3D 1) + n =3D (seg->layout >> 8) & 0xFF; + need =3D seg->node_count - n + 1; + } + break; + } + return need; +} + +/* Return whether node is readable and if so update node->generation. *= / +static void +recompute_node_readable (struct grub_diskfilter_node *node) { /* Check whether we actually know the physical volume we want to read from. */ if (node->pv) - return !!(node->pv->disk); + { + node->readability.is_readable =3D !!(node->pv->disk); + node->readability.is_easily_readable =3D !!(node->pv->disk); + node->readability.generation =3D node->pv->generation; + return; + } if (node->lv) - return is_lv_readable (node->lv, easily); + { + recompute_lv_readable (node->lv); + node->readability =3D node->lv->readability; + return; + } + node->readability.is_readable =3D 0; + node->readability.is_easily_readable =3D 0; + node->readability.generation =3D 0; + return; +} + +static grub_uint64_t +compute_generation (struct grub_diskfilter_segment *seg, int need) +{ + unsigned i; + for (i =3D 0; i < seg->node_count; i++) + if (seg->nodes[i].readability.is_readable) { + unsigned j; + grub_uint64_t candidate =3D seg->nodes[i].readability.generation; + int higher =3D 0, strictly_higher =3D 0; + for (j =3D 0; j < seg->node_count; j++) + if (seg->nodes[j].readability.is_readable) { + strictly_higher +=3D (seg->nodes[j].readability.generation > candidat= e); + higher +=3D (seg->nodes[j].readability.generation >=3D candidate); + } + if (higher >=3D need && strictly_higher < need) + return candidate; + } return 0; } =20 static int -is_lv_readable (struct grub_diskfilter_lv *lv, int easily) +still_could_increase (struct grub_diskfilter_segment *seg, int need, gru= b_uint64_t generation) { - unsigned i, j; - if (!lv) - return 0; - for (i =3D 0; i < lv->segment_count; i++) + unsigned j; + int strictly_higher =3D 0; + for (j =3D 0; j < seg->node_count; j++) + { + strictly_higher +=3D (seg->nodes[j].readability.generation > gener= ation) || !(seg->nodes[j].readability.is_readable); + } + return (strictly_higher >=3D need); +} + +static void +recompute_segment_readable (struct grub_diskfilter_segment *seg) +{ + int need =3D get_number_needed_nodes(seg, 0), have =3D 0; + int easily_readable; + grub_uint64_t generation; + unsigned j; + for (j =3D 0; j < seg->node_count; j++) + recompute_node_readable (seg->nodes + j); + for (j =3D 0; j < seg->node_count; j++) + { + if (seg->nodes[j].readability.is_readable) + have++; + } + /* Not enough disks. */ + if (have < need) + { + seg->readability.is_easily_readable =3D 0; + seg->readability.is_readable =3D 0; + seg->readability.generation =3D 0; + return; + } + + generation =3D compute_generation (seg, need); + /* Do not tolerate any staleness on easily readable level. */ + if (still_could_increase (seg, need, generation)) + { + easily_readable =3D 0; + } + else { - int need =3D lv->segments[i].node_count, have =3D 0; - switch (lv->segments[i].type) + int have_easily =3D 0, need_easily =3D get_number_needed_nodes(seg= , 1); + for (j =3D 0; j < seg->node_count; j++) { - case GRUB_DISKFILTER_RAID6: - if (!easily) - need--; - /* Fallthrough. */ - case GRUB_DISKFILTER_RAID4: - case GRUB_DISKFILTER_RAID5: - if (!easily) - need--; - /* Fallthrough. */ - case GRUB_DISKFILTER_STRIPED: - break; - - case GRUB_DISKFILTER_MIRROR: - need =3D 1; - break; - - case GRUB_DISKFILTER_RAID10: - { - unsigned int n; - n =3D lv->segments[i].layout & 0xFF; - if (n =3D=3D 1) - n =3D (lv->segments[i].layout >> 8) & 0xFF; - need =3D lv->segments[i].node_count - n + 1; - } - break; + if (seg->nodes[j].readability.is_easily_readable && seg->nodes[j].rea= dability.generation >=3D generation) + have_easily++; } - for (j =3D 0; j < lv->segments[i].node_count; j++) - { - if (is_node_readable (lv->segments[i].nodes + j, easily)) - have++; - if (have >=3D need) - break; - } - if (have < need) - return 0; + easily_readable =3D have_easily >=3D need_easily; } + seg->readability.generation =3D generation; + seg->readability.is_readable =3D 1; + seg->readability.is_easily_readable =3D easily_readable; +} =20 - return 1; +static void +recompute_lv_readable (struct grub_diskfilter_lv *lv) +{ + unsigned i; + struct grub_diskfilter_readability ret =3D + { + .is_readable =3D 1, + .is_easily_readable =3D 1, + .generation =3D -1 + }; + if (!lv) + return; + for (i =3D 0; i < lv->segment_count; i++) + { + recompute_segment_readable (&lv->segments[i]); + if (!lv->segments[i].readability.is_easily_readable) + ret.is_easily_readable =3D 0; + if (!lv->segments[i].readability.is_readable) + ret.is_readable =3D 0; + if (ret.generation > lv->segments[i].readability.generation) + ret.generation =3D lv->segments[i].readability.generation; + } + lv->readability =3D ret; +} + +static int +is_lv_readable (struct grub_diskfilter_lv *lv) +{ + if (!lv) + return 0; + + if (lv->readability.is_readable) + return 1; + recompute_lv_readable(lv); + return lv->readability.is_readable; +} + +static int +is_lv_easily_readable (struct grub_diskfilter_lv *lv) +{ + if (!lv) + return 0; + if (lv->readability.is_easily_readable) + return 1; + recompute_lv_readable(lv); + return lv->readability.is_easily_readable; } =20 static grub_err_t insert_array (grub_disk_t disk, const struct grub_diskfilter_pv_id *id, struct grub_diskfilter_vg *array, grub_disk_addr_t start_sector, + grub_uint64_t generation, grub_diskfilter_t diskfilter __attribute__ ((unused))); =20 static int @@ -154,15 +278,16 @@ scan_disk_partition_iter (grub_disk_t disk, grub_pa= rtition_t p, void *data) =20 for (diskfilter =3D grub_diskfilter_list; diskfilter; diskfilter =3D d= iskfilter->next) { + grub_uint64_t generation =3D 0; #ifdef GRUB_UTIL grub_util_info ("Scanning for %s devices on disk %s",=20 diskfilter->name, name); #endif id.uuid =3D 0; id.uuidlen =3D 0; - arr =3D diskfilter->detect (disk, &id, &start_sector); + arr =3D diskfilter->detect (disk, &id, &start_sector, &generation)= ; if (arr && - (! insert_array (disk, &id, arr, start_sector, diskfilter))) + (! insert_array (disk, &id, arr, start_sector, generation, diskfilter= ))) { if (id.uuidlen) grub_free (id.uuid); @@ -232,7 +357,7 @@ scan_devices (const char *arname) { if ((p->iterate) (scan_disk_hook, NULL, pull)) return; - if (arname && is_lv_readable (find_lv (arname), 1)) + if (arname && is_lv_easily_readable (find_lv (arname))) return; } =20 @@ -412,7 +537,7 @@ find_lv (const char *name) for (lv =3D vg->lvs; lv; lv =3D lv->next) if (((lv->fullname && grub_strcmp (lv->fullname, name) =3D=3D 0) || (lv->idname && grub_strcmp (lv->idname, name) =3D=3D 0)) - && is_lv_readable (lv, 0)) + && is_lv_readable (lv)) return lv; } return NULL; @@ -429,7 +554,7 @@ grub_diskfilter_open (const char *name, grub_disk_t d= isk) =20 lv =3D find_lv (name); =20 - if (! lv) + if (! lv || !lv->readability.is_easily_readable) { scan_devices (name); if (grub_errno) @@ -644,16 +769,19 @@ read_segment (struct grub_diskfilter_segment *seg, = grub_disk_addr_t sector, || grub_errno =3D=3D GRUB_ERR_UNKNOWN_DEVICE) grub_errno =3D GRUB_ERR_NONE; =20 - err =3D grub_diskfilter_read_node (&seg->nodes[k], - read_sector - + j * far_ofs + b, - read_size, - buf); - if (! err) - break; - else if (err !=3D GRUB_ERR_READ_ERROR - && err !=3D GRUB_ERR_UNKNOWN_DEVICE) - return err; + if (seg->nodes[k].readability.generation >=3D seg->readability.gen= eration) + { + err =3D grub_diskfilter_read_node (&seg->nodes[k], + read_sector + + j * far_ofs + b, + read_size, + buf); + if (! err) + break; + else if (err !=3D GRUB_ERR_READ_ERROR + && err !=3D GRUB_ERR_UNKNOWN_DEVICE) + return err; + } k++; if (k =3D=3D seg->node_count) k =3D 0; @@ -749,10 +877,13 @@ read_segment (struct grub_diskfilter_segment *seg, = grub_disk_addr_t sector, || grub_errno =3D=3D GRUB_ERR_UNKNOWN_DEVICE) grub_errno =3D GRUB_ERR_NONE; =20 - err =3D grub_diskfilter_read_node (&seg->nodes[disknr], - read_sector + b, - read_size, - buf); + if (seg->nodes[disknr].readability.generation >=3D seg->readability= =2Egeneration) + err =3D grub_diskfilter_read_node (&seg->nodes[disknr], + read_sector + b, + read_size, + buf); + else + err =3D GRUB_ERR_READ_ERROR; =20 if ((err) && (err !=3D GRUB_ERR_READ_ERROR && err !=3D GRUB_ERR_UNKNOWN_DEVICE)) @@ -1183,6 +1314,7 @@ static grub_err_t insert_array (grub_disk_t disk, const struct grub_diskfilter_pv_id *id, struct grub_diskfilter_vg *array, grub_disk_addr_t start_sector, + grub_uint64_t generation, grub_diskfilter_t diskfilter __attribute__ ((unused))) { struct grub_diskfilter_pv *pv; @@ -1219,6 +1351,7 @@ insert_array (grub_disk_t disk, const struct grub_d= iskfilter_pv_id *id, pv->start_sector -=3D pv->part_start; pv->part_start =3D grub_partition_get_start (disk->partition); pv->part_size =3D grub_disk_get_size (disk); + pv->generation =3D generation; =20 #ifdef GRUB_UTIL { @@ -1238,7 +1371,7 @@ insert_array (grub_disk_t disk, const struct grub_d= iskfilter_pv_id *id, pv->start_sector +=3D pv->part_start; /* Add the device to the array. */ for (lv =3D array->lvs; lv; lv =3D lv->next) - if (!lv->became_readable_at && lv->fullname && is_lv_readable (lv, 0)= ) + if (!lv->became_readable_at && lv->fullname && is_lv_readable (lv)) lv->became_readable_at =3D ++inscnt; break; } diff --git a/grub-core/disk/dmraid_nvidia.c b/grub-core/disk/dmraid_nvidi= a.c index 881508c..73895ad 100644 --- a/grub-core/disk/dmraid_nvidia.c +++ b/grub-core/disk/dmraid_nvidia.c @@ -92,8 +92,9 @@ struct grub_nv_super =20 static struct grub_diskfilter_vg * grub_dmraid_nv_detect (grub_disk_t disk, - struct grub_diskfilter_pv_id *id, - grub_disk_addr_t *start_sector) + struct grub_diskfilter_pv_id *id, + grub_disk_addr_t *start_sector, + grub_uint64_t *generation) { grub_disk_addr_t sector; struct grub_nv_super sb; @@ -103,6 +104,8 @@ grub_dmraid_nv_detect (grub_disk_t disk, grub_uint8_t total_volumes; char *uuid; =20 + *generation =3D 0; + if (disk->partition) /* Skip partition. */ return NULL; diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c index 8075f2a..f8f3be0 100644 --- a/grub-core/disk/ldm.c +++ b/grub-core/disk/ldm.c @@ -780,12 +780,15 @@ make_vg (grub_disk_t disk, static struct grub_diskfilter_vg *=20 grub_ldm_detect (grub_disk_t disk, struct grub_diskfilter_pv_id *id, - grub_disk_addr_t *start_sector) + grub_disk_addr_t *start_sector, + grub_uint64_t *generation) { grub_err_t err; struct grub_ldm_label label; struct grub_diskfilter_vg *vg; =20 + *generation =3D 0; + #ifdef GRUB_UTIL grub_util_info ("scanning %s for LDM", disk->name); #endif diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c index 7b265c7..58b0704 100644 --- a/grub-core/disk/lvm.c +++ b/grub-core/disk/lvm.c @@ -98,7 +98,8 @@ grub_lvm_check_flag (char *p, const char *str, const ch= ar *flag) static struct grub_diskfilter_vg *=20 grub_lvm_detect (grub_disk_t disk, struct grub_diskfilter_pv_id *id, - grub_disk_addr_t *start_sector) + grub_disk_addr_t *start_sector, + grub_uint64_t *generation) { grub_err_t err; grub_uint64_t mda_offset, mda_size; @@ -116,6 +117,8 @@ grub_lvm_detect (grub_disk_t disk, struct grub_diskfilter_vg *vg; struct grub_diskfilter_pv *pv; =20 + *generation =3D 0; + =20 /* Search for label. */ for (i =3D 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++) { diff --git a/grub-core/disk/mdraid1x_linux.c b/grub-core/disk/mdraid1x_li= nux.c index 7cc80d3..40a5ab7 100644 --- a/grub-core/disk/mdraid1x_linux.c +++ b/grub-core/disk/mdraid1x_linux.c @@ -106,7 +106,8 @@ struct grub_raid_super_1x static struct grub_diskfilter_vg * grub_mdraid_detect (grub_disk_t disk, struct grub_diskfilter_pv_id *id, - grub_disk_addr_t *start_sector) + grub_disk_addr_t *start_sector, + grub_uint64_t *generation) { grub_uint64_t size; grub_uint8_t minor_version; @@ -198,6 +199,7 @@ grub_mdraid_detect (grub_disk_t disk, grub_memcpy (uuid, sb.set_uuid, 16); =20 *start_sector =3D grub_le_to_cpu64 (sb.data_offset); + *generation =3D grub_le_to_cpu64 (sb.events); =20 array =3D grub_diskfilter_make_raid (16, uuid, grub_le_to_cpu32 (sb.raid_disks), diff --git a/grub-core/disk/mdraid_linux.c b/grub-core/disk/mdraid_linux.= c index 11024ae..7b9768c 100644 --- a/grub-core/disk/mdraid_linux.c +++ b/grub-core/disk/mdraid_linux.c @@ -180,7 +180,8 @@ struct grub_raid_super_09 static struct grub_diskfilter_vg * grub_mdraid_detect (grub_disk_t disk, struct grub_diskfilter_pv_id *id, - grub_disk_addr_t *start_sector) + grub_disk_addr_t *start_sector, + grub_uint64_t *generation) { grub_disk_addr_t sector; grub_uint64_t size; @@ -247,6 +248,7 @@ grub_mdraid_detect (grub_disk_t disk, uuid[3] =3D grub_swap_bytes32 (sb->set_uuid3); =20 *start_sector =3D 0; + *generation =3D grub_md_to_cpu64 (sb->cp_events); =20 id->uuidlen =3D 0; id->id =3D grub_md_to_cpu32 (sb->this_disk.number); diff --git a/include/grub/diskfilter.h b/include/grub/diskfilter.h index 1aedcd3..947500b 100644 --- a/include/grub/diskfilter.h +++ b/include/grub/diskfilter.h @@ -69,6 +69,7 @@ struct grub_diskfilter_pv { grub_disk_addr_t part_start; grub_disk_addr_t part_size; grub_disk_addr_t start_sector; /* Sector number where the data area st= arts. */ + grub_uint64_t generation; struct grub_diskfilter_pv *next; /* Optional. */ grub_uint8_t *internal_id; @@ -77,6 +78,15 @@ struct grub_diskfilter_pv { #endif }; =20 +struct grub_diskfilter_readability +{ + /* Readable without reading any stale disks or doing any recovery. */= + int is_easily_readable; + /* Readable at all: even reding stale disks and doing recovery. */ + int is_readable; + grub_uint64_t generation; +}; + struct grub_diskfilter_lv { /* Name used for disk. */ char *fullname; @@ -90,6 +100,7 @@ struct grub_diskfilter_lv { int became_readable_at; int scanned; int visible; + struct grub_diskfilter_readability readability; =20 /* Pointer to segment_count segments. */ struct grub_diskfilter_segment *segments; @@ -119,6 +130,7 @@ struct grub_diskfilter_segment { unsigned int node_count; unsigned int node_alloc; struct grub_diskfilter_node *nodes; + struct grub_diskfilter_readability readability; =20 unsigned int stripe_size; }; @@ -127,6 +139,7 @@ struct grub_diskfilter_node { grub_disk_addr_t start; /* Optional. */ char *name; + struct grub_diskfilter_readability readability; struct grub_diskfilter_pv *pv; struct grub_diskfilter_lv *lv; }; @@ -143,7 +156,8 @@ struct grub_diskfilter =20 struct grub_diskfilter_vg * (*detect) (grub_disk_t disk, struct grub_diskfilter_pv_id *id, - grub_disk_addr_t *start_sector); + grub_disk_addr_t *start_sector, + grub_uint64_t *generation); }; typedef struct grub_diskfilter *grub_diskfilter_t; =20 --------------020503070108040807030506-- --gd5eo4ob5oKXs6IE6ecm0FmJUneElK9od Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iF4EAREKAAYFAlWm1PoACgkQmBXlbbo5nOsa3AD/agBqydn0eTlf9mJiv5dsTvQy 8UJKUHUiagp2QfpcqJQA/2XYBb/HepJV5metU9H1OIFGdD//KAyHtGzwifX50VZo =TxNs -----END PGP SIGNATURE----- --gd5eo4ob5oKXs6IE6ecm0FmJUneElK9od--