Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

misc: keba: Fix kernfs warning on module unload

Unloading the cp500 module leads to the following warning:

kernfs: can not remove 'eeprom', no directory
WARNING: CPU: 1 PID: 1610 at fs/kernfs/dir.c:1683 kernfs_remove_by_name_ns+0xb1/0xc0

The parent I2C device of the nvmem devices is freed before the nvmem
devices. The reference to the nvmem devices is put by devm after
cp500_remove(), but at this time the parent I2C device does not exist
anymore as the I2C controller and its devices have already been freed in
cp500_remove(). Thus, nvmem tries to remove an entry from an already
deleted directory.

Free nvmem devices before I2C controller auxiliary device.

Signed-off-by: Gerhard Engleder <eg@keba.com>
Link: https://lore.kernel.org/r/20241214215759.60811-1-gerhard@engleder-embedded.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Gerhard Engleder and committed by
Greg Kroah-Hartman
6847b00c 2d390e06

+45 -24
+45 -24
drivers/misc/keba/cp500.c
··· 126 126 }; 127 127 128 128 struct cp500_nvmem { 129 - struct nvmem_device *nvmem; 129 + struct nvmem_device *base_nvmem; 130 130 unsigned int offset; 131 + struct nvmem_device *nvmem; 131 132 }; 132 133 133 134 struct cp500 { ··· 582 581 struct cp500_nvmem *nvmem = priv; 583 582 int ret; 584 583 585 - ret = nvmem_device_read(nvmem->nvmem, nvmem->offset + offset, bytes, 586 - val); 584 + ret = nvmem_device_read(nvmem->base_nvmem, nvmem->offset + offset, 585 + bytes, val); 587 586 if (ret != bytes) 588 587 return ret; 589 588 ··· 596 595 struct cp500_nvmem *nvmem = priv; 597 596 int ret; 598 597 599 - ret = nvmem_device_write(nvmem->nvmem, nvmem->offset + offset, bytes, 600 - val); 598 + ret = nvmem_device_write(nvmem->base_nvmem, nvmem->offset + offset, 599 + bytes, val); 601 600 if (ret != bytes) 602 601 return ret; 603 602 604 603 return 0; 605 604 } 606 605 607 - static int cp500_nvmem_register(struct cp500 *cp500, struct nvmem_device *nvmem) 606 + static int cp500_nvmem_register(struct cp500 *cp500, 607 + struct nvmem_device *base_nvmem) 608 608 { 609 609 struct device *dev = &cp500->pci_dev->dev; 610 610 struct nvmem_config nvmem_config = {}; ··· 627 625 nvmem_config.reg_read = cp500_nvmem_read; 628 626 nvmem_config.reg_write = cp500_nvmem_write; 629 627 630 - cp500->nvmem_cpu.nvmem = nvmem; 628 + cp500->nvmem_cpu.base_nvmem = base_nvmem; 631 629 cp500->nvmem_cpu.offset = CP500_EEPROM_CPU_OFFSET; 632 630 nvmem_config.name = CP500_EEPROM_CPU_NAME; 633 631 nvmem_config.size = CP500_EEPROM_CPU_SIZE; 634 632 nvmem_config.priv = &cp500->nvmem_cpu; 635 - tmp = devm_nvmem_register(dev, &nvmem_config); 633 + tmp = nvmem_register(&nvmem_config); 636 634 if (IS_ERR(tmp)) 637 635 return PTR_ERR(tmp); 636 + cp500->nvmem_cpu.nvmem = tmp; 638 637 639 - cp500->nvmem_user.nvmem = nvmem; 638 + cp500->nvmem_user.base_nvmem = base_nvmem; 640 639 cp500->nvmem_user.offset = CP500_EEPROM_USER_OFFSET; 641 640 nvmem_config.name = CP500_EEPROM_USER_NAME; 642 641 nvmem_config.size = CP500_EEPROM_USER_SIZE; 643 642 nvmem_config.priv = &cp500->nvmem_user; 644 - tmp = devm_nvmem_register(dev, &nvmem_config); 645 - if (IS_ERR(tmp)) 643 + tmp = nvmem_register(&nvmem_config); 644 + if (IS_ERR(tmp)) { 645 + nvmem_unregister(cp500->nvmem_cpu.nvmem); 646 + cp500->nvmem_cpu.nvmem = NULL; 647 + 646 648 return PTR_ERR(tmp); 649 + } 650 + cp500->nvmem_user.nvmem = tmp; 647 651 648 652 return 0; 653 + } 654 + 655 + static void cp500_nvmem_unregister(struct cp500 *cp500) 656 + { 657 + int notified; 658 + 659 + if (cp500->nvmem_user.nvmem) { 660 + nvmem_unregister(cp500->nvmem_user.nvmem); 661 + cp500->nvmem_user.nvmem = NULL; 662 + } 663 + if (cp500->nvmem_cpu.nvmem) { 664 + nvmem_unregister(cp500->nvmem_cpu.nvmem); 665 + cp500->nvmem_cpu.nvmem = NULL; 666 + } 667 + 668 + /* CPU and user nvmem use the same base_nvmem, put only once */ 669 + notified = atomic_read(&cp500->nvmem_notified); 670 + if (notified) 671 + nvmem_device_put(cp500->nvmem_cpu.base_nvmem); 649 672 } 650 673 651 674 static int cp500_nvmem_match(struct device *dev, const void *data) ··· 688 661 return 1; 689 662 690 663 return 0; 691 - } 692 - 693 - static void cp500_devm_nvmem_put(void *data) 694 - { 695 - struct nvmem_device *nvmem = data; 696 - 697 - nvmem_device_put(nvmem); 698 664 } 699 665 700 666 static int cp500_nvmem(struct notifier_block *nb, unsigned long action, ··· 717 697 718 698 return NOTIFY_DONE; 719 699 } 720 - 721 - ret = devm_add_action_or_reset(dev, cp500_devm_nvmem_put, nvmem); 722 - if (ret) 723 - return ret; 724 700 725 701 ret = cp500_nvmem_register(cp500, nvmem); 726 702 if (ret) ··· 948 932 { 949 933 struct cp500 *cp500 = pci_get_drvdata(pci_dev); 950 934 935 + /* 936 + * unregister CPU and user nvmem and put base_nvmem before parent 937 + * auxiliary device of base_nvmem is unregistered 938 + */ 939 + nvmem_unregister_notifier(&cp500->nvmem_notifier); 940 + cp500_nvmem_unregister(cp500); 941 + 951 942 cp500_unregister_auxiliary_devs(cp500); 952 943 953 944 cp500_disable(cp500); 954 - 955 - nvmem_unregister_notifier(&cp500->nvmem_notifier); 956 945 957 946 pci_set_drvdata(pci_dev, 0); 958 947