Commit 09a81269 authored by Jarkko Lavinen's avatar Jarkko Lavinen Committed by Linus Torvalds

i82875p_edac: fix module remove

Fix module removal bugs of i82875p_edac.  Also i82975x_edac code seems to
have the same module removal bugs as in i82875p_edac.

The problems were:

1. In module removal i82875p_remove_one() is never called.

   Variable i82875p_registered is newer changed from 1, which
   guarantees i82875p_remove_one() is not called (and even if it were
   called, it would be called in wrong order).

   As a result, the edac_mc workque is not stopped and keeps probing.
   If kernel debugging options are not enabled, user may not notice
   anything going wrong.

   if debugging options are enabled and I do "rmmod i82875p_edac", I
   get:

      edac debug: edac_pci_workq_function() checking
      BUG: unable to handle kernel paging request at f882d16f
      ...
      call trace:
       [<f8834df3>] ? edac_mc_workq_function+0x55/0x7e [edac_core]
       [<c0233974>] ? run_workqueue+0xd7/0x1a5
       [<c023392f>] ? run_workqueue+0x92/0x1a5
       [<f8834d9e>] ? edac_mc_workq_function+0x0/0x7e [edac_core]
       [<c0233af9>] ? worker_thread+0xb7/0xc3
       [<c0236a7b>] ? autoremove_wake_function+0x0/0x33
       [<c0233a42>] ? worker_thread+0x0/0xc3
       [<c0236809>] ? kthread+0x3b/0x61
       [<c02367ce>] ? kthread+0x0/0x61
       [<c0204587>] ? kernel_thread_helper+0x7/0x10

   Fix for this is to get rid of needles variable i82875p_registered
   altogether and run i82875p_remove_one() *before*
   pci_unregister_driver().

2. edac_mc_del_mc() uses mci after freeing mci

   edac_mc_del_mc() calls calls edac_remove_sysfs_mci_device().  The
   kobject refcount of mci drops to 0 and mci is freed.  After this
   mci is accessed via debug print and i82875p_remove_one() still
   uses mci->pvt and tries to free mci again with edac_mc_free().

   The fix for this is add kobject_get(&mci->edac_mci_kobj) after
   edac_mc_alloc(). Then the mci is still available after returning
   from edac_mc_del_mc() with refcount 1, and mci->pvt is still
   available. When i82875p_remove_one() finally calls edac_mc_free(),
   this will cause kobject_put() and mci is released properly.
Signed-off-by: default avatarJarkko Lavinen <jlavi@iki.fi>
Cc: Doug Thompson <norsk5@yahoo.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 307d1144
...@@ -182,8 +182,6 @@ static struct pci_dev *mci_pdev; /* init dev: in case that AGP code has ...@@ -182,8 +182,6 @@ static struct pci_dev *mci_pdev; /* init dev: in case that AGP code has
* already registered driver * already registered driver
*/ */
static int i82875p_registered = 1;
static struct edac_pci_ctl_info *i82875p_pci; static struct edac_pci_ctl_info *i82875p_pci;
static void i82875p_get_error_info(struct mem_ctl_info *mci, static void i82875p_get_error_info(struct mem_ctl_info *mci,
...@@ -410,6 +408,9 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx) ...@@ -410,6 +408,9 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
goto fail0; goto fail0;
} }
/* Keeps mci available after edac_mc_del_mc() till edac_mc_free() */
kobject_get(&mci->edac_mci_kobj);
debugf3("%s(): init mci\n", __func__); debugf3("%s(): init mci\n", __func__);
mci->dev = &pdev->dev; mci->dev = &pdev->dev;
mci->mtype_cap = MEM_FLAG_DDR; mci->mtype_cap = MEM_FLAG_DDR;
...@@ -452,6 +453,7 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx) ...@@ -452,6 +453,7 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
return 0; return 0;
fail1: fail1:
kobject_put(&mci->edac_mci_kobj);
edac_mc_free(mci); edac_mc_free(mci);
fail0: fail0:
...@@ -579,12 +581,11 @@ static void __exit i82875p_exit(void) ...@@ -579,12 +581,11 @@ static void __exit i82875p_exit(void)
{ {
debugf3("%s()\n", __func__); debugf3("%s()\n", __func__);
i82875p_remove_one(mci_pdev);
pci_dev_put(mci_pdev);
pci_unregister_driver(&i82875p_driver); pci_unregister_driver(&i82875p_driver);
if (!i82875p_registered) {
i82875p_remove_one(mci_pdev);
pci_dev_put(mci_pdev);
}
} }
module_init(i82875p_init); module_init(i82875p_init);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment