[PATCH 2/2] drm/i915: Tear down properly on early i915_init exit

Daniel Vetter daniel at ffwll.ch
Mon Jul 19 08:28:22 UTC 2021


On Sat, Jul 17, 2021 at 12:48 AM Jason Ekstrand <jason at jlekstrand.net> wrote:
> In i915_exit(), we check i915_pci_driver.driver.owner to detect if
> i915_init exited early and don't tear anything down.  However, we didn't
> have proper tear-down paths for early exits in i915_init().
>
> Most of the time, you would never notice this as driver init failures
> are extremely rare and generally the sign of a bigger bug.  However,
> when the mock self-tests are run, they run as part of i915_init() and
> exit early once they complete.  They run after i915_globals_init() and
> before we set up anything else.  The IGT test then unloads the module,
> invoking i915_exit() which, thanks to our i915_pci_driver.driver.owner
> check, doesn't actually tear anything down.  Importantly, this means
> i915_globals_exit() never gets called even though i915_globals_init()
> was and we leak the globals.
>
> The most annoying part is that you don't actually notice the failure as
> part of the self-tests since leaking a bit of memory, while bad, doesn't
> result in anything observable from userspace.  Instead, the next time we
> load the driver (usually for next IGT test), i915_globals_init() gets
> invoked again, we go to allocate a bunch of new memory slabs, those
> implicitly create debugfs entries, and debugfs warns that we're trying
> to create directories and files that already exist.  Since this all
> happens as part of the next driver load, it shows up in the dmesg-warn
> of whatever IGT test ran after the mock selftests.

My idea was to onion-unwind in i915_exit, but that means we need to
carry state over or have checks for every step, which is a bit
annoying.

Yours unwinds even if i915_init returns 0, i.e. success, if we had
some selftests, which is most unusual and I think deserves an
explainer here in the commit message and maybe somewhere in the code.

> Signed-off-by: Jason Ekstrand <jason at jlekstrand.net>
> Fixes: 32eb6bcfdda9 ("drm/i915: Make request allocation caches global")
> Cc: Daniel Vetter <daniel at ffwll.ch>
> ---
>  drivers/gpu/drm/i915/i915_globals.c |  4 ++--
>  drivers/gpu/drm/i915/i915_pci.c     | 23 +++++++++++++++++------
>  2 files changed, 19 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_globals.c b/drivers/gpu/drm/i915/i915_globals.c
> index 77f1911c463b8..87267e1d2ad92 100644
> --- a/drivers/gpu/drm/i915/i915_globals.c
> +++ b/drivers/gpu/drm/i915/i915_globals.c
> @@ -138,7 +138,7 @@ void i915_globals_unpark(void)
>         atomic_inc(&active);
>  }
>
> -static void __exit __i915_globals_flush(void)
> +static void __i915_globals_flush(void)
>  {
>         atomic_inc(&active); /* skip shrinking */
>
> @@ -148,7 +148,7 @@ static void __exit __i915_globals_flush(void)
>         atomic_dec(&active);
>  }
>
> -void __exit i915_globals_exit(void)
> +void i915_globals_exit(void)
>  {
>         GEM_BUG_ON(atomic_read(&active));
>
> diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c
> index 50ed93b03e582..783f547be0990 100644
> --- a/drivers/gpu/drm/i915/i915_pci.c
> +++ b/drivers/gpu/drm/i915/i915_pci.c
> @@ -1199,13 +1199,20 @@ static int __init i915_init(void)
>         bool use_kms = true;
>         int err;
>
> +       /* We use this to detect early returns from i915_init() so we don't
> +        * tear anything down in i915_exit()
> +        */
> +       i915_pci_driver.driver.owner = NULL;

Setting this seems redundant? Or if you want to make it explicit, just
have a dedicated bool with a big comment explaining that only when we
load the full pci driver do we tear down stuff in i915_exit. You could
then set after pci_register_driver was successful. Some screaming name
like driver_fully_loaded or something like that ...

> +
>         err = i915_globals_init();
>         if (err)
>                 return err;
>
>         err = i915_mock_selftests();
> -       if (err)
> -               return err > 0 ? 0 : err;
> +       if (err) {
> +               err = err > 0 ? 0 : err;
> +               goto globals_exit;
> +       }
>
>         /*
>          * Enable KMS by default, unless explicitly overriden by

Imo move this up, but if you want I can send out my diff so you score
an r-b: tag :-)

> @@ -1228,13 +1235,17 @@ static int __init i915_init(void)
>         i915_pmu_init();
>
>         err = pci_register_driver(&i915_pci_driver);
> -       if (err) {
> -               i915_pmu_exit();
> -               return err;
> -       }
> +       if (err)
> +               goto pmu_exit;
>
>         i915_perf_sysctl_register();
>         return 0;
> +

We unwind even on success, which is most unusual. I think that
deserves a comment.

> +pmu_exit:
> +       i915_pmu_exit();
> +globals_exit:
> +       i915_globals_exit();
> +       return err;
>  }
>
>  static void __exit i915_exit(void)
> --
> 2.31.1
>


-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch


More information about the dri-devel mailing list