Precede each serialized folio entry in the preserved memfd folio array with struct kho_ser_hdr via DECLARE_KHO_SER so future per-folio memfd features can append fields to struct memfd_luo_folio_ser without breaking compatibility between adjacent kernels. Allocate the preserved folio array using kho_ser_size(memfd_luo_folio_ser) per entry and initialize each entry feature header in memfd_luo_preserve_folios(). On the incoming path in memfd_luo_discard_folios() and memfd_luo_retrieve_folios(), validate each entry feature header with kho_ser_validate() and advance between entries using fhdr->size so entries written with a different feature layout are traversed accurately. Signed-off-by: Tarun Sahu --- include/linux/kho/abi/memfd.h | 6 ++-- mm/memfd_luo.c | 66 +++++++++++++++++++++++++---------- 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/include/linux/kho/abi/memfd.h b/include/linux/kho/abi/memfd.h index 27f8880ee593..1aad47ce7322 100644 --- a/include/linux/kho/abi/memfd.h +++ b/include/linux/kho/abi/memfd.h @@ -51,6 +51,8 @@ * @pfn: The page frame number of the folio. * @flags: Flags to describe the state of the folio. * @index: The page offset (pgoff_t) of the folio within the original file. + * + * Preceded by &struct kho_ser_hdr. */ struct memfd_luo_folio_ser { u64 pfn:52; @@ -58,9 +60,7 @@ struct memfd_luo_folio_ser { u64 index; }; -static_assert(sizeof(struct memfd_luo_folio_ser) == 16); -static_assert(!IS_ENABLED(CONFIG_64BIT) || - __alignof__(struct memfd_luo_folio_ser) == 8); +DECLARE_KHO_SER(memfd_luo_folio_ser, 16, 0, 0); /* * The set of seals this version supports preserving. If support for any new diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c index 94510f73a606..c00daa8a508e 100644 --- a/mm/memfd_luo.c +++ b/mm/memfd_luo.c @@ -86,10 +86,10 @@ static int memfd_luo_preserve_folios(struct file *file, struct memfd_luo_ser *ser, - struct memfd_luo_folio_ser **out_folios_ser) + DECLARE_KHO_SER_HDR(memfd_luo_folio_ser, **out_folios_ser)) { struct inode *inode = file_inode(file); - struct memfd_luo_folio_ser *folios_ser; + DECLARE_KHO_SER_HDR(memfd_luo_folio_ser, *folios_ser); unsigned int max_folios; long i, size, nr_pinned; struct folio **folios; @@ -138,14 +138,16 @@ static int memfd_luo_preserve_folios(struct file *file, } nr_folios = nr_pinned; - folios_ser = vcalloc(nr_folios, sizeof(*folios_ser)); + folios_ser = vcalloc(nr_folios, kho_ser_size(memfd_luo_folio_ser)); if (!folios_ser) { err = -ENOMEM; goto err_unpin; } for (i = 0; i < nr_folios; i++) { - struct memfd_luo_folio_ser *pfolio = &folios_ser[i]; + DECLARE_KHO_SER_HDR(memfd_luo_folio_ser, *fhdr) = + (void *)folios_ser + i * kho_ser_size(memfd_luo_folio_ser); + struct memfd_luo_folio_ser *pfolio; struct folio *folio = folios[i]; err = kho_preserve_folio(folio); @@ -195,6 +197,8 @@ static int memfd_luo_preserve_folios(struct file *file, folio_unlock(folio); + kho_ser_init(fhdr, memfd_luo_folio_ser); + pfolio = kho_ser_payload(fhdr, memfd_luo_folio_ser); pfolio->pfn = folio_pfn(folio); pfolio->flags = MEMFD_LUO_FOLIO_DIRTY | MEMFD_LUO_FOLIO_UPTODATE; pfolio->index = folio->index; @@ -228,7 +232,7 @@ static int memfd_luo_preserve_folios(struct file *file, } static void memfd_luo_unpreserve_folios(DECLARE_KHO_SER_HDR(kho_vmalloc, *folios_fhdr), - struct memfd_luo_folio_ser *folios_ser, + const DECLARE_KHO_SER_HDR(memfd_luo_folio_ser, *folios_ser), u64 nr_folios) { long i; @@ -239,7 +243,10 @@ static void memfd_luo_unpreserve_folios(DECLARE_KHO_SER_HDR(kho_vmalloc, *folios kho_unpreserve_vmalloc(folios_fhdr); for (i = 0; i < nr_folios; i++) { - const struct memfd_luo_folio_ser *pfolio = &folios_ser[i]; + const DECLARE_KHO_SER_HDR(memfd_luo_folio_ser, *fhdr) = + (const void *)folios_ser + i * kho_ser_size(memfd_luo_folio_ser); + const struct memfd_luo_folio_ser *pfolio = + kho_ser_payload(fhdr, memfd_luo_folio_ser); struct folio *folio; if (!pfolio->pfn) @@ -277,7 +284,7 @@ memfd_luo_ser_init(DECLARE_KHO_SER_HDR(memfd_luo_ser, *fhdr)) static int memfd_luo_preserve(struct liveupdate_file_op_args *args) { struct inode *inode = file_inode(args->file); - struct memfd_luo_folio_ser *folios_ser; + DECLARE_KHO_SER_HDR(memfd_luo_folio_ser, *folios_ser); DECLARE_KHO_SER_HDR(memfd_luo_ser, *fhdr); struct memfd_luo_ser *ser; int err = 0, seals; @@ -384,16 +391,23 @@ static void memfd_luo_unpreserve(struct liveupdate_file_op_args *args) inode_unlock(inode); } -static void memfd_luo_discard_folios(const struct memfd_luo_folio_ser *folios_ser, +static void memfd_luo_discard_folios(const DECLARE_KHO_SER_HDR(memfd_luo_folio_ser, *folios_ser), u64 nr_folios) { + const DECLARE_KHO_SER_HDR(memfd_luo_folio_ser, *fhdr) = folios_ser; u64 i; - for (i = 0; i < nr_folios; i++) { - const struct memfd_luo_folio_ser *pfolio = &folios_ser[i]; + for (i = 0; i < nr_folios; i++, fhdr = (const void *)fhdr + fhdr->size) { + const struct memfd_luo_folio_ser *pfolio; struct folio *folio; phys_addr_t phys; + if (kho_ser_validate(fhdr, memfd_luo_folio_ser)) { + pr_warn("invalid folio feature header, folios not discarded\n"); + return; + } + + pfolio = kho_ser_payload(fhdr, memfd_luo_folio_ser); if (!pfolio->pfn) continue; @@ -411,7 +425,7 @@ static void memfd_luo_discard_folios(const struct memfd_luo_folio_ser *folios_se static void memfd_luo_finish(struct liveupdate_file_op_args *args) { - struct memfd_luo_folio_ser *folios_ser; + DECLARE_KHO_SER_HDR(memfd_luo_folio_ser, *folios_ser); DECLARE_KHO_SER_HDR(memfd_luo_ser, *fhdr); struct memfd_luo_ser *ser; @@ -447,9 +461,10 @@ static void memfd_luo_finish(struct liveupdate_file_op_args *args) } static int memfd_luo_retrieve_folios(struct file *file, - struct memfd_luo_folio_ser *folios_ser, + const DECLARE_KHO_SER_HDR(memfd_luo_folio_ser, *folios_ser), u64 nr_folios) { + const DECLARE_KHO_SER_HDR(memfd_luo_folio_ser, *fhdr) = folios_ser; struct inode *inode = file_inode(file); struct address_space *mapping = inode->i_mapping; struct folio *folio; @@ -457,12 +472,20 @@ static int memfd_luo_retrieve_folios(struct file *file, int err = -EIO; long i; - for (i = 0; i < nr_folios; i++) { - const struct memfd_luo_folio_ser *pfolio = &folios_ser[i]; + for (i = 0; i < nr_folios; i++, fhdr = (const void *)fhdr + fhdr->size) { + const struct memfd_luo_folio_ser *pfolio; phys_addr_t phys; u64 index; int flags; + err = kho_ser_validate(fhdr, memfd_luo_folio_ser); + if (err) { + pr_err("memfd_luo_folio_ser feature validation failed: %pe\n", + ERR_PTR(err)); + goto put_folios; + } + + pfolio = kho_ser_payload(fhdr, memfd_luo_folio_ser); if (!pfolio->pfn) continue; @@ -472,7 +495,7 @@ static int memfd_luo_retrieve_folios(struct file *file, pr_err("Unable to restore folio at physical address: %llx\n", phys); err = -EIO; - goto put_folios; + goto next_put_folios; } index = pfolio->index; flags = pfolio->flags; @@ -524,15 +547,22 @@ static int memfd_luo_retrieve_folios(struct file *file, unlock_folio: folio_unlock(folio); folio_put(folio); +next_put_folios: + i++; + fhdr = (const void *)fhdr + fhdr->size; put_folios: /* * Note: don't free the folios already added to the file. They will be * freed when the file is freed. Free the ones not added yet here. */ - for (long j = i + 1; j < nr_folios; j++) { - const struct memfd_luo_folio_ser *pfolio = &folios_ser[j]; + for (; i < nr_folios; i++, fhdr = (const void *)fhdr + fhdr->size) { + const struct memfd_luo_folio_ser *pfolio; phys_addr_t phys; + if (kho_ser_validate(fhdr, memfd_luo_folio_ser)) + break; + + pfolio = kho_ser_payload(fhdr, memfd_luo_folio_ser); if (!pfolio->pfn) continue; @@ -549,7 +579,7 @@ static int memfd_luo_retrieve_folios(struct file *file, static int memfd_luo_retrieve(struct liveupdate_file_op_args *args) { - struct memfd_luo_folio_ser *folios_ser; + DECLARE_KHO_SER_HDR(memfd_luo_folio_ser, *folios_ser); DECLARE_KHO_SER_HDR(memfd_luo_ser, *fhdr); struct memfd_luo_ser *ser; struct file *file; -- 2.56.0.506.g506a7eabc5-goog