亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 操作系統 > 正文

高級I/O之記錄鎖

2024-06-28 13:28:01
字體:
來源:轉載
供稿:網友
高級I/O之記錄鎖

若兩個人同時編輯一個文件,其后果將如何呢?在很多UNIX系統中,該文件的最后狀態取決于寫該文件的最后一個進程。但是對于有些應用程序(例如數據庫),進程有時需要確保它正在單獨寫一個文件。為了向進程提供這種功能,商用UNIX系統提供了記錄鎖機制。

記錄鎖(record locking)的功能是:當一個進程正在讀或修改文件的某個部分時,它可以阻止其他進程修改同一文件區。對于UNIX系統而言,“記錄”這個詞是一種誤用,因為UNIX系統內核根本沒有使用文件記錄這種概念。更適合的術語可能是字節范圍鎖(byte-range locking),因為它鎖定的只是文件中的一個區域(也可能是整個文件)。

1、歷史

對早期UNIX系統的一種批評是它們不能用來運行數據庫系統,其原因是這些系統不支持部分地對文件加鎖。在UNIX系統開始進入商用計算領域時,很多系統開發小組以各種不同方式增加了對記錄鎖的支持。

早期的伯克利版本只支持flock函數。該函數鎖整個文件,不能鎖文件中的一部分。

SVR3通過fcntl函數增加了記錄鎖功能。在此基礎上構造了lockf函數,它提供了一個簡化的接口。這些函數允許調用者鎖一個文件中任意字節數的區域,長至整個文件,短至文件中的一個字節。

POSIX.1標準的基礎是fcntl。

2、fcntl記錄鎖

http://www.CUOXin.com/nufangrensheng/p/3500350.html中已經給出了fcntl函數的原型。

#include <fcntl.h>int fcntl(int filedes, int cmd, ... /* struct flock *flockptr */);返回值:若成功則依賴于cmd,若出錯則返回-1

對于記錄鎖,cmd是F_GETLK、F_SETLK或F_SETLKW。第三個參數(稱其為flockptr)是一個指向flock結構的指針:

struct flock{    short    l_type;       /* F_RDLCK, F_WRLCK, or F_UNLCK */    off_t    l_start;      /* offset in bytes, relative to l_whence */    short    l_whence;     /* SEEK_SET, SEEK_CUR, or SEEK_END */    off_t    l_len;        /* length, in bytes; 0 means lock to EOF */    pid_t    l_pid;        /* returned with F_GETLK */};

對flock結構說明如下:

  • 所希望的鎖類型:F_RDLCK(共享讀鎖)、F_WRLCK(獨占性寫鎖)或F_UNLCK(解鎖一個區域)。
  • 要加鎖或解鎖區域的起始字節偏移量,這由l_start和l_whence兩者決定。
  • 區域的字節長度,由l_len表示。
  • 具有能阻塞當前進程的鎖,其持有進程的ID存放在l_pid中(僅由F_GETLK返回)。

關于加鎖和解鎖區域的說明還要注意下列各點:

  • l_start是相對偏移量(字節),l_whence則決定了相對偏移量的起點。這與lseek函數(http://www.CUOXin.com/nufangrensheng/p/3498080.html)中最后兩個參數類似。確實,l_whence可選用的值是SEEK_SET、SEEK_CUR或SEEK_END。
  • 該區域可以在當前文件尾端處開始或越過其尾端處開始,但是不能在文件起始位置之前開始。
  • 如若l_len為0,則表示鎖的區域從其起點(由l_start和l_whence決定)開始直至最大可能偏移量為止,也就是不管添寫到該文件中多少數據,它們都處于鎖的范圍內(不必猜測會有多少字節被追加到文件之后)。
  • 為了鎖整個文件,我們設置l_start和l_whence,使鎖的起點在文件起始處,并且說明長度(l_len)為0。(有多種方法可以指定文件起始處,但常用的方法是將l_start指定為0,l_whence指定為SEEK_SET。)

上面提到了兩種類型的鎖:共享讀鎖(l_type為F_RDLCK)和獨占寫鎖(F_WRLCK)?;疽巹t是:多個進程在一個給定的字節上可以有一把共享的讀鎖,但是在一個給定字節上只能有一個進程獨用的一把寫鎖。進一步而言,如果在一個給定字節上已經有一把或多把讀鎖,則不能在該字節上再加上寫鎖;如果在一個字節上已經有一把獨占性的寫鎖,則不能再對它加任何讀鎖。在表14-2示出了這些規則。

1364815984_5781

上面說明的兼容性規則適用于不同進程提出的鎖請求,并不適用于單個進程提出的多個鎖請求。如果一個進程對一個文件區間已經有了一把鎖,后來該進程又企圖在同一文件區間再加一把鎖,那么新鎖將替換老鎖。例如,若一進程在某文件的16-32字節區間有一把寫鎖,然后又試圖在16-32字節區間加一把讀鎖,那么該請求將成功執行(假定其他進程此時并不試圖向該文件的同一區間加鎖),原來的寫鎖被替換為讀鎖。

加讀鎖時,該描述符必須是讀打開;加寫鎖時,該描述符必須是寫打開。

以下說明fcntl函數的三種命令:

F_GETLK          判斷由flockptr所描述的鎖是否會被另外一把鎖所排斥(阻塞)。如果存在一把鎖,它阻止創建由flockptr所描述的鎖,則把該現存鎖的信息寫到flockptr指向的結構中。如果不存在這種情況,則除了將l_type設置為F_UNLCK之外,flockptr所指向結構中的其他信息保持不變。

F_SETLK          設置由flockptr所描述的鎖。如果試圖建立一把讀鎖(l_type設為F_RDLCK)或寫鎖(l_type設為F_WRLCK),而按上述兼容性規則不能允許,則fcntl立即出錯返回,此時errno設置為EACCES或EAGAIN。此命令也用來清除由flockptr說明的鎖(l_type為F_UNLCK)。

F_SETLKW       這是F_SETLK的阻塞版本(命令名中的W表示等待(wait))。如果因為當前在所請求區間的某個部分另一進程已經有一把鎖,因而按兼容性規則由flockptr所請求的鎖不能被創建,則使調用進程休眠。如果請求創建的鎖已經可用,或者休眠由信號中斷,則該進程被喚醒。

應當了解,用F_GETLK測試能否建立一把鎖,然后用F_SETLK和F_SETLKW企圖建立一把鎖,這兩者不是一個原子操作。因此不能保證在這兩次fcntl調用之間不會有另一個進程插入并建立一把相關的鎖,從而使原來測試到的情況發生變化。如果不希望在建立鎖時可能產生的長期阻塞,則應使用F_SETLK,并對返回結果進行測試,以判別是否成功地建立了所要求的鎖。

在設置或釋放文件上的鎖時,系統按要求組合或裂開相鄰區。例如,若字節100-199是加鎖的區,需解鎖地150字節,則內核將維持兩把鎖,一把用于字節100-149,另一把用于字節151-199。圖14-1說明了這種情況。

1346927157_4200

                                    圖14-1 文件字節范圍鎖

假定我們又對第150字節設置鎖,那么系統將會把三個相鄰的加鎖區合并成一個區(從字節100至199)。其結果如圖14-1中的第一圖所示,于是我們又回到了出發點。

實例:請求和釋放一把鎖

為了避免每次分配flock結構,然后又填入各項信息,可以用程序清單14-2中的函數lock_reg來處理所有這些細節。

程序清單14-2 加鎖和解鎖一個文件區域的函數

#include "apue.h"#include <fcntl.h>intlock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len){    struct flock    lock;    lock.l_type = type;        /* F_RDLCK, F_WRLCK, F_UNLCK */    lock.l_start = offset;        /* byte offset, relative to l_whence */    lock.l_whence = whence;        /* SEEK_SET, SEEK_CUR, SEEK_END */    lock.l_len = len;        /* #bytes (0 means to EOF) */    return(fcntl(fd, cmd, &lock));}

   因為大多數鎖調用是加鎖或解鎖一個文件區域(命令F_GETLK很少使用),故通常使用下列5個宏,它們都定義在apue.h中。 

#define    read_lock(fd, offset, whence, len) /                lock_reg((fd), F_SETLK, F_RDLCK, (offset), (whence), (len))#define    readw_lock(fd, offset, whence, len) /                lock_reg((fd), F_SETLKW, F_RDLCK, (offset), (whence), (len))#define    write_lock(fd, offset, whence, len) /                lock_reg((fd), F_SETLK, F_WRLCK, (offset), (whence), (len))#define    writew_lock(fd, offset, whence, len) /                lock_reg((fd), F_SETLKW, F_WRLCK, (offset), (whence), (len))#define    un_lock(fd, offset, whence, len) /                lock_reg((fd), F_SETLK, F_UNLCK, (offset), (whence), (len))

實例:測試一把鎖

程序清單14-3中定義了一個函數lock_test,可用其測試一把鎖。

程序清單14-3 測試一個鎖狀態的函數

#include "apue.h"#include <fcntl.h>pid_tlock_test(int fd, int type, off_t offset, int whence, off_t len){    struct flock    lock;    lock.l_type = type;        /* F_RDLCK or F_WRLCK */    lock.l_start = offset;     /* byte offset,  relative to l_whence */    lock.l_whence = whence;    /* SEEK_SET, SEEK_CUR, SEEK_END */    lock.l_len = len;          /* bytes (0 means to EOF) */    if(fcntl(fd, F_GETLK, &lock) < 0)        err_sys("fcntl error");    if(lock.l_type == F_UNLCK)        return(0);         /* false, region isn't locked by another PRoc */    return(lock.l_pid);    /* true, return pid of lock owner */}

如果存在一把鎖,它阻塞由參數說明的鎖請求,則此函數返回持有這把現存鎖的進程ID,否則此函數返回0。通常用下面兩個宏來調用此函數(它們也定義在apue.h中)。

#define    is_read_lockable(fd, offset, whence, len) /              (lock_test((fd), F_RDLCK, (offset), (whence), (len)) == 0)#define    is_write_lockable(fd, offset, whence, len) /              (lock_test((fd), F_WRLCK, (offset), (whence), (len)) == 0)

注意,進程不能使用lock_test函數測試它自己是否在文件的某一部分持有一把鎖。F_GETLK命令的定義說明,返回信息指示是否有現存的鎖阻止調用進程設置它自己的鎖。因為F_SETLK和F_SETLKW命令總是替換調用進程現存的鎖(若已存在),所以調用進程決不會阻塞在自己持有的鎖上;于是,F_GETLK命令決不會報告調用進程自己持有的鎖。

實例:死鎖

如果兩個進程相互等待對方持有并且鎖定的資源時,則這兩個進程就處于死鎖狀態。如果一個進程已經控制了文件中的一個加鎖區域,然后它又試圖對另一個進程控制的區域加鎖,則它就會休眠,在這種情況下,有發生死鎖的可能性。

程序清單14-4給出了一個死鎖的例子。子進程鎖字節0,父進程鎖字節1。然后,它們又都試圖鎖對方已經加鎖的字節。在該程序中使用了http://www.CUOXin.com/nufangrensheng/p/3510306.html中介紹的父、子進程同步例程(TELL_xxx和WAIT_xxx),使得每個進程能夠等待另一個進程獲得它設置的第一把鎖。運行程序清單14-4所示程序得到:

未命名

程序清單14-4 死鎖檢測實例

#include "apue.h"#include <fcntl.h>static voidlockabyte(const char *name, int fd, off_t offset){    if(writew_lock(fd, offset, SEEK_SET, 1) < 0)        err_sys("%s: write_lock error", name);    printf("%s: got the lock, byte %ld/n", name, offset);}int main(void){    int    fd;    pid_t    pid;    /*    * Create a file and write two bytes to it.    */    if((fd = creat("templock", FILE_MODE)) < 0)        err_sys("creat error");    if(write(fd, "ab", 2) != 2)        err_sys("write error");    TELL_WAIT();    if((pid = fork()) < 0)    {        err_sys("fork error");    }    else if(pid == 0)            /* child */    {        lockabyte("child", fd, 0);        TELL_PARENT(getppid());        WAIT_PARENT();        lockabyte("child", fd, 1);    }    else                    /* parent */    {        lockabyte("parent", fd, 1);        TELL_CHILD(pid);        WAIT_CHILD();        lockabyte("parent", fd, 0);    }    exit(0);}

檢測到死鎖時,內核必須選擇一個進程接收出錯返回。在本實例中選擇了子進程,這是一個實現細節。在某些系統上,總是子進程接收到出錯信息;在另一些系統上,總是父進程接到出錯信息。在某些系統上,當試圖使用多把鎖時,有時是子進程接到出錯信息,有時則是父進程接到出錯信息。

3、鎖的隱含繼承和釋放

關于記錄鎖的自動繼承和釋放有三條規則:

(1)鎖與進程和文件兩方面有關。這有兩重含義:第一重很明顯,當一個進程終止時,它所建立的鎖全部釋放;第二重意思就不很明顯,任何時候關閉一個描述符時,則該進程通過這一描述符可以引用的文件上的任何一把鎖都被釋放(這些鎖都是該進程設置的)。這就意味著如果執行下列四步:

fd1 = open(pathname, ...);read_lock(fd1, ...);fd2 = dup(fd1);close(fd2);

則在close(fd2)后,在fd1上設置的鎖被釋放。如果將dup換為open,以打開另一描述符上的同一文件,其效果也一樣:

fd1 = open(pathname, ...);read_lock(fd1, ...);fd2 = open(pathname, ...);close(fd2);

(2)由fork產生的子進程不繼承父進程所設置的鎖。這意味著,若一個進程得到一把鎖,然后調用fork,那么對于父進程獲得的鎖而言,子進程被視為另一個進程,對于從父進程處繼承過來的任一描述符,子進程需要調用fcntl才能獲得它自己的鎖。這與鎖的作用是相一致的。鎖的作用是阻止多個進程同時寫同一文件(或同一文件區域)。如果子進程繼承父進程的鎖,則父、子進程就可以同時寫同一個文件。

(3)在執行exec后,新程序可以繼承原執行程序的鎖。但是注意,如果對一個文件描述符設置了close-on-exec標志,那么當作為exec的一部分關閉該文件描述符時,對相應文件的所有鎖都被釋放了。

4、FreeBSD的實現

先簡要地觀察FreeBSD實現中使用的數據結構。這會幫助我們進一步理解規則1:鎖是與進程、文件兩者相關聯的。

考慮一個進程,它執行下列語句(忽略出錯返回):

fd1 = open(pathname, ...);write_lock(fd1, 0, SEEK_SET, 1);        /* parent write locks byte 0 */if((pid = fork()) > 0)                  /* parent */{    fd2 = dup(fd1);    fd3 = open(pathname, ...);    }else if(pid == 0){    read_lock(fd1, 1, SEEK_SET, 1);    /* child read locks byte 1 */}pause();

圖14-2顯示了父、子進程暫停后的數據結構情況。

1346079230_9409

                                               圖14-2 關于記錄鎖的FreeBSD數據結構

http://www.CUOXin.com/nufangrensheng/p/3498736.html中的圖3-3和http://www.CUOXin.com/nufangrensheng/p/3509492.html中的圖8-1已顯示了open、fork以及dup后的數據結構。有了記錄鎖后,在原來的這些圖上新加了lockf結構,它們由i節點結構開始相互鏈接起來。注意,每個lockf結構說明了一個給定進程的一個加鎖區域(由偏移量和長度定義)。圖中顯示了兩個lockf結構,一個是由父進程調用write_lock形成的,另一個則是由子進程調用read_lock形成的。每一個結構都包含了相應進程ID。

在父進程中,關閉fd1、fd2和fd3中的任意一個都將釋放由父進程設置的寫鎖。在關閉這三個描述符中的任意一個時,內核會從該描述符所關聯的i節點開始,逐個檢查lockf鏈接表中各項,并釋放由調用進程持有的各把鎖。內核并不清楚也不關心父進程是用哪一個描述符來設置這把鎖的。

實例

在程序清單13-2(http://www.CUOXin.com/nufangrensheng/p/3544370.html)中,我們了解到,守護進程可用一把文件鎖以保證只有該守護進程的唯一副本正在運行。程序清單14-5示出了lockfile函數的實現,守護進程可用該函數在文件上加鎖。

程序清單14-5 在文件整體上加鎖

#include <unistd.h>#include <fcntl.h>intlockfile(int fd){    struct flock fl;        fl.l_type = F_WRLCK;    fl.l_start = 0;    fl.l_whence = SEEK_SET;    fl.l_len = 0;    return(fcntl(fd, F_SETLK, &fl));}

另一種方法是,用write_lock函數定義lockfile函數:

#define lockfile(fd)    write_lock((fd), 0, SEEK_SET, 0)

5、在文件尾端加鎖(不是很明白)

在接近文件尾端加鎖或解鎖時需要特別小心。大多數實現按照l_whence的SEEK_CUR或SEEK_END值,用l_start以及文件當前位置或當前長度得到絕對文件偏移量。但是,常常需要相對于文件的當前位置或當前長度指定一把鎖。其原因是,我們在該文件上沒有鎖,所以不能調用lseek以正確無誤地獲得加鎖時的當前文件偏移量。(在lseek和加鎖調用之間,另一個進程可能改變該文件長度。)

考慮以下代碼序列:

writew_lock(fd, 0, SEEK_END, 0);write(fd, buf, 1);un_lock(fd, 0, SEEK_END);write(fd, buf, 1);

該代碼序列所作的可能并不是你所期望的。它得到一把寫鎖,該寫鎖從當前文件尾端起,包括以后可能添加到該文件的任何數據。假定在文件尾端時執行第一個write,它給文件添寫了1個字節,而該字節將被加鎖。跟隨其后的解鎖,其作用是對以后添寫到文件上的數據不再加鎖,但在它之前剛添寫的一個字節則保留加鎖。當執行第二個寫時,文件尾端又延伸了1個字節,但該字節并未加鎖。

當對文件的一部分加鎖時,內核將指定的偏移量變換成絕對文件偏移量。另外,除了指定一個絕對偏移量(SEEK_SET)之外,fcntl還允許我們相對于文件中的某個點(當前偏移量(SEEK_CUR)或文件尾端(SEEK_END))指定該偏移量。當前偏移量和文件尾端是可能不斷變化的,而這種變化又不應影響現存鎖的狀態,所以內核必須獨立于當前文件偏移量或文件尾端而記住鎖。

如果我們想要解除第一次write所寫1個字節上的鎖,那么應指定長度為-1。負的長度值表示在指定偏移量之前的字節數。

6、建議性鎖和強制性鎖(結合http://hi.baidu.com/24688395/item/93381c477d8e82ec1381da3d中的內容來理解)

考慮數據庫訪問例程庫。如果該庫中所有函數都以一致的方法處理記錄鎖,則稱使用這些函數訪問數據庫的任何進程集為合作進程(coOperating process)。如果這些函數是僅有的用來訪問數據庫的函數,那么它們使用建議性鎖是可行的。但是建議性鎖并不能阻止對數據庫文件有寫權限的任何其他進程對數據庫文件進行隨意的寫操作。沒有使用被認可的方法(數據庫函數庫)訪問數據庫的進程是一個非合作進程

強制性鎖使內核對每一個open、read和write系統調用都進行檢查,檢查調用進程對正在訪問的文件是否違背了某一把鎖的作用。強制性鎖有時也被稱為強迫方式鎖(enforcement-mode locking)。

linux2.4.22和Solaris 9提供強制性記錄鎖,而FreeBSD 5.2.1和Mac OS X 10.3則不提供。強制性記錄鎖不是Single UNIX Specification的組成部分。在Linux中,如果用戶想要使用強制性鎖,則要在各個文件系統基礎上,對mount命令用 -o mand 選項打開該機制。

對一個特定文件打開其設置組ID位并關閉其組執行位,則對該文件開啟了強制性鎖機制(回憶http://www.CUOXin.com/nufangrensheng/p/3502457.html中的程序清單4-4)。因為當組執行位關閉時,設置組ID位不再有意義,所以SVR3的設計者借用兩者的這種組合來指定對一個文件的鎖是強制性的而非建議性的。

如果一個進程試圖讀、寫一個強制性鎖起作用的文件,而欲讀、寫的部分又由其他進程加上了讀或寫鎖,此時會發生什么呢?對這一問題的回答取決于三方面的因素:操作類型(read或write),其他進程保有的鎖的類型(讀鎖或寫鎖),以及有關描述符是阻塞還是非阻塞的。表14-3列出了8種可能性。

表14-3 強制性鎖對其他進程讀、寫的影響

其他進程在文件區段中持有的現存鎖的類型 阻塞描述符,試圖 read          write 非阻塞描述符,試圖 read             write
讀鎖 寫鎖 允許           阻塞 阻塞           阻塞 允許             EAGAIN EAGAIN       EAGAIN

除了表14-3中的read和write函數,其他進程持有的強制性鎖也會對open函數產生影響。通常,即使正在打開的文件具有強制性記錄鎖,該打開操作也會成功。后隨的read或write依從于表14-3所示的規則。但是,如果欲打開的文件具有強制性記錄鎖(讀鎖或寫鎖),而且open調用中的flag指定為O_TRUNC或O_CREAT,則不論是否指定O_NONBLOCK,open都立即出錯返回,errno設置為EAGAIN。

實例

程序清單14-6用于確定一個系統是否支持強制性鎖機制

程序清單14-6 確定是否支持強制性鎖

#include "apue.h"#include <errno.h>#include <fcntl.h>#include <sys/wait.h>intmain(int argc, char *argv[]){    int        fd;    pid_t        pid;    char        buf[5];    struct stat    statbuf;    if(argc != 2)    {        fprintf(stderr, "usage: %s filename/n", argv[0]);        exit(1);    }    if((fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, FILE_MODE)) < 0)        err_sys("open error");    if(write(fd, "abcdef", 6) != 6)        err_sys("write error");    /* turn on set-group-ID and turn off group-execute */    if(fstat(fd, &statbuf) < 0)        err_sys("fstat error");    if(fchmod(fd, (statbuf.st_mode & ~S_IXGRP) | S_ISGID) < 0)        err_sys("fchmod error");    TELL_WAIT();    if((pid = fork()) < 0)    {        err_sys("fork error");    }    else if(pid > 0)  /* parent */    {        /* write lock entire file */        if(write_lock(fd, 0, SEEK_SET, 0) < 0)            err_sys("write_lock error");        TELL_CHILD(pid);        if(waitpid(pid, NULL, 0) < 0)            err_sys("waitpid error");    }    else    /* child */    {        WAIT_PARENT();     /* wait for parent to set lock */        set_fl(fd, O_NONBLOCK);    /* set_fl()參見http://www.CUOXin.com/nufangrensheng/p/3500350.html */        /* first let's see what error we get if  region is locked */        if(read_lock(fd, 0, SEEK_SET, 0) != -1)    /* no wait */            err_sys("child: read_lock succeeded");        printf("read_lock of already-locked region returns %d/n", errno);                /* now try to read the mandatory locked file */        if(lseek(fd, 0, SEEK_SET) == -1)            err_sys("lseek error");        if(read(fd, buf, 2) < 0)            err_ret("read failed (mandatory locking works)");        else            printf("read OK (no mandatory locking), buf = %2.2s/n", buf);    }    exit(0);}

此程序首先創建一個文件,并使強制性鎖機制對其起作用。然后程序分裂為父進程和子進程。父進程對整個文件設置一把寫鎖,子進程則將該文件的描述符設置為非阻塞的,然后企圖對該文件設置一把讀鎖,我們期望這會出錯返回,并希望看到系統返回是EACCES或EAGAIN。接著,子進程將文件讀、寫位置調整到文件起點,并試圖讀(read)該文件。如果系統提供強制性鎖機制,則read應返回EACCES或EAGAIN(因為該描述符是非阻塞的),否則read返回所讀的數據。

在RedHat Linux 2.6.18上運行此程序(該系統不支持強制性鎖機制),得到:

未命名 

本篇博文內容摘自《UNIX環境高級編程》(第二版),僅作個人學習記錄所用。關于本書可參考:http://www.apuebook.com/。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美性xxxxxxxxx| 久久亚洲精品一区二区| 亚洲精品自拍视频| 亚洲欧美第一页| 中文字幕欧美亚洲| 欧美香蕉大胸在线视频观看| 亚洲国产精品成人精品| 亚洲欧美三级在线| 欧美影院久久久| 亚洲天堂网在线观看| 欧美在线激情网| 国产精品狠色婷| 亚洲伊人第一页| 亚洲人成网站777色婷婷| 欧美电影院免费观看| 7777免费精品视频| 欧美黑人极品猛少妇色xxxxx| 亚洲欧美国产日韩中文字幕| 91精品国产99| 久久久久久午夜| 欧美一级大片在线免费观看| 一区二区三区天堂av| 久久精品国产2020观看福利| 国产精品最新在线观看| 亚洲国内精品在线| 国产精品久久久久久久久久三级| 久久精品国产免费观看| 日韩在线播放一区| 日韩av电影免费观看高清| 国产精品爱啪在线线免费观看| 亚洲欧美精品伊人久久| 午夜精品久久久久久久久久久久久| 欧美性一区二区三区| 国产日韩精品一区二区| 国产mv免费观看入口亚洲| 亚洲黄色在线观看| 国产精品久久久久秋霞鲁丝| 国产一区二区免费| 6080yy精品一区二区三区| 欧美在线免费观看| 欧美激情一级二级| www.久久草.com| 欧美日韩亚洲国产一区| 中文字幕av一区二区三区谷原希美| 亚洲国产成人精品女人久久久| 亚洲国产精品电影在线观看| 亚洲第一福利网| 青青精品视频播放| 欧美午夜xxx| 久久九九有精品国产23| 亚洲成年人影院在线| 日韩精品中文字幕在线观看| 国产精品一区二区女厕厕| 色悠悠久久88| 日韩高清av在线| 欧美日韩高清区| 亚洲欧美综合v| 亚洲偷熟乱区亚洲香蕉av| 国产精品99久久久久久www| 91精品国产91久久久久久最新| 亚洲国产日韩欧美在线图片| 一本色道久久88综合亚洲精品ⅰ| 国产欧美精品一区二区三区-老狼| 中文字幕日韩综合av| 欧美黑人狂野猛交老妇| 欧美激情videos| 久久久久久久久久av| 51ⅴ精品国产91久久久久久| 最近日韩中文字幕中文| 韩国19禁主播vip福利视频| 国产精品国产自产拍高清av水多| 国产精品日韩在线一区| 亚洲精品久久久久久久久久久久| 色www亚洲国产张柏芝| 精品亚洲国产成av人片传媒| 欧美电影免费观看高清完整| 午夜精品一区二区三区在线| 久久五月情影视| 亚洲第一区在线| 亚洲伊人一本大道中文字幕| 91久久嫩草影院一区二区| 精品亚洲aⅴ在线观看| 色无极亚洲影院| 久久久久久久激情视频| 国产精品国产亚洲伊人久久| 亚洲mm色国产网站| 亚洲精美色品网站| 亚洲欧美精品伊人久久| 亚洲成人激情在线| 国产精品18久久久久久麻辣| 91精品国产91久久久久久吃药| 欧美在线视频导航| 国内伊人久久久久久网站视频| 激情亚洲一区二区三区四区| 欧美性猛交xxxx偷拍洗澡| 亚洲欧美国产精品久久久久久久| 欧美电影免费观看高清完整| 精品久久久久久久久中文字幕| 北条麻妃一区二区在线观看| 91色视频在线观看| 亚洲精品一区二区三区婷婷月| 亚洲国产一区自拍| 国产一区欧美二区三区| 国产美女精品视频免费观看| 日韩av中文字幕在线播放| 黑人与娇小精品av专区| 亚洲欧美色图片| 久久久久久国产三级电影| 精品无人区太爽高潮在线播放| 亚洲天堂第一页| 美日韩精品免费观看视频| 亚洲自拍偷拍福利| 亚洲人成电影网站色www| 国产精品久久久久久一区二区| 色综合久久中文字幕综合网小说| 欧美一区深夜视频| 日本高清+成人网在线观看| 日韩一二三在线视频播| 在线精品高清中文字幕| 91在线精品播放| 国产成人精品久久二区二区| 久久久99免费视频| 91欧美精品成人综合在线观看| 亚洲天堂2020| 欧美精品在线免费观看| 最新国产精品亚洲| 亚洲国产欧美一区二区三区久久| 久久久久北条麻妃免费看| 久久不射热爱视频精品| 亚洲激情在线观看| 亚洲国产成人精品电影| 欧美激情va永久在线播放| 亚洲国产福利在线| 欧美巨大黑人极品精男| 78m国产成人精品视频| 欧美日韩激情网| 91久久精品一区| 欧美性猛交xxxx乱大交| 久久中文字幕视频| 亚洲毛片在线看| 国产日韩在线一区| 日韩精品中文字幕久久臀| 亚洲成av人乱码色午夜| 国产精品99蜜臀久久不卡二区| 国产综合在线视频| 日韩亚洲在线观看| 久久久久久97| 欧美怡春院一区二区三区| 91亚洲精品久久久久久久久久久久| 久久久成人精品| 欧美性xxxxx| 国产美女精品视频免费观看| 色综合伊人色综合网站| 欧美电影在线观看完整版| 91九色视频导航| 日韩美女免费线视频| 亚洲国产精品久久| 激情成人在线视频| 久久久久久久av| 国产精品高潮在线| 成人免费视频网址| 中文字幕亚洲欧美一区二区三区| www欧美日韩| 亚洲天堂影视av|