一区二区免费看,久久精品国产一区二区三区,一区二区在线视频观看http://www.shnenglu.com/momoxiao/category/13037.htmlzh-cnWed, 15 Jun 2011 12:18:08 GMTWed, 15 Jun 2011 12:18:08 GMT60thread 多線程http://www.shnenglu.com/momoxiao/archive/2011/06/14/148668.html小默小默Tue, 14 Jun 2011 12:27:00 GMThttp://www.shnenglu.com/momoxiao/archive/2011/06/14/148668.htmlhttp://www.shnenglu.com/momoxiao/comments/148668.htmlhttp://www.shnenglu.com/momoxiao/archive/2011/06/14/148668.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/148668.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/148668.html多線程

編寫多線程程序時(shí),在設(shè)計(jì)上要特別小心.
對(duì)共享變量,多個(gè)執(zhí)行路徑,要引起足夠重視.
創(chuàng)建多線程:
/*
 * 多線程
 
*/
#include 
<stdio.h>
#include 
<unistd.h>
#include 
<stdlib.h>
#include 
<pthread.h>

#define NUM_THREADS 6

void *thread_function(void *arg);

int main(){
    
int res;
    pthread_t a_thread[NUM_THREADS];
    
void *thread_result;
    
int lots_of_threads;

    
for(lots_of_threads = 0; lots_of_threads < NUM_THREADS; lots_of_threads++){
        printf(
"before pthread_create, lots_of_threads=%d\n",lots_of_threads);
        res 
= pthread_create(&(a_thread[lots_of_threads]),NULL,
                thread_function, (
void *)&lots_of_threads);
        
if(res != 0){
            perror(
"Thread creation failed");
            exit(EXIT_FAILURE);
        }
    }

    printf(
"Waiting for threads to finish\n");

    
for(lots_of_threads = NUM_THREADS - 1; lots_of_threads >= 0; lots_of_threads--){
        res 
= pthread_join(a_thread[lots_of_threads], &thread_result);
        
if(res == 0){
            perror(
"Picked up a thread\n");
        }
        
else{
            perror(
"pthread_join failed\n");
        }
    }

    printf(
"All done\n");
    exit(EXIT_SUCCESS);
}

void *thread_function(void *arg){
    
int my_number = *(int *)arg;
    
int rand_num;

    printf(
"thread_funcion is running. Argument was %d\n", my_number);
    rand_num 
= 1+(int)(9.0*rand()/(RAND_MAX+1.0));
    sleep(rand_num);
    printf(
"Bye from %d\n", my_number);
    pthread_exit(NULL);
}

執(zhí)行結(jié)果:
[green@colorfulgreen ch11]$ gcc -D_REENTRANT thread8.c -o thread8 -lpthread
[green@colorfulgreen ch11]$ .
/thread8    
before pthread_create, lots_of_threads
=0
before pthread_create, lots_of_threads
=1
before pthread_create, lots_of_threads
=2
before pthread_create, lots_of_threads
=3
before pthread_create, lots_of_threads
=4
before pthread_create, lots_of_threads
=5
Waiting 
for threads to finish
thread_funcion 
is running. Argument was 5
thread_funcion 
is running. Argument was 5
thread_funcion 
is running. Argument was 5
thread_funcion 
is running. Argument was 5
thread_funcion 
is running. Argument was 5
thread_funcion 
is running. Argument was 5
Bye from 
5
Bye from 
5
Picked up a thread
: Success
Bye from 
5
Picked up a thread
: Success
Bye from 
5
Picked up a thread
: Success
Bye from 
5
Picked up a thread
: Success
Bye from 
5
Picked up a thread
: Success
Picked up a thread
: Success
All done

從執(zhí)行結(jié)果里,很顯然看到有bug,5個(gè)線程的argument全是5.
因?yàn)樾戮€程的參數(shù),是使用地址引用傳遞的:
res = pthread_create(&(a_thread[lots_of_threads]),NULL,
                thread_function, (void *)&lots_of_threads);
主線程創(chuàng)建線程循環(huán),很快執(zhí)行完. 引用地址中的值,在子線程執(zhí)行前,已經(jīng)被改成了5.
線程參數(shù)改成值傳遞就好了.

--
FROM:Linux程序設(shè)計(jì)

]]>
thread 取消線程http://www.shnenglu.com/momoxiao/archive/2011/06/14/148666.html小默小默Tue, 14 Jun 2011 11:45:00 GMThttp://www.shnenglu.com/momoxiao/archive/2011/06/14/148666.htmlhttp://www.shnenglu.com/momoxiao/comments/148666.htmlhttp://www.shnenglu.com/momoxiao/archive/2011/06/14/148666.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/148666.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/148666.html取消一個(gè)線程

可以請(qǐng)求一個(gè)線程終止,像給它發(fā)送一個(gè)信號(hào)一樣.

1 請(qǐng)求端:

#include <pthread.h>
int pthread_cancel(pthread_t thread);
請(qǐng)求取消指定線程.

2 接收請(qǐng)求端:

#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);
state: 線程是否接收取消請(qǐng)求.
| PTHREAD_CANCEL_ENABLE 允許線程接收取消請(qǐng)求
| PTHREAD_CANCEL_DISABLE 忽略取消請(qǐng)求
oldstate: 獲取先前的取消狀態(tài),不關(guān)心先前狀態(tài)傳NULL.

#include <pthread.h>
int pthread_setcanceltype(int type, int *oldtype);
type: 如果接收到取消請(qǐng)求,什么時(shí)候采取行動(dòng).
| PTHREAD_CANCEL_ASYNCHRONOUS 接收到取消請(qǐng)求后立即采取行動(dòng).
| PTHREAD_CANCEL_DEFERRED 接收到取消請(qǐng)求后,等待請(qǐng)求端線程執(zhí)行以下函數(shù)之一,再采取行動(dòng).
|    (pthread_join,pthread_cond_wait, pthread_cond_timedwait, pthread_testcancel, sem_wait, sigwait)
oldtype: 獲取先前的取消狀態(tài),不關(guān)心先前狀態(tài)傳NULL.
取消一個(gè)線程:
/*
 * 取消一個(gè)線程
 
*/
#include 
<stdio.h>
#include 
<unistd.h>
#include 
<stdlib.h>
#include 
<pthread.h>

void *thread_function(void *arg);

int main(){
    
int res;
    pthread_t a_thread;
    
void *thread_result;

    res 
= pthread_create(&a_thread, NULL, thread_function, NULL);
    
if(res != 0){
        perror(
"Thread creation failed");
        exit(EXIT_FAILURE);
    }

    sleep(
3);
    printf(
"Canceling thread\n");
    res 
= pthread_cancel(a_thread);
    
if(res != 0){
        perror(
"Thread cancelation failed");
        exit(EXIT_FAILURE);
    }

    printf(
"Waiting for thread to finished\n");
    res 
= pthread_join(a_thread, &thread_result);
    
if(res != 0){
        perror(
"Thread join failed");
        exit(EXIT_FAILURE);
    }

    exit(EXIT_SUCCESS);
}

void *thread_function(void *arg){
    
int i,res;

    res 
= pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    
if(res != 0){
        perror(
"Thread pthread_setcancelstate failed");
        exit(EXIT_FAILURE);
    }

    res 
= pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
    
if(res != 0){
        perror(
"Thread pthread_setcanceltype failed");
        exit(EXIT_FAILURE);
    }
    printf(
"thread_function is running\n");

    
for(i = 0; i < 10; i++){
        printf(
"Thread is still running (%d)\n", i);
        sleep(
1);
    }

    pthread_exit(
0);
}

運(yùn)行結(jié)果:
$ gcc -D_REENTRANT thread7.c -o thread7 -lpthread
$ .
/thread7
thread_function 
is running
Thread 
is still running (0)
Thread 
is still running (1)
Thread 
is still running (2)
Canceling thread
Waiting 
for thread to finished

--
FROM:Linux程序設(shè)計(jì)

]]>
thread 線程屬性 脫離線程http://www.shnenglu.com/momoxiao/archive/2011/06/14/148663.html小默小默Tue, 14 Jun 2011 10:56:00 GMThttp://www.shnenglu.com/momoxiao/archive/2011/06/14/148663.htmlhttp://www.shnenglu.com/momoxiao/comments/148663.htmlhttp://www.shnenglu.com/momoxiao/archive/2011/06/14/148663.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/148663.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/148663.html線程的屬性

脫離線程:不向主線程返回信息,不需要主線程等待.
通過兩種方法創(chuàng)建:
調(diào)用pthread_detach;
修改線程的屬性. <- 這里使用

#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
初始化一個(gè)線程屬性對(duì)象.
pthread_destroy
回收一個(gè)線程屬性對(duì)象.

#include <pthread.h>
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
這個(gè)屬性允許我們無需對(duì)線程進(jìn)行合并:
| PTHREAD_CREATE_JOINABLE 默認(rèn).
| PTHREAD_CREATE_DETACHED 不能調(diào)用pthread_join來獲得另一個(gè)線程的退出狀態(tài).

int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);
控制線程的調(diào)度方式:
| SCHED_OTHER 默認(rèn)
| SCHED_RP   循環(huán)(round_robin) <- 下面2個(gè)調(diào)度方式具備實(shí)時(shí)調(diào)度功能,需要root權(quán)限.
| SCHED_FIFO 先進(jìn)先出

int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);
和schedpolicy配合使用,控制SCHED_OTHER線程的調(diào)度策略.

int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit);
int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit);
| PTHREAD_EXPLICIT_SCHED 調(diào)度由屬性明確設(shè)置.
| PTHREAD_INHERIT_SCHED  新線程沿用創(chuàng)建者的屬性.

int pthread_attr_setscope(pthread_attr_t *attr, int scope);
int pthread_attr_getscope(const pthread_attr_t *attr, int *scope);
控制一個(gè)線程調(diào)度的計(jì)算方式,目前Linux只支持PTHREAD_SCOPE_SYSTEM.

int pthread_attr_setstacksize(pthread_attr_t *attr, int scope);
int pthread_attr_getstacksize(const pthread_attr_t *attr, int *scope);
控制線程創(chuàng)建的棧大小,單位字節(jié).可選.
Linux在實(shí)現(xiàn)線程時(shí),默認(rèn)的棧很大,這個(gè)屬性有點(diǎn)多余.
創(chuàng)建脫離線程:
/*
 * 線程屬性-創(chuàng)建脫離線程
 * 主線程不等待子線程結(jié)束,只通過thread_finished標(biāo)志來檢測(cè)子線程是否已結(jié)束,并顯示線程之間仍然共享的變量.
 
*/
#include 
<stdio.h>
#include 
<unistd.h>
#include 
<stdlib.h>
#include 
<pthread.h>

void *thread_function(void *arg);

char g_message[] = "Hello World!";
int g_thread_finished = 0;

int main(){
    
int res;
    pthread_t a_thread;
    pthread_attr_t thread_attr;

    res 
= pthread_attr_init(&thread_attr);
    
if(res != 0){
        perror(
"Attribute creation failed");
        exit(EXIT_FAILURE);
    }

    res 
= pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
    
if(res != 0){
        perror(
"Setting detached attribute failed");
        exit(EXIT_FAILURE);
    }

    res 
= pthread_create(&a_thread, &thread_attr,
            thread_function, (
void *)g_message);
    
if(res != 0){
        perror(
"Thread creation failed");
        exit(EXIT_FAILURE);
    }

    (
void)pthread_attr_destroy(&thread_attr);
    
while(!g_thread_finished){
        printf(
"Waiting for thread to say it's finished\n");
        sleep(
1);
    }
    printf(
"Other thread finished, bye!\n");
    exit(EXIT_SUCCESS);
}

void *thread_function(void *arg){
    printf(
"thread_function is running. Argument was %s\n", (char *)arg);
    sleep(
4);
    printf(
"Second thread setting finished flag, and exit now\n");
    g_thread_finished 
= 1;
    pthread_exit(NULL);
}

執(zhí)行結(jié)果:
$ gcc -D_REENTRANT thread5.c -o thread5 -lpthread  
$ .
/thread5 
Waiting 
for thread to say it's finished
thread_function is running. Argument was Hello World!
Waiting 
for thread to say it's finished
Waiting for thread to say it's finished
Waiting for thread to say it's finished
Second thread setting finished flag, and exit now
Other thread finished, bye
!

--
FROM: Linux程序設(shè)計(jì)

]]>
struct sk_buffhttp://www.shnenglu.com/momoxiao/archive/2011/03/24/142666.html小默小默Thu, 24 Mar 2011 10:07:00 GMThttp://www.shnenglu.com/momoxiao/archive/2011/03/24/142666.htmlhttp://www.shnenglu.com/momoxiao/comments/142666.htmlhttp://www.shnenglu.com/momoxiao/archive/2011/03/24/142666.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/142666.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/142666.html/home/green/src/list.c
alloc_skb
kfree_skb
skb_put
skb_trim


#############
/home/green/src/list.c
#############
alloc_skb
kfree_skb
skb_put  // used data后部擴(kuò)展
skb_push // used data前部擴(kuò)展
skb_pull // used data前部截?cái)?/div>
skb_trim // used data后部截?cái)?/div>
skb_reserve // data+分片后移,只允許對(duì)空緩存使用

skb_queue_head_init  // 初始化struct sk_buff_head
skb_queue_head  // list頭部添加一個(gè)packet
skb_queue_tail  // list尾部添加一個(gè)packet
skb_dequeue      // 移去list頭部第一個(gè)packet(返回移除的packet指針,內(nèi)存沒有收回?)
skb_dequeue_tail // 移去list尾部第一個(gè)packet  
skb_queue_purge  // 清空list中的節(jié)點(diǎn)
skb_append      // 在list的給定packet后append一個(gè)packet
skb_insert      // 在list的給定packet前insert一個(gè)packet



#############
alloc_skb
#############
<linux-2.6.36/net/core/skbuff.c>

__alloc_skb()分析:

申請(qǐng)struct skb_buff skb空間, 必須從CACHE中申請(qǐng)(skbuff_fclone_cache或skbuff_head_cache).
申請(qǐng)數(shù)據(jù)區(qū)內(nèi)存, 使用kmalloc. 數(shù)據(jù)區(qū)包括字節(jié)對(duì)齊后的size和struct skb_shared_info.
填充skb結(jié)構(gòu).
填充分片信息struct skb_shared_info shinfo.
如果頭部skb_buff是從skbuff_fclone_cache中申請(qǐng)的,do something... //TODO

********

__alloc_skb()完成時(shí),內(nèi)存狀態(tài):

skb           struct sk_buff     <-| skb->truesize
              --------------       |
data          size                 |
skb->data                          |
skb->head                          |
              -------------      <-|
              struct skb_shared_info

tail 和 end是偏移量
skb->tail = skb->data - skb->head = 0
skb->end = skb->tail + skb->size

********

head,data是指針,tail,end是偏移量。

<linux-2.6.36/include/linux/skbuff.h>
#ifdef NET_SKBUFF_DATA_USES_OFFSET
typedef unsigned int sk_buff_data_t;
#else
typedef unsigned char *sk_buff_data_t;
#endif

struct sk_buff {
    /* These elements must be at the end, see alloc_skb() for details.  */
    sk_buff_data_t      tail;
    sk_buff_data_t      end;
    unsigned char       *head,
    *data;

    unsigned int        truesize;
    atomic_t        users;
};

*********
skb,shinfo的引用計(jì)數(shù)都是原子類型atomic_t.
volatile只讀內(nèi)存,不讀寄存器. 


#############
kfree_skb
#############
內(nèi)存屏障

軟件可通過讀寫屏障強(qiáng)制內(nèi)存訪問次序.所有在設(shè)置讀寫屏障之前發(fā)起的內(nèi)存訪問,必須先于在設(shè)置屏障之后發(fā)起的內(nèi)存訪問之前完成,確保內(nèi)存訪問按程序的順序完成.

smp_mb()    適用于多處理器的內(nèi)存屏障。
smp_rmb()   適用于多處理器的讀內(nèi)存屏障。

http://blogold.chinaunix.net/u3/93713/showart_2061476.html


#############
skb_put
#############
BUG() BUGON()

BUG()和BUG_ON()被用來提供斷言,當(dāng)被調(diào)用時(shí)會(huì)引發(fā)oops,導(dǎo)致棧的回溯和錯(cuò)誤信息的打印.
大部分體系結(jié)構(gòu)把BUG()定義成某種非法操作.
斷言某種情況不該發(fā)生:
if(bad_thing):
    BUG();
或者更好的形式:
BUG_ON(bad_thing);

******
frag_list

如果傳輸層將數(shù)據(jù)包分片了,就會(huì)把這些數(shù)據(jù)包放到skb的frag_list鏈表中.

******
skb_put 在尾部擴(kuò)展used data area.常被用于給數(shù)據(jù)塊添加協(xié)議尾部.
其實(shí)就修改了tail偏移量和len值,別的什么都沒做.
設(shè)了倆斷言:
數(shù)據(jù)包不能有分片;
擴(kuò)展數(shù)據(jù)區(qū)不能超出skb->end.


#############
skb_trim
#############
struct sk_buff

truesize = skb + data
len = data + 分片
data+len = 分片



]]>【轉(zhuǎn)】Fedora Linux中的日志服務(wù)http://www.shnenglu.com/momoxiao/archive/2011/03/02/141009.html小默小默Wed, 02 Mar 2011 13:23:00 GMThttp://www.shnenglu.com/momoxiao/archive/2011/03/02/141009.htmlhttp://www.shnenglu.com/momoxiao/comments/141009.htmlhttp://www.shnenglu.com/momoxiao/archive/2011/03/02/141009.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/141009.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/141009.htmlhttp://blog.csdn.net/flagonxia/archive/2009/08/09/4427756.aspx

---

<序言>

我已經(jīng)寫過兩篇實(shí)用型的博文,可以作為參考:

1) 如何將Linux主機(jī)設(shè)置成syslog服務(wù)器;

2) 使用cron和logrotate來管理日志文件。

     這篇文章主要介紹日志服務(wù)的基礎(chǔ)知識(shí)。涉及日志的服務(wù)有兩個(gè),在Fedora9中是rsyslog服務(wù)和logrotate服務(wù)。前者負(fù)責(zé)寫入日志,后者負(fù)責(zé)備份和刪除舊日志,以及更新日志文件。

1. rsyslogd 服務(wù)

1.1 查看當(dāng)前rsyslogd服務(wù)的狀態(tài)

     在Fedora 9開始,負(fù)責(zé)寫入日志信息的服務(wù)是rsyslogd,它的配置文件為:/etc/rsyslog.conf。我們檢測(cè)一下當(dāng)前這個(gè)服務(wù)是不是在運(yùn)行。

     [flagonxia@airhouse etc]$ ps -ef | grep -v grep | grep rsyslog
     root      1584     1  0 10:33 ?        00:00:00 rsyslogd -c 3

      從上面命令的輸出結(jié)果看到rsyslogd執(zhí)行時(shí)使用的參數(shù)是-c 3。這個(gè)輸入?yún)?shù)在文件/etc/sysconfig/rsyslog中指定。

      [flagonxia@airhouse sysconfig]$ less rsyslog
      # Options to syslogd
      # syslogd options are deprecated in rsyslog v3 
      # if you want to use them, switch to compatibility mode 2 by "-c 2"
      SYSLOGD_OPTIONS="-c 3"

      也可以通過另一種方式,查看當(dāng)前運(yùn)行級(jí)別中,rsyslogd是否運(yùn)行。

      [flagonxia@airhouse sysconfig]$ sudo chkconfig --list rsyslog
      rsyslog         0:off   1:off   2:on    3:on    4:on    5:on    6:off

      注意,這里的服務(wù)名是rsyslog。

1.2 配置文件/etc/rsyslog.conf

1.2.1 配置文件的基本信息

      配置文件/etc/rsyslog.conf中有很多內(nèi)容,但最主要的是指定需要記錄哪些服務(wù)和需要記錄什么等級(jí)的信息。

      下面是rsyslog.conf的內(nèi)容。

      # /etc/rsyslog.conf

      ... ...

      #### RULES ####

      # Log all kernel messages to the console.
      # Logging much else clutters up the screen.
      #kern.*                                                 /dev/console

      # Log anything (except mail) of level info or higher.
      # Don't log private authentication messages!
A    *.info;mail.none;authpriv.none;cron.none                /var/log/messages

      # The authpriv file has restricted access.
      authpriv.*                                              /var/log/secure

      # Log all the mail messages in one place.
B    mail.*                                                  -/var/log/maillog


      # Log cron stuff
      cron.*                                                  /var/log/cron

      # Everybody gets emergency messages
C      *.emerg                                                 *

      # Save news errors of level crit and higher in a special file.
D    uucp,news.crit                                       /var/log/spooler

      # Save boot messages also to boot.log
      local7.*                                                /var/log/boot.log     

     【注釋】

      A:把所有大于info級(jí)別的信息都記錄到/var/log/messages中,但不要記錄mail,authpriv和cron服務(wù)產(chǎn)生的信息;

      B:把mail產(chǎn)生的信息都記錄到/var/log/maillog中

      C:把所有服務(wù)輸出的“大于”emergy級(jí)別的信息顯示給每個(gè)在線的人,通過wall工具

      D:把uucp和news輸出的大雨crit級(jí)別的信息記錄到/var/log/spooler中

1.2.2 信息的等級(jí)及其在配置文件中指定的方式

     A 七種信息等級(jí)

        1)info

        2)notice

        3)warning或warn

        4)err或error

        5)crit

        6)alert

        7)emerg或panic:導(dǎo)致系統(tǒng)幾乎要死機(jī)

     B 信息等級(jí)的指定方式

        1). xxx: 表示大于xxx級(jí)別的信息

        2).=xxx:表示等于xxx級(jí)別的信息

        3).!xxx:表示在xxx之外的等級(jí)的信息

2. logrotate服務(wù)

2.1 logrotate服務(wù)的啟動(dòng)方式

       logrotate是一個(gè)日志管理程序,用來把舊的日志文件刪除(備份),并創(chuàng)建新的日志文件,這個(gè)過程稱為“轉(zhuǎn)儲(chǔ)”。我們可以根據(jù)日志的大小,或者根據(jù)其使用的天數(shù)來轉(zhuǎn)儲(chǔ)。

       logrotate的執(zhí)行由crond服務(wù)實(shí)現(xiàn)。在/etc/cron.daily目錄中,有個(gè)文件logrotate,它實(shí)際上是個(gè)shell script,用來啟動(dòng)logrotate。logrotate程序每天由cron在指定的時(shí)間(/etc/crontab)啟動(dòng)。

       [flagonxia@airhouse cron.daily]$ less logrotate
       #!/bin/sh

       /usr/sbin/logrotate /etc/logrotate.conf
       EXITVALUE=$?
       if [ $EXITVALUE != 0 ]; then
       /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
       fi
       exit 0

       因此,使用ps是無法查看到logrotate的。如果它沒有起來,就要查看一下crond服務(wù)有沒有在運(yùn)行。

       [flagonxia@airhouse logrotate.d]$ ps -ef | grep -v grep | grep cron
       root      1984     1  0 10:34 ?        00:00:00 crond

2.2 logrotate的配置文件/etc/logrotate.conf 

       在執(zhí)行l(wèi)ogrotate時(shí),需要指定其配置文件/etc/logrotate.conf。這個(gè)文件定義了如何轉(zhuǎn)儲(chǔ)日志文件的規(guī)則。如下:

       # see "man logrotate" for details
       # rotate log files weekly
       weekly

       # keep 4 weeks worth of backlogs
       rotate 4

       # create new (empty) log files after rotating old ones
       create

       # use date as a suffix of the rotated file
       dateext

       # uncomment this if you want your log files compressed
       #compress

       # RPM packages drop log rotation information into this directory
       include /etc/logrotate.d

       # no packages own wtmp and btmp -- we'll rotate them here
       /var/log/wtmp {
              monthly
              create 0664 root utmp
              rotate 1
        }

        /var/log/btmp {
              missingok
              monthly
              create 0600 root utmp
              rotate 1
         }

         # system-specific logs may be also be configured here.

      這個(gè)配置文件的注釋寫得很清楚,沒有必要再羅嗦了。只想強(qiáng)調(diào)下面這行,它的作用包含存放在/etc/logrotate.d目錄下面的配置文件,不可或缺。如果你安裝了一個(gè)新的服務(wù),它的日志轉(zhuǎn)儲(chǔ)的規(guī)則可以建立一個(gè)專門的配置文件,放在/etc/logrotate.d下面。它其實(shí)也因?yàn)橄旅娴倪@句話,在logrotate服務(wù)啟動(dòng)時(shí)被讀取。

       include /etc/logrotate.d

       這里有個(gè)例子:/etc/logrotate.d/syslog

       /var/log/messages /var/log/secure /var/log/maillog /var/log/spooler /var/log/boot.log /var/log/cron {
             sharedscripts
             postrotate
                  /bin/kill -HUP `cat /var/run/rsyslogd.pid 2> /dev/null` 2> /dev/null || true
             endscript
       }

      上面的配置對(duì)于/var/log/messages, /var/log/secure, /var/log/mailog/ /var/log/spooler, /var/log/boot.log, /var/log/cron都是適用的。

      注意,prerotate和postrotate必須和sharescripts...endscript一起用。上面的信息表示日志文件轉(zhuǎn)儲(chǔ)后,重啟rsyslogd服務(wù)。

      每個(gè)存放在/etc/logrotate.d目錄里的文件,都有上面格式的配置信息。在{}中定義的規(guī)則,如果與logrotate.conf中的沖突,以/etc/logrotatate.d/中的文件定義的為準(zhǔn)。



]]>
linux kernel macro likely() unlikely()http://www.shnenglu.com/momoxiao/archive/2011/02/03/139709.html小默小默Thu, 03 Feb 2011 08:23:00 GMThttp://www.shnenglu.com/momoxiao/archive/2011/02/03/139709.htmlhttp://www.shnenglu.com/momoxiao/comments/139709.htmlhttp://www.shnenglu.com/momoxiao/archive/2011/02/03/139709.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/139709.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/139709.html<linux/compiler.h> 2.6.36
142 # define likely(x)  __builtin_expect(!!(x), 1)
143 # define unlikely(x)    __builtin_expect(!!(x), 0)

long __buildin_expect(long EXP, C)是GCC的內(nèi)置函數(shù),用來給編譯器提供分支預(yù)測(cè)信息:期望EXP==C,返回值是EXP。其中C是編譯時(shí)常量。
eg:
if(__buildin_expect(ptr != NULL, 1)) error(); // 期望ptr!=NULL為1;當(dāng)期望滿足時(shí)(返回的ptr != NULL為1)執(zhí)行error()
if(__buildin_expect(x,0)) foo(); // 期望x==0;當(dāng)期望未滿足(返回的x為真)時(shí)執(zhí)行foo()

總之:
if(likely(x)) foo();     // 期望x為真,且x為真時(shí)執(zhí)行foo()
if(unlikely(x)) foo(); // 期望x為假,且x為真時(shí)執(zhí)行foo()
也就是說,likely()和unlikely()都是在x為真時(shí)執(zhí)行分支下面的語句;不同的是likely()期望x為真,unlikely期望x為假,

--
ref:
http://blog.richliu.com/2007/02/01/428/



]]>
implicit declaration of function 'NIPQUAD'http://www.shnenglu.com/momoxiao/archive/2011/01/27/139393.html小默小默Wed, 26 Jan 2011 20:28:00 GMThttp://www.shnenglu.com/momoxiao/archive/2011/01/27/139393.htmlhttp://www.shnenglu.com/momoxiao/comments/139393.htmlhttp://www.shnenglu.com/momoxiao/archive/2011/01/27/139393.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/139393.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/139393.htmlQ:implicit declaration of function 'NIPQUAD'
A:

http://kerneltrap.org/mailarchive/linux-netdev/2008/10/31/3873584

 Using NIPQUAD() with NIPQUAD_FMT, %d.%d.%d.%d or %u.%u.%u.%u
can be replaced with %pI4

-  dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n",
-   NIPQUAD(src_ipaddr),
-   NIPQUAD(arpinfo->smsk.s_addr),
-   NIPQUAD(arpinfo->src.s_addr),
+  dprintf("SRC: %pI4. Mask: %pI4. Target: %pI4.%s\n",
+   &src_ipaddr,
+   &arpinfo->smsk.s_addr,
+   &arpinfo->src.s_addr,
    arpinfo->invflags & ARPT_INV_SRCIP ? " (INV)" : "");



]]>
ldd3讀書筆記http://www.shnenglu.com/momoxiao/archive/2011/01/05/138041.html小默小默Wed, 05 Jan 2011 15:24:00 GMThttp://www.shnenglu.com/momoxiao/archive/2011/01/05/138041.htmlhttp://www.shnenglu.com/momoxiao/comments/138041.htmlhttp://www.shnenglu.com/momoxiao/archive/2011/01/05/138041.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/138041.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/138041.html閱讀全文

]]>
scull源碼分析 //未完待續(xù),囧http://www.shnenglu.com/momoxiao/archive/2010/12/10/136112.html小默小默Fri, 10 Dec 2010 15:48:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/12/10/136112.htmlhttp://www.shnenglu.com/momoxiao/comments/136112.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/12/10/136112.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/136112.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/136112.html# disable/enable debugging#DEBUG = y# 當(dāng)DEBUG變量等于y時(shí)。兩個(gè)比較變量用括...  閱讀全文

]]>
蓋樓 http://www.shnenglu.com/momoxiao/archive/2010/11/09/133126.html小默小默Tue, 09 Nov 2010 14:18:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/11/09/133126.htmlhttp://www.shnenglu.com/momoxiao/comments/133126.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/11/09/133126.html#Feedback25http://www.shnenglu.com/momoxiao/comments/commentRss/133126.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/133126.html

]]>
killhttp://www.shnenglu.com/momoxiao/archive/2010/08/17/123645.html小默小默Mon, 16 Aug 2010 16:18:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/08/17/123645.htmlhttp://www.shnenglu.com/momoxiao/comments/123645.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/08/17/123645.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/123645.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/123645.htmlkill(傳送信號(hào)給指定的進(jìn)程,使用 kill -l 命令可查看linux系統(tǒng)中信號(hào)。)

相關(guān)函數(shù)
raise,signal

表頭文件
#include<sys/types.h>
#include<signal.h>

定義函數(shù)
int kill(pid_t pid,int sig);

函數(shù)說明
kill()可以用來送參數(shù)sig指定的信號(hào)給參數(shù)pid指定的進(jìn)程。

參數(shù)pid有幾種情況:
pid>0 將信號(hào)傳給進(jìn)程識(shí)別碼為pid 的進(jìn)程。
pid=0 將信號(hào)傳給和目前進(jìn)程相同進(jìn)程組的所有進(jìn)程
pid=-1 將信號(hào)廣播傳送給系統(tǒng)內(nèi)所有的進(jìn)程
pid<0 將信號(hào)傳給進(jìn)程組識(shí)別碼為pid絕對(duì)值的所有進(jìn)程

返回值
執(zhí)行成功則返回0,如果有錯(cuò)誤則返回-1。

錯(cuò)誤代碼
EINVAL 參數(shù)sig 不合法
ESRCH 參數(shù)pid 所指定的進(jìn)程或進(jìn)程組不存在 
EPERM 權(quán)限不夠無法傳送信號(hào)給指定進(jìn)程


]]>
SIGHUPhttp://www.shnenglu.com/momoxiao/archive/2010/08/17/123642.html小默小默Mon, 16 Aug 2010 16:05:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/08/17/123642.htmlhttp://www.shnenglu.com/momoxiao/comments/123642.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/08/17/123642.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/123642.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/123642.html
On POSIX-compliant platforms, SIGHUP is a signal sent to a process when its controlling terminal is closed. (It was originally designed to notify the process of a serial line drop). SIGHUP is a symbolic constant defined in theheader file signal.h.

]]>
waithttp://www.shnenglu.com/momoxiao/archive/2010/08/16/123640.html小默小默Mon, 16 Aug 2010 15:42:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/08/16/123640.htmlhttp://www.shnenglu.com/momoxiao/comments/123640.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/08/16/123640.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/123640.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/123640.htmlwait(等待子進(jìn)程中斷或結(jié)束)

相關(guān)函數(shù)
waitpid,fork

表頭文件
#include<sys/types.h>
#include<sys/wait.h>

定義函數(shù)
pid_t wait (int * status);

函數(shù)說明
wait()會(huì)暫時(shí)停止目前進(jìn)程的執(zhí)行,直到有信號(hào)來到或子進(jìn)程結(jié)束。如果在調(diào)用wait()時(shí)子進(jìn)程已經(jīng)結(jié)束,則wait()會(huì)立即返回子進(jìn)程結(jié)束狀態(tài)值。子進(jìn)程的結(jié)束狀態(tài)值會(huì)由參數(shù)status 返回,而子進(jìn)程的進(jìn)程識(shí)別碼也會(huì)一快返回。如果不在意結(jié)束狀態(tài)值,則參數(shù)status 可以設(shè)成NULL。子進(jìn)程的結(jié)束狀態(tài)值請(qǐng)參考下面的waitpid()。

返回值
如果執(zhí)行成功則返回子進(jìn)程識(shí)別碼(PID),如果有錯(cuò)誤發(fā)生則返回-1。失敗原因存于errno 中。

==============
EINTR ,A signal interrupted this function


]]>
forkhttp://www.shnenglu.com/momoxiao/archive/2010/08/16/123639.html小默小默Mon, 16 Aug 2010 15:27:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/08/16/123639.htmlhttp://www.shnenglu.com/momoxiao/comments/123639.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/08/16/123639.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/123639.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/123639.html頭文件:
#include <unistd.h>

函數(shù)定義:
int fork( void );

返回值:
子進(jìn)程中返回0,父進(jìn)程中返回子進(jìn)程ID,出錯(cuò)返回-1

函數(shù)說明:
一個(gè)現(xiàn)有進(jìn)程可以調(diào)用fork函數(shù)創(chuàng)建一個(gè)新進(jìn)程。由fork創(chuàng)建的新進(jìn)程被稱為子進(jìn)程(child process)。fork函數(shù)被調(diào)用一次但返回兩次。兩次返回的唯一區(qū)別是子進(jìn)程中返回0值而父進(jìn)程中返回子進(jìn)程ID。
子進(jìn)程是父進(jìn)程的副本,它將獲得父進(jìn)程數(shù)據(jù)空間、堆、棧等資源的副本。注意,子進(jìn)程持有的是上述存儲(chǔ)空間的“副本”,這意味著父子進(jìn)程間不共享這些存儲(chǔ)空間,它們之間共享的存儲(chǔ)空間只有代碼段。



]]>
gcc math.h -lmhttp://www.shnenglu.com/momoxiao/archive/2010/08/05/122265.html小默小默Thu, 05 Aug 2010 01:04:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/08/05/122265.htmlhttp://www.shnenglu.com/momoxiao/comments/122265.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/08/05/122265.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/122265.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/122265.html-l表示使用庫,m為數(shù)學(xué)庫。
=================
Linux程序設(shè)計(jì)中的一個(gè)例子:
#include <sys/types.h>
#include 
<sys/resource.h>
#include 
<sys/time.h>
#include 
<unistd.h>
#include 
<stdio.h>
#include 
<math.h>

/// 向一個(gè)臨時(shí)文件寫一個(gè)字符串10000次,然后進(jìn)行一些數(shù)學(xué)運(yùn)算,目的是制造一些CPU負(fù)荷
void work()
{
    FILE 
*f;
    
int i;
    
double x = 4.5;

    f 
= tmpfile(); // 創(chuàng)建臨時(shí)文件
    for(i = 0; i < 10000; i++){
        fprintf(f, 
"Do some output\n");
        
if(ferror(f)){ //TODO ferror?
            fprintf(stderr, "Error writing to temporary file\n");
            exit(
1);
        }
    }

    
for(i = 0; i < 1000000; i++)
        x 
= log(x*+ 3.21);
}

/// main 函數(shù)先調(diào)用 work, 再調(diào)用 getrusage 函數(shù)查看它使用了多少 CPU 時(shí)間。把這些資料顯示在屏幕上。
int main()
{
    
struct rusage r_usage;
    
struct rlimit r_limit;
    
int priority;

    work();
    getrusage(RUSAGE_SELF, 
&r_usage); // 只返回當(dāng)前程序的 CPU 占用時(shí)間

    printf(
"CPU usage: User = %ld.%06ld, System = %ld.%06ld\n",
           r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec,    
// r_usage.ru_utime 程序本身執(zhí)行它的指令所消耗的時(shí)間
           r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec);   // r_usage.ru_stime OS由于這個(gè)程序而消耗的 CPU 時(shí)間

    
/// 調(diào)用 getpriority 和 getrlimit 函數(shù)分別查出自己的當(dāng)前優(yōu)先級(jí)和文件長(zhǎng)度限制
    priority = getpriority(PRIO_PROCESS, getpid()); // PRIO_PROCESS 表示后面是進(jìn)程標(biāo)識(shí)符
    printf("Current priority = %d\n", priority);
    getrlimit(RLIMIT_FSIZE, 
&r_limit); // 讀取以字節(jié)計(jì)的文件長(zhǎng)度限制到 r_limit 中
    printf("Current FSIZE limit: soft = %ld, hard = %ld\n",
              r_limit.rlim_cur, r_limit.rlim_max);  
// rlim_cur 軟限制, rlimt_max 硬限制

    
/// 通過 setrlimit 函數(shù)設(shè)置了一個(gè)文件長(zhǎng)度限制。
    r_limit.rlim_cur = 2048;    // 軟限制2M
    r_limit.rlim_max = 4096;    // 硬限制4M
    printf("Setting a 2K file size limit\n");
    setrlimit(RLIMIT_FSIZE, 
&r_limit);

    
/// 然后再次調(diào)用 work 失敗,因?yàn)樗鼑L試創(chuàng)建的文件尺寸過大。
    work();

    exit(
0);

}

編譯:
[green@colorfulgreen environ]$ gcc limits.c -o limits

報(bào)錯(cuò):
/tmp/ccxW94yi.o: In function `work':
limits.c:(.text+0xaf): undefined reference to `log'
collect2: ld returned 1 exit status

編譯時(shí)加上 -lm 選項(xiàng):
[green@colorfulgreen environ]$ gcc limits.c -lm -o limits

Done.
============
PS:為嘛這個(gè)編輯器插入代碼時(shí)最前面不能有下面這幾行T_T
/**
  * 資源限制
**/








]]>
硬盤安裝 Fedore13 Livehttp://www.shnenglu.com/momoxiao/archive/2010/07/18/120668.html小默小默Sat, 17 Jul 2010 23:20:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/07/18/120668.htmlhttp://www.shnenglu.com/momoxiao/comments/120668.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/07/18/120668.html#Feedback1http://www.shnenglu.com/momoxiao/comments/commentRss/120668.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/120668.html昨晚無聊把Fedora裝本上了,記一下,免得每次都得上網(wǎng)找。

1. grldr 放在C盤
2. boot.ini 最后添加一行 c:\grldr="GRUB"
3. ISO安裝鏡像中提取 LiveOS目錄,/isolinux/vmlinuz0,/isolinux/initrd0.img 放在FAT32分區(qū)盤根目錄中。
4. 重啟進(jìn)入grub
kernel (hd0,7)/isolinux/vmlinuz0 root=live:LABEL=FILE liveimg rhgb rootfstype=auto
initrd (hd0,7)/isolinux/initrd0.img
boot

其中(hd0,7)是第3步中的FAT32分區(qū)盤,卷標(biāo)為FILE

]]>
fedora13 mp3 rmvbhttp://www.shnenglu.com/momoxiao/archive/2010/07/18/120665.html小默小默Sat, 17 Jul 2010 20:21:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/07/18/120665.htmlhttp://www.shnenglu.com/momoxiao/comments/120665.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/07/18/120665.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/120665.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/120665.htmlrpm -ivh http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-stable.noarch.rpm
yum install gstreamer-plugins-bad gstreamer-ffmpeg gstreamer-plugins-ugly -y


]]>
Grub磁盤分區(qū)表示方法http://www.shnenglu.com/momoxiao/archive/2010/07/18/120660.html小默小默Sat, 17 Jul 2010 18:20:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/07/18/120660.htmlhttp://www.shnenglu.com/momoxiao/comments/120660.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/07/18/120660.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/120660.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/120660.html

http://www.linux-wiki.cn/index.php?title=Grub磁盤分區(qū)表示方法&variant=zh-cn
==============================================

Grub指定分區(qū)的方法和Linux、Windows等系統(tǒng)不一樣,它的主要特點(diǎn)為:

  • Grub在表示方式上并不區(qū)分普通的IDE硬盤、當(dāng)下流行的SATA硬盤和SCSI硬盤等,在Grub中,硬盤會(huì)被識(shí)別為hd#,#是從0開始的硬盤編號(hào),而軟盤被類似地識(shí)別為fd#。
  • Grub的硬盤編號(hào)和分區(qū)編號(hào)都是從0開始的,這一點(diǎn)linux不同。

按照以上兩個(gè)特點(diǎn),假設(shè)有一塊硬盤(hd0),那么(hd0,0) (hd0,1) (hd0,2) (hd0,3)依次表示它的四個(gè)主分區(qū),而隨后的(hd0,4)...則是邏輯分區(qū) Image:Example.jpg

通常情況下,裝有Windows的硬盤中,通常是按照一個(gè)主分區(qū)(hd0,0),一個(gè)擴(kuò)展分區(qū)(hd0,1)該擴(kuò)展分區(qū)下是若干邏輯分區(qū)。這樣(hd0,0)對(duì)應(yīng)C盤,(hd0,4)對(duì)應(yīng)D盤,依此類推。

如果您還不能確定你需要的那個(gè)分區(qū),可以在輸入過程中按下Tab鍵實(shí)現(xiàn)命令補(bǔ)全。比如你在輸入一條root語句:

root (hd0,

此時(shí)按下Tab鍵,grub將列出可用的分區(qū)編號(hào)和分區(qū)類型(grub還不能識(shí)別ntfs分區(qū),顯示為不知道類型的分區(qū))。你可以依照這個(gè)提示來完成命令的輸入。

如果不能確定ISO文件的位置,可使用find 文件名.iso(find debian-40r2-i386-CD-1.iso)

==============================

試了下Tab鍵命令補(bǔ)全。。。竊喜ing。。。


]]>
volume group "volgroup00" not foundhttp://www.shnenglu.com/momoxiao/archive/2010/06/26/118758.html小默小默Sat, 26 Jun 2010 02:49:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/06/26/118758.htmlhttp://www.shnenglu.com/momoxiao/comments/118758.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/06/26/118758.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/118758.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/118758.htmlhttp://www.csource.org/bbs/thread-1140084-1-1.html 
by SharkBones

前段時(shí)間也遇到和lz類似的問題,出現(xiàn)這種情況可能是有以下幾個(gè)原因:
1.編譯內(nèi)核時(shí)未添加相應(yīng)的硬件支持,比如對(duì)于SCSI或IDE硬盤的支持,這些硬件驅(qū)動(dòng)都是以模塊的形式編譯進(jìn)內(nèi)核。
2.編譯時(shí)的選項(xiàng)不正確對(duì)LVM,RAID的支持應(yīng)該是以模塊的形式編譯進(jìn)內(nèi)核,而不是Built-in,否則可能就會(huì)出現(xiàn)lz所說的情況。
建議樓主用cpio解壓你的initrd-2.6.31.4-*.img,檢查一下解壓后的lib目錄里是否有相應(yīng)的支持LVM的內(nèi)核模塊,如果沒有,那就是編譯時(shí)內(nèi)核選項(xiàng)不正確,需要重新編譯了。

=============================

那為啥還提供Build-in選項(xiàng)。。。悲劇。。。
呃,想起來了,貌似只有yes,no,module;yes,no.沒有module,no。。。

==============================

好吧# make defconfig 好了,傳說中Linus的配置 >_<
貌似又悲劇了。。。


]]>
【轉(zhuǎn)】proc文件系統(tǒng)分析(四)http://www.shnenglu.com/momoxiao/archive/2010/06/23/118521.html小默小默Tue, 22 Jun 2010 22:10:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/06/23/118521.htmlhttp://www.shnenglu.com/momoxiao/comments/118521.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/06/23/118521.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/118521.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/118521.html(六) 對(duì)proc文件默認(rèn)操作的分析 
現(xiàn)在,我們已經(jīng)基本清楚了proc文件系統(tǒng)對(duì)自己proc_dir_entry結(jié)構(gòu)的管理了。下面我們回過頭來,再看一下在文件注冊(cè)函數(shù)中的一段代碼: 
if (S_ISDIR(dp->mode)) { 
if (dp->proc_iops == NULL) { 
dp->proc_fops = &proc_dir_operations; 
dp->proc_iops = &proc_dir_inode_operations; 
} 
dir->nlink++; 
} else if (S_ISLNK(dp->mode)) { 
if (dp->proc_iops == NULL) 
dp->proc_iops = &proc_link_inode_operations; 
} else if (S_ISREG(dp->mode)) { 
if (dp->proc_fops == NULL) 
dp->proc_fops = &proc_file_operations; 
} 
我在前面已經(jīng)提過,這段代碼根據(jù)注冊(cè)的proc文件類型的不同,為proc_dir_entry結(jié)構(gòu)設(shè)置了不同的操作函數(shù)集。也就是說,我們使用封裝的create_proc_entry函數(shù)在proc文件系統(tǒng)中注冊(cè)文件時(shí),可以不用去管這些操作函數(shù)集,因?yàn)樵摻Y(jié)構(gòu)總是自動(dòng)地設(shè)置了相應(yīng)的proc_iops和proc_fops操作函數(shù)。下面我們就對(duì)這些默認(rèn)的操作進(jìn)行一個(gè)分析,因?yàn)檫@對(duì)我們了解proc文件系統(tǒng)和VFS的結(jié)構(gòu)非常重要。 
1 對(duì)普通文件的操作 
我們首先看一下普通proc文件的函數(shù)集,根據(jù)代碼段: 
if (S_ISREG(dp->mode)) { 
if (dp->proc_fops == NULL) 
dp->proc_fops = &proc_file_operations; 
} 
我們可以看到,對(duì)于普通的proc文件,只設(shè)置了文件操作,即proc_file_operations,從這一點(diǎn)上可以看出,對(duì)于普通的proc文件,只缺省提供了文件操作,因此,在必要的時(shí)候,我們必須手工設(shè)置需要的索引節(jié)點(diǎn)操作函數(shù)集,比如inode_operations中的權(quán)限檢查函數(shù)permission等等。 
對(duì)于proc_file_operations,我們可以看到,只實(shí)現(xiàn)了三個(gè)函數(shù): 
static struct file_operations proc_file_operations = { 
llseek: proc_file_lseek, 
read: proc_file_read, 
write: proc_file_write, 
}; 
下面我們簡(jiǎn)單的看一下它們實(shí)現(xiàn)的功能: 
(1)llseek: proc_file_lseek 
這個(gè)函數(shù),用來實(shí)現(xiàn)lseek系統(tǒng)調(diào)用,其功能是設(shè)置file結(jié)構(gòu)的->f_pos域,因此,根據(jù)第三個(gè)參數(shù)orig的不同,將f_pos設(shè)置為相應(yīng)的值,該函數(shù)非常簡(jiǎn)單,因此不作過多的介紹。 
(2)read: proc_file_read 
這個(gè)函數(shù)是file_operations結(jié)構(gòu)中的成員,在后面我們將看到,在proc_dir_entry結(jié)構(gòu)中實(shí)現(xiàn)的file_operations和inode_operations將鏈接至VFS的inode中,因此,該函數(shù)將用來實(shí)現(xiàn)read系統(tǒng)調(diào)用。在這個(gè)函數(shù)中,首先根據(jù)file結(jié)構(gòu),得到相應(yīng)的inode,然后由 
struct proc_dir_entry * dp; 
dp = (struct proc_dir_entry *) inode->u.generic_ip; 
而得到proc_dir_entry結(jié)構(gòu),然后,開始調(diào)用該proc_dir_entry結(jié)構(gòu)中的函數(shù),向用戶空間返回指定大小的數(shù)據(jù),我們看一下下面的代碼片斷: 
if (dp->get_info) { 
/* 
* Handle backwards compatibility with the old net 
* routines. 
*/ 
n = dp->get_info(page, &start, *ppos, count); 
if (n read_proc) { 
n = dp->read_proc(page, &start, *ppos, 
count, &eof, dp->data); 
} else 
break; 
由此我們看出,該函數(shù)的實(shí)現(xiàn)依賴于proc_dir_entry結(jié)構(gòu)中的get_info和read_proc函數(shù),因此,如果我們要注冊(cè)自己的proc文件,在不設(shè)置自己的proc_fops操作函數(shù)集的時(shí)候,必須實(shí)現(xiàn)上面兩個(gè)函數(shù)中的一個(gè),否則,這個(gè)缺省的proc_file_read函數(shù)將做不了任何工作。示意圖如下: 
在這個(gè)函數(shù)中,實(shí)現(xiàn)了從內(nèi)核空間向用戶空間傳遞數(shù)據(jù)的功能,其中使用了許多技巧,在這里就不作討論了,具體實(shí)現(xiàn)可以參考源碼。 
(3)write: proc_file_write 
與上面的函數(shù)類似,我們可以看到proc_file_write函數(shù)同樣依賴于proc_dir_entry中的write_proc(file, buffer, count, dp->data)函數(shù),它的實(shí)現(xiàn)非常簡(jiǎn)單: 
static ssize_t 
proc_file_write(struct file * file, const char * buffer, 
size_t count, loff_t *ppos) 
{ 
struct inode *inode = file->f_dentry->d_inode; 
struct proc_dir_entry * dp; 
dp = (struct proc_dir_entry *) inode->u.generic_ip; 
if (!dp->write_proc) 
return -EIO; 
/* FIXME: does this routine need ppos? probably... */ 
return dp->write_proc(file, buffer, count, dp->data); 
} 
我們看到,它只是簡(jiǎn)單地檢測(cè)了->write_proc函數(shù)是否存在,如果我們?cè)趐roc_dir_entry結(jié)構(gòu)中實(shí)現(xiàn)了這個(gè)函數(shù),那么就調(diào)用它,否則,就退出。 
根據(jù)上面的討論,我們看到,對(duì)于普通文件的操作函數(shù),proc文件系統(tǒng)為我們提供了一個(gè)簡(jiǎn)單的封裝,因此,我們只要在proc_dir_entry中實(shí)現(xiàn)相關(guān)的讀寫操作即可。 
但是,如果我們想提供讀寫操作之外的函數(shù),那么我們就可以定義自己的file_operations函數(shù)集,并且在proc文件注冊(cè)后,將它鏈接到proc_dir_entry的proc_fops上,這樣,就可以使用自己的函數(shù)集了。 
2 對(duì)鏈接文件的操作 
根據(jù)代碼段: 
else if (S_ISLNK(dp->mode)) { 
if (dp->proc_iops == NULL) 
dp->proc_iops = &proc_link_inode_operations; 
我們可以看出,對(duì)于鏈接文件,proc文件系統(tǒng)為它設(shè)置了索引節(jié)點(diǎn)操作proc_iops。因?yàn)槲覀冎溃粋€(gè)符號(hào)鏈接,只擁有inode結(jié)構(gòu),而沒有文件結(jié)構(gòu),所以,為它提供proc_link_inode_operations函數(shù)集就可以了。 
下面我們看一下,這個(gè)函數(shù)集的內(nèi)容: 
static struct inode_operations proc_link_inode_operations = { 
readlink: proc_readlink, 
follow_link: proc_follow_link, 
}; 
這個(gè)函數(shù)集實(shí)現(xiàn)了和鏈接相關(guān)的兩個(gè)函數(shù),我們分別來看一下: 
(1)readlink: proc_readlink 
該函數(shù)用來實(shí)現(xiàn)readlink系統(tǒng)調(diào)用,它的功能是獲得目標(biāo)文件的文件名,我們?cè)谇懊婵吹剑瑢?duì)于一個(gè)鏈接文件,在注冊(cè)時(shí)已經(jīng)將鏈接目標(biāo)的文件放在了proc_dir_entry結(jié)構(gòu)的->data域中(參考前面介紹的函數(shù)proc_symlink),因此,我們只要將->data中的數(shù)據(jù)返回就可以了,它的代碼如下: 
static int proc_readlink(struct dentry *dentry, char *buffer, int buflen) 
{ 
char *s= 
((struct proc_dir_entry *)dentry->d_inode->u.generic_ip)->data; 
return vfs_readlink(dentry, buffer, buflen, s); 
} 
我們看到,這個(gè)函數(shù)使用一個(gè)指針指向->data,然后,使用VFS函數(shù)vfs_readlink將數(shù)據(jù)返回到用戶空間,非常的簡(jiǎn)單。 
(2)follow_link: proc_follow_link 
這個(gè)函數(shù)代碼如下: 
static int proc_follow_link(struct dentry *dentry, struct nameidata *nd) 
{ 
char *s= 
((struct proc_dir_entry *)dentry->d_inode->u.generic_ip)->data; 
return vfs_follow_link(nd, s); 
} 
和上面介紹的函數(shù)類似,它同樣利用VFS的函數(shù)實(shí)現(xiàn)其功能,對(duì)于vfs_follow_link,可以參考fs/namei.c文件。其結(jié)構(gòu)如下圖所示: 
3 對(duì)目錄文件的操作 
最后我們看一下proc文件系統(tǒng)對(duì)目錄文件的操作函數(shù)集,在文件注冊(cè)的時(shí)候,有如下代碼: 
if (S_ISDIR(dp->mode)) { 
if (dp->proc_iops == NULL) { 
dp->proc_fops = &proc_dir_operations; 
dp->proc_iops = &proc_dir_inode_operations; 
} 
dir->nlink++; 
} 
從中我們可以看到,在proc文件系統(tǒng)中注冊(cè)目錄文件的時(shí)候,它會(huì)檢查是否該proc_dir_entry結(jié)構(gòu)已經(jīng)注冊(cè)了proc_iops函數(shù)集,如果沒有,那么就為proc_fops和proc_iops設(shè)置相應(yīng)的缺省函數(shù)集。下面我們對(duì)它們分別進(jìn)行討論: 
1.對(duì)目錄的文件操作proc_dir_operations: 
static struct file_operations proc_dir_operations = { 
read: generic_read_dir, 
readdir: proc_readdir, 
}; 
這個(gè)函數(shù)集的主要功能,是在由proc_dir_entry結(jié)構(gòu)構(gòu)成的proc文件樹中解析目錄。下面我們對(duì)這兩個(gè)函數(shù)進(jìn)行一個(gè)簡(jiǎn)單的分析: 
(1)read: generic_read_dir 
我們知道,對(duì)于read系統(tǒng)調(diào)用,當(dāng)其參數(shù)文件句柄指向目錄的時(shí)候,將返回EISDIR錯(cuò)誤。因此,目錄文件的read函數(shù)將完成這個(gè)工作。generic_read_dir函數(shù)是VFS提供的通用函數(shù),可以參考fs/read_write.c文件: 
ssize_t generic_read_dir(struct file *filp, char *buf, size_t siz, loff_t *ppos){ 
return –EISDIR; 
} 
這個(gè)函數(shù)很簡(jiǎn)單,只要返回錯(cuò)誤碼就可以了。 
(2)readdir: proc_readdir 
這個(gè)函數(shù)用來實(shí)現(xiàn)readdir系統(tǒng)調(diào)用,它從目錄文件中讀出dirent結(jié)構(gòu)到內(nèi)存中。我們可以參考fs/readdir.c中的filldir()函數(shù)。 
2.對(duì)目錄文件索引節(jié)點(diǎn)的操作函數(shù):proc_dir_inode_operations 
首先,我們看一下proc_dir_inode_operations的定義: 
/* 
* proc directories can do almost nothing.. 
*/ 
static struct inode_operations proc_dir_inode_operations = { 
lookup: proc_lookup, 
}; 
我們看到,對(duì)于目錄文件的索引節(jié)點(diǎn),只定義了一個(gè)函數(shù)lookup。因?yàn)槲覀冊(cè)谇懊鎸?duì)VFS進(jìn)行分析的時(shí)候知道,以下操作,是只在目錄節(jié)點(diǎn)中定義的: 
int (*create) (struct inode *,struct dentry *,int); 
struct dentry * (*lookup) (struct inode *,struct dentry *); 
int (*link) (struct dentry *,struct inode *,struct dentry *); 
int (*unlink) (struct inode *,struct dentry *); 
int (*symlink) (struct inode *,struct dentry *,const char *); 
int (*mkdir) (struct inode *,struct dentry *,int); 
int (*rmdir) (struct inode *,struct dentry *); 
int (*mknod) (struct inode *,struct dentry *,int,int); 
int (*rename) (struct inode *, struct dentry *, 
struct inode *, struct dentry *); 
但是經(jīng)過我們對(duì)proc文件系統(tǒng)的分析,我們知道,proc文件系統(tǒng)中的文件都是在內(nèi)核代碼中通過proc_dir_entry實(shí)現(xiàn)的,因此,它不提供目錄索引節(jié)點(diǎn)的create,link,unlink,symlink,mkdir,rmdir,mknod,rename方法,也就是說,用戶是不能通過shell命令在/proc目錄中對(duì)proc文件進(jìn)行改名,刪除,建子目錄等操作的。這也算是proc文件系統(tǒng)的一種保護(hù)策略。 
而在內(nèi)核中,則使用proc_mkdir,proc_mknod等函數(shù),在核心內(nèi)通過代碼來維護(hù)proc文件樹。由此可以看出虛擬文件系統(tǒng)的一些特性。對(duì)目錄文件的默認(rèn)操作,可以參見下面的示意圖: 
下面我們就來看一下唯一定義的函數(shù)lookup: proc_lookup,到底實(shí)現(xiàn)了什么功能。 
在進(jìn)行具體分析之前,我們先考慮一個(gè)問題,我們知道,proc文件系統(tǒng)維護(hù)了自己的proc_dir_entry結(jié)構(gòu),因此提供了create_proc_entry,remove_proc_entry等等函數(shù),并且為了方便實(shí)現(xiàn)對(duì)proc文件的讀寫功能,特意在proc_dir_entry結(jié)構(gòu)中設(shè)置了get_info,read_proc和write_proc函數(shù)指針(我們?cè)谇懊娼榻B過,這三個(gè)函數(shù)被封裝在proc_file_operations中),并且,提供了自己的inode_operations和file_operations,分別是proc_iops 和proc_fops。也就是說,我們?cè)诮roc文件以及為proc文件建立操作函數(shù)的時(shí)候,似乎可以不用考慮VFS的實(shí)現(xiàn),只要建立并注冊(cè)該proc_dir_entry結(jié)構(gòu),然后實(shí)現(xiàn)其proc_iops 和proc_fops(或者get_info,read_proc和write_proc)就可以了。 
但是我們知道,在linux系統(tǒng)中,所有的子系統(tǒng)都是與VFS層交互,而VFS是通過inode結(jié)構(gòu)進(jìn)行管理的,并且在其上的操作(文件和索引節(jié)點(diǎn)的操作)也是通過該inode結(jié)構(gòu)的inode_operations和file_operations實(shí)現(xiàn)的。因此,proc文件系統(tǒng)必須將自己的文件與VFS的inode鏈接起來。 
那么proc文件系統(tǒng)是在何時(shí),通過何種方法將自己的proc_dir_entry結(jié)構(gòu)和VFS的inode聯(lián)系在一起的,并且將對(duì)inode的inode_operations和file_operations操作定位到自己結(jié)構(gòu)中的proc_iops 和proc_fops上呢?通過我們對(duì)lookup: proc_lookup的分析,就會(huì)明白這一過程。 
我們先看一下它的代碼: 
struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry) 
{ 
struct inode *inode; 
struct proc_dir_entry * de; 
int error; 
error = -ENOENT; 
inode = NULL; 
de = (struct proc_dir_entry *) dir->u.generic_ip; 
if (de) { 
for (de = de->subdir; de ; de = de->next) { 
if (!de || !de->low_ino) 
continue; 
if (de->namelen != dentry->d_name.len) 
continue; 
if (!memcmp(dentry->d_name.name, 
de->name, de->namelen)) { 
int ino = de->low_ino; 
error = -EINVAL; 
inode = proc_get_inode(dir->i_sb, ino, de); 
break; 
} 
} 
} 
if (inode) { 
dentry->d_op = &proc_dentry_operations; 
d_add(dentry, inode); 
return NULL; 
} 
return ERR_PTR(error); 
} 
這個(gè)函數(shù)的參數(shù)是struct inode * dir和struct dentry *dentry,它的功能是查找由dentry指定的文件,是否在由dir指定的目錄中。 
我們知道,proc文件系統(tǒng)通過proc_dir_entry結(jié)構(gòu)維護(hù)文件信息,并且該結(jié)構(gòu)與相應(yīng)的inode->u.generic_ip聯(lián)系,因此,這個(gè)函數(shù)首先通過struct inode * dir得到了相應(yīng)目錄文件的proc_dir_entry結(jié)構(gòu),并使用指針de指向它,然后,開始在該結(jié)構(gòu)的孩子中查找指定的dentry。 
判斷是否找到的條件很簡(jiǎn)單,就是de->namelen等于 dentry->d_name.len,并且dentry->d_name.name等于de->name,根據(jù)程序流程,如果沒有找到,那么將返回-ENOENT錯(cuò)誤(使用inode指針作為判斷條件),如果找到該文件,那么就根據(jù)ino = de->low_ino(要注意的是,這時(shí)候的de已經(jīng)指向由dentry確定的proc_dir_entry結(jié)構(gòu)了。)調(diào)用函數(shù): 
inode = proc_get_inode(dir->i_sb, ino, de); 
這個(gè)proc_get_inode的功能很容易猜到,就是從由超級(jí)塊i_sb確定的文件系統(tǒng)中,得到索引節(jié)點(diǎn)號(hào)為ino的inode。因此考慮兩種情況,第一種情況,這個(gè)索引節(jié)點(diǎn)已經(jīng)被讀入緩存了,那么直接返回該inode即可。第二種情況是,指定ino的索引節(jié)點(diǎn)不在緩存中,那么就需要調(diào)用相應(yīng)的函數(shù),將該索引節(jié)點(diǎn)從邏輯文件系統(tǒng)中讀入inode中。 
下面我們就來分析一下proc_get_inode函數(shù),尤其注意上面所說的第二種情況,因?yàn)檫@正是inode和proc_dir_entry建立聯(lián)系并重定位操作函數(shù)集的時(shí)機(jī)。先看一下源碼: 
struct inode * proc_get_inode(struct super_block * sb, int ino, 
struct proc_dir_entry * de) 
{ 
struct inode * inode; 
/* 
* Increment the use count so the dir entry can't disappear. 
*/ 
de_get(de); 
#if 1 
/* shouldn't ever happen */ 
if (de && de->deleted) 
printk("proc_iget: using deleted entry %s, count=%d\n", de->name, atomic_read(&de->count)); 
#endif 
inode = iget(sb, ino); 
if (!inode) 
goto out_fail; 
inode->u.generic_ip = (void *) de; /* link the proc_dir_entry to inode */ 
/* 
* set up other fields in the inode 
*/ 
if (de) { 
if (de->mode) { 
inode->i_mode = de->mode; 
inode->i_uid = de->uid; 
inode->i_gid = de->gid; 
} 
if (de->size) 
inode->i_size = de->size; 
if (de->nlink) 
inode->i_nlink = de->nlink; 
if (de->owner) 
__MOD_INC_USE_COUNT(de->owner); 
if (S_ISBLK(de->mode)||S_ISCHR(de->mode)||S_ISFIFO(de->mode)) 
init_special_inode(inode,de->mode,kdev_t_to_nr(de->rdev)); 
else { 
if (de->proc_iops) 
inode->i_op = de->proc_iops; 
if (de->proc_fops) 
inode->i_fop = de->proc_fops; 
} 
} 
out: 
return inode; 
out_fail: 
de_put(de); 
goto out; 
} 
我們根據(jù)程序流程,分析它的功能: 
1.使用de_get(de)增加proc_dir_entry結(jié)構(gòu)de的引用計(jì)數(shù)。 
2.使用VFS的iget(sb, ino)函數(shù),從sb指定的文件系統(tǒng)中得到節(jié)點(diǎn)號(hào)為ino的索引節(jié)點(diǎn),并使用指針inode指向它。如果沒有得到,則直接跳到標(biāo)號(hào)out_fail,減少de的引用計(jì)數(shù)后退出。 
因此我們要了解一下iget,這個(gè)函數(shù)由VFS提供,可以參考源文件fs/inode.c和頭文件include/linux/fs.h,在fs.h頭文件中,有如下定義: 
static inline struct inode *iget(struct super_block *sb, unsigned long ino) 
{ 
return iget4(sb, ino, NULL, NULL); 
} 
因此該函數(shù)是由fs/inode.c中的iget4實(shí)現(xiàn)的。主要步驟是,首先根據(jù)sb和ino得到要查找的索引節(jié)點(diǎn)的哈希鏈表,然后調(diào)用find_inode函數(shù)在該鏈表中查找該索引節(jié)點(diǎn)。如果找到了,那么就增加該索引節(jié)點(diǎn)的引用計(jì)數(shù),并將其返回;否則,調(diào)用get_new_inode函數(shù),以便從邏輯文件系統(tǒng)中讀出該索引節(jié)點(diǎn)。 
而get_new_inode函數(shù)也很簡(jiǎn)單,它分配一個(gè)inode結(jié)構(gòu),并試圖重新查找指定的索引節(jié)點(diǎn),如果還是沒有找到,那么就給新分配的索引節(jié)點(diǎn)加入到哈希鏈表和使用鏈表中,并設(shè)置一些基本信息,如i_ino,i_sb,i_dev等,并且,將其引用計(jì)數(shù)i_count初始化為1。然后,調(diào)用超級(jí)塊sb的read_inode函數(shù),來作邏輯文件系統(tǒng)自己特定的工作,但對(duì)于proc文件系統(tǒng)來說,read_inode函數(shù)基本沒有實(shí)質(zhì)性的功能,可參考前文對(duì)該函數(shù)的分析。最后,返回這個(gè)新建的索引節(jié)點(diǎn)。 
3.這時(shí),我們已經(jīng)得到了指定的inode(或者是從緩存中返回,或者是利用get_new_inode函數(shù)剛剛創(chuàng)建),那么就使用語句 
inode->u.generic_ip = (void *) de; 
將proc_dir_entry結(jié)構(gòu)de與相應(yīng)的索引節(jié)點(diǎn)鏈接起來。因此,我們就可以在其他時(shí)刻,利用proc文件索引節(jié)點(diǎn)的->u.generic_ip得到相應(yīng)的proc_dir_entry結(jié)構(gòu)了。 
對(duì)于新創(chuàng)建的inode來說,將其->u.generic_ip域指向(void *) de沒什么問題,因?yàn)樵撚蜻€沒有被賦值,但是如果這個(gè)inode是從緩存中得到的,那么,說明該域已經(jīng)指向了一個(gè)proc_dir_entry結(jié)構(gòu),這樣直接賦值,會(huì)不會(huì)引起問題呢? 
這有兩種情況,第一種情況,它指向的proc_dir_entry結(jié)構(gòu)沒有發(fā)生過變化,那么,由于索引節(jié)點(diǎn)是由ino確定的,而且在一個(gè)文件系統(tǒng)中,確保了索引節(jié)點(diǎn)號(hào)ino的唯一性,因此,使用inode->u.generic_ip = (void *) de語句對(duì)其重新進(jìn)行賦值,不會(huì)發(fā)生任何問題。 
另一種情況是在這之前,程序曾調(diào)用remove_proc_entry要將該proc_dir_entry結(jié)構(gòu)刪除,那么由于它的引用計(jì)數(shù)count不等于零,因此,該結(jié)構(gòu)不會(huì)被釋放,而只是打上了刪除標(biāo)記。所以這種情況下,該賦值語句也不會(huì)引起問題。 
我們知道,當(dāng)inode的i_count變?yōu)?的時(shí)候,會(huì)調(diào)用sb的proc_delete_inode函數(shù),這個(gè)函數(shù)將inode的i_state設(shè)置為I_CLEAR,這可以理解為將該inode刪除了,并調(diào)用de_put,減少并檢查proc_dir_entry的引用計(jì)數(shù),如果到零,也將其釋放。因此我們看到,引用計(jì)數(shù)的機(jī)制使得VFS的inode結(jié)構(gòu)和proc的proc_dir_entry結(jié)構(gòu)能夠保持同步,也就是說,對(duì)于一個(gè)存在于緩存中的的inode,必有一個(gè)proc_dir_entry結(jié)構(gòu)存在。 
4.這時(shí),我們已經(jīng)得到了inode結(jié)構(gòu),并且將相應(yīng)的proc_dir_entry結(jié)構(gòu)de與inode鏈接在了一起。因此,就可以根據(jù)de的信息,對(duì)inode的一些域進(jìn)行填充了。其中最重要的是使用語句: 
if (de->proc_iops) 
inode->i_op = de->proc_iops; 
if (de->proc_fops) 
inode->i_fop = de->proc_fops; 
將inode的操作函數(shù)集重定向到proc_dir_entry結(jié)構(gòu)提供的函數(shù)集上。這是因?yàn)槲覀兛梢酝ㄟ^proc_dir_entry結(jié)構(gòu)進(jìn)行方便的設(shè)置和調(diào)整,但最終要將文件提交至VFS進(jìn)行管理。正是在這種思想下,proc文件系統(tǒng)提供提供了一套封裝函數(shù),使得我們可以只對(duì)proc_dir_entry結(jié)構(gòu)進(jìn)行操作,而忽略與VFS的inode的聯(lián)系。 
5.最后,成功地返回所要的inode結(jié)構(gòu)。 
(七) 小結(jié) 
至此,已經(jīng)對(duì)proc文件系統(tǒng)進(jìn)行了一個(gè)粗略的分析,從文件系統(tǒng)的注冊(cè),到proc_dir_entry結(jié)構(gòu)的管理,以及與VFS的聯(lián)系等等。下面我們對(duì)proc文件系統(tǒng)的整體結(jié)構(gòu)作一個(gè)總結(jié)。 
proc文件系統(tǒng)使用VFS接口,注冊(cè)自己的文件類型,并且通過注冊(cè)時(shí)提供的proc_read_super函數(shù),創(chuàng)建自己的超級(jí)塊,然后裝載vfsmount結(jié)構(gòu)。在proc文件系統(tǒng)內(nèi)部,則使用proc_dir_entry結(jié)構(gòu)來維護(hù)自己的文件樹,并且通過目錄文件的lookup函數(shù),將proc_dir_entry結(jié)構(gòu)與VFS的inode結(jié)構(gòu)建立聯(lián)系。 


本文來自ChinaUnix博客,如果查看原文請(qǐng)點(diǎn):http://blog.chinaunix.net/u2/74524/showart_1129842.html


]]>
『轉(zhuǎn)』文件結(jié)構(gòu)體struct file(Linux 2.6.23內(nèi)核)http://www.shnenglu.com/momoxiao/archive/2010/06/17/118121.html小默小默Thu, 17 Jun 2010 15:14:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/06/17/118121.htmlhttp://www.shnenglu.com/momoxiao/comments/118121.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/06/17/118121.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/118121.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/118121.htmlstruct file結(jié)構(gòu)體定義在/linux/include/linux/fs.h(Linux 2.6.11內(nèi)核)中,其原型是:
struct file {
        /*
         * fu_list becomes invalid after file_free is called and queued via
         * fu_rcuhead for RCU freeing
         */
        union {
                struct list_head        fu_list;
                struct rcu_head         fu_rcuhead;
        } f_u;
        struct path             f_path;
#define f_dentry        f_path.dentry
#define f_vfsmnt        f_path.mnt
        const struct file_operations    *f_op;
        atomic_t                f_count;
        unsigned int            f_flags;
        mode_t                  f_mode;
        loff_t                  f_pos;
        struct fown_struct      f_owner;
        unsigned int            f_uid, f_gid;
        struct file_ra_state    f_ra;
        unsigned long           f_version;
#ifdef CONFIG_SECURITY
        void                    *f_security;
#endif
        /* needed for tty driver, and maybe others */
        void                    *private_data;
#ifdef CONFIG_EPOLL
        /* Used by fs/eventpoll.c to link all the hooks to this file */
        struct list_head        f_ep_links;
        spinlock_t              f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */
        struct address_space    *f_mapping;
};
文件結(jié)構(gòu)體代表一個(gè)打開的文件,系統(tǒng)中的每個(gè)打開的文件在內(nèi)核空間都有一個(gè)關(guān)聯(lián)的struct file。它由內(nèi)核在打開文件時(shí)創(chuàng)建,并傳遞給在文件上進(jìn)行操作的任何函數(shù)。在文件的所有實(shí)例都關(guān)閉后,內(nèi)核釋放這個(gè)數(shù)據(jù)結(jié)構(gòu)。在內(nèi)核創(chuàng)建和驅(qū)動(dòng)源碼中,struct file的指針通常被命名為file或filp。一下是對(duì)結(jié)構(gòu)中的每個(gè)數(shù)據(jù)成員的解釋:
一、
union {
    struct list_head fu_list;
    struct rcu_head rcuhead;
}f_u;
其中的struct list_head定義在 linux/include/linux/list.h中,原型為:
struct list_head {
        struct list_head *next, *prev;
};
用于通用文件對(duì)象鏈表的指針。
struct rcu_head定義在linux/include/linux/rcupdate.h中,其原型為:
/**
* struct rcu_head - callback structure for use with RCU
* @next: next update requests in a list
* @func: actual update function to call after the grace period.
*/
struct rcu_head {
        struct rcu_head *next;
        void (*func)(struct rcu_head *head);
};
RCU(Read-Copy Update)是Linux 2.6內(nèi)核中新的鎖機(jī)制,具體在這里有介紹:
http://www.ibm.com/developerworks/cn/linux/l-rcu/
二、
struct path             f_path;
被定義在linux/include/linux/namei.h中,其原型為:
struct path {
        struct vfsmount *mnt;
        struct dentry *dentry;
};
在早些版本的內(nèi)核中并沒有此結(jié)構(gòu),而是直接將path的兩個(gè)數(shù)據(jù)成員作為struct file的數(shù)據(jù)成員,
struct vfsmount *mnt的作用是指出該文件的已安裝的文件系統(tǒng),
struct dentry *dentry是與文件相關(guān)的目錄項(xiàng)對(duì)象。
三、
const struct file_operations    *f_op;
被定義在linux/include/linux/fs.h中,其中包含著與文件關(guān)聯(lián)的操作,如:
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
等。當(dāng)打開一個(gè)文件時(shí),內(nèi)核就創(chuàng)建一個(gè)與該文件相關(guān)聯(lián)的struct file結(jié)構(gòu),其中的*f_op就指向的是
具體對(duì)該文件進(jìn)行操作的函數(shù)。例如用戶調(diào)用系統(tǒng)調(diào)用read來讀取該文件的內(nèi)容時(shí),那么系統(tǒng)調(diào)用read最終會(huì)陷入內(nèi)核調(diào)用sys_read函數(shù),而sys_read最終會(huì)調(diào)用于該文件關(guān)聯(lián)的struct file結(jié)構(gòu)中的f_op->read函數(shù)對(duì)文件內(nèi)容進(jìn)行讀取。
四、
atomic_t                f_count;
atomic_t被定義為:
typedef struct { volatile int counter; } atomic_t;
volatile修飾字段告訴gcc不要對(duì)該類型的數(shù)據(jù)做優(yōu)化處理,對(duì)它的訪問都是對(duì)內(nèi)存的訪問,而不是對(duì)寄存器的訪問。 
本質(zhì)是int類型,之所以這樣寫是讓編譯器對(duì)基于該類型變量的操作進(jìn)行嚴(yán)格的類型檢查。此處f_count的作用是記錄對(duì)文件對(duì)象的引用計(jì)數(shù),也即當(dāng)前有多少個(gè)進(jìn)程在使用該文件。
五、
unsigned int            f_flags;
當(dāng)打開文件時(shí)指定的標(biāo)志,對(duì)應(yīng)系統(tǒng)調(diào)用open的int flags參數(shù)。驅(qū)動(dòng)程序?yàn)榱酥С址亲枞筒僮餍枰獧z查這個(gè)標(biāo)志。
六、
mode_t                  f_mode;
對(duì)文件的讀寫模式,對(duì)應(yīng)系統(tǒng)調(diào)用open的mod_t mode參數(shù)。如果驅(qū)動(dòng)程序需要這個(gè)值,可以直接讀取這個(gè)字段。
mod_t被定義為:
typedef unsigned int __kernel_mode_t;
typedef __kernel_mode_t         mode_t;
七、
loff_t                  f_pos;
當(dāng)前的文件指針位置,即文件的讀寫位置。
loff_t被定義為:
typedef long long       __kernel_loff_t;
typedef __kernel_loff_t         loff_t;
八、
struct fown_struct      f_owner;
struct fown_struct在linux/include/linux/fs.h被定義,原型為:
struct fown_struct {
        rwlock_t lock;          /* protects pid, uid, euid fields */
        struct pid *pid;        /* pid or -pgrp where SIGIO should be sent */
        enum pid_type pid_type; /* Kind of process group SIGIO should be sent to */
        uid_t uid, euid;        /* uid/euid of process setting the owner */
        int signum;             /* posix.1b rt signal to be delivered on IO */
};
該結(jié)構(gòu)的作用是通過信號(hào)進(jìn)行I/O時(shí)間通知的數(shù)據(jù)。
九、
unsigned int            f_uid, f_gid;
標(biāo)識(shí)文件的所有者id,所有者所在組的id.
十、
struct file_ra_state    f_ra;
struct file_ra_state結(jié)構(gòu)被定義在/linux/include/linux/fs.h中,原型為:
struct file_ra_state {
        pgoff_t start;                  /* where readahead started */
        unsigned long size;             /* # of readahead pages */
        unsigned long async_size;       /* do asynchronous readahead when
                                           there are only # of pages ahead */
                                           
        unsigned long ra_pages;         /* Maximum readahead window */
        unsigned long mmap_hit;         /* Cache hit stat for mmap accesses */
        unsigned long mmap_miss;        /* Cache miss stat for mmap accesses */
        unsigned long prev_index;       /* Cache last read() position */
        unsigned int prev_offset;       /* Offset where last read() ended in a page */
};
文件預(yù)讀狀態(tài),文件預(yù)讀算法使用的主要數(shù)據(jù)結(jié)構(gòu),當(dāng)打開一個(gè)文件時(shí),f_ra中出了perv_page(默認(rèn)為-1)和ra_apges(對(duì)該文件允許的最大預(yù)讀量)這兩個(gè)字段外,其他的所有西端都置為0。
十一、
unsigned long           f_version;
記錄文件的版本號(hào),每次使用后都自動(dòng)遞增。
十二、
#ifdef CONFIG_SECURITY
        void                    *f_security;
#endif
此處我的理解是如果在編譯內(nèi)核時(shí)配置了安全措施,那么struct file結(jié)構(gòu)中就會(huì)有void *f_security數(shù)據(jù)項(xiàng),用來描述安全措施或者是記錄與安全有關(guān)的信息。
十三、
void *private_data;
系統(tǒng)在調(diào)用驅(qū)動(dòng)程序的open方法前將這個(gè)指針置為NULL。驅(qū)動(dòng)程序可以將這個(gè)字段用于任意目的,也可以忽略這個(gè)字段。驅(qū)動(dòng)程序可以用這個(gè)字段指向已分配的數(shù)據(jù),但是一定要在內(nèi)核釋放file結(jié)構(gòu)前的release方法中清除它。
十四、
#ifdef CONFIG_EPOLL
        /* Used by fs/eventpoll.c to link all the hooks to this file */
        struct list_head        f_ep_links;
        spinlock_t              f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */
被用在fs/eventpoll.c來鏈接所有鉤到這個(gè)文件上。其中f_ep_links是文件的事件輪詢等待者鏈表的頭,f_ep_lock是保護(hù)f_ep_links鏈表的自旋鎖。
十五、struct address_space    *f_mapping;
struct address_space被定義在/linux/include/linux/fs.h中,此處是指向文件地址空間的指針。
  在驅(qū)動(dòng)開發(fā)中,文件讀/寫模式mode、標(biāo)志f_flags都是設(shè)備驅(qū)動(dòng)關(guān)心的內(nèi)容,而私有數(shù)據(jù)指針private_data在折本驅(qū)動(dòng)中被廣泛使用,大多被指向設(shè)備驅(qū)動(dòng)自定義用于描述設(shè)備的結(jié)構(gòu)體。 
驅(qū)動(dòng)程序中常用如下類似的代碼來檢測(cè)用戶打開文件的讀寫方式:
if (file->f_mode & FMODE_WRITE) //用戶要求可寫
  {
  }
  if (file->f_mode & FMODE_READ) //用戶要求可讀
  {
  }
下面的代碼可用于判斷以阻塞還是非阻塞方式打開設(shè)備文件:
  if (file->f_flags & O_NONBLOCK) //非阻塞
      pr_debug("open:non-blocking\n");
  else //阻塞
      pr_debug("open:blocking\n");
參考:
Linux設(shè)備驅(qū)動(dòng)開發(fā)詳解
深入理解linux內(nèi)核

]]>
warning: Clock skew detected. Your build may be incomplete.http://www.shnenglu.com/momoxiao/archive/2010/06/15/117967.html小默小默Tue, 15 Jun 2010 07:33:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/06/15/117967.htmlhttp://www.shnenglu.com/momoxiao/comments/117967.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/06/15/117967.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/117967.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/117967.html怎么檢測(cè)的? //TODO

“在系統(tǒng)啟動(dòng)時(shí),Linux操作系統(tǒng)將時(shí)間從CMOS中讀到系統(tǒng)時(shí)間變量中,以后修改時(shí)間通過修改系統(tǒng)時(shí)間實(shí)現(xiàn)。為了保持系統(tǒng)時(shí)間與CMOS時(shí)間的一致性,Linux每隔一段時(shí)間會(huì)將系統(tǒng)時(shí)間寫入CMOS。由于該同步是每隔一段時(shí)間(大約是11分鐘)進(jìn)行的,在我們執(zhí)行date -s后,如果馬上重起機(jī)器,修改時(shí)間就有可能沒有被寫入CMOS。如果要確保修改生效可以執(zhí)行命令clock -w。“
[root@colorfulgreen rkit]# date 
Thu Jun 
10 20:50:30 CST 2010
[root@colorfulgreen rkit]# date 
-6/15/2010 //修改時(shí)間-指由Linux操作系統(tǒng)維護(hù)的時(shí)間
Tue Jun 15 00:00:00 CST 2010
[root@colorfulgreen rkit]# date 
-15:20:00
Tue Jun 
15 15:20:00 CST 2010
[root@colorfulgreen rkit]# date
Tue Jun 
15 15:20:04 CST 2010
[root@colorfulgreen rkit]# clock 
-//強(qiáng)制把系統(tǒng)時(shí)間寫入CMOS
[root@colorfulgreen rkit]# date
Tue Jun 
15 15:20:20 CST 2010
[root@colorfulgreen rkit]# 



]]>
【轉(zhuǎn)】SELinux targeted policy relabel is required.http://www.shnenglu.com/momoxiao/archive/2010/06/13/117767.html小默小默Sun, 13 Jun 2010 01:48:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/06/13/117767.htmlhttp://www.shnenglu.com/momoxiao/comments/117767.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/06/13/117767.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/117767.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/117767.htmlhttp://www.centos.org/modules/newbb/viewtopic.php?topic_id=15960

]]>
Ubuntu 登錄密碼忘記 & root密碼設(shè)置http://www.shnenglu.com/momoxiao/archive/2010/06/06/117253.html小默小默Sat, 05 Jun 2010 23:53:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/06/06/117253.htmlhttp://www.shnenglu.com/momoxiao/comments/117253.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/06/06/117253.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/117253.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/117253.html剛裝好Ubuntu 8.04可以剛才設(shè)置的密碼忘記了
用了以下方法恢復(fù)了系統(tǒng)的登陸密碼:
1、重新啟動(dòng),按ESC鍵進(jìn)入Boot Menu,選擇recovery mode(一般是第二個(gè)選項(xiàng))。
2、在#號(hào)提示符下用cat /etc/shadow,查看剛才設(shè)置的用戶名
3、輸入passwd "用戶名"(引號(hào)是必須的)。
4、輸入新的密碼.
5、重新啟動(dòng),用新密碼登錄。

================

首先設(shè)置root密碼,利用現(xiàn)有管理員帳戶登陸Ubuntu,在終端執(zhí)行命令:sudo passwd root,接著輸入密碼和root密碼,重復(fù)密碼。這樣就有了可用的root用戶。



]]>
ps lkmhttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116924.html小默小默Tue, 01 Jun 2010 12:23:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116924.htmlhttp://www.shnenglu.com/momoxiao/comments/116924.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116924.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/116924.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/116924.html
#include <linux/module.h>
#include 
<linux/init.h>
#include 
<linux/list.h>
#include 
<linux/sched.h>

#define METHOD 1

static int list_init(void)
{
    
struct task_struct *task, *p;
    
struct list_head *pos;

    
int count;

    
char *method;



    count 
= 0;

    p 
= NULL;

    task 
= NULL;

    method 
= NULL;

    task 
= &init_task;


    
switch(METHOD){

        
case 1:

            method 
= "list_for_each";

            
break;

        
case 2:

            method 
= "for_each_process";

            
break;

        
case 3:

            method 
= "list_for_each_entry";

            
break;

    }



    printk(
"The method is %s\n",method);


    printk(KERN_ALERT
"PID\tCOMM\n");




    
if(METHOD == 1){

        list_for_each(pos,
&task->tasks){

            p 
= list_entry(pos,struct task_struct,tasks);

            count
++;

            printk(KERN_ALERT
"%d\t%s\n",p->pid,p->comm);

        }

    }

    
else if(METHOD == 2){

        for_each_process(task){

        count
++;

        printk(KERN_ALERT
"%d\t%s\n",task->pid,task->comm);

        }

    }

    
else if(METHOD == 3){

        list_for_each_entry(p,
&task->tasks,tasks){

        count
++;

        printk(KERN_ALERT 
"%d\t%s\n",p->pid,p->comm);

        }

    }



    printk(
"系統(tǒng)當(dāng)前共有 %d 個(gè)進(jìn)程!\n",count);



    
return 0;


}



static void list_exit(void)

{

    printk(KERN_ALERT 
"GOOD BYE!\n");

}



module_init(list_init);

module_exit(list_exit);



MODULE_AUTHOR(
"...");

MODULE_LICENSE(
"GPL");


Makefile:
obj-m := pslkm.o

KERNELDIR 
?= /lib/modules/$(shell uname -r)/build

PWD :
= $(shell pwd)

all:

    make 
-C $(KERNELDIR) M=$(PWD) modules

clean:

    make 
-C $(KERNELDIR) M=$(PWD) clean




]]>
paramhttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116923.html小默小默Tue, 01 Jun 2010 12:21:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116923.htmlhttp://www.shnenglu.com/momoxiao/comments/116923.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116923.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/116923.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/116923.html
#include<linux/module.h>
#include
<linux/kernel.h>
#include 
<linux/init.h>


static int module_int = 100;


module_param(module_int,
int,S_IRUSR);




int __init para_init(void)
{
    printk(
"My linux kernel module\n");
    printk(
"module_int = %d\n",module_int);
    
return 0;
}

void __exit para_exit(void)
{
    printk(
"My linux kernel module was removed.\n");
}

module_init(para_init);
module_exit(para_exit);

MODULE_LICENSE(
"GPL");



//向內(nèi)核注冊(cè)模塊所提供的新功能
//module_init(lkp_init); 
//注銷由模塊提供的所有功能
//module_exit(lkp_cleanup);

//MODULE_LICENSE("GPL");



Makefile:
KERNELBUILD := /lib/modules/$(shell uname -r)/build



obj
-+= para.o



default: para



para:

    make 
-C $(KERNELBUILD) M=$(shell pwd) modules



clean:

    rm 
-f  *.ko *.o hide

    rm 
-*mod* Module*




]]>
mallochttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116922.html小默小默Tue, 01 Jun 2010 12:20:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116922.htmlhttp://www.shnenglu.com/momoxiao/comments/116922.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116922.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/116922.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/116922.html//malloc.c
#include 
<linux/module.h>
#include 
<linux/slab.h>
#include 
<linux/vmalloc.h>
MODULE_LICENSE(
"GPL");
unsigned 
char *pagemem;
unsigned 
char *kmallocmem;
unsigned 
char *vmallocmem;

int __init mem_module_init(void)
{
//最好每次內(nèi)存申請(qǐng)都檢查申請(qǐng)是否成功
//下面這段僅僅作為演示的代碼沒有檢查
//pagemem = (unsigned char*)get_free_page(0);
//printk("<1>pagemem addr=%x", pagemem);

kmallocmem 
= (unsigned char*)kmalloc(1000);
printk(
"<1>kmallocmem addr=%x", kmallocmem);

vmallocmem 
= (unsigned char*)vmalloc(1000000);
printk(
"<1>vmallocmem addr=%x", vmallocmem);

return 0;
}

void __exit mem_module_exit(void)
{
//free_page(pagemem);
kfree(kmallocmem);
vfree(vmallocmem);
}

module_init(mem_module_init);
module_exit(mem_module_exit);

Makefile:
obj-m := malloc.o
KDIR :
= /lib/modules/$(shell uname -r)/build
PWD :
= $(shell pwd)

default:
    $(MAKE) 
-C $(KDIR) SUBDIRS=$(PWD) modules




]]>free pageshttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116921.html小默小默Tue, 01 Jun 2010 12:18:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116921.htmlhttp://www.shnenglu.com/momoxiao/comments/116921.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116921.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/116921.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/116921.html#include <linux/module.h>
#include 
<linux/kernel.h>
#include 
<linux/gfp.h>
#include 
<linux/mm.h>

int __init freepage_init()
{
    unsigned 
long page;

    page 
= __get_free_pages(GFP_KERNEL,3);  //8 page
    if(!page){
        
//no enough space
        return -ENOMEM;
    }

    printk(
"<1>the vaddr of the first page is <%lx>..",page);

    free_pages(page,
3);

    
return 0;
}

void __exit freepage_exit()
{
    
return;
}

module_init(freepage_init);
module_exit(freepage_exit);

MODULE_LICENSE(
"GPL");

Makefile:
obj-m := freepage.o
KDIR :
= /lib/modules/$(shell uname -r)/build
PWD :
= $(shell pwd)

default:
    $(MAKE) 
-C $(KDIR) SUBDIRS=$(PWD) modules




]]>
【轉(zhuǎn)】使用 /sys 文件系統(tǒng)訪問 Linux 內(nèi)核http://www.shnenglu.com/momoxiao/archive/2010/05/31/116813.html小默小默Mon, 31 May 2010 07:33:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/05/31/116813.htmlhttp://www.shnenglu.com/momoxiao/comments/116813.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/05/31/116813.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/116813.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/116813.html閱讀全文

]]>
[zz]Ubuntu hostshttp://www.shnenglu.com/momoxiao/archive/2010/05/26/116355.html小默小默Wed, 26 May 2010 01:35:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/05/26/116355.htmlhttp://www.shnenglu.com/momoxiao/comments/116355.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/05/26/116355.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/116355.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/116355.htmlUbuntu系統(tǒng)的Hosts只需修改/etc/hosts文件,在目錄中還有一個(gè)hosts.conf文件,剛開始還以為只需要修改這個(gè)就可以了,結(jié)果發(fā)現(xiàn)是需要修改hosts。修改完之后要重啟網(wǎng)絡(luò)。
具體過程如下:
1、修改hosts
sudo gedit /etc/hosts
2、添加解析記錄( . )
完整案例:127.0.0.1 localhost.localdomain localhost
簡(jiǎn)潔記錄:127.0.0.1 localhost
3、保存后重啟網(wǎng)絡(luò)
sudo /etc/init.d/networking restart


]]>
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            日韩亚洲欧美一区| 久久夜色撩人精品| 老巨人导航500精品| 国产精品久久久久永久免费观看 | 免费看av成人| 99re6热在线精品视频播放速度| 翔田千里一区二区| 欧美岛国激情| 国产一区二区黄色| 亚洲综合视频在线| 亚洲人成在线播放网站岛国| 欧美成人午夜剧场免费观看| 亚洲一区二区精品视频| 欧美黑人多人双交| 亚洲大胆av| 久久精品一区二区三区不卡| 亚洲美女精品一区| 免费视频亚洲| 亚洲高清免费视频| 久热爱精品视频线路一| 亚洲欧美www| 国产女精品视频网站免费| 亚洲一区二区三区在线视频| 亚洲人线精品午夜| 国产精品久久77777| 亚洲少妇中出一区| 亚洲精品国产视频| 国产精品资源| 欧美在线|欧美| 亚洲一区二区三| 尤物九九久久国产精品的特点| 久久精品人人做人人爽电影蜜月| 欧美一级黄色网| 国产九九精品| 欧美激情一区在线| 欧美国产精品专区| 久久福利影视| 欧美中文字幕视频在线观看| 国产欧美日韩精品专区| 欧美高清不卡| 国产精品日韩欧美一区| 欧美在线免费一级片| 噜噜噜在线观看免费视频日韩| 亚洲国产一区二区在线| 亚洲国产婷婷香蕉久久久久久| 欧美11—12娇小xxxx| 亚洲欧美成人| 欧美一区二区三区在线播放| 日韩香蕉视频| 久久精品综合一区| 久久九九精品99国产精品| 一区二区三区高清在线观看| 一本色道久久精品| 国产精品国产三级国产普通话蜜臀| 久久综合一区二区| 欧美日韩dvd在线观看| 亚洲天堂久久| 免费久久99精品国产| 欧美在线啊v一区| 欧美激情黄色片| 久久婷婷成人综合色| 欧美ed2k| 久久久青草婷婷精品综合日韩 | 欧美v日韩v国产v| 免费日本视频一区| 久久久久国内| 欧美性开放视频| 久久精品视频va| 国产精品sss| 亚洲国产片色| 在线观看亚洲精品视频| 午夜精品一区二区在线观看| 亚洲天堂av高清| 欧美成人午夜影院| 欧美成人免费在线观看| 国产综合一区二区| 欧美激情精品久久久久久久变态 | 韩国一区二区三区美女美女秀| 欧美国产91| 国内外成人免费激情在线视频| 中日韩视频在线观看| 今天的高清视频免费播放成人| 亚洲国产精品专区久久| 一区在线播放| 午夜亚洲伦理| 午夜精品视频一区| 葵司免费一区二区三区四区五区| 久久久久久亚洲精品中文字幕| 国产精品亚洲精品| 在线亚洲欧美视频| 国产精品99久久久久久宅男 | 欧美日韩国产一级片| 亚洲国产日韩欧美在线图片| 1769国内精品视频在线播放| 久久精品视频一| 久久久www成人免费无遮挡大片| 国产精品毛片va一区二区三区 | 久久天堂成人| 麻豆精品91| 在线播放豆国产99亚洲| 久久成人一区| 亚洲女性裸体视频| 欧美午夜久久| 一本色道久久88综合日韩精品| 一区二区三区欧美亚洲| 欧美日本在线播放| 噜噜噜躁狠狠躁狠狠精品视频 | 欧美综合国产| 久久久www成人免费毛片麻豆 | 午夜精品成人在线视频| 日韩亚洲欧美在线观看| 欧美精品国产一区| 麻豆精品国产91久久久久久| 在线播放精品| 久久午夜精品| 亚洲第一精品福利| 国产视频在线一区二区| 亚洲精品裸体| 亚洲婷婷综合久久一本伊一区| 欧美视频一区二区三区在线观看| 欧美激情网站在线观看| 亚洲欧洲一区二区三区| 性8sex亚洲区入口| 久久久久久色| 亚洲高清不卡av| 欧美风情在线观看| 一本色道久久综合亚洲二区三区 | 久久精品国产一区二区电影 | **网站欧美大片在线观看| 猫咪成人在线观看| 亚洲人在线视频| 亚洲小说春色综合另类电影| 国产精品午夜久久| 欧美在线二区| 欧美电影免费观看| 一本大道久久a久久精二百| 老色批av在线精品| 亚洲精品久久久蜜桃| 亚洲一区尤物| 国产一区二区三区在线观看网站 | 亚洲日韩成人| 亚洲欧美日韩精品久久久| 国产一区二区三区久久悠悠色av| 久久综合激情| 亚洲精品中文字幕有码专区| 午夜精品久久久久久久蜜桃app | 欧美三级不卡| 久久成人精品一区二区三区| 欧美激情中文字幕一区二区| 亚洲天堂av在线免费| 国产婷婷色一区二区三区| 久久一区二区三区国产精品| 日韩亚洲欧美一区| 久久久久久亚洲综合影院红桃| 亚洲精品美女免费| 欧美激情在线观看| 亚洲女人天堂成人av在线| 老司机aⅴ在线精品导航| 夜夜狂射影院欧美极品| 国产欧美一区在线| 你懂的亚洲视频| 亚洲一区久久久| 美女日韩在线中文字幕| 这里只有精品视频| 国语自产精品视频在线看抢先版结局 | 亚洲人成啪啪网站| 午夜视频在线观看一区二区三区 | 亚洲欧洲精品一区二区三区不卡 | 亚洲视频观看| 欧美插天视频在线播放| 亚洲一区二区三区影院| 一区二区三区在线高清| 国产精品jizz在线观看美国| 久久麻豆一区二区| 欧美承认网站| 亚洲欧美日韩精品久久久| 亚洲高清毛片| 国产精品综合网站| 欧美精品三级在线观看| 欧美在线综合视频| 99视频精品免费观看| 亚洲欧美综合另类中字| 亚洲国产日韩欧美一区二区三区| 国产精品久久久久久福利一牛影视| 久久亚洲影音av资源网| 亚洲尤物在线视频观看| 最新国产成人在线观看| 亚洲一区www| 91久久精品www人人做人人爽| 国产欧美日本一区视频| 欧美日本在线播放| 蜜臀a∨国产成人精品| 欧美亚洲视频一区二区| 99国产精品国产精品久久| 欧美1区3d| 久久精品国亚洲| 午夜在线电影亚洲一区| 一区二区三区在线高清| 国产精品一区二区三区免费观看| 欧美另类久久久品|