2021-06-25

linux驅動管理利器,詳解dkms工作原理 原文網址:https://kknews.cc/code/x6ay3yo.html

 

背景

最近遇到一個麻煩的問題,幾台伺服器在升級內核之後,新的內核啟動直接panic,無法正常驅動raid卡. 通過進入ramos,發現新的內核裡面沒有對應的raid卡驅動ko文件. 後面才發現老的內核中rraid卡驅動是從原始碼單獨編譯出來的. 換了新的kernel之後,忘了給新的內核重新編譯這個驅動就重啟了,導致kernel panic.

在linux中,每個驅動ko文件是與一個特定內核綁定的,也就是在老內核下面編譯的驅動在新內核下面無法使用,同樣的,在新內核下面編譯的驅動在老內核也無法使用.

在linux kernel原始碼樹中,已經包含了我們常見的很多驅動,那麼在安裝一個新的內核rpm包的時候,這些驅動也就被一起安裝了. 但是有些驅動不在原始碼樹裡面,這些驅動需要手動編譯安裝;還有一些驅動雖然在原始碼樹中,但是原始碼樹中的可能太老了,新的驅動也需要單獨編譯安裝.

使用dkms來管理原始碼樹外的驅動

dkms就是用來處理在kernel原始碼樹中不存在的驅動,或者我們自己維護的驅動的. 它可以保證新的kernel安裝之後,這些驅動被自動重新編譯,自動運行depmod命令,自動生成新的initram文件.

dkms這個工具存在於epel源中,需要先保證epel打開,然後yum -y install dkms就可以安裝這個工具了.使用rpm -ql dkms看下這個包安裝了什麼東西.

/usr/sbin/dkms是dkms命令行本身,是一個bash腳本.我們用的最多的是dkms status,用來查看當前dkms管理的驅動的狀態

/var/lib/dkms是dkms工作目錄.

/etc/kernel/目錄下面的兩個文件,分別是postinst和prerm的kernel hook,dkms自動管理驅動核心就是這兩個文件.

現在大部分驅動rpm包都有兩種形式的,一種是直接針對rhel特定版本(也就是特定內核)編譯好的. 還有就是一個dkms enabled的rpm包.

下面以megaraid_sas-07.710.06.00-1dkms.noarch.rpm這個dkms enabled包為例來操作.什麼是dkms enabled的rpm包呢

首先,這個rpm安裝文件的路徑一定是/usr/src/module-version目錄,比如這兒的/usr/src/megaraid_sas-07.710.06.00,然後這個包裡面一定有一個dkms.conf文件.

因為dkms工作的時候需要讀取這個dkms.conf文件,這個文件實際是一個shell腳本,dkms工作的時候會source進去.

我們看下安裝這個包的時候具體會做的事情

安裝之前,dkms status輸出為空,表示沒有管理任何驅動

這個包安裝的時候,會看到dkms add,dkms build(編譯驅動),dkms install(把編譯好的驅動安裝到/lib/modules/`uname -r`目錄下),跑depmod,跑dracut重新生成initramfs的過程(如果手動裝驅動,就是這些過程)

dkms enabled包的scripts,裡面是核心的dkms命令
dkms enabled包的安裝過程,能看到關鍵的步驟被執行

如果dkms只是能幫我們執行這些命令,那麼其實用處也不大. dkms最主要的用處是當我們安裝了一個新的kernel包之後,其會用到kernel hook給我們自動重新給新內核完成上面的事情.

dkms使用kernel hook自動管理驅動

在我們安裝了這個dkms enabled的驅動包之後,我們安裝一個新的內核

能看到這個新的kernel包安裝的過程中跑了一些腳本.

完成之後,dkms status直接顯示新的內核直接把這個驅動包安裝上了.

dkms的工作目錄/var/lib/dkms也顯示這個驅動包安裝到了新的內核.

那麼dkms在安裝新的內核包的時候,怎麼觸發給新的內核包重新編譯驅動的呢?

我們看下內核包的scripts,發現裡面有對/usr/sbin/new-kernel-pkg腳本的調用

而/usr/sbin/new-kernel-pkg裡面有對/etc/kernel/postinst.d/目錄下的腳本進行調用的邏輯.

dkms給/etc/kernel/postinst.d下面安裝了腳本

這個腳本裡面調用/usr/lib/dkms/dkms_autoinstaller進行自動安裝

dkms_autoinstaller調用dkms autoinstall,在autoinstall中,會對當前所有狀態為installed,並且dkms.conf配置匯總AUTOINSTALL=yes的模塊對安裝的內核進行編譯安裝.

總結

dkms是dell做的一個自動管理kernel原始碼樹外的驅動框架,現在大量用於各種硬體,特別是存儲硬體的驅動管理中. 其使用方法特別簡單,只需要將一個dkms enabled的原始碼包安裝即可. 後面的事情就是dkms自己處理了. 大家找硬體驅動包的時候可以找dkms enabled的,如果沒有也可以從原始碼用tarball的方式導入,自己再加個dkms.conf就可以了.



原文網址:https://kknews.cc/code/x6ay3yo.html

2021-06-24

Ubuntu – TP-Link Archer T3U Plus USB adapter

 Cannot make this wireless adapter work on Ubuntu 20.04… please help.

I've tried this: TP-LINK Archer T3U not working in Ubuntu 18.04
and now lsusb sees the device, but still doesn't work.

lsusb:
Bus 002 Device 006: ID 2357:0138 TP-Link 802.11ac NIC

uname -r:
5.4.0-39-generic

Edit: It works on my other computer with Ubuntu 18.04 using T2U Plus driver from here: https://github.com/RinCat/RTL88x2BU-Linux-Driver

But it does not work with Ubuntu 20.04…

sudo modprobe 88x2bu: Gives nothing.

modinfo 88x2bu | grep -e version -e 0138 :

version:        v5.6.1_30362.20181109_COEX20180928-6a6a
srcversion:     9C5282368F93050B7206C8D
parm:           rtw_chip_version:int

dmesg | grep 88×2 :

[ 8087.334869] 88x2bu: loading out-of-tree module taints kernel.
[ 8087.336610] 88x2bu: module verification failed: signature and/or required key missing - tainting kernel
[ 8087.341389] usbcore: registered new interface driver rtl88x2bu

Best Answer

  • Please notice at the git repository that you linked:

    enter image description here

    Your son is evidently using the latest (5 or less days ago) version and you are not.

    Since dkms status returned nothing, we conclude that you installed with sudo make install. Let's remove the inoperative driver, update it and reinstall:

    cd ~/RTL88x2BU-Linux-Driver/
    sudo make uninstall
    make clean
    git pull
    make
    sudo make install
    sudo modprobe 88x2bu
    

    After each kernel update, you must recompile:

    cd ~/RTL88x2BU-Linux-Driver/
    make clean
    git pull
    make
    sudo make install
    sudo modprobe 88x2bu
    

    EDIT: As we have seen, the git pull step was ineffective as you downloaded the zip file rather than obtaining the driver by git clone.

    Please do:

    cd ~/RTL88x2BU-Linux-Driver-master
    

    Or whatever the name of the previously downloaded and extracted driver file is. Next:

    sudo make uninstall
    cd ..
    sudo rm -r RTL88x2BU-Linux-Driver-master
    

    Now. we'll download a fresh copy with updates that drive your device. With a temporary working internet connection, please do:

    wget https://github.com/RinCat/RTL88x2BU-Linux-Driver/archive/master.zip
    unzip master.zip
    cd RTL88x2BU-Linux-Driver-master
    make
    sudo make install
    sudo modprobe 88x2bu
  • 2021-05-06

    Get Volume Path from Drive Name using Powershell script

     Get Volume Path from Drive Name using Powershell script

    November 11, 2014 by Morgan

    I have been working with file access events in Clustered File Server. In event log, for every file access, we are getting 4663 and 4656 events with file path like: DeviceHarddiskVolume4MySharetest.txt instead of my local path F:MySharetest.txt. After I have analyzed , found the prefix path DeviceHarddiskVolume4 is mapped with the device F:. Finally, I found this link (http://poshcode.org/4768), it contains powershell script to list Device Name (Drive letter) and mapped Device Path (Volume Path).

    List Device Name and Volume Path

    Get Volume Path from Device Name (Drive Letter)

    List Device Name and Volume Path using Powershell script

    We can get the Volume Path from Device Name using the Kernel32 module function QueryDosDevice and we can list the available device names (drive letter) using WMI class Win32_Volume. Use the the below Powershell script to list device path and device name.


       1. Copy the below Powershell script and paste in Notepad file.

       2. Save As the Notepad file with the extension .ps1 like List-Device-Name-and-Path.ps1


    Powershell Script: Download List-Device-Name-and-Path.ps1


    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    # Biuild System Assembly in order to call Kernel32:QueryDosDevice. 

       $DynAssembly = New-Object System.Reflection.AssemblyName('SysUtils')

       $AssemblyBuilder = [AppDomain]::CurrentDomain.DefineDynamicAssembly($DynAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run)

       $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('SysUtils', $False)

     

       # Define [Kernel32]::QueryDosDevice method

       $TypeBuilder = $ModuleBuilder.DefineType('Kernel32', 'Public, Class')

       $PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('QueryDosDevice', 'kernel32.dll', ([Reflection.MethodAttributes]::Public -bor [Reflection.MethodAttributes]::Static), [Reflection.CallingConventions]::Standard, [UInt32], [Type[]]@([String], [Text.StringBuilder], [UInt32]), [Runtime.InteropServices.CallingConvention]::Winapi, [Runtime.InteropServices.CharSet]::Auto)

       $DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String]))

       $SetLastError = [Runtime.InteropServices.DllImportAttribute].GetField('SetLastError')

       $SetLastErrorCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($DllImportConstructor, @('kernel32.dll'), [Reflection.FieldInfo[]]@($SetLastError), @($true))

       $PInvokeMethod.SetCustomAttribute($SetLastErrorCustomAttribute)

       $Kernel32 = $TypeBuilder.CreateType()

     

       $Max = 65536

       $StringBuilder = New-Object System.Text.StringBuilder($Max)

     

       Get-WmiObject Win32_Volume | ? { $_.DriveLetter } | % {

           $ReturnLength = $Kernel32::QueryDosDevice($_.DriveLetter, $StringBuilder, $Max)

     

           if ($ReturnLength)

           {

               $DriveMapping = @{

                   DriveLetter = $_.DriveLetter

                   DevicePath = $StringBuilder.ToString()

               }

     

               New-Object PSObject -Property $DriveMapping

           }

       }

       3. Now run the script file List-Device-Name-and-Path.ps1 from Powershell to list all the Device Name and Volume Path in local machine.



    Get Device Path from Device Name using Powershell script

    Get Device Path from Device Name (Drive Letter) using Powershell script

    The below script displays Device Path for the given Device Name(Derive letter). The device name(drive letter) cannot have a trailing backslash; for example, use “C:“, not “C:“. Follow the below steps to get volume path from drive letter.


       1. Copy the below Powershell script and paste in Notepad file.

       2. Save As the Notepad file with the extension .ps1 like Get-DevicePath-from-DeviceName.ps1


    Powershell Script: Download Get-DevicePath-from-DeviceName.ps1


    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    $driveLetter = Read-Host "Enter Drive Letter:"

    Write-Host " "

    $DynAssembly = New-Object System.Reflection.AssemblyName('SysUtils')

    $AssemblyBuilder = [AppDomain]::CurrentDomain.DefineDynamicAssembly($DynAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run)

    $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('SysUtils', $False)

     

    # Define [Kernel32]::QueryDosDevice method

    $TypeBuilder = $ModuleBuilder.DefineType('Kernel32', 'Public, Class')

    $PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('QueryDosDevice', 'kernel32.dll', ([Reflection.MethodAttributes]::Public -bor [Reflection.MethodAttributes]::Static), [Reflection.CallingConventions]::Standard, [UInt32], [Type[]]@([String], [Text.StringBuilder], [UInt32]), [Runtime.InteropServices.CallingConvention]::Winapi, [Runtime.InteropServices.CharSet]::Auto)

    $DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String]))

    $SetLastError = [Runtime.InteropServices.DllImportAttribute].GetField('SetLastError')

    $SetLastErrorCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($DllImportConstructor, @('kernel32.dll'), [Reflection.FieldInfo[]]@($SetLastError), @($true))

    $PInvokeMethod.SetCustomAttribute($SetLastErrorCustomAttribute)

    $Kernel32 = $TypeBuilder.CreateType()

     

    $Max = 65536

    $StringBuilder = New-Object System.Text.StringBuilder($Max)

    $ReturnLength = $Kernel32::QueryDosDevice($driveLetter, $StringBuilder, $Max)

     

     if ($ReturnLength)

     {

         Write-Host "Device Path: "$StringBuilder.ToString()

      }

      else

      {

          Write-Host "Device Path: not found"

      }

    Write-Host " "

       3. Now run the script file Get-DevicePath-from-DeviceName.ps1 from Powershell, and give the Drive letter as argument which you want to get device path.



    2021-03-13

    win10 關閉螢幕/無法休眠

     用管理員權限打開CMD或POWERSHELL powercfg /requests 會列出是甚麼東西阻止電源管理進入休眠/關閉螢幕

    MoUsoCoreWorker.exe ...又是windows update

    1. 更新出問題導致這個東西卡在那邊

    可以試著重開機

    然後打開windows update手動檢查

    可能會出現更新

    沒先重開的話是不會出現的 因為已經卡住了

    2.從服務停用windows update然後再啟用

    win+R 輸入 services.msc

    開始>右鍵>電腦管理>服務與應用程式>服務

    找到windows update

    停用

    等個幾分鐘

    啟用


    再次用powercfg /requests檢查, MoUsoCoreWorker.exe應該會消失


    3.強制覆寫

    用這個指令

    powercfg /requestsoverride process MoUsoCoreWorker.exe

    把這個程式排除


    ====== 另外一種被自動喚醒的情形 =====================================

    Windows 10 May 2019 update (1903) breaking sleep

    解法 : gpedit.msc 本機電腦 原則 -> 電腦設定 -> 系統管理範本 ->windows 元件 ->Windows Update ->啟用 Windows Update 電源管理以自動喚醒系統安裝排程的更新 [尚未設定]->[已停用]


    網卡 電源管理 允許這個裝置喚醒電腦 -> disable

    2021-01-30

    不小心, 又把 WZR-HP-G300N 刷壞了

    原本是 OpenWRT, 不小心直接刷 DD-WRT, 導致無法開機 

    bootloader 沒壞

    使用刷 WZR-HP-G450H 的方式救回 

    https://digi9.net/221/openwrt-fix-loi-firmware-router-buffalo-wzr-hp-g450h/#.XDI5XIxR3tQ