2016年4月29日 星期五

How To Compiler udev (udevadm)




Linux 初學者, 對這邊核心程式的編譯方式一定會被搞瘋掉
有時間再寫一篇 udevadm 移殖到Eclipse中 Debug的流程

The options used usually look like:


# mkdir udev
# cd udev
# git clone git://git.kernel.org/pub/scm/linux/hotplug/udev.git git





# cd git
# apt-get install gtk-doc-tools
# ./autogen.sh --without-selinux --disable-extras --disable-introspection
# ./configure CFLAGS='-g -O1'  --prefix=/usr --sysconfdir=/etc --libdir=/usr/lib --with-selinux --enable-gtk-doc --with-rootprefix= --with-rootlibdir=/lib --bindir=/sbin --libexecdir=/lib --with-systemdsystemunitdir=/lib/systemd/system 

checking for BLKID... no
configure: error: Package requirements (blkid >= 2.20) were not met:
No package 'blkid' found
No blkid, need install libblkid-dev


# apt-get install libblkid-dev

# ./configure CFLAGS='-g -O1'  --prefix=/usr --sysconfdir=/etc --libdir=/usr/lib --with-selinux --enable-gtk-doc --with-rootprefix= --with-rootlibdir=/lib --bindir=/sbin --libexecdir=/lib --with-systemdsystemunitdir=/lib/systemd/system 
checking for KMOD... no
configure: error: Package requirements (libkmod >= 5) were not met:

No package 'libkmod' found
No 'libkmod', Need install libkmod-dev

# apt-get install libkmod-dev
# apt-get install libselinux-dev

# apt-get install libglib2.0-dev

# apt-get install libgirepository1.0-dev

# apt-get install gperf

# ./configure CFLAGS='-g -O1'  --prefix=/usr --sysconfdir=/etc --libdir=/usr/lib --with-selinux --enable-gtk-doc --with-rootprefix= --with-rootlibdir=/lib --bindir=/sbin --libexecdir=/lib --with-systemdsystemunitdir=/lib/systemd/system 






configure 完成, 會在目錄下發現一個 makefile 檔案! 

可以開始進行 gcc make 動作


# make


編譯出現錯誤, 原來這個 mq_getattr 很久以前的功能,可以直接作廢.

# gedit /root/udev/git/src/sd-daemon.c
comment it out line 394 & 395 
 //        if (mq_getattr(fd, &attr) < 0)
 //              return -errno;

重新作執行一次 gcc make 動作
# make

 




# ./udevadm --version
182

請參考 Ubuntu udevadm用法
# ./udevadm info -q all -n /dev/sda | grep DEVPATH


可以使用 udevadm監控Hot Plug的狀態

# udevadm monitor





2016年4月25日 星期一

HTML with C++ cpp Code


原文來自
How can I show code (specifically C++) in an HTML page?



<head>
  <link href="css/shCore.css" rel="stylesheet" type="text/css" />
  <link href="css/shThemeDefault.css" rel="stylesheet" type="text/css" />
</head>

<body>
  <pre class='brush: cpp'>
  // my first program in C++
  #include <iostream>
  using namespace std;

  int main ()
  {
    cout << "Hello World!";
    return 0;
  }
  </pre>

  <script src="js/shCore.js"></script>
  <script src="js/shBrushCpp.js"></script>
  <script>
    SyntaxHighlighter.all()
  </script>
</body>

Debugging with GDB


因為在 Eclipse中 Debug 多個 pthread 真的有點痛苦
奇怪的是 Altera Eclipse 版本不會這樣

後來查出原來是其他程式段錯誤
卻造成 Debug thread混亂


但 Linux Eclipse CDT 中 switch thread時卻會卡卡的
只好找找看別的方式來試試看

Debugging with GDB學習記錄(一)

Debugging with GDB學習記錄(二)

Debugging with GDB學習記錄(三)


2016年4月21日 星期四

Linux Memory Leak

Linux Tools Project - Valgrind Support
 https://eclipse.org/linuxtools/projectPages/valgrind/


Eclipse 外掛︰ MAT, Memory Analyzer Tool (JAVA Only)
  http://www.eclipse.org/mat/downloads.php
  http://lp43.blogspot.tw/2011/11/mat.html

valgrind:
使用valgrind檢查C語言memory leak
 # apt-get install valgrind
 # valgrind --leak-check=full --show-leak-kinds=all --verbose ./My-Leaky-Program-Filename


mtrace:

在程式中加入兩行
#include <mcheck.h>

static void Main()
{
 ...
  mtrace();
 ...
}

在終端機模式下
# mtrace ./My-Leaky-Program-Filename  Memory_Leak.txt


2016年4月19日 星期二

Linux Physical Block Size

Linux 這個  physical_block_size 是 File System 的 physical block

> 磁區大小 (邏輯/實體):512 位元組 / 4096 位元組
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
File System 以上, 一個 Block Size是 4096Byte
SCSI Direct IO以下, 一個 Sector Size是 512Byte 
(但有一些少見的裝置其 Sector Size是 1024Byte)

/sys/block/sda/queue/physical_block_size
 4096

/sys/block/sdb/queue/physical_block_size
 512

/sys/block/sdc/queue/physical_block_size
 512



Linux SCSI Pass Through Interface

其實不難, 只是專案必需要知道每一個實體 PHY Port 是連結到 Linux 中那一個 /dev/sgn 中
原來是直接用 /dev/sdN , 但發現這對以逅的專案會有影響, 所以就改用/dev/sgN 方式
而且習慣看 SCSI Sense Code, 除錯也比較容易.

過去十幾年來都在 Windows 和 NIOS-II 下對 Device直接下 SCSI Command
終於換到 Linux 平台來.

Some examples of storage device names of the supported operating systems

 //===========================================
方式一:
   一般都是利用 sg3-utils核心
   # apt-get install sg3-utils

   也就是開啟 "/dev/sgN" 方法
   http://sg3-utils.sourcearchive.com/
    sg3_utils-1.32 Example
 

  參考下面這幾篇
   T10 Working Drafts
   這個 T10很多檔案都已經改為付費購買. 其實只要只知道檔案名稱, 還是在Google搜尋下載得到.

   Seagate SCSI Commands Reference Manual
   Seagate SCSI Commands Reference Manual April 2010
   wiki SCSI command


   http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/
   Appendix C. Programming example

   ioctrl-using-scsi-pass-through

   linux scsi generic howto學習筆記

 
typedef struct sg_io_hdr
{
  int interface_id;           /* [i] 'S' for SCSI generic (required) */
  int dxfer_direction;        /* [i] data transfer direction  */
                                     SG_DXFER_NONE /* e.g. a SCSI Test Unit Ready command */
                                     SG_DXFER_TO_DEV /* e.g. a SCSI WRITE command */
                                     SG_DXFER_FROM_DEV /* e.g. a SCSI READ command */
                                   
                                     TestUnitReady => SG_DXFER_NONE
                                     ReadCapacity10 => SG_DXFER_FROM_DEV
                                     Read10 => SG_DXFER_FROM_DEV
                                     Write10 => SG_DXFER_TO_DEV
 
  unsigned char cmd_len;      /* [i] SCSI command length ( <= 16 bytes) */
                                     ReadCapacity10 => cmd_len = 10
                                     ReadCapacity16 => cmd_len = 16
                                     Read10 => cmd_len = 10
                                     Write10 => cmd_len = 10
                                     Write16 => cmd_len = 16

  ...
} sg_io_hdr_t;
//===========================================

使用 SG_IO 出現 ENOMEM
表示要求傳輸的記憶體太大
經測試只傳輸到 512byte * 9181sector
一呼叫 512byte * 9182sector   就會發生 ENOMEM
經查 Google 這是Linux的核心限制
scsi sg ioctl要求向 blk-mq 取得一塊和要求傳輸大小的記憶體區塊失敗.

對 Storage一次使用大區塊讀取, 並不一定會比較穩定快速
因為不同的 Storage, 其晶片的特性不同
讀取太大塊, 速度反而會變慢, 變錯.
這個數字是多少, 就依賴經驗值, 必竟Storage的種類範圍太廣.


下面只是參考, 別太認真.
void ReadWrite_Test()
{
 int nI, nJ;
 TLBA nReadLba, nWriteLba;
 DWORD nSectorSize, nReadLen, nWriteLen;
 DWORD nReadCrc32, nWriteCrc32, nWriteSectorCrc32;
 DWORD nReadBufLen, nWriteBufLen;
 UCHAR *pReadBuf = new UCHAR[16*1024*1024];
 UCHAR *pWriteBuf = new UCHAR[16*1024*1024];


 nSectorSize = 512;
 nWriteLba = 0;
 nWriteLen = 8192;
 memset( pWriteBuf, 0, 16*1024*1024);
 /* 初始化 Writer Data Buffer */
 for( nI =0; nI < nWriteLen; nI++)
 {
  /* 中間填入 序號Index */
  for( nJ = 4; nJ < nSectorSize-sizeof(DWORD); nJ++)
   pWriteBuf[nI*nSectorSize+nJ] = nJ%255;
  /* 前4個Byte 是 Sector Index */
  pWriteBuf[nI*nSectorSize]   = (UCHAR)((nWriteLba+nI) >> 24); // MSB
  pWriteBuf[nI*nSectorSize+1] = (UCHAR)((nWriteLba+nI) >> 16);
  pWriteBuf[nI*nSectorSize+2] = (UCHAR)((nWriteLba+nI) >> 8);
  pWriteBuf[nI*nSectorSize+3] = (UCHAR)((nWriteLba+nI));            // LSB
  nWriteSectorCrc32 = Get_CRC32( pWriteBuf+(nI*nSectorSize), nSectorSize-sizeof(DWORD));
  /* 後 2個Byte 是 Sector Index */
  pWriteBuf[nI*nSectorSize+nSectorSize-sizeof(DWORD)]    = (UCHAR)(nWriteSectorCrc32 >> 24); // MSB
  pWriteBuf[nI*nSectorSize+nSectorSize-sizeof(DWORD)+1]  = (UCHAR)(nWriteSectorCrc32 >> 16);
  pWriteBuf[nI*nSectorSize+nSectorSize-sizeof(DWORD)+2]  = (UCHAR)(nWriteSectorCrc32 >> 8);
  pWriteBuf[nI*nSectorSize+nSectorSize-sizeof(DWORD)+3]  = (UCHAR)(nWriteSectorCrc32);       // LSB
 }

 nWriteBufLen = nSectorSize*nWriteLen;
 /* 整個 Write Data Buffer 的 CRC-32 */
 nWriteCrc32  = Get_CRC32( pWriteBuf, nWriteBufLen);
 if( Write16( nWriteLba, nSectorSize, nWriteLen, pWriteBuf) == true)
 {
  memset( pReadBuf, 0, 4096);
  memset( pReadBuf, 0, 16*1024*1024);
  nReadLen = nWriteLen;
  nReadLba = nWriteLba;
  nReadBufLen = nSectorSize * nReadLen;
  if( Read16( nReadLba, nSectorSize, nReadLen, pReadBuf))
  {
   /* 驗證讀回來的資料是否正確 */
   nReadCrc32 = Get_CRC32( pReadBuf, nReadBufLen);
   if( nReadCrc32 != nWriteCrc32)
    nprintf( "Read/Write Test CRAC-32 Failed!");
   if( memcmp( pReadBuf, pWriteBuf, nReadBufLen) == 0)
    nprintf( "Read/Write Test Compare Ok!");
   else
    nprintf( "Read/Write Test Compare Failed!");
  }
 }
// Write12( nWriteLba, nSectorSize, nWriteLen, pWriteBuf);
// Write16( nWriteLba, nSectorSize, nWriteLen, pWriteBuf);

if( pReadBuf)
 delete[] pReadBuf;
if( pWriteBuf)
 delete[] pWriteBuf;
}


 //===========================================
# lsscsi
[0:0:0:0]    disk    SEAGATE  ST3500414SS      0006  /dev/sdb
[0:0:1:0]    disk    SEAGATE  ST3500414SS      0006  /dev/sdc
[1:0:0:0]    disk    ATA      ST1000DM003-9YN1 CC4B  /dev/sda

# lsscsi --transport
[6:0:0:0]    disk    sas:0x5000c500418fac39          /dev/sdb
[6:0:1:0]    disk    sas:0x5000c50041ea5265          /dev/sdc

  /sys/class/scsi_generic/sg2/device/block/sdc
  /sys/class/scsi_generic/sg2/device/scsi_device/6:0:1:0
  /sys/class/scsi_generic/sg2/device/scsi_device/6:0:1:0/sas_address

可以交叉驗證, 就可以知道 /dev/sg3 是那一顆HDD
要注意  Hot-Plug 的狀態下, Target 會改變, /sys/class/scsi_generic/sgN的目錄會自動消失, 也會自動出現.

所以用udevadm 來監控 (但監控這幾個目錄也是可以, 而且比較簡單)
How To Compiler udev


 $ apt-get install sg3-utils
 $ sg_scan -i -x

 //===========================================
 sg3_utils-1.32 Example




如果是 SATA HDD交叉驗證, 請看另一篇取得 SATA PHY Port Index 的相關文章

//===========================================
關於超過 2TB 容量的 Device
請使用 ReadCapacity16, Read16, Write16 這幾組指令
ReadCapacity10  有的會直接失敗, 有的 Device會回傳四個 0xFF
這時就轉換為  ReadCapacity16指令

ReadCapacity回傳的 Capacity是最後一個 LBA位置
所以實際容量為 Capacity + 1

還有一種情況是造假的 Capacity, 也就是回傳的 Capacity都是假的
這時要實際的去 Write & Read Last LBA, 進行資料驗證

記得有一次, 遇到一個Device, 一次 Read/Write 16MB, 回傳都是正常
讀寫的資料只有前面 4MB 資料是正確, 後面 12MB資料都是晶片亂編出來.

其實最常見的是, 寫入時, Device回傳 Write OK, 但確沒有真正的寫入.


//===========================================
//===========================================
方式二:
   使用 /dev/bsg/1:0:0:0
http://sg.danny.cz/sg/p/libsgutils2-2_1.42-0.1_i386.deb
http://www.spinics.net/lists/linux-scsi/msg53920.html
sg_tst_context


//===========================================
//===========================================
方式三:
  這方法只適用 LSI  控制卡上的 Device
  Linux LSI SAS 9211-8i Utility
  Source Code中一個 doScsiIo(), doMptCommand()  的函式
  利用 LSI 驅動程式提供的 mpt_ioctl_command
  直接對 LSI CHIP 下達 SCSI Command
  LSI Util 原始程式是一個 SCSI Command就 Open Device Handle一次
  速度會比較慢, 最好要改寫一些程式.

//===========================================
關於 Linux 下直接使用 ATA Command
  Linux ioctl command for bypassing ATA command(Identify) - Sample Code
  這是直接使用 ioctl(device, HDIO_DRIVE_CMD, buf);
  真是方便, 以前在 NIOS 中, 程式寫了一大堆程式才做出來.
  但還是建議使用 Hdparm 的  sgio方式

另一個是請查詢 hdparm 的原始程式
  https://sourceforge.net/projects/hdparm/
  hdparm.c / sgio.c / sgio.h

//===========================================



Linux IPC 進程間通信

Linux 並沒有 Windows下面的 WM_COPYDAT 這個簡單好用的功能
比較像的是 msgget() 這一組

這有一篇參考文章
http://albert-oma.blogspot.tw/2013/06/linux-ipc.html