Patch driver builds affected by pfn_valid regression for cos-gpu-driver-builder

linux-5.10.210/ linux-5.15.149 has modified the non-ARCH-specific
pfn_valid() to use __rcu_read_lock/unlock[1][2] that is marked GPL and
cannot be used for non open source nvidia gpu driver builds.

As a workaround, reuse the old implementation for pfn_valid.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/include/linux/mmzone.h?h=v5.10.210&id=90ad17575d26874287271127d43ef3c2af876cea
[2] https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/include/linux/mmzone.h?h=v5.15.149&id=b448de2459b6d62a53892487ab18b7d823ff0529

BUG=b/326550811, b/326701851
TEST=manual
RELEASE_NOTE=Fix driver builds for drivers affected with pfn_valid build
errors.

Change-Id: I0d4f272a73cab34f027104a66830c57147fb8e22
Reviewed-on: https://cos-review.googlesource.com/c/cos/tools/+/67830
Cloud-Build: GCB Service account <228075978874@cloudbuild.gserviceaccount.com>
Tested-by: Arnav Kansal <rnv@google.com>
Reviewed-by: Kevin Berry <kpberry@google.com>
diff --git a/src/cmd/cos_gpu_driver_builder/Dockerfile b/src/cmd/cos_gpu_driver_builder/Dockerfile
index 69a0553..9917a3b 100644
--- a/src/cmd/cos_gpu_driver_builder/Dockerfile
+++ b/src/cmd/cos_gpu_driver_builder/Dockerfile
@@ -6,6 +6,7 @@
 RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} CGO_ENABLED=0 go build -o cos-gpu-driver-builder main.go
 FROM ubuntu:latest
 LABEL maintainer="cos-containers@google.com"
+COPY --from=go-builder /work/src/cmd/cos_gpu_driver_builder/driver_patches/ /build/patches/
 COPY --from=go-builder /work/src/cmd/cos_gpu_driver_builder/cos-gpu-driver-builder /cos-gpu-driver-builder
-RUN apt-get update && apt-get -y install ca-certificates xz-utils kmod make libc-dev libc6-dev libelf-dev binutils
+RUN apt-get update && apt-get -y install ca-certificates xz-utils kmod make libc-dev libc6-dev libelf-dev binutils patch
 ENTRYPOINT ["/cos-gpu-driver-builder"]
diff --git a/src/cmd/cos_gpu_driver_builder/driver_patches/nvidia-drivers-470-5.10-gpl-pfn_valid.patch b/src/cmd/cos_gpu_driver_builder/driver_patches/nvidia-drivers-470-5.10-gpl-pfn_valid.patch
new file mode 100644
index 0000000..93f2377
--- /dev/null
+++ b/src/cmd/cos_gpu_driver_builder/driver_patches/nvidia-drivers-470-5.10-gpl-pfn_valid.patch
@@ -0,0 +1,55 @@
+linux-5.10.210 [1] has modified the non-ARCH-specific pfn_valid() to use
+__rcu_read_lock/unlock[1] that is marked GPL and cannot be used non open source
+nvidia gpu driver builds.
+
+As a workaround, reuse the old implementation of pfn_valid.
+
+[1] https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/include/linux/mmzone.h?h=v5.10.210&id=90ad17575d26874287271127d43ef3c2af876cea
+diff --git a/kernel/common/inc/nv-linux.h b/kernel/common/inc/nv-linux.h
+index f8df9e3..a5c8634 100644
+--- kernel/common/inc/nv-linux.h
++++ kernel/common/inc/nv-linux.h
+@@ -1990,2 +1990,20 @@
+ 
++#if defined(CONFIG_HAVE_ARCH_PFN_VALID) || LINUX_VERSION_CODE < KERNEL_VERSION(5,10,210)
++#  define nv_pfn_valid pfn_valid
++#else
++/* pre-5.10.210 kernel pfn_valid version without GPL rcu_read_lock/unlock() */
++static inline int nv_pfn_valid(unsigned long pfn)
++{
++        struct mem_section *ms;
++
++        if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
++                return 0;
++
++        ms = __pfn_to_section(pfn);
++        if (!valid_section(ms))
++                return 0;
++
++        return early_section(ms) || pfn_section_valid(ms, pfn);
++}
++#endif
+ #endif /* _NV_LINUX_H_ */
+diff --git a/kernel/nvidia/nv-mmap.c b/kernel/nvidia/nv-mmap.c
+index 5926d3c..d2052c4 100644
+--- kernel/nvidia/nv-mmap.c
++++ kernel/nvidia/nv-mmap.c
+@@ -576,3 +576,3 @@
+             if (!IS_REG_OFFSET(nv, access_start, access_len) &&
+-                (pfn_valid(PFN_DOWN(mmap_start))))
++                (nv_pfn_valid(PFN_DOWN(mmap_start))))
+             {
+diff --git a/kernel/nvidia/os-mlock.c b/kernel/nvidia/os-mlock.c
+index c97ef4c..44e37c2 100644
+--- kernel/nvidia/os-mlock.c
++++ kernel/nvidia/os-mlock.c
+@@ -102,3 +102,3 @@
+         if ((nv_follow_pfn(vma, (start + (i * PAGE_SIZE)), &pfn) < 0) ||
+-            (!pfn_valid(pfn)))
++            (!nv_pfn_valid(pfn)))
+         {
+@@ -176,3 +176,3 @@
+ 
+-    if (pfn_valid(pfn))
++    if (nv_pfn_valid(pfn))
+     {
diff --git a/src/cmd/cos_gpu_driver_builder/driver_patches/nvidia-drivers-470-5.15-gpl-pfn_valid.patch b/src/cmd/cos_gpu_driver_builder/driver_patches/nvidia-drivers-470-5.15-gpl-pfn_valid.patch
new file mode 100644
index 0000000..b63694a
--- /dev/null
+++ b/src/cmd/cos_gpu_driver_builder/driver_patches/nvidia-drivers-470-5.15-gpl-pfn_valid.patch
@@ -0,0 +1,58 @@
+linux-5.15.149 [1] has modified the non-ARCH-specific pfn_valid() to use
+__rcu_read_lock/unlock[1] that is marked GPL and cannot be used non open source
+nvidia gpu driver builds.
+
+As a workaround, reuse the old implementation of pfn_valid.
+
+[1] https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/include/linux/mmzone.h?h=v5.15.149&id=b448de2459b6d62a53892487ab18b7d823ff0529
+diff --git a/kernel/common/inc/nv-linux.h b/kernel/common/inc/nv-linux.h
+index f8df9e3..a5c8634 100644
+--- kernel/common/inc/nv-linux.h
++++ kernel/common/inc/nv-linux.h
+@@ -1990,2 +1990,23 @@
+ 
++#if defined(CONFIG_HAVE_ARCH_PFN_VALID) || LINUX_VERSION_CODE < KERNEL_VERSION(5,15,149)
++#  define nv_pfn_valid pfn_valid
++#else
++/* pre-5.15.149 kernel pfn_valid version without GPL rcu_read_lock/unlock() */
++static inline int nv_pfn_valid(unsigned long pfn)
++{
++        struct mem_section *ms;
++
++        if (PHYS_PFN(PFN_PHYS(pfn)) != pfn)
++                return 0;
++
++        if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
++                return 0;
++
++        ms = __pfn_to_section(pfn);
++        if (!valid_section(ms))
++                return 0;
++
++        return early_section(ms) || pfn_section_valid(ms, pfn);
++}
++#endif
+ #endif /* _NV_LINUX_H_ */
+diff --git a/kernel/nvidia/nv-mmap.c b/kernel/nvidia/nv-mmap.c
+index 5926d3c..d2052c4 100644
+--- kernel/nvidia/nv-mmap.c
++++ kernel/nvidia/nv-mmap.c
+@@ -576,3 +576,3 @@
+             if (!IS_REG_OFFSET(nv, access_start, access_len) &&
+-                (pfn_valid(PFN_DOWN(mmap_start))))
++                (nv_pfn_valid(PFN_DOWN(mmap_start))))
+             {
+diff --git a/kernel/nvidia/os-mlock.c b/kernel/nvidia/os-mlock.c
+index c97ef4c..44e37c2 100644
+--- kernel/nvidia/os-mlock.c
++++ kernel/nvidia/os-mlock.c
+@@ -102,3 +102,3 @@
+         if ((nv_follow_pfn(vma, (start + (i * PAGE_SIZE)), &pfn) < 0) ||
+-            (!pfn_valid(pfn)))
++            (!nv_pfn_valid(pfn)))
+         {
+@@ -176,3 +176,3 @@
+ 
+-    if (pfn_valid(pfn))
++    if (nv_pfn_valid(pfn))
+     {
diff --git a/src/cmd/cos_gpu_driver_builder/driver_patches/nvidia-drivers-525-5.10-gpl-pfn_valid.patch b/src/cmd/cos_gpu_driver_builder/driver_patches/nvidia-drivers-525-5.10-gpl-pfn_valid.patch
new file mode 100644
index 0000000..a2d9346
--- /dev/null
+++ b/src/cmd/cos_gpu_driver_builder/driver_patches/nvidia-drivers-525-5.10-gpl-pfn_valid.patch
@@ -0,0 +1,55 @@
+linux-5.10.210 [1] has modified the non-ARCH-specific pfn_valid() to use
+__rcu_read_lock/unlock[1] that is marked GPL and cannot be used non open source
+nvidia gpu driver builds.
+
+As a workaround, reuse the old implementation of pfn_valid.
+
+[1] https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/include/linux/mmzone.h?h=v5.10.210&id=90ad17575d26874287271127d43ef3c2af876cea
+diff --git a/kernel/common/inc/nv-linux.h b/kernel/common/inc/nv-linux.h
+index f8df9e3..a5c8634 100644
+--- kernel/common/inc/nv-linux.h
++++ kernel/common/inc/nv-linux.h
+@@ -2000,2 +2000,20 @@
+ 
++#if defined(CONFIG_HAVE_ARCH_PFN_VALID) || LINUX_VERSION_CODE < KERNEL_VERSION(5,10,210)
++#  define nv_pfn_valid pfn_valid
++#else
++/* pre-5.10.210 kernel pfn_valid version without GPL rcu_read_lock/unlock() */
++static inline int nv_pfn_valid(unsigned long pfn)
++{
++        struct mem_section *ms;
++
++        if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
++                return 0;
++
++        ms = __pfn_to_section(pfn);
++        if (!valid_section(ms))
++                return 0;
++
++        return early_section(ms) || pfn_section_valid(ms, pfn);
++}
++#endif
+ #endif /* _NV_LINUX_H_ */
+diff --git a/kernel/nvidia/nv-mmap.c b/kernel/nvidia/nv-mmap.c
+index 5926d3c..d2052c4 100644
+--- kernel/nvidia/nv-mmap.c
++++ kernel/nvidia/nv-mmap.c
+@@ -576,3 +576,3 @@
+             if (!IS_REG_OFFSET(nv, access_start, access_len) &&
+-                (pfn_valid(PFN_DOWN(mmap_start))))
++                (nv_pfn_valid(PFN_DOWN(mmap_start))))
+             {
+diff --git a/kernel/nvidia/os-mlock.c b/kernel/nvidia/os-mlock.c
+index c97ef4c..44e37c2 100644
+--- kernel/nvidia/os-mlock.c
++++ kernel/nvidia/os-mlock.c
+@@ -102,3 +102,3 @@
+         if ((nv_follow_pfn(vma, (start + (i * PAGE_SIZE)), &pfn) < 0) ||
+-            (!pfn_valid(pfn)))
++            (!nv_pfn_valid(pfn)))
+         {
+@@ -176,3 +176,3 @@
+ 
+-    if (pfn_valid(pfn))
++    if (nv_pfn_valid(pfn))
+     {
diff --git a/src/cmd/cos_gpu_driver_builder/driver_patches/nvidia-drivers-525-5.15-gpl-pfn_valid.patch b/src/cmd/cos_gpu_driver_builder/driver_patches/nvidia-drivers-525-5.15-gpl-pfn_valid.patch
new file mode 100644
index 0000000..7ac8cc4
--- /dev/null
+++ b/src/cmd/cos_gpu_driver_builder/driver_patches/nvidia-drivers-525-5.15-gpl-pfn_valid.patch
@@ -0,0 +1,58 @@
+linux-5.15.149 [1] has modified the non-ARCH-specific pfn_valid() to use
+__rcu_read_lock/unlock[1] that is marked GPL and cannot be used non open source
+nvidia gpu driver builds.
+
+As a workaround, reuse the old implementation of pfn_valid.
+
+[1] https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/include/linux/mmzone.h?h=v5.15.149&id=b448de2459b6d62a53892487ab18b7d823ff0529
+diff --git a/kernel/common/inc/nv-linux.h b/kernel/common/inc/nv-linux.h
+index f8df9e3..a5c8634 100644
+--- kernel/common/inc/nv-linux.h
++++ kernel/common/inc/nv-linux.h
+@@ -2000,2 +2000,23 @@
+ 
++#if defined(CONFIG_HAVE_ARCH_PFN_VALID) || LINUX_VERSION_CODE < KERNEL_VERSION(5,15,149)
++#  define nv_pfn_valid pfn_valid
++#else
++/* pre-5.15.149 kernel pfn_valid version without GPL rcu_read_lock/unlock() */
++static inline int nv_pfn_valid(unsigned long pfn)
++{
++        struct mem_section *ms;
++
++        if (PHYS_PFN(PFN_PHYS(pfn)) != pfn)
++                return 0;
++
++        if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
++                return 0;
++
++        ms = __pfn_to_section(pfn);
++        if (!valid_section(ms))
++                return 0;
++
++        return early_section(ms) || pfn_section_valid(ms, pfn);
++}
++#endif
+ #endif /* _NV_LINUX_H_ */
+diff --git a/kernel/nvidia/nv-mmap.c b/kernel/nvidia/nv-mmap.c
+index 5926d3c..d2052c4 100644
+--- kernel/nvidia/nv-mmap.c
++++ kernel/nvidia/nv-mmap.c
+@@ -576,3 +576,3 @@
+             if (!IS_REG_OFFSET(nv, access_start, access_len) &&
+-                (pfn_valid(PFN_DOWN(mmap_start))))
++                (nv_pfn_valid(PFN_DOWN(mmap_start))))
+             {
+diff --git a/kernel/nvidia/os-mlock.c b/kernel/nvidia/os-mlock.c
+index c97ef4c..44e37c2 100644
+--- kernel/nvidia/os-mlock.c
++++ kernel/nvidia/os-mlock.c
+@@ -102,3 +102,3 @@
+         if ((nv_follow_pfn(vma, (start + (i * PAGE_SIZE)), &pfn) < 0) ||
+-            (!pfn_valid(pfn)))
++            (!nv_pfn_valid(pfn)))
+         {
+@@ -176,3 +176,3 @@
+ 
+-    if (pfn_valid(pfn))
++    if (nv_pfn_valid(pfn))
+     {
diff --git a/src/cmd/cos_gpu_driver_builder/driver_patches/nvidia-drivers-535-5.10-gpl-pfn_valid.patch b/src/cmd/cos_gpu_driver_builder/driver_patches/nvidia-drivers-535-5.10-gpl-pfn_valid.patch
new file mode 100644
index 0000000..b2bbd43
--- /dev/null
+++ b/src/cmd/cos_gpu_driver_builder/driver_patches/nvidia-drivers-535-5.10-gpl-pfn_valid.patch
@@ -0,0 +1,55 @@
+linux-5.10.210 [1] has modified the non-ARCH-specific pfn_valid() to use
+__rcu_read_lock/unlock[1] that is marked GPL and cannot be used non open source
+nvidia gpu driver builds.
+
+As a workaround, reuse the old implementation of pfn_valid.
+
+[1] https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/include/linux/mmzone.h?h=v5.10.210&id=90ad17575d26874287271127d43ef3c2af876cea
+diff --git a/kernel/common/inc/nv-linux.h b/kernel/common/inc/nv-linux.h
+index f8df9e3..a5c8634 100644
+--- kernel/common/inc/nv-linux.h
++++ kernel/common/inc/nv-linux.h
+@@ -2065,2 +2065,20 @@
+ 
++#if defined(CONFIG_HAVE_ARCH_PFN_VALID) || LINUX_VERSION_CODE < KERNEL_VERSION(5,10,210)
++#  define nv_pfn_valid pfn_valid
++#else
++/* pre-5.10.210 kernel pfn_valid version without GPL rcu_read_lock/unlock() */
++static inline int nv_pfn_valid(unsigned long pfn)
++{
++        struct mem_section *ms;
++
++        if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
++                return 0;
++
++        ms = __pfn_to_section(pfn);
++        if (!valid_section(ms))
++                return 0;
++
++        return early_section(ms) || pfn_section_valid(ms, pfn);
++}
++#endif
+ #endif /* _NV_LINUX_H_ */
+diff --git a/kernel/nvidia/nv-mmap.c b/kernel/nvidia/nv-mmap.c
+index 5926d3c..d2052c4 100644
+--- kernel/nvidia/nv-mmap.c
++++ kernel/nvidia/nv-mmap.c
+@@ -576,3 +576,3 @@
+             if (!IS_REG_OFFSET(nv, access_start, access_len) &&
+-                (pfn_valid(PFN_DOWN(mmap_start))))
++                (nv_pfn_valid(PFN_DOWN(mmap_start))))
+             {
+diff --git a/kernel/nvidia/os-mlock.c b/kernel/nvidia/os-mlock.c
+index c97ef4c..44e37c2 100644
+--- kernel/nvidia/os-mlock.c
++++ kernel/nvidia/os-mlock.c
+@@ -102,3 +102,3 @@
+         if ((nv_follow_pfn(vma, (start + (i * PAGE_SIZE)), &pfn) < 0) ||
+-            (!pfn_valid(pfn)))
++            (!nv_pfn_valid(pfn)))
+         {
+@@ -176,3 +176,3 @@
+ 
+-    if (pfn_valid(pfn))
++    if (nv_pfn_valid(pfn))
+     {
diff --git a/src/cmd/cos_gpu_driver_builder/driver_patches/nvidia-drivers-535-5.15-gpl-pfn_valid.patch b/src/cmd/cos_gpu_driver_builder/driver_patches/nvidia-drivers-535-5.15-gpl-pfn_valid.patch
new file mode 100644
index 0000000..5631e98
--- /dev/null
+++ b/src/cmd/cos_gpu_driver_builder/driver_patches/nvidia-drivers-535-5.15-gpl-pfn_valid.patch
@@ -0,0 +1,58 @@
+linux-5.15.149 [1] has modified the non-ARCH-specific pfn_valid() to use
+__rcu_read_lock/unlock[1] that is marked GPL and cannot be used non open source
+nvidia gpu driver builds.
+
+As a workaround, reuse the old implementation of pfn_valid.
+
+[1] https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/include/linux/mmzone.h?h=v5.15.149&id=b448de2459b6d62a53892487ab18b7d823ff0529
+diff --git a/kernel/common/inc/nv-linux.h b/kernel/common/inc/nv-linux.h
+index f8df9e3..a5c8634 100644
+--- kernel/common/inc/nv-linux.h
++++ kernel/common/inc/nv-linux.h
+@@ -2065,2 +2065,23 @@
+ 
++#if defined(CONFIG_HAVE_ARCH_PFN_VALID) || LINUX_VERSION_CODE < KERNEL_VERSION(5,15,149)
++#  define nv_pfn_valid pfn_valid
++#else
++/* pre-5.15.149 kernel pfn_valid version without GPL rcu_read_lock/unlock() */
++static inline int nv_pfn_valid(unsigned long pfn)
++{
++        struct mem_section *ms;
++
++        if (PHYS_PFN(PFN_PHYS(pfn)) != pfn)
++                return 0;
++
++        if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
++                return 0;
++
++        ms = __pfn_to_section(pfn);
++        if (!valid_section(ms))
++                return 0;
++
++        return early_section(ms) || pfn_section_valid(ms, pfn);
++}
++#endif
+ #endif /* _NV_LINUX_H_ */
+diff --git a/kernel/nvidia/nv-mmap.c b/kernel/nvidia/nv-mmap.c
+index 5926d3c..d2052c4 100644
+--- kernel/nvidia/nv-mmap.c
++++ kernel/nvidia/nv-mmap.c
+@@ -576,3 +576,3 @@
+             if (!IS_REG_OFFSET(nv, access_start, access_len) &&
+-                (pfn_valid(PFN_DOWN(mmap_start))))
++                (nv_pfn_valid(PFN_DOWN(mmap_start))))
+             {
+diff --git a/kernel/nvidia/os-mlock.c b/kernel/nvidia/os-mlock.c
+index c97ef4c..44e37c2 100644
+--- kernel/nvidia/os-mlock.c
++++ kernel/nvidia/os-mlock.c
+@@ -102,3 +102,3 @@
+         if ((nv_follow_pfn(vma, (start + (i * PAGE_SIZE)), &pfn) < 0) ||
+-            (!pfn_valid(pfn)))
++            (!nv_pfn_valid(pfn)))
+         {
+@@ -176,3 +176,3 @@
+ 
+-    if (pfn_valid(pfn))
++    if (nv_pfn_valid(pfn))
+     {
diff --git a/src/cmd/cos_gpu_driver_builder/internal/builder/builder.go b/src/cmd/cos_gpu_driver_builder/internal/builder/builder.go
index a554d65..3a034e9 100644
--- a/src/cmd/cos_gpu_driver_builder/internal/builder/builder.go
+++ b/src/cmd/cos_gpu_driver_builder/internal/builder/builder.go
@@ -16,6 +16,7 @@
 
 const (
 	linkerLocation        = "/bin/ld"
+	patchDir              = "/build/patches"
 	installDirTemplate    = "/install/%s"
 	defaultFilePermission = 0755
 	kernelSrcTemplate     = "usr/src/linux-headers-*"
@@ -29,13 +30,18 @@
 	return files[0]
 }
 
-func nvidiaInstallerCommand(dirName, runfile string, config gpuconfig.GPUPrecompilationConfig) *exec.Cmd {
-
+func nvidiaInstallerBuildCommand(dirName, runfile string, config gpuconfig.GPUPrecompilationConfig) *exec.Cmd {
 	cmd := exec.Command(filepath.Join(dirName, runfile), "--kernel-source-path="+kernelSrcDirectory(dirName), "--add-this-kernel", "--no-install-compat32-libs", "--silent", "--accept-license")
 	cmd.Dir = dirName
 	return cmd
 }
 
+func nvidiaInstallerPatchCommand(dirName, runfile, patchDir, patchfile string) *exec.Cmd {
+	cmd := exec.Command(filepath.Join(dirName, runfile), "--apply-patch", filepath.Join(patchDir, patchfile))
+	cmd.Dir = dirName
+	return cmd
+}
+
 func BuildPrecompiledDriver(ctx context.Context, client *storage.Client, config gpuconfig.GPUPrecompilationConfig) (string, string, error) {
 	var err error
 	dirName := fmt.Sprintf(installDirTemplate, config.Version)
@@ -74,7 +80,22 @@
 	if err = os.Chmod(filepath.Join(dirName, nvidiaInstaller), defaultFilePermission); err != nil {
 		return "", "", err
 	}
-	cmd := nvidiaInstallerCommand(dirName, nvidiaInstaller, config)
+
+	// TODO: add driver patches arg to pb.COSGPUBuildRequest
+	// hardcoded list for known patches for now.
+	patches := patchesForDriverBuild(config)
+	for _, patch := range patches {
+		cmd := nvidiaInstallerPatchCommand(dirName, nvidiaInstaller, patchDir, patch)
+		if err := utils.RunCommandAndLogOutput(cmd, false); err != nil {
+			return "", "", fmt.Errorf("error applying provided patch to NVIDIA driver package: %v", err)
+		}
+		patchedInstaller := strings.Split(nvidiaInstaller, ".run")[0] + "-custom.run"
+		if err := os.Rename(filepath.Join(dirName, patchedInstaller), filepath.Join(dirName, nvidiaInstaller)); err != nil {
+			return "", "", fmt.Errorf("error moving patched NVIDIA driver package: %v", err)
+		}
+	}
+
+	cmd := nvidiaInstallerBuildCommand(dirName, nvidiaInstaller, config)
 	if err = utils.RunCommandAndLogOutput(cmd, false); err != nil {
 		return "", "", fmt.Errorf("error running NVIDIA driver installation package: %v", err)
 	}
@@ -82,3 +103,21 @@
 	outputFileName := strings.Split(nvidiaInstaller, ".run")[0] + "-custom.run"
 	return dirName, outputFileName, nil
 }
+
+func patchesForDriverBuild(config gpuconfig.GPUPrecompilationConfig) []string {
+	pfnAffectedDriverVersions := []string{"470.199.02", "470.223.02", "525.125.06", "525.147.05", "535.104.05", "535.104.12", "535.129.03", "535.154.05"}
+	pfnAffectedMilestones := []string{"97", "101", "105"}
+	var patches []string
+	if utils.StringSliceContains(pfnAffectedDriverVersions, config.DriverVersion) && utils.StringSliceContains(pfnAffectedMilestones, config.Milestone) {
+		var kernelVersionDot string
+		if config.Milestone == "97" {
+			kernelVersionDot = "5.10"
+		} else {
+			kernelVersionDot = "5.15"
+		}
+		majorDriverVersion := strings.Split(config.DriverVersion, ".")[0]
+		patchFile := fmt.Sprintf("nvidia-drivers-%s-%s-gpl-pfn_valid.patch", majorDriverVersion, kernelVersionDot)
+		patches = append(patches, patchFile)
+	}
+	return patches
+}