블록 장치 기반 > > Linux 장치 드라이버

집중 하기 때문에 전공 은 매우 중요 한 일 입 니 다. 더 이상 일 을 극 대화 하지 않 았 을 때 사람들 앞에서 자랑 하지 마 세 요. 그러면 두려움 이 긴장 되 고 도움 이 되 지 않 습 니 다.얼마나 화려 한 연 기 는 기본 적 인 집착 에서 비롯 되 는 지 가능 한 한 그 이 유 를 알 아야 한다.
글 목록
  • [0x 100] 개념 과 특징
  • [0x 110] 블록 장치 속성 정보
  • [0x 120] 요청 대기 열
  • [0x 122] 역할
  • [0x 122] 내용
  • [0x 200] 관련 데이터 구조
  • [0x 210] 장치 번호 링크 구조 [struct blk major name]
  • [0x 220] 블록 설비 관리
  • [0x 221] 블록 설비 조작 리 셋 함수 집합
  • [0x 222] 분 구 속성 정보 구조
  • [0x 230] 블록 설비 요청 구조
  • [0x 231] 요청 항목 구조 [struct request]
  • [0x 232] 요청 체인 분할 물리 페이지 구조 [struct bio]
  • [0x 300] 특성 과 인터페이스
  • [0x 310] 블록 설비 초기 화
  • [0x 311] 등록 블록 장치 드라이버 [struct blk major name]
  • [0x312] 블록 장치 드라이버 로그아웃
  • [0x313] 블록 설비 추가 준비 작업
  • [0x314] 분배 디스크 속성 저장 공간 [struct gendisk]
  • [0x315] 커 널 목록 에 블록 장 치 를 추가 합 니 다
  • [0x 320] 요청 대기 열 [struct request queue]
  • [0x 321] 대기 열 구조 초기 화
  • [0x 322] 대기 열 관리 인터페이스
  • [0x 330] 대기 열 메모리 맵 오프셋 요청
  • [0x 331] bio 벡터 파라미터 방문
  • [0x 332] 가상 주소 맵
  • [0x 100] 개념 과 특징
  • 데 이 터 는 고정 크기 의 데이터 블록 을 형성 하고 블록 크기 단위 로 무 작위 범위 의 데이터 접근 을 한다.
  • Linux 커 널 섹 터 크기 는 512 Btye 이 므 로 섹 터 번호 [저장 공간 바이트 수 / 512] 의 결과;
  • 서로 다른 시스템 구조 에 따라 데이터 블록 의 크기 가 다 르 고 보통 4096 바이트, 즉 4KBtye 이다.

  • [0x 110] 블록 장치 속성 정보
  • 블록 설비 의 속성 정 보 를 묘사 하 는데 설비 표지, 구역 표 지 를 포함한다.
  • IO 요청 이벤트 관리;
  • 블록 설비 관리 리 셋 함수;

  • [0x 120] 요청 대기 열
    [0x 122] 역할
  • 블록 장치 의 I / O 요청 을 저장 하 는 대기 열
  • 블록 장치 처리 가 필요 한 요청 매개 변수: 독립 세그먼트 수, 하드웨어 섹 터 크기, 정렬 방식 등;
  • 최종 기한 I / O 스케줄 러: 효율 을 확보 한 상황 에서 모든 요청 이 기한 을 초과 하지 않도록 확보한다.
  • 예상 I / O 스케줄 러: 짧 은 간격 에서 같은 유형의 블록 장치 요청 을 막 았 습 니 다.

  • [0x 122] 내용
  • 설비 파라미터: 제조 업 체 ID, 제품 모델, 용량, 사용 가능 한 크기, 진단 정보 등
  • 읽 기 및 쓰기 IO 요청
  • 제어 명령: 미디어 쓰기 모드 설정, 트랙 전환, 감사 보고서 반환 등 을 기록 합 니 다.

  • [0x 200] 관련 데이터 구조
    [0x 210] 장치 번호 링크 구조 [struct blk major name]
    #include 
    static struct blk_major_name {
            struct blk_major_name *next;   //          
            int major;                     //    
            char name[16];                 //    
    } *major_names[BLKDEV_MAJOR_HASH_SIZE];
    

    [0x 220] 블록 설비 관리
    [0x 221] 블록 장치 조작 리 셋 함수 집합
    #include 
    struct block_device_operations {
            int (*open) (struct block_device *, fmode_t);
            int (*release) (struct gendisk *, fmode_t);
            int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
            int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
            int (*direct_access) (struct block_device *, sector_t,void **, unsigned long *);
            unsigned int (*check_events) (struct gendisk *disk,unsigned int clearing);
            
            int (*media_changed) (struct gendisk *);
            void (*unlock_native_capacity) (struct gendisk *);
            int (*revalidate_disk) (struct gendisk *);
            int (*getgeo)(struct block_device *, struct hd_geometry *);
            /* this callback is with swap_lock and sometimes page table lock held */
            void (*swap_slot_free_notify) (struct block_device *, unsigned long);
            struct module *owner;
    };
    

    [0x222] 분 구 속성 정보 구조
    #include 
    struct gendisk {
            /*【    】             disk_devt()*/
            int major;                      
            /*【    】         */
            int first_minor;               
            /*【    】      =1,      ;US=16,  15  ,    disk_max_parts()  */
            int minors;                     
            /*        ,  /proc/partions sysfs  */
            char disk_name[DISK_NAME_LEN];  
            
            char *(*devnode)(struct gendisk *gd, umode_t *mode);
            unsigned int events;            /* supported events */
            unsigned int async_events;      /* async events, subset of all */
            struct disk_part_tbl __rcu *part_tbl;
            struct hd_struct part0;
            /*          */
            const struct block_device_operations *fops;
            /*   I/O    */
            struct request_queue *queue;
            /*           */
            void *private_data;
            /*          GENHD_FL_* */
            int flags;
            struct device *driverfs_dev;  // FIXME: remove
            /*sysfs   */
            struct kobject *slave_dir;
    
            struct timer_rand_state *random;
            atomic_t sync_io;               /* RAID */
            struct disk_events *ev;
    #ifdef  CONFIG_BLK_DEV_INTEGRITY
            struct blk_integrity *integrity;
    #endif
            int node_id;
    };
    

    [0x 230] 블록 장치 요청 구조
    [0x 231] 요청 항목 구조 [struct request]
    struct request {
            struct list_head queuelist;       /*        request  */
            struct call_single_data csd;
    
            struct request_queue *q;          /*         */
    
            unsigned int cmd_flags;
            enum rq_cmd_type_bits cmd_type;
            unsigned long atomic_flags;
    
            int cpu;
    
            struct bio *bio;                      /*             */
            struct bio *biotail;
    
            struct hlist_node hash;               /*    hash     */
            union {
                    struct rb_node rb_node; /* sort/lookup */
                    void *completion_data;
            };
            union {
                    struct {
                            struct io_cq            *icq;
                            void                    *priv[2];
                    } elv;
    
                    struct {
                            unsigned int            seq;
                            struct list_head        list;
                            rq_end_io_fn            *saved_end_io;
                    } flush;
            };
            struct gendisk *rq_disk;
            struct hd_struct *part;
            unsigned long start_time;
    #ifdef CONFIG_BLK_CGROUP
            unsigned long long start_time_ns;
            unsigned long long io_start_time_ns;    /* when passed to hardware */
    #endif
            unsigned short nr_phys_segments;        /*           */
    #if defined(CONFIG_BLK_DEV_INTEGRITY)
            unsigned short nr_integrity_segments;
    #endif
            unsigned short ioprio;
            int ref_count;
            void *special;          /* opaque pointer available for LLD use */
            char *buffer;           /* kaddr of the current segment if available */
            int tag;
            int errors;
            unsigned char __cmd[BLK_MAX_CDB];
            unsigned char *cmd;
            unsigned short cmd_len;
            unsigned int extra_len; /* length of alignment and padding */
            unsigned int sense_len;
            unsigned int resid_len; /* residual count */
            void *sense;
            unsigned long deadline;
            struct list_head timeout_list;
            unsigned int timeout;
            int retries;
            rq_end_io_fn *end_io;
            void *end_io_data;
            struct request *next_rq;
    };
    

    [0x 232] 물리 적 페이지 구조 분할 요청 [struct bio]
  • 블록 장치 IO 가 요청 한 실행 순서 에 대한 조직 관리 정보
  • struct bio {
            sector_t                bi_sector;      /*         512K      */
            struct bio              *bi_next;       /*         IO     */
            struct block_device     *bi_bdev;
            unsigned long           bi_flags;       /*         */
            unsigned long           bi_rw;          /*      ,      */
            unsigned short          bi_vcnt;        /* how many bio_vec's */
            unsigned short          bi_idx;         /* current index into bvl_vec */
            
            unsigned int            bi_phys_segments; /*     */
            unsigned int            bi_size;          /*              */
    
           /*          , bi_seg_front_size~bi_seg_back_size*/
            unsigned int            bi_seg_front_size;
            unsigned int            bi_seg_back_size;
    
            unsigned int            bi_max_vecs;    /* max bvl_vecs we can hold */
    
            atomic_t                bi_cnt;         /* pin count */
    
            struct bio_vec   
            { 
                struct page     *bv_page;      
                unsigned int    bv_len;     
                unsigned int    bv_offset;
             } *bi_io_vec;     /*    bio  :  IO      ,    bv_offset     bv_len   */
             struct bio_vec          bi_inline_vecs[0];  
            bio_end_io_t            *bi_end_io;
    
            void                    *bi_private;
    #if defined(CONFIG_BLK_DEV_INTEGRITY)
            struct bio_integrity_payload *bi_integrity;  /* data integrity */
    #endif
    
            bio_destructor_t        *bi_destructor; /* destructor */
    
    };
    
    

    [0x 300] 특성 및 인터페이스
    [0x 310] 블록 장치 초기 화
    [0x 311] 등록 블록 장치 드라이버 [struct blk major name]
    #include 
    /*implement kernel-dir/block/genhd.c */
    
    static inline int major_to_index(unsigned major)
    {
            return major % BLKDEV_MAJOR_HASH_SIZE;
    }
    /*                */
    int register_blkdev(unsigned int major, const char *name)
    {
            struct blk_major_name **n, *p;
            int index, ret = 0;
    
            mutex_lock(&block_class_lock);
    
            /*   major   0,                    */
            if (major == 0) {
                    for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) {
                            if (major_names[index] == NULL)
                                    break;
                    }
            /*index    0,          ,       */
                    if (index == 0) {
                            printk("register_blkdev: failed to get major for %s
    "
    ,name); ret = -EBUSY; goto out; } /* */ major = index; ret = major; } /* , */ p = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL); if (p == NULL) { ret = -ENOMEM; goto out; } /* , */ p->major = major; strlcpy(p->name, name, sizeof(p->name)); p->next = NULL; /* , , , 。 */ index = major_to_index(major); /* , , , */ for (n = &major_names[index]; *n; n = &(*n)->next) { if ((*n)->major == major) break; } /* */ if (!*n) *n = p; else ret = -EBUSY; if (ret < 0) { printk("register_blkdev: cannot get major %d for %s
    "
    ,major, name); kfree(p); } out: mutex_unlock(&block_class_lock); return ret; }

    args 1: 할당 해 야 할 주 장치 번호, 예 를 들 어 0 은 자동 으로 분 배 됩 니 다. 예 를 들 어 N0 은 정적 으로 args 2 를 분배 합 니 다. 디 스 플레이 와 / proc / dev / 의 장치 이름 retval: 성공 major, 실패 errno;
    [0x312] 블록 장치 드라이버 로그아웃
    #include 
    /*implement kernel-dir/block/genhd.c */
    void unregister_blkdev(unsigned int major, const char *name)
    {
            struct blk_major_name **n;
            /*      */
            struct blk_major_name *p = NULL;
            /*        index*/
            int index = major_to_index(major);
    
            mutex_lock(&block_class_lock);
            /*       major     */
            for (n = &major_names[index]; *n; n = &(*n)->next)
                    if ((*n)->major == major)
                            break;
           /*                 */
            if (!*n || strcmp((*n)->name, name)) {
                    WARN_ON(1);
            } else {  /*          */
                    p = *n;
                    *n = p->next;
            }
            mutex_unlock(&block_class_lock);
            /*  */
            kfree(p);
    }
    

    args 1: 로그아웃 해 야 할 주 장치 번호;args 2: 로그아웃 해 야 할 장치 이름;[/ proc / dev / 에 표 시 된 장치 이름] retval: 성공 major, 실패 errno;
    [0x 313] 블록 장치 추가 준비 작업
    struc sbull_dev
    {
        int size;                     /*    */
        u8 *data;
        short users;
        spinlock_t lock;              /*     */ 
        short media_change;           /*    */
        struct request_queue *queue;  /*  IO  */
        struct gendisk *gd;           /*       */
        struct timer_list timer;      /*     */
    };
    
    /*1.        */
    struc sbull_dev * blk_dev =(struc sbull_dev *) kzalloc(sizeof(struc sbull_dev),GFP_KERNEL);
    /*2.        */
    spin_lock_init(spinlock_t *lock);
    /*3.       ,   node_id =-1*/
    struct request_queue *blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
    

    [0x314] 디스크 속성 저장 공간 할당 [struct gendisk]
    /*implement kernel-3.4.39/block/genhd.c*/
    /*    */
    struct gendisk *alloc_disk(int minors) {  return alloc_disk_node(minors, -1); }
    /*     kmalloc     ,     ,sysfs    */
    struct gendisk *alloc_disk_node(int minors, int node_id)
    /*     */
    void del_gendisk(struct gendisk *disk)
    
  • 디스크 를 등록 하 는 차 장치 의 수량 [minor] 은 설정 후 수정 할 수 없습니다.
  • 동적 구 조 는 수 동 으로 공간 을 분배 할 수 없고 커 널 은 그의 인용 수 를 유지 해 야 한다.
  • 내용 [major \ first minor \ fops \ quue \ disk name] 을 채 웁 니 다.

  • [0x315] 커 널 목록 에 블록 장 치 를 추가 합 니 다.
  • 호출 하기 전에 드라이버 등록 성공 을 확인 해 야 합 니 다. 되 돌아 오기 전에 커 널 이 블록 장치 에 접근 하 는 파 티 션 표를 호출 해 야 합 니 다.
  • 이 함 수 는 확장 구역 의 블록 설 비 를 등록 하 는 데 사용 할 수 있 습 니 다.
  • void add_disk(struct gendisk *disk)
    {
            struct backing_dev_info *bdi;
            dev_t devt;
            int retval;
            
            WARN_ON(disk->minors && !(disk->major || disk->first_minor));
            /*       0,   flag    GENHD_FL_EXT_DEVT,alloc_disk()            */
            WARN_ON(!disk->minors && !(disk->flags & GENHD_FL_EXT_DEVT));
    
            disk->flags |= GENHD_FL_UP;
           /*        */
            retval = blk_alloc_devt(&disk->part0, &devt);
            if (retval) {
                    WARN_ON(1);
                    return;
            }
            disk_to_dev(disk)->devt = devt;
    
            disk->major = MAJOR(devt);
            disk->first_minor = MINOR(devt);
    
            disk_alloc_events(disk);
    
            /*   BDI */
            bdi = &disk->queue->backing_dev_info;
            bdi_register_dev(bdi, disk_devt(disk));
            /*     */
            blk_register_region(disk_devt(disk), disk->minors, NULL,exact_match, exact_lock, disk);
            /*    */
            register_disk(disk);
            /*       ,         */
            blk_register_queue(disk);
            
            WARN_ON_ONCE(!blk_get_queue(disk->queue));
            /*          sysfs*/
            retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj,"bdi");
            WARN_ON(retval);
            disk_add_events(disk);
    }
    

    [0x 320] 요청 대기 열 [struct request queue]
    [0x 321] 대기 열 구조 초기 화
    #include 
    /*implement kernel-dir/block/blk-core.c*/ 
    typedef void (request_fn_proc) (struct request_queue *q);
    struct request_queue *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock)
    {
            return blk_init_queue_node(rfn, lock, -1);    
    }
    EXPORT_SYMBOL(blk_init_queue);
    /*                       */
    struct request_queue *blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
    {
            struct request_queue *uninit_q, *q;
          
            uninit_q = blk_alloc_queue_node(GFP_KERNEL, node_id);
            if (!uninit_q)
                    return NULL;
    
            q = blk_init_allocated_queue(uninit_q, rfn, lock);
            if (!q)
                    blk_cleanup_queue(uninit_q);
            return q;
    }
    

    Func: 요청 대기 열 구조 공간 을 분배 하고 요청 대기 열 args 1: 요청 대기 열 처리 함수 포인터 비우 기;args 2: 블록 설비 가 유지 하 는 자 회전 자물쇠 구 조 는 이것 이 원자 조작 임 을 나타 낸다.args 3: 작 동 하 는 노드 ID 는 보통 - 1 이 모든 노드 로 설정 합 니 다.retval: 요청 대기 열 구 조 를 성공 적 으로 되 돌려 주 었 습 니 다. NULL 을 되 돌려 주 는 데 실 패 했 습 니 다.
    [0x 322] 대기 열 관리 인터페이스
    /*        */
    void blk_start_request(struct request *req)
    /*        ,       */
    struct request *blk_peek_request(struct request_queue *q)
    /*         */
    void blk_dequeue_request(struct request *rq)
    /*       */
    int blk_noretry_request(struct request *rq)
    /*           */
    void blk_requeue_request(struct request_queue *q, struct request *rq)
    /*        */
    void blk_stop_request(struct request *req)
    

    [0x 330] 대기 열 메모리 맵 오프셋 요청
    [0x 331] bio 벡터 파라미터 방문
    #define bio_page(bio)           bio_iovec((bio))->bv_page
    #define bio_offset(bio)         bio_iovec((bio))->bv_offset
    #define bio_segments(bio)       ((bio)->bi_vcnt - (bio)->bi_idx)
    #define bio_sectors(bio)        ((bio)->bi_size >> 9)
    

    [0x 332] 가상 주소 맵
    /*        bio           ,              */
    static inline void *bio_data(struct bio *bio)
    {
            if (bio->bi_vcnt)
                    return page_address(bio_page(bio)) + bio_offset(bio);
    
            return NULL;
    }
    
    static inline char *__bio_kmap_irq(struct bio *bio, unsigned short idx,unsigned long *flags)
    {
            return bvec_kmap_irq(bio_iovec_idx(bio, idx), flags);
    }
    
    #ifdef CONFIG_HIGHMEM
    
    static inline char *bvec_kmap_irq(struct bio_vec *bvec, unsigned long *flags)
    {       
            unsigned long addr;
            
            /*
             * might not be a highmem page, but the preempt/irq count
             * balancing is a lot nicer this way
             */
            local_irq_save(*flags);
            addr = (unsigned long) kmap_atomic(bvec->bv_page);
            
            BUG_ON(addr & ~PAGE_MASK);
            
            return (char *) addr + bvec->bv_offset;
    }
    
    static inline void bvec_kunmap_irq(char *buffer, unsigned long *flags)
    {
            unsigned long ptr = (unsigned long) buffer & PAGE_MASK;
    
            kunmap_atomic((void *) ptr);
            local_irq_restore(*flags);
    }
    
    #else
    static inline char *bvec_kmap_irq(struct bio_vec *bvec, unsigned long *flags)
    {
            return page_address(bvec->bv_page) + bvec->bv_offset;
    }
    
    static inline void bvec_kunmap_irq(char *buffer, unsigned long *flags)
    {
            *flags = 0;
    }
    #endif
    
    #define __bio_kunmap_irq(buf, flags)    bvec_kunmap_irq(buf, flags)
    /*bio                  */
    #define bio_kmap_irq(bio, flags)        __bio_kmap_irq((bio), (bio)->bi_idx, (flags))
    #define bio_kunmap_irq(buf,flags)       __bio_kunmap_irq(buf, flags)
    

    어떤 부분 은 알 아 볼 수 없고 정리 해 야 합 니 다. 메모리 관리 와 연결 되 어 있 는 것 같 습 니 다!나중에 자신 에 게 닭 피 주 사 를 맞 고 메모리 관리 부분 을 정리 한 다음 에 그 부분 이 끝나 면 다시 업데이트 하 세 요!힘 든 QAQ 를 두 드 리 는 시간 이 얼마 남지 않 았 습 니 다!

    좋은 웹페이지 즐겨찾기