support different endian raidframe component label. there are two on-disk formats in use in raidframe: - the component label - the parity map the parity map is a bitmap implemnented as bytes, so it has no endian issue. the component label is the problem, as most of the fields are 32 bit. this change only supports version 2 of raidframe (active since the year 2000.) as component labels are read and used before a raidPtr for the raid set has been created, there is no obvious storage for the swapped indicator, so the in-core version remains the on-disk version, while the rest of in-core label is swapped. in raidread_component_label() and raidwrite_component_label(), check if the swapped version, and if so, call new rf_swap_label() and ensure that the in-core label is native-byte order. for the write method, an on-stack copy is modified before writing, so that the in-core version remains valid. (this stack usage is below other stack usage in similar functions here.) adjust the label ioctls RAIDFRAME_GET_COMPONENT_LABEL and RAIDFRAME_GET_COMPONENT_LABEL80 to return the byte-swapped version so that eg, raidctl -s reports the right version. when performing final configuration of a raidset, report if a label swapped, and also complain if there are differently swapped versions on the other components. Index: rf_compat80.c =================================================================== RCS file: /cvsroot/src/sys/dev/raidframe/rf_compat80.c,v retrieving revision 1.14 diff -p -u -r1.14 rf_compat80.c --- rf_compat80.c 12 Dec 2019 02:15:43 -0000 1.14 +++ rf_compat80.c 25 May 2021 08:07:25 -0000 @@ -215,6 +215,10 @@ rf_get_component_label80(RF_Raid_t *raid } rf_get_component_label(raidPtr, clabel); + /* Fix-up for userland. */ + if (clabel->version == bswap32(RF_COMPONENT_LABEL_VERSION)) + clabel->version = RF_COMPONENT_LABEL_VERSION; + retcode = copyout(clabel, *clabel_ptr, sizeof(**clabel_ptr)); RF_Free(clabel, sizeof(*clabel)); Index: rf_driver.c =================================================================== RCS file: /cvsroot/src/sys/dev/raidframe/rf_driver.c,v retrieving revision 1.136 diff -p -u -r1.136 rf_driver.c --- rf_driver.c 10 Oct 2019 03:43:59 -0000 1.136 +++ rf_driver.c 25 May 2021 08:07:25 -0000 @@ -300,6 +300,8 @@ rf_Configure(RF_Raid_t *raidPtr, RF_Conf { RF_RowCol_t col; int rc; + bool swapped = false; + bool first = true; rf_lock_mutex2(configureMutex); configureCount++; @@ -430,10 +432,21 @@ rf_Configure(RF_Raid_t *raidPtr, RF_Conf printf("raid%d: Components:", raidPtr->raidid); for (col = 0; col < raidPtr->numCol; col++) { + RF_ComponentLabel_t *clabel; + bool compswapped; + printf(" %s", raidPtr->Disks[col].devname); if (RF_DEAD_DISK(raidPtr->Disks[col].status)) { printf("[**FAILED**]"); } + clabel = raidget_component_label(raidPtr, col); + compswapped = clabel->version == + bswap32(RF_COMPONENT_LABEL_VERSION); + if (first) + swapped = compswapped; + else if (swapped != compswapped) + printf("raid%d: Component %d has different endian " + "than first component.", raidPtr->raidid, col); } printf("\n"); printf("raid%d: Total Sectors: %" PRIu64 " (%" PRIu64 " MB)\n", @@ -441,6 +454,8 @@ rf_Configure(RF_Raid_t *raidPtr, RF_Conf raidPtr->totalSectors, (raidPtr->totalSectors / 1024 * (1 << raidPtr->logBytesPerSector) / 1024)); + if (swapped) + printf("raid%d: Swapped component labels.\n", raidPtr->raidid); return (0); } Index: rf_netbsdkintf.c =================================================================== RCS file: /cvsroot/src/sys/dev/raidframe/rf_netbsdkintf.c,v retrieving revision 1.393 diff -p -u -r1.393 rf_netbsdkintf.c --- rf_netbsdkintf.c 24 May 2021 07:43:15 -0000 1.393 +++ rf_netbsdkintf.c 25 May 2021 08:07:25 -0000 @@ -2264,6 +2264,7 @@ int raidfetch_component_label(RF_Raid_t *raidPtr, RF_RowCol_t col) { KASSERT(raidPtr->bytesPerSector); + return raidread_component_label(raidPtr->bytesPerSector, raidPtr->Disks[col].dev, raidPtr->raid_cinfo[col].ci_vp, @@ -2291,15 +2292,54 @@ raidflush_component_label(RF_Raid_t *rai raidPtr->raid_cinfo[col].ci_vp, label); } +/* + * Swap the label endianness. + * + * Everything in the component label is 4-byte-swapped except the version, + * which is kept in the byte-swapped version at all times, and indicates + * for the writer that a swap is necessary. + * + * For reads it is expected that out_label == clabel, but writes expect + * separate labels so only the re-swapped label is written out to disk, + * leaving the swapped-except-version internally. + * + * Only support swapping label version 2. + */ +static void +rf_swap_label(RF_ComponentLabel_t *clabel, RF_ComponentLabel_t *out_label) +{ + int *in, *out, *in_last; + + KASSERT(clabel->version == bswap32(RF_COMPONENT_LABEL_VERSION)); + + /* Don't swap the label, but do copy it. */ + out_label->version = clabel->version; + + in = &clabel->serial_number; + in_last = &clabel->future_use2[42]; + out = &out_label->serial_number; + + for (; in < in_last; in++, out++) + *out = bswap32(*in); +} static int raidread_component_label(unsigned secsize, dev_t dev, struct vnode *b_vp, RF_ComponentLabel_t *clabel) { - return raidread_component_area(dev, b_vp, clabel, + int error; + + error = raidread_component_area(dev, b_vp, clabel, sizeof(RF_ComponentLabel_t), rf_component_info_offset(), rf_component_info_size(secsize)); + + if (error == 0 && + clabel->version == bswap32(RF_COMPONENT_LABEL_VERSION)) { + rf_swap_label(clabel, clabel); + } + + return error; } /* ARGSUSED */ @@ -2340,15 +2380,24 @@ raidread_component_area(dev_t dev, struc return(error); } - static int raidwrite_component_label(unsigned secsize, dev_t dev, struct vnode *b_vp, RF_ComponentLabel_t *clabel) { - return raidwrite_component_area(dev, b_vp, clabel, + RF_ComponentLabel_t *clabel_write = clabel; + RF_ComponentLabel_t lclabel; + int error; + + if (clabel->version == bswap32(RF_COMPONENT_LABEL_VERSION)) { + clabel_write = &lclabel; + rf_swap_label(clabel, clabel_write); + } + error = raidwrite_component_area(dev, b_vp, clabel_write, sizeof(RF_ComponentLabel_t), rf_component_info_offset(), rf_component_info_size(secsize), 0); + + return error; } /* ARGSUSED */ @@ -2962,7 +3011,8 @@ rf_reasonable_label(RF_ComponentLabel_t { if ((clabel->version==RF_COMPONENT_LABEL_VERSION_1 || - clabel->version==RF_COMPONENT_LABEL_VERSION) && + clabel->version==RF_COMPONENT_LABEL_VERSION || + clabel->version == bswap32(RF_COMPONENT_LABEL_VERSION)) && (clabel->clean == RF_RAID_CLEAN || clabel->clean == RF_RAID_DIRTY) && clabel->row >=0 && @@ -3404,8 +3454,9 @@ rf_cleanup_config_set(RF_ConfigSet_t *cs void raid_init_component_label(RF_Raid_t *raidPtr, RF_ComponentLabel_t *clabel) { - /* current version number */ - clabel->version = RF_COMPONENT_LABEL_VERSION; + /* avoid over-writing byteswapped version. */ + if (clabel->version != bswap32(RF_COMPONENT_LABEL_VERSION)) + clabel->version = RF_COMPONENT_LABEL_VERSION; clabel->serial_number = raidPtr->serial_number; clabel->mod_counter = raidPtr->mod_counter; @@ -3795,6 +3846,9 @@ rf_get_component_label(RF_Raid_t *raidPt return EINVAL; raid_clabel = raidget_component_label(raidPtr, column); memcpy(clabel, raid_clabel, sizeof *clabel); + /* Fix-up for userland. */ + if (clabel->version == bswap32(RF_COMPONENT_LABEL_VERSION)) + clabel->version = RF_COMPONENT_LABEL_VERSION; return 0; }