From e56c40ade88270bec8b50680fe34bb358919057b Mon Sep 17 00:00:00 2001 From: Avnish Chouhan Date: Mon, 19 May 2025 16:34:34 +0530 Subject: [PATCH] ieee1275: support added for multiple nvme bootpaths This patch sets mupltiple NVMe boot-devices for more robust boot. Scenario where NVMe multipaths are available, all the available bootpaths (Max 5) will be added as the boot-device. Signed-off-by: Avnish Chouhan Link: https://lore.kernel.org/r/20250519110434.28686-1-avnish@linux.ibm.com --- grub-core/osdep/linux/ofpath.c | 6 +- grub-core/osdep/unix/platform.c | 114 +++++++++++++++++++++++++++++++- include/grub/util/install.h | 3 + include/grub/util/ofpath.h | 4 ++ 4 files changed, 123 insertions(+), 4 deletions(-) diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c index dd50d785dd..66a256b18b 100644 --- a/grub-core/osdep/linux/ofpath.c +++ b/grub-core/osdep/linux/ofpath.c @@ -209,7 +209,7 @@ find_obppath (const char *sysfs_path_orig) } } -static char * +char * xrealpath (const char *in) { char *out; @@ -224,7 +224,7 @@ xrealpath (const char *in) return out; } -static char * +char * block_device_get_sysfs_path_and_link(const char *devicenode) { char *rpath; @@ -613,7 +613,7 @@ of_path_get_nvme_nsid (const char* devname) return nsid; } -static char * +char * nvme_get_syspath (const char *nvmedev) { char *sysfs_path, *controller_node; diff --git a/grub-core/osdep/unix/platform.c b/grub-core/osdep/unix/platform.c index 1e2961e006..e8e28f3d4b 100644 --- a/grub-core/osdep/unix/platform.c +++ b/grub-core/osdep/unix/platform.c @@ -28,6 +28,8 @@ #include #include #include +#include +#define BOOTDEV_BUFFER 1000 static char * get_ofpathname (const char *dev) @@ -203,6 +205,105 @@ grub_install_register_efi (const grub_disk_t *efidir_grub_disk, return 0; } + +char * +add_multiple_nvme_bootdevices (const char *install_device) +{ + char *sysfs_path, *nvme_ns, *ptr, *non_splitter_path; + unsigned int nsid; + char *multipath_boot, *ofpath, *ext_dir; + struct dirent *ep, *splitter_ep; + DIR *dp, *splitter_dp; + char *cntl_id, *dirR1, *dirR2, *splitter_info_path; + int is_FC = 0, is_splitter = 0; + + nvme_ns = grub_strstr (install_device, "nvme"); + nsid = of_path_get_nvme_nsid (nvme_ns); + if (nsid == 0) + return NULL; + + sysfs_path = nvme_get_syspath (nvme_ns); + ofpath = xasprintf ("%s",get_ofpathname (nvme_ns)); + + if (grub_strstr (ofpath, "fibre-channel")) + { + strcat (sysfs_path, "/device"); + is_FC = 1; + } + else + { + strcat (sysfs_path, "/subsystem"); + is_FC = 0; + } + if (is_FC == 0) + { + cntl_id = grub_strstr (nvme_ns, "e"); + dirR1 = xasprintf ("nvme%c",cntl_id[1]); + + splitter_info_path = xasprintf ("%s%s%s", "/sys/block/", nvme_ns, "/device"); + splitter_dp = opendir (splitter_info_path); + if (!splitter_dp) + return NULL; + + while ((splitter_ep = readdir (splitter_dp)) != NULL) + { + if (grub_strstr (splitter_ep->d_name, "nvme")) + { + if (grub_strstr (splitter_ep->d_name, dirR1)) + continue; + + ext_dir = grub_strstr (splitter_ep->d_name, "e"); + if (!(grub_strstr (ext_dir, "n"))) + { + dirR2 = xasprintf("%s", splitter_ep->d_name); + is_splitter = 1; + break; + } + } + } + closedir (splitter_dp); + } + sysfs_path = xrealpath (sysfs_path); + dp = opendir (sysfs_path); + if (!dp) + return NULL; + + ptr = multipath_boot = xmalloc (BOOTDEV_BUFFER); + if (is_splitter == 0 && is_FC == 0) + { + non_splitter_path = xasprintf ("%s%s%x:1 ", get_ofpathname (dirR1), "/namespace@", nsid); + strncpy (ptr, non_splitter_path, strlen (non_splitter_path)); + ptr += strlen (non_splitter_path); + free (non_splitter_path); + } + else + { + while ((ep = readdir (dp)) != NULL) + { + char *path; + if (grub_strstr (ep->d_name, "nvme")) + { + if (is_FC == 0 && !grub_strstr (ep->d_name, dirR1) && !grub_strstr (ep->d_name, dirR2)) + continue; + path = xasprintf ("%s%s%x ", get_ofpathname (ep->d_name), "/namespace@", nsid); + if ((strlen (multipath_boot) + strlen (path)) > BOOTDEV_BUFFER) + { + grub_util_warn (_("Maximum five entries are allowed in the bootlist")); + free (path); + break; + } + strncpy (ptr, path, strlen (path)); + ptr += strlen (path); + free (path); + } + } + } + *--ptr = '\0'; + closedir (dp); + + return multipath_boot; +} + void grub_install_register_ieee1275 (int is_prep, const char *install_device, int partno, const char *relpath) @@ -242,8 +343,19 @@ grub_install_register_ieee1275 (int is_prep, const char *install_device, } *ptr = '\0'; } + else if (grub_strstr (install_device, "nvme")) + { + boot_device = add_multiple_nvme_bootdevices (install_device); + } else - boot_device = get_ofpathname (install_device); + { + boot_device = get_ofpathname (install_device); + if (grub_strstr (boot_device, "nvme-of")) + { + free (boot_device); + boot_device = add_multiple_nvme_bootdevices (install_device); + } + } if (grub_util_exec ((const char * []){ "nvsetenv", "boot-device", boot_device, NULL })) diff --git a/include/grub/util/install.h b/include/grub/util/install.h index 563cf68e94..2f220ed3aa 100644 --- a/include/grub/util/install.h +++ b/include/grub/util/install.h @@ -223,6 +223,9 @@ grub_install_get_image_targets_string (void); const char * grub_util_get_target_dirname (const struct grub_install_image_target_desc *t); +char * +add_multiple_nvme_bootdevices (const char *install_device); + void grub_install_create_envblk_file (const char *name); diff --git a/include/grub/util/ofpath.h b/include/grub/util/ofpath.h index 7ab377c7cc..7e75866853 100644 --- a/include/grub/util/ofpath.h +++ b/include/grub/util/ofpath.h @@ -30,5 +30,9 @@ int add_filename_to_pile (char *filename, struct ofpath_files_list_root* root); void find_file (char* filename, char* directory, struct ofpath_files_list_root* root, int max_depth, int depth); char* of_find_fc_host (char* host_wwpn); void free_ofpath_files_list (struct ofpath_files_list_root* root); +char* nvme_get_syspath (const char *nvmedev); +char* block_device_get_sysfs_path_and_link (const char *devicenode); +char* xrealpath (const char *in); +unsigned int of_path_get_nvme_nsid (const char* devname); #endif /* ! GRUB_OFPATH_MACHINE_UTIL_HEADER */ -- 2.49.0