[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 3/5] Refactoring of function nvlist_find_value
From: |
Massimo Maggi |
Subject: |
[PATCH 3/5] Refactoring of function nvlist_find_value |
Date: |
Mon, 04 Feb 2013 12:09:27 +0100 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130128 Thunderbird/17.0.2 |
It's needed to allow iteration of nvlists in other functions.
Ported to GRUB2 from IllumOS changeset 13700 2889e2596bd6
Author: Christopher Siden <address@hidden>
Ported-by: Massimo Maggi <address@hidden>
---
grub-core/fs/zfs/zfs.c | 230
+++++++++++++++++++++++++++++++++----------------
1 file changed, 158 insertions(+), 72 deletions(-)
diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c
index 3ea9c95..7f76445 100644
--- a/grub-core/fs/zfs/zfs.c
+++ b/grub-core/fs/zfs/zfs.c
@@ -2,6 +2,7 @@
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2004,2009,2010,2011 Free
Software Foundation, Inc.
* Copyright 2010 Sun Microsystems, Inc.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
*
* GRUB is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -768,6 +769,155 @@ fill_vdev_info (struct grub_zfs_data *data,
}
/*
+ * For a given XDR packed nvlist, verify the first 4 bytes and move on.
+ *
+ * An XDR packed nvlist is encoded as (comments from nvs_xdr_create) :
+ *
+ * encoding method/host endian (4 bytes)
+ * nvl_version (4 bytes)
+ * nvl_nvflag (4 bytes)
+ * encoded nvpairs:
+ * encoded size of the nvpair (4 bytes)
+ * decoded size of the nvpair (4 bytes)
+ * name string size (4 bytes)
+ * name string data (sizeof(NV_ALIGN4(string))
+ * data type (4 bytes)
+ * # of elements in the nvpair (4 bytes)
+ * data
+ * 2 zero's for the last nvpair
+ * (end of the entire list) (8 bytes)
+ *
+ */
+
+/*
+ * The nvlist_next_nvpair() function returns a handle to the next
nvpair in the
+ * list following nvpair. If nvpair is NULL, the first pair is returned. If
+ * nvpair is the last pair in the nvlist, NULL is returned.
+ */
+static const char *
+nvlist_next_nvpair(const char *nvl, const char *nvpair)
+{
+ const char *nvp;
+ int encode_size;
+ int name_len;
+ if (nvl == NULL)
+ return (NULL);
+
+ if (nvpair == NULL) {
+ /* skip over header, nvl_version and nvl_nvflag */
+ nvpair = nvl + 4 * 3;
+ } else {
+ /* skip to the next nvpair */
+ encode_size = grub_be_to_cpu32 (grub_get_unaligned32(nvpair));
+ nvpair += encode_size;
+ }
+ /* 8 bytes of 0 marks the end of the list */
+ if (*(grub_uint64_t*)nvpair == 0)
+ return (NULL);
+ /*consistency checks*/
+ if (nvpair + 4 * 3 >= nvl + VDEV_PHYS_SIZE)
+ {
+ grub_dprintf ("zfs", "nvlist overflow\n");
+ grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist");
+ return (NULL);
+ }
+ encode_size = grub_be_to_cpu32 (grub_get_unaligned32(nvpair));
+
+ nvp = nvpair + 4*2;
+ name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp));
+ nvp += 4;
+
+ nvp = nvp + ((name_len + 3) & ~3); // align + if (nvp + 4 >= nvl +
VDEV_PHYS_SIZE + || encode_size < 0
+ || nvp + 4 + encode_size > nvl + VDEV_PHYS_SIZE) + {
+ grub_dprintf ("zfs", "nvlist overflow\n");
+ grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist");
+ return (NULL);
+ }
+ /* end consistency checks */
+
+ return (nvpair);
+}
+/*
+ * This function returns 0 on success and 1 on failure. On success, a
string
+ * containing the name of nvpair is saved in buf.
+ */
+static int
+nvpair_name(const char *nvp, char **buf, int* buflen)
+{
+ int len;
+
+ /* skip over encode/decode size */
+ nvp += 4 * 2;
+
+ len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp));
+ nvp=nvp+4;
+
+ *buf=(char*)nvp;
+ *buflen=len;
+
+ return (0);
+}
+/*
+ * This function retrieves the value of the nvpair in the form of
enumerated
+ * type data_type_t.
+ */
+static int
+nvpair_type(const char *nvp)
+{
+ int name_len, type;
+
+ /* skip over encode/decode size */
+ nvp += 4 * 2;
+
+ /* skip over name_len */
+ name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp));
+ nvp += 4;
+
+ /* skip over name */
+ nvp = nvp + ((name_len + 3) & ~3); /* align */
+
+ type = grub_be_to_cpu32 (grub_get_unaligned32 (nvp));
+
+ return (type);
+}
+static int
+nvpair_value(const char *nvp,char **val,
+ grub_size_t *size_out, grub_size_t *nelm_out)
+{
+ int name_len,nelm,encode_size;
+
+ /* skip over encode/decode size */
+ encode_size = grub_be_to_cpu32 (grub_get_unaligned32(nvp));
+ nvp += 8;
+
+ /* skip over name_len */
+ name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp));
+ nvp += 4;
+
+ /* skip over name */
+ nvp = nvp + ((name_len + 3) & ~3); /* align */
+
+ /* skip over type */
+ nvp += 4;
+ nelm = grub_be_to_cpu32 (grub_get_unaligned32 (nvp));
+ nvp +=4;
+ if (nelm < 1)
+ {
+ grub_error (GRUB_ERR_BAD_FS, "empty nvpair");
+ return 0;
+ }
+ *val = (char *) nvp;
+ *size_out = encode_size;
+ if (nelm_out)
+ *nelm_out = nelm;
+ + return 1;
+}
+
+/*
* Check the disk label information and retrieve needed vdev name-value
pairs.
*
*/
@@ -3064,34 +3214,14 @@ dnode_get_fullpath (const char *fullpath, struct
subvolume *subvol,
return err;
}
-/*
- * For a given XDR packed nvlist, verify the first 4 bytes and move on.
- *
- * An XDR packed nvlist is encoded as (comments from nvs_xdr_create) :
- *
- * encoding method/host endian (4 bytes)
- * nvl_version (4 bytes)
- * nvl_nvflag (4 bytes)
- * encoded nvpairs:
- * encoded size of the nvpair (4 bytes)
- * decoded size of the nvpair (4 bytes)
- * name string size (4 bytes)
- * name string data (sizeof(NV_ALIGN4(string))
- * data type (4 bytes)
- * # of elements in the nvpair (4 bytes)
- * data
- * 2 zero's for the last nvpair
- * (end of the entire list) (8 bytes)
- *
- */
-
static int
nvlist_find_value (const char *nvlist_in, const char *name,
int valtype, char **val,
grub_size_t *size_out, grub_size_t *nelm_out)
{
- int name_len, type, encode_size;
- const char *nvpair, *nvp_name, *nvlist = nvlist_in;
+ int name_len, type ;
+ const char *nvpair=NULL,*nvlist=nvlist_in;
+ char *nvp_name;
/* Verify if the 1st and 2nd byte in the nvlist are valid. */
/* NOTE: independently of what endianness header announces all @@
-3104,62 +3234,18 @@ nvlist_find_value (const char *nvlist_in, const
char *name,
return 0;
}
- /* skip the header, nvl_version, and nvl_nvflag */
- nvlist = nvlist + 4 * 3;
/*
* Loop thru the nvpair list
* The XDR representation of an integer is in big-endian byte order.
*/
- while ((encode_size = grub_be_to_cpu32 (grub_get_unaligned32 (nvlist))))
+ while ((nvpair=nvlist_next_nvpair(nvlist,nvpair)))
{
- int nelm;
-
- if (nvlist + 4 * 4 >= nvlist_in + VDEV_PHYS_SIZE)
+ nvpair_name(nvpair,&nvp_name,&name_len);
+ type = nvpair_type(nvpair);
+ if ((grub_strncmp (nvp_name, name, grub_strlen(name)) == 0) &&
type == valtype)
{
- grub_dprintf ("zfs", "nvlist overflow\n");
- grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist");
- return 0;
- }
-
- nvpair = nvlist + 4 * 2; /* skip the encode/decode size */
-
- name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair));
- nvpair += 4;
-
- nvp_name = nvpair;
- nvpair = nvpair + ((name_len + 3) & ~3); /* align */
-
- if (nvpair + 8 >= nvlist_in + VDEV_PHYS_SIZE
- || encode_size < 0
- || nvpair + 8 + encode_size > nvlist_in + VDEV_PHYS_SIZE)
- {
- grub_dprintf ("zfs", "nvlist overflow\n");
- grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist");
- return 0;
+ return nvpair_value(nvpair,val,size_out,nelm_out);
}
-
- type = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair));
- nvpair += 4;
-
- nelm = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair));
- if (nelm < 1)
- {
- grub_error (GRUB_ERR_BAD_FS, "empty nvpair");
- return 0;
- }
-
- nvpair += 4;
-
- if ((grub_strncmp (nvp_name, name, name_len) == 0) && type ==
valtype)
- {
- *val = (char *) nvpair;
- *size_out = encode_size;
- if (nelm_out)
- *nelm_out = nelm;
- return 1;
- }
-
- nvlist += encode_size; /* goto the next nvpair */
}
return 0;
}
--
1.8.1.1
Attached Message Part
Description: Text document
signature.asc
Description: OpenPGP digital signature
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [PATCH 3/5] Refactoring of function nvlist_find_value,
Massimo Maggi <=