summaryrefslogtreecommitdiff
path: root/fs/zfs/zfs.c
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2024-04-17 10:08:03 -0600
committerTom Rini <trini@konsulko.com>2024-04-17 10:08:59 -0600
commit198f33a2ebdc0039d3b0a521e83a75496aadde82 (patch)
tree779998a47c6e62ea1d9245ea429ff7f7c308de8a /fs/zfs/zfs.c
parentbeac9581531d7882df8c1de653db18fb3ab4100a (diff)
parent730c69f133edf8a38c9479e116dbd944ebb2cb6c (diff)
Merge patch series "zfs: Fix zfs support on aarch64"
mwleeds@mailtundra.com <mwleeds@mailtundra.com> says: This patch series is needed to get U-Boot to boot from a ZFS filesystem on an aarch64 computer. Some of the patches are not architecture specific and would be needed to boot ZFS on other platforms as well. The ZFS support in U-Boot hasn't been substantively touched in several years and to me it seems like it must have been broken for a long time on all platforms, but I have only tested on aarch64. Since there doesn't seem to be a mantainer for this area who I can cc, I'm hoping these patches get seen and pulled in by a general U-Boot maintainer. [trini: Per Igor's comment and Phaedrus agreement, dropped his Tested-by on the patches themselves]
Diffstat (limited to 'fs/zfs/zfs.c')
-rw-r--r--fs/zfs/zfs.c30
1 files changed, 26 insertions, 4 deletions
diff --git a/fs/zfs/zfs.c b/fs/zfs/zfs.c
index 1fec96cd5ce..bfc11fa6676 100644
--- a/fs/zfs/zfs.c
+++ b/fs/zfs/zfs.c
@@ -655,7 +655,7 @@ dmu_read(dnode_end_t *dn, uint64_t blkid, void **buf,
dn->endian)
<< SPA_MINBLOCKSHIFT;
*buf = malloc(size);
- if (*buf) {
+ if (!*buf) {
err = ZFS_ERR_OUT_OF_MEMORY;
break;
}
@@ -1559,6 +1559,10 @@ nvlist_find_value(char *nvlist, char *name, int valtype, char **val,
return 0;
}
+int is_word_aligned_ptr(void *ptr) {
+ return ((uintptr_t)ptr & (sizeof(void *) - 1)) == 0;
+}
+
int
zfs_nvlist_lookup_uint64(char *nvlist, char *name, uint64_t *out)
{
@@ -1574,6 +1578,20 @@ zfs_nvlist_lookup_uint64(char *nvlist, char *name, uint64_t *out)
return ZFS_ERR_BAD_FS;
}
+ /* On arm64, calling be64_to_cpu() on a value stored at a memory address
+ * that's not 8-byte aligned causes the CPU to reset. Avoid that by copying the
+ * value somewhere else if needed.
+ */
+ if (!is_word_aligned_ptr((void *)nvpair)) {
+ uint64_t *alignedptr = malloc(sizeof(uint64_t));
+ if (!alignedptr)
+ return 0;
+ memcpy(alignedptr, nvpair, sizeof(uint64_t));
+ *out = be64_to_cpu(*alignedptr);
+ free(alignedptr);
+ return 1;
+ }
+
*out = be64_to_cpu(*(uint64_t *) nvpair);
return 1;
}
@@ -1617,6 +1635,11 @@ zfs_nvlist_lookup_nvlist(char *nvlist, char *name)
&size, 0);
if (!found)
return 0;
+
+ /* Allocate 12 bytes in addition to the nvlist size: One uint32 before the
+ * nvlist to hold the encoding method, and two zero uint32's after the
+ * nvlist as the NULL terminator.
+ */
ret = calloc(1, size + 3 * sizeof(uint32_t));
if (!ret)
return 0;
@@ -2112,7 +2135,7 @@ zfs_read(zfs_file_t file, char *buf, uint64_t len)
* Find requested blkid and the offset within that block.
*/
uint64_t blkid = file->offset + red;
- blkid = do_div(blkid, blksz);
+ uint64_t blkoff = do_div(blkid, blksz);
free(data->file_buf);
data->file_buf = 0;
@@ -2127,8 +2150,7 @@ zfs_read(zfs_file_t file, char *buf, uint64_t len)
movesize = min(length, data->file_end - (int)file->offset - red);
- memmove(buf, data->file_buf + file->offset + red
- - data->file_start, movesize);
+ memmove(buf, data->file_buf + blkoff, movesize);
buf += movesize;
length -= movesize;
red += movesize;