亚洲欧美制服另类日韩,久久男人资源视频,亚洲一区二区三区乱码aⅴ蜜桃女http://m.shnenglu.com/momoxiao/category/13037.htmlzh-cnWed, 15 Jun 2011 12:18:08 GMTWed, 15 Jun 2011 12:18:08 GMT60thread 多線程http://m.shnenglu.com/momoxiao/archive/2011/06/14/148668.html小默小默Tue, 14 Jun 2011 12:27:00 GMThttp://m.shnenglu.com/momoxiao/archive/2011/06/14/148668.htmlhttp://m.shnenglu.com/momoxiao/comments/148668.htmlhttp://m.shnenglu.com/momoxiao/archive/2011/06/14/148668.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/148668.htmlhttp://m.shnenglu.com/momoxiao/services/trackbacks/148668.html多線程

編寫多線程程序時,在設(shè)計上要特別小心.
對共享變量,多個執(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個線程的argument全是5.
因為新線程的參數(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è)計

小默 2011-06-14 20:27 發(fā)表評論
]]>
thread 取消線程http://m.shnenglu.com/momoxiao/archive/2011/06/14/148666.html小默小默Tue, 14 Jun 2011 11:45:00 GMThttp://m.shnenglu.com/momoxiao/archive/2011/06/14/148666.htmlhttp://m.shnenglu.com/momoxiao/comments/148666.htmlhttp://m.shnenglu.com/momoxiao/archive/2011/06/14/148666.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/148666.htmlhttp://m.shnenglu.com/momoxiao/services/trackbacks/148666.html取消一個線程

可以請求一個線程終止,像給它發(fā)送一個信號一樣.

1 請求端:

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

2 接收請求端:

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

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

小默 2011-06-14 19:45 發(fā)表評論
]]>
thread 線程屬性 脫離線程http://m.shnenglu.com/momoxiao/archive/2011/06/14/148663.html小默小默Tue, 14 Jun 2011 10:56:00 GMThttp://m.shnenglu.com/momoxiao/archive/2011/06/14/148663.htmlhttp://m.shnenglu.com/momoxiao/comments/148663.htmlhttp://m.shnenglu.com/momoxiao/archive/2011/06/14/148663.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/148663.htmlhttp://m.shnenglu.com/momoxiao/services/trackbacks/148663.html線程的屬性

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

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

#include <pthread.h>
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
這個屬性允許我們無需對線程進(jìn)行合并:
| PTHREAD_CREATE_JOINABLE 默認(rèn).
| PTHREAD_CREATE_DETACHED 不能調(diào)用pthread_join來獲得另一個線程的退出狀態(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個調(diào)度方式具備實(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);
控制一個線程調(diào)度的計算方式,目前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)線程時,默認(rèn)的棧很大,這個屬性有點(diǎn)多余.
創(chuàng)建脫離線程:
/*
 * 線程屬性-創(chuàng)建脫離線程
 * 主線程不等待子線程結(jié)束,只通過thread_finished標(biāo)志來檢測子線程是否已結(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è)計

小默 2011-06-14 18:56 發(fā)表評論
]]>
struct sk_buffhttp://m.shnenglu.com/momoxiao/archive/2011/03/24/142666.html小默小默Thu, 24 Mar 2011 10:07:00 GMThttp://m.shnenglu.com/momoxiao/archive/2011/03/24/142666.htmlhttp://m.shnenglu.com/momoxiao/comments/142666.htmlhttp://m.shnenglu.com/momoxiao/archive/2011/03/24/142666.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/142666.htmlhttp://m.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前部截斷
skb_trim // used data后部截斷
skb_reserve // data+分片后移,只允許對空緩存使用

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



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

__alloc_skb()分析:

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

********

__alloc_skb()完成時,內(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的引用計數(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)用時會引發(fā)oops,導(dǎo)致棧的回溯和錯誤信息的打印.
大部分體系結(jié)構(gòu)把BUG()定義成某種非法操作.
斷言某種情況不該發(fā)生:
if(bad_thing):
    BUG();
或者更好的形式:
BUG_ON(bad_thing);

******
frag_list

如果傳輸層將數(shù)據(jù)包分片了,就會把這些數(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 = 分片



小默 2011-03-24 18:07 發(fā)表評論
]]>
【轉(zhuǎn)】Fedora Linux中的日志服務(wù)http://m.shnenglu.com/momoxiao/archive/2011/03/02/141009.html小默小默Wed, 02 Mar 2011 13:23:00 GMThttp://m.shnenglu.com/momoxiao/archive/2011/03/02/141009.htmlhttp://m.shnenglu.com/momoxiao/comments/141009.htmlhttp://m.shnenglu.com/momoxiao/archive/2011/03/02/141009.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/141009.htmlhttp://m.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ǔ)知識。涉及日志的服務(wù)有兩個,在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。我們檢測一下當(dāng)前這個服務(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ù)是-c 3。這個輸入?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)行級別中,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ù)和需要記錄什么等級的信息。

      下面是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級別的信息都記錄到/var/log/messages中,但不要記錄mail,authpriv和cron服務(wù)產(chǎn)生的信息;

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

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

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

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

     A 七種信息等級

        1)info

        2)notice

        3)warning或warn

        4)err或error

        5)crit

        6)alert

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

     B 信息等級的指定方式

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

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

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

2. logrotate服務(wù)

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

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

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

       [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時,需要指定其配置文件/etc/logrotate.conf。這個文件定義了如何轉(zhuǎn)儲日志文件的規(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.

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

       include /etc/logrotate.d

       這里有個例子:/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
       }

      上面的配置對于/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)儲后,重啟rsyslogd服務(wù)。

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



小默 2011-03-02 21:23 發(fā)表評論
]]>
linux kernel macro likely() unlikely()http://m.shnenglu.com/momoxiao/archive/2011/02/03/139709.html小默小默Thu, 03 Feb 2011 08:23:00 GMThttp://m.shnenglu.com/momoxiao/archive/2011/02/03/139709.htmlhttp://m.shnenglu.com/momoxiao/comments/139709.htmlhttp://m.shnenglu.com/momoxiao/archive/2011/02/03/139709.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/139709.htmlhttp://m.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ù)測信息:期望EXP==C,返回值是EXP。其中C是編譯時常量。
eg:
if(__buildin_expect(ptr != NULL, 1)) error(); // 期望ptr!=NULL為1;當(dāng)期望滿足時(返回的ptr != NULL為1)執(zhí)行error()
if(__buildin_expect(x,0)) foo(); // 期望x==0;當(dāng)期望未滿足(返回的x為真)時執(zhí)行foo()

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

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



小默 2011-02-03 16:23 發(fā)表評論
]]>
implicit declaration of function 'NIPQUAD'http://m.shnenglu.com/momoxiao/archive/2011/01/27/139393.html小默小默Wed, 26 Jan 2011 20:28:00 GMThttp://m.shnenglu.com/momoxiao/archive/2011/01/27/139393.htmlhttp://m.shnenglu.com/momoxiao/comments/139393.htmlhttp://m.shnenglu.com/momoxiao/archive/2011/01/27/139393.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/139393.htmlhttp://m.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)" : "");



小默 2011-01-27 04:28 發(fā)表評論
]]>
ldd3讀書筆記http://m.shnenglu.com/momoxiao/archive/2011/01/05/138041.html小默小默Wed, 05 Jan 2011 15:24:00 GMThttp://m.shnenglu.com/momoxiao/archive/2011/01/05/138041.htmlhttp://m.shnenglu.com/momoxiao/comments/138041.htmlhttp://m.shnenglu.com/momoxiao/archive/2011/01/05/138041.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/138041.htmlhttp://m.shnenglu.com/momoxiao/services/trackbacks/138041.html閱讀全文

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

小默 2010-12-10 23:48 發(fā)表評論
]]>
蓋樓 http://m.shnenglu.com/momoxiao/archive/2010/11/09/133126.html小默小默Tue, 09 Nov 2010 14:18:00 GMThttp://m.shnenglu.com/momoxiao/archive/2010/11/09/133126.htmlhttp://m.shnenglu.com/momoxiao/comments/133126.htmlhttp://m.shnenglu.com/momoxiao/archive/2010/11/09/133126.html#Feedback25http://m.shnenglu.com/momoxiao/comments/commentRss/133126.htmlhttp://m.shnenglu.com/momoxiao/services/trackbacks/133126.html

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

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

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

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

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

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

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

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


小默 2010-08-17 00:18 發(fā)表評論
]]>
SIGHUPhttp://m.shnenglu.com/momoxiao/archive/2010/08/17/123642.html小默小默Mon, 16 Aug 2010 16:05:00 GMThttp://m.shnenglu.com/momoxiao/archive/2010/08/17/123642.htmlhttp://m.shnenglu.com/momoxiao/comments/123642.htmlhttp://m.shnenglu.com/momoxiao/archive/2010/08/17/123642.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/123642.htmlhttp://m.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.

小默 2010-08-17 00:05 發(fā)表評論
]]>
waithttp://m.shnenglu.com/momoxiao/archive/2010/08/16/123640.html小默小默Mon, 16 Aug 2010 15:42:00 GMThttp://m.shnenglu.com/momoxiao/archive/2010/08/16/123640.htmlhttp://m.shnenglu.com/momoxiao/comments/123640.htmlhttp://m.shnenglu.com/momoxiao/archive/2010/08/16/123640.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/123640.htmlhttp://m.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()會暫時停止目前進(jìn)程的執(zhí)行,直到有信號來到或子進(jìn)程結(jié)束。如果在調(diào)用wait()時子進(jìn)程已經(jīng)結(jié)束,則wait()會立即返回子進(jìn)程結(jié)束狀態(tài)值。子進(jìn)程的結(jié)束狀態(tài)值會由參數(shù)status 返回,而子進(jìn)程的進(jìn)程識別碼也會一快返回。如果不在意結(jié)束狀態(tài)值,則參數(shù)status 可以設(shè)成NULL。子進(jìn)程的結(jié)束狀態(tài)值請參考下面的waitpid()。

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

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


小默 2010-08-16 23:42 發(fā)表評論
]]>
forkhttp://m.shnenglu.com/momoxiao/archive/2010/08/16/123639.html小默小默Mon, 16 Aug 2010 15:27:00 GMThttp://m.shnenglu.com/momoxiao/archive/2010/08/16/123639.htmlhttp://m.shnenglu.com/momoxiao/comments/123639.htmlhttp://m.shnenglu.com/momoxiao/archive/2010/08/16/123639.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/123639.htmlhttp://m.shnenglu.com/momoxiao/services/trackbacks/123639.html頭文件:
#include <unistd.h>

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

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

函數(shù)說明:
一個現(xiàn)有進(jìn)程可以調(diào)用fork函數(shù)創(chuàng)建一個新進(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)程持有的是上述存儲空間的“副本”,這意味著父子進(jìn)程間不共享這些存儲空間,它們之間共享的存儲空間只有代碼段。



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

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

    f 
= tmpfile(); // 創(chuàng)建臨時文件
    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 時間。把這些資料顯示在屏幕上。
int main()
{
    
struct rusage r_usage;
    
struct rlimit r_limit;
    
int priority;

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

    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í)行它的指令所消耗的時間
           r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec);   // r_usage.ru_stime OS由于這個程序而消耗的 CPU 時間

    
/// 調(diào)用 getpriority 和 getrlimit 函數(shù)分別查出自己的當(dāng)前優(yōu)先級和文件長度限制
    priority = getpriority(PRIO_PROCESS, getpid()); // PRIO_PROCESS 表示后面是進(jìn)程標(biāo)識符
    printf("Current priority = %d\n", priority);
    getrlimit(RLIMIT_FSIZE, 
&r_limit); // 讀取以字節(jié)計的文件長度限制到 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è)置了一個文件長度限制。
    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 失敗,因為它嘗試創(chuàng)建的文件尺寸過大。
    work();

    exit(
0);

}

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

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

編譯時加上 -lm 選項:
[green@colorfulgreen environ]$ gcc limits.c -lm -o limits

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








小默 2010-08-05 09:04 發(fā)表評論
]]>
硬盤安裝 Fedore13 Livehttp://m.shnenglu.com/momoxiao/archive/2010/07/18/120668.html小默小默Sat, 17 Jul 2010 23:20:00 GMThttp://m.shnenglu.com/momoxiao/archive/2010/07/18/120668.htmlhttp://m.shnenglu.com/momoxiao/comments/120668.htmlhttp://m.shnenglu.com/momoxiao/archive/2010/07/18/120668.html#Feedback1http://m.shnenglu.com/momoxiao/comments/commentRss/120668.htmlhttp://m.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

小默 2010-07-18 07:20 發(fā)表評論
]]>
fedora13 mp3 rmvbhttp://m.shnenglu.com/momoxiao/archive/2010/07/18/120665.html小默小默Sat, 17 Jul 2010 20:21:00 GMThttp://m.shnenglu.com/momoxiao/archive/2010/07/18/120665.htmlhttp://m.shnenglu.com/momoxiao/comments/120665.htmlhttp://m.shnenglu.com/momoxiao/archive/2010/07/18/120665.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/120665.htmlhttp://m.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


小默 2010-07-18 04:21 發(fā)表評論
]]>
Grub磁盤分區(qū)表示方法http://m.shnenglu.com/momoxiao/archive/2010/07/18/120660.html小默小默Sat, 17 Jul 2010 18:20:00 GMThttp://m.shnenglu.com/momoxiao/archive/2010/07/18/120660.htmlhttp://m.shnenglu.com/momoxiao/comments/120660.htmlhttp://m.shnenglu.com/momoxiao/archive/2010/07/18/120660.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/120660.htmlhttp://m.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中,硬盤會被識別為hd#,#是從0開始的硬盤編號,而軟盤被類似地識別為fd#。
  • Grub的硬盤編號和分區(qū)編號都是從0開始的,這一點(diǎn)linux不同。

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

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

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

root (hd0,

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

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

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

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


小默 2010-07-18 02:20 發(fā)表評論
]]>
volume group "volgroup00" not foundhttp://m.shnenglu.com/momoxiao/archive/2010/06/26/118758.html小默小默Sat, 26 Jun 2010 02:49:00 GMThttp://m.shnenglu.com/momoxiao/archive/2010/06/26/118758.htmlhttp://m.shnenglu.com/momoxiao/comments/118758.htmlhttp://m.shnenglu.com/momoxiao/archive/2010/06/26/118758.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/118758.htmlhttp://m.shnenglu.com/momoxiao/services/trackbacks/118758.htmlhttp://www.csource.org/bbs/thread-1140084-1-1.html 
by SharkBones

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

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

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

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

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


小默 2010-06-26 10:49 發(fā)表評論
]]>
【轉(zhuǎn)】proc文件系統(tǒng)分析(四)http://m.shnenglu.com/momoxiao/archive/2010/06/23/118521.html小默小默Tue, 22 Jun 2010 22:10:00 GMThttp://m.shnenglu.com/momoxiao/archive/2010/06/23/118521.htmlhttp://m.shnenglu.com/momoxiao/comments/118521.htmlhttp://m.shnenglu.com/momoxiao/archive/2010/06/23/118521.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/118521.htmlhttp://m.shnenglu.com/momoxiao/services/trackbacks/118521.html(六) 對proc文件默認(rèn)操作的分析 
現(xiàn)在,我們已經(jīng)基本清楚了proc文件系統(tǒng)對自己proc_dir_entry結(jié)構(gòu)的管理了。下面我們回過頭來,再看一下在文件注冊函數(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ù)注冊的proc文件類型的不同,為proc_dir_entry結(jié)構(gòu)設(shè)置了不同的操作函數(shù)集。也就是說,我們使用封裝的create_proc_entry函數(shù)在proc文件系統(tǒng)中注冊文件時,可以不用去管這些操作函數(shù)集,因為該結(jié)構(gòu)總是自動地設(shè)置了相應(yīng)的proc_iops和proc_fops操作函數(shù)。下面我們就對這些默認(rèn)的操作進(jìn)行一個分析,因為這對我們了解proc文件系統(tǒng)和VFS的結(jié)構(gòu)非常重要。 
1 對普通文件的操作 
我們首先看一下普通proc文件的函數(shù)集,根據(jù)代碼段: 
if (S_ISREG(dp->mode)) { 
if (dp->proc_fops == NULL) 
dp->proc_fops = &proc_file_operations; 
} 
我們可以看到,對于普通的proc文件,只設(shè)置了文件操作,即proc_file_operations,從這一點(diǎn)上可以看出,對于普通的proc文件,只缺省提供了文件操作,因此,在必要的時候,我們必須手工設(shè)置需要的索引節(jié)點(diǎn)操作函數(shù)集,比如inode_operations中的權(quán)限檢查函數(shù)permission等等。 
對于proc_file_operations,我們可以看到,只實(shí)現(xiàn)了三個函數(shù): 
static struct file_operations proc_file_operations = { 
llseek: proc_file_lseek, 
read: proc_file_read, 
write: proc_file_write, 
}; 
下面我們簡單的看一下它們實(shí)現(xiàn)的功能: 
(1)llseek: proc_file_lseek 
這個函數(shù),用來實(shí)現(xiàn)lseek系統(tǒng)調(diào)用,其功能是設(shè)置file結(jié)構(gòu)的->f_pos域,因此,根據(jù)第三個參數(shù)orig的不同,將f_pos設(shè)置為相應(yīng)的值,該函數(shù)非常簡單,因此不作過多的介紹。 
(2)read: proc_file_read 
這個函數(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)用。在這個函數(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ù),因此,如果我們要注冊自己的proc文件,在不設(shè)置自己的proc_fops操作函數(shù)集的時候,必須實(shí)現(xiàn)上面兩個函數(shù)中的一個,否則,這個缺省的proc_file_read函數(shù)將做不了任何工作。示意圖如下: 
在這個函數(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)非常簡單: 
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); 
} 
我們看到,它只是簡單地檢測了->write_proc函數(shù)是否存在,如果我們在proc_dir_entry結(jié)構(gòu)中實(shí)現(xiàn)了這個函數(shù),那么就調(diào)用它,否則,就退出。 
根據(jù)上面的討論,我們看到,對于普通文件的操作函數(shù),proc文件系統(tǒng)為我們提供了一個簡單的封裝,因此,我們只要在proc_dir_entry中實(shí)現(xiàn)相關(guān)的讀寫操作即可。 
但是,如果我們想提供讀寫操作之外的函數(shù),那么我們就可以定義自己的file_operations函數(shù)集,并且在proc文件注冊后,將它鏈接到proc_dir_entry的proc_fops上,這樣,就可以使用自己的函數(shù)集了。 
2 對鏈接文件的操作 
根據(jù)代碼段: 
else if (S_ISLNK(dp->mode)) { 
if (dp->proc_iops == NULL) 
dp->proc_iops = &proc_link_inode_operations; 
我們可以看出,對于鏈接文件,proc文件系統(tǒng)為它設(shè)置了索引節(jié)點(diǎn)操作proc_iops。因為我們知道,一個符號鏈接,只擁有inode結(jié)構(gòu),而沒有文件結(jié)構(gòu),所以,為它提供proc_link_inode_operations函數(shù)集就可以了。 
下面我們看一下,這個函數(shù)集的內(nèi)容: 
static struct inode_operations proc_link_inode_operations = { 
readlink: proc_readlink, 
follow_link: proc_follow_link, 
}; 
這個函數(shù)集實(shí)現(xiàn)了和鏈接相關(guān)的兩個函數(shù),我們分別來看一下: 
(1)readlink: proc_readlink 
該函數(shù)用來實(shí)現(xiàn)readlink系統(tǒng)調(diào)用,它的功能是獲得目標(biāo)文件的文件名,我們在前面看到,對于一個鏈接文件,在注冊時已經(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); 
} 
我們看到,這個函數(shù)使用一個指針指向->data,然后,使用VFS函數(shù)vfs_readlink將數(shù)據(jù)返回到用戶空間,非常的簡單。 
(2)follow_link: proc_follow_link 
這個函數(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)其功能,對于vfs_follow_link,可以參考fs/namei.c文件。其結(jié)構(gòu)如下圖所示: 
3 對目錄文件的操作 
最后我們看一下proc文件系統(tǒng)對目錄文件的操作函數(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)中注冊目錄文件的時候,它會檢查是否該proc_dir_entry結(jié)構(gòu)已經(jīng)注冊了proc_iops函數(shù)集,如果沒有,那么就為proc_fops和proc_iops設(shè)置相應(yīng)的缺省函數(shù)集。下面我們對它們分別進(jìn)行討論: 
1.對目錄的文件操作proc_dir_operations: 
static struct file_operations proc_dir_operations = { 
read: generic_read_dir, 
readdir: proc_readdir, 
}; 
這個函數(shù)集的主要功能,是在由proc_dir_entry結(jié)構(gòu)構(gòu)成的proc文件樹中解析目錄。下面我們對這兩個函數(shù)進(jìn)行一個簡單的分析: 
(1)read: generic_read_dir 
我們知道,對于read系統(tǒng)調(diào)用,當(dāng)其參數(shù)文件句柄指向目錄的時候,將返回EISDIR錯誤。因此,目錄文件的read函數(shù)將完成這個工作。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; 
} 
這個函數(shù)很簡單,只要返回錯誤碼就可以了。 
(2)readdir: proc_readdir 
這個函數(shù)用來實(shí)現(xiàn)readdir系統(tǒng)調(diào)用,它從目錄文件中讀出dirent結(jié)構(gòu)到內(nèi)存中。我們可以參考fs/readdir.c中的filldir()函數(shù)。 
2.對目錄文件索引節(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, 
}; 
我們看到,對于目錄文件的索引節(jié)點(diǎn),只定義了一個函數(shù)lookup。因為我們在前面對VFS進(jìn)行分析的時候知道,以下操作,是只在目錄節(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)過我們對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目錄中對proc文件進(jìn)行改名,刪除,建子目錄等操作的。這也算是proc文件系統(tǒng)的一種保護(hù)策略。 
而在內(nèi)核中,則使用proc_mkdir,proc_mknod等函數(shù),在核心內(nèi)通過代碼來維護(hù)proc文件樹。由此可以看出虛擬文件系統(tǒng)的一些特性。對目錄文件的默認(rèn)操作,可以參見下面的示意圖: 
下面我們就來看一下唯一定義的函數(shù)lookup: proc_lookup,到底實(shí)現(xiàn)了什么功能。 
在進(jìn)行具體分析之前,我們先考慮一個問題,我們知道,proc文件系統(tǒng)維護(hù)了自己的proc_dir_entry結(jié)構(gòu),因此提供了create_proc_entry,remove_proc_entry等等函數(shù),并且為了方便實(shí)現(xiàn)對proc文件的讀寫功能,特意在proc_dir_entry結(jié)構(gòu)中設(shè)置了get_info,read_proc和write_proc函數(shù)指針(我們在前面介紹過,這三個函數(shù)被封裝在proc_file_operations中),并且,提供了自己的inode_operations和file_operations,分別是proc_iops 和proc_fops。也就是說,我們在建立proc文件以及為proc文件建立操作函數(shù)的時候,似乎可以不用考慮VFS的實(shí)現(xiàn),只要建立并注冊該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)是在何時,通過何種方法將自己的proc_dir_entry結(jié)構(gòu)和VFS的inode聯(lián)系在一起的,并且將對inode的inode_operations和file_operations操作定位到自己結(jié)構(gòu)中的proc_iops 和proc_fops上呢?通過我們對lookup: proc_lookup的分析,就會明白這一過程。 
我們先看一下它的代碼: 
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); 
} 
這個函數(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)系,因此,這個函數(shù)首先通過struct inode * dir得到了相應(yīng)目錄文件的proc_dir_entry結(jié)構(gòu),并使用指針de指向它,然后,開始在該結(jié)構(gòu)的孩子中查找指定的dentry。 
判斷是否找到的條件很簡單,就是de->namelen等于 dentry->d_name.len,并且dentry->d_name.name等于de->name,根據(jù)程序流程,如果沒有找到,那么將返回-ENOENT錯誤(使用inode指針作為判斷條件),如果找到該文件,那么就根據(jù)ino = de->low_ino(要注意的是,這時候的de已經(jīng)指向由dentry確定的proc_dir_entry結(jié)構(gòu)了。)調(diào)用函數(shù): 
inode = proc_get_inode(dir->i_sb, ino, de); 
這個proc_get_inode的功能很容易猜到,就是從由超級塊i_sb確定的文件系統(tǒng)中,得到索引節(jié)點(diǎn)號為ino的inode。因此考慮兩種情況,第一種情況,這個索引節(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ù),尤其注意上面所說的第二種情況,因為這正是inode和proc_dir_entry建立聯(lián)系并重定位操作函數(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的引用計數(shù)。 
2.使用VFS的iget(sb, ino)函數(shù),從sb指定的文件系統(tǒng)中得到節(jié)點(diǎn)號為ino的索引節(jié)點(diǎn),并使用指針inode指向它。如果沒有得到,則直接跳到標(biāo)號out_fail,減少de的引用計數(shù)后退出。 
因此我們要了解一下iget,這個函數(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)的引用計數(shù),并將其返回;否則,調(diào)用get_new_inode函數(shù),以便從邏輯文件系統(tǒng)中讀出該索引節(jié)點(diǎn)。 
而get_new_inode函數(shù)也很簡單,它分配一個inode結(jié)構(gòu),并試圖重新查找指定的索引節(jié)點(diǎn),如果還是沒有找到,那么就給新分配的索引節(jié)點(diǎn)加入到哈希鏈表和使用鏈表中,并設(shè)置一些基本信息,如i_ino,i_sb,i_dev等,并且,將其引用計數(shù)i_count初始化為1。然后,調(diào)用超級塊sb的read_inode函數(shù),來作邏輯文件系統(tǒng)自己特定的工作,但對于proc文件系統(tǒng)來說,read_inode函數(shù)基本沒有實(shí)質(zhì)性的功能,可參考前文對該函數(shù)的分析。最后,返回這個新建的索引節(jié)點(diǎn)。 
3.這時,我們已經(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)鏈接起來。因此,我們就可以在其他時刻,利用proc文件索引節(jié)點(diǎn)的->u.generic_ip得到相應(yīng)的proc_dir_entry結(jié)構(gòu)了。 
對于新創(chuàng)建的inode來說,將其->u.generic_ip域指向(void *) de沒什么問題,因為該域還沒有被賦值,但是如果這個inode是從緩存中得到的,那么,說明該域已經(jīng)指向了一個proc_dir_entry結(jié)構(gòu),這樣直接賦值,會不會引起問題呢? 
這有兩種情況,第一種情況,它指向的proc_dir_entry結(jié)構(gòu)沒有發(fā)生過變化,那么,由于索引節(jié)點(diǎn)是由ino確定的,而且在一個文件系統(tǒng)中,確保了索引節(jié)點(diǎn)號ino的唯一性,因此,使用inode->u.generic_ip = (void *) de語句對其重新進(jìn)行賦值,不會發(fā)生任何問題。 
另一種情況是在這之前,程序曾調(diào)用remove_proc_entry要將該proc_dir_entry結(jié)構(gòu)刪除,那么由于它的引用計數(shù)count不等于零,因此,該結(jié)構(gòu)不會被釋放,而只是打上了刪除標(biāo)記。所以這種情況下,該賦值語句也不會引起問題。 
我們知道,當(dāng)inode的i_count變?yōu)?的時候,會調(diào)用sb的proc_delete_inode函數(shù),這個函數(shù)將inode的i_state設(shè)置為I_CLEAR,這可以理解為將該inode刪除了,并調(diào)用de_put,減少并檢查proc_dir_entry的引用計數(shù),如果到零,也將其釋放。因此我們看到,引用計數(shù)的機(jī)制使得VFS的inode結(jié)構(gòu)和proc的proc_dir_entry結(jié)構(gòu)能夠保持同步,也就是說,對于一個存在于緩存中的的inode,必有一個proc_dir_entry結(jié)構(gòu)存在。 
4.這時,我們已經(jīng)得到了inode結(jié)構(gòu),并且將相應(yīng)的proc_dir_entry結(jié)構(gòu)de與inode鏈接在了一起。因此,就可以根據(jù)de的信息,對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ù)集上。這是因為我們可以通過proc_dir_entry結(jié)構(gòu)進(jìn)行方便的設(shè)置和調(diào)整,但最終要將文件提交至VFS進(jìn)行管理。正是在這種思想下,proc文件系統(tǒng)提供提供了一套封裝函數(shù),使得我們可以只對proc_dir_entry結(jié)構(gòu)進(jìn)行操作,而忽略與VFS的inode的聯(lián)系。 
5.最后,成功地返回所要的inode結(jié)構(gòu)。 
(七) 小結(jié) 
至此,已經(jīng)對proc文件系統(tǒng)進(jìn)行了一個粗略的分析,從文件系統(tǒng)的注冊,到proc_dir_entry結(jié)構(gòu)的管理,以及與VFS的聯(lián)系等等。下面我們對proc文件系統(tǒng)的整體結(jié)構(gòu)作一個總結(jié)。 
proc文件系統(tǒng)使用VFS接口,注冊自己的文件類型,并且通過注冊時提供的proc_read_super函數(shù),創(chuàng)建自己的超級塊,然后裝載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博客,如果查看原文請點(diǎn):http://blog.chinaunix.net/u2/74524/showart_1129842.html


小默 2010-06-23 06:10 發(fā)表評論
]]>
『轉(zhuǎn)』文件結(jié)構(gòu)體struct file(Linux 2.6.23內(nèi)核)http://m.shnenglu.com/momoxiao/archive/2010/06/17/118121.html小默小默Thu, 17 Jun 2010 15:14:00 GMThttp://m.shnenglu.com/momoxiao/archive/2010/06/17/118121.htmlhttp://m.shnenglu.com/momoxiao/comments/118121.htmlhttp://m.shnenglu.com/momoxiao/archive/2010/06/17/118121.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/118121.htmlhttp://m.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)體代表一個打開的文件,系統(tǒng)中的每個打開的文件在內(nèi)核空間都有一個關(guān)聯(lián)的struct file。它由內(nèi)核在打開文件時創(chuàng)建,并傳遞給在文件上進(jìn)行操作的任何函數(shù)。在文件的所有實(shí)例都關(guān)閉后,內(nèi)核釋放這個數(shù)據(jù)結(jié)構(gòu)。在內(nèi)核創(chuàng)建和驅(qū)動源碼中,struct file的指針通常被命名為file或filp。一下是對結(jié)構(gòu)中的每個數(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;
};
用于通用文件對象鏈表的指針。
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的兩個數(shù)據(jù)成員作為struct file的數(shù)據(jù)成員,
struct vfsmount *mnt的作用是指出該文件的已安裝的文件系統(tǒng),
struct dentry *dentry是與文件相關(guān)的目錄項對象。
三、
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)打開一個文件時,內(nèi)核就創(chuàng)建一個與該文件相關(guān)聯(lián)的struct file結(jié)構(gòu),其中的*f_op就指向的是
具體對該文件進(jìn)行操作的函數(shù)。例如用戶調(diào)用系統(tǒng)調(diào)用read來讀取該文件的內(nèi)容時,那么系統(tǒng)調(diào)用read最終會陷入內(nèi)核調(diào)用sys_read函數(shù),而sys_read最終會調(diào)用于該文件關(guān)聯(lián)的struct file結(jié)構(gòu)中的f_op->read函數(shù)對文件內(nèi)容進(jìn)行讀取。
四、
atomic_t                f_count;
atomic_t被定義為:
typedef struct { volatile int counter; } atomic_t;
volatile修飾字段告訴gcc不要對該類型的數(shù)據(jù)做優(yōu)化處理,對它的訪問都是對內(nèi)存的訪問,而不是對寄存器的訪問。 
本質(zhì)是int類型,之所以這樣寫是讓編譯器對基于該類型變量的操作進(jìn)行嚴(yán)格的類型檢查。此處f_count的作用是記錄對文件對象的引用計數(shù),也即當(dāng)前有多少個進(jìn)程在使用該文件。
五、
unsigned int            f_flags;
當(dāng)打開文件時指定的標(biāo)志,對應(yīng)系統(tǒng)調(diào)用open的int flags參數(shù)。驅(qū)動程序為了支持非阻塞型操作需要檢查這個標(biāo)志。
六、
mode_t                  f_mode;
對文件的讀寫模式,對應(yīng)系統(tǒng)調(diào)用open的mod_t mode參數(shù)。如果驅(qū)動程序需要這個值,可以直接讀取這個字段。
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)的作用是通過信號進(jìn)行I/O時間通知的數(shù)據(jù)。
九、
unsigned int            f_uid, f_gid;
標(biāo)識文件的所有者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)打開一個文件時,f_ra中出了perv_page(默認(rèn)為-1)和ra_apges(對該文件允許的最大預(yù)讀量)這兩個字段外,其他的所有西端都置為0。
十一、
unsigned long           f_version;
記錄文件的版本號,每次使用后都自動遞增。
十二、
#ifdef CONFIG_SECURITY
        void                    *f_security;
#endif
此處我的理解是如果在編譯內(nèi)核時配置了安全措施,那么struct file結(jié)構(gòu)中就會有void *f_security數(shù)據(jù)項,用來描述安全措施或者是記錄與安全有關(guān)的信息。
十三、
void *private_data;
系統(tǒng)在調(diào)用驅(qū)動程序的open方法前將這個指針置為NULL。驅(qū)動程序可以將這個字段用于任意目的,也可以忽略這個字段。驅(qū)動程序可以用這個字段指向已分配的數(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來鏈接所有鉤到這個文件上。其中f_ep_links是文件的事件輪詢等待者鏈表的頭,f_ep_lock是保護(hù)f_ep_links鏈表的自旋鎖。
十五、struct address_space    *f_mapping;
struct address_space被定義在/linux/include/linux/fs.h中,此處是指向文件地址空間的指針。
  在驅(qū)動開發(fā)中,文件讀/寫模式mode、標(biāo)志f_flags都是設(shè)備驅(qū)動關(guān)心的內(nèi)容,而私有數(shù)據(jù)指針private_data在折本驅(qū)動中被廣泛使用,大多被指向設(shè)備驅(qū)動自定義用于描述設(shè)備的結(jié)構(gòu)體。 
驅(qū)動程序中常用如下類似的代碼來檢測用戶打開文件的讀寫方式:
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ū)動開發(fā)詳解
深入理解linux內(nèi)核

小默 2010-06-17 23:14 發(fā)表評論
]]>
warning: Clock skew detected. Your build may be incomplete.http://m.shnenglu.com/momoxiao/archive/2010/06/15/117967.html小默小默Tue, 15 Jun 2010 07:33:00 GMThttp://m.shnenglu.com/momoxiao/archive/2010/06/15/117967.htmlhttp://m.shnenglu.com/momoxiao/comments/117967.htmlhttp://m.shnenglu.com/momoxiao/archive/2010/06/15/117967.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/117967.htmlhttp://m.shnenglu.com/momoxiao/services/trackbacks/117967.html怎么檢測的? //TODO

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



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

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

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

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



小默 2010-06-06 07:53 發(fā)表評論
]]>
ps lkmhttp://m.shnenglu.com/momoxiao/archive/2010/06/01/116924.html小默小默Tue, 01 Jun 2010 12:23:00 GMThttp://m.shnenglu.com/momoxiao/archive/2010/06/01/116924.htmlhttp://m.shnenglu.com/momoxiao/comments/116924.htmlhttp://m.shnenglu.com/momoxiao/archive/2010/06/01/116924.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/116924.htmlhttp://m.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 個進(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




小默 2010-06-01 20:23 發(fā)表評論
]]>
paramhttp://m.shnenglu.com/momoxiao/archive/2010/06/01/116923.html小默小默Tue, 01 Jun 2010 12:21:00 GMThttp://m.shnenglu.com/momoxiao/archive/2010/06/01/116923.htmlhttp://m.shnenglu.com/momoxiao/comments/116923.htmlhttp://m.shnenglu.com/momoxiao/archive/2010/06/01/116923.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/116923.htmlhttp://m.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)核注冊模塊所提供的新功能
//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*




小默 2010-06-01 20:21 發(fā)表評論
]]>
mallochttp://m.shnenglu.com/momoxiao/archive/2010/06/01/116922.html小默小默Tue, 01 Jun 2010 12:20:00 GMThttp://m.shnenglu.com/momoxiao/archive/2010/06/01/116922.htmlhttp://m.shnenglu.com/momoxiao/comments/116922.htmlhttp://m.shnenglu.com/momoxiao/archive/2010/06/01/116922.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/116922.htmlhttp://m.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)存申請都檢查申請是否成功
//下面這段僅僅作為演示的代碼沒有檢查
//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




小默 2010-06-01 20:20 發(fā)表評論
]]>
free pageshttp://m.shnenglu.com/momoxiao/archive/2010/06/01/116921.html小默小默Tue, 01 Jun 2010 12:18:00 GMThttp://m.shnenglu.com/momoxiao/archive/2010/06/01/116921.htmlhttp://m.shnenglu.com/momoxiao/comments/116921.htmlhttp://m.shnenglu.com/momoxiao/archive/2010/06/01/116921.html#Feedback0http://m.shnenglu.com/momoxiao/comments/commentRss/116921.htmlhttp://m.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




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

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


小默 2010-05-26 09:35 發(fā)表評論
]]>
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            免费在线看成人av| 欧美亚洲尤物久久| 欧美在线日韩在线| 欧美亚洲综合另类| 久久激情中文| 久久久久这里只有精品| 久久久久在线| 亚洲高清二区| 美女主播一区| 亚洲三级影院| 亚洲一区图片| 老牛影视一区二区三区| 欧美高清在线视频| 欧美日韩在线视频观看| 国产女同一区二区| 亚洲国产一区二区在线| 9i看片成人免费高清| 亚洲欧美日韩高清| 久久久久久久综合色一本| 欧美激情网友自拍| 亚洲天堂免费在线观看视频| 亚洲在线一区二区| 亚洲人成人一区二区三区| 亚洲免费在线视频| 久久成人综合网| 欧美成人一区二区| 一区二区欧美激情| 久久久久在线观看| 国产精品久久久久久久久久久久久久 | 最近看过的日韩成人| 日韩手机在线导航| 久久久久久日产精品| 国产精品九九| 亚洲高清在线精品| 欧美在线观看天堂一区二区三区| 欧美成人69av| 性8sex亚洲区入口| 欧美日韩精品一区二区在线播放| 国产亚洲人成a一在线v站| 亚洲视频免费在线| 亚洲国产精品福利| 久久精品在线| 国产精品亚洲美女av网站| 亚洲国产天堂久久国产91| 久久激情视频久久| 亚洲一区二区免费看| 欧美日韩123| 亚洲乱码久久| 亚洲第一视频| 可以看av的网站久久看| 国产亚洲一区二区三区在线播放 | 国产精品丝袜91| 在线午夜精品自拍| 亚洲国产视频a| 免费av成人在线| 亚洲国产高清aⅴ视频| 久久久久久69| 亚洲图片在线观看| 国产精品久久久久9999| 在线视频欧美一区| 一本久道久久久| 欧美日韩无遮挡| 一本久久综合亚洲鲁鲁五月天| 亚洲高清成人| 欧美国产1区2区| 日韩一区二区福利| 99国产精品国产精品毛片| 欧美日韩国产黄| 亚洲网站视频| 亚洲午夜久久久久久久久电影院 | 久久久99久久精品女同性| 亚洲天堂偷拍| 国产欧美视频在线观看| 久久se精品一区精品二区| 欧美亚洲在线视频| 欧美成ee人免费视频| 欧美综合77777色婷婷| 欧美一区二区三区四区在线观看地址| 中国成人亚色综合网站| 久久成人精品无人区| 亚洲视频在线观看| 国产精品一区二区三区观看| 欧美一级视频免费在线观看| 欧美亚洲免费电影| 国外精品视频| 欧美激情亚洲国产| 欧美三级网址| 久久精品中文| 欧美成人精品在线| 午夜精品国产精品大乳美女| 欧美一区二区三区四区在线观看地址| 黑丝一区二区三区| 亚洲日韩视频| 国产日韩欧美在线视频观看| 欧美+亚洲+精品+三区| 久久av老司机精品网站导航| 久久久精品2019中文字幕神马| 亚洲在线一区二区三区| 亚洲第一视频| 日韩亚洲视频| 国产在线精品自拍| 亚洲日本欧美在线| 国产一级久久| 亚洲免费成人| 在线欧美视频| 午夜亚洲一区| 99精品福利视频| 久久九九国产| 欧美一区二区日韩一区二区| 一区二区三区久久久| 国产精品三级久久久久久电影| 麻豆精品视频在线观看| 欧美性猛交xxxx乱大交退制版 | 国产日产精品一区二区三区四区的观看方式| 午夜久久久久久久久久一区二区| 一区二区三区 在线观看视频| 亚洲第一区色| 老牛影视一区二区三区| 欧美日韩国产精品一区| 久久精品视频在线看| 欧美天堂亚洲电影院在线播放| 免费欧美电影| 激情视频一区二区| 亚洲午夜高清视频| 91久久久久久| 久久精品亚洲精品| 欧美在线视频免费观看| 欧美视频手机在线| 亚洲国产视频a| 亚洲国产精品一区二区www| 一区二区三区在线观看国产| 久久人人爽人人| 国产麻豆午夜三级精品| 日韩午夜av在线| 久久九九热免费视频| 久久精品国产第一区二区三区最新章节| 欧美久久久久久久| 亚洲乱码视频| 亚洲一区二区视频| 国产精品av久久久久久麻豆网| 亚洲黄色免费电影| 亚洲精品一区二区三区樱花| 麻豆免费精品视频| 亚洲国产导航| 日韩视频在线一区二区三区| 一本久道久久综合中文字幕| 日韩天堂在线观看| 欧美日韩精品一区二区天天拍小说| 91久久久在线| 亚洲一区二区三区涩| 国产精品影片在线观看| 欧美一区=区| 欧美成人一区二区三区在线观看| 亚洲黄色小视频| 欧美国产日韩免费| 夜夜嗨av一区二区三区四季av| 亚洲制服av| 狠狠色综合色区| 欧美成人精品在线视频| 欧美成人精品高清在线播放| 久久人人爽人人爽爽久久| 欧美日韩在线观看一区二区| 国产精品亚洲аv天堂网| 亚洲美女福利视频网站| 久久亚洲精品一区| 性欧美激情精品| 国产精品福利影院| 国产欧美一区二区精品性色 | 亚洲午夜电影| 亚洲精品一区二区在线观看| 午夜在线精品| 亚洲自拍啪啪| 性色av一区二区三区在线观看| 美女脱光内衣内裤视频久久网站| 国产精品另类一区| 欧美日本成人| 国产一区二区电影在线观看| 久久国内精品自在自线400部| 91久久久亚洲精品| 欧美精品免费在线观看| 亚洲欧美在线播放| 一区二区三区毛片| 18成人免费观看视频| 欧美一级在线视频| 亚洲国产日韩欧美在线99| 蜜臀av一级做a爰片久久| 激情综合自拍| 西西裸体人体做爰大胆久久久| 国内精品久久久久久久影视蜜臀| 免费不卡亚洲欧美| 性色av一区二区三区| 亚洲精品乱码久久久久久久久| 欧美一区二区三区的| 亚洲精品一区二区在线观看| 国产综合久久久久久鬼色| 国产精品久久久久久亚洲调教| 欧美成人午夜影院| 久久手机精品视频| 午夜精品视频| 欧美 日韩 国产一区二区在线视频|