추가 읽기

추가 읽기

나는 이 책을 읽었습니다:https://lwn.net/Kernel/LDD3/. 여기서 저자는 장치 파일을 캐릭터 장치, 블록 장치, 네트워크 장치의 3가지 종류로 구분한다. 1장 6페이지에서 나는 다음과 같은 사실을 발견했습니다.

캐릭터 장치

문자(char) 장치는 바이트 스트림(예: 파일)으로 액세스할 수 있는 장치입니다. 문자 드라이버는 이 동작을 구현합니다. 이러한 드라이버는 일반적으로 최소한 , open및 시스템 호출을 구현합니다. 텍스트 콘솔( )과 직렬 포트( 및 유사한 포트)는 스트림 추상화로 잘 표현될 수 있으므로 문자 장치의 예입니다. Char 장치는 및 와 같은 파일 시스템 노드를 통해 액세스됩니다 .closereadwrite/dev/console/dev/ttyS0/dev/tty1/dev/lp0

그렇다면 char 장치와 이 장치의 차이점은 무엇입니까?파일 시스템 노드? 나를 더욱 혼란스럽게 만드는 것은 ls -la /dev/이것이 다음과 같다는 것입니다.파일 시스템 노드char 장치로도 사용 가능합니다(설명은 ac로 시작됨).

내 생각엔 이 책에서 문자 장치를 하드웨어 간의 일대일 대응으로 언급한 것 같습니다.파일 시스템 노드소프트웨어 추상화로. 이에 대한 좋은 자료를 주시면 감사하겠습니다.

답변1

그렇다면 char 장치와 이 장치의 차이점은 무엇입니까?파일 시스템 노드?

저는 이 질문을 "문자 장치 드라이버와 문자 장치 파일의 차이점이 무엇입니까?"로 해석합니다.

캐릭터 장치운전사바이트 스트림에서 작동하는 커널 소프트웨어로, 바이트 스트림에서도 작동하는 일부 하드웨어와 통신하는 데 자주 사용됩니다.

캐릭터 장치문서파일 시스템의 파일입니다. 장치 파일에는 파일과 관련된 문자 장치 드라이버에 대해 알아보기 위해 커널에서 사용되는 메타데이터가 연결되어 있습니다. 문자 장치 파일(실제로 모든 장치 파일)에는 주요 장치 번호와 보조 장치 번호라는 두 가지 메타데이터가 있습니다. 출력을 보면 메이저/마이너 숫자를 볼 수 있습니다 ls -l. 예를 들어 문자 장치 파일을 고려해보세요 /dev/null.

$ ls -l /dev/null
crw-rw-rw- 1 root root 1, 3 Jun  6 14:30 /dev/null

두 번째 루트 다음에 나오는 내용에 유의하세요 1, 3. 이는 메이저(1) 및 마이너(3) 숫자입니다. 프로세스가 장치 파일과 상호 작용할 때 커널은 주요 장치 번호를 사용하여 해당 파일에 대한 I/O를 처리하는 커널 장치 드라이버를 파악합니다. 메이저 번호 1의 문자 장치는 메모리 장치와 연관되어 있습니다 major.h.

./include/uapi/linux/major.h:#define MEM_MAJOR      1

단일 장치 드라이버는 종종 여러 장치를 "구동"할 수 있습니다. 보조 장치 번호는 사용자가 작동 중인 특정 장치를 커널에 알려줍니다. 예를 들어, 다음 문자 장치 파일은 모두 주 번호는 동일하지만 부 번호는 다릅니다.

# ls -l /dev/zero /dev/mem /dev/null /dev/full /dev/random /dev/urandom /dev/kmsg
crw-rw-rw- 1 root root 1,  7 Jun  6 14:30 /dev/full
crw-r--r-- 1 root root 1, 11 Jun  6 14:30 /dev/kmsg
crw-r----- 1 root kmem 1,  1 Jun  6 14:30 /dev/mem
crw-rw-rw- 1 root root 1,  3 Jun  6 14:30 /dev/null
crw-rw-rw- 1 root root 1,  8 Jun  6 14:30 /dev/random
crw-rw-rw- 1 root root 1,  9 Jun  6 14:30 /dev/urandom
crw-rw-rw- 1 root root 1,  5 Jun  6 14:30 /dev/zero

다음 소스 코드 조각은 Linux 5.4.32, 설명서 에서 가져온 것입니다 drivers/char/mem.c.

위 출력 에서 ls​​모든 파일의 주요 번호가 1임을 알 수 있습니다. 이를 통해 우리는 동일한 커널 장치 드라이버가 이러한 파일을 열고/읽고/쓰는 모든 프로세스에 대한 I/O 요청에 응답한다는 것을 알 수 있습니다. 커널 소스 코드에서 메모리 장치 드라이버가 이러한 모든 파일에 대한 I/O를 처리하는 역할을 한다는 것을 알 수 있습니다.

static const struct memdev {
        const char *name;
        umode_t mode;
        const struct file_operations *fops;
        fmode_t fmode;
} devlist[] = {
#ifdef CONFIG_DEVMEM
         [1] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET },
#endif
#ifdef CONFIG_DEVKMEM
         [2] = { "kmem", 0, &kmem_fops, FMODE_UNSIGNED_OFFSET },
#endif
         [3] = { "null", 0666, &null_fops, 0 },
#ifdef CONFIG_DEVPORT
         [4] = { "port", 0, &port_fops, 0 },
#endif
         [5] = { "zero", 0666, &zero_fops, 0 },
         [7] = { "full", 0666, &full_fops, 0 },
         [8] = { "random", 0666, &random_fops, 0 },
         [9] = { "urandom", 0666, &urandom_fops, 0 },
#ifdef CONFIG_PRINTK
        [11] = { "kmsg", 0644, &kmsg_fops, 0 },
#endif
};

배열 인덱스(괄호 안의 숫자)는 관련 파일의 보조 장치 번호와 일치합니다.

이제 캐릭터 디바이스 파일 중 하나를 사용하는 프로세스의 예를 살펴보겠습니다. 다음을 포함하는 쉘 스크립트가 있는 경우:

echo "hello" > /dev/null

그런 다음 스크립트는 open()문자 장치 파일입니다 /dev/null. 커널은 이것이 /dev/null문자 장치임을 알고 파일과 관련된 주요 번호와 보조 번호를 확인합니다. 메이저 번호 1을 확인하므로 open()메이저 번호 1(메모리 장치)의 작업을 처리하는 문자 장치 드라이버로 요청을 라우팅합니다. 열기 호출을 처리하는 메모리 장치 드라이버의 함수로 끝납니다.

static int memory_open(struct inode *inode, struct file *filp)
{
        int minor;
        const struct memdev *dev;

        minor = iminor(inode);
        if (minor >= ARRAY_SIZE(devlist))
                return -ENXIO;

        dev = &devlist[minor];
        if (!dev->fops)
                return -ENXIO;

        filp->f_op = dev->fops;
        filp->f_mode |= dev->fmode;

        if (dev->fops->open)
                return dev->fops->open(inode, filp);

        return 0;
}

그런 다음 함수 memory_open()는 마이너 번호를 사용하여 devlist이전에 본 배열의 인덱스를 지정합니다. 장치에 특수 open()기능이 있는 경우 해당 기능을 호출하고, 그렇지 않으면 장치 null에 특수 기능이 없으면 0을 반환합니다 open().

결국 프로세스는 write()열린 파일과 관련된 파일 설명자에 "hello"를 쓰는 호출을 수행합니다. 마찬가지로 커널은 열린 파일이 메이저 번호 1과 마이너 번호 3을 가진 문자 장치와 연관되어 있다는 것을 알고 있으므로 파일을 write()메이저 장치 유형 1(메모리 장치)에 대한 드라이버로 라우팅합니다. 마이너 번호 3을 가진 장치는 I/O 처리를 위한 기능 세트를 등록합니다(여기 null_fops).

         [3] = { "null", 0666, &null_fops, 0 },

구조 null_fops에는 다음 함수 포인터가 포함되어 있습니다.

static const struct file_operations null_fops = {
        ...
        .write          = write_null,
        ...
};

따라서 write()주 장치 번호가 1이고 부 장치 번호가 3인 문자 장치 파일을 호출하면 write_null()이 함수의 구현은 다음과 같습니다.

static ssize_t write_null(struct file *file, const char __user *buf,
                          size_t count, loff_t *ppos)
{
        return count;
}

write_null()함수는 아무 작업도 수행하지 않고 바이트가 성공적으로 기록되었음을 count나타내기 위해 반환됩니다 count(writes에서 기대하는 동작 /dev/null).

정리하자면, 캐릭터 디바이스문서메타데이터(주 및 부 장치 번호)를 포함합니다. 프로세스가 문자 장치 파일에서 I/O를 수행하면 커널은 이 메타데이터를 사용하여 올바른 문자 장치를 찾습니다.운전사파일에 대한 I/O 요청은 커널에서 처리됩니다.

답변2

일반적으로 노드는 모든 그래프의 정점에 대한 일반적인 이름일 수 있습니다. 파일 시스템의 맥락에서 파일과 디렉터리는 자연스럽게 노드입니다(파일 이름은 그래프의 가장자리일 수 있음). 파일 데이터를 보유하는 데이터 구조를 "i"라고도 합니다.마디".

mknod()장치에 대한 특수 파일을 생성하기 위한 호출 컨텍스트를 제외하고는 "i" 없이 파일을 일반 "노드"로 참조하는 경우는 거의 없습니다 .

장치 파일은 데이터를 포함하지 않는 특수 파일이지만 대신 이러한 장치 파일에 대한 액세스를 처리하는 커널 드라이버를 식별하는 숫자가 있습니다.

드라이버는 유용한 작업을 수행하는 커널의 소프트웨어 조각입니다. 실제 하드웨어(예: 직렬 포트)에 대한 액세스를 제공할 수도 /dev/ttyS0있고 제공하지 않을 수도 있습니다 /dev/zero.

실제 장치는 물론 물리적 하드웨어, 커넥터 및 칩입니다.

물론, 혼동을 주기 위해 이러한 "장치 파일"을 간단히 "장치"라고 부르겠습니다.

따라서 /dev/ttyS0주:부 장치 번호가 64:0인 문자 특수 파일인 파일 시스템 노드는 직렬 드라이버에 의해 처리되는 장치로 식별되며 일부 물리적 장치에 액세스하며 16550 UART와 유사할 수 있습니다. 칩.

답변3

장치는 메이저 번호와 마이너 번호의 조합이라고 할 수 있습니다. 이 조합은 고정되어 있으며 변경할 수 없습니다. 이 조합은 장치 파일의 일부입니다. 애플리케이션은 장치 파일을 열고 해당 번호 조합을 통해 장치로 연결됩니다.

메이저 및 마이너 번호와 달리 장치 파일 이름은 이론적으로 무작위로 지정됩니다. /dev/sda커널 장치 이름을 가리키는 파일을 생성할 수 있습니다 sdb.

답변4

Dalton 씨의 답변이 길었음에도 불구하고 이 책은 여전히 ​​여러분을 혼란스럽게 만듭니다. 이 책은 당신을 오해했습니다. 책에 이런 내용이 있네~해야 한다설명하다:

커널 가상 터미널, 병렬 포트 및 직렬 포트는 스트림 추상화로 잘 표현될 수 있으므로 문자 장치의 예입니다. 문자 장치는 /dev/tty1(첫 번째 커널 가상 터미널 열기), /dev/lp0(첫 번째 병렬 포트 열기), /dev/ttyS0(첫 번째 직렬 포트 열기) 와 같은 파일 시스템 노드를 통해 열립니다 .

사실, 그것은 전혀 논의되어서는 안 됩니다 /dev/console. 이 두 가지 모두 /dev/tty너무 복잡하여 기본 예제로 사용할 수 없습니다. (M. Dalton은 현명하게도 이를 사용하지 않았다는 점에 유의하십시오.) 또한 문자 장치를 여는 데에도 사용되지만,어떤거야?문자 장치는 앞서 언급한 KVT, 직렬 포트 및 병렬 포트보다 더 복잡합니다. 특히 콘솔에는 파일 시스템 노드 이름처럼 보이지만 그렇지 않은 두 번째 이름 세트가 도입되었습니다.

추가 읽기

관련 정보