欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

GlusterFS之內存池(mem-pool)實現原理及代碼

系統 2029 0

我的新浪微博: http://weibo.com/freshairbrucewoo

歡迎大家相互交流,共同提高技術。

最近一直在研究glusterfs的源代碼,自己也在上面做了一些小的改動。我最開始研究的是3.2.5這個版本,因為據同行和網上資料顯示這個版本目前是最穩定的版本。glusterfs實現比較復雜,具體的設計思想和架構就不詳細介紹了,網上有這方面的資料(CSDN博客里面就有很好介紹的文章)。

? ? ? ? 研究開源系統的一個好處就是可以充分了解它的實現,如果是看這方面的論文只能了解一些原理性的東西,但是我們真正做項目還需要實際的實現。很多開源系統可能本身不一定就很適合你的系統,但是如果可以改造那么利用它來改造也是很值得劃算的。研究開源系統最大的好處就是學習它的優秀的代碼,今天這篇博文就是要分享glusterfs里面使用的內存池技術。

? ? ? ? glusterfs實現內存池技術的源文件和頭文件分別是mem-pool.c和mem-pool.h,首先看看頭文件中內存池對象結構體的定義如下:

      
         1
      
      
        struct
      
      
         mem_pool {  


      
      
         2
      
      
        struct
      
       list_head  list;
      
        //
      
      
        用于管理內存池的標準雙向鏈表  
      
      
         3
      
      
        int
      
                     hot_count;
      
        //
      
      
        正在使用的內存數量計數  
      
      
         4
      
      
        int
      
                     cold_count;
      
        //
      
      
        未使用的內存數量計數  
      
      
         5
      
               gf_lock_t         
      
        lock
      
      
        ;  


      
      
         6
      
               unsigned 
      
        long
      
           padded_sizeof_type;
      
        //
      
      
        帶有填充  
      
      
         7
      
      
        void
      
                   *pool;
      
        //
      
      
        內存池開始地址  
      
      
         8
      
      
        void
      
                   *pool_end;
      
        //
      
      
        內存池結束地址  
      
      
         9
      
      
        int
      
                     real_sizeof_type;
      
        //
      
      
        內存池存放對象的真實大小  
      
      
        10
      
               uint64_t          alloc_count;
      
        //
      
      
        采用alloc分配的次數  
      
      
        11
      
               uint64_t          pool_misses;
      
        //
      
      
        內出池缺少次數  
      
      
        12
      
      
        int
      
                     max_alloc;
      
        //
      
      
        采用alloc分配的最大次數  
      
      
        13
      
      
        int
      
      
                       curr_stdalloc;  


      
      
        14
      
      
        int
      
      
                       max_stdalloc;  


      
      
        15
      
      
        char
      
                   *
      
        name;  


      
      
        16
      
      
        struct
      
       list_head  global_list;
      
        //
      
      
        加入到全局的內存池鏈表  
      
      
        17
      
       };  
    

?


然后我們在來分析幾個重要的實現函數,第一個函數就是mem_pool_new_fn,它會新建一個內存池對象,然后按照傳遞進來的內存的大小和個數分配內存,還要加上一些額外存儲內容的內存容量,如存放鏈表指針的因為這些內存池對象本身是通過通用鏈表來管理的,還有如標識內存是否在被使用的一個標志等。具體看下面代碼的實現,關鍵代碼都有注釋:

?

      
         1
      
      
        struct
      
       mem_pool *  


      
         2
      
       mem_pool_new_fn (unsigned 
      
        long
      
      
         sizeof_type,  


      
      
         3
      
                        unsigned 
      
        long
      
       count, 
      
        char
      
       *
      
        name)  


      
      
         4
      
      
        {  


      
      
         5
      
      
        struct
      
       mem_pool  *mem_pool =
      
         NULL;  


      
      
         6
      
               unsigned 
      
        long
      
           padded_sizeof_type = 
      
        0
      
      
        ;  


      
      
         7
      
      
        void
      
                   *pool =
      
         NULL;  


      
      
         8
      
      
        int
      
                     i = 
      
        0
      
      
        ;  


      
      
         9
      
      
        int
      
                     ret = 
      
        0
      
      
        ;  


      
      
        10
      
      
        struct
      
       list_head *list =
      
         NULL;  


      
      
        11
      
               jdfs_ctx_t  *ctx =
      
         NULL;  


      
      
        12
      
      
        13
      
      
        if
      
       (!sizeof_type || !
      
        count) {  


      
      
        14
      
                       gf_log_callingfn (
      
        "
      
      
        mem-pool
      
      
        "
      
      , GF_LOG_ERROR, 
      
        "
      
      
        invalid argument
      
      
        "
      
      
        );  


      
      
        15
      
      
        return
      
      
         NULL;  


      
      
        16
      
      
                }  


      
      
        17
      
               padded_sizeof_type = sizeof_type + GF_MEM_POOL_PAD_BOUNDARY;
      
        //
      
      
        計算大小:對象本身所占內存+鏈表頭+內存池指針+int內存大小(存放in_use變量)  
      
      
        18
      
      
        19
      
               mem_pool = GF_CALLOC (
      
        sizeof
      
       (*mem_pool), 
      
        1
      
      
        , gf_common_mt_mem_pool);  


      
      
        20
      
      
        if
      
       (!
      
        mem_pool)  


      
      
        21
      
      
        return
      
      
         NULL;  


      
      
        22
      
      
        23
      
               ret = gf_asprintf (&mem_pool->name, 
      
        "
      
      
        %s:%s
      
      
        "
      
      , THIS->name, name);
      
        //
      
      
        哪一個xlator分配什么名字內存  
      
      
        24
      
      
        if
      
       (ret < 
      
        0
      
      
        )  


      
      
        25
      
      
        return
      
      
         NULL;  


      
      
        26
      
      
        27
      
      
        if
      
       (!mem_pool->
      
        name) {  


      
      
        28
      
      
                        GF_FREE (mem_pool);  


      
      
        29
      
      
        return
      
      
         NULL;  


      
      
        30
      
      
                }  


      
      
        31
      
      
        32
      
               LOCK_INIT (&mem_pool->
      
        lock
      
      
        );  


      
      
        33
      
               INIT_LIST_HEAD (&mem_pool->
      
        list);  


      
      
        34
      
               INIT_LIST_HEAD (&mem_pool->
      
        global_list);  


      
      
        35
      
      
        36
      
               mem_pool->padded_sizeof_type = padded_sizeof_type;
      
        //
      
      
        總的對齊內存大小  
      
      
        37
      
               mem_pool->cold_count = count;
      
        //
      
      
        數量:剛開始都是冷的(未使用的)  
      
      
        38
      
               mem_pool->real_sizeof_type = sizeof_type;
      
        //
      
      
        使用內存池對象的真實內存大小  
      
      
        39
      
      
        40
      
               pool = GF_CALLOC (count, padded_sizeof_type, gf_common_mt_long);
      
        //
      
      
        分配count個padded_sizeof_type大小的內存  
      
      
        41
      
      
        if
      
       (!
      
        pool) {  


      
      
        42
      
                       GF_FREE (mem_pool->
      
        name);  


      
      
        43
      
      
                        GF_FREE (mem_pool);  


      
      
        44
      
      
        return
      
      
         NULL;  


      
      
        45
      
      
                }  


      
      
        46
      
      
        47
      
      
        for
      
       (i = 
      
        0
      
      ; i < count; i++
      
        ) {  


      
      
        48
      
                       list = pool + (i * (padded_sizeof_type));
      
        //
      
      
        分配每一個內存對象大小到鏈表  
      
      
        49
      
      
                        INIT_LIST_HEAD (list);  


      
      
        50
      
                       list_add_tail (list, &mem_pool->list);
      
        //
      
      
        加入到內存池的鏈表中去  
      
      
        51
      
      
                }  


      
      
        52
      
      
        53
      
               mem_pool->pool = pool;
      
        //
      
      
        記錄分配的內存區域  
      
      
        54
      
               mem_pool->pool_end = pool + (count * (padded_sizeof_type));
      
        //
      
      
        內存分配結束的地址  
      
      
        55
      
      
        56
      
      
        /*
      
      
         add this pool to the global list 
      
      
        */
      
      
        57
      
               ctx =
      
         jdfs_ctx_get ();  


      
      
        58
      
      
        if
      
       (!
      
        ctx)  


      
      
        59
      
      
        goto
      
      
        out
      
      
        ;  


      
      
        60
      
      
        61
      
               list_add (&mem_pool->global_list, &ctx->mempool_list);
      
        //
      
      
        加入全局的內存池鏈表  
      
      
        62
      
      
        63
      
      
        out
      
      
        :  


      
      
        64
      
      
        return
      
      
         mem_pool;  


      
      
        65
      
       }  
    

?

?

如果我們需要使用這種內存池中的內存,那么就從內存池中拿出一個對象(不同對象需要不同的內存池對象保存,每一個內存池對象只保存一種對象的內存結構)的內存,代碼實現和注釋如下:

?

      
         1
      
      
        void
      
       *  


      
         2
      
       mem_get (
      
        struct
      
       mem_pool *
      
        mem_pool)  


      
      
         3
      
      
        {  


      
      
         4
      
      
        struct
      
       list_head *list =
      
         NULL;  


      
      
         5
      
      
        void
      
                   *ptr =
      
         NULL;  


      
      
         6
      
      
        int
      
                   *in_use =
      
         NULL;  


      
      
         7
      
      
        struct
      
       mem_pool **pool_ptr =
      
         NULL;  


      
      
         8
      
      
         9
      
      
        if
      
       (!
      
        mem_pool) {  


      
      
        10
      
                       gf_log_callingfn (
      
        "
      
      
        mem-pool
      
      
        "
      
      , GF_LOG_ERROR, 
      
        "
      
      
        invalid argument
      
      
        "
      
      
        );  


      
      
        11
      
      
        return
      
      
         NULL;  


      
      
        12
      
      
                }  


      
      
        13
      
      
        14
      
               LOCK (&mem_pool->
      
        lock
      
      
        );  


      
      
        15
      
      
                {  


      
      
        16
      
                       mem_pool->alloc_count++
      
        ;  


      
      
        17
      
      
        if
      
       (mem_pool->cold_count) {
      
        //
      
      
        內存池中是否還有未使用的內存對象  
      
      
        18
      
                               list = mem_pool->list.next;
      
        //
      
      
        取出一個  
      
      
        19
      
                               list_del (list);
      
        //
      
      
        從鏈表中脫鏈  
      
      
        20
      
      
        21
      
                               mem_pool->hot_count++
      
        ;  


      
      
        22
      
                               mem_pool->cold_count--
      
        ;  


      
      
        23
      
      
        24
      
      
        if
      
       (mem_pool->max_alloc < mem_pool->hot_count)
      
        //
      
      
        最大以分配的內存是否小于正在使用的內存數量  
      
      
        25
      
                                       mem_pool->max_alloc = mem_pool->
      
        hot_count;  


      
      
        26
      
      
        27
      
                               ptr =
      
         list;  


      
      
        28
      
                               in_use = (ptr + GF_MEM_POOL_LIST_BOUNDARY +  


      
        29
      
                                         GF_MEM_POOL_PTR);
      
        //
      
      
        分配內存池對象的時候分配了這個區域來保存次塊內存是否在使用  
      
      
        30
      
                               *in_use = 
      
        1
      
      ;
      
        //
      
      
        標記次塊內存正在使用  
      
      
        31
      
      
        32
      
      
        goto
      
      
         fwd_addr_out;  


      
      
        33
      
      
                        }  


      
      
        34
      
      
        35
      
      
        /*
      
      
         This is a problem area. If we've run out of 


      
      
        36
      
      
                         * chunks in our slab above, we need to allocate 


      
      
        37
      
      
                         * enough memory to service this request. 


      
      
        38
      
      
                         * The problem is, these individual chunks will fail 


      
      
        39
      
      
                         * the first address range check in __is_member. Now, since 


      
      
        40
      
      
                         * we're not allocating a full second slab, we wont have 


      
      
        41
      
      
                         * enough info perform the range check in __is_member. 


      
      
        42
      
      
                         * 


      
      
        43
      
      
                         * I am working around this by performing a regular allocation 


      
      
        44
      
      
                         * , just the way the caller would've done when not using the 


      
      
        45
      
      
                         * mem-pool. That also means, we're not padding the size with 


      
      
        46
      
      
                         * the list_head structure because, this will not be added to 


      
      
        47
      
      
                         * the list of chunks that belong to the mem-pool allocated 


      
      
        48
      
      
                         * initially. 


      
      
        49
      
      
                         * 


      
      
        50
      
      
                         * This is the best we can do without adding functionality for 


      
      
        51
      
      
                         * managing multiple slabs. That does not interest us at present 


      
      
        52
      
      
                         * because it is too much work knowing that a better slab 


      
      
        53
      
      
                         * allocator is coming RSN. 


      
      
        54
      
      
        */
      
      
        55
      
                       mem_pool->pool_misses++;
      
        //
      
      
        內存池缺失計數次數加1  
      
      
        56
      
                       mem_pool->curr_stdalloc++;
      
        //
      
      
        系統標準分配次數加1  
      
      
        57
      
      
        if
      
       (mem_pool->max_stdalloc < mem_pool->
      
        curr_stdalloc)  


      
      
        58
      
                               mem_pool->max_stdalloc = mem_pool->
      
        curr_stdalloc;  


      
      
        59
      
                       ptr = GF_CALLOC (
      
        1
      
      , mem_pool->
      
        padded_sizeof_type,  


      
      
        60
      
                                        gf_common_mt_mem_pool);
      
        //
      
      
        分配一個內存池對象  
      
      
        61
      
                       gf_log_callingfn (
      
        "
      
      
        mem-pool
      
      
        "
      
      , GF_LOG_DEBUG, 
      
        "
      
      
        Mem pool is full. 
      
      
        "
      
      
        62
      
      
        "
      
      
        Callocing mem
      
      
        "
      
      
        );  


      
      
        63
      
      
        64
      
      
        /*
      
      
         Memory coming from the heap need not be transformed from a 


      
      
        65
      
      
                         * chunkhead to a usable pointer since it is not coming from 


      
      
        66
      
      
                         * the pool. 


      
      
        67
      
      
        */
      
      
        68
      
      
                }  


      
      
        69
      
      
        fwd_addr_out:  


      
      
        70
      
               pool_ptr =
      
         mem_pool_from_ptr (ptr);  


      
      
        71
      
               *pool_ptr = (
      
        struct
      
       mem_pool *
      
        )mem_pool;  


      
      
        72
      
               ptr = mem_pool_chunkhead2ptr (ptr);
      
        //
      
      
        得到真正開始的內存  
      
      
        73
      
               UNLOCK (&mem_pool->
      
        lock
      
      
        );  


      
      
        74
      
      
        75
      
      
        return
      
      
         ptr;  


      
      
        76
      
       }  
    

?

當我們使用完一個內存池中的內存結構以后就需要還給內存池以便被以后的程序使用,達到循環使用的目的。但是在歸還以前我們首先需要判斷是不是內存池對象的一個成員,判斷的結果有三種,分別是:是,不是和錯誤情況(就是它在內存池的內存范圍以內,但是不符合內存池對象的大小),實現如下:

?

      
         1
      
      
        static
      
      
        int
      
      
         2
      
       __is_member (
      
        struct
      
       mem_pool *pool, 
      
        void
      
       *ptr)
      
        //
      
      
        判斷ptr指向的內存是否是pool的成員  
      
      
         3
      
      
        {  


      
      
         4
      
      
        if
      
       (!pool || !
      
        ptr) {  


      
      
         5
      
                       gf_log_callingfn (
      
        "
      
      
        mem-pool
      
      
        "
      
      , GF_LOG_ERROR, 
      
        "
      
      
        invalid argument
      
      
        "
      
      
        );  


      
      
         6
      
      
        return
      
       -
      
        1
      
      
        ;  


      
      
         7
      
      
                }  


      
      
         8
      
      
         9
      
      
        if
      
       (ptr < pool->pool || ptr >= pool->pool_end)
      
        //
      
      
        ptr如果不再pool開始到結束的范圍內就不是  
      
      
        10
      
      
        return
      
      
        0
      
      
        ;  


      
      
        11
      
      
        12
      
      
        if
      
       ((mem_pool_ptr2chunkhead (ptr) - pool->
      
        pool)  


      
      
        13
      
                   % pool->padded_sizeof_type)
      
        //
      
      
        判斷是否是一個符合內存塊大小的內存對象  
      
      
        14
      
      
        return
      
       -
      
        1
      
      
        ;  


      
      
        15
      
      
        16
      
      
        return
      
      
        1
      
      
        ;  


      
      
        17
      
       }  
    

?

那么根據上面函數判斷的結果,放入內存對象到內存池對象的函數就會做相應的處理,具體代碼如下:

?

      
         1
      
      
        void
      
      
         2
      
       mem_put (
      
        void
      
       *ptr)
      
        //
      
      
        將ptr放回到內存池中去  
      
      
         3
      
      
        {  


      
      
         4
      
      
        struct
      
       list_head *list =
      
         NULL;  


      
      
         5
      
      
        int
      
          *in_use =
      
         NULL;  


      
      
         6
      
      
        void
      
         *head =
      
         NULL;  


      
      
         7
      
      
        struct
      
       mem_pool **tmp =
      
         NULL;  


      
      
         8
      
      
        struct
      
       mem_pool *pool =
      
         NULL;  


      
      
         9
      
      
        10
      
      
        if
      
       (!
      
        ptr) {  


      
      
        11
      
                       gf_log_callingfn (
      
        "
      
      
        mem-pool
      
      
        "
      
      , GF_LOG_ERROR, 
      
        "
      
      
        invalid argument
      
      
        "
      
      
        );  


      
      
        12
      
      
        return
      
      
        ;  


      
      
        13
      
      
                }  


      
      
        14
      
      
        15
      
               list = head = mem_pool_ptr2chunkhead (ptr);
      
        //
      
      
        得到鏈表指針  
      
      
        16
      
               tmp =
      
         mem_pool_from_ptr (head);  


      
      
        17
      
      
        if
      
       (!
      
        tmp) {  


      
      
        18
      
                       gf_log_callingfn (
      
        "
      
      
        mem-pool
      
      
        "
      
      
        , GF_LOG_ERROR,  


      
      
        19
      
      
        "
      
      
        ptr header is corrupted
      
      
        "
      
      
        );  


      
      
        20
      
      
        return
      
      
        ;  


      
      
        21
      
      
                }  


      
      
        22
      
      
        23
      
               pool = *
      
        tmp;  


      
      
        24
      
      
        if
      
       (!
      
        pool) {  


      
      
        25
      
                       gf_log_callingfn (
      
        "
      
      
        mem-pool
      
      
        "
      
      
        , GF_LOG_ERROR,  


      
      
        26
      
      
        "
      
      
        mem-pool ptr is NULL
      
      
        "
      
      
        );  


      
      
        27
      
      
        return
      
      
        ;  


      
      
        28
      
      
                }  


      
      
        29
      
               LOCK (&pool->
      
        lock
      
      
        );  


      
      
        30
      
      
                {  


      
      
        31
      
      
        32
      
      
        switch
      
      
         (__is_member (pool, ptr))  


      
      
        33
      
      
                        {  


      
      
        34
      
      
        case
      
      
        1
      
      :
      
        //
      
      
        是內存池中的內存  
      
      
        35
      
                               in_use = (head + GF_MEM_POOL_LIST_BOUNDARY +  


      
        36
      
                                         GF_MEM_POOL_PTR);
      
        //
      
      
        得到是否正在使用變量  
      
      
        37
      
      
        if
      
       (!is_mem_chunk_in_use(in_use)) {
      
        //
      
      
        正在使用就暫時不回收  
      
      
        38
      
                                       gf_log_callingfn (
      
        "
      
      
        mem-pool
      
      
        "
      
      
        , GF_LOG_CRITICAL,  


      
      
        39
      
      
        "
      
      
        mem_put called on freed ptr %p of mem 
      
      
        "
      
      
        40
      
      
        "
      
      
        pool %p
      
      
        "
      
      
        , ptr, pool);  


      
      
        41
      
      
        break
      
      
        ;  


      
      
        42
      
      
                                }  


      
      
        43
      
                               pool->hot_count--
      
        ;  


      
      
        44
      
                               pool->cold_count++
      
        ;  


      
      
        45
      
                               *in_use = 
      
        0
      
      
        ;  


      
      
        46
      
                               list_add (list, &pool->list);
      
        //
      
      
        加入到內存池中的鏈表  
      
      
        47
      
      
        break
      
      
        ;  


      
      
        48
      
      
        case
      
       -
      
        1
      
      :
      
        //
      
      
        錯誤就終止程序  
      
      
        49
      
      
        /*
      
      
         For some reason, the address given is within 


      
      
        50
      
      
                                 * the address range of the mem-pool but does not align 


      
      
        51
      
      
                                 * with the expected start of a chunk that includes 


      
      
        52
      
      
                                 * the list headers also. Sounds like a problem in 


      
      
        53
      
      
                                 * layers of clouds up above us. ;) 


      
      
        54
      
      
        */
      
      
        55
      
      
                                abort ();  


      
      
        56
      
      
        break
      
      
        ;  


      
      
        57
      
      
        case
      
      
        0
      
      :
      
        //
      
      
        不是內存池中的內存直接釋放掉  
      
      
        58
      
      
        /*
      
      
         The address is outside the range of the mem-pool. We 


      
      
        59
      
      
                                 * assume here that this address was allocated at a 


      
      
        60
      
      
                                 * point when the mem-pool was out of chunks in mem_get 


      
      
        61
      
      
                                 * or the programmer has made a mistake by calling the 


      
      
        62
      
      
                                 * wrong de-allocation interface. We do 


      
      
        63
      
      
                                 * not have enough info to distinguish between the two 


      
      
        64
      
      
                                 * situations. 


      
      
        65
      
      
        */
      
      
        66
      
                               pool->curr_stdalloc--;
      
        //
      
      
        系統分配次數減1  
      
      
        67
      
      
                                GF_FREE (list);  


      
      
        68
      
      
        break
      
      
        ;  


      
      
        69
      
      
        default
      
      
        :  


      
      
        70
      
      
        /*
      
      
         log error 
      
      
        */
      
      
        71
      
      
        break
      
      
        ;  


      
      
        72
      
      
                        }  


      
      
        73
      
      
                }  


      
      
        74
      
               UNLOCK (&pool->
      
        lock
      
      
        );  


      
      
        75
      
       }  
    

?

除了上面介紹的,當然還有銷毀內存池的功能函數mem_pool_destroy,輔助分配系統內存的一些封裝函數等;另外還有一個對于調試有用的功能,那就是記錄分配內存的信息,這些東西相對簡單,可以自己直接看源碼理解。

?

下班了,今天就到此為止吧!以后準備分享iobuf實現的原理以及源代碼!

GlusterFS之內存池(mem-pool)實現原理及代碼詳解


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 亚洲精品美女久久久 | 日韩精品中文字幕久久 | 久久综合九色综合欧洲 | 国产精品夜色一区二区三区 | av在线视 | 欧美一级夜夜爽 | 日本高清无遮挡 | 日韩在线观看毛片 | 精品久久久久久免费影院 | 精品视频在线观看 | 6全高清智能录播系统视频 精品九九 | 欧美一级永久免费毛片在线 | 免费国产一级特黄久久 | 色婷亚洲 | 欧美日韩亚洲高清不卡一区二区三区 | 曰批全过程40分钟免费视频多人 | 九九热视频精品在线观看 | 久久久无码精品亚洲日韩按摩 | 成人免费毛片网站 | 国产精品久久久久久吹潮 | 国产精品成人亚洲一区二区 | 亚洲成色 | 亚洲精品在线免费观看视频 | 免费污的网站 | 三A级做爰片免费观看国产电影 | 久久青草国产免费观看 | 精品免费国产一区二区三区 | 久草在线免费新视频 | 成人在线免费观看 | 日韩在线高清视频 | 精品免费久久久久欧美亚一区 | 免费观看成人拍拍拍1000视频 | 亚洲日本人成中文字幕 | 国产精品99久久 | 国产全肉乱妇杂乱视频 | 免费视频拗女稀缺一区二区 | 久久精品日韩 | 久久久久久久久久久久久久久久久久久 | 免费观看黄色小视频 | 久久久久中文 | 天天色av|