2

커널 소스에서 일부 함수 호출을하는 커널 모듈의 코드를 이해하려고합니다. 코드는 device-mapper.h입니다.리눅스 커널의 dm_per_bio_data 기능은 무엇을합니까?

struct dm_target_io { 
    struct dm_io *io; 
    struct dm_target *ti; 
    unsigned target_bio_nr; 
    unsigned *len_ptr; 
    struct bio clone; 
}; 

static inline void *dm_per_bio_data(struct bio *bio, size_t data_size) 
{ 
    return (char *)bio - offsetof(struct dm_target_io, clone) - data_size; 
} 

는 우리는 "dm_per_bio_data 데이터의 위치를 ​​반환한다."고, device_mapper.h의 의견에, 다른 말된다 이것이 왜 그런지 나는 확신하지 못한다.

먼저 dm_per_bio_data는 구조체 bio *를 취해 offsetof (struct dm_target_io, clone)로 감산합니다.이 구조체는 둘러싸는 dm_target_io 구조체의 시작을 제공해야합니다. 그런 다음 data_size를 뺍니다.이 포인터는 - 어디로?

dm_target_io가 data_size로 빼는 것이 나를 차지할 수있는 다른 구조체 내에서 선언 된 위치를 찾고자했습니다. 그런 행운은 지금까지는 없습니다.

답변

1

per_io_data_size이 핵심입니다.

(추가) (dm_target_io (클론))

: 그래서 그들은 같이 배치되도록 struct dm_target의 부재로 설정함으로써, 디바이스 매퍼 앞서 dm_target_io의 사용자 정의 데이터를위한 여분의 공간을 할당 dm_per_bio_data는 추가 공간의 시작 부분에 대한 포인터를 리턴합니다.

struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, enum dm_queue_mode type, 
              unsigned integrity, unsigned per_io_data_size) 
{ 
     struct dm_md_mempools *pools = kzalloc_node(sizeof(*pools), GFP_KERNEL, md->numa_node_id); 
     unsigned int pool_size = 0; 
     unsigned int front_pad; 

     if (!pools) 
       return NULL; 

     switch (type) { 
     case DM_TYPE_BIO_BASED: 
     case DM_TYPE_DAX_BIO_BASED: 
       pool_size = dm_get_reserved_bio_based_ios(); 
       front_pad = roundup(per_io_data_size, __alignof__(struct dm_target_io)) + offsetof(struct dm_target_io, clone); 

       pools->io_pool = mempool_create_slab_pool(pool_size, _io_cache); 
       if (!pools->io_pool) 
         goto out; 
       break; 
     case DM_TYPE_REQUEST_BASED: 
     case DM_TYPE_MQ_REQUEST_BASED: 
       pool_size = dm_get_reserved_rq_based_ios(); 
       front_pad = offsetof(struct dm_rq_clone_bio_info, clone); 
       /* per_io_data_size is used for blk-mq pdu at queue allocation */ 
       break; 
     default: 
       BUG(); 
     } 

     pools->bs = bioset_create(pool_size, front_pad, BIOSET_NEED_RESCUER); 
     if (!pools->bs) 
       goto out;