kernel 작업중 block I/O의 분할 처리

kyungminLim·2024년 8월 12일

dm-zoned

목록 보기
3/4

kernel code 분석중에, 특정 BIO를 클론하여 submit하는 역할을 하는 함수가 있었다. clone된 bio는 원래 bio의 일부만 처리할 수 있다. 여기서 왜 bio를 clone하고 분할 처리를 하는지에 대해 설명을 할 예정이다.

bio를 클론해서 submit하는 이유는 주로 asynchronous I/O 처리와 원본 bio의 상태 보존때문이다. 이 방법은 특히 kernel 내에서 복잡한 I/O 작업을 처리할 때 유용하다. 그 이유는:

비동기 I/O 처리

bio를 클론하면, 클론된 bio는 원본과 독립적으로 비동기적으로 처리될 수 있다. 이는 원본 bio의 처리와는 별로도 클론된 bio가 I/O 작업을 수행할 수 있다는 의미이다. 이 방식은 I/O 작업을 병렬로 처리하거나, 특정 조건 하에서만 일부 작업을 따로 처리하고자 할 때 유용하다.

예를 들어, seq-zone에서는 data를 반드시 순차적으로 써야한다. 이때 특정 블록을 따로 클론해서 독립적으로 처리함으로써, 복잡한 sequential write 작업을 더 효율적으로 관리할 수 있다.

원본 bio의 상태 보존

클론을 사용하면 원본 bio의 상태를 그대로 보존할 수 있다. bio는 kernel에서 block i/o 요청을 표현하는 구조체인데, error, scheduling, device driver, caching 등의 이유로 bio 구조체가 변경이 되면 원본 bio에 대한 정보가 손실될 수 있다. 특히, 복잡한 i/o 작업에서 여러 단계를 거치면서 bio가 여러 번 수정될 수 있기 때문에 원본 정보를 보존하는 것이 매우 중요하다.

다음은 이에 대한 예시 kernel 코드이다.

/*
 * Issue a clone of a target BIO. The clone may only partially process the
 * original target BIO.
 */
static int dmz_submit_bio(struct dmz_target * dmz, struct dm_zone * zone,
    struct bio * bio, sector_t chunk_block,
    unsigned int nr_blocks) {
    struct dmz_bioctx * bioctx =
        dm_per_bio_data(bio, sizeof(struct dmz_bioctx));
    struct dmz_dev * dev = zone - > dev;
    struct bio * clone;
    if (dev - > flags & DMZ_BDEV_DYING) return -EIO;
    clone = bio_clone_fast(bio, GFP_NOIO, & dmz - > bio_set);
    if (!clone) return -ENOMEM;
    bio_set_dev(clone, dev - > bdev);
    bioctx - > dev = dev;
    clone - > bi_iter.bi_sector = dmz_start_sect(dmz - > metadata, zone) + dmz_blk2sect(chunk_block);
    clone - > bi_iter.bi_size = dmz_blk2sect(nr_blocks) << SECTOR_SHIFT;
    clone - > bi_end_io = dmz_clone_endio;
    clone - > bi_private = bioctx;
    bio_advance(bio, clone - > bi_iter.bi_size);
    refcount_inc( & bioctx - > ref);
    submit_bio_noacct(clone);
    if (bio_op(bio) == REQ_OP_WRITE && dmz_is_seq(zone)) zone - > wp_block += nr_blocks;
    return 0;
}

위 함수는 zoned block device와 관련된 bio 작업에서 특정 bio를 클론해서 submit하는 역할을 한다. 주로, bio 작업을 수행할 때, 원본 bio를 복사하고, 복사된 bio를 장치에 제출하여 작업을 수행한다.

  • dmz_target
    ZBD와 관련된 target 구조체이다. bio 작업을 수행하는데 필요한 다양한 metadata와 설정을 포함한다.

  • dm-zone
    bio 작업이 수행될 특정 zone을 나타낸다.

  • struct bio *bio
    이 함수가 처리할 원본 bio 요청이다. bio는 kernel에서 block device에 대한 i/o 요청을 나타내는 구조체

  • sector_t chunk_block
    zone에서 bio 작업이 시작될 블록의 위치를 나타낸다.

  • nr_blocks
    이 bio 요청에서 처리할 블록의 수

  • dmz_bioctx 초기화
    bio 작업의 context를 나타내는 구조체로, dm_per_bio_data를 사용해서 bio에 할당된 메모리에서 이 context를 가져온다.
    struct dmz_dev *dev = zone->dev 를 통해 해당 zone이 속한 device를 가져온다.

  • bio 클론 생성
    bio_clone_fast를 사용해서 원본 bio clone을 생성한다. 이 함수는 원본 bio의 내용을 복사해서 새로운 bio 구조체를 생성한다.

  • bio clone 설정
    bio_set_dev를 사용해서 clone된 bio가 작동할 block device를 설정

/*
 * Zone descriptor.
 */
struct dm_zone {
    /* For listing the zone depending on its state */
    struct list_head link;

    /* Device containing this zone */
    struct dmz_dev * dev;

    /* Zone type and state */
    unsigned long flags;

    /* Zone activation reference count */
    atomic_t refcount;

    /* Zone id */
    unsigned int id;

    /* Zone write pointer block (relative to the zone start block) */
    unsigned int wp_block;

    /* Zone weight (number of valid blocks in the zone) */
    unsigned int weight;

    /* The chunk that the zone maps */
    unsigned int chunk;

    /*
     * For a sequential data zone, pointer to the random zone
     * used as a buffer for processing unaligned writes.
     * For a buffer zone, this points back to the data zone.
     */
    struct dm_zone * bzone;
};

dm_zoned 구조체는 zoned block device에서 특정 zone에 대한 정보를 저장하고 관리하는데 사용되는 자료 구조이다. 이 구조체는 각 존에 대한 다양한 메타데이터와 상태 정보를 담고 있으며, zoned block device의 효율적인 I/O 작업 관리를 돕는다.

  • struct list_head
    현재 zone의 상태에 따라 다른 zone들과 연결하기 위한 list node이다. kernel에서 사용하는 이중 연결 리스트의 구조로, 특정 상태에 있는 여러 zone들을 관리하는데 사용된다.

  • struct dmz_dev
    이 zone이 속한 block device를 가리킨다. 이 zone이 어느 장치에 속해있는지, 어떤 장치와 관련된 작업인지 알 수 있게 한다.

  • unsigned long flags
    zone의 타입과 상태를 나타내는 flag를 저장한다. 예를 들면, 이 flag를 통해 해당 zone이 seq-zone인지 conv-zone인지 등의 정보를 관리할 수 있다.

  • atomic_t refcount
    zone의 활성화 참조 카운터이다. 특정 zone이 활성화된 상태에서 여러 작업에 의해 참조될 때, 이 카운터를 통해 참조 횟수를 추적하고, 마지막 참조가 해제되면 zone을 비활성화할 수 있다.

  • unsigned int id
    zone의 고유 식별자( zone id)를 나타낸다. 각 zone을 고유하게 식별하기 위한 ID이다.

  • unsigned int wp_block
    write pointer의 위치를 나타낸다. seq-zone의 경우, data는 반드시 sequential 하게 쓰여야 하므로, 현재까지 쓰여진 마지막 블록의 위치를 나타낸다. wp_block은 zone의 시작 블록을 기준으로 상대적인 위치를 가리킨다.

  • unsigned int weight
    zone 내의 valid block의 수를 나타낸다. 즉, zone에서 실제로 데이터가 쓰여져서 valid 상태로 남아 있는 block의 개수를 의미한다.

  • unsigned int chunk
    이 zone이 매핑되는 chunk를 나타낸다. chunk는 ZBD에서 zone을 더 작은 단위로 나누어 관리하는 개념으로, 특정 zone이 어느 청크에 속해 있는지를 나타낸다.

  • struct dm_zone
    이 멤버는 seq-zone이 conv-zone을 buffer로 사용해서 정렬 되지 않은 write를 처리할 때 사용된다.
    seq-zone의 경우, 정렬되지 않은 write 작업을 처리하기 위해 conv-zone을 임시 buffer로 사용할 수 있다. 이 경우 conv-zone을 가리킨다.
    conv-zone이 buffer로 사용되는 경우, 이 멤버는 그 conv-zone이 buffering하는 원래의 seq-zone을 가리킨다.

0개의 댓글