Skip to content

Commit

Permalink
Check for feature flags needed to read from the pool.
Browse files Browse the repository at this point in the history
Ported to GRUB2 from IllumOS changeset 13700    2889e2596bd6

Author: Christopher Siden <chris.siden@delphix.com>
Ported-by: Massimo Maggi <me@massimo-maggi.eu>
  • Loading branch information
maxximino committed Jan 26, 2013
1 parent 5834403 commit f98cb07
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 3 deletions.
102 changes: 100 additions & 2 deletions grub-core/fs/zfs/zfs.c
Expand Up @@ -272,6 +272,19 @@ grub_crypto_cipher_handle_t (*grub_zfs_load_key) (const struct grub_zfs_key *key
grub_size_t keysize,
grub_uint64_t salt,
grub_uint64_t algo) = NULL;
/*
* List of pool features that the grub implementation of ZFS supports for
* read. Note that features that are only required for write do not need
* to be listed here since grub opens pools in read-only mode.
*/
static const char *spa_feature_names[] = {
"max.test:feat1",NULL
};

static int
check_feature(const char *name, grub_uint64_t val, struct grub_zfs_dir_ctx *ctx);
static int
check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct grub_zfs_data* data );

static grub_err_t
zlib_decompress (void *s, void *d,
Expand Down Expand Up @@ -927,7 +940,7 @@ check_pool_label (struct grub_zfs_data *data,
int *inserted)
{
grub_uint64_t pool_state, txg = 0;
char *nvlist;
char *nvlist,*features;
#if 0
char *nv;
#endif
Expand Down Expand Up @@ -1047,7 +1060,30 @@ check_pool_label (struct grub_zfs_data *data,
grub_free (nv);
}
grub_dprintf ("zfs", "check 10 passed\n");

if ((features=grub_zfs_nvlist_lookup_nvlist(nvlist, ZPOOL_CONFIG_FEATURES_FOR_READ)))
{
const char *nvp=NULL;
char *name = grub_zalloc(51);
char *nameptr;
int namelen;
while ((nvp = nvlist_next_nvpair(features, nvp)) != NULL)
{
nvpair_name(nvp, &nameptr,&namelen);
if(namelen > 50){namelen=50;}
grub_strncpy(name,nameptr,namelen);
name[namelen]=0;
grub_dprintf("zfs","namelen=%u str=%s\n",namelen,name);
if (check_feature(name,1, NULL) != 0)
{
grub_dprintf("zfs","feature missing in check_pool_label:%s\n",name);
err= grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET," check_pool_label missing feature '%s' for read",name);
grub_free(name);
return err;
}
}
grub_free(name);
}
grub_dprintf ("zfs", "check 12 passed (feature flags)\n");
grub_free (nvlist);

return GRUB_ERR_NONE;
Expand Down Expand Up @@ -3502,6 +3538,10 @@ zfs_mount (grub_device_t dev)
return NULL;
}

if (ub->ub_version >= SPA_VERSION_FEATURES &&
check_mos_features(&((objset_phys_t *) osp)->os_meta_dnode,ub_endian, data) != 0)
return NULL;

/* Got the MOS. Save it at the memory addr MOS. */
grub_memmove (&(data->mos.dn), &((objset_phys_t *) osp)->os_meta_dnode,
DNODE_SIZE);
Expand Down Expand Up @@ -4042,6 +4082,64 @@ grub_zfs_dir (grub_device_t device, const char *path,
return grub_errno;
}

static int
check_feature(const char *name, grub_uint64_t val,__attribute__((unused)) struct grub_zfs_dir_ctx *ctx)
{
int i;
if(val ==0) return 0;
if(*name==0) return 0;
for (i = 0; spa_feature_names[i] != NULL; i++)
{
if (grub_strcmp(name, spa_feature_names[i]) == 0)
return 0;
}
grub_printf("missing feature for read '%s'\n",name);
return 1;
}

/*
* Checks whether the MOS features that are active are supported by this
* (GRUB's) implementation of ZFS.
*
* Return:
* 0: Success.
* errnum: Failure.
*/

static int
check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct grub_zfs_data* data )
{
grub_uint64_t objnum;
grub_uint8_t errnum = 0;
dnode_end_t dn,mosmdn;
mzap_phys_t* mzp;
grub_zfs_endian_t endianzap;
int size;
grub_memmove(&(mosmdn.dn),mosmdn_phys,sizeof(dnode_phys_t));
mosmdn.endian=endian;
if ((errnum = dnode_get(&mosmdn, DMU_POOL_DIRECTORY_OBJECT,
DMU_OT_OBJECT_DIRECTORY, &dn,data)) != 0)
return (errnum);

/*
* Find the object number for 'features_for_read' and retrieve its
* corresponding dnode. Note that we don't check features_for_write
* because GRUB is not opening the pool for write.
*/
if ((errnum = zap_lookup(&dn, DMU_POOL_FEATURES_FOR_READ, &objnum, data,0)) != 0)
return (errnum);

if ((errnum = dnode_get(&mosmdn, objnum, DMU_OTN_ZAP_METADATA, &dn, data)) != 0)
return (errnum);

if ((errnum = dmu_read(&dn, 0, (void**)&mzp, &endianzap,data)) != 0)
return (errnum);

size = grub_zfs_to_cpu16 (dn.dn.dn_datablkszsec, dn.endian) << SPA_MINBLOCKSHIFT;
return (mzap_iterate(mzp,endianzap, size, check_feature,NULL));
}


#ifdef GRUB_UTIL
static grub_err_t
grub_zfs_embed (grub_device_t device __attribute__ ((unused)),
Expand Down
46 changes: 45 additions & 1 deletion include/grub/zfs/dmu.h
Expand Up @@ -22,6 +22,39 @@

#ifndef _SYS_DMU_H
#define _SYS_DMU_H
#define B_FALSE 0
#define B_TRUE 1

#define DMU_OT_NEWTYPE 0x80
#define DMU_OT_METADATA 0x40
#define DMU_OT_BYTESWAP_MASK 0x3f

#define DMU_OT(byteswap, metadata) \
(DMU_OT_NEWTYPE | \
((metadata) ? DMU_OT_METADATA : 0) | \
((byteswap) & DMU_OT_BYTESWAP_MASK))

#define DMU_OT_IS_VALID(ot) (((ot) & DMU_OT_NEWTYPE) ? \
((ot) & DMU_OT_BYTESWAP_MASK) < DMU_BSWAP_NUMFUNCS : \
(ot) < DMU_OT_NUMTYPES)

#define DMU_OT_IS_METADATA(ot) (((ot) & DMU_OT_NEWTYPE) ? \
((ot) & DMU_OT_METADATA) : \
dmu_ot[(ot)].ot_metadata)

typedef enum dmu_object_byteswap {
DMU_BSWAP_UINT8,
DMU_BSWAP_UINT16,
DMU_BSWAP_UINT32,
DMU_BSWAP_UINT64,
DMU_BSWAP_ZAP,
DMU_BSWAP_DNODE,
DMU_BSWAP_OBJSET,
DMU_BSWAP_ZNODE,
DMU_BSWAP_OLDACL,
DMU_BSWAP_ACL,
DMU_BSWAP_NUMFUNCS
} dmu_object_byteswap_t;

/*
* This file describes the interface that the DMU provides for its
Expand Down Expand Up @@ -89,7 +122,17 @@ typedef enum dmu_object_type {
DMU_OT_SA_ATTR_REGISTRATION, /* ZAP */
DMU_OT_SA_ATTR_LAYOUTS, /* ZAP */
DMU_OT_DSL_KEYCHAIN = 54,
DMU_OT_NUMTYPES
DMU_OT_NUMTYPES,
DMU_OTN_UINT8_DATA = DMU_OT(DMU_BSWAP_UINT8, B_FALSE),
DMU_OTN_UINT8_METADATA = DMU_OT(DMU_BSWAP_UINT8, B_TRUE),
DMU_OTN_UINT16_DATA = DMU_OT(DMU_BSWAP_UINT16, B_FALSE),
DMU_OTN_UINT16_METADATA = DMU_OT(DMU_BSWAP_UINT16, B_TRUE),
DMU_OTN_UINT32_DATA = DMU_OT(DMU_BSWAP_UINT32, B_FALSE),
DMU_OTN_UINT32_METADATA = DMU_OT(DMU_BSWAP_UINT32, B_TRUE),
DMU_OTN_UINT64_DATA = DMU_OT(DMU_BSWAP_UINT64, B_FALSE),
DMU_OTN_UINT64_METADATA = DMU_OT(DMU_BSWAP_UINT64, B_TRUE),
DMU_OTN_ZAP_DATA = DMU_OT(DMU_BSWAP_ZAP, B_FALSE),
DMU_OTN_ZAP_METADATA = DMU_OT(DMU_BSWAP_ZAP, B_TRUE),
} dmu_object_type_t;

typedef enum dmu_objset_type {
Expand All @@ -116,5 +159,6 @@ typedef enum dmu_objset_type {
#define DMU_POOL_HISTORY "history"
#define DMU_POOL_PROPS "pool_props"
#define DMU_POOL_L2CACHE "l2cache"
#define DMU_POOL_FEATURES_FOR_READ "features_for_read"

#endif /* _SYS_DMU_H */
1 change: 1 addition & 0 deletions include/grub/zfs/zfs.h
Expand Up @@ -81,6 +81,7 @@ typedef enum grub_zfs_endian
#define ZPOOL_CONFIG_DDT_HISTOGRAM "ddt_histogram"
#define ZPOOL_CONFIG_DDT_OBJ_STATS "ddt_object_stats"
#define ZPOOL_CONFIG_DDT_STATS "ddt_stats"
#define ZPOOL_CONFIG_FEATURES_FOR_READ "features_for_read"
/*
* The persistent vdev state is stored as separate values rather than a single
* 'vdev_state' entry. This is because a device can be in multiple states, such
Expand Down

0 comments on commit f98cb07

Please sign in to comment.