PIXNET Logo登入

成功运行的部落格

跳到主文

歡迎光臨成功运行在痞客邦的小天地

部落格全站分類:數位生活

  • 相簿
  • 部落格
  • 留言
  • 名片
  • 7月 23 週四 201514:30
  • linux機制之IDR

linux機制之IDR
一.前言
在linux中有idr,關於idr的用處並不是清楚。查看網上所述知所谓IDR,其实就是和身份证的含义差不多,我们知道,每个人有一个身份证,身份证只是一串数字,从数字,我们就能知道这个人的信息。同样道理,idr的要完成的任务是给要管理的对象分配一个数字,可以通过这个数字找到要管理的对象。類似于為內核任何對象創建一個普通的id,通過該id可以很快的索引到該對象。在該文中將詳細講述linux中idr的具體實現。
二.idr數據結構
在linux中關於idr有兩個很重要的數據結構1. struct idr 2. struct idr_layer,下面具體來看這兩個數據結構
struct idr_layer {
         unsigned long           bitmap;   --標示id在ary中的位置
         struct idr_layer        *ary[1<  --用於保存對象的地址
         int                       count;    --當該值為0時,釋放他
         int                       layer;      --距離葉子的距離
         struct rcu_head                 rcu_head;  --這個不管
};
struct idr {
         struct idr_layer *top;       --標示使用的idr_layer
         struct idr_layer *id_free;    --連接沒有使用的idr_layer
         int                layers;         --拒絕幷發
         int                id_free_cnt;    --空閒的idr_layer計數
         spinlock_t           lock;
};
三.定義idr
#define IDR_INIT(name)                                                \
{                                                                         \
         .top           = NULL,                                         \
         .id_free    = NULL,                                         \
         .layers     = 0,                                        \
         .id_free_cnt     = 0,                                        \
         .lock          = __SPIN_LOCK_UNLOCKED(name.lock),        \
}
#define DEFINE_IDR(name)    struct idr name = IDR_INIT(name)
通過宏定義定義一個名為name的idr實體。
四.具體使用idr
在開始idr具體使用之前,需要說明幾個宏的意思
在32位機下IDR_BITS為5
#define IDR_SIZE (1 << IDR_BITS)   =32即0x20
#define IDR_MASK ((1 << IDR_BITS)-1) =31即0x1F
#define MAX_ID_SHIFT (sizeof(int)*8 - 1)  =31
#define MAX_ID_BIT (1U << MAX_ID_SHIFT) =0x100000000
#define MAX_ID_MASK (MAX_ID_BIT - 1)  =0xFFFFFFFF
#define MAX_LEVEL (MAX_ID_SHIFT + IDR_BITS - 1) / IDR_BITS =7
#define IDR_FREE_MAX MAX_LEVEL + MAX_LEVEL =14
上面的宏定義中比較難以理解的是MAX_LEVEL爲什麽是7,其實很好理解,由於我們是32位機,其可以使用的id號時0xFFFFFFFF,而我們idr_layer一層最多為0x1F,故最少需要7level才能將一個id號瓜分完成。也許空口在這兒說,可能一層霧水。下面根據具體的示例就好理解很多。
4.1 idr_pre_get
int idr_pre_get(struct idr *idp, gfp_t gfp_mask)
{
         while (idp->id_free_cnt < IDR_FREE_MAX) {
                   struct idr_layer *new;
                   new = kmem_cache_zalloc(idr_layer_cache, gfp_mask);
                   if (new == NULL)
                            return (0);
                   move_to_free_list(idp, new);
         }
         return 1;
}
上面的重點是move_to_free_list。
move_to_free_list-> __move_to_free_list
static void __move_to_free_list(struct idr *idp, struct idr_layer *p)
{
         p->ary[0] = idp->id_free;
         idp->id_free = p;
         idp->id_free_cnt++;
}
上面的函數很好理解,下圖會很好的闡述上面函數的意思
當idr_pre_get結束時id_free_count=14.其實該函數的本質是開闢idr_layer內存。
4.2 idr_get_new
分配一個新的idr entry,返回值存儲在id中。
int idr_get_new(struct idr *idp, void *ptr, int *id)
{
         int rv;
         rv = idr_get_new_above_int(idp, ptr, 0);
         if (rv < 0)
                   return _idr_rc_to_errno(rv);
         *id = rv;
         return 0;
}
下面就是按圖索驥,一步一步去分析idr的內幕。
static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id)
{
         struct idr_layer *pa[MAX_LEVEL];
         int id;
         id = idr_get_empty_slot(idp, starting_id, pa);--獲得一個空位
         if (id >= 0) {
                   rcu_assign_pointer(pa[0]->ary[id & IDR_MASK], (struct idr_layer *)ptr);
                   pa[0]->count++;
                   idr_mark_full(pa, id);
         }
         return id;
}
也許單看這些函數會很枯燥,我們來假設一情況,結合具體的內容會好理解很多。在某一驅動中,調用idr_pre_get后第一次調用下面函數。以starting_id為0。
static int idr_get_empty_slot(struct idr *idp, int starting_id,struct idr_layer **pa)
{
         struct idr_layer *p, *new;
         int layers, v, id;
         unsigned long flags;
         id = starting_id;
build_up:
         p = idp->top;   --p=NULL
         layers = idp->layers; -- layers = 0
         if (unlikely(!p)) {
                   if (!(p = get_from_free_list(idp))) –從上面的id_free上卸下一個idr_layer,第一次使用。
                            return -1;
                   p->layer = 0;
                   layers = 1;
         }
//當id為0時,直接跳過下面的while
         while ((layers < (MAX_LEVEL - 1)) && (id >= (1 << (layers*IDR_BITS)))) {
                   layers++;
                   if (!p->count) {
                            p->layer++;
                            continue;
                   }
                   if (!(new = get_from_free_list(idp))) {
                            spin_lock_irqsave(&idp->lock, flags);
                            for (new = p; p && p != idp->top; new = p) {
                                     p = p->ary[0];
                                     new->ary[0] = NULL;
                                     new->bitmap = new->count = 0;
                                     __move_to_free_list(idp, new);
                            }
                            spin_unlock_irqrestore(&idp->lock, flags);
                            return -1;
                   }
                   new->ary[0] = p;
                   new->count = 1;
                   new->layer = layers-1;
                   if (p->bitmap == IDR_FULL)
                            __set_bit(0, &new->bitmap);
                   p = new;
         }
         rcu_assign_pointer(idp->top, p); --idp->top = p;
         idp->layers = layers;    --idp->layers = 1
         v = sub_alloc(idp, &id, pa); --這個是個關鍵
         if (v == IDR_NEED_TO_GROW)
                   goto build_up;
         return(v);
}
從free_list上獲得一個未使用的idr_layer
static struct idr_layer *get_from_free_list(struct idr *idp)
{
         struct idr_layer *p;
         if ((p = idp->id_free)) {
                   idp->id_free = p->ary[0];
                   idp->id_free_cnt--;
                   p->ary[0] = NULL;
         }
         return(p);
}
Sub_alloc函數比較難懂,不過也好理解。
static int sub_alloc(struct idr *idp, int *starting_id, struct idr_layer **pa)
{
         int n, m, sh;
         struct idr_layer *p, *new;
         int l, id, oid;
         unsigned long bm;
         id = *starting_id;   --id = 0;
 restart:
         p = idp->top;    --p應該為第一個可用的idr_layer
         l = idp->layers;  --l = 1;
         pa[l--] = NULL;
         while (1) {
                   n = (id >> (IDR_BITS*l)) & IDR_MASK;  --n = 0
                   bm = ~p->bitmap;               --bm = 0xFFFFFFFF
                   m = find_next_bit(&bm, IDR_SIZE, n); --查找第一個bit為1的位,這裡m = 1
                   if (m == IDR_SIZE) {
                            l++;
                            oid = id;
                            id = (id | ((1 << (IDR_BITS * l)) - 1)) + 1;
                                     if (!(p = pa[l])) {
                                     *starting_id = id;
                                     return IDR_NEED_TO_GROW;
                            }
                            sh = IDR_BITS * (l + 1);
                            if (oid >> sh == id >> sh)
                                     continue;
                            else
                                     goto restart;
                   }
                   if (m != n) {
                            sh = IDR_BITS*l;
                            id = ((id >> sh) ^ n ^ m) << sh;
                   }
                   if ((id >= MAX_ID_BIT) || (id < 0))
                            return IDR_NOMORE_SPACE;
                   if (l == 0)              --現在l=0,直接跳出while
                            break;
                   if (!p->ary[m]) {
                            new = get_from_free_list(idp);
                            if (!new)
                                     return -1;
                            new->layer = l-1;
                            rcu_assign_pointer(p->ary[m], new);
                            p->count++;
                   }
                   pa[l--] = p;
                   p = p->ary[m];
         }
         pa[l] = p;  --此時的pa[0] = idr_layer1
         return id;
}
在idr_get_new_above_int函數中
rcu_assign_pointer(pa[0]->ary[id & IDR_MASK], (struct idr_layer *)ptr);
pa[0]->count++;
idr_mark_full(pa, id);
即*idr_lay1->ary[0] = (struct idr_layer *)ptr , idr_lay1->count = 1;同時將bitmap中對應id的bit位設置為1.
上面主要是針對第一次調用idr_get_new情況的分析。
(繼續閱讀...)
文章標籤

成功运行 發表在 痞客邦 留言(0) 人氣(110)

  • 個人分類:
▲top
  • 7月 22 週三 201517:50
  • Linux之內存管理free

free命令可以顯示Linux系統中空閑的、已用的物理內存及swap內存,及被內核使用的buffer。在Linux系統監控的工具中,free命令是最經常使用的命令之一。下面給出一個free命令的栗子:
1 [root@compute ~]# free
2              total       used       free     shared    buffers cached
3 Mem: 8062392 2092832 5969560 0 187132 1498832
4 -/+ buffers/cache: 406868 7655524
5 Swap: 2097148 0 2097148
下面介紹一下這個命令的輸出結果信息:
第一行:顯示了內存的詳細信息,比如說總內存、已用的內存、空閑的內存、多個進程共享的內存、用於緩沖區的內存以及用於緩存的內存。
第二行:顯示了總的緩沖區內存/緩存的內存使用以及空閑的情況。使用的是第二行used總內存(2092832)-used緩沖區內存 (187132)-used緩存區內存(1498832)=406868.空閑的是total的(8062392)-used的緩存/緩沖區內存 (406868)=7655524.
第三行:顯示了總的交換區總內存、已用的以及空閑的內存。交換區的就是在HDD上創建的用來增加虛擬的增加內存大小的虛擬內存。那麼問題來了:
緩沖區和緩存有什麼區別呢?
緩沖區是針對特定的應用臨時存儲數據的地方,而且這些數據不能被其它應用使用。這和帶寬的概念比較相似。當你嘗試通過網絡來傳輸突發性的數據 時,如果你的網卡只能發送少量的數據時,它能把這些大量的數據存在緩沖區中,以便它能以較低的網卡能接受的速度來發送這些數據。在另一方面,緩存是為了更 快的訪問而存儲一些被頻繁使用的數據的東西。其它的不同就是緩存能被多次使用而緩沖區只能被用一次。但是它們都為你的數據處理提供一個臨時存儲。下面舉些 栗子來說下使用方法。
free命令使用的栗子
1.以兆字節為單位顯示內存(常用)
這個是很好記的,就是-m:
1 [root@compute ~]# free -m
2              total       used       free     shared    buffers     cached
3 Mem: 7873 2043 5829 0 182 1463
4 -/+ buffers/cache: 397 7476
5 Swap: 2047 0 2047
2. 還有以字節、千字節、千兆為單位顯示內存 (不常用)
使用-b、-k、-g參數,即可以字節、千字節、千兆字節為單位顯示內存的大小:
1 [root@compute ~]# free -b
2              total       used       free     shared    buffers     cached
3 Mem: 8255889408 2142736384 6113153024 0 191623168 1534803968
4 -/+ buffers/cache: 416309248 7839580160
5 Swap: 2147479552 0 2147479552
3.顯示總計使用情況
使用-t參數,將會多一行total用於顯示總的使用量:
1 [root@compute ~]# free -t
2              total       used       free     shared    buffers     cached
3 Mem: 8062392 2092516 5969876 0 187132 1498832
4 -/+ buffers/cache: 406552 7655840
5 Swap: 2097148 0 2097148
6 Total: 10159540 2092516 8067024
4.關閉顯示緩沖區那一行
使用-o參數,即可關閉第二行的顯示:
1 [root@compute ~]# free -o
2              total       used       free     shared    buffers     cached
3 Mem: 8062392 2092764 5969628 0 187132 1498832
4 Swap: 2097148 0 2097148
5. 以一個固定的時間間隔更新當前內存使用情況
加上-s參數,然後在-s參數後加上一個整數便會在定期的時間間隔中更新內存的使用情況,下面我將舉個栗子,湊個整數吧,在1024s內更新一次:
1 [root@compute ~]# free -o
2              total       used       free     shared    buffers     cached
3 Mem: 8062392 2092764 5969628 0 187132 1498832
4 Swap: 2097148 0 2097148
6. 額外顯示低以及高的內存的統計數據
使用-l參數額外顯示低以及高的內存大小統計數據:
1 [root@compute ~]# free -l
2              total       used       free     shared    buffers     cached
3 Mem: 8062392 2092516 5969876 0 187132 1498832
4 Low: 8062392 2092516 5969876
5 High: 0 0 0
6 -/+ buffers/cache: 406552 7655840
7 Swap: 2097148 0 2097148
7.查看free命令的版本
使用-V參數顯示版本信息:
1 [root@compute ~]# free -V
2 procps version 3.2.8
(繼續閱讀...)
文章標籤

成功运行 發表在 痞客邦 留言(0) 人氣(22)

  • 個人分類:
▲top
  • 7月 21 週二 201514:04
  • 在Linux下通過PPP上WCDMA

折騰了一番通過幾種USB上網卡在Linux下上WCDMA,在此記錄一下:
通用配置文件:
/etc/ppp/peers/wcdma :
/dev/ttyACM0
460800
connect '/etc/ppp/chat-wcdma'
noauth
usepeerdns
noipdefault
defaultroute
----
註意,其中的/dev/ttyACM0 是串口設備,後面描述。
/etc/ppp/chat-wcdma
#!/bin/sh
#
# This is part 2 of the ppp-on script. It will perform the connection
# protocol for the desired connection.
#
exec /usr/sbin/chat -v        \
    ECHO        ON        \
    ABORT        'BUSY'        \
    ABORT        'NO ANSWER'    \
    ABORT        'ERROR'        \
    TIMEOUT        20        \
    ''        'AT'        \
    OK        AT+CFUN=6    \
        OK              'AT+CGDCONT=1,"IP","3gnet",,0,0' \
    OK        'ATDT*99#'    \
    CONNECT    
其中的3gnet 就是聯通WCDMA上網需要的APN啦。 CFUN=6是讓索愛MD-400只工作在WCDMA網絡下。相應地CFUN=5就只工作再GSM/GPRS/EDGE下, CFUN=1就是全自動選擇
撥號連接時,用
              pppd call wcdma
即可。你可以自己設置IP偽裝NAT等等事宜。
以上是用索尼愛立信MD-400上網卡設置的,如果你用的是華為E1750, 那麽設備名就換成/dev/ttyUSB0 即可。
無論是索愛MD400還是華為E1750, 都需要小工具 usb_modeswitch 1.0.2 切換其倒黴的USB工作狀態,詳細的介紹和下載可以去這裏看看: http://www.draisberghof.de/usb_modeswitch/
如果是電信的天翼CDMA2000 EV-DO 3G, 測試了一下華為EC1260,基本區別不大,註意以下幾點:
1, 2.6.19之後的核心有專門對付EC1260的代碼, 插進去直接就令其工作在Modem模式,你會看到有/dev/ttyUSB0設備,可以不需要usb_modeswitch的幫助。低版本核心可能還離不開。
2, EVDO沒有APN的概念,上面的/etc/ppp/chat-wcdma 腳本改成這樣即可:
[root@pxi4g ppp]# cat chat-evdo
#!/bin/sh
#
# This is part 2 of the ppp-on script. It will perform the connection
# protocol for the desired connection.
#
exec /usr/sbin/chat -v        \
    ECHO        ON        \
    ABORT        'BUSY'        \
    ABORT        'NO ANSWER'    \
    ABORT        'ERROR'        \
    TIMEOUT        20        \
    ''        'AT'        \
    OK        'ATDT#777'    \
    CONNECT    
也就是說,直接撥特殊號碼#777即可。 peers/wcdma文件可以不改。
(繼續閱讀...)
文章標籤

成功运行 發表在 痞客邦 留言(0) 人氣(445)

  • 個人分類:
▲top
  • 7月 20 週一 201512:55
  • 修改linux分區卷標

http://647777.blogspot.com/2015/07/linux_15.html
Fat16/Fat32格式:
#安裝
$ sudo apt-get install mtools
#新建配置文件
$ cp /etc/mtools.conf ~/.mtoolsrc
#編輯剛復制的”~/.mtoolsrc”文件,在最後一行加入如下命令行:
drive i: file="/dev/sda2" //裏面的”/devsda2”應根據實際情況更改為你要改的盤
#更改命令提示符路徑到”i:”盤:
$ mcd i:
#查看”i:”當前的卷標
$ sudo mlabel -s i:
#更改”i:”盤原始卷標為你喜歡的新卷標名:
$ sudo mlabel i: newLabelName
--------
NTFS格式
#安裝
$ sudo apt-get install ntfsprogs
#修改
sudo ntfslabel /dev/sda1 newLabelName //裏面的"/dev/sda1"應根據實際情況修改
--------
ext2/ext3格式
使用內置命令
$ sudo e2label /dev/sda1 newLabelName
(繼續閱讀...)
文章標籤

成功运行 發表在 痞客邦 留言(0) 人氣(6)

  • 個人分類:
▲top
  • 7月 18 週六 201523:57
  • Linux之文件系統理論

低級格式化: 廠商設置,用於創建磁盤隧道
Paration:劃分獨立的文件系統
MBR:主引導記錄(512Byte) 只關重要
 Master Boot Record
      446Bytes:BootLoader
      64Bytes:
              16Bytes:標識一個主分區
      2Bytes:Magic Number
主分區選擇一個作為擴展分區
主+擴戰<=4 做多只能有4個主分區
擴展分區裏存放指針指向更大的空間在更大的空間可以劃分多個分區
按柱面存儲同時按柱面分區
磁盤的讀寫與延遲:磁頭轉到數據所在的相應磁道以及數據需要再轉一圈與磁頭相碰
磁道越靠近外圍,讀寫速率越高,因此經常訪問的數據存儲在磁道外圍
文件系統本身不在分區上,文件系統裏的數據在分區上,文件系統只是一種軟件
文件系統:
     元數據存儲區:
         塊位圖:位圖為0表示沒用過的邏輯存儲區
         iNode去
     數據存儲區:
         邏輯存儲單元(block 磁盤塊) 有編號
iNode(索引):存儲有屬主屬組擴展屬性等,就是沒有文件名
文件名在目錄下
例如:/var/log/messages
 先在iNode位圖中找到根所對應的iNode號
 再根據根的iNode號找到對應的存儲單元
 根的存儲單元裏存儲的是var文件名以及var對應的iNode號
 回到塊位圖
 根據找到var對應的iNode,找到對應的存儲單元
 var的存儲單元裏存儲的是log文件名及log對用的iNode
 回到塊位圖
 根據找到log的iNode,找到對應存儲單元
 log的存儲單元裏存儲的是messag文件名及messag對應的iNode
 回到塊位圖
 根據message的iNode,找到對應的存儲單元
所以目錄不是容器,它也是個文件,是個路徑映射表
創建文件 例如/backup/a.txt 假設backup目錄已經存在
 先掃描iNode位圖找一個沒人用的iNode號
 找backu對應的iNode,根據iNode找到存儲塊
 存儲塊的內容為a.txt及剛開始的iNode號
 到塊位圖中給其分配n個存儲塊
 最開始找的iNode號即指向這些存儲塊
刪除文件:
 將對應的iNode號標為未使用
 將對應的存儲塊標記為空(原來的數據並未刪除)新的數據來時選擇直接覆蓋
同一分區剪切 速度比較快
只是將原來的目錄裏對應的映射內容刪除了
在新的目錄裏創建映射
文件的iNode和磁盤塊(存儲單元)都未動
每個分區有很多塊組,沒一個塊組都有源數據存儲區和數據存儲區
硬鏈接和符號鏈接(軟鏈接)
硬鏈接指向的是同一個文件  iNode號相同,只是有不同的路徑
軟鏈接指向的是不同的文件 iNode號不同
硬鏈接刪除其中一個也能訪問另一個
軟鏈接刪除a-->b中的b 則a不能訪問   
找到/backup/a/m.txt的iNode 但是該iNode不是指向存儲塊而是指向/backup/b/n.txt的路徑名稱
則該/backup/a/m.txt文件的大小顯示為/backup/b/n.txt的字符個數
ln [-s -v] SRC DEST
硬鏈接:
 1、只能對文件創建,不能用於目錄
 2、不能跨文件系統
 3、創建硬鏈接會增加文件被鏈接的次數
 4、原文件被刪除後仍能通過鏈接文件訪問內容
符號鏈接:
 1、可用於目錄
 2、可跨文件系統
 3、不會增加被鏈接文件的鏈接次數
 4、大小為指定路徑所包含的字符個數
 5、原文件刪除後鏈接文件不能訪問原內容
du    
 -s
 -h
df:分區使用情況
 -i iNode
 -h
 -P 在同一行顯示
/dev
 major number
 minor number
    標識同一類型的不同設備
    主次設備號均放在iNode中,不占實際物理內存
mknod  創建塊設備文件或字符設備文件
mknod [options] NAME TYPE [MAJOR MINOR]
  -m MODE
硬盤設備的設備文件名:
IDE,ATA: hd
STAT:sd
SCSI: sd
USB: sd
 a,b,c...來區別同一種類型下的不同設備
IDE
 第一個IDE口:主、從
         /dev/hda /dev/hdb
 第二個IDE口:主、從
         /dev/hdc /dev/hdd
sda,sdb,sdc...
hda:
 hda1:第一個主分區
 hda2:
 hda3:
 hda4:
 hda5:第一個邏輯分區
查看當前系統識別了幾塊硬盤
fdisk -l [/dev/to/some_device_file]
文件系統屬於內核的功能
mkfs -t 文件系統類型
VFS(Virtual File System)
 mkdir 這個命令可能只對ext3這個文件類型的系統有效,對於其他文件系統無效,為了讓mkdir對於所有類型的文件系統都有效,在所有不同類型的文件系統上抽象出一個VFS
 VFS為mkdir提供統一的接口
一個分區就是一個獨立的文件系統
只有根是自引用的
例如:/usr/var 假若根在第一個分區,若將usr關聯到第二分區,則usr本身在第一分區。而usr裏的內容在第二分區,此時usr只是作為第二分區的入口,本身屬於第一分區,不關聯的話,usr裏的內容還是在第一分區
根所在的分區稱為根分區或者根文件系統
管理磁盤分區
fdisk /dev/sda
 p:顯示當前硬件的分區,包括沒保存的改動
 n:創建新分區
     e:擴展分區
     p:主分區
 d:刪除分區
 w:保存退出
 q:不保存退出
 t: 修改分區類型
 l:顯示所支持的所有類型
partprobe 讓內核重讀分區表
進程在用戶模式,用戶空間
內核模式,內核空間
CPU有4個級別圓環。由內往外ring0,ring1,ring2,ring3,ring4
 ring0 內核 與外部硬件交互
 ring1 不使用
 ring2 不使用
 ring3 用戶進程
blocksize:1024,2048,4096Bytes 即 1k 2k 4k linux上
設備文件 套接字文件 管道文件都不需要磁盤塊 所以沒有文件大小
iNode map
         通過掃描位圖來判斷iNode和磁盤塊是否沒被錄用
block map
將數據存儲區分為多個塊組,每個塊組都有各自的iNode bitmap 和
block bitmap
塊組的大小個數由源數據區的super block 確定
為了防止super block崩潰,可有多個備份
superblock 包含的信息:
         有幾個塊組
         每個塊組有多少個磁盤塊
         空閑iNode
         空閑磁盤塊
         等等
塊組描述符表(GDT group description table)
boot block blockgroup0 blockgroup1 blockgourp2...
blockgroup0:superblock
         GDT
         block bitmap
         iNode bitmap
         iNode table
         data blocks
超級塊
描述整個分區的文件系統信息,例如塊大小,文件系統版本號,上次mount時間等待
超級快在每個組的開頭都有一份拷貝
塊組描述符
由很多塊組描述組成,整個分區分成多個個塊組對應有多少個塊組描述符
每個塊組描述符存儲一個組的描述信息,例如在這個塊組中從哪兒開始是iNode表,從哪兒開始是數據塊,空閑的iNode和數據塊還有多少等等。
和超級塊類似,塊組描述符表在每個塊組的開頭都有一份拷貝,這些信息十分重要,一旦超級塊意外損壞就會丟失整個分區的數據,一旦塊組描述符意外損壞就會丟失整個塊組的數據,因此他們有很多拷貝
塊位圖(Block Bitmap)
塊位圖就是用來描述整個塊組中哪些塊已用哪些空閑。它本身占一個塊,其中的每個bit代表本塊組中的一個塊,這個bit為1表示塊已用,為0表示該空閑塊可用
iNode位圖
和塊位圖類似,本身占一個塊,其中的每個bit表示一個inode是否空閑可用
inode表(inode Table)
一個文件除了數據需要存儲之外,一些描述信息也需要存儲,例如文件類型(常規、目錄、符號鏈接等),權限,文件大小,創建/修改/訪問時間等,也就是ls -l命令看到的那些信息,這些信息存在inode中而不是數據塊中
每個文件都有一個inode,一個塊組中的所有inode組成了inode表
inode表占多少個塊在格式化時就要決定並寫入塊組描述符中
mke2fs格式化工具的默認策略是一個塊組有多少個8KB就分配多少個inode
數據塊(Data Block)
對於常規文件,文件的數據存儲在數據塊中
對於目錄,該目錄下的所有文件名和目錄名存儲在數據塊中,文件名保存在它所在目錄的數據塊中
除文件名之外,ls -l命令看到的其它信息都保存在該文件的inode中
目錄也是一種文件,是一種特殊類型的文件
對於符號鏈接,如果目標路徑名較短則直接保存在inode中以便更快地查找,如果目標路徑名較長則分配一個數據塊來保存
設備文件、FIFO和socket等特殊文件沒有數據塊,設備文件的主設備號和次設備號保存在inode中
iNode號內容有 MODE,Owner Info,Group Info,Size,TimesStamps,磁盤塊的序列號,主次設備號
磁盤分割在文件系統創建的那一刻起已經把元數據區域預留出來
(繼續閱讀...)
文章標籤

成功运行 發表在 痞客邦 留言(0) 人氣(17)

  • 個人分類:
▲top
  • 7月 17 週五 201516:50
  • linux的exec函數家族

1.exec家族一共有六個函數,分別是:
(1)int execl(const char *path, const char *arg, ......);
(2)int execle(const char *path, const char *arg, ...... , char * const envp[]);
(3)int execv(const char *path, char *const argv[]);
(4)int execve(const char *filename, char *const argv[], char *const envp[]);
(5)int execvp(const char *file, char * const argv[]);
(6)int execlp(const char *file, const char *arg, ......);
其中只有execve是真正意義上的系統調用,其它都是在此基礎上經過包裝的庫函數。
    exec函數族的作用是根據指定的文件名找到可執行文件,並用它來取代調用進程的內容,換句話說,就是在調用進程內部執行一個可執行文件。這裏的可執行文件既可以是二進制文件,也可以是任何Linux下可執行的腳本文件。
與一般情況不同,exec函數族的函數執行成功後不會返回,因為調用進程的實體,包括代碼段,數據段和堆棧等都已經被新的內容取代,只留下進程ID等一些表面上的信息仍保持原樣,頗有些神似"三十六計"中的"金蟬脫殼"。看上去還是舊的軀殼,卻已經註入了新的靈魂。只有調用失敗了,它們才會返回一個-1,從原程序的調用點接著往下執行。
2.它們之間的區別:
第一個區別是:
前四個取路徑名做為參數,後兩個取文件名做為參數,如果文件名中不包含 “/” 則從PATH環境變量中搜尋可執行文件, 如果找到了一個可執行文件,但是該文件不是連接編輯程序產生的可執行代碼文件,則當做shell腳本處理。
第二個區別:
前兩個和最後一個函數中都包括“ l ”這個字母 ,而另三個都包括“ v ”, " l "代表 list即表 ,而" v "代表 vector即矢量,也是是前三個函數的參數都是以list的形式給出的,但最後要加一個空指針,如果用常數0來表示空指針,則必須將它強行轉換成字符指針,否則有可能出錯。,而後三個都是以矢量的形式給出,即數組。
最後一個區別:
與向新程序傳遞環境變量有關,如第二個和第四個以e結尾的函數,可以向函數傳遞一個指向環境字符串指針數組的指針。即自個定義各個環境變量,而其它四個則使用進程中的環境變量。
 
3.實例講解:
(1)在平時的編程中,如果用到了exec函數族,一定記得要加錯誤判斷語句。先判斷execl的返回值,如果出錯,可以用perror( )函數打印出錯誤信息。
如:if (execl(“path”,”..””(char *)0) < 0)
    {
       perror(“execl error!”);
   }
如果調用出錯,可輸出:execl error!: 錯誤原因   這樣可方便查找出錯原因
(2)註意下面書寫格式:
先定義一個指針數組:char *argv[]={“ls”,”-l”,(char *)0}
用execv調用ls:    execv(“/bin/ls”,argv)
 如果用execvp
execvp(“ls”,argv)      //直接寫ls就可以了
註意:
execl調用shell 時,要在shell腳本中指明使用的shell版本:#!/bin/bash。在命令行下執行shell腳本,系統為它自動打開一個shell,在程序中沒有shell,在調用shell腳本時,會出錯,所以要在shell腳本中先打開shell。
(繼續閱讀...)
文章標籤

成功运行 發表在 痞客邦 留言(0) 人氣(226)

  • 個人分類:
▲top
  • 7月 16 週四 201511:16
  • Linux常見環境變量及其作用

Linux是一個多用戶多任務的操作系統,可以在Linux中為不同的用戶設置不同的運行環境,具體做法是設置不同用戶的環境變量(稱之為 Linux中定制的環境變量)。但是仍有些環境變量是用戶都需要的,我們稱之為Linux中常見的環境變量,本文只涉及常見的環境變量的簡介!
Linux中常見的環境變量有:
1.PATH:指定命令的搜索路徑
2.HOME:指定用戶的主工作目錄(即用戶登陸到Linux系統中時,默認的目錄)
3.HISTSIZE:指保存歷史命令記錄的條數。
4.LOGNAME:指當前用戶的登錄名。
5.HOSTNAME:指主機的名稱,許多應用程序如果要用到主機名的話,通常是從這個環境變量中來取得的。
6.SHELL:指當前用戶用的是哪種Shell。
7.LANG/LANGUGE:和語言相關的環境變量,使用多種語言的用戶可以修改此環境變量。
8.MAIL:指當前用戶的郵件存放目錄。
9.PS1:命令基本提示符,對於root用戶是#,對於普通用戶是$。
10.PS2:附屬提示符,默認是“>”。
    備註:可以通過修改此環境變量來修改當前的命令符,比如下列命令會將提示符修改成字符串“Hello,My        NewPrompt ”。
  # PS1="Hello,My NewPrompt"
註意:上述變量的名字並不固定,如HOSTNAME在某些Linux系統中可能設置成HOST
當然,我所列舉的上述環境變量並非窮盡列出!
Linux也提供了修改和查看環境變量的命令!下面通過幾個實例來說明:
1.echo         顯示某個環境變量值 echo $PATH
2.export     設置一個新的環境變量 export HELLO="hello" (可以無引號)
3.env         顯示所有環境變量
4.set         顯示本地定義的shell變量
5.unset         清除環境變量 unset HELLO
6.readonly     設置只讀環境變量 readonly HELLO
(繼續閱讀...)
文章標籤

成功运行 發表在 痞客邦 留言(0) 人氣(16)

  • 個人分類:
▲top
  • 7月 15 週三 201515:54
  • Linux內核的OOM機制

Linux 內核根據應用程序的要求分配內存,通常來說應用程序分配了內存但是並沒有實際全部使用,為了提高性能,這部分沒用的內存可以留作它用,這部分內存是屬於每個進程的,內核直接回收利用的話比較麻煩,所以內核采用一種過度分配內存(over-commit memory)的辦法來間接利用這部分“空閑”的內存,提高整體內存的使用效率。一般來說這樣做沒有問題,但當大多數應用程序都消耗完自己的內存的時候麻煩就來了,因為這些應用程序的內存需求加起來超出了物理內存(包括 swap)的容量,內核(OOM killer)必須殺掉一些進程才能騰出空間保障系統正常運行。用銀行的例子來講可能更容易懂一些,部分人取錢的時候銀行不怕,銀行有足夠的存款應付,當全國人民(或者絕大多數)都取錢而且每個人都想把自己錢取完的時候銀行的麻煩就來了,銀行實際上是沒有這麽多錢給大家取的。
比如某天一臺機器突然ssh遠程登錄不了,但能ping通,說明不是網絡的故障,原因是sshd進程被OOM killer殺掉了。重啟機器後查看系統日誌/var/log/messages會發現Out of Memory:Kill process 1865(sshd)類似的錯誤信息。又比如有時VPS 的MySQL總是無緣無故掛掉,或者VPS 經常死機,登陸到終端發現都是常見的 Out of memory 問題。這通常是因為某時刻應用程序大量請求內存導致系統內存不足造成的,這時會觸發 Linux 內核裏的 Out of Memory (OOM) killer,OOM killer 會殺掉某個進程以騰出內存留給系統用,不致於讓系統立刻崩潰。如果檢查相關的日誌文件(/var/log/messages)就會看到下面類似的Out of memory: Kill process 信息:
...
Out of memory: Kill process 9682 (mysqld) score 9 or sacrifice child
Killed process 9682, UID 27, (mysqld) total-vm:47388kB, anon-rss:3744kB, file-rss:80kB
httpd invoked oom-killer: gfp_mask=0x201da, order=0, oom_adj=0, oom_score_adj=0
httpd cpuset=/ mems_allowed=0
Pid: 8911, comm: httpd Not tainted 2.6.32-279.1.1.el6.i686 #1
...
21556 total pagecache pages
21049 pages in swap cache
Swap cache stats: add 12819103, delete 12798054, find 3188096/4634617
Free swap = 0kB
Total swap = 524280kB
131071 pages RAM
0 pages HighMem
3673 pages reserved
67960 pages shared
124940 pages non-shared
Linux內核有個機制叫OOM killer(Out-Of-Memory killer),該機制會監控那些占用內存過大,尤其是瞬間很快消耗大量內存的進程,為了防止內存耗盡內核會把該進程殺掉。
內核檢測到系統內存不足、挑選並殺掉某個進程的過程可以參考內核源代碼 linux/mm/oom_kill.c,當系統內存不足的時候,out_of_memory() 被觸發,然後調用 select_bad_process() 選擇一個“bad”進程殺掉,判斷和選擇一個“bad”進程的過程由 oom_badness()決定,最 bad 的那個進程就是那個最占用內存的進程。
/**
* oom_badness - heuristic function to determine which candidate task to kill
* @p: task struct of which task we should calculate
* @totalpages: total present RAM allowed for page allocation
*
* The heuristic for determining which task to kill is made to be as simple and
* predictable as possible. The goal is to return the highest value for the
* task consuming the most memory to avoid subsequent oom failures.
*/
unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg,
const nodemask_t *nodemask, unsigned long totalpages)
{
long points;
long adj;
if (oom_unkillable_task(p, memcg, nodemask))
return 0;
p = find_lock_task_mm(p);
if (!p)
return 0;
adj = (long)p->signal->oom_score_adj;
if (adj == OOM_SCORE_ADJ_MIN) {
task_unlock(p);
return 0;
}
/*
* The baseline for the badness score is the proportion of RAM that each
* task's rss, pagetable and swap space use.
*/
points = get_mm_rss(p->mm) + atomic_long_read(&p->mm->nr_ptes) +
get_mm_counter(p->mm, MM_SWAPENTS);
task_unlock(p);
/*
* Root processes get 3% bonus, just like the __vm_enough_memory()
* implementation used by LSMs.
*/
if (has_capability_noaudit(p, CAP_SYS_ADMIN))
adj -= (points * 3) / 100;
/* Normalize to oom_score_adj units */
adj *= totalpages / 1000;
points += adj;
/*
* Never return 0 for an eligible task regardless of the root bonus and
* oom_score_adj (oom_score_adj can't be OOM_SCORE_ADJ_MIN here).
*/
return points > 0 ? points : 1;
}
從上面的 oom_kill.c 代碼裏可以看到 oom_badness() 給每個進程打分,根據 points 的高低來決定殺哪個進程,這個 points 可以根據 adj 調節,root 權限的進程通常被認為很重要,不應該被輕易殺掉,所以打分的時候可以得到 3% 的優惠(分數越低越不容易被殺掉)。我們可以在用戶空間通過操作每個進程的 oom_adj 內核參數來決定哪些進程不這麽容易被 OOM killer 選中殺掉。比如,如果不想 MySQL 進程被輕易殺掉的話可以找到 MySQL 運行的進程號後,調整 /proc/PID/oom_score_adj 為 -15(註意 points 越小越不容易被殺)防止重要的系統進程觸發(OOM)機制而被殺死,內核會通過特定的算法給每個進程計算一個分數來決定殺哪個進程,每個進程的oom分數可以在/proc/PID/oom_score中找到。每個進程都有一個oom_score的屬性,oom killer會殺死oom_score較大的進程,當oom_score為0時禁止內核殺死該進程。設置/proc/PID/oom_adj可以改變oom_score,oom_adj的範圍為【-17,15】,其中15最大-16最小,-17為禁止使用OOM,至於為什麽用-17而不用其他數值(默認值為0),這個是由linux內核定義的,查看內核源碼可知:路徑為linux-xxxxx/include /uapi/linux/oom.h。
oom_score為2的n次方計算出來的,其中n就是進程的oom_adj值,oom_score的分數越高就越會被內核優先殺掉。當oom_adj=-17時,oom_score將變為0,所以可以設置參數/proc/PID/oom_adj為-17禁止內核殺死該進程。
上面的那個MySQL例子可以如下解決來降低mysql的points,降低被殺掉的可能:
# ps aux | grep mysqld
mysql 2196 1.6 2.1 623800 44876 ? Ssl 09:42 0:00 /usr/sbin/mysqld
# cat /proc/2196/oom_score_adj
0
# echo -15 > /proc/2196/oom_score_adj
當然了,保證某個進程不被內核殺掉可以這樣操作:
echo -17 > /proc/$PID/oom_adj
例如防止sshd被殺,可以這樣操作:
pgrep -f "/usr/sbin/sshd" | while read PID;do echo -17 > /proc/$PID/oom_adj;done
為了驗證OOM機制的效果,我們不妨做個測試。
首先看看我系統現有內存大小,沒錯96G多,物理上還要比查看的值大一些。
再看看目前進程最大的有哪些,top查看,我目前只跑了兩個java程序的進程,分別4.6G,再往後redis進程吃了21m,iscsi服務占了32m,gdm占了25m,其它的進程都是幾M而已。
現在我自己用C寫一個叫bigmem程序,我指定該程序分配內存85G,呵呵,效果明顯,然後執行後再用top查看,排在第一位的是我的bigmem,RES是物理內存,已經吃滿了85G。
繼續觀察,當bigmem穩定保持在85G一會後,內核會自動將其進程kill掉,增長的過程中沒有被殺,如果不希望被殺可以執行
pgrep -f "bigmem" | while read PID; do echo -17 > /proc/$PID/oom_adj;done
執行以上命令前後,明顯會對比出效果,就可以體會到內核OOM機制的實際作用了。
註意,由任意調整的進程衍生的任意進程將繼承該進程的 oom_score。例如:如果 sshd 進程不受 oom_killer 功能影響,所有由 SSH 會話產生的進程都將不受其影響。這可在出現 OOM 時影響 oom_killer 功能救援系統的能力。
當然還可以通過修改內核參數禁止在內存出現OOM時采取殺掉進程的這種機制,但此時會觸發kernel panic。當內存嚴重不足時,內核有兩種選擇:1.直接panic 2.殺掉部分進程,釋放一些內存。通過/proc/sys/vm/panic_on_oom可以控制,當panic_on_oom為1時,直接panic,當panic_on_oom為0時內核將通過oom killer殺掉部分進程。(默認是為0的)
# sysctl -w vm.panic_on_oom=1
vm.panic_on_oom = 1   //1表示關閉,默認為0表示開啟OOM killer
# sysctl –p
我們可以通過一些內核參數來調整 OOM killer 的行為,避免系統在那裏不停的殺進程。比如我們可以在觸發 OOM 後立刻觸發 kernel panic,kernel panic 10秒後自動重啟系統:
# sysctl -w vm.panic_on_oom=1
vm.panic_on_oom = 1
# sysctl -w kernel.panic=10
kernel.panic = 10
或者:
# echo "vm.panic_on_oom=1" >> /etc/sysctl.conf
# echo "kernel.panic=10" >> /etc/sysctl.conf
當然,如果需要的話可以完全不允許過度分配內存,此時也就不會出現OOM的問題(不過不推薦這樣做):
# sysctl -w vm.overcommit_memory=2
# echo "vm.overcommit_memory=2" >> /etc/sysctl.conf,
vm.overcommit_memory 表示內核在分配內存時候做檢查的方式。這個變量可以取到0,1,2三個值。對取不同的值時的處理方式都定義在內核源碼 mm/mmap.c 的 __vm_enough_memory 函數中。
0:當用戶空間請求更多的的內存時,內核嘗試估算出剩余可用的內存。此時宏為 OVERCOMMIT_GUESS,內核計算:NR_FILE_PAGES 總量+SWAP總量+slab中可以釋放的內存總量,如果申請空間超過此數值,則將此數值與空閑內存總量減掉 totalreserve_pages(?) 的總量相加。如果申請空間依然超過此數值,則分配失敗。
1:當設這個參數值為1時,宏為 OVERCOMMIT_ALWAYS,內核允許超量使用內存直到用完為止,主要用於科學計算。
2:當設這個參數值為2時,此時宏為 OVERCOMMIT_NEVER,內核會使用一個決不過量使用內存的算法,即系統整個內存地址空間不能超過swap+50%的RAM值,50%參數的設定是在overcommit_ratio中設定,內核計算:內存總量×vm.overcommit_ratio/100+SWAP 的總量,如果申請空間超過此數值,則分配失敗。vm.overcommit_ratio 的默認值為50。
以上為粗略描述,在實際計算時,如果非root進程,則在計算時候會保留3%的空間,而root進程則沒有該限制。詳細過程可看源碼。
找出最有可能被 OOM Killer 殺掉的進程:
我們知道了在用戶空間可以通過操作每個進程的 oom_adj 內核參數來調整進程的分數,這個分數也可以通過 oom_score 這個內核參數看到,比如查看進程號為981的 omm_score,這個分數被上面提到的 omm_score_adj 參數調整後(-15),就變成了3:
# cat /proc/981/oom_score
18
# echo -15 > /proc/981/oom_score_adj
# cat /proc/981/oom_score
3
下面這個 bash 腳本可用來打印當前系統上 oom_score 分數最高(最容易被 OOM Killer 殺掉)的進程:
#!/bin/bash
for proc in $(find /proc -maxdepth 1 -regex '/proc/[0-9]+'); do
printf "%2d %5d %s\n" \
"$(cat $proc/oom_score)" \
"$(basename $proc)" \
"$(cat $proc/cmdline | tr '\0' ' ' | head -c 50)"
done 2>/dev/null | sort -nr | head -n 10
# chmod +x oomscore.sh
# ./oomscore.sh
   18 981 /usr/sbin/mysqld
        4 31359 -bash
        4 31056 -bash
   1 31358 sshd: root@pts/6
        1 31244 sshd: vpsee [priv]
        1 31159 -bash
        1 31158 sudo -i
        1 31055 sshd: root@pts/3
        1 30912 sshd: vpsee [priv]
        1 29547 /usr/sbin/sshd –D
註意:
1.Kernel-2.6.26之前版本的oomkiller算法不夠精確,RHEL6.x版本的2.6.32可以解決這個問題。
2.子進程會繼承父進程的oom_adj。
3.OOM不適合於解決內存泄漏(Memory leak)的問題。
4.有時free查看還有充足的內存,但還是會觸發OOM,是因為該進程可能占用了特殊的內存地址空間。
(繼續閱讀...)
文章標籤

成功运行 發表在 痞客邦 留言(0) 人氣(8,031)

  • 個人分類:
▲top
  • 7月 14 週二 201513:54
  • linux之shell拾零

1. Linux中命令順序執行:
command1;command1
命令1結束,順序執行命令2
# echo Hello World! ; pwd ; ls
command1&&command2
第一個命令成功結束執行第二個命令
# ls /home/alex && cd /home/alex
command1||command2
第一個命令執行不成功才執行第二個命令
# ls /home/alex/copy || cp copy  /home/alex
note: 只有當目錄/home/alex下不存在copy文件時,才將該文件復制到/home/alex目錄下,如果該目       錄下已經存在該文件,則不再進行復制
2. Linux $標識符意思
$0:        存儲命令名
$1~ $n:    存儲第1個到第n個命令參數
$#:        存儲參數個數
$*:         存儲所有參數,作為一個字符串
$@:         存儲所有參數,作為一個字符串數組
$$:        當前命令的進程號
$!:        前一個命令的進程號
$?:        前一個命令的返回結果
3. 變量賦值
${var:-value}: 如果變量var存在,返回變量var值,否則返回value
${var:=value}: 如果變量var存在,返回變量var值,否則var=value, 返回value
${var:?value}: 如果變量var存在,返回變量var值,否則輸出錯誤消息value
${var:+value}: 如果變量var存在,返回變量var值,否則不返回任何值
${var:offset[:length]}: 返回變量var中offset開始length長度字符串,第一位offset=0
4. Linux中軟鏈接與硬鏈接區別
1. 軟鏈接可以跨越文件系統,硬鏈接不可以
2. 關於I節點。硬鏈接不管有多少個,都指向的是同一個I節點,即inode number相同,會把節點連接       增加,只要節點連接數不是0,文件就一直存在,不管刪除的是源文件還是鏈接文件,只要有一個存         在,文件就存在,當修改源文件或鏈接文件中任何一個的時候,其它文件都會同步修改。軟鏈接不直接       使用I節點作為文件指針,而是使用文件路徑名作為指針,所以刪除鏈接文件對源文件無影響,但是刪       除源文件,鏈接文件就會找不到指向的文件,軟鏈接有自己的inode,並在磁盤上有一小片空間存放路       徑名
3. 軟鏈接可以對一個不存在的文件進行鏈接
4. 軟鏈接可以對目錄進行鏈接
5. Shell 通配符
?:        表示任意單個字符
*:        表示任意長度的任意字符串
[]:        表示匹配放在[]中的字符集中的任意一個字符
{}:    將大括號中 的字符串以及前導字符和後繼字符串作為匹配條件
# ls *.txt    
    #顯示當前目錄下所有以.txt結尾的文件
# ls 20.?
    #顯示所有由四個字符組成的文件名,且前3個字符必須是“20.”
# ls 2[0, 1] *
    #顯示當前目錄下所有以“20”或“21”開頭的文件, 通配符[]在表示一個連續的數字或字符時可                       以使用“_”,例如[1_9]表示數字1~9,[1~3, 8, 9]表示1,2,3,8,9中任意一個數字。
# echo m{oon,op,ud}s
    #顯示moons, mops, muds
6. 單引號、雙引號及反引號
雙引號(“ ”):在雙引號中的字符,除了“$”,""","'",和“\”以外的所有字符都被翻譯成字符本身
單引號('):在單引號中的所有字符(如“$”,""","'",和“\”)都失去特殊意義,而成為普通字符
反引號(`): Esc下面的那個鍵,在反引號中的的字符被解釋成命令
# echo "$PATH"
/usr/kerberos/sbin...
#echo "I am $USER"
I am root
# echo '$PATH'
$PATH
# echo Today \' year is `date +%y`
Today ' year is 10
7. 運行腳本
1.  通過chmod命令把文件權限設成可讀、可執行然後直接執行該可執行文件
$ chmod u+x 腳本文件名
$ ./腳本文件名及其參數
2. 直接使用shell的啟動命令來執行腳本
$ bash 腳本文件名及其參數
$ bash 腳本文件名及其參數
$ tcsh 腳本文件名及其參數
$ sh 腳本文件名及其參數
$ tcsh tcshsript
3. 使用bash內部命令“source”或“.”運行shell腳本
$ source 腳本文件名及其參數
$ . 腳本文件名及其參數
$ source hello
hello world!
8. 創建變量
1. declare 或 typeset 創建變量
如:declare -r x    #創建只讀變量x
2. 直接給變量賦值來創建變量,為變量賦值,變量名前不應加美元符號"$", 如下
CITY=Beijing    #"=" 前後不要有空格
3. 使用變量時,前面要加美元符號“$”
如:echo $SHELL
4. 變量使用舉例:
# order=22
# echo "Tom is ${order}nd"
輸出:Tom is 22nd   
5. 清除變量
uset x    #只能清楚非只讀變量
9. read命令賦值
1. 多個數據或變量之間用空格分隔
2. 若變量變量個數與輸入數據個數相等,則對應賦值
3. 若變量變量個數大於輸入數據個數相等,則沒有輸入數據的變量取空值
4. 若變量變量個數小於輸入數據個數相等,則多余的數據賦值給最後一個變量
10. 數組
1. 數組定義
name=(element1 element2 ...)
e.g.: name=("alex" "jim")
2. 顯示系統所有數組
# declare -a
3. 數組復制
all=("${name[*]}")    //將數組name的全部內容作為一個元素復制到all中,即all=("alex jim")
list=(""${name[@]})        //將數組name的內容復制到一個新數組list中
4. 數組元素個數
${#name[*]}
5. 數組元素的長度
${#name[ num]}
11. 算數運算
expr: 表達式處理命令,5種算數運算:+ - * / %
# x=`expr $b / $a`
# x=`expr $b % $a`
let: 為變量賦值
# let y=x / 2
(繼續閱讀...)
文章標籤

成功运行 發表在 痞客邦 留言(0) 人氣(8)

  • 個人分類:
▲top
  • 7月 13 週一 201518:04
  • Linux系統中常見錯誤碼

http://fc4777.blog.fc2blog.us/blog-entry-4.html
在 Unix 系統中,使用 perror 程序來顯示操作系統錯誤編碼的含義,它包含在 MySQL 的分發中。
下面的列表顯示常見的 Linux 系統錯誤代碼。
1 EPERM
Operation not permitted
操作不許可
2 ENOENT
No such file or directory
無此文件或目錄
3 ESRCH
No such process
無此過程
4 EINTR
Interrupted system call
系統調用被禁止
5 EIO
I/O error
I/O 錯誤
6 ENXIO
No such device or address
無此器件或地址
7 E2BIG
Arg list too long
Arg 列表太長
8 ENOEXEC
Exec format error
Exec 格式錯誤
9 EBADF
Bad file number
文件數目錯誤
10 ECHILD
No child processes
無子過程
11 EAGAIN
Try again
再試一遍
12 ENOMEM
Out of memory
內存溢出
13 EACCES
Permission denied
許可拒絕
14 EFAULT
Bad address
錯誤的地址
15 ENOTBLK
Block device required
需要塊設備
16 EBUSY
Device or resource busy
設備或資源忙
17 EEXIST
File exists
文件存在
18 EXDEV
Cross-device link
跨器鏈接
19 ENODEV
No such device
無此設備
20 ENOTDIR
Not a directory
不是一個目錄
21 EISDIR
Is a directory
是一個目錄
22 EINVAL
Invalid argument
無效的函數自變量
23 ENFILE
File table overflow
文件表溢出
24 EMFILE
Too many open files
打開的文件太多
25 ENOTTY
Inappropriate ioctl for device
26 ETXTBSY
Text file busy
文本文件忙
27 EFBIG
File too large
文件太大
28 ENOSPC
No space left on device
磁盤空間不足
29 ESPIPE
Illegal seek
不合法的尋找
30 EROFS
Read-only file system
只讀文件系統
31 EMLINK
Too many links
太多的鏈接
(繼續閱讀...)
文章標籤

成功运行 發表在 痞客邦 留言(0) 人氣(368)

  • 個人分類:
▲top
«1...3456»

個人資訊

成功运行
暱稱:
成功运行
分類:
數位生活
好友:
累積中
地區:

熱門文章

  • (8,031)Linux內核的OOM機制
  • (6,721)Linux下清除系統日誌方法
  • (2,986)VC++動態鏈接庫(DLL)編程深入淺出
  • (2,551)使用C++處理JSON數據交換格式
  • (1,352)linux做單臂路由實現trunk使vlan之間通信
  • (1,246)輕型數據庫SQLite結合PHP的開發
  • (868)Linux的USB驅動框架分析
  • (350)使用pcap庫學習TCP/Ip協議
  • (226)linux的exec函數家族
  • (65)Linux下最完整的Samba服務器配置攻略

文章分類

  • 未分類文章 (1)

最新文章

  • 用ipmitool管理服務器
  • softirq原理以及源碼分析
  • 監控ORACLE數據庫
  • 一次設計存儲的經歷
  • JAVA類和繼承
  • oracle RAC開啟歸檔日誌
  • 輕型數據庫SQLite結合PHP的開發
  • 使用pcap庫學習TCP/Ip協議
  • 存儲要實現快速可持續發展
  • c++雜談

最新留言

  • [20/08/21] Jesse 於文章「用ipmitool管理服務器...」留言:
    IPMI simulator build step htt...

動態訂閱

文章精選

文章搜尋

誰來我家

參觀人氣

  • 本日人氣:
  • 累積人氣: