* grub-core/fs/zfs/zfs.c: Check for feature compatibility.
This commit is contained in:
parent
c71dbd40a9
commit
776bdce291
4 changed files with 157 additions and 3 deletions
|
@ -1,3 +1,7 @@
|
||||||
|
2013-07-14 Massimo Maggi <me@massimo-maggi.eu>
|
||||||
|
|
||||||
|
* grub-core/fs/zfs/zfs.c: Check for feature compatibility.
|
||||||
|
|
||||||
2013-07-14 Massimo Maggi <me@massimo-maggi.eu>
|
2013-07-14 Massimo Maggi <me@massimo-maggi.eu>
|
||||||
|
|
||||||
* grub-core/fs/zfs/zfs.c (uberblock_verify): Accept version 5000.
|
* grub-core/fs/zfs/zfs.c (uberblock_verify): Accept version 5000.
|
||||||
|
|
|
@ -271,6 +271,20 @@ grub_crypto_cipher_handle_t (*grub_zfs_load_key) (const struct grub_zfs_key *key
|
||||||
grub_size_t keysize,
|
grub_size_t keysize,
|
||||||
grub_uint64_t salt,
|
grub_uint64_t salt,
|
||||||
grub_uint64_t algo) = NULL;
|
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.
|
||||||
|
*/
|
||||||
|
#define MAX_SUPPORTED_FEATURE_STRLEN 50
|
||||||
|
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
|
static grub_err_t
|
||||||
zlib_decompress (void *s, void *d,
|
zlib_decompress (void *s, void *d,
|
||||||
|
@ -777,7 +791,7 @@ check_pool_label (struct grub_zfs_data *data,
|
||||||
int *inserted)
|
int *inserted)
|
||||||
{
|
{
|
||||||
grub_uint64_t pool_state, txg = 0;
|
grub_uint64_t pool_state, txg = 0;
|
||||||
char *nvlist;
|
char *nvlist,*features;
|
||||||
#if 0
|
#if 0
|
||||||
char *nv;
|
char *nv;
|
||||||
#endif
|
#endif
|
||||||
|
@ -897,7 +911,31 @@ check_pool_label (struct grub_zfs_data *data,
|
||||||
grub_free (nv);
|
grub_free (nv);
|
||||||
}
|
}
|
||||||
grub_dprintf ("zfs", "check 10 passed\n");
|
grub_dprintf ("zfs", "check 10 passed\n");
|
||||||
|
features = grub_zfs_nvlist_lookup_nvlist(nvlist,
|
||||||
|
ZPOOL_CONFIG_FEATURES_FOR_READ);
|
||||||
|
if (features)
|
||||||
|
{
|
||||||
|
const char *nvp=NULL;
|
||||||
|
char name[MAX_SUPPORTED_FEATURE_STRLEN + 1];
|
||||||
|
char *nameptr;
|
||||||
|
int namelen;
|
||||||
|
while ((nvp = nvlist_next_nvpair(features, nvp)) != NULL)
|
||||||
|
{
|
||||||
|
nvpair_name(nvp, &nameptr,&namelen);
|
||||||
|
if(namelen > MAX_SUPPORTED_FEATURE_STRLEN)
|
||||||
|
namelen = MAX_SUPPORTED_FEATURE_STRLEN;
|
||||||
|
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);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
grub_dprintf ("zfs", "check 12 passed (feature flags)\n");
|
||||||
grub_free (nvlist);
|
grub_free (nvlist);
|
||||||
|
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
|
@ -3416,6 +3454,11 @@ zfs_mount (grub_device_t dev)
|
||||||
return NULL;
|
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. */
|
/* Got the MOS. Save it at the memory addr MOS. */
|
||||||
grub_memmove (&(data->mos.dn), &((objset_phys_t *) osp)->os_meta_dnode,
|
grub_memmove (&(data->mos.dn), &((objset_phys_t *) osp)->os_meta_dnode,
|
||||||
DNODE_SIZE);
|
DNODE_SIZE);
|
||||||
|
@ -3983,6 +4026,68 @@ grub_zfs_dir (grub_device_t device, const char *path,
|
||||||
return grub_errno;
|
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;
|
||||||
|
errnum = dnode_get(&mosmdn, DMU_POOL_DIRECTORY_OBJECT,
|
||||||
|
DMU_OT_OBJECT_DIRECTORY, &dn,data);
|
||||||
|
if (errnum != 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.
|
||||||
|
*/
|
||||||
|
errnum = zap_lookup(&dn, DMU_POOL_FEATURES_FOR_READ, &objnum, data,0);
|
||||||
|
if (errnum != 0)
|
||||||
|
return errnum;
|
||||||
|
|
||||||
|
errnum = dnode_get(&mosmdn, objnum, DMU_OTN_ZAP_METADATA, &dn, data);
|
||||||
|
if (errnum != 0)
|
||||||
|
return errnum;
|
||||||
|
|
||||||
|
errnum = dmu_read(&dn, 0, (void**)&mzp, &endianzap,data);
|
||||||
|
if (errnum != 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
|
#ifdef GRUB_UTIL
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
grub_zfs_embed (grub_device_t device __attribute__ ((unused)),
|
grub_zfs_embed (grub_device_t device __attribute__ ((unused)),
|
||||||
|
|
|
@ -22,6 +22,39 @@
|
||||||
|
|
||||||
#ifndef _SYS_DMU_H
|
#ifndef _SYS_DMU_H
|
||||||
#define _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
|
* This file describes the interface that the DMU provides for its
|
||||||
|
@ -89,7 +122,17 @@ typedef enum dmu_object_type {
|
||||||
DMU_OT_SA_ATTR_REGISTRATION, /* ZAP */
|
DMU_OT_SA_ATTR_REGISTRATION, /* ZAP */
|
||||||
DMU_OT_SA_ATTR_LAYOUTS, /* ZAP */
|
DMU_OT_SA_ATTR_LAYOUTS, /* ZAP */
|
||||||
DMU_OT_DSL_KEYCHAIN = 54,
|
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;
|
} dmu_object_type_t;
|
||||||
|
|
||||||
typedef enum dmu_objset_type {
|
typedef enum dmu_objset_type {
|
||||||
|
@ -116,5 +159,6 @@ typedef enum dmu_objset_type {
|
||||||
#define DMU_POOL_HISTORY "history"
|
#define DMU_POOL_HISTORY "history"
|
||||||
#define DMU_POOL_PROPS "pool_props"
|
#define DMU_POOL_PROPS "pool_props"
|
||||||
#define DMU_POOL_L2CACHE "l2cache"
|
#define DMU_POOL_L2CACHE "l2cache"
|
||||||
|
#define DMU_POOL_FEATURES_FOR_READ "features_for_read"
|
||||||
|
|
||||||
#endif /* _SYS_DMU_H */
|
#endif /* _SYS_DMU_H */
|
||||||
|
|
|
@ -80,6 +80,7 @@ typedef enum grub_zfs_endian
|
||||||
#define ZPOOL_CONFIG_DDT_HISTOGRAM "ddt_histogram"
|
#define ZPOOL_CONFIG_DDT_HISTOGRAM "ddt_histogram"
|
||||||
#define ZPOOL_CONFIG_DDT_OBJ_STATS "ddt_object_stats"
|
#define ZPOOL_CONFIG_DDT_OBJ_STATS "ddt_object_stats"
|
||||||
#define ZPOOL_CONFIG_DDT_STATS "ddt_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
|
* 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
|
* 'vdev_state' entry. This is because a device can be in multiple states, such
|
||||||
|
|
Loading…
Reference in a new issue