<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Move Fast</title>
    <link>https://movefast.tistory.com/</link>
    <description>Like.</description>
    <language>ko</language>
    <pubDate>Tue, 16 Jun 2026 15:25:12 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>r4v3n-k</managingEditor>
    <image>
      <title>Move Fast</title>
      <url>https://tistory1.daumcdn.net/tistory/2730167/attach/9a4344ef20c24726b76a9747cdd04483</url>
      <link>https://movefast.tistory.com</link>
    </image>
    <item>
      <title>깃헙 로컬 유저와 원격 유저가 연동되지 않는 문제</title>
      <link>https://movefast.tistory.com/352</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 깃헙 인증 방식이 바뀌어서 SSH 로 인증하려고 했음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로 로컬 유저와 리모트 유저가 다른 유저 권한으로 저장소에 액세스 하는 문제가 생김&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1234&quot; data-origin-height=&quot;920&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8bHwD/btrgRUCPINZ/ZuYUukkzrKBV5mAhT3Ka70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8bHwD/btrgRUCPINZ/ZuYUukkzrKBV5mAhT3Ka70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8bHwD/btrgRUCPINZ/ZuYUukkzrKBV5mAhT3Ka70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8bHwD%2FbtrgRUCPINZ%2FZuYUukkzrKBV5mAhT3Ka70%2Fimg.png&quot; data-origin-width=&quot;1234&quot; data-origin-height=&quot;920&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결책은 SSH 키에 -C 옵션과 config 파일을 설정함으로써 해결&lt;/p&gt;
&lt;pre id=&quot;code_1633390647563&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ssh-keygen -t rsa -C &quot;github_email_address&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;config 파일 내용은 다음과 같음&lt;/p&gt;
&lt;pre id=&quot;code_1633390641786&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Host github.com-ke2ek
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_rs&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 push 하기 전에 global 설정으로 유저이름과 메일을 설정해주어야 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git config -l --global 로 확인해보면 다음과 같다. 향후 https 접근을 모두 ssh 로 바꿔주기&lt;/p&gt;
&lt;pre id=&quot;code_1633390696232&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;url.git@github.com:ke2ek.insteadof=https://github.com/ke2ek
user.name=사용자 이름
user.email=깃헙 메일&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Note</category>
      <author>r4v3n-k</author>
      <guid isPermaLink="true">https://movefast.tistory.com/352</guid>
      <comments>https://movefast.tistory.com/352#entry352comment</comments>
      <pubDate>Tue, 5 Oct 2021 08:39:11 +0900</pubDate>
    </item>
    <item>
      <title>2021 상반기 네이버 신입공채</title>
      <link>https://movefast.tistory.com/351</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;지원서&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요한 문항은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;학교 수업 과정에서 의미있었던 과목 5개를 설명&lt;/li&gt;
&lt;li&gt;프로젝트 경험 및 문제 해결 방법을 자유롭게 쓰는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과목은 A/A+ 받은 전공 과목만 썼고, 프로젝트 경험은 코드까지 붙여가면서 음슴체(...)로 6000자를 채웠다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서류 합격자들 말에 따르면 1000자도 안 적은 사람들이 있다고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코딩테스트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전부터 구글 코드잼 준비 때문에 알고리즘 공부를 하긴 했으나, 국내 대기업들의 코딩 테스트는 구글 것과는 차이가 있다. 수학적인 능력보다 실무에 집중된 문제라는 점이다. 예를 들어, 해시 테이블, 이분 탐색, 슬라이딩 윈도우 등의 문제가 주로 나오며 DFS/BFS나 DP의 비율은 낮은 편이다. 이전 공채에서 투 포인터 알고리즘도 나왔다길래 공부했는데 전혀 도움이 되지 않았다. (언젠간 쓰이겠지..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 비슷한 성향이 있는 카카오의 프로그래머스 페이지 Lv3과 Lv4를 2번 정도 풀었다. (풀이를 외웠다고 보는게 맞겠다) 난이도는 비슷하거나 더 낮았는데 마지막 문제는 DFS로 정말 노가다여서 결국 남은 시간 안에 못풀었다. (제출하려고 했는데 끝났다...)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 문제 못 풀긴 했는데 통과였다. 두 문제 못풀어도 통과한 사람들이 있다고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1차 면접&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 블로그에 운영체제/데이터베이스/네트워크/머신러닝 등 정리해놓은 글들이 있는데, 이거를 다시 정리해서 달달달 외웠다. (그냥 버튼 누르면 튀어나오듯이...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 너무 달달외워가서 더 이상 질문을 안하셨다 ㅋㅋㅋㅋ........ (넘하잖아)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;면접은 생각보다 어려웠고, 암기해서 내뱉는 기본 지식보다는 프로그래밍을 얼마나 이해하고 있는지 테스트하는 느낌이었다. 그 외에 수학/CS 질문도 받았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 알려줄 수 없지만, 본인이 충실하게 &lt;u&gt;기초 수학(필수)과 기초 알고리즘(필수)&lt;/u&gt;을 공부했다면 충분히 통과할 수 있는 면접이었다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;모르겠다&quot;는 말을 어떤 면접보다 많이 했었지만, 면접관 분들은 개의치 않고 조금 더 생각해보라고 이야기했다.&lt;/li&gt;
&lt;li&gt;정말 말 그대로 &quot;생각해야 하는 문제&quot;를 낸다. 그리고 본인의 논리를 잘 설명해야 통과하는 듯 하다.&lt;/li&gt;
&lt;li&gt;인성검사는 답 못하고 넘어간 것도 있는데 (제한시간 넘 적음..) 문제될 사유가 없다면 상관없는 듯 하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2차 면접&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 면접은 리더급 두 분과 자기소개서 기반 종합면접이었다. 근데 30분? 정도 걸렸는데 이게 정말 역대급이다. 별걸 다 묻는다. 나 혼자 갈등 경험 정리하고 그랬는데.. 4일 내내 달달 외우던거 쓸모 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 자기소개서는 대부분 기술기반 경험이었고, 그렇기에 1차 면접보다 더 실무에 가까운 질문을 받았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 외 지원 동기나 인턴 경험 관련 질문도 받았는데, 질문 자체가 명확하지 않고 두루뭉실하기 때문에 본인이 조리있게 설명해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;창의 수학 문제도 냈다 ㅋㅋ ㅠ.. (왜 내신건지 잘 모르겠다.) 순간 멍해져서 &quot;생각 할 시간을 주세요.&quot; 그러고 5분~10분 정도 고민했다. 맞췄으니 다행이지 말도 못했으면 답도 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로, 본인이 생각하는 &lt;u&gt;엔지니어링에 대한 가치관&lt;/u&gt;을 잘 정립해가면 도움이 많이 된다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 경우는 최소 비용으로 원하는 시스템을 구축하는 것이었고 이를 위해 알고리즘뿐만 아니라 CS기초지식을 바탕으로 여러 기술 스택을 비교하고 더 나은 방법을 선택하기 위해 많은 경험이 필요하다고 답했었다. 그러기 위해 네이버라는 회사는 큰 데이터셋을 가지기 때문에 도움이 될 거라고 말했다. 회사를 위한다기 보다 내 커리어 패스에 관한 이야기였다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1차 면접에서 문제를 못풀면 그걸 다시 물어본다고 한다. 아마 내 경우는 다 풀어서 면접 시간이 짧았던 거 같다.&lt;/li&gt;
&lt;li&gt;자기소개서에 협업 관련 경험을 적어놓았다면, 높은 확률로 인성 질문을 받을 것이다. 예를 들어, 갈등 경험&lt;/li&gt;
&lt;li&gt;인성 관련 질문 왜 안하냐고 물었더니, 면접관이 보고자 하는 것은 그 사람의 인성이 아니라 얼마나 끈기 있게 해왔는지를 본다고 했다.&lt;/li&gt;
&lt;li&gt;압박 면접이었다. 이건 지나가는 개를 붙잡고 물어봐도 맞다고 할거다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;후기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대기업, 중소기업, 난다긴다하는 스타트업 등 면접 많이 봤었는데 생각보다 네이버가 제일 어려웠다. IT대기업이다 보니 신입 공채에서 실무 질문은 안할 줄 알았다. 근데 기초/실무/수학/CS/커리어 패스/가치관 등등 별걸 다 물었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;마냥 열심히 하기 보다 어떤 목적과 목표를 가지고 공부를 해왔는지 보고 싶어 하는 듯하다.&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그러나 모든 면접이 그렇듯 대답 못하는 것이 존재할 수 밖에 없고, 대답 못하더라도 적절한 긴장감으로, 느리더라도 자신의 생각을 명확하게 이야기해야 될 것이다. (그렇게 못해서 떨어진게 한 두번이 아니다....ㅜ)&lt;/li&gt;
&lt;li&gt;네이버 면접은 후기를 찾기가 어려워서 기록용으로 남겼다. 다만, 문제는 발설할 수 없기 때문에 그 때의 느낌만 적어보았다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;1472&quot; data-filename=&quot;Screen Shot 2021-07-15 at 18.47.50.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Fia5T/btrbwgYNgkK/aaIR0HcRCVfq4HHrzLJbxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Fia5T/btrbwgYNgkK/aaIR0HcRCVfq4HHrzLJbxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Fia5T/btrbwgYNgkK/aaIR0HcRCVfq4HHrzLJbxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFia5T%2FbtrbwgYNgkK%2FaaIR0HcRCVfq4HHrzLJbxK%2Fimg.png&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;1472&quot; data-filename=&quot;Screen Shot 2021-07-15 at 18.47.50.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Review</category>
      <category>네이버</category>
      <category>면접후기</category>
      <category>신입공채</category>
      <category>후기</category>
      <author>r4v3n-k</author>
      <guid isPermaLink="true">https://movefast.tistory.com/351</guid>
      <comments>https://movefast.tistory.com/351#entry351comment</comments>
      <pubDate>Thu, 5 Aug 2021 16:58:12 +0900</pubDate>
    </item>
    <item>
      <title>리눅스 커널 - 네트워크</title>
      <link>https://movefast.tistory.com/350</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;본 글은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;http://wiki.kldp.org/Translations/html/The_Linux_Kernel-KLDP/The_Linux_Kernel-KLDP.html&quot;&gt;The Linux Kernel&lt;/a&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;을 정리한 것이며, 출처를 밝히지 않은 모든 이미지는 원글에 속한 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;TCP/IP 네트워크 개요&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;766&quot; height=&quot;388&quot; data-origin-width=&quot;870&quot; data-origin-height=&quot;441&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k1Upr/btq6Ft4chbX/tBC0iDJk2Tjzzkn9jDKfbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k1Upr/btq6Ft4chbX/tBC0iDJk2Tjzzkn9jDKfbk/img.png&quot; data-alt=&quot;이더넷 프레임&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k1Upr/btq6Ft4chbX/tBC0iDJk2Tjzzkn9jDKfbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk1Upr%2Fbtq6Ft4chbX%2FtBC0iDJk2Tjzzkn9jDKfbk%2Fimg.png&quot; width=&quot;766&quot; height=&quot;388&quot; data-origin-width=&quot;870&quot; data-origin-height=&quot;441&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이더넷 프레임&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;월드 와이드 웹(이하 WWW)은 거대한 IP 네트워크로, 연결된 기계들은 할당된 고유한 &lt;b&gt;IP 주소(32비트 숫자)&lt;/b&gt;로 식별됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IP 주소는 네트워크 주소와 호스트 주소로 나누어 구분할 수 있음&lt;/li&gt;
&lt;li&gt;호스트 주소는 서브넷(subnetwork, subnet)과 호스트 주소로 더 자세히 나눌 수 있으며, 네트워크를 사용하는 기관은 자신의 네트워크를 몇 구획으로 나눌 수 있음&lt;/li&gt;
&lt;li&gt;네트워크 관리자는 IP 주소를 할당할 때, IP 서브넷을 사용하여 네트워크 관리 부담을 분산시킴&lt;/li&gt;
&lt;li&gt;IP 서브넷 관리자는 자신의 IP 서브넷 내에서 자유롭게 IP 주소를 할당&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;576&quot; width=&quot;667&quot; height=&quot;314&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btOaz3/btq6NbBjjWz/BEE6sZLy764h8AdH5GDyc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btOaz3/btq6NbBjjWz/BEE6sZLy764h8AdH5GDyc1/img.png&quot; data-alt=&quot;https://www.slideshare.net/hugolu/the-linux-networking-architecture&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btOaz3/btq6NbBjjWz/BEE6sZLy764h8AdH5GDyc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtOaz3%2Fbtq6NbBjjWz%2FBEE6sZLy764h8AdH5GDyc1%2Fimg.png&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;576&quot; width=&quot;667&quot; height=&quot;314&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.slideshare.net/hugolu/the-linux-networking-architecture&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IP 주소는 숫자가 많아 외우기 어려우며, 문자열로 된 네트워크 이름을 부여해 기계들은 통신 할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;네트워크 이름을 IP 주소로 변환해주는 작업은, /etc/hosts 파일에 정적으로 명시하거나 분산 네임 서버(Distributed Name Server, DNS)에 변환 요청을 보내서 처리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로컬 호스트는 하나 이상의 DNS 서버의 IP 주소를 알고 있어야 하며, 이 주소들을 /etc/resolv.conf 에 기록&lt;/li&gt;
&lt;li&gt;웹 페이지를 읽을 때처럼 다른 호스트(서버)에 접속할 때, 데이터를 교환하기 위해 접속할 대상의 IP 주소를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터들은 IP 패킷(packet)에 담겨 전달되며, 각 패킷마다 출발지 호스트와 목적지 호스트의 IP 주소, 체크섬(checksum) 및 IP 헤더가 추가됨&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;체크섬은 IP 패킷에 있는 데이터를 가지고 계산한 것으로, IP 패킷 수신자(목적지 호스트)는 전화선의 잡음 등에 의해 전달 중에 패킷이 손상되었는지 판단&lt;/li&gt;
&lt;li&gt;데이터는 다루기 쉽게 작은 패킷들로 쪼개져서 보내질 수 있고, 목적지 호스트는 패킷들을 다시 조합하여 프로세스에게 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1182&quot; data-origin-height=&quot;574&quot; width=&quot;393&quot; height=&quot;191&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0re6v/btq6PDKZvld/8oXsYQk5olo8QasVgOoeIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0re6v/btq6PDKZvld/8oXsYQk5olo8QasVgOoeIK/img.png&quot; data-alt=&quot;https://www.slideshare.net/hugolu/the-linux-networking-architecture&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0re6v/btq6PDKZvld/8oXsYQk5olo8QasVgOoeIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0re6v%2Fbtq6PDKZvld%2F8oXsYQk5olo8QasVgOoeIK%2Fimg.png&quot; data-origin-width=&quot;1182&quot; data-origin-height=&quot;574&quot; width=&quot;393&quot; height=&quot;191&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.slideshare.net/hugolu/the-linux-networking-architecture&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;같은 IP 서브넷에 있는 호스트끼리는 IP 패킷을 직접 보낼 수 있지만, 그렇지 않으면 게이트웨이(gateway) 또는 라우터(router)라고 하는 특별한 호스트에 IP 패킷을 전송 (게이트웨이나 라우터는 한 IP 서브넷에서 다른 IP 서브넷으로 패킷을 전달하는 역할)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;각 호스트들은 정확한 목적지로 IP 패킷을 전달하기 위해 &lt;u&gt;라우팅 테이블(routing table)&lt;/u&gt;을 작성해서 다음 도착지로 패킷을 전달
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;라우팅 테이블에는 모든 IP 목적지에 대해 다음 도착지를 결정하는데 필요한 정보를 포함&lt;/li&gt;
&lt;li&gt;이 테이블은 동적으로 변경되는데, 네트워크를 사용하거나 네트워크 구성도가 변경되면 시간이 지나면서 바뀜&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;TCP 프로토콜은 신뢰할 수 있는 일대일 프로토콜로, 데이터를 주고 받기 위해 IP 프로토콜을 사용하며, IP 프로토콜은 TCP 외에 다른 프로토콜이 데이터를 보낼 때 사용하는 전송 계층&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IP 패킷에 헤더가 붙는 것처럼 TCP 패킷에도 헤더가 추가됨&lt;/li&gt;
&lt;li&gt;TCP 프로토콜로 통신하는 두 프로세스는 통신 과정에서 많은 서브넷, 게이트웨이, 라우터가 있더라도 하나의 가상 접속으로 연결됨 (&lt;u&gt;연결 지향 프로토콜&lt;/u&gt;)&lt;/li&gt;
&lt;li&gt;TCP 프로토콜은 데이터의 손실이나 중복이 없다는 것을 보장 (&lt;u&gt;신뢰할 수 있는 프로토콜&lt;/u&gt;)&lt;/li&gt;
&lt;li&gt;TCP 프로토콜이 IP 프로토콜을 통해 TCP 패킷을 전송할 때, TCP 패킷에 헤더까지 포함된 것이 IP 패킷의 데이터&lt;/li&gt;
&lt;li&gt;서로 통신하고 있는 호스트의 IP 계층은 IP 패킷을 주고 받는 역할 (받을 때는 헤더를 제거한 데이터를 TCP 계층으로 보냄)&lt;/li&gt;
&lt;li&gt;UDP 프로토콜은 TCP 프로토콜과는 달리 신뢰할 수 없는 프로토콜로, IP 계층을 사용하여 데이터그램(datagram) 서비스를 제공하는데 패킷의 순서와 도착을 보장하지 않음&lt;/li&gt;
&lt;li&gt;IP 프로토콜은 IP 패킷에 담긴 데이터를 전달할 상위 프로토콜을 결정하기 위해 모든 IP 패킷 헤더에 프로토콜 식별자를 지정하는 바이트가 존재 (e.g., TCP라면 IP 패킷 헤더에 데이터가 TCP 패킷인 것을 기록)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로그램이 TCP/IP 계층으로 통신할 때, 프로세스는 상대 IP 주소 외에 포트(port)도 명시해야 함&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;포트 번호는 프로세스마다 유일한 것으로, 표준 네트워크 프로세스는 표준 포트 번호를 사용 (e.g., 웹서버의 경우 80번)&lt;/li&gt;
&lt;li&gt;등록된 포트 번호는 /etc/services 파일에서 확인 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프로토콜의 계층 구조는 TCP/UDP 및 IP로 구분하지 않고, IP 프로토콜 자체도 패킷을 전달하는데 여러 장치를 사용하기 때문에 각 장치에서 각자의 프로토콜 헤더를 추가하기도 함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어, 이더넷 네트워크에서 많은 호스트가 실제로 하나의 케이블에 동시에 접속할 수 있으므로, 전송되는 모든 이더넷 프레임은 연결된 모든 호스트에게 보여짐 (단, 모든 이더넷 장치는 고유한 주소를 가짐)&lt;/li&gt;
&lt;li&gt;호스트는 자기 주소로 전달되는 모든 이더넷 프레임을 받아들이지만, 같은 네트워크에 연결된 다른 호스트들은 이들을 무시&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이더넷 주소는 6바이트 길이로 (흔히 MAC 주소로 알려진), &quot;08-00-2B-00-49-A4&quot;와 같은 형식&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;어떤 이더넷 주소는 멀티캐스트(multicast) 목적으로 예약되어 있어, 이 주소로 보내지는 이더넷 프레임들은 같은 네트워크 안에 있는 모든 호스트가 수신함&lt;/li&gt;
&lt;li&gt;이더넷 프레임은 데이터로 수많은 프로토콜들을 전송할 수 있기 때문에, 헤더에 프로토콜 식별자가 존재하며, 이더넷 계층은 정확하게 IP 패킷을 IP 계층에 전달 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이더넷 같은 다중 접속 프로토콜을 통해 IP 패킷을 보내려면, IP 계층은 IP 호스트의 이더넷 주소를 탐색 (IP 주소는 개념적 주소이며, 이더넷 장치는 고유한 물리적 주소를 가짐)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IP 주소는 네트워크 관리자에 의해 지정되고 변경될 수 있으나, 네트워크 하드웨어는 각자의 물리적 주소 또는 멀티캐스트 주소에만 반응함 (즉, 이더넷 주소는 변경할 수 없음)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;IP 주소를 이더넷 주소 같은 실제 하드웨어 주소로 변환하는 작업은, 주소 변환 프로토콜(ARP)을 사용해서 처리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;변환하고자 하는 IP 주소가 담긴 ARP 요청 패킷을 멀티캐스트 주소로 보내 모든 연결된 호스트에 전달&lt;/li&gt;
&lt;li&gt;그 IP 주소를 가지고 있는 호스트는 자신의 하드웨어 주소를 ARP 응답 패킷에 담아서 응답&lt;/li&gt;
&lt;li&gt;ARP 요청이 불가능한 장치들은 별도로 표시하여 ARP를 시도하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;하드웨어 주소를 IP 주소로 변환하는 작업은, RARP를 사용해서 처리. 보통 이 기능은 게이트웨이가 사용하며, 원격 네트워크에 있는 IP 주소를 대신해서 게이트웨이가 ARP 요청에 응답&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;584&quot; height=&quot;220&quot; data-origin-width=&quot;1196&quot; data-origin-height=&quot;450&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSxPcW/btq6HQZeXk4/J2GhRUNjdzrADlhA6rJZHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSxPcW/btq6HQZeXk4/J2GhRUNjdzrADlhA6rJZHk/img.png&quot; data-alt=&quot;https://slidetodoc.com/chapter-8-arp-and-rarp-objectives-upon-completion/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSxPcW/btq6HQZeXk4/J2GhRUNjdzrADlhA6rJZHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSxPcW%2Fbtq6HQZeXk4%2FJ2GhRUNjdzrADlhA6rJZHk%2Fimg.png&quot; width=&quot;584&quot; height=&quot;220&quot; data-origin-width=&quot;1196&quot; data-origin-height=&quot;450&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://slidetodoc.com/chapter-8-arp-and-rarp-objectives-upon-completion/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;리눅스의 TCP/IP 네트워크 계층&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;652&quot; height=&quot;724&quot; data-origin-width=&quot;653&quot; data-origin-height=&quot;725&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LyDbx/btq6MyC1sJw/yCzSUpPOByw8b6LmMOj4J0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LyDbx/btq6MyC1sJw/yCzSUpPOByw8b6LmMOj4J0/img.png&quot; data-alt=&quot;리눅스 네트워크 계층&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LyDbx/btq6MyC1sJw/yCzSUpPOByw8b6LmMOj4J0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLyDbx%2Fbtq6MyC1sJw%2FyCzSUpPOByw8b6LmMOj4J0%2Fimg.png&quot; width=&quot;652&quot; height=&quot;724&quot; data-origin-width=&quot;653&quot; data-origin-height=&quot;725&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;리눅스 네트워크 계층&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리눅스는 인터넷 프로토콜 주소 패밀리를 일련의 연관된 소프트웨어 계층으로 구현&lt;/li&gt;
&lt;li&gt;&lt;b&gt;BSD Sockets 계층&lt;/b&gt;&amp;nbsp;일반적인 소켓 관리 소프트웨어가 BSD 소켓만 처리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;INET Sockets 계층&lt;/b&gt;&amp;nbsp;소켓 관리 소프트웨어를 지원하는데, IP 기반 프로토콜인 TCP/UDP의 통신 종점을 관리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TCP(Transmission Control Protocol)&lt;/b&gt; 연결 지향의 신뢰할 수 있는 일대일 프로토콜 (TCP 패킷들에 번호를 매겨 종점 호스트는 데이터를 수신할 때 패킷 순서 및 손실을 확인)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1040&quot; data-origin-height=&quot;772&quot; width=&quot;542&quot; height=&quot;403&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dgi25E/btq6Hj1F391/XdKYFY09gWkNEpCVCicYbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dgi25E/btq6Hj1F391/XdKYFY09gWkNEpCVCicYbk/img.png&quot; data-alt=&quot;https://www.slideshare.net/hugolu/the-linux-networking-architecture&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dgi25E/btq6Hj1F391/XdKYFY09gWkNEpCVCicYbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdgi25E%2Fbtq6Hj1F391%2FXdKYFY09gWkNEpCVCicYbk%2Fimg.png&quot; data-origin-width=&quot;1040&quot; data-origin-height=&quot;772&quot; width=&quot;542&quot; height=&quot;403&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.slideshare.net/hugolu/the-linux-networking-architecture&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;UDP(User Datagram Protocol)&lt;/b&gt;&amp;nbsp;비연결지향 방식의 프로토콜 (패킷이 전송 시 제대로 도착했는지 확인 불가)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;IP 계층&lt;/b&gt;&amp;nbsp;인터넷 프로토콜을 구현한 계층으로, 전송하는 데이터 앞에 IP 헤더를 붙이고, 들어오는 IP 패킷의 헤더를 제거하여 TCP나 UDP로 전달&lt;/li&gt;
&lt;li&gt;IP 계층 아래의 PPP 또는 이더넷 같은 네트워크 장치들이 리눅스의 모든 네트워킹을 지원하며, 네트워크 장치는 항상 물리 장치를 가리키는 것이 아니라 루프백 장치 같은 몇몇 순수 소프트웨어로 작성된 것도 존재
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네트워크 장치는 다른 장치들과 달리 관련 소프트웨어가 장치를 찾아 초기화해야 장치 파일로 보여짐&lt;/li&gt;
&lt;li&gt;해당 이더넷 디바이스 드라이버를 추가하여 커널을 빌드해야만 /dev/eth0 를 볼 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;926&quot; data-origin-height=&quot;716&quot; width=&quot;664&quot; height=&quot;513&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eJPLug/btq6L34k2d0/155YoBhA17twd0JokdnopK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eJPLug/btq6L34k2d0/155YoBhA17twd0JokdnopK/img.png&quot; data-alt=&quot;https://www.educative.io/edpresso/tcp-vs-udp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eJPLug/btq6L34k2d0/155YoBhA17twd0JokdnopK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeJPLug%2Fbtq6L34k2d0%2F155YoBhA17twd0JokdnopK%2Fimg.png&quot; data-origin-width=&quot;926&quot; data-origin-height=&quot;716&quot; width=&quot;664&quot; height=&quot;513&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.educative.io/edpresso/tcp-vs-udp&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;BSD 소켓 인터페이스&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다양한 형태의 네트워킹 외에 프로세스간 통신도 지원하는 일반적인 인터페이스&lt;/li&gt;
&lt;li&gt;통신하고 있는 두 프로세스는 연결 시, 데이터를 주고 받기 위한 소켓을 가지며, 파이프와 달리 소켓은 저장가능한 데이터 용량이 제한되지 않음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주소 패밀리(Address Family)&lt;/b&gt; 소켓의 클래스, 각 클래스별로 통신에 사용하는 주소 표현법을 가짐
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;UNIX&lt;/b&gt;&amp;nbsp;유닉스 도메인 소켓&lt;/li&gt;
&lt;li&gt;&lt;b&gt;INET&lt;/b&gt;&amp;nbsp;TCP/IP 프로토콜을 이용한 통신을 지원하는 인터넷 주소 패밀리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;AX25&lt;/b&gt;&amp;nbsp;아마추어 라디오 X.25&lt;/li&gt;
&lt;li&gt;&lt;b&gt;IPX&lt;/b&gt; 노벨의 IPX 프로토콜&lt;/li&gt;
&lt;li&gt;&lt;b&gt;APPLETALK&lt;/b&gt; 애플사의 Appletalk DDP 프로토콜&lt;/li&gt;
&lt;li&gt;&lt;b&gt;X25&lt;/b&gt;&amp;nbsp;X.25 프로토콜&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;소켓에는 접속을 지원하는 서비스의 종류를 나타내는 타입이 존재 (모든 주소 패밀리가 모든 형태의 서비스를 지원하지는 않음)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Stream&lt;/b&gt;&amp;nbsp;이 소켓은 데이터가 전송 중 분실, 오염, 또는 중복되지 않는다는 것을 보장하는 신뢰성 있는 양방향 순차 데이터 스트림&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Datagram&lt;/b&gt;&amp;nbsp;이 소켓은 양방향 데이터 전송을 제공하나, 메시지 도착 유무, 순서 보장, 중복 제거, 오염 유무 등을 보장하지 않음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Raw&lt;/b&gt;&amp;nbsp;프로세스가 하부 프로토콜에 직접 접근 가능. 이더넷 장치에 이 소켓을 열어 가공되지 않은 IP 데이터 흐름을 볼 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Reliable Delivered Messages&lt;/b&gt;&amp;nbsp;데이터그램 소켓과 유사하지만, 데이터가 목적지에 도착한다는 것을 보장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Sequenced Packets&lt;/b&gt;&amp;nbsp;스트림 소켓과 유사하며, 데이터 패킷 크기가 고정됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Packet&lt;/b&gt;&amp;nbsp;표준 BSD 소켓 타입이 아니며, 장치 수준에서 프로세스가 직접 패킷에 접근할 수 있는 확장 패킷 유형&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;소켓을 사용하여 통신하는 프로세스는 &lt;u&gt;클라이언트 서버 모델&lt;/u&gt;을 따르며, 서버는 서비스를 제공하고, 클라이언트는 이 서비스를 이용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버는 먼저 소켓을 생성하여 이름(소켓 주소 패밀리에 따라 다르며 대개 로컬 주소)을 bind한 후, 소켓의 이름 또는 주소를 sockaddr 구조체에 명시 (INET 소켓은 그것에 바인드된 IP 포트 번호를 가짐)&lt;/li&gt;
&lt;li&gt;서버는 바인드된 주소를 가리키는 연결 요청이 들어오는 listen&lt;/li&gt;
&lt;li&gt;클라이언트는 소켓을 생성하여 서버의 주소를 명시하여 서버측 소켓에 대해 연결 요청 (INET 소켓의 경우 포트 번호를 포함)&lt;/li&gt;
&lt;li&gt;연결 요청은 다양한 프로토콜 계층을 통해 전달되어 서버의 소켓에 도달하고, 서버는 요청을 받고 수락(accept) 또는 거절(reject) 할 수 있음&lt;/li&gt;
&lt;li&gt;요청을 받아들이면, 새로운 소켓을 생성 (listen 소켓은 연결 요청을 받아들이는데만 사용 가능)&lt;/li&gt;
&lt;li&gt;연결이 성립되면, 서버와 클라이언트는 자유롭게 데이터를 주고 받음&lt;/li&gt;
&lt;li&gt;연결이 필요없는 경우, 소켓을 종료(shutdown)하며, 이때 전송 중인 데이터 처리에 유의해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;565&quot; data-origin-height=&quot;732&quot; width=&quot;597&quot; height=&quot;773&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBEO23/btq6CN9ZoVb/OQVZtjRRbRHjONMPk8JR0K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBEO23/btq6CN9ZoVb/OQVZtjRRbRHjONMPk8JR0K/img.jpg&quot; data-alt=&quot;https://rastating.github.io/using-socket-reuse-to-exploit-vulnserver/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBEO23/btq6CN9ZoVb/OQVZtjRRbRHjONMPk8JR0K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBEO23%2Fbtq6CN9ZoVb%2FOQVZtjRRbRHjONMPk8JR0K%2Fimg.jpg&quot; data-origin-width=&quot;565&quot; data-origin-height=&quot;732&quot; width=&quot;597&quot; height=&quot;773&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://rastating.github.io/using-socket-reuse-to-exploit-vulnserver/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커널 초기화 과정에서 커널에 구현된 주소 패밀리는 BSD 소켓 인터페이스와 함께 커널에 자신을 등록&lt;/li&gt;
&lt;li&gt;프로세스가 BSD 소켓을 만들어 사용할 때, BSD 소켓과 지원하는 주소 패밀리 사이의 연관관계는 connection 자료구조와 주소 패밀리 고유의 지원 루틴 테이블을 통해 생성 (프로그램이 새 소켓을 생성할 때, 주소 패밀리 고유의 소켓 생성 루틴이 존재)&lt;/li&gt;
&lt;li&gt;커널을 설정할 때 주소 패밀리와 프로토콜을 protocols 배열에 추가. 이&amp;nbsp;배열에는 각 주소 패밀리 또는 프로토콜의 이름(e.g., INET)과 초기화 루틴이 포함되어 있음&lt;/li&gt;
&lt;li&gt;부팅 시 소켓 인터페이스를 초기화할 때, 각 프로토콜의 초기화 루틴이 호출되고, 소켓 주소 패밀리마다 일련의 프로토콜 연산 루틴을 등록 (이것은 루틴들의 집합이며, 각 루틴은 해당 주소 패밀리의 고유한 특정 연산을 수행)&lt;/li&gt;
&lt;li&gt;proto_ops 구조체는 주소 패밀리 타입과 특정 주소 패밀리에 고유한 소켓 연산 루틴에 대한 포인터들의 집합으로 구성됨&lt;/li&gt;
&lt;li&gt;pops 배열은 인터넷 주소 패밀리 같은 (AF_INET은 2) 주소 패밀리 식별자로 인덱싱&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;658&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cU0hMz/btq6NtnVpy1/zzt3Lk5JABxcMGBkKQtzsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cU0hMz/btq6NtnVpy1/zzt3Lk5JABxcMGBkKQtzsk/img.png&quot; data-alt=&quot;https://slidetodoc.com/socket-layer-coms-w-6998-spring-2010-erich/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cU0hMz/btq6NtnVpy1/zzt3Lk5JABxcMGBkKQtzsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcU0hMz%2Fbtq6NtnVpy1%2Fzzt3Lk5JABxcMGBkKQtzsk%2Fimg.png&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;658&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://slidetodoc.com/socket-layer-coms-w-6998-spring-2010-erich/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;INET 소켓 계층&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TCP/IP 프로토콜을 포함하는 인터넷 주소 패밀리를 지원, 한 프로토콜이 다른 프로토콜의 서비스를 이용하며, 리눅스 TCP/IP 코드와 자료구조는 프로토콜들의 계층 구조를 반영&lt;/li&gt;
&lt;li&gt;BSD 소켓 계층과의 인터페이스는 네트워크 초기화 중에 BSD 소켓 계층에 등록한 인터넷 주소 패밀리 소켓 함수들의 집합
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BSD 소켓 계층에서 pops 배열에 등록된 다른 주소 패밀리와 함께 보관됨&lt;/li&gt;
&lt;li&gt;BSD 소켓 계층은 등록된 INET proto_ops 구조체로부터 INET 계층의 소켓 지원 루틴을 호출하여 작업&lt;/li&gt;
&lt;li&gt;주소 패밀리에 INET을 주고 BSD 소켓 생성을 요구하면, 이는 하위 INET 소켓 생성 함수를 호출&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;BSD 소켓 계층은 각 함수를 호출할 때마다 INET 계층에 있는 BSD 소켓을 나타내는 socket 구조체를 전달하고, socket 구조체에 있는 data 포인터는 sock 구조체를 참조하는데, 이 구조체는 INET 소켓 계층에서 사용됨&lt;/li&gt;
&lt;li&gt;sock 구조체의 프로토콜 함수 포인터는 생성 시 설정되는 것으로, 요구한 프로토콜에 따라 다름.&amp;nbsp;만약 TCP를 요구했다면, 프로토콜 함수 포인터는 TCP 연결을 위해 필요한 TCP 프로토콜 함수 집합을 참조&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;686&quot; height=&quot;694&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;801&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sF2wM/btq6MctyzWX/q0cZHBnThVa7mgcWFq1ef1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sF2wM/btq6MctyzWX/q0cZHBnThVa7mgcWFq1ef1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sF2wM/btq6MctyzWX/q0cZHBnThVa7mgcWFq1ef1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsF2wM%2Fbtq6MctyzWX%2Fq0cZHBnThVa7mgcWFq1ef1%2Fimg.png&quot; width=&quot;686&quot; height=&quot;694&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;801&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;BSD 소켓 생성&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새 소켓을 만드는 시스템 콜에는 주소 패밀리 식별자, 소켓 타입, 프로토콜을 인자로 넘겨야 하며, 요구한 주소 패밀리를 사용하여 pops 배열에서 일치하는 주소 패밀리를 탐색
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 주소 패밀리는 커널 모듈에 의해 생성되었기 때문에, kerneld 데몬이 이 모듈을 이용해서 주소 패밀리를 탐색&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;BSD 소켓을 나타내기 위해 새 socket 구조체를 할당. 이 구조체는 VFS inode 구조체의 일부이며 실제로 VFS inode를 할당하는 것과 같음 (이는 소켓이 일반 파일과 동일하게 작동하게 하며, 파일 함수들을 이용해 소켓을 열고, 닫고, 읽고, 쓸 수 있음)&lt;/li&gt;
&lt;li&gt;socket 구조체는 주소 패밀리에 따라 특수한 소켓 루틴들에 대한 포인터를 포함하며, pops 배열에서 얻을 수 있는 proto_ops 구조체에 이 포인터들이 설정됨 (타입은 요구한 소켓 타입으로 설정: SOCK_STREAM 또는 SOCK_DGRAM 등)&lt;/li&gt;
&lt;li&gt;proto_ops 구조체에 있는 주소를 호출하면, 주소 패밀리에 따라 다른 생성 루틴이 실행&lt;/li&gt;
&lt;li&gt;현재 프로세스의 fd 배열에 텅빈 파일 기술자가 할당되고 이는 초기화된 file 구조체를 참조하며 이 구조체의&amp;nbsp;파일 함수 포인터가 BSD 소켓 파일 함수들을 가리키도록 설정&lt;/li&gt;
&lt;li&gt;이후 소켓 파일 연산들은 BSD 소켓 인터페이스로 전달되며, 인터페이스는 차례로 주소 패밀리의 함수들을 호출함으로써 각 주소 패밀리로 작업을 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&amp;nbsp;bind: 주소와 INET BSD 소켓 바인딩&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 서버는 INET BSD 소켓(접속 요청을 받는 listen 용도)을 만들어 서버의 주소와 바인드
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주소와 바인드된 소켓은 다른 통신을 위해서는 사용할 수 없음 (socket 상태는 TCP_CLOSE)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;바인드 작업은 대부분 INET 소켓 계층이 아래 계층인 TCP/UDP 프로토콜 계층으로부터 어느 정도 지원을 받아 처리&lt;/li&gt;
&lt;li&gt;INET 주소 패밀리를 지원하며, 네트워크 장치에 할당된 IP 주소가 바인드된 주소
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IP 주소는 모두 1 또는 0인 IP 브로드캐스트(broadcast) 주소일 수 있으며, 이는 모든 호스트에게 보내라는 의미&lt;/li&gt;
&lt;li&gt;단, 슈퍼유저 권한의 프로세스만이 아무 IP 주소에나 바인드 할 수 있음&lt;/li&gt;
&lt;li&gt;바인드된 IP 주소는 recv_addr 구조체에 있는 sock 구조체와 &amp;nbsp;saddr 항목에 저장됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;포트 번호는 옵션이며, 지정하지 않으면 이를 지원하는 네트워크에게 빈 포트 번호를 요청
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1024보다 작은 포트 번호는 슈퍼유저 권한이 없는 프로세스는 사용할 수 없음 (well-known ports)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;네트워크 장치는 패킷을 받으면, 이를 올바른 INET 과 BSD 소켓으로 전달하여 처리&lt;/li&gt;
&lt;li&gt;TCP/UDP는 들어온 IP 메시지에 있는 주소를 조회하여 올바른 socket/sock 쌍으로 전달하기 위한 해시 테이블을 관리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TCP는 연결 지향 프로토콜로, UDP 패킷을 처리할 때보다 TCP 패킷을 처리할 때 더 많은 정보가 사용됨&lt;/li&gt;
&lt;li&gt;UDP는 할당된 UDP 포트의 해시 테이블인 udp_hash 자료구조를 관리&lt;/li&gt;
&lt;li&gt;이는 sock 구조체의 포인터 배열로, 포트 번호에 기반하여 해시 값을 계산&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;TCP는 바인드 작업 동안에 바인드하는 sock 구조체를 해시 테이블에 추가하지 않고, 단지 요구한 포트 번호가 현재 사용중인지만 검사 (sock 구조체는 listen 작업 중에 TCP 해시 테이블에 추가됨)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;connect: INET BSD 소켓으로 연결&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;연결 요청을 받는 용도(listen)로 사용되지 않으면, 연결 요청을 하는 용도(connect)로 사용 가능&lt;/li&gt;
&lt;li&gt;&lt;u&gt;UDP는 비연결지향이므로 이런 작업이 필요 없으며, TCP만 두 프로세스 사이에 가상 연결을 생성할 때 필요함&lt;/u&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UDP도 접속 BSD 소켓 함수를 지원하지만, UDP INET BSD 소켓에서의 접속 작업은 단순히 원격지의 IP 주소 및 포트 번호를 설정하는 것&lt;/li&gt;
&lt;li&gt;추가적으로 라우팅 테이블 엔트리에 대한 캐시를 설정하여, 이 BSD 소켓으로 보낸 UDP 패킷이 다시 라우팅 DB를 검사하지 않도록 함 (경로가 틀리지 않은 경우)&lt;/li&gt;
&lt;li&gt;캐시된 라우팅 정보는 INET sock 구조체에서 ip_route_cache 에 의해 참조됨&lt;/li&gt;
&lt;li&gt;UDP는 sock 상태를 TCP_ESTABLISHED 로 변경&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;TCP는 접속 정보를 가진 메시지를 하나 생성해 목적지로 전달하며, 이 메시지는 시작 메시지 순서 번호와 시작하는 호스트에서 처리할 수 있는 메시지 최대 크기, 송수신 윈도우 크기(아직 보내지 않은 메시지들 중 보관 가능한 메시지의 수) 등을 포함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최대 메시지 크기(MTU)는 요청을 시작한 쪽에서 사용하고 있는 네트워크 장치에 따라 바뀜&lt;/li&gt;
&lt;li&gt;받는 쪽의 네트워크 장치가 이보다 작은 최대 메시지 크기를 지원하면 접속중 최소 MTU 값을 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;TCP에서는 모든 메시지에 번호가 붙으며, 초기 순서 번호는 첫번째 메시지 번호와 같고, 악의적인 프로토콜 공격을 피하기 위해 허용 범위 내에서 임의값으로 번호를 지정&lt;/li&gt;
&lt;li&gt;TCP에서 메시지를 수신하는 호스트는 모든 메시지에 대해 성공적으로 도착하였다는 응답을 송신지로 전달. 만약 이 응답이 없으면 송신측에서 같은 메시지를 재전송&lt;/li&gt;
&lt;li&gt;TCP 접속 요청을 원하는 프로세스는 요청이 accept/reject 중 하나라는 응답을 받을 때까지 블락되며, 타이머를 걸어 타임아웃시 프로세스가 실행되도록 할 수 있음&lt;/li&gt;
&lt;li&gt;TCP는 메시지가 들어올 때까지 대기하며, tcp_listening_hash 를 추가하여 들어온 메시지가 sock 구조체로 전달되게 함&lt;/li&gt;
&lt;li&gt;클라이언트가 연결을 요청하고, 서버가 요청을 수락하는 과정에서 TCP는 총 3개의 패킷을 주고 받음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;3-Way Handshaking&lt;/u&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이라고 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;클라이언트가 연결 종료를 요청하고, 서버가 요청을 받고 소켓을 종료하는 과정에서 TCP는 총 4개의 패킷을 주고 받음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;4-Way Handshaking&lt;/u&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이라고 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;639&quot; height=&quot;332&quot; data-origin-width=&quot;1276&quot; data-origin-height=&quot;664&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mbr8l/btq6EVfJ8Qz/iJM5CykqDHQIddyMkOQ7kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mbr8l/btq6EVfJ8Qz/iJM5CykqDHQIddyMkOQ7kk/img.png&quot; data-alt=&quot;3-way handshaking&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mbr8l/btq6EVfJ8Qz/iJM5CykqDHQIddyMkOQ7kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmbr8l%2Fbtq6EVfJ8Qz%2FiJM5CykqDHQIddyMkOQ7kk%2Fimg.png&quot; width=&quot;639&quot; height=&quot;332&quot; data-origin-width=&quot;1276&quot; data-origin-height=&quot;664&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;3-way handshaking&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;518&quot; height=&quot;401&quot; data-origin-width=&quot;1058&quot; data-origin-height=&quot;818&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SDKPA/btq6JxLYs7f/huYc4OH06VxplYQWkkH6fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SDKPA/btq6JxLYs7f/huYc4OH06VxplYQWkkH6fk/img.png&quot; data-alt=&quot;https://asfirstalways.tistory.com/356&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SDKPA/btq6JxLYs7f/huYc4OH06VxplYQWkkH6fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSDKPA%2Fbtq6JxLYs7f%2FhuYc4OH06VxplYQWkkH6fk%2Fimg.png&quot; width=&quot;518&quot; height=&quot;401&quot; data-origin-width=&quot;1058&quot; data-origin-height=&quot;818&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://asfirstalways.tistory.com/356&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;listen: INET BSD 소켓에서 접속 요청 대기&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;소켓에 주소를 바인딩 했으면, 바인드한 주소를 지정하여 들어오는 접속 요청을 대기하는데, listen 함수는 소켓의 상태를 TCP_LISTEN 으로 바꾸고 들어오는 접속을 허가하기 위해 필요한 특수 작업을 처리&lt;/li&gt;
&lt;li&gt;먼저 주소를 바인드하지 않고 접속을 기다릴 수 있으며, 여기서 INET 소켓 계층은 사용하지 않는 포트 번호를 찾아 소켓에 지정&lt;/li&gt;
&lt;li&gt;UDP는 소켓 상태만 변경하는 반면, TCP는 sock 구조체를 두 개의 해시 테이블(tcp_bound_hash, tcp_listening_hash)에 추가 (두 해시 테이블 모두 IP 포트 번호에 기반한 해시 함수를 통해 인덱싱)&lt;/li&gt;
&lt;li&gt;listen 소켓은 TCP 접속 요청을 받으면 이를 나타내는 sock 구조체를 생성하고, 접속 요청을 포함한 sk_buff 구조체를 복사하여 sock 구조체의 receive_queue 뒤에 이를 추가&lt;/li&gt;
&lt;li&gt;복사한 sk_buff 는 새로 만든 sock 구조체에 대한 포인터를 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;681&quot; height=&quot;295&quot; data-origin-width=&quot;876&quot; data-origin-height=&quot;379&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beEiMG/btq6LQq0SNt/gYwHPUAB3dbTUxLc09sek1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beEiMG/btq6LQq0SNt/gYwHPUAB3dbTUxLc09sek1/img.png&quot; data-alt=&quot;https://myaut.github.io/dtrace-stap-book/kernel/net.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beEiMG/btq6LQq0SNt/gYwHPUAB3dbTUxLc09sek1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeEiMG%2Fbtq6LQq0SNt%2FgYwHPUAB3dbTUxLc09sek1%2Fimg.png&quot; width=&quot;681&quot; height=&quot;295&quot; data-origin-width=&quot;876&quot; data-origin-height=&quot;379&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://myaut.github.io/dtrace-stap-book/kernel/net.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;accept: 접속 요청 허가&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;INET 소켓 접속을 허락하는 것은 TCP 프로토콜에만 적용 (UDP는 해당 없음)&lt;/li&gt;
&lt;li&gt;listen 소켓 외에 accept/reject 을 위한 소켓에서 socket 구조체를 복사하여 새 socket 구조체를 생성&lt;/li&gt;
&lt;li&gt;지원하는 프로토콜 계층(TCP)에 허가하라는 명령을 전달&lt;/li&gt;
&lt;li&gt;블럭킹 모드가 아닌 경우, 들어오는 접속이 없으면, 위 작업은 실패하며 새로 만들어진 socket 구조체는 제거됨&lt;/li&gt;
&lt;li&gt;블럭킹 모드이면, 접속을 허가하는 프로세스는 대기 큐에 추가되고, 요청을 받을 때까지 중단됨&lt;/li&gt;
&lt;li&gt;클라이언트는 서버로부터 ACK 받으면 다시 ACK(접속을 허용 해달라는 메시지)를 보내는데, 이때 sk_buff 구조체는 무시되고, sock 구조체는 이전에 새로 만든 socket 구조체와 연결된 INET 소켓 계층으로 반환됨&lt;/li&gt;
&lt;li&gt;새로 생성된 소켓의 파일 기술자(fd)를 프로세스에게 돌려주고, 프로세스는 새 BSD 소켓을 가지고 작업할 때마다 fd를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;663&quot; height=&quot;381&quot; data-origin-width=&quot;841&quot; data-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WiZfV/btq6L3X0CYn/yVMrcMZ1Mqed2JBZ2OPUS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WiZfV/btq6L3X0CYn/yVMrcMZ1Mqed2JBZ2OPUS1/img.png&quot; data-alt=&quot;TCP 연결 과정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WiZfV/btq6L3X0CYn/yVMrcMZ1Mqed2JBZ2OPUS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWiZfV%2Fbtq6L3X0CYn%2FyVMrcMZ1Mqed2JBZ2OPUS1%2Fimg.png&quot; width=&quot;663&quot; height=&quot;381&quot; data-origin-width=&quot;841&quot; data-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;TCP 연결 과정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;519&quot; height=&quot;238&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;316&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSK6Xe/btq6HQFm1BM/Vs2hD8lNLQS3IGjcyTXfM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSK6Xe/btq6HQFm1BM/Vs2hD8lNLQS3IGjcyTXfM1/img.png&quot; data-alt=&quot;https://myaut.github.io/dtrace-stap-book/kernel/net.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSK6Xe/btq6HQFm1BM/Vs2hD8lNLQS3IGjcyTXfM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSK6Xe%2Fbtq6HQFm1BM%2FVs2hD8lNLQS3IGjcyTXfM1%2Fimg.png&quot; width=&quot;519&quot; height=&quot;238&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;316&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://myaut.github.io/dtrace-stap-book/kernel/net.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;IP 계층&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1278&quot; data-origin-height=&quot;612&quot; width=&quot;538&quot; height=&quot;258&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bT7Hjz/btq6MSBL67D/Vn8pi8OjRlz4fNuthN0GP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bT7Hjz/btq6MSBL67D/Vn8pi8OjRlz4fNuthN0GP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bT7Hjz/btq6MSBL67D/Vn8pi8OjRlz4fNuthN0GP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbT7Hjz%2Fbtq6MSBL67D%2FVn8pi8OjRlz4fNuthN0GP1%2Fimg.png&quot; data-origin-width=&quot;1278&quot; data-origin-height=&quot;612&quot; width=&quot;538&quot; height=&quot;258&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1256&quot; data-origin-height=&quot;712&quot; width=&quot;678&quot; height=&quot;384&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmLaWo/btq6QyP3DY2/K19hSK5eD1fOKuQOZ2gch0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmLaWo/btq6QyP3DY2/K19hSK5eD1fOKuQOZ2gch0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmLaWo/btq6QyP3DY2/K19hSK5eD1fOKuQOZ2gch0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmLaWo%2Fbtq6QyP3DY2%2FK19hSK5eD1fOKuQOZ2gch0%2Fimg.png&quot; data-origin-width=&quot;1256&quot; data-origin-height=&quot;712&quot; width=&quot;678&quot; height=&quot;384&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;856&quot; width=&quot;656&quot; height=&quot;462&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/edrr7I/btq6PEpthSW/NoihFF3ANGBNbFoVdNkhnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/edrr7I/btq6PEpthSW/NoihFF3ANGBNbFoVdNkhnK/img.png&quot; data-alt=&quot;https://www.slideshare.net/hugolu/the-linux-networking-architecture&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/edrr7I/btq6PEpthSW/NoihFF3ANGBNbFoVdNkhnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fedrr7I%2Fbtq6PEpthSW%2FNoihFF3ANGBNbFoVdNkhnK%2Fimg.png&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;856&quot; width=&quot;656&quot; height=&quot;462&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.slideshare.net/hugolu/the-linux-networking-architecture&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;소켓 버퍼(Socket Buffer)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 네트워크 프로토콜 계층을 가지면, 각 계층에서 다른 계층의 서비스를 사용하게 되는데, 전송할 때는 데이터에 헤더와 테일을 붙이고, 받을 때는 데이터에서 헤더와 테일을 제거해야 하는 오버헤드가 존재&lt;/li&gt;
&lt;li&gt;패킷에서 프로토콜 헤더와 테일을 탐색해야 하므로, 프로토콜 사이에 데이터 버퍼를 전달하는 것을 어렵게 함 (단순히 버퍼를 복사하는 것은 매우 비효율적)&lt;/li&gt;
&lt;li&gt;리눅스는 프로토콜 계층 사이에서 네트워크 디바이스 드라이버 간에 데이터를 주고 받기 위해, sk_buff 구조체의 리스트 포인터를 이용하는 소켓 버퍼를 사용&lt;/li&gt;
&lt;li&gt;소켓 버퍼는 포인터를 이용해 각 프로토콜 계층이 표준 함수로 프로그램 데이터를 다룰 수 있게 함&lt;/li&gt;
&lt;li&gt;각 sk_buff 구조체는 각자의 데이터 블럭을 가지며, 데이터를 다루고 관리하기 위해 4개의 데이터 포인터를 포함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;head&lt;/b&gt;&amp;nbsp;메모리에서 데이터의 시작 위치를 참조 (블럭 할당 시 고정)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;data&lt;/b&gt;&amp;nbsp;현재 프로토콜 데이터의 시작 위치를 참조 (현재 sk_buff 구조체를 소유하고 있는 프로토콜 계층에 따라 바뀜)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;tail&lt;/b&gt;&amp;nbsp;현재 프로토콜 데이터의 끝 위치를 참조&amp;nbsp;(현재 sk_buff 구조체를 소유하고 있는 프로토콜 계층에 따라 바뀜)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;end&lt;/b&gt;&amp;nbsp;메모리에서 데이터의 끝 위치를 참조 (블럭 할당 시 고정)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;sk_buff 구조체를 다루는 코드는 데이터에 헤더와 테일을 붙이고 제거하는 표준 함수를 제공
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;len&lt;/b&gt; 현재 프로토콜 패킷의 길이 (data ~ tail)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;truesize&lt;/b&gt;&amp;nbsp;데이터 버퍼의 전체 크기 (head ~ end)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;push()&lt;/b&gt;&amp;nbsp;data 포인터를 데이터 영역의 시작 쪽으로 이동시키고, len 값을 증가시킴. 전송할 패킷의 시작 부분에 데이터나 프로토콜 헤더를 추가하는데 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;pull()&lt;/b&gt;&amp;nbsp;data 포인터를 데이터 영역의 끝 쪽으로 이동시키고, len 값을 감소시킴. 수신한 패킷의 시작 부분에서 데이터나 프로토콜 헤더를 제거하는데 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;put()&lt;/b&gt;&amp;nbsp;tail 포인터를 데이터 영역의 끝 쪽으로 이동시키고, len 값을 증가시킴. 전송할 패킷의 끝에 데이터나 프로토콜 정보를 추가하는데 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;trim()&lt;/b&gt;&amp;nbsp;tail 포인터를 데이터 영역의 시작 쪽으로 이동시키고, len 값을 감소시킴. 수신한 패킷의 끝 부분에서 데이터나 프로토콜 정보를 제거하는데 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1210&quot; data-origin-height=&quot;762&quot; width=&quot;677&quot; height=&quot;426&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YAncI/btq6MTgrpWg/SAFyai6VrGkaY8DOwZ5OmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YAncI/btq6MTgrpWg/SAFyai6VrGkaY8DOwZ5OmK/img.png&quot; data-alt=&quot;https://www.slideshare.net/hugolu/the-linux-networking-architecture&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YAncI/btq6MTgrpWg/SAFyai6VrGkaY8DOwZ5OmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYAncI%2Fbtq6MTgrpWg%2FSAFyai6VrGkaY8DOwZ5OmK%2Fimg.png&quot; data-origin-width=&quot;1210&quot; data-origin-height=&quot;762&quot; width=&quot;677&quot; height=&quot;426&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.slideshare.net/hugolu/the-linux-networking-architecture&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디바이스 드라이버 초기화의 결과는 dev_base 리스트에서 서로 연결되어 있는 일련의 device 구조체들로, 각 구조체는 장치를 기술하고 네트워크 프로토콜 계층에서 드라이버가 작업할 때 호출하는 콜백 함수 집합을 제공
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이들 함수들은 대부분 데이터 전송 및 네트워크 장치 주소와 관련된 것&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1204&quot; data-origin-height=&quot;904&quot; width=&quot;651&quot; height=&quot;489&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxHao3/btq6LONNxDD/Bzl7CXk2V9Enq3Vou3p3k0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxHao3/btq6LONNxDD/Bzl7CXk2V9Enq3Vou3p3k0/img.png&quot; data-alt=&quot;https://www.slideshare.net/hugolu/the-linux-networking-architecture&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxHao3/btq6LONNxDD/Bzl7CXk2V9Enq3Vou3p3k0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxHao3%2Fbtq6LONNxDD%2FBzl7CXk2V9Enq3Vou3p3k0%2Fimg.png&quot; data-origin-width=&quot;1204&quot; data-origin-height=&quot;904&quot; width=&quot;651&quot; height=&quot;489&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.slideshare.net/hugolu/the-linux-networking-architecture&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;IP 패킷 수신&lt;/b&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네트워크 장치가 패킷을 수신하면 이들은 sk_buff 구조체로 변환되어, backlog 큐에 sk_buff 구조체가 추가됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 backlog 큐가 너무 커지면, 패킷을 무시&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이후 실행 준비가 되었음을 네트워크 하반부(bottom half)에 표시하고, 스케줄러는 하반부 핸들러를 실행하는데, 이&amp;nbsp;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;핸들러는 backlog 큐를 처리하기 전에 수신한 패킷을 전달할 프로토콜 계층을 결정하며, 전송 대기 중인 패킷들을 처리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;네트워크 계층은 초기화될 때, 각 프로토콜은 packet_type 구조체를 ptype_all 리스트나 ptype_base 해시 테이블에 추가하여 자신을 커널에 등록
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;packet_type 구조체는 프로토콜 타입, 네트워크 장치에 대한 포인터, 프로토콜의 수신 데이터 처리 루틴 및 리스트나 해시 테이블에 있는 다음 packet_type 구조체에 대한 포인터를 포함&lt;/li&gt;
&lt;li&gt;ptype_base 해시 테이블은 프로토콜 식별자로 인덱싱되어, 수신한 패킷을 받을 프로토콜을 결정하기 위해 사용됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;네트워크 하반부 핸들러는 들어오는 sk_buff 구조체의 프로토콜 타입과 ptype_base 해시 테이블에 있는 하나 이상의 packet_type 엔트리와 비교 (반드시 프로토콜은 하나 이상의 엔트리와 매칭됨)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;1008&quot; width=&quot;643&quot; height=&quot;529&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnVCCK/btq6HjOg6dL/wZwlv93fiAFElqZmi9DSQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnVCCK/btq6HjOg6dL/wZwlv93fiAFElqZmi9DSQK/img.png&quot; data-alt=&quot;https://www.slideshare.net/hugolu/the-linux-networking-architecture&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnVCCK/btq6HjOg6dL/wZwlv93fiAFElqZmi9DSQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnVCCK%2Fbtq6HjOg6dL%2FwZwlv93fiAFElqZmi9DSQK%2Fimg.png&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;1008&quot; width=&quot;643&quot; height=&quot;529&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.slideshare.net/hugolu/the-linux-networking-architecture&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;IP 패킷 송신&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그램이 전송할 데이터를 생성하면, 데이터를 포함한 sk_buff 구조체가 만들어지고, 각 프로토콜 계층을 위에서 아래로 통과하면서 계층별 헤더가 추가됨&lt;/li&gt;
&lt;li&gt;sk_buff 구조체는 전송할 네트워크 장치로 전달되며, IP 같은 프로토콜은 사용할 장치를 결정&lt;/li&gt;
&lt;li&gt;패킷은 루프백 장치를 통해 PPP 모뎀 연결의 끝에 있는 게이트웨이 또는 로컬 호스트 둘 중 하나로 전달됨&lt;/li&gt;
&lt;li&gt;IP 패킷을 전송할 때는 도달할 IP 주소로 가는 루트(route)를 결정하기 위해 라우팅 테이블(routing table)이 사용되며, 각 IP 목적지는 자신의 라우팅 테이블로부터 다음 도착지를 알아내 루트를 기술하는 rtable 구조체를 반환
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 구조체는 사용할 출발지 IP 주소, 네트워크 device 구조체의 주소, 간혹 미리 만들어진 하드웨어 헤더를 포함&lt;/li&gt;
&lt;li&gt;하드웨어 헤더는 네트워크 장치마다 다르며, 출발지와 도착지의 하드웨어 주소와 매개체 별로 다른 정보를 포함&lt;/li&gt;
&lt;li&gt;예를 들어, 이더넷 장치이면 출발지/도착지 주소는 물리적 주소(이던세 주소)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;하드웨어 헤더는 루트와 함께 캐시되는데, 이 헤더가 해당 루트를 통하여 전송하는 모든 IP 패킷에 추가되는 과정을 줄임&lt;/li&gt;
&lt;li&gt;하드웨어 헤더는 ARP 프로토콜로 해결(resolve)되어야 하는 물리 주소가 필요할 수 있는데, 패킷은 주소가 해결될 때까지 블락됨 (한 번 ARP를 요청하면 캐싱하므로 재요청이 필요 없음)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 조각내기(Data Fragmentation)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 네트워크 장치는 최대 패킷 크기(MTU)를 가지기 때문에 이보다 큰 크기의 데이터를 보내거나 받기 위해 IP 프로토콜은 데이터를 처리 가능한 크기로 나눔&lt;/li&gt;
&lt;li&gt;IP 패킷을 보내기 위해, IP 라우팅 테이블에서 네트워크 장치를 찾고, 패킷 크기가 MTU 보다 크면 크기에 맞춰 데이터를 조각내서 각 sk_buff 구조체를 전달 (패킷을 쪼개는 도중에 IP가 sk_buff 구조체를 할당받지 못한다면 전송은 실패)&lt;/li&gt;
&lt;li&gt;IP 패킷 헤더는 플래그와 이 조각의 오프셋을 가리키는 항목을 포함하며, 마지막 패킷은 마지막 IP 조각이라고 표시&lt;/li&gt;
&lt;li&gt;&amp;nbsp;IP 패킷을 받기 위해, IP 패킷 조각이 임의의 순서로 도착하는 점을 고려하여 모두 받은 뒤 재조립
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수신할 때마다 패킷 조각인지 검사하고, 처음 받은 경우 새 ipq 구조체를 생성&lt;/li&gt;
&lt;li&gt;ipq 구조체는 재조립을 기다리는 IP 패킷 조각 리스트인 ipqueue 에 추가됨&lt;/li&gt;
&lt;li&gt;IP 패킷 조각을 받을 때마다, 맞는 ipq 구조체를 찾기 위해 이 조각을 나타낼 ipfrag 구조체를 생성함 (ipq 구조체에서 fragments 변수에 저장됨)&lt;/li&gt;
&lt;li&gt;각 ipq 구조체는 조각난 IP 수신 프레임을 출발지와 도착지 IP 주소와 함께 유일하게 기술하며, 위 프로토콜 계층의 식별자와 해당 IP 프레임의 식별자를 가짐&lt;/li&gt;
&lt;li&gt;모든 조각이 도착하면, 데이터들은 하나의 ipq 구조체에서 리스트로 보관되므로, 이들을 sk_buff 구조체 하나로 병합&lt;/li&gt;
&lt;li&gt;병합된 sk_buff 구조체를 다음 프로토콜 계층으로 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;각 ipq 구조체는 조각이 도착할 때마다 타이머를 시작하는데, 타임아웃되면 ipq 구조체와 이것의 ipfrag 구조체들은 메모리에서 소멸되어 메시지는 전송 중 사라진 것으로 간주 (이들의 재전송은 상위 프로토콜의 책임)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1148&quot; data-origin-height=&quot;664&quot; width=&quot;525&quot; height=&quot;304&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8cKU6/btq6NabzfGQ/HKq96jWMxnsvOmG9wQAje1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8cKU6/btq6NabzfGQ/HKq96jWMxnsvOmG9wQAje1/img.png&quot; data-alt=&quot;데이터 조각화&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8cKU6/btq6NabzfGQ/HKq96jWMxnsvOmG9wQAje1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8cKU6%2Fbtq6NabzfGQ%2FHKq96jWMxnsvOmG9wQAje1%2Fimg.png&quot; data-origin-width=&quot;1148&quot; data-origin-height=&quot;664&quot; width=&quot;525&quot; height=&quot;304&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;데이터 조각화&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1238&quot; data-origin-height=&quot;926&quot; width=&quot;717&quot; height=&quot;537&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2UPP9/btq6MSIM39r/1kGJN4vKIQS9JDduLqClxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2UPP9/btq6MSIM39r/1kGJN4vKIQS9JDduLqClxk/img.png&quot; data-alt=&quot;https://www.slideshare.net/hugolu/the-linux-networking-architecture&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2UPP9/btq6MSIM39r/1kGJN4vKIQS9JDduLqClxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2UPP9%2Fbtq6MSIM39r%2F1kGJN4vKIQS9JDduLqClxk%2Fimg.png&quot; data-origin-width=&quot;1238&quot; data-origin-height=&quot;926&quot; width=&quot;717&quot; height=&quot;537&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.slideshare.net/hugolu/the-linux-networking-architecture&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;주소 결정 프로토콜(Address Resolution Protocol, ARP)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IP 주소에서 이더넷 주소 같은 하드웨어 주소로의 변환을 제공하는 프로토콜&lt;/li&gt;
&lt;li&gt;IP는 디바이스 드라이버에게 데이터를 sk_buff 구조체로 전달하기 전에 ARP를 호출해서 하드웨어 주소를 설정&lt;/li&gt;
&lt;li&gt;이 장치가 하드웨어 헤더를 필요로 한다면, 패킷용으로 하드웨어 헤더를 다시 만들어야 하는지 알기 위해 여러 검사를 수행&lt;/li&gt;
&lt;li&gt;리눅스는 하드웨어 헤더를 자주 만들지 않도록 캐시를 사용하며, 다시 만들어야 한다면 장치 고유의 하드웨어 헤더 재생성 루틴을 호출&lt;/li&gt;
&lt;li&gt;모든 이더넷 장치는 동일한 헤더 재생성 루틴을 호출하며, 이 루틴은 목적지 IP 주소를 물리 주소로 바꾸기 위한 ARP 서비스를 사용&lt;/li&gt;
&lt;li&gt;ARP 요청과 응답 두 가지 메시지 형태가 존재: 요청은 변환할 IP 주소를 가지며, 응답은 하드웨어 주소(변환된 IP 주소)를 가짐&lt;/li&gt;
&lt;li&gt;ARP 요청은 네트워크에 연결된 모든 호스트로 전달(브로드캐스트)되므로, 이더넷에 연결된 모든 호스트들이 ARP 요청을 수신하게 되는데 해당 IP 주소의 호스트만 응답&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;536&quot; height=&quot;394&quot; data-origin-width=&quot;1046&quot; data-origin-height=&quot;770&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tgWW0/btq6QNGw5fA/rYp1GuxWvOSDZWVO2upcJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tgWW0/btq6QNGw5fA/rYp1GuxWvOSDZWVO2upcJK/img.png&quot; data-alt=&quot;https://slidetodoc.com/chapter-8-arp-and-rarp-objectives-upon-completion/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tgWW0/btq6QNGw5fA/rYp1GuxWvOSDZWVO2upcJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtgWW0%2Fbtq6QNGw5fA%2FrYp1GuxWvOSDZWVO2upcJK%2Fimg.png&quot; width=&quot;536&quot; height=&quot;394&quot; data-origin-width=&quot;1046&quot; data-origin-height=&quot;770&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://slidetodoc.com/chapter-8-arp-and-rarp-objectives-upon-completion/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ARP 계층은 각 IP 주소에서 하드웨어 주소로의 변환을 나타내는 arp_table 자료구조를 가지며, 각 엔트리는 IP 주소가 변환될 필요가 있을 때 만들어지고 시간이 지나면서 제거됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;last used&lt;/b&gt;&amp;nbsp;arp_table 엔트리가 마지막으로 사용된 시간&lt;/li&gt;
&lt;li&gt;&lt;b&gt;last updated&lt;/b&gt;&amp;nbsp;arp_table 엔트리가 마지막으로 수정된 시간&lt;/li&gt;
&lt;li&gt;&lt;b&gt;flags&lt;/b&gt;&amp;nbsp;arp_table 엔트리가 완료되었는지 같은 상태를 나타내는 플래그&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ip address&lt;/b&gt;&amp;nbsp;엔트리가 나타내는 IP 주소&lt;/li&gt;
&lt;li&gt;&lt;b&gt;hardware address&lt;/b&gt;&amp;nbsp;변환된 하드웨어 주소&lt;/li&gt;
&lt;li&gt;&lt;b&gt;hardware header&lt;/b&gt;&amp;nbsp;캐시된 하드웨어 헤더에 대한 포인터&lt;/li&gt;
&lt;li&gt;&lt;b&gt;timer&lt;/b&gt;&amp;nbsp;응답하지 않는 요구를 타임아웃시키기 위한 timer_list 리스트의 엔트리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;retries&lt;/b&gt;&amp;nbsp;ARP 요청을 재시도한 횟수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;sk_buff queue&lt;/b&gt;&amp;nbsp;이 IP 주소를 해결(resolve)하길 기다리는 sk_buff 구조체들의 리스트&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;arp_tables 배열은 arp_table의 엔트리들에 대한 캐시로, 각 엔트리는 IP 주소의 끝 두 바이트를 가져와 인덱싱되며, 원하는 엔트리를 찾기 위해 해시 테이블에서 배열을 인덱싱하여 얻은 리스트를 순회&lt;/li&gt;
&lt;li&gt;미리 만들어진 하드웨어 헤더의 경우 hh_cache 구조체로 arp_table 엔트리에 캐시&lt;/li&gt;
&lt;li&gt;&lt;b&gt;일치하는 arp_table 엔트리가 없는 경우&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ARP 요청 메시지를 브로드캐스트로 전달하고 타이머를 실행&lt;/li&gt;
&lt;li&gt;새 arp_table 엔트리를 생성한 후, 주소 변환을 필요로 하는 패킷들을 엔트리의 리스트(sk_buff queue)에 추가&lt;/li&gt;
&lt;li&gt;ARP 응답이 없다면, 여러번 요청을 재시도 (여전히 응답이 없으면 arp_table에서 엔트리는 제거되고 큐된 sk_buff 구조체는 실패로 처리 --&amp;gt; TCP는 성립된 TCP 연결을 통해 패킷을 재전송하려고 시도)&lt;/li&gt;
&lt;li&gt;ARP 응답이 있다면, arp_table 엔트리는 완료된 것으로 표시되고 큐에서 sk_buff 구조체들을 제거&lt;/li&gt;
&lt;li&gt;하드웨어 주소는 각 sk_buff 구조체의 하드웨어 헤더에 기록됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ARP 계층은 자신의 프로토콜 타입(ETH_P_ARP)을 커널 네트워크 자료구조에 등록하고, packet_type 구조체를 생성&lt;/li&gt;
&lt;li&gt;ARP 계층은 네트워크 장치가 수신한 모든 ARP 패킷을 전달받으며, ARP 요청에는 자신의 IP 주소가 지정되어 있으면 반드시 응답&lt;/li&gt;
&lt;li&gt;수신한 장치의 device 구조체에 저장되어 있는 하드웨어 주소로 ARP 응답을 생성&lt;/li&gt;
&lt;li&gt;네트워크 구성은 시간에 따라 바뀔 수 있으며, IP 주소는 다른 하드웨어 주소로 재할당 될 수 있음. 예를 들어, 전화접속 서비스는 연결될 때마다 각각 다른 IP 주소를 배정 받음&lt;/li&gt;
&lt;li&gt;arp_tables 캐시가 항상 가장 최근의 엔트리를 가질 수 있도록, 정기적인 타이머를 실행해 모든 엔트리들이 타임아웃되지 않았는지 검사. 만약 하나 이상의 캐시된 하드웨어 헤더를 가지는 엔트리들(다른 자료구조들과 의존 관계)은 제거되지 않도록 주의&lt;/li&gt;
&lt;li&gt;arp_table 엔트리 중 몇몇은 영구적이며, 이들은 할당이 해제되지 않도록 별도로 표시됨&lt;/li&gt;
&lt;li&gt;각 엔트리는 커널 메모리에 저장되기 때문에 너쿠 커지지 않도록 크기가 최대값에 도달할 때마다 가장 오래된 엔트리들을 제거&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;669&quot; height=&quot;546&quot; data-origin-width=&quot;1276&quot; data-origin-height=&quot;1040&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/si2RQ/btq6PbnFsBs/Xm8GmCkAMcv5Fp3XkumrJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/si2RQ/btq6PbnFsBs/Xm8GmCkAMcv5Fp3XkumrJ0/img.png&quot; data-alt=&quot;https://slidetodoc.com/chapter-8-arp-and-rarp-objectives-upon-completion/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/si2RQ/btq6PbnFsBs/Xm8GmCkAMcv5Fp3XkumrJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsi2RQ%2Fbtq6PbnFsBs%2FXm8GmCkAMcv5Fp3XkumrJ0%2Fimg.png&quot; width=&quot;669&quot; height=&quot;546&quot; data-origin-width=&quot;1276&quot; data-origin-height=&quot;1040&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://slidetodoc.com/chapter-8-arp-and-rarp-objectives-upon-completion/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;IP 라우팅&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IP 라우팅 함수는 특정 IP 주소를 목적지로 하는 IP 패킷의 다음 도착지를 결정&lt;/li&gt;
&lt;li&gt;목적지에 도착 가능 유무, 전송하는데 사용할 네트워크 장치, 장치의 성능 등에 관한 정보를 관리하는 IP 라우팅 DB가 2개 존재&lt;/li&gt;
&lt;li&gt;&lt;b&gt;전달 정보 데이터베이스(Forwarding Information Database)&amp;nbsp;&lt;/b&gt;IP 주소와 알려진 루트(route)의 목록을 저장&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 IP 서브넷은 fib_zone 구조체로 표현되며, 이들 모두는 fib_zones 해시 테이블에서 참조&lt;/li&gt;
&lt;li&gt;해시 값은 IP 서브넷 마스크로 생성되며, 동일한 서브넷으로의 모든 루트들은 fib_node 쌍으로 기술됨&lt;/li&gt;
&lt;li&gt;fib_info 구조체는 각 fib_zone 구조체의 fz_list 큐에 추가됨&lt;/li&gt;
&lt;li&gt;만약 이 서브넷에 있는 루트 개수가 많아지면, fib_node 구조체를 쉽게 찾도록 해시 테이블이 생성됨&lt;/li&gt;
&lt;li&gt;서브넷으로 가는 루트가 여러 개 있다면, 각 루트는 다른 게이트웨이를 사용해야 함&lt;/li&gt;
&lt;li&gt;&lt;u&gt;한 루트의 거리&lt;/u&gt;는 도달해야 하는 서브넷까지 &lt;u&gt;거쳐야 하는 IP 서브넷의 개수&lt;/u&gt;를 의미 (이 값이 클수록 좋지 않은 루트)&lt;/li&gt;
&lt;li&gt;루트는 BSD 소켓 인터페이스로 IOCTL 요청을 보내서 추가되거나 제거 될 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네트워크 구성이 시간이 지남에 따라 바뀌면 루트도 동적으로 변할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;슈퍼유저 권한을 프로세스만이 INET 프로토콜 계층에서 IP 루트를 추가 및 제거 할 수 있음&lt;/li&gt;
&lt;li&gt;대부분 시스템은 라우터가 아닌 단말 시스템의 경우, 고정된 루트를 사용&lt;/li&gt;
&lt;li&gt;라우팅 프로토콜은 GATED 같은 데몬으로 구현되어 있으며, IOCTL 요청을 보내서 루트를 추가하거나 삭제&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;706&quot; height=&quot;476&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;570&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbD2HQ/btq6Ld78IBl/Xm0RBGPQtrQZc2kF3ZSBk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbD2HQ/btq6Ld78IBl/Xm0RBGPQtrQZc2kF3ZSBk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbD2HQ/btq6Ld78IBl/Xm0RBGPQtrQZc2kF3ZSBk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbD2HQ%2Fbtq6Ld78IBl%2FXm0RBGPQtrQZc2kF3ZSBk1%2Fimg.png&quot; width=&quot;706&quot; height=&quot;476&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;570&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;목적지로 가는 루트를 빨리 찾기 위해, 더 작고 더 빠른 DB인 &lt;b&gt;루트 캐시(route cache)&lt;/b&gt;를 사용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;루트 캐시는 자주 접근하는 루트에 대한 것들만 저장하며, ip_rt_hash_table 자료구조로 표현&lt;/li&gt;
&lt;li&gt;이 해시 테이블은 rtable 구조체의 리스트에 대한 포인터를 가진 배열로, 해시 값은 IP 주소 하위 두 바이트로 계산됨&lt;/li&gt;
&lt;li&gt;두 바이트는 목적지마다 다르기 때문에 해시 값을 가장 잘 분산시켜줌&lt;/li&gt;
&lt;li&gt;각 rtable 엔트리는 루트에 대한 정보를 포함: 목적지 IP 주소, 이 주소에 도달하는데 사용할 네트워크 장치, 메시지의 최대 크기, 참조 횟수, 사용 횟수, 타임스탬프 등&lt;/li&gt;
&lt;li&gt;참조 횟수는 이 루트가 사용될 때마다 증가하는 값으로, 이 루트를 사용하는 네트워크 연결의 개수를 의미. 프로세스가 이 루트로 데이터를 주고받지 않게 되면 감소&lt;/li&gt;
&lt;li&gt;사용 횟수는 이 루트를 발견할 때마다 증가하며, rtable 리스트에서 엔트리의 순서를 결정하는데 사용&lt;/li&gt;
&lt;li&gt;타임스탬프는 마지막으로 사용한 시간 값으로, 엔트리가 너무 오래되지 않았는지 검사하는데 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;IP 루트를 조회하면 일치하는 루트를 찾기 위해 루트 캐시를 먼저 검사&lt;/li&gt;
&lt;li&gt;루트 캐시에 일치하는 루트가 없다면, 전달 정보 데이터베이스에서 루트를 탐색&lt;/li&gt;
&lt;li&gt;어떤 루트도 찾을 수 없다면, IP 패킷은 전송 실패로 처리되어 프로세스에게 전달됨&lt;/li&gt;
&lt;li&gt;루트가 전달 정보 데이터베이스에 있고 루트 캐시에 없다면, 이 루트에 해당하는 새 엔트리를 만들어 루트 캐시에 추가&lt;/li&gt;
&lt;li&gt;루트 캐시는 LRU 방식으로 동작: 최근에 많이 사용되지 않은 엔트리는 루트 캐시에서 제거하고, 만약 찾는 루트가 캐시에 있다면 리스트 맨 앞에 오도록 배치 (가장 최근에 많이 접한 엔트리가 항상 앞에 오도록 함)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Operating System/Linux</category>
      <category>ARP</category>
      <category>BSD 소켓 인터페이스</category>
      <category>INET 계층</category>
      <category>Linux Kernel</category>
      <category>LRU</category>
      <category>Operating System</category>
      <category>sk_buff</category>
      <category>TCP/IP</category>
      <category>리눅스 커널</category>
      <category>운영체제</category>
      <author>r4v3n-k</author>
      <guid isPermaLink="true">https://movefast.tistory.com/350</guid>
      <comments>https://movefast.tistory.com/350#entry350comment</comments>
      <pubDate>Mon, 7 Jun 2021 18:24:50 +0900</pubDate>
    </item>
    <item>
      <title>리눅스 커널 - 파일 시스템</title>
      <link>https://movefast.tistory.com/349</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;본 글은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;http://wiki.kldp.org/Translations/html/The_Linux_Kernel-KLDP/The_Linux_Kernel-KLDP.html&quot;&gt;The Linux Kernel&lt;/a&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;을 정리한 것이며, 출처를 밝히지 않은 모든 이미지는 원글에 속한 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;리눅스 파일 시스템&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;리눅스는 각 파일 시스템이 계층적인 트리 구조로 통합해서 나타내므로, 파일 시스템이 하나인 것처럼 보여줌&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;윈도우즈는 드라이브 이름 등의 장치 식별자로 구분&lt;/li&gt;
&lt;li&gt;새로운 파일 시스템을 마운트하면 하나의 파일 시스템에 추가된 형태로 보여짐&lt;/li&gt;
&lt;li&gt;파일 시스템은 로컬 시스템이 아닌 네트워크 연결로 원격지에서 마운트된 디스크도 포함 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모든 파일 시스템은 어떤 타입이든지 하나의 디렉토리에 마운트되어, 마운트된 파일 시스템의 파일들이 그 디렉토리의 내용을 구성&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이는 많은 파일 시스템을 지원할 수 있게 함&lt;/li&gt;
&lt;li&gt;이러한 디렉토리를 마운트 디렉토리 또는 마운트 포인트라고 부름&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;파일 시스템의 마운트가 해제되면, 마운트 디렉토리가 원래 가지고 있던 파일들이 보여짐&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디스크가 초기화될 때, 파티션 구조를 가지며 물리 디스크를 논리적으로 나누는 작업을 파티셔닝(partitioning)이라고 함&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;각 파티션은 하나의 파일 시스템을 가지며,&lt;/b&gt; 파일 시스템은 장치의 블럭에 파일을 디렉토리나 소프트 링크(윈도우즈의 바로가기 같은) 등과 함께 논리적인 계층 구조로 구성 (블럭 장치만이 파일 시스템을 저장할 수 있음)&lt;/li&gt;
&lt;li&gt;파일 시스템은 일련의 블럭 장치들의 집합이며, 운영체제는 물리 디스크가 어떤 형태(구조)인지 알 필요가 없음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하드웨어의 추상화 단계로 물리 장치의 세부 사항을 알 필요가 없음&lt;/li&gt;
&lt;li&gt;블럭을 읽는 요청은 각 블럭 디바이스 드라이버의 책임(블럭이 읽어야 하는 위치를 매핑)으로, 파일 시스템은 어떤 장치에 블럭이 있는지 상관없이 동작함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;파일(file)이란 데이터의 집합이며, 파일에 담긴 데이터 외에 파일 시스템의 구조도 포함되는데, 이러한 정보들은 신뢰성있게 저장되어야 하며 파일 시스템은 무결성을 보장해야 함&lt;/li&gt;
&lt;li&gt;처음에 제안된 파일 시스템은 확장 파일 시스템(Extended File System, EXT)으로, 가상 파일 시스템(Virtual File System, VFS)이라는 인터페이스 계층을 통해 실제 파일 시스템이&amp;nbsp;운영체제와 운영체제의 서비스로부터 분리됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;즉, 파일 시스템의 세부 사항들이 소프트웨어에 의해 변환되는 것이고, VFS를 지원하는 파일 시스템들은 모두 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;VFS는 마운트되어 사용중인 각 파일 시스템의 정보를 메모리에 캐싱하며, 파일이나 디렉토리가 생성, 삭제, 또는 자료가 입력될 때 캐시 안의 자료를 정확하게 수정함. 이는 메모리 내 캐시와 디스크의 내용의 일치성을 보장함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 과정에서 디바이스 드라이버에 의해 접근하려는 파일이나 디렉토리 관련 자료구조가 생성되거나 제거됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;버퍼 캐시(Buffer Cache)는 각 파일 시스템이 블럭 장치에 접근할 때 사용되며, 블럭에 접근할 때마다 그 블럭은 버퍼 캐시에 들어가고 상태에 따라 다양한 큐에 추가됨. 버퍼 캐시는 데이터 버퍼를 캐시할 뿐만 아니라, 블럭 디바이스 드라이버와의 비동기적인 인터페이스 관리에도 도움이 됨.&lt;/li&gt;
&lt;li&gt;EXT가 성능이 떨어지면서 2차 확장 파일 시스템(EXT2)가 등장&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;401&quot; data-origin-height=&quot;319&quot; width=&quot;668&quot; height=&quot;532&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buVBhC/btq6A9qMIfS/dNsHgF8xTxinPOEeH3FuRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buVBhC/btq6A9qMIfS/dNsHgF8xTxinPOEeH3FuRk/img.png&quot; data-alt=&quot;https://stackoverflow.com/questions/34253611/are-device-files-implemented-by-the-specific-file-systems-or-the-virtual-file-sy&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buVBhC/btq6A9qMIfS/dNsHgF8xTxinPOEeH3FuRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuVBhC%2Fbtq6A9qMIfS%2FdNsHgF8xTxinPOEeH3FuRk%2Fimg.png&quot; data-origin-width=&quot;401&quot; data-origin-height=&quot;319&quot; width=&quot;668&quot; height=&quot;532&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://stackoverflow.com/questions/34253611/are-device-files-implemented-by-the-specific-file-systems-or-the-virtual-file-sy&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;572&quot; height=&quot;634&quot; data-origin-width=&quot;1244&quot; data-origin-height=&quot;1378&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/esKku1/btq6EWEcZHL/CzBuHF3AK3kUem4LHIBB21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/esKku1/btq6EWEcZHL/CzBuHF3AK3kUem4LHIBB21/img.png&quot; data-alt=&quot;공통 파일 시스템 인터페이스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/esKku1/btq6EWEcZHL/CzBuHF3AK3kUem4LHIBB21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FesKku1%2Fbtq6EWEcZHL%2FCzBuHF3AK3kUem4LHIBB21%2Fimg.png&quot; width=&quot;572&quot; height=&quot;634&quot; data-origin-width=&quot;1244&quot; data-origin-height=&quot;1378&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;공통 파일 시스템 인터페이스&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;701&quot; height=&quot;526&quot; data-origin-width=&quot;1300&quot; data-origin-height=&quot;976&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bT4hSb/btq6BaJY0DB/5sALChNzxAQkk1tlmhFJ7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bT4hSb/btq6BaJY0DB/5sALChNzxAQkk1tlmhFJ7k/img.png&quot; data-alt=&quot;https://scslab-intern.gitbooks.io/linux-kernel-hacking/content/chapter13.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bT4hSb/btq6BaJY0DB/5sALChNzxAQkk1tlmhFJ7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbT4hSb%2Fbtq6BaJY0DB%2F5sALChNzxAQkk1tlmhFJ7k%2Fimg.png&quot; width=&quot;701&quot; height=&quot;526&quot; data-origin-width=&quot;1300&quot; data-origin-height=&quot;976&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://scslab-intern.gitbooks.io/linux-kernel-hacking/content/chapter13.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2차 확장 파일 시스템(Second Extended File System, EXT2)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;701&quot; height=&quot;298&quot; data-origin-width=&quot;631&quot; data-origin-height=&quot;269&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnmpHP/btq6DRbSgoH/crysHhDn5FQ8bhUlzAriVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnmpHP/btq6DRbSgoH/crysHhDn5FQ8bhUlzAriVk/img.png&quot; data-alt=&quot;EXT2 파일 시스템의 물리적 배치도&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnmpHP/btq6DRbSgoH/crysHhDn5FQ8bhUlzAriVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnmpHP%2Fbtq6DRbSgoH%2FcrysHhDn5FQ8bhUlzAriVk%2Fimg.png&quot; width=&quot;701&quot; height=&quot;298&quot; data-origin-width=&quot;631&quot; data-origin-height=&quot;269&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;EXT2 파일 시스템의 물리적 배치도&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;EXT2의 파일에 저장된 데이터는 블럭에 저장되는데, 데이터 블럭의 크기는 동일하며, 서로 다른 EXT2의 경우 크기가 다를 수 있음&lt;/li&gt;
&lt;li&gt;블럭 크기는 파일 시스템이 만들어질 때 결정되며, 모든 파일의 크기는 블럭의 크기에 따라 올림이 됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어, 블럭 크기가 1024바이트이고, 파일 크기가 1025바이트일 때, 이 파일은 1024바이트 블럭 2개를 차지함&lt;/li&gt;
&lt;li&gt;실제로 파일 하나당 평균 블럭 크기의 절반을 낭비하는데, 이는 CPU의 메모리 사용량과 디스크 공간의 활용도 사이에 트레이드 오프(trade off) 문제로, 리눅스는 CPU 부담을 줄이는 방향으로 디스크 공간의 활용도를 희생함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;파일 시스템의 모든 블럭이 데이터만 저장하는 것은 아니며, 몇몇 블럭에는 파일 시스템의 구조를 표현하는 정보가 있음&lt;/li&gt;
&lt;li&gt;파티션은 하나의 파일 시스템을 가지는데, 파일 시스템은 공간을 블럭 그룹으로 쪼개고, 각 블럭 그룹은 파일 시스템에서 무결성을 보장해야 하는 정보를 중복해서 갖고 있어 파일 시스템 복구 시 중복 정보를 이용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;EXT2 inode&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;EXT2는 파일 시스템 배치도를 정의하기 위해 시스템 내의 각 파일을 inode 자료구조로 표현하며, 모든 inode는 inode 테이블에 저장되고, 파일은 일반 파일, 디렉토리, 소프트 링크, 하드 링크, 장치 파일을 포함&lt;/li&gt;
&lt;li&gt;즉, 디렉토리도 inode로 기술되며, 디렉토리에 속하는 파일들의 inode 포인터를 디렉토리 inode에서 보관&lt;/li&gt;
&lt;li&gt;inode는 파일의 데이터가 위치한 블럭과 파일에 대한 접근 권한 및 파일 수정 시간, 파일 종류 등의 정보를 가지며, EXT2의 모든 파일은 각각 하나의 inode와 대응 (즉, inode는 구분 가능한 고유 번호를 가지고 식별됨)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Mode&lt;/b&gt;&amp;nbsp;접근 권한 정보 및 파일의 유형(일반 파일, 디렉토리, 심볼릭 링크, 블럭 장치, 문자 장치, FIFO)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Owner Information&lt;/b&gt;&amp;nbsp;해당 파일의 소유자 및 그룹 식별자&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Size&lt;/b&gt;&amp;nbsp;바이트 단위의 파일 크기&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Timestamp&lt;/b&gt;&amp;nbsp;inode가 만들어진 시각과 최종 수정 시각&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Datablocks&lt;/b&gt;&amp;nbsp;데이터가 저장된 블럭에 대한 포인터, 맨 앞 12개의 포인터는 데이터를 저장한 실제 블럭에 대한 포인터이고 마지막 3개는 점점 더 높은 수준의 간접 연결(블럭의 포인터의 포인터)을 포함.&lt;/li&gt;
&lt;li&gt;특수 장치 파일은 실제 디스크에 존재하지 않는 파일이지만 inode로 표현되며, 커널 내부에는 장치를 접근하기 위한 코드가 존재&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;551&quot; height=&quot;561&quot; data-origin-width=&quot;499&quot; data-origin-height=&quot;508&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yCRyX/btq6BDSWJjR/CJNEvCktKakz2ako0rJmtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yCRyX/btq6BDSWJjR/CJNEvCktKakz2ako0rJmtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yCRyX/btq6BDSWJjR/CJNEvCktKakz2ako0rJmtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyCRyX%2Fbtq6BDSWJjR%2FCJNEvCktKakz2ako0rJmtK%2Fimg.png&quot; width=&quot;551&quot; height=&quot;561&quot; data-origin-width=&quot;499&quot; data-origin-height=&quot;508&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;EXT2 Superblock&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수퍼블럭은 파일 시스템의 기본 크기나 모양에 대한 설명을 기술하는 자료구조로, 이 정보를 이용하여 관리자가 파일 시스템을 활용하고 유지&lt;/li&gt;
&lt;li&gt;보통 파일 시스템이 마운트 될 때, 블럭 그룹 0에 있는 수퍼블럭을 읽어들이지만, 모든 블럭 그룹에는 동일한 복사본이 존재해 파일 시스템이 깨지는 경우를 대비함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Magic Number&lt;/b&gt;&amp;nbsp;마운트 프로그램에 EXT2의 수퍼블럭이라는 것을 알리는 용도 (=0xEF53)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Revision Level&lt;/b&gt;&amp;nbsp;메이저 개정 레벨과 마이너 개정 레벨로 구성되며, 마운트 프로그램이 어떤 특정 버전에서만 지원되는 기능이 현재 파일 시스템에서 지원되는지 확인하는 용도. 또한 마운트 프로그램이 파일 시스템에서 안전하게 사용가능한 기능 목록(기능 호환성 항목)을 판단할 때 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Mount Count &amp;amp; Maximum Mount Count&lt;/b&gt;&amp;nbsp;파일 시스템 전부를 검사할 필요가 있는지 확인할 때 사용. 마운트 횟수는 파일 시스템이 마운트될 때마다 1씩 증가하며, 그 값이 최대 마운트 횟수에 도달하면 e2fsck를 실행하라는 메시지가 출력됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Block Group Number&lt;/b&gt;&amp;nbsp;현재 수퍼블럭 복제본을 가지는 블럭 그룹의 번호&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Block Size&lt;/b&gt; 바이트 단위의 블럭 크기&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Blocks per Group&lt;/b&gt;&amp;nbsp;그룹당 블럭 수 (파일 시스템 만들 때 지정됨)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Free Blocks&lt;/b&gt;&amp;nbsp;파일 시스템 내 프리 블럭 수 = 사용 가능한 블럭 수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Free Inode&lt;/b&gt;&amp;nbsp;파일 시스템 내 프리 inode 수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;First Inode&lt;/b&gt;&amp;nbsp;첫번째 inode 번호, 루트 파일 시스템에 루트 디렉토리를 나타냄&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;648&quot; height=&quot;469&quot; data-origin-width=&quot;1044&quot; data-origin-height=&quot;756&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/du5bI0/btq6AsqRkWS/zSYTjK7qaBWGnowpacjznk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/du5bI0/btq6AsqRkWS/zSYTjK7qaBWGnowpacjznk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/du5bI0/btq6AsqRkWS/zSYTjK7qaBWGnowpacjznk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdu5bI0%2Fbtq6AsqRkWS%2FzSYTjK7qaBWGnowpacjznk%2Fimg.png&quot; width=&quot;648&quot; height=&quot;469&quot; data-origin-width=&quot;1044&quot; data-origin-height=&quot;756&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;EXT2 Group Descriptor&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 블럭 그룹은 자신을 기술하는 자료구조를 가지며, 수퍼블럭처럼 모든 블럭 그룹을 위한 그룹 기술자는 각 블럭 그룹에 복제되어 있어 파일 시스템이 깨지는 경우를 대비 (실제로 블럭 그룹 0에 있는 첫번째 복사본만 사용됨)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Block Bitmap&lt;/b&gt;&amp;nbsp;블럭 그룹에서 블럭의 할당 상태를 나타내는 비트맵 (블럭 수만큼 존재, 블럭 할당 및 해제 시 사용)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Inode Bitmap&lt;/b&gt;&amp;nbsp;블럭 그룹에서 inode의 할당 상태를 나타내는 비트맵 (블럭 수만큼 존재, inode 할당 및 해제 시 사용)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Inode Table&lt;/b&gt;&amp;nbsp;블럭 그룹의 inode 테이블의 시작 블럭 (블럭 수만큼 존재, 각 inode는 EXT2 inode 구조체에 의해 표현)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Free Blocks Count &amp;amp; Free Inode Count&lt;/b&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Used Directory Count&lt;/b&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;그룹 기술자는 전체적으로 하나의 그룹 기술자 테이블을 형성하며, 각 블럭 그룹에는 수퍼블럭 뒤에 그룹 기술자 테이블이 존재&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;EXT2 Directory&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디렉토리는 파일에 대한 접근 경로를 생성하고 저장하는 특별한 파일&lt;/li&gt;
&lt;li&gt;메모리 상에서 디렉토리 파일은 디렉토리 엔트리의 리스트&lt;/li&gt;
&lt;li&gt;디렉토리 엔트리는 디렉토리에 저장된 파일과 1:1 대응이며, 모든 디렉토리에서 첫 2개의 엔트리는 각각 .과 ..으로 현재 디렉토리와 부모 디렉토리를 의미&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Inode&lt;/b&gt; 엔트리에 해당하는 Inode로, 이 값은 블럭 그룹의 inode 테이블에 저장되어 있는 inode 배열에 대한 인덱스&lt;/li&gt;
&lt;li&gt;&lt;b&gt;name length&lt;/b&gt; 바이트 단위의 파일 이름 길이&lt;/li&gt;
&lt;li&gt;&lt;b&gt;name&lt;/b&gt; 파일 이름&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;585&quot; height=&quot;506&quot; data-origin-width=&quot;563&quot; data-origin-height=&quot;486&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTV6FA/btq6A86FhTX/jHbC36GwJ7Ph1vAqtUMzy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTV6FA/btq6A86FhTX/jHbC36GwJ7Ph1vAqtUMzy0/img.png&quot; data-alt=&quot;디렉토리 엔트리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTV6FA/btq6A86FhTX/jHbC36GwJ7Ph1vAqtUMzy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTV6FA%2Fbtq6A86FhTX%2FjHbC36GwJ7Ph1vAqtUMzy0%2Fimg.png&quot; width=&quot;585&quot; height=&quot;506&quot; data-origin-width=&quot;563&quot; data-origin-height=&quot;486&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;디렉토리 엔트리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;EXT2 파일 연산&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;파일 탐색&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파일 이름은 길이 제한이 없고 인쇄 가능한 문자면 가능. 단, 전체 경로에서 파일을 구분하기 위해 슬래시(/)를 사용&lt;/li&gt;
&lt;li&gt;파일을 나타내는 inode를 찾기 위해 시스템은 파일 이름을 해석해서 한 디렉토리씩 처리하면서 마지막 슬래시 뒤에 있는 이름을 가진 파일을 얻음&lt;/li&gt;
&lt;li&gt;루트 디렉토리의 inode 번호는 파일 시스템의 수퍼블럭에서 얻으며, 이 번호의 파일을 읽기 위해 해당 블럭 그룹의 inode 테이블을 이 번호로 인덱싱하여 엔트리를 얻음&lt;/li&gt;
&lt;li&gt;정리하자면, 전체 경로에서 파일을 찾을 때까지 디렉토리 엔트리를 반복적으로 찾아가면서 마지막 슬래시 뒤에 이름을 갖는 파일의 데이터 블럭을 얻음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;파일 크기 변경&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파일 시스템은 데이터를 가지고 있는 블럭들이 분할되는 경향(디스크 조각화)이 있는데, EXT2의 경우 어떤 파일에 대한 새로운 블럭을 현재 데이터 블럭들에 인접하도록 할당하거나 적어도 현재 블럭 그룹과 같은 그룹에 할당하는 것으로 이 문제를 극복
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;둘 다 실패하면, 다른 블럭 그룹에 있는 데이터 블럭을 할당 (어쩔 수 없음)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프로세스가 파일에 데이터를 쓰려고 할 때마다, 파일 시스템은 데이터가 파일에 마지막으로 할당된 블럭을 넘어가는지 검사하고,&amp;nbsp;넘어가면, 이 파일을 위한 새로운 데이터 블럭을 할당 (프로세스는 할당하고 기록이 끝날 때까지 대기)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;u&gt;블럭 할당 루틴은 파일 시스템의 수퍼블럭에 락을 걸어 수퍼블럭에 있는 항목을 변경. 이는 둘 이상의 프로세스가 파일 시스템을 동시에 변경하는 것을 막기 위한 것으로, 다른 프로세스가 블럭을 할당하려고 하면 현재 프로세스는 대기&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;수퍼블럭의 사용은 요청 순서에 따르며, 한 프로세스가 제어를 갖게 되면 작업을 종료할 때까지 제어를 가짐(원자적)&lt;/li&gt;
&lt;li&gt;수퍼블럭에 락을 걸고 나면, 프리 블럭(사용가능한 블럭)이 충분한지 검사. 만약 충분하지 않다면 할당 루틴은 실패하고 프로세스는 수퍼블럭에 대한 제어권을 양도&lt;/li&gt;
&lt;li&gt;만약 프리 블럭이 충분하다면, 프로세스는 새 블럭을 할당 받고 수퍼블럭에 대한 제어권을 양도&lt;/li&gt;
&lt;li&gt;미리 할당된 블럭을 사용할 수 있는데, 실제 존재하지는 않으며 단지 할당된 블럭 비트맵에 예약되어 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;inode에는 새로운 데이터 블럭을 할당하기 위한 항목 2개가 존재
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;prealloc_block&lt;/b&gt; 처음에 미리 할당된 데이터 블럭 수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;prealloc_count&lt;/b&gt;&amp;nbsp;그 중에서 남은 개수&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;할당할 때는 마지막 데이터 블럭의 다음 데이터 블럭이 비었는지 검사해서 비었으면 할당하고 안비었으면 검색 범위를 넓혀 가까운 블럭에서 64블럭 이내의 데이터 블럭을 살펴봄 (순차 접근을 빠르게 하기 위함)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대부분 그 파일에 속한 다른 데이터 블럭과 같은 블럭 그룹&lt;/li&gt;
&lt;li&gt;빈 블럭이 없다면 계속 탐색하는데, 한 블럭 그룹 안에 8개의 빈 데이터 블럭으로 된 덩어리를 찾으려고 함&lt;/li&gt;
&lt;li&gt;만약 블럭 미리 할당 기능이 필요하고 사용 가능할 경우, prealloc_block 과 prealloc_count 값을 각각 갱신&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;빈 블럭을 찾을 때마다 블럭 그룹의 블럭 비트맵을 갱신하고 버퍼 캐시 내에 데이터 버퍼를 할당
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 버퍼는 파일 시스템을 지원하는 장치 식별자와 할당된 블럭의 번호에 의해 식별됨&lt;/li&gt;
&lt;li&gt;버퍼 내의 데이터가 모두 0이고 버퍼가 더티(dirty)라고 표시되어 있으면 실제 디스크에 내용이 기록되지 않은 것&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;수퍼블럭을 기다리는 프로세스가 있으면 큐에 있는 프로세스 중 첫번째 프로세스가 다시 실행되며 파일 처리에 필요한 수퍼블럭을 독점&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;가상 파일 시스템(Virtual File System, VFS)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;437&quot; height=&quot;443&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;558&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lVcsq/btq6BelMjLO/2kgavamhQy5Ij3Sjr8ROK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lVcsq/btq6BelMjLO/2kgavamhQy5Ij3Sjr8ROK0/img.png&quot; data-alt=&quot;VFS 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lVcsq/btq6BelMjLO/2kgavamhQy5Ij3Sjr8ROK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlVcsq%2Fbtq6BelMjLO%2F2kgavamhQy5Ij3Sjr8ROK0%2Fimg.png&quot; width=&quot;437&quot; height=&quot;443&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;558&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;VFS 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;전체 파일 시스템과 특정 마운트된 파일 시스템을 기술하는 자료구조를 관리하기 위한 인터페이스&lt;/b&gt;로, EXT2와 비슷한 방법으로 시스템에 있는 파일을 수퍼블럭과 inode로 표현 (&lt;b&gt;VFS inode&lt;/b&gt;는 EXT2 inode처럼 시스템에 있는 파일과 디렉토리를 나타냄)&lt;/li&gt;
&lt;li&gt;각 파일 시스템들은 부팅 중 초기화될 때, 자신을 VFS에 등록하여 커널에 파일 시스템이 포함될 수 있으며, 특정 파일 시스템을 마운트하는 경우 모듈에 의해 VFS에 등록됨&lt;/li&gt;
&lt;li&gt;블럭 장치에 기반한 파일 시스템이 마운트되었고, 루트 파일 시스템이 존재한다면, VFS는 이것의 수퍼블럭을 읽어와 해당 파일 시스템의 배치도를 VFS 수퍼블럭 자료구조에 매핑시킴&lt;/li&gt;
&lt;li&gt;VFS는 마운트된 파일 시스템과 VFS 수퍼블럭의 리스트를 관리하며, 각각의 VFS 수퍼블럭은 특정 기능을 수행하는 루틴에 대한 정보와 포인터 및 파일 시스템의 첫번째 VFS inode에 대한 포인터를 포함 (루트 파일 시스템의 경우 이 inode는 루트 디렉토리의 것)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어, 마운트된 파일 시스템을 나타내는 수퍼블럭은 고유의 inode 읽기 루틴에 대한 포인터를 가지며, 호출 시 적절한 파일 시스템의 블럭을 읽을 수 있게 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로세스가 파일이나 디렉토리에 접근할 때, VFS inode를 탐색하는 시스템 루틴이 호출되며, 수많은 inode가 반복적으로 접근&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;접근 속도를 빠르게 하기 위해 inode는 캐시에 저장됨&lt;/li&gt;
&lt;li&gt;어떤 inode가 캐시에 존재하지 않으면, 해당 inode를 읽기 위해(디스크-&amp;gt;메모리) 각 파일 시스템 고유의 루틴을 호출&lt;/li&gt;
&lt;li&gt;읽어들인 inode는 캐시에 저장되어 다음번 접근 시 캐시에서 탐색됨&lt;/li&gt;
&lt;li&gt;덜 사용되는 VFS inode는 캐시로부터 제거 (LRU Cache)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모든 파일 시스템은 실제 장치에 대한 접근 속도를 높이기 위해 버퍼 캐시(Buffer Cache)를 사용&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;같은 데이터가 자주 필요할 때를 대비하여 디스크 접근 횟수를 줄임&lt;/li&gt;
&lt;li&gt;버퍼 캐시는 파일 시스템과는 상호 독립적(비동기 요청 인터페이스를 제공)이며, 커널이 데이터 버퍼를 할당하고 읽고 쓰는 메커니즘에 통합되어 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;inode를 읽기 위해, 커널은 블럭 디바이스 드라이버에게 제어하는 장치로부터 블럭을 읽도록 요청하여 디스크에서 데이터를 가져옴
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이러한 블럭 장치 인터페이스는 버퍼 캐시에 통합되어 있음 (버퍼 캐시에서 데이터가 없는 경우 즉시 호출)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;파일 시스템이 어떤 블럭을 읽으면 그 블럭은 버퍼 캐시에 저장되어 모든 파일 시스템과 커널에 의하여 공유되며, 버퍼 캐시에 있는 각 데이터 버퍼는 블럭 번호와 그 블럭을 읽은 장치의 고유 식별자에 의하여 구분됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자주 사용되는 디렉토리의 inode를 빨리 찾기 위해 디렉토리 캐시도 제공, 이 캐시는 전체 디렉토리 이름과 해당되는 inode 번호와의 매핑을 저장하며 디렉토리 자체에 대한 inode는 inode 캐시에 저장됨&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;785&quot; data-origin-height=&quot;558&quot; width=&quot;716&quot; height=&quot;509&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lh35P/btq6Lekp786/RHWDytdOnExErpPZKBJxk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lh35P/btq6Lekp786/RHWDytdOnExErpPZKBJxk0/img.png&quot; data-alt=&quot;http://www.haifux.org/lectures/119/linux-2.4-vfs/linux-2.4-vfs.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lh35P/btq6Lekp786/RHWDytdOnExErpPZKBJxk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flh35P%2Fbtq6Lekp786%2FRHWDytdOnExErpPZKBJxk0%2Fimg.png&quot; data-origin-width=&quot;785&quot; data-origin-height=&quot;558&quot; width=&quot;716&quot; height=&quot;509&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;http://www.haifux.org/lectures/119/linux-2.4-vfs/linux-2.4-vfs.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;VFS Super Block&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;device&lt;/b&gt; 파일 시스템이 저장되어 있는 블럭 장치의 식별자&lt;/li&gt;
&lt;li&gt;&lt;b&gt;mounted inode&lt;/b&gt; 파일 시스템의 첫번째 inode를 참조하는 포인터&lt;/li&gt;
&lt;li&gt;&lt;b&gt;covered inode&lt;/b&gt; 파일 시스템이 마운트된 디렉토리를 표현하는 inode를 참조하는 포인터
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;루트 파일 시스템의 VFS 수퍼블럭은 covered inode 가 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;block size&lt;/b&gt;&amp;nbsp;바이트 단위의 블럭 크기&lt;/li&gt;
&lt;li&gt;&lt;b&gt;superblock operations&lt;/b&gt;&amp;nbsp;마운트된 파일 시스템의 file_system_type 구조체를 참조하는 포인터&lt;/li&gt;
&lt;li&gt;&lt;b&gt;file system specific&lt;/b&gt;&amp;nbsp;파일 시스템이 필요로 하는 정보를 참조하는 포인터&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;VFS inode&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 VFS inode의 정보는 파일 시스템의 정보로부터 파일 시스템 고유 루틴에 의해 생성되며, VFS inode는 커널 메모리에만 존재하고 시스템이 필요한 동안 VFS inode 캐시에 저장됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;device&lt;/b&gt;&amp;nbsp;해당 VFS inode가 나타내는 파일 또는 장치의 식별자&lt;/li&gt;
&lt;li&gt;&lt;b&gt;inode&lt;/b&gt;&amp;nbsp;파일 시스템 안에서 유일한 inode 번호, 장치와 inode 번호의 조합은 VFS 내에서 유일&lt;/li&gt;
&lt;li&gt;&lt;b&gt;mode&lt;/b&gt;&amp;nbsp;VFS inode가 해당하는 파일의 종류(파일, 디렉토리, 기타 등)와 적븐 권한 등을 나타냄&lt;/li&gt;
&lt;li&gt;&lt;b&gt;user id&lt;/b&gt;&amp;nbsp;파일의 소유자&lt;/li&gt;
&lt;li&gt;&lt;b&gt;times&lt;/b&gt;&amp;nbsp;생성 시각, 변경 시각, 읽은 시각 등을 나타냄&lt;/li&gt;
&lt;li&gt;&lt;b&gt;block size&lt;/b&gt;&amp;nbsp;바이트 단위의 블럭 크기&lt;/li&gt;
&lt;li&gt;&lt;b&gt;inode operations&lt;/b&gt;&amp;nbsp;연산 루틴의 주소들에 대한 포인터 (만약 0이면 inode가 프리되어 제거되거나 재사용됨)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;count&lt;/b&gt;&amp;nbsp;VFS inode를 현재 사용하는 시스템 요소(프로세스 등)의 수 (만약 0이면 inode가 프리되어 제거되거나 재사용됨)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;lock&lt;/b&gt;&amp;nbsp;VFS inode를 락 걸기 위해 사용 (inode를 읽을 때)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;dirty&lt;/b&gt;&amp;nbsp;VFS inode가 기록되어 파일 시스템 아래 계층에서 변경이 필요한지 나타냄&lt;/li&gt;
&lt;li&gt;&lt;b&gt;file system specific information&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;470&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJlZj2/btq6BC8ajzk/AlQYqfJZkhM6LzSlXx86W1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJlZj2/btq6BC8ajzk/AlQYqfJZkhM6LzSlXx86W1/img.png&quot; data-alt=&quot;VFS 자료구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJlZj2/btq6BC8ajzk/AlQYqfJZkhM6LzSlXx86W1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJlZj2%2Fbtq6BC8ajzk%2FAlQYqfJZkhM6LzSlXx86W1%2Fimg.png&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;470&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;VFS 자료구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;609&quot; data-origin-height=&quot;485&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b94NrA/btq6CPzsnrs/XKCZBf91R3CJvwysIlEXek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b94NrA/btq6CPzsnrs/XKCZBf91R3CJvwysIlEXek/img.png&quot; data-alt=&quot;https://myaut.github.io/dtrace-stap-book/kernel/fs.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b94NrA/btq6CPzsnrs/XKCZBf91R3CJvwysIlEXek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb94NrA%2Fbtq6CPzsnrs%2FXKCZBf91R3CJvwysIlEXek%2Fimg.png&quot; data-origin-width=&quot;609&quot; data-origin-height=&quot;485&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://myaut.github.io/dtrace-stap-book/kernel/fs.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;691&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rpM3B/btq6BCG9S6b/vN3Hr7ccplhQQUwIh3sfJk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rpM3B/btq6BCG9S6b/vN3Hr7ccplhQQUwIh3sfJk/img.jpg&quot; data-alt=&quot;https://www.programmersought.com/article/50821832993/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rpM3B/btq6BCG9S6b/vN3Hr7ccplhQQUwIh3sfJk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrpM3B%2Fbtq6BCG9S6b%2FvN3Hr7ccplhQQUwIh3sfJk%2Fimg.jpg&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;691&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.programmersought.com/article/50821832993/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;VFS 연산&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;파일 시스템 등록&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커널을 빌드할 때 지원할 파일 시스템을 지정할 수 있음.&lt;/li&gt;
&lt;li&gt;파일 시스템 시작 코드는 내장된 모든 파일 시스템의 초기화 루틴을 호출&lt;/li&gt;
&lt;li&gt;파일 시스템 모듈은 로드될 때마다 자신을 커널에 등록하고, 언로드될 때 자신을 커널로부터 해제함&lt;/li&gt;
&lt;li&gt;각 파일 시스템의 초기화 루틴은 자신을 VFS에 등록하며, file_system_type 구조체로 표현&lt;/li&gt;
&lt;li&gt;이 구조체에는 파일 시스템의 이름과 VFS 수퍼블럭 읽기 루틴에 대한 포인터가 저장되어 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;*read_super()&lt;/b&gt;&amp;nbsp;파일 시스템이 마운트될 때 VFS에 의해 호출&lt;/li&gt;
&lt;li&gt;&lt;b&gt;name&lt;/b&gt;&amp;nbsp;e.g., ext2&lt;/li&gt;
&lt;li&gt;&lt;b&gt;required_dev&lt;/b&gt;&amp;nbsp;이 파일 시스템을 실제로 지원하는 장치가 필요한지를 나타냄&lt;/li&gt;
&lt;li&gt;어떤 파일 시스템이 등록되어 있는지는 /proc/filesystems 파일 내용을 출력해서 알 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;709&quot; height=&quot;172&quot; data-origin-width=&quot;647&quot; data-origin-height=&quot;157&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOvmLK/btq6EVGjhrC/G8EOudGPJVxXWYKoYkOnq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOvmLK/btq6EVGjhrC/G8EOudGPJVxXWYKoYkOnq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOvmLK/btq6EVGjhrC/G8EOudGPJVxXWYKoYkOnq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOvmLK%2Fbtq6EVGjhrC%2FG8EOudGPJVxXWYKoYkOnq0%2Fimg.png&quot; width=&quot;709&quot; height=&quot;172&quot; data-origin-width=&quot;647&quot; data-origin-height=&quot;157&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;파일 시스템 마운트&lt;/span&gt;&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;수퍼유저가 파일 시스템을 마운트하려고 할 때, 커널은 시스테 콜로 전달된 인자가 옳은지 파악
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;e.g., mount -t iso9660 -o ro /dev/cdrom /mnt/cdrom&lt;/li&gt;
&lt;li&gt;커널에 3가지 정보를 전달: 파일 시스템 이름, 파일 시스템을 포함하고 있는 블럭 장치, 마운트할 위치&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;VFS는 먼저 파일 시스템 리스트(file_systems)를 탐색하여 각 file_system_type 구조체를 살펴보고, 인자로 넘어온 이름의 구조체를 발견하면 커널에서 지원하는 타입인지 검사
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일치하는 것을 찾지 못하더라도, 커널이 그 파일 시스템의 모듈을 요구시 로드하도록 빌드되었다면 커널 데몬이 모듈을 로드&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;새로운 파일 시스템의 마운트 지점이 될 디렉토리의 VFS inode를 탐색
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 VFS inode는 캐시에 있거나, 마운트 지점의 파일 시스템을 저장하고 있는 블럭 장치에서 읽어옴&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;inode를 찾으면 디렉토리인지 혹은 이미 다른 파일 시스템이 마운트되었는지 검사
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 디렉토리는 단 하나의 파일 시스템의 마운트 지점으로만 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;새로운 VFS 수퍼블럭을 할당하고, 이를 마운트 정보와 함께 해당 파일 시스템을 위한 수퍼블럭 읽기 루틴에 전달
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 VFS 수퍼블럭은 super_block 구조체의 배열인 super_blocks에 저장됨&lt;/li&gt;
&lt;li&gt;이번 마운트를 위해 super_block 구조체는 하나만 할당됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;수퍼블럭 읽기 루틴은 물리 장치에서 읽은 정보에 따라 VFS 수퍼블럭을 채워넣음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 그 파일 시스템의 블럭 장치로부터 읽지 못한다면(블럭 장치가 해당 파일 시스템의 타입으로 사용 불가한 경우) 마운트 명령은 실패&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;마운트된 각 파일 시스템은 vfsmount 구조체로 기술되며, 이들은 vfsmntlist 가 참조하는 리스트에 추가됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;vfsmnttail 포인터는 리스트의 마지막 항목을 가리키고, mru_vfsmnt 포인터는 가장 최근에 사용된 파일 시스템을 참조&lt;/li&gt;
&lt;li&gt;각 vfsmount 구조는 파일 시스템을 담고 있는 블럭 장치의 장치 번호, 이 파일 시스템이 마운트된 디렉토리, 마운트될 때 할당된 VFS 수퍼블럭에 대한 포인터 등을 포함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;704&quot; height=&quot;447&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;454&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3j0Nb/btq6MAtFATK/HjtZW2Rl0ekG6erjb9ROX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3j0Nb/btq6MAtFATK/HjtZW2Rl0ekG6erjb9ROX0/img.png&quot; data-alt=&quot;마운트 커널 자료구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3j0Nb/btq6MAtFATK/HjtZW2Rl0ekG6erjb9ROX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3j0Nb%2Fbtq6MAtFATK%2FHjtZW2Rl0ekG6erjb9ROX0%2Fimg.png&quot; width=&quot;704&quot; height=&quot;447&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;454&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;마운트 커널 자료구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;파일 시스템 마운트 해제&lt;/span&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 프로세스도 마운트된 디렉토리나 그 하위 디렉토리를 사용하지 않는 상태에서만 마운트 해제 가능&lt;/li&gt;
&lt;li&gt;사용중이면 VFS inode 캐시에 해당 파일 시스템이 속하는 VFS inode가 존재하기 때문에, 캐시의 inode 리스트를 검사&lt;/li&gt;
&lt;li&gt;마운트된 파일 시스템의 VFS 수퍼블럭이 더티(dirty) 상태이면, 수퍼블럭을 디스크에 기록&lt;/li&gt;
&lt;li&gt;디스크 기록 후, VFS 수퍼블럭이 차지하고 있던 메모리를 커널 메모리 풀(memory pool)에 보내고, 마지막으로 이 파일 시스템의 마운트에 필요했던 vfsmount 구조체를 vfsmntlist 리스트에서 제거한 뒤 메모리 해제&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;VFS 캐시&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;VFS inode 캐시&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;VFS는 마운트된 파일 시스템에 대한 접근 속도를 높이기 위해 해시 테이블로 구현된 inode 캐시를 유지&lt;/li&gt;
&lt;li&gt;inode를 접근할 때마다 VFS inode 캐시를 먼저 탐색&lt;/li&gt;
&lt;li&gt;해시 테이블 내의 각 엔트리는 같은 해시 값을 갖는 VFS inode 리스트를 참조&lt;/li&gt;
&lt;li&gt;해시 값은 inode 번호와 그 파일 시스템을 갖는 장치의 장치 식별자로 계산됨&lt;/li&gt;
&lt;li&gt;VFS inode 를 얻으려면 찾으려는 것과 같은 inode 번호와 장치 식별자를 가진 inode를 찾을 때까지 리스트를 순회&lt;/li&gt;
&lt;li&gt;만약 inode가 있으면, 카운트 값을 증가시키면서 그 inode를 사용하는 프로세스가 있음을 알리고 파일 시스템에 접근&lt;/li&gt;
&lt;li&gt;만약 찾을 수 없다면, 파일 시스템이 메모리로 파일을 가져오기 위해 빈 VFS inode를 탐색&lt;/li&gt;
&lt;li&gt;VFS inode를 더 할당할 수 있으면, 커널 페이지를 할당하고 이를 여러 새 빈 inode로 쪼갠 뒤,&amp;nbsp;할당된 VFS inode는 first_inode가 가리키는 리스트와 캐시의 리스트에 추가됨&lt;/li&gt;
&lt;li&gt;VFS inode를 더 할당할 수 없으면, 재사용할만한 inode 후보들을 탐색 (사용횟수가 0인 inode는 좋은 후보)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 VFS inode가 더티 상태이면 파일 시스템에 그 내용을 기록&lt;/li&gt;
&lt;li&gt;만약 락이 걸려 있으면 풀릴 때까지 대기&lt;/li&gt;
&lt;li&gt;재사용 후보가 선택되면 내용을 지움&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;할당된 VFS inode는 파일 시스템에서 읽어온 정보를 채우는 루틴이 호출되며, 카운트 값은 1이 되고 락이 걸림
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그 inode가 완전한 정보를 가지기 전까지 아무도 접근 할 수 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;VFS inode 캐시가 사용되어 꽉 차면, 덜 사용되는 inode는 버려지고 더 많이 사용되는 것들만 남음 (LRU Cache)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디렉토리 캐시&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;VFS는 디렉토리에 대한 접근 속도를 높이기 위해 해시 테이블로 구현된 디렉토리 엔트리에 대한 캐시를 유지&lt;/li&gt;
&lt;li&gt;디렉토리는 실제 파일 시스템에 의하여 참조되므로, 그 내용도 디렉토리 캐시에 저장됨&lt;/li&gt;
&lt;li&gt;짧은 이름(최대 15자)을 가진 디렉토리 엔트리만 캐시되며, 이는 짧은 것이 더 자주 사용되기 때문&lt;/li&gt;
&lt;li&gt;캐시의 테이블 엔트리는 같은 해시 값을 가진 디렉토리 캐시 엔트리들의 리스트를 참조&lt;/li&gt;
&lt;li&gt;해시 함수는 파일 시스템을 갖고 있는 장치의 장치 번호 및 디렉토리 이름을 사용하여 해시 테이블 내의 인덱스를 산출&lt;/li&gt;
&lt;li&gt;캐시 값을 유효하게 하고 최신 값을 유지하는 LRU 방식으로 디렉토리 캐시 엔트리 리스를 관리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디렉토리 엔트리는 처음에 참조되면 1단계 LRU 리스트의 맨 뒤에 추가&lt;/li&gt;
&lt;li&gt;1단계 리스트가 꽉 차서 자리가 없으면, 이 리스트의 맨 앞 엔트리를 제거 (가장 적게 사용된 것)&lt;/li&gt;
&lt;li&gt;디렉토리 엔트리가 다시 참조되면 2단계 LRU 리스트로 엔트리를 옮김&lt;/li&gt;
&lt;li&gt;2단계 리스트가 꽉 차서 자리가 없으면, 이 리스트의 맨 앞 엔트리를 제거&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;912&quot; width=&quot;697&quot; height=&quot;442&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8prZd/btq6L5gz5Az/XHMIkXYOn49phf0nRDmM0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8prZd/btq6L5gz5Az/XHMIkXYOn49phf0nRDmM0K/img.png&quot; data-alt=&quot;https://www.researchgate.net/figure/The-Linux-original-path-lookup-mechanism-The-block-means-a-dentry-structure-and-p_fig1_325982529&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8prZd/btq6L5gz5Az/XHMIkXYOn49phf0nRDmM0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8prZd%2Fbtq6L5gz5Az%2FXHMIkXYOn49phf0nRDmM0K%2Fimg.png&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;912&quot; width=&quot;697&quot; height=&quot;442&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.researchgate.net/figure/The-Linux-original-path-lookup-mechanism-The-block-means-a-dentry-structure-and-p_fig1_325982529&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;751&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;606&quot; height=&quot;759&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lWHGr/btq6BCm338J/eKNTceYkIkclfHkOpa2gq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lWHGr/btq6BCm338J/eKNTceYkIkclfHkOpa2gq0/img.png&quot; data-alt=&quot;https://scslab-intern.gitbooks.io/linux-kernel-hacking/content/chapter13.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lWHGr/btq6BCm338J/eKNTceYkIkclfHkOpa2gq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlWHGr%2Fbtq6BCm338J%2FeKNTceYkIkclfHkOpa2gq0%2Fimg.png&quot; width=&quot;751&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;606&quot; height=&quot;759&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://scslab-intern.gitbooks.io/linux-kernel-hacking/content/chapter13.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;버퍼 캐시&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디스크에서 데이터 블럭을 읽고 쓸 때 디스크 접근 횟수를 줄이기 위해 해시 테이블로 구현된 블럭 버퍼에 대한 캐시&lt;/li&gt;
&lt;li&gt;파일 시스템이 데이터 블럭을 읽고 쓰는 요청을 보내면, 표준 커널 함수를 호출하여 블럭 디바이스 드라이버에게 buffer_head 구조체를 전달. 이 구조체는 블럭 디바이스 드라이버가 필요로 하는 모든 정보를 제공
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장치 식별자는 장치를 유일하게 구별해주고, 블록 번호는 읽어야 할 위치를 알려줌&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;모든 블럭 버퍼들은 새 것이거나 안 쓰이거나 상관없이 버퍼 캐시 어딘가에 존재하며, 모든 블럭 장치들이 이 캐시를 공유&lt;/li&gt;
&lt;li&gt;지원하는 버퍼 크기별로 각각 하나의 리스트가 존재하며, 시스템의 프리 블럭 버퍼는 처음 만들어질 때나 블럭이 해제될 때 이 리스트에 추가됨 (현재 지원하는 버퍼 크기는 512, 1024, 2048, 4096, 8192바이트)&lt;/li&gt;
&lt;li&gt;버퍼 캐시는 똑같은 해시 값을 가지는 버퍼들의 리스트를 참조하는 포인터들의 배열로, 해시 값은 블럭 버퍼를 소유하는 장치 식별자와 버퍼의 블럭 번호로 산출되며, 각 버퍼 유형마다 LRU 리스트가 있고 캐시에 추가되면 이 리스트에도 추가됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LRU 리스트는 특정 유형의 버퍼에 대해 작업할 때 사용되며, 새로운 데이터를 가진 버퍼를 디스크에 기록&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;버퍼의 유형은 버퍼의 상태를 반영한 것
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;clean&lt;/b&gt; 사용하지 않은 새 버퍼&lt;/li&gt;
&lt;li&gt;&lt;b&gt;locked&lt;/b&gt;&amp;nbsp;버퍼에 락이 걸려 있으며, 기록되기를 기다리는 버퍼&lt;/li&gt;
&lt;li&gt;&lt;b&gt;dirty&lt;/b&gt;&amp;nbsp;새롭고 유효한 데이터를 가지며, 언제 기록될지 스케줄되지 않은 버퍼&lt;/li&gt;
&lt;li&gt;&lt;b&gt;shared&lt;/b&gt;&amp;nbsp;공유 버퍼&lt;/li&gt;
&lt;li&gt;&lt;b&gt;unshared&lt;/b&gt;&amp;nbsp;이전에 공유되었으나 지금은 공유하지 않는 버퍼&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;블럭 버퍼는 프리 리스트 중 어떤 하나의 리스트나, 버퍼 캐시 둘 중 하나에만 속함&lt;/li&gt;
&lt;li&gt;파일 시스템이 물리 장치로부터 버퍼를 읽을 때마다 가장 먼저 버퍼 캐시에 접근해서 블럭을 얻으려고 시도
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 버퍼 캐시에서 얻을 수 없다면, 프리 리스트에서 적당한 크기의 버퍼를 하나 얻고, 이는 버퍼 캐시에 추가됨&lt;/li&gt;
&lt;li&gt;만약 버퍼 캐시에서 얻을 수 있다면, 최근 것이 아니고 새로운 버퍼일 경우 파일 시스템은 디바이스 드라이버에게 해당하는 데이터 블럭을 디스크에 요청해서 읽어옴&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;bdflush 커널 데몬&lt;/b&gt;&amp;nbsp; 버퍼 캐시를 사용하는 블럭 장치들 사이에 공평하게 캐시 엔트리를 할당하는 데몬&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시스템에 있는 더티 버퍼의 개수가 충분히 많아지기를 기다리며 잠들어 있다가 버퍼가 할당되거나 버려질 때 시스템에 있는 더티 버퍼의 개수를 검사&lt;/li&gt;
&lt;li&gt;전체 버퍼의 개수 중 더티 버퍼의 비율이 너무 커지면 bdflush 가 깨어나 BUF_DIRTY_LRU 리스트에 데이터 버퍼를 연결 (비율은 기본값이 60%이지만, 시스템에서 버퍼가 필요하다면 이 데몬은 언제든 깨어남)&lt;/li&gt;
&lt;li&gt;bdflush는 이중에서 적당한 개수(디폴트 500)를 디스크에 기록&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;update 명령어&lt;/b&gt;&amp;nbsp;실행될 때마다 시스템에 있는 모든 더티 버퍼에서 시간이 만료된 것들만 디스크에 기록. 더티 버퍼가 다 쓰여지면 시스템 시간을 표시&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;779&quot; height=&quot;552&quot; data-origin-width=&quot;608&quot; data-origin-height=&quot;431&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgt2CS/btq6LQqtY8W/Yb1oekS5cQ88lLD9vFR2Vk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgt2CS/btq6LQqtY8W/Yb1oekS5cQ88lLD9vFR2Vk/img.png&quot; data-alt=&quot;버퍼 캐시 커널 자료구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgt2CS/btq6LQqtY8W/Yb1oekS5cQ88lLD9vFR2Vk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcgt2CS%2Fbtq6LQqtY8W%2FYb1oekS5cQ88lLD9vFR2Vk%2Fimg.png&quot; width=&quot;779&quot; height=&quot;552&quot; data-origin-width=&quot;608&quot; data-origin-height=&quot;431&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;버퍼 캐시 커널 자료구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;/proc 파일 시스템&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제로 존재하는 것이 아니며, 내부 파일과 디렉토리를 커널에 있는 정보를 가지고 생성&lt;/li&gt;
&lt;li&gt;실제 파일 시스템과 마찬가지로 자신을 VFS에 등록하고 파일이나 디렉토리를 열면 VFS가 inode를 요청&lt;/li&gt;
&lt;li&gt;커널의 /proc/devices 파일은 장치들을 나타내는 커널 자료구조로부터 생성됨&lt;/li&gt;
&lt;li&gt;/proc 파일 시스템은 사용자에게 커널 내부 작업을 볼 수 있는 뷰(view)를 제공&lt;/li&gt;
&lt;li&gt;커널 모듈같은 몇몇 리눅스 서브시스템들은 /proc 파일 시스템에 엔트리를 생성함&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;734&quot; height=&quot;591&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;589&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7R91B/btq6CN2ZCkH/3Q4rdcb3kobKNtGv6Xu9fK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7R91B/btq6CN2ZCkH/3Q4rdcb3kobKNtGv6Xu9fK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7R91B/btq6CN2ZCkH/3Q4rdcb3kobKNtGv6Xu9fK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7R91B%2Fbtq6CN2ZCkH%2F3Q4rdcb3kobKNtGv6Xu9fK%2Fimg.png&quot; width=&quot;734&quot; height=&quot;591&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;589&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;장치 특수 파일(Device Special File)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리눅스는 하드웨어 장치들을 특수 파일로 저장하며, /dev/null의 경우 널 장치라 해서 윈도우즈의 휴지통과 같은 역할을 함&lt;/li&gt;
&lt;li&gt;장치 파일은 파일 시스템에서 어떤 데이터 영역도 차지하지 않으며, EXT2와 VFS는 모두 장치 파일을 inode의 특수한 유형으로 구현&lt;/li&gt;
&lt;li&gt;장치 파일에는 2가지 형태가 존재: &lt;b&gt;문자 특수 파일, 블럭 특수 파일&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;문자 장치는 문자 모드로 I/O 작업을 할 수 있고, 블럭 장치는 모든 I/O가 버퍼 캐시를 통하도록 되어 있음&lt;/li&gt;
&lt;li&gt;장치 파일로 I/O를 요구하면, 시스템 내에 있는 해당 디바이스 드라이버가 요청을 받음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디바이스 드라이버는 실제하지 않고 SCSI 디바이스 드라이버 같은 어떤 서브시스템을 위한 유사 디바이스 드라이버일 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;커널에서 모든 장치는 각각 kdev_t 구조체로 기술되고, 이는 2바이트 길이로 첫번째 바이트는 마이너 장치 번호, 두번째 바이트는 메이저 장치 번호를 의미. (장치의 유형을 구별하는 메이저 번호와, 장치 유형의 하나의 케이스를 구별하는 마이너 번호로 장치 파일이 참조됨)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Operating System/Linux</category>
      <category>ext2</category>
      <category>file system</category>
      <category>inode</category>
      <category>Linux Kernel</category>
      <category>Operating System</category>
      <category>vfs</category>
      <category>가상 파일 시스템</category>
      <category>리눅스 커널</category>
      <category>운영체제</category>
      <category>파일 시스템</category>
      <author>r4v3n-k</author>
      <guid isPermaLink="true">https://movefast.tistory.com/349</guid>
      <comments>https://movefast.tistory.com/349#entry349comment</comments>
      <pubDate>Sun, 6 Jun 2021 19:27:26 +0900</pubDate>
    </item>
    <item>
      <title>리눅스 커널 - 디바이스 드라이버 2</title>
      <link>https://movefast.tistory.com/348</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;본 글은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;http://wiki.kldp.org/Translations/html/The_Linux_Kernel-KLDP/The_Linux_Kernel-KLDP.html&quot;&gt;The Linux Kernel&lt;/a&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;을 정리한 것이며, 출처를 밝히지 않은 모든 이미지는 원글에 속한 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;하드 디스크&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;380&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vvjxC/btq6AdgtlCo/QSvlvcmfksh4cjHF9JC89k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vvjxC/btq6AdgtlCo/QSvlvcmfksh4cjHF9JC89k/img.png&quot; data-alt=&quot;https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&amp;amp;amp;amp;blogId=capemay&amp;amp;amp;amp;logNo=220221154613&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vvjxC/btq6AdgtlCo/QSvlvcmfksh4cjHF9JC89k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvvjxC%2Fbtq6AdgtlCo%2FQSvlvcmfksh4cjHF9JC89k%2Fimg.png&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;380&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&amp;amp;blogId=capemay&amp;amp;logNo=220221154613&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하드 디스크는 &lt;b&gt;작동기(actuator)&lt;/b&gt;로 원반 표면 위에서 헤드를 움직이게 하며, 이 &lt;b&gt;원반(platter)&lt;/b&gt;은 가운데 &lt;b&gt;축(spindle)&lt;/b&gt;에 연결되어 일정한 속도로 회전하는데 이 원반은 하나 이상 존재
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;회전 속도는 3000RPM ~ 10000RPM 사이 다양함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;읽기/쓰기 헤드(read/write head)&lt;/b&gt;는 원반 표면에 있는 미세한 알갱이에 자성을 띄워서 디스크에 자료를 기록하고, 이 자성을 감지하여 자료를 읽음&lt;/li&gt;
&lt;li&gt;각 원반의 윗면과 아랫면에 각각 헤드가 존재하고, 읽기/쓰기 헤드는 물리적으로 원반 표면을 건드리지 않고 아주 얕게 원반 위에 떠있으며, 모든 읽기/쓰기 헤드는 원반 표면에서 동일하게 움직임&lt;/li&gt;
&lt;li&gt;원반의 각 표면은 &lt;b&gt;트랙(track)&lt;/b&gt;이라는 작은 동심원으로 나누어지며, 바깥쪽에 있을 수록 작은 번호, 중심에 가까울수록 큰 번호의 트랙&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실린더(cylinder)&lt;/b&gt;는 동일한 번호를 가진 트랙의 집합으로, 원반 양면의 k번 트랙은 모두 k번 실린더&lt;/li&gt;
&lt;li&gt;각 트랙은 &lt;b&gt;섹터(sector)&lt;/b&gt;로 나뉘며, 섹터는 자료를 디스크에 저장하고 읽어들이는 최소 단위로, 디스크 블럭 크기와 동일 (보통 512바이트로, 이 크기는 디스크 제작 후 포맷 시 지정됨)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;터미널에서 출력했을 때 보여지는 디스크 용량이 더 작은 이유는 섹터 중 일부는 디스크 파티션 정보를 저장하므로 제외되기 때문&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;디스크는 보통 기하학 구조로 표현되며, 부팅 시 IDE 디스크는 다음과 같이 나타낼 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;hdb: Conner Peripherals 540MB-CFS540A, &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;516MB&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot;&gt; w/64kB Cache, &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;CHS=1050/16/63&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;디스크 1050개의 실린더(트랙), 16개의 헤드(8개의 원반), 각 트랙에는 63개의 섹터가 있음을 의미&lt;/li&gt;
&lt;li&gt;디스크 저장 용량은 516MB&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;어떤 디스크들은 자동으로 배드 섹터(bad sector)를 찾아내서 디스크가 제대로 작동하도록 인덱스를 다시 부여하기도 함&lt;/li&gt;
&lt;li&gt;하드 디스크는 특별한 목적을 위해 할당된 섹터들의 그룹인 &lt;b&gt;파티션(partition)&lt;/b&gt; 단위로 쪼개질 수 있고, 파티셔닝은 디스크를 여러 OS에게 나눠주는 등의 이유로 사용&lt;/li&gt;
&lt;li&gt;많은 리눅스 시스템은 하나의 디스크에 3개의 파티션을 포함: DOS 파일 시스템, EXT2 파일 시스템, 스왑 파티션
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이러한 파티션 정보는 파티션 테이블에 나와 있으며, 이 테이블의 각 엔트리는 파티션의 시작과 끝에 해당되는 헤드와 섹터, 실린더 번호를 포함&lt;/li&gt;
&lt;li&gt;fdisk로 DOS로 포맷된 디스크는 4개의 1차 디스크 파티션(primary disk partition)을 가질 수 있고, 파티션 테이블의 4개 엔트리 모두 쓰일 필요는 없음&lt;/li&gt;
&lt;li&gt;fdisk는 3가지 유형의 파티션을 지원: 1차(primary), 확장(ㄷxtended), 논리(logical) 파티션&lt;/li&gt;
&lt;li&gt;확장 파티션은 진짜 파티션이 아니며, 여러 논리 파티션을 가지고 있는 것&lt;/li&gt;
&lt;li&gt;다음은 2개의 1차 파티션을 갖는 디스크에 fdisk를 실행한 결과: 첫번째 파티션이 헤드 1, 섹터 1, 실린더 0에서 시작하며, 헤드 63, 섹터 32, 실린더 477 까지 있음을 의미. 두번째 파티션은 스왑 파티션으로 다음 실린더 478에서 시작하여 디스크 가장 안쪽 실린더까지 포함 (원반 표면의 바깥에서 안쪽 방향으로 각 파티션들이 위치함)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;769&quot; height=&quot;264&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;470&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EJhEk/btq6DCFPEz8/BTHGW826VbHfYNGU7N7X4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EJhEk/btq6DCFPEz8/BTHGW826VbHfYNGU7N7X4K/img.png&quot; data-alt=&quot;fdisk 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EJhEk/btq6DCFPEz8/BTHGW826VbHfYNGU7N7X4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEJhEk%2Fbtq6DCFPEz8%2FBTHGW826VbHfYNGU7N7X4K%2Fimg.png&quot; width=&quot;769&quot; height=&quot;264&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;470&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;fdisk 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리눅스는 초기화할 때 하드 디스크의 배치도를 메모리에 매핑하는데, 먼저 시스템에 디스크 개수와 각 디스크의 종류를 파악하여 각 디스크 파티션이 나누어지는 구조를 탐색&lt;/li&gt;
&lt;li&gt;IDE 같은 개별 디스크 서브시스템은 초기화할 때 찾은 디스크를 gendisk 구조체로 기술하며,&amp;nbsp;gendisk_head 포인터가 이 구조체들의 리스트를 참조
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 gendisk 구조체는 블럭 특수 장치의 메이저 번호와 일치하는 고유한 번호를 가짐&lt;/li&gt;
&lt;li&gt;아래 그림의 맨 앞 gendisk는 SCSI 디스크 서브시스템의 것이고, 다음은 IDE 디스크 서브시스템의 것으로, 첫번째 IDE 컨트롤러는 &quot;ide0&quot;&lt;/li&gt;
&lt;li&gt;gendisk 구조체는 리눅스가 파티션을 검사할 때만 쓰이며, 각 디스크 서브시스템은 장치의 메이저와 마이너 장치 번호를 물리 디스크에 있는 파티션과 매핑시킬 수 있도록 각자의 자료구조를 구축함&lt;/li&gt;
&lt;li&gt;블럭 장치가 버퍼 캐시나 파일 연산을 통해 읽혀지거나 쓰일 때, 커널은 이 연산을 블럭 장치 특수 파일(e.g., /dev/sda2)에서 발견한 메이저 장치 번호를 이용하여 올바른 장치로 보냄&lt;/li&gt;
&lt;li&gt;마이너 장치 번호를 물리 장치에 연결하는 것은 개별 디스크 드라이버나 서브시스템의 역할 (마이너 장치 번호로 장치를 구별)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;829&quot; height=&quot;394&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;350&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ReF01/btq6Gqro8F1/KvjWbDug2jBENHwZjBzloK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ReF01/btq6Gqro8F1/KvjWbDug2jBENHwZjBzloK/img.png&quot; data-alt=&quot;디스크 커널 자료구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ReF01/btq6Gqro8F1/KvjWbDug2jBENHwZjBzloK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FReF01%2Fbtq6Gqro8F1%2FKvjWbDug2jBENHwZjBzloK%2Fimg.png&quot; width=&quot;829&quot; height=&quot;394&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;350&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;디스크 커널 자료구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;725&quot; data-original=&quot;https://pic1.xuehuaimg.com/proxy/csdn/https://img-blog.csdnimg.cn/2019040315124076.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc4MDI2MA==,size_8,color_FFFFFF,t_70&quot; data-loaded=&quot;true&quot; data-origin-width=&quot;1734&quot; data-origin-height=&quot;1222&quot; height=&quot;511&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSWVMb/btq6GoG7Gw5/GHhrJ2b7xLtj1kmomJkRKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSWVMb/btq6GoG7Gw5/GHhrJ2b7xLtj1kmomJkRKK/img.png&quot; data-alt=&quot;https://www.twblogs.net/a/5ca59651bd9eee5b1a0720f4&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSWVMb/btq6GoG7Gw5/GHhrJ2b7xLtj1kmomJkRKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSWVMb%2Fbtq6GoG7Gw5%2FGHhrJ2b7xLtj1kmomJkRKK%2Fimg.png&quot; width=&quot;725&quot; data-original=&quot;https://pic1.xuehuaimg.com/proxy/csdn/https://img-blog.csdnimg.cn/2019040315124076.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc4MDI2MA==,size_8,color_FFFFFF,t_70&quot; data-loaded=&quot;true&quot; data-origin-width=&quot;1734&quot; data-origin-height=&quot;1222&quot; height=&quot;511&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.twblogs.net/a/5ca59651bd9eee5b1a0720f4&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;IDE(Intergrated Disk Electronics) 디스크&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;u&gt;IDE는 SCSI 같은 I/O 버스가 아닌 디스크 인터페이스&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;각 IDE 컨트롤러는 2개의 디스크까지 지원: 주 디스크(master), 종속 디스크(slave)&lt;/li&gt;
&lt;li&gt;IDE는 1초에 3.3 Mbytes의 데이터를 전송, 디스크 최대 크기는 538MB&lt;/li&gt;
&lt;li&gt;확장 IDE(Extended IDE, EIDE)는 디스크 크기를 최대 8.6GB로 가지며, 전송 속도를 초당 16.6MB로 올린 것&lt;/li&gt;
&lt;li&gt;IDE/EIDE 디스크는 SCSI 디스크보다 저렴하며 대부분 PC는 IDE 컨트롤러를 포함&lt;/li&gt;
&lt;li&gt;리눅스는 IDE 디스크의 이름을 컨트롤러(최대 2개)를 발견한 순서에 따라 부여함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1차 IDE 컨트롤러의 주 디스크는 /dev/hda 이고 종속 디스크는 /dev/hdb&lt;/li&gt;
&lt;li&gt;2차 IDE 컨트롤러의 주 디스크는 /dev/hdc&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;IDE 서브시스템은 커널에 IDE 컨트롤러를 등록하지만 디스크를 등록하지는 않음&lt;/li&gt;
&lt;li&gt;1차 IDE 컨트롤러의 메이저 장치 번호는 3이고, 2차 IDE 컨트롤러의 것은 22일 때, blk_dev와 blkdevs 배열의 3번과 22번 인덱스에 IDE 서브시스템 엔트리가 저장됨&lt;/li&gt;
&lt;li&gt;커널은 &lt;u&gt;블럭 특수 파일을 관리하는 IDE 서브시스템에 대한 파일 연산이나 버퍼 캐시 연산&lt;/u&gt;을 메이저 장치 번호를 인덱스로 사용하여 알아낸 IDE 서브시스템으로 전달하며,&amp;nbsp;어떤 디스크에 대한 요청인지는 IDE 서브시스템이 마이너 장치 번호를 사용하여 판별&lt;/li&gt;
&lt;li&gt;&lt;b&gt;IDE 서브시스템 초기화&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커널은 시스템의 CMOS 메모리에 디스크 정보를 살펴보고, 발견한 디스크의 기하학 정보를 BIOS로부터 알아내 이 정보를 각자의 ide_hwif_t 구조체를 설정하는데 사용함&lt;/li&gt;
&lt;li&gt;최근 PCI EIDE 컨트롤러를 포함하는 경우 PCI 칩셋을 사용하는데, 여기서 PCI BIOS 콜백을 이용해서 컨트롤러를 찾음&lt;/li&gt;
&lt;li&gt;IDE 컨트롤러가 발견되면, 연결된 디스크를 반영하여 ide_hwif_t가 설정됨&lt;/li&gt;
&lt;li&gt;IDE 드라이버가 I/O 메모리 공간에 있는 IDE 명령 레지스터에 쓰면서 동작하는데, 각 컨트롤러는 리눅스 블럭 버퍼 캐시와 가상 파일 시스템에 자신을 등록 (blk_dev와 blkdevs 배열에 추가되는 것)&lt;/li&gt;
&lt;li&gt;추가로, 인터럽트에 대한 제어권을 요청하고, 부팅 시 발견된 컨트롤러마다 gnedisk 구조체를 생성해 gendisk_head 포인터가 참조하는 리스트에 추가 (이 리스트는 디스크의 파티션을 찾는데 사용됨)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SCSI(Small Computer System Interface) 디스크&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;SCSI 버스&lt;/b&gt; 하나 이상의 호스트를 포함하여 버스마다 8개까지의 장치를 지원할 수 있는 1:1 데이터 버스&lt;/li&gt;
&lt;li&gt;각 장치는 고유 식별자를 가지며, 대개 디스크에 있는 점퍼로 설정됨&lt;/li&gt;
&lt;li&gt;버스에 있는 두 장치 사이에는 동기적 또는 비동기적 데이터 전송이 가능하며, 32비트 크기로 초당 40MB까지 허용&lt;/li&gt;
&lt;li&gt;SCSI 버스는 데이터 뿐만 아니라 상태 정보도 전송&lt;/li&gt;
&lt;li&gt;전송 시작(initator)과 전송 대상(target) 사이의 하나의 트랜잭션은 8개의 서로 다른 상태를 가지며, SCSI 버스의 현재 상태는 5개의 신호로부터 알 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;BUS FREE&lt;/b&gt; 버스에 대한 제어권을 가진 장치 또는 트랜잭션이 없음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ARBITRATION&lt;/b&gt; 어떤 장치가 자신의 식별자를 보내 SCSI 버스에 대한 제어권을 얻는 중(중재), 동시에 발생할 경우 더 높은 번호에 제어권이 주어짐&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SELECTION&lt;/b&gt;&amp;nbsp;장치가 중재를 통해 제어권을 얻으면, SCSI 요청을 받을 대상에게 명령을 보낼 준비라는 신호를 전달&lt;/li&gt;
&lt;li&gt;&lt;b&gt;COMMAND&lt;/b&gt;&amp;nbsp;6/10/12 바이트의 명령을 전송 시작자에서 전송 대상으로 전달&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DATA IN, DATA OUT&lt;/b&gt;&amp;nbsp;데이터가 전달되는 상태&lt;/li&gt;
&lt;li&gt;&lt;b&gt;STATUS&lt;/b&gt;&amp;nbsp;모든 명령을 완료한 상태로, 성공과 실패를 나타내는 바이트를 응답해야 함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MESSAGE IN, MESSAGE OUT&lt;/b&gt;&amp;nbsp;추가적인 정보 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SCSI 서브시스템의 2가지 요소(호스트와 장치)는 각 자료구조로 표현됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;호스트(host)&lt;/b&gt;&amp;nbsp;SCSI 컨트롤러, 같은 종류의 컨트롤러가 하나 이상 존재하면 각각 별도의 호스트로 표현
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SCSI 디바이스 드라이버는 컨트롤러가 여러개 일 때 제어 가능&lt;/li&gt;
&lt;li&gt;SCSI 호스트는 대부분 SCSI 명령의 전송 시작자&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장치(device)&lt;/b&gt;&amp;nbsp;가장 일반적인 장치 유형으로 SCSI 디스크가 있으며, 테이프나 CD-ROM 같은 여러 종류를 지원하기도 함.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 장치는 서로 다르게 취급되며, SCSI 장치는 대부분 SCSI 명령의 전송 대상&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;616&quot; height=&quot;796&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;656&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mYRPT/btq6A95k0RV/PgV3rxeoa5z3BIobyRdBC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mYRPT/btq6A95k0RV/PgV3rxeoa5z3BIobyRdBC0/img.png&quot; data-alt=&quot;SCSI 디스크 커널 자료구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mYRPT/btq6A95k0RV/PgV3rxeoa5z3BIobyRdBC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmYRPT%2Fbtq6A95k0RV%2FPgV3rxeoa5z3BIobyRdBC0%2Fimg.png&quot; width=&quot;616&quot; height=&quot;796&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;656&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SCSI 디스크 커널 자료구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;SCSI 서브시스템 초기화&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;먼저 시스템에 있는 SCSI 컨트롤러(호스트)를 찾은 뒤, SCSI 버스를 검사하여 모든 장치를 탐색&lt;/li&gt;
&lt;li&gt;각 장치를 초기화: 일반 파일 연산과 버퍼 캐시 블럭 장치 연산을 매핑하여 나중에 사용될 수 있게 함&lt;/li&gt;
&lt;li&gt;커널을 빌드할 때 SCSI 호스트 어댑터(컨트롤러) 중 제어할 하드웨어의 것을 찾음&lt;/li&gt;
&lt;li&gt;커널에 포함된 호스트들은 builtin_scsi_hosts 배열에 Scsi_Host_Template 엔트리를 가지며, 이 구조체는 각 SCSI 호스트에 어떤 SCSI 장치가 연결되었는지 알기 위해 호스트마다 고유 루틴에 대한 포인터를 포함&lt;/li&gt;
&lt;li&gt;SCSI 서브시스템은 자신을 설정하는 동안 이 루틴들을 호출하는데 루틴은 각 호스트에 대한 SCSI 디바이스 드라이버의 일부&lt;/li&gt;
&lt;li&gt;실제 장치가 연결된 호스트는 자신의 Scsi_Host_Template 구조체를 활성화된 호스트 목록인 scsi_hosts 리스트에 추가&lt;/li&gt;
&lt;li&gt;감지된 호스트 유형에 해당하는 호스트는 scsi_hostlist 리스트에 있는 Scsi_Host 구조체로 기술됨&lt;/li&gt;
&lt;li&gt;모든 호스트를 발견하면, SCSI 버스에 있는 장치로 TEST_UNIT_READY 명령을 전달해 버스에 연결된 장치들을 탐색&lt;/li&gt;
&lt;li&gt;장치가 응답하면 ENQUIRY 명령을 보내 신원 확인을 통해 커널에 제작자 이름과 장치 모델명 및 개정 이름을 전달&lt;/li&gt;
&lt;li&gt;SCSI 명령은 Scsi_Cmnd 구조체로 기술되며, Scsi_Host_Template 구조체 있는 디바이스 드라이버 루틴을 호출할 때 Scsi_Cmnd 구조체가 전달됨&lt;/li&gt;
&lt;li&gt;SCSI 장치는 Scsi_Device 구조체로 기술되며, 각각 부모 Scsi_Host 구조체를 참조하는데, 모든 Scsi_Device 구조체는 scsi_devices 리스트에 추가됨&lt;/li&gt;
&lt;li&gt;장치의 유형은 4가지가 존재: 디스크, 테이프, CD, 일반
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메이저 블럭 장치 유형으로 커널에 별도로 등록&lt;/li&gt;
&lt;li&gt;각 유형마다 장치 테이블을 관리하며, 이 테이블은 커널의 블럭 연산(파일, 버퍼 캐시)을 올바른 디바이스 드라이버나 SCSI 호스트로 보내는데 사용됨&lt;/li&gt;
&lt;li&gt;유형별로 Scsi_Device_Template 구조체를 생성하며, 이는 장치에 대한 정보 및 다양한 작업을 수행하는 루틴들의 주소를 포함. SCSI 서브시스템은 이 구조체를 이용해 장치의 유형별 루틴을 호출&lt;/li&gt;
&lt;li&gt;어떤 유형을 갖는 SCSI 장치가 하나 이상 발견되면 Scsi_Type_Template 구조체가 scsi_Devicelist 리스트에 추가됨&lt;/li&gt;
&lt;li&gt;초기화의 마지막 상태는 등록된 각 Scsi_Device_Template 구조체로부터 종료 함수를 부르는 것으로, SCSI 디스크 유형의 경우 발견한 모든 디스크를 회전시켜 각 디스크 구조를 기록한 뒤, 모든 SCSI 디스크를 나타내는 gendisk 구조체를 디스크 구조체 리스트에 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;블럭 장치 요청 전달&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SCSI 서브시스템을 초기화하면 SCSI 장치들을 사용할 수 있으며, 정상 동작하는 장치 유형은 커널에 자신을 등록하여 블럭 장치 요청이 들어올 때마다 해당 장치 유형으로 전달되게 함&lt;/li&gt;
&lt;li&gt;요청은 blk_dev 배열을 인덱싱하여 버퍼 캐시 요청이나 blkdevs 배열을 인덱싱하여 파일 연산 요청으로 나뉨&lt;/li&gt;
&lt;li&gt;SCSI 디스크에서 하나 이상의 EXT2 파일 시스템 파티션을 가지는 경우, 디바이스 드라이버는 파티션 중 하나를 마운트할 때 커널 버퍼 요청을 올바른 파일 시스템으로 전달&lt;/li&gt;
&lt;li&gt;SCSI 디스크 파티션에서 한 블럭의 데이터를 읽고 쓰는 요청은 SCSI 디스크의 current_request 리스트에 새로운 request 구조체를 추가하여 처리됨. 처리중이면 버퍼 캐시는 다른 일을 할 필요가 없으며, 처리중이 아니면, 계속 요청 큐를 하나씩 처리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SCSI 디스크 파티션의 마이너 장치 번호 중 일부를 사용하여 blk_dev 배열을 인덱싱하며, 얻은 자료구조의 일부에 current_request 포인터가 존재&lt;/li&gt;
&lt;li&gt;각 Scsi_Disk 구조체는 이 장치를 나타내는 Scsi_Device 구조체에 대한 포인터를 가짐&lt;/li&gt;
&lt;li&gt;Scsi_Device 구조체는 각자 소유한 Scsi_Host 구조체를 순서대로 참조&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;버퍼 캐시로부터 온 request 구조체는 Scsi_Cmnd 구조체로 변환되고, 이 구조체는 Scsi_Host 구조체의 큐에 추가됨&lt;/li&gt;
&lt;li&gt;한 번 데이터 블럭을 읽거나 쓰고 나면, 이 요청들은 개별 SCSI 디바이스 드라이버에 의해 처리됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;네트워크 장치&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네트워크 디바이스 드라이버는 커널이 부팅하면서 초기화하는 동안 제어하는 장치를 커널에 등록하는데, 네트워크 장치는 device 구조체로 표현되며, 각 구조체는 장치 정보 및 리눅스에서 네트워크 프로토콜들이 장치의 서비스를 이용할 수 있는 (대부분 장치를 통한 데이터 전송과 관련된) 함수들의 주소를 포함&lt;/li&gt;
&lt;li&gt;네트워크 장치 특수 파일은 초기화 과정에서 차례로 생성되며, 이들 이름은 장치 유형을 나타내는 표준 이름이며 0부터 시작하는 번호가 뒤에 붙어서 식별됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이더넷 장치: /dev/eth0, /dev/eth1, /dev/eth2&lt;/li&gt;
&lt;li&gt;SLIP 장치: /dev/sl0, /dev/sl1, /dev/sl2&lt;/li&gt;
&lt;li&gt;PPP 장치: /dev/ppp0, /dev/ppp1, /dev/ppp2&lt;/li&gt;
&lt;li&gt;루프백 장치: /dev/lo&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;device 구조체가 포함한 장치 정보 등 모든 정보는 부팅 시 초기화될 때 설정됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;버스 정보&lt;/b&gt; 디바이스 드라이버가 장치를 제어하기 위한 것&lt;/li&gt;
&lt;li&gt;&lt;b&gt;IRQ 번호&lt;/b&gt; 장치가 사용하는 인터럽트 번호&lt;/li&gt;
&lt;li&gt;&lt;b&gt;베이스 주소&lt;/b&gt; 장치의 제어 레지스터 및 상태 레지스터가 있는 I/O 공간의 주소&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DMA 채널&lt;/b&gt;&amp;nbsp;네트워크 장치가 사용하는 DMA 채널 번호&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인터페이스 플래그&lt;/b&gt; 네트워크 장치의 특징과 능력을 설명&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;586&quot; height=&quot;212&quot; data-origin-width=&quot;1084&quot; data-origin-height=&quot;392&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIzRjq/btq6HkYRNLH/ifd4XkGy9xAO73tkiEf1K0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIzRjq/btq6HkYRNLH/ifd4XkGy9xAO73tkiEf1K0/img.png&quot; data-alt=&quot;인터페이스 플래그&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIzRjq/btq6HkYRNLH/ifd4XkGy9xAO73tkiEf1K0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIzRjq%2Fbtq6HkYRNLH%2Fifd4XkGy9xAO73tkiEf1K0%2Fimg.png&quot; width=&quot;586&quot; height=&quot;212&quot; data-origin-width=&quot;1084&quot; data-origin-height=&quot;392&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;인터페이스 플래그&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;프로토콜 정보&lt;/b&gt;&amp;nbsp;네트워크 프로토콜 게층이 장치를 제어하는 방법을 나타냄
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;MTU&lt;/b&gt;&amp;nbsp;링크 계층에서 붙이는 헤더를 제외하고 전송 가능한 최대 패킷 크기&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Family&lt;/b&gt;&amp;nbsp;장치가 지원할 수 있는 프로토콜 계열 e.g., AF_INET: 인터넷 주소&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Type&lt;/b&gt;&amp;nbsp;하드웨어 인터페이스 유형으로, 장치에 연결된 매체 e.g., 이더넷&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Address&lt;/b&gt;&amp;nbsp;device 구조체는 IP 주소를 포함하여 여러 주소를 가짐&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;패킷 큐(Packet Queue)&lt;/b&gt; 네트워크 장치가 전송하기를 기다리는 sk_buff 구조체의 리스트
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;보내고 받는 모든 네트워크 데이터(패킷)은 sk_buff 구조체로 기술됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;각 장치는 프로토콜 계층에서 호출 가능한 표준 함수 집합을 제공하여 전송받은 데이터를 올바른 프로토콜 계층으로 전달&lt;/li&gt;
&lt;li&gt;이는 셋업하고 프레임을 전송하는 루틴 외에 표준 프레임 헤더를 추가하고 통계 정보를 모으는 루틴도 포함되어 있으며, 통계 정보는 ifconfig 명령으로 출력 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;네트워크 장치 초기화&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네트워크 게층은 장치에 고유한 작업을 수행할 때 device 구조체에 있는 서비스 루틴을 호출&lt;/li&gt;
&lt;li&gt;단, device 구조체는 최초에 초기화나 장치를 탐사(probe)하는 루틴의 주소만 가짐&lt;/li&gt;
&lt;li&gt;장치의 초기화 루틴을 호출하면, 구동할 컨트롤러가 존재하는지 나타내는 상태값을 얻게 되고, 아무런 장치도 못찾으면 dev_base 포인터가 참조하는 device 리스트에 있는 엔트리가 제거됨&lt;/li&gt;
&lt;li&gt;장치를 찾게 되면, device 구조체의 나머지 부분을 장치 정보 및 드라이버가 지원하는 함수들로 설정&lt;/li&gt;
&lt;li&gt;장치 리스트에는 eth0 부터 eht7 까지 8개의 표준 엔트리가 있는데, 초기화 코드는 장치를 찾을 때까지 이더넷 디바이스 드라이버를 하나씩 시도&lt;/li&gt;
&lt;li&gt;이더넷 장치를 찾으면 device 구조체의 내용을 채우고, 제어할 하드웨어를 초기화한 뒤 사용할 IRQ 번호 및 DMA 채널 등을 알아냄. 8개 모두 할당되면 이더넷 장치를 더 이상 찾지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;네트워크 장치 파일은 실제로 장치가 존재하는 경우에만 생성되나, 보통 문자 장치나 블럭 장치는 실제로 장치가 존재하지 않더라도 장치 특수 파일이 존재함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Operating System/Linux</category>
      <category>Device Driver</category>
      <category>Linux Kernel</category>
      <category>Operating System</category>
      <category>네트워크 장치</category>
      <category>디바이스 드라이버</category>
      <category>리눅스 커널</category>
      <category>운영체제</category>
      <category>하드 디스크</category>
      <author>r4v3n-k</author>
      <guid isPermaLink="true">https://movefast.tistory.com/348</guid>
      <comments>https://movefast.tistory.com/348#entry348comment</comments>
      <pubDate>Sat, 5 Jun 2021 21:22:50 +0900</pubDate>
    </item>
    <item>
      <title>리눅스 커널 - 디바이스 드라이버 1</title>
      <link>https://movefast.tistory.com/347</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;본 글은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;http://wiki.kldp.org/Translations/html/The_Linux_Kernel-KLDP/The_Linux_Kernel-KLDP.html&quot;&gt;The Linux Kernel&lt;/a&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;을 정리한 것이며, 출처를 밝히지 않은 모든 이미지는 원글에 속한 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;하드웨어 장치의 추상화&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;운영체제는 하드웨어 장치별로 다른 특징을 보이지 않는, 일관된 인터페이스를 사용자에게 제공&lt;/li&gt;
&lt;li&gt;모든 물리 장치는 각자의 하드웨어 컨트롤러를 가지며, 모든 하드웨어 컨트롤러는 각자의 고유한 &lt;b&gt;제어/상태 레지스터(Control and Status Registers, CSRs)&lt;/b&gt;를 포함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;키보드, 마우스, 직렬포트는 Super I/O 칩이 제어하며, IDE 디스크는 IDE 컨트롤러, SCSI 디스크는 SCSI 컨트롤러가 제어&lt;/li&gt;
&lt;li&gt;CSRs는 장치를 시작 및 중단하고 초기화하며, 문제가 발생했을 때 진단하는 용도로 사용됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커널에는 하드웨어 컨트롤러를 제어하고 관리하기 위해 디바이스 드라이버(Device Driver)가 존재하는데, 이는 커널 모드에서 실행되고 메모리에 존재하며 저수준 하드웨어 처리 루틴을 포함한 공유 라이브러리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 디바이스 드라이버는 각자 관리하는 장치들의 특성들을 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모든 물리 장치들은 일반 파일처럼 사용자에게 보여지며, 이를 장치 특수 파일(device special file)이라고 하는데, 파일을 다루는 표준 시스템 콜을 이용해서 열고, 닫고, 읽고, 쓸 수 있음&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IDE 디스크는 /dev/hda 로 나타냄&lt;/li&gt;
&lt;li&gt;네트워크 장치들도 파일로 표시되지만 커널이 네트워크 컨트롤러를 초기화할 때 장치 특수 파일이 생성됨&lt;/li&gt;
&lt;li&gt;동일한 디바이스 드라이버로 제어되는 모든 장치는 동일한 메이저 장치 번호를 가지며, 각 장치나 컨트롤러를 구분하기 위해 마이너 장치 번호를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;리눅스는 문자, 블럭, 네트워크 3가지 종류로 하드웨어 장치의 추상화를 제공&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문자 장치는 버퍼 없이 하나씩 바로 읽고 쓸 수 있음 e.g., 키보드&lt;/li&gt;
&lt;li&gt;블럭 장치는 일정한 크기(512 또는 1024바이트)의 배수로만 읽고 쓸 수 있음 e.g., 하드 디스크&lt;/li&gt;
&lt;li&gt;네트워크 장치는 BSD 소켓 인터페이스로 하위 네트워크 계층(TCP/IP)에 접근할 수 있음 e.g., 이더넷&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커널 디바이스 드라이버의 공통 특성&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커널 코드의 일부로, 잘못되면 시스템에 큰 피해를 줄 수 있음&lt;/li&gt;
&lt;li&gt;커널이나 자신이 속한 서브시스템에 표준 인터페이스를 제공
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;터미널 디바이스 드라이버는 커널에 파일 I/O 인터페이스를 제공&lt;/li&gt;
&lt;li&gt;SCSI 디바이스 드라이버는 커널에 파일 I/O와 버퍼 캐시 인터페이스를 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;커널 메커니즘 및 서비스 제공: 메모리 할당, 인터럽트 전달, 대기 큐 같은 커널 서비스 사용&lt;/li&gt;
&lt;li&gt;대부분 디바이스 드라이버는 필요 시 물리 메모리에 로드하고 필요없으면 언로드 가능&lt;/li&gt;
&lt;li&gt;커널에 포함된 상태로 함께 컴파일 될 수 있고, 장치는 컴파일 시 설정 가능&lt;/li&gt;
&lt;li&gt;부팅 후 디바이스 드라이버가 초기화 될 때, 시스템은 제어할 하드웨어 장치를 가지며, 없다하더라도 문제가 되지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;폴링(Polling)과 인터럽트(Interrupt)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장치에 명려을 전달할 때, 그 명령이 언제 끝났는지 알 수 있는 방법&lt;/li&gt;
&lt;li&gt;&lt;u&gt;폴링하는 디바이스 드라이버&lt;/u&gt;는 시스템 타이머를 이용하여 어느정도 시간이 지나면 커널이 디바이스 드라이버에 있는 한 루틴을 호출. 이 타이머 루틴은 명령이 수행되었는지 상태를 검사 (주기적으로 확인하는 작업)&lt;/li&gt;
&lt;li&gt;&lt;u&gt;인터럽트를 이용하는 디바이스 드라이버&lt;/u&gt;는 제어하는 장치가 작업을 끝냈거나 서비스를 받아야할 때 인터럽트를 발생시킴. 커널은 이 인터럽트를 올바른 디바이스 드라이버로 전달함 (비동기적으로 요청하고 결과를 받음)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이더넷 디바이스 드라이버는 네트워크에서 패킷을 받을 때마다 인터럽트를 발생시킴&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;디바이스 드라이버는 인터럽트를 사용하기 위해 인터럽트 처리 루틴의 주소와 사용할 인터럽트 번호를 커널에 등록
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;/proc/interrupts 파일을 살펴보면, 디바이스 드라이버가 사용중인 인터럽트를 알 수 있음&lt;/li&gt;
&lt;li&gt;드라이버가 초기화될 때 인터럽트 자원(제어권)을 커널에 요청&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;357&quot; height=&quot;187&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;304&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/La1ol/btq6DS2rNOP/FIJDZaDT8NK3Xt9pxMLxj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/La1ol/btq6DS2rNOP/FIJDZaDT8NK3Xt9pxMLxj1/img.png&quot; data-alt=&quot;/proc/interrupts, 중간 숫자가 인터럽트 번호&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/La1ol/btq6DS2rNOP/FIJDZaDT8NK3Xt9pxMLxj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLa1ol%2Fbtq6DS2rNOP%2FFIJDZaDT8NK3Xt9pxMLxj1%2Fimg.png&quot; width=&quot;357&quot; height=&quot;187&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;304&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;/proc/interrupts, 중간 숫자가 인터럽트 번호&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시스템의 어떤 인터럽트들은 처음부터 고정되어 있으며, 플로피 디스크 컨트롤러의 경우 항상 6번을 사용. 또는 PCI 장치에서 발생하는 인터럽트들은 부팅 시 동적으로 할당됨&lt;/li&gt;
&lt;li&gt;PCI 디바이스 드라이버는 제어할 장치의 인터럽트 번호(IRQ)를 먼저 알아낸 뒤(즉, 탐사 과정) 인터럽트의 제어권을 요청
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리눅스는 표준 PCI BIOS 콜백을 지원해서 장치 정보를 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;인터럽트가 PIC에서 CPU로 전달될 때는 인터럽트 모드에서 처리 루틴을 실행하는데, 다른 인터럽트가 발생하지 못하므로 되도록 처리 루틴에서는 적은 일을 하고 인터럽트 전으로 돌아갈 수 있도록 스택에 컨텍스트를 저장하고 복구함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;작업량이 많으면 나중에 해도 될 일을 커널의 하반부 핸들러나 작업큐에 넣어 처리 (인터럽트 모드를 빨리 벗어나려는 의도)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;직접 메모리 접근(Direct Memory Access, DMA)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;인터럽트를 사용하는 디바이스 드라이버는 데이터의 양이 작을 때는 잘 동작하지만, 디스크 컨트롤러 및 이더넷 장치 같은 데이터 전송률이 높은 장치의 경우 CPU 이용률이 높을 수 밖에 없음&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DMA 컨트롤러는 장치와 시스템 메모리 사이에 CPU 도움 없이 데이터 전송을 가능하게 함&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;ISA DMA 컨트롤러는 8개의 DMA 채널을 제공하고, 이 중 7개를 디바이스 드라이버가 사용하는데, 드라이버끼리는 채널을 공유할 수 없음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 DMA 채널은 16비트 주소 레지스터와 16비트 카운터 레지스터로 접근 가능&lt;/li&gt;
&lt;li&gt;데이터 전송을 초기화하기 위해, 디바이스 드라이버는 DMA 채널의 두 레지스터와 데이터 전송 방향(읽기/쓰기)을 함께 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;DMA를 사용해도 좋다는 명령을 보내야 사용 가능하며, 데이터 전송이 완료되면 장치는 인터럽트를 발생시키고, 전송하는 동안 CPU는 다른 일을 할 수 있음&lt;/li&gt;
&lt;li&gt;DMA 컨트롤러는 물리 메모리에 직접 접근하기 때문에, 프로세스의 가상 메모리로 DMA를 바로 사용할 수 없고, DMA에서 사용하는 메모리는 물리 메모리에서 연속된 블럭으로 할당되어야 함&lt;/li&gt;
&lt;li&gt;사용자는 시스템 콜로 프로세스가 사용하는 물리 페이지에 락을 걸어 DMA 작업 중 스왑 아웃되는 것을 방지할 수 있음&lt;/li&gt;
&lt;li&gt;DMA가 사용하는 메모리는 하부 16MB 로 제한되어 있어 DMA 컨트롤러는 물리 메모리 전체에 접근 불가&lt;/li&gt;
&lt;li&gt;인터럽트처럼 어떤 장치가 사용하는 DMA 채널이 고정되어 있고, 이더넷 장치의 경우 하드웨어에 점퍼로 설정 가능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;또는 장치들이 CSRs를 통해 사용할 DMA 채널을 알려주고 디바이스 드라이버가 빈 채널을 사용할 수도 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;리눅스는 DMA 채널 하나당 dma_chan 구조체를 생성하며, 이 구조체의 배열을 이용하여 채널의 사용유무를 추적
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 구조체는 2개의 항목을 포함: DMA 채널의 소유자를 나타내는 문자열 및 해당 채널의 할당 유무를 나타내는 플래그&lt;/li&gt;
&lt;li&gt;cat /proc/dma 명령을 실행하면 나오는 것이 dma_chan 구조체의 배열&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DMA가 없을 때와 있을 때의 차이&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DMA 없을 때, CPU가 장치로부터 데이터 읽고 쓰는 작업을 반복해야 되서 CPU 이용률이 증가함&lt;/li&gt;
&lt;li&gt;DMA 있을 때, CPU는 장치에게 DMA 시작 신호 및 DMA 완료 인터럽트만 수신하고, 데이터 전송에는 개입하지 않기 때문에 CPU 이용률이 낮음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;815&quot; height=&quot;495&quot; data-origin-width=&quot;969&quot; data-origin-height=&quot;588&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRiCHZ/btq6AOfDiKS/LHNEYsG858g5Gkk8XlKH21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRiCHZ/btq6AOfDiKS/LHNEYsG858g5Gkk8XlKH21/img.png&quot; data-alt=&quot;http://jake.dothome.co.kr/dma-1/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRiCHZ/btq6AOfDiKS/LHNEYsG858g5Gkk8XlKH21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRiCHZ%2Fbtq6AOfDiKS%2FLHNEYsG858g5Gkk8XlKH21%2Fimg.png&quot; width=&quot;815&quot; height=&quot;495&quot; data-origin-width=&quot;969&quot; data-origin-height=&quot;588&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;http://jake.dothome.co.kr/dma-1/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;디바이스 드라이버가 제공하는 인터페이스&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;디바이스 드라이버의 메모리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디바이스 드라이버는 커널 코드의 일부이기 때문에 물리 메모리만 사용 가능&lt;/li&gt;
&lt;li&gt;인터럽트를 받았거나 하반부 핸들러 또는 작업 큐 핸들러가 스케줄되었을 때, 현재 프로세스는 바뀔 수 있는데, 이는 디바이스 드라이버가 특정 프로세스가 실행될 때 독립적으로 다른 한 켠(백그라운드)에서 실행되기 때문 (커널 코드의 특성)&lt;/li&gt;
&lt;li&gt;부팅 시 커널에서 사용할 메모리가 할당되고 메모리를 해제하는 루틴을 전달받아, 디바이스 드라이버는 사용할 메모리를 2의 제곱승 단위로 할당 받거나 해제할 수 있음&lt;/li&gt;
&lt;li&gt;디바이스 드라이버가 할당 받은 메모리를 DMA로 입출력하려면, 그 메모리를 DMA 가능이라고 지정해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;커널이 모든 종류의 디바이스 드라이버에게 서비스를 요청할 때 사용할 수 있는 공통적인 인터페이스가 존재
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서로 다른 장치들 또는 디바이스 드라이버들을 일관적이게 다루기 위한 인터페이스&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;디바이스 드라이버는 장치가 없더라도 시스템이 동작할 수 있도록 커널에 의해 초기화될 때 스스로 커널에 등록&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커널은 등록된 디바이스 드라이버들을 테이블로 관리하며, 이 테이블은 해당 종류의 장치와 인터페이스를 제공하는 함수들의 포인터를 저장하고 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;문자 장치(Character Device)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;초기화될 때, 이 장치의 디바이스 드라이버는 device_struct 구조체를 생성하여 &lt;b&gt;chrdevs&lt;/b&gt; 배열에 추가하는 것으로 커널에 자신을 등록&lt;/li&gt;
&lt;li&gt;/proc/devices 에서 문자 장치에 대한 내용은 모두 chrdevs 배열에서 가져온 것&lt;/li&gt;
&lt;li&gt;메이저 장치 번호(tty 장치는 4번 같은)는 이 배열의 인덱스로 사용되며, 고정되어 있음&lt;/li&gt;
&lt;li&gt;device_struct 구조체는 2가지 항목을 포함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디바이스 드라이버의 등록 이름에 대한 문자열 포인터&lt;/li&gt;
&lt;li&gt;파일 연산 블럭에 대한 포인터&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프로세스가 문자 장치를 나타내는 문자 특수 파일(character specific file)을 열면, 커널은 올바른 문자 디바이스 드라이버의 파일 처리 루틴이 호출되도록 설정함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 장치 특수 파일은 VFS inode로 기술되며, VFS inode는 장치의 메이저 식별자와 마이너 식별자를 가짐&lt;/li&gt;
&lt;li&gt;각 VFS inode는 파일 연산 루틴에 대한 포인터를 가지는데, 생성 시 기본 문자 장치 연산으로 설정됨 (이 연산은 가리키는 파일 시스템 객체에 따라 다름)&lt;/li&gt;
&lt;li&gt;파일 연산 함수를 실행하면, 장치의 메이저 식별자로 chrdevs 배열에 인덱싱 --&amp;gt; 이 장치에 대한 파일 연산 블럭을 가져옴 --&amp;gt; file 구조체와 파일 연산 포인터가 디바이스 드라이버의 것을 참조하도록 device_struct 구조체를 설정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이후 프로세스에서 호출하는 모든 파일 연산은 문자 장치의 파일 연산으로 매핑되어 호출됨&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;블럭 장치(Block Device)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;초기화될 때, 이 장치의 디바이스 드라이버는 device_struct 구조체를 생성하여 &lt;b&gt;blkdevs&lt;/b&gt; 배열에 추가하는 것으로 커널에 자신을 등록&lt;/li&gt;
&lt;li&gt;문자 장치와 마찬가지로, 메이저 장치 번호는 blkdevs 배열의 인덱스로 사용되며, 다른 점은 장치의 유형을 분류하는 클래스가 존재한다는 것. SCSI 장치와 IDE 장치를 클래스로 구분하며, 각 클래스는 커널에 파일 함수를 제공해야 함&lt;/li&gt;
&lt;li&gt;각 클래스의 블럭 장치들을 사용하는 디바이스 드라이버는 고유의 클래스 인터페이스를 제공하는데, 예를 들어, SCSI 디바이스 드라이버는 &quot;SCSI 서브시스템이 커널에 파일 함수를 제공하기 위해 사용하는 인터페이스&quot;를 서브시스템에 제공해야 함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모든 블럭 디바이스 드라이버는 파일 연산과 함께 버퍼 캐시에 대한 인터페이스를 제공&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;버퍼 캐시에 한 블럭의 데이터를 읽고 쓰기 위한 요청을 보내면, 각 드라이버는 all_requests (정적 리스트)에서 request 구조체를 할당받아 blk_dev_struct 구조체에 있는 request 리스크 (요청 큐)에 할당받은 것을 추가. 이후 요청 큐를 처리하기 위해 blk_dev_struct 구조체에 있는 요청 루틴의 주소로 점프해서 요청을 처리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;blk_dev_struct 구조체는 blk_dev 배열의 원소이며, 메이저 장치 번호로 인덱싱됨&lt;/li&gt;
&lt;li&gt;각 request 구조체는 하나 이상의 buffer_head 구조체에 대한 포인터를 가지며, 이 구조체는 버퍼 캐시에 의해 락됨&lt;/li&gt;
&lt;li&gt;이 버퍼로 블럭 연산이 끝날 때까지 프로세스는 대기 상태가 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;요청이 처리되면 드라이버는 request 구조체에서 각 buffer_head 구조체를 제거하고 갱신되었음을 표시한 뒤 락을 해제. 대기 중인 프로세스는 다음 스케줄링에서 실행됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;755&quot; height=&quot;416&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;406&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dVY6er/btq6DDK7eYM/5bEevlAKDPP4m40vtcERd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dVY6er/btq6DDK7eYM/5bEevlAKDPP4m40vtcERd1/img.png&quot; data-alt=&quot;blk_dev 구조체&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dVY6er/btq6DDK7eYM/5bEevlAKDPP4m40vtcERd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdVY6er%2Fbtq6DDK7eYM%2F5bEevlAKDPP4m40vtcERd1%2Fimg.png&quot; width=&quot;755&quot; height=&quot;416&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;406&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;blk_dev 구조체&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;583&quot; height=&quot;657&quot; data-origin-width=&quot;484&quot; data-origin-height=&quot;545&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dWeKOR/btq6AsjEa03/nKM8L3V9kNXijpkg510vK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dWeKOR/btq6AsjEa03/nKM8L3V9kNXijpkg510vK1/img.png&quot; data-alt=&quot;https://lwn.net/Kernel/LDD2/ch12.lwn&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dWeKOR/btq6AsjEa03/nKM8L3V9kNXijpkg510vK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdWeKOR%2Fbtq6AsjEa03%2FnKM8L3V9kNXijpkg510vK1%2Fimg.png&quot; width=&quot;583&quot; height=&quot;657&quot; data-origin-width=&quot;484&quot; data-origin-height=&quot;545&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://lwn.net/Kernel/LDD2/ch12.lwn&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;707&quot; height=&quot;519&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;353&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bG6d34/btq6DSuEHFq/46Qk4kzQPdFaoTLtCKmrF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bG6d34/btq6DSuEHFq/46Qk4kzQPdFaoTLtCKmrF0/img.png&quot; data-alt=&quot;https://lwn.net/Kernel/LDD2/ch12.lwn&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bG6d34/btq6DSuEHFq/46Qk4kzQPdFaoTLtCKmrF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbG6d34%2Fbtq6DSuEHFq%2F46Qk4kzQPdFaoTLtCKmrF0%2Fimg.png&quot; width=&quot;707&quot; height=&quot;519&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;353&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://lwn.net/Kernel/LDD2/ch12.lwn&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Operating System/Linux</category>
      <category>Device Driver</category>
      <category>DMA</category>
      <category>Linux Kernel</category>
      <category>Operating System</category>
      <category>디바이스 드라이버</category>
      <category>리눅스 커널</category>
      <category>문자 장치</category>
      <category>블럭 장치</category>
      <category>운영체제</category>
      <category>인터럽트</category>
      <author>r4v3n-k</author>
      <guid isPermaLink="true">https://movefast.tistory.com/347</guid>
      <comments>https://movefast.tistory.com/347#entry347comment</comments>
      <pubDate>Sat, 5 Jun 2021 10:31:49 +0900</pubDate>
    </item>
    <item>
      <title>리눅스 커널 - 인터럽트와 인터럽트 처리</title>
      <link>https://movefast.tistory.com/346</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;본 글은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;http://wiki.kldp.org/Translations/html/The_Linux_Kernel-KLDP/The_Linux_Kernel-KLDP.html&quot;&gt;The Linux Kernel&lt;/a&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;을 정리한 것이며, 출처를 밝히지 않은 모든 이미지는 원글에 속한 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;인터럽트(Interrupt)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;커널은 장치에 요청을 한 뒤 기다리지 않고 다른 작업을 하면서 요청한 작업이 끝나면 장치로부터 인터럽트를 받음&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리눅스는 여러 하드웨어 장치를 사용하는데, 동기적으로 구동할 경우 요청을 완료할 때까지 기다려야하는 문제가 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인터럽트를 사용할 경우 여러 장치에 동시에 작업을 요청하는 것이 가능&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;커널이 인터럽트를 처리하는데 일반적인 메커니즘과 인터페이스 표준이 존재하지만 세부 내용은 아키텍처마다 상이함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장치가 인터럽트를 전달하는 것은 하드웨어에서 지원해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;보통 CPU의 특정한 핀의 전압이 바뀌면(예를 들어 +5볼트에서 -5볼트), CPU는 하던 일을 멈추고 인터럽트 처리 코드를 실행
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 핀은 간격 타이머에 의해 1000분의 1초마다 인터럽트를 받기도 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; srcset=&quot;https://www.embien.com/blog/wp-content/uploads/interrupt-mechanism.png 960w, https://www.embien.com/blog/wp-content/uploads/interrupt-mechanism-500x375.png 500w, https://www.embien.com/blog/wp-content/uploads/interrupt-mechanism-300x225.png 300w&quot; width=&quot;599&quot; height=&quot;449&quot; data-origin-width=&quot;1012&quot; data-origin-height=&quot;759&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OjGsq/btq6AN8zR8P/9LEBL56SsKk3PGGU4qiuW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OjGsq/btq6AN8zR8P/9LEBL56SsKk3PGGU4qiuW1/img.png&quot; data-alt=&quot;https://www.embien.com/blog/interrupt-handling-in-embedded-software/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OjGsq/btq6AN8zR8P/9LEBL56SsKk3PGGU4qiuW1/img.png&quot; srcset=&quot;https://www.embien.com/blog/wp-content/uploads/interrupt-mechanism.png 960w, https://www.embien.com/blog/wp-content/uploads/interrupt-mechanism-500x375.png 500w, https://www.embien.com/blog/wp-content/uploads/interrupt-mechanism-300x225.png 300w&quot; width=&quot;599&quot; height=&quot;449&quot; data-origin-width=&quot;1012&quot; data-origin-height=&quot;759&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.embien.com/blog/interrupt-handling-in-embedded-software/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;인터럽트 컨트롤러(Interrupt Controller)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대체로 시스템은 CPU의 인터럽트 핀으로 1:1로 인터럽트를 전달하지 않고, 컨트롤러를 사용하여 장치 인터럽트들을 그룹화&lt;/li&gt;
&lt;li&gt;인터럽트 컨트롤러에는 인터럽트를 조정하는 마스크 레지스터와 상태 레지스터가 존재&lt;/li&gt;
&lt;li&gt;마스크 레지스터의 비트들을 1 또는 0으로 설정하여 인터럽트를 가능하게 하거나 불가능하게 만들 수 있음&lt;/li&gt;
&lt;li&gt;상태 레지스터는 시스템에 현재 발생한 인터럽트를 가짐&lt;/li&gt;
&lt;li&gt;시스템의 일부 인터럽트는 하드웨어적으로 연결되어 있는데, 실시간 간격 타이머가 이에 해당되며, 각 시스템은 독자적인 인터럽트 전달 방식을 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인터럽트 모드(Interrupt Mode)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인터럽트가 발생하면 CPU는 지금 실행중인 명령어를 잠시 중단하고 인터럽트 처리 코드(Interrupt Handler)가 있거나 해당 코드로 분기하는 명령어의 메모리 주소로 점프(jump)하는데, 여기서 인터럽트 모드에 진입한다고 함&lt;/li&gt;
&lt;li&gt;보통 이 모드에서는 다른 인터럽트가 발생할 수 없으며, 예외로 인터럽트에 우선순위를 매기는 CPU의 경우, 높은 인터럽트가 발생하는 것을 허용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인터럽트 처리 코드는 인터럽트 처리하기 전에 CPU의 수행 상태(즉, CPU의 레지스터 등을 포함한 컨텍스트)를 &lt;b&gt;자신의 스택에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;저장하고, 인터럽트를 처리하고 나면 CPU의 수행 상태가 인터럽트 처리 전으로 복구되고 인터럽트는 해제됨&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;이후 CPU는 인터럽트가 발생하기 전에 수행하던 명령어를 재개&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;프로그램 가능 인터럽트 컨트롤러(Programmable Interrupt Controller, PIC)&lt;/span&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;ISA 주소 공간에 있는 컨트롤러의 레지스터를 이용해 프로그램할 수 있는 컨트롤러&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;이 레지스터의 위치는 고정되어 이미 알려진 것&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;인텔에 기반하지 않은 시스템은 위와 같은 구조적 제약에서 자유로우며, 대개 다른 인터럽트 컨트롤러를 사용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;PIC는 마스크 레지스터와 상태 레지스터를 포함하는데, 마스크 레지스터는 특정 비트를 1 또는 0으로 설정하여 특정 인터럽트(N번 비트면 N번 인터럽트)의 사용 유무를 결정&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&amp;nbsp;마스크 레지스터는 쓸 수만 있으며, 써 놓은 값을 읽어오려면 설정 값을 별도로 복사해야 함&lt;/li&gt;
&lt;li&gt;인터럽트 허용 상태의 루틴과 인터럽트 금지 상태의 루틴에서, 마스크 레지스터의 복사본을 변경하고 매번 레지스터에 변경된 마스크 값을 씀&lt;/li&gt;
&lt;li&gt;&amp;nbsp;인터럽트가 발생하면 인터럽트 처리 코드는 2개의 인터럽트 상태 레지스터(Interrupt Status Register, ISR)를 읽어서 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;514&quot; height=&quot;144&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;308&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmvk9F/btq6AQdcGNu/2cLPOtaNmr5vbF7vlu368k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmvk9F/btq6AQdcGNu/2cLPOtaNmr5vbF7vlu368k/img.png&quot; data-alt=&quot;(출처를 못찾겠..) 2개의 PIC 로 장치를 연결&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmvk9F/btq6AQdcGNu/2cLPOtaNmr5vbF7vlu368k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbmvk9F%2Fbtq6AQdcGNu%2F2cLPOtaNmr5vbF7vlu368k%2Fimg.png&quot; width=&quot;514&quot; height=&quot;144&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;308&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;(출처를 못찾겠..) 2개의 PIC 로 장치를 연결&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;인터럽트 관련 자료구조&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;717&quot; height=&quot;461&quot; data-origin-width=&quot;726&quot; data-origin-height=&quot;467&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bq5RTh/btq6zVsKk9p/SFrobm7IJDDv9qRhhfb6N1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bq5RTh/btq6zVsKk9p/SFrobm7IJDDv9qRhhfb6N1/img.png&quot; data-alt=&quot;인터럽트 처리 커널 자료구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bq5RTh/btq6zVsKk9p/SFrobm7IJDDv9qRhhfb6N1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbq5RTh%2Fbtq6zVsKk9p%2FSFrobm7IJDDv9qRhhfb6N1%2Fimg.png&quot; width=&quot;717&quot; height=&quot;461&quot; data-origin-width=&quot;726&quot; data-origin-height=&quot;467&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;인터럽트 처리 커널 자료구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디바이스 드라이버들이 시스템의 인터럽트에 대한 제어권을 요청하면서 자료구조를 초기화&lt;/li&gt;
&lt;li&gt;각 디바이스 드라이버는 인터럽트를 요청해서 켜거나 끄거나 하는 루틴들을 호출해 각자의 인터럽트 처리 루틴의 주소를 커널 자료구조에 저장(등록 과정)&lt;/li&gt;
&lt;li&gt;PCI 디바이스 드라이버는 장치가 어떤 인터럽트를 사용하는지 알고 있으나, ISA 디바이스 드라이버는 알 방법이 없으므로 커널은 사용할 인터럽트를 탐사(probe)할 기회를 제공
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;탐사 과정: 디바이스 드라이버는 장치에 인터럽트를 발생하게 한 다음, 다른 장치에 할당되지 않은 모든 인터럽트를 켜서, 처음에 발생시켰던 장치의 인터럽트가 PIC를 통해 커널로 전달되면, 커널은 ISR을 읽어 디바이스 드라이버에게 값을 알려줌. 만약 그 값이 0이 아니라면 탐사 중에 하나 이상의 인터럽트가 발생한 것을 의미. 탐사 종료 후 다른 장치에 할당되지 않은 인터럽트를 모두 끄기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ISA 장치가 사용하는 인터럽트 핀은 대개 장치 위에 있는 점퍼를 사용해 설정하고 디바이스 드라이버는 지정된 값을 사용하지만, &amp;nbsp;PCI 장치가 사용할 인터럽트는 시스템이 부팅 중 PCI 초기화 과정에서 PCI BIOS나 PCI 서브시스템에 의해 할당됨&lt;/li&gt;
&lt;li&gt;인텔 칩을 사용하는 PC에서는 시스템 부팅 시 BIOS 에서 셋업 코드를 실행하나, BIOS가 없는 경우 리눅스 커널이 셋업을 수행
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;PCI 셋업 코드는 각 장치별로 인터럽트 컨트롤러의 핀 번호를 PCI 설정 헤더에 쓰고, 장치가 사용하는 PCI 슬롯 번호와 PCI 인터럽트 핀 번호 및 PCI 인터럽트 전달 구조를 이용하여 인터럽트 핀(또는 IRQ)을 결정&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디바이스 드라이버는 셋업 코드가 위 정보를 저장한 인터럽트 라인 항목을 읽어서 인터럽트 제어권을 커널에 요청할 때 사용&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;PCI-PCI 브릿지를 사용할 때와 같이 시스템에 PCI 인터럽트를 일으키는 장치가 많은 경우, PCI 장치는 인터럽트를 공유하여 여러 장치의 인터럽트가 하나의 핀에 발생하게 함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;공유 인터럽트를 사용하려면 커널에게 인터럽트 제어권을 요청할 때 해당 디바이스 드라이버가 인터럽트 공유 유무를 전달&lt;/li&gt;
&lt;li&gt;irq_action 배열에 irqaction 구조체를 여러 개 저장하여 인터럽트를 공유&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공유 인터럽트가 발생하면 커널은 그 인터럽트 핀을 사용하는 장치의 모든 인터럽트 핸들러를 호출하므로,&amp;nbsp;모든 PCI 디바이스 드라이버는 서비스할 인터럽트가 없더라도 무시 등의 동작으로 호출을 대비해야함&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;인터럽트 처리(Interrupt Handling)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; srcset=&quot;https://www.embien.com/blog/wp-content/uploads/interrupt-handling-and-isr.png 960w, https://www.embien.com/blog/wp-content/uploads/interrupt-handling-and-isr-500x375.png 500w, https://www.embien.com/blog/wp-content/uploads/interrupt-handling-and-isr-300x225.png 300w&quot; width=&quot;589&quot; height=&quot;441&quot; data-origin-width=&quot;1012&quot; data-origin-height=&quot;759&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjgGjQ/btq6BdMMAU7/ZlIsW675wTFviNqlqaIT0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjgGjQ/btq6BdMMAU7/ZlIsW675wTFviNqlqaIT0K/img.png&quot; data-alt=&quot;https://www.embien.com/blog/interrupt-handling-in-embedded-software/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjgGjQ/btq6BdMMAU7/ZlIsW675wTFviNqlqaIT0K/img.png&quot; srcset=&quot;https://www.embien.com/blog/wp-content/uploads/interrupt-handling-and-isr.png 960w, https://www.embien.com/blog/wp-content/uploads/interrupt-handling-and-isr-500x375.png 500w, https://www.embien.com/blog/wp-content/uploads/interrupt-handling-and-isr-300x225.png 300w&quot; width=&quot;589&quot; height=&quot;441&quot; data-origin-width=&quot;1012&quot; data-origin-height=&quot;759&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.embien.com/blog/interrupt-handling-in-embedded-software/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리눅스에서 인터럽트 처리 서브시스템은 인터럽트를 올바른 핸들러로 전달하기 위해 인터럽트 처리 루틴의 주소를 저장하고 있는 구조체에 대한 포인터를 사용&lt;/li&gt;
&lt;li&gt;이 루틴들은 해당 디바이스 드라이버에 있는 것이며, 드라이버가 초기화 될 때 각자 사용할 인터럽트의 제어권을 커널에 요청하면서 루틴의 주소를 알려주게 됨&lt;/li&gt;
&lt;li&gt;각 irqaction 구조체는 인터럽트 처리 루틴의 주소를 포함하는데, 핸들러에 필요한 정보도 가짐
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;irq_action 배열의 크기는 인터럽트가 발생하는 장치의 수&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;인터럽트의 수와 이들이 처리되는 방법은 아키텍처마다 다르기 때문에 리눅스의 인터럽트 핸들러는 아키텍처에 종속적&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인터럽트 처리 과정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커널은 시스템에 있는 PIC의 인터럽트 상태 레지스터(ISR)을 읽어 어느 장치가 인터럽트가 발생했는지 파악하고 irq_action 배열의 오프셋을 계산&lt;/li&gt;
&lt;li&gt;irqaction 구조체에 접근하여 저장된 핸들러가 없다면 커널은 오류를 기록하고, 핸들러가 있다면 이 인터럽트가 발생하는 모든 장치에 대해 irqaction 구조체에 있는 핸들러를 호출&lt;/li&gt;
&lt;li&gt;디바이스 드라이버는 인터럽트 원인(오류/요청 작업 완료)을 파악하기 위해 해당 장치의 상태 레지스터를 읽어 인터럽트를 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;디바이스 드라이버는 인터럽트를 처리할 때 작업량이 많을 수 있는데, 커널에서는 CPU가 오랫동안 인터럽트 모드에 있는 것을 피하기 위해 작업을 인터럽트 처리 후로 미루는 메커니즘을 지원
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://jake.dothome.co.kr/two-part-interrupt-handler/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;하반부 핸들러(bottom half handler)와 작업 큐(task queue)를 사용&lt;/a&gt;하는데, 작업 큐에 할 일을 추가하면 하반부 핸들러가 하나씩 작업을 처리함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;예를 들어, 터미널에 출력하기 위해 인터럽트가 발생(어셈블리어 명령 int가 인터럽트 처리 루틴을 호출)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1252&quot; data-origin-height=&quot;742&quot; width=&quot;623&quot; height=&quot;370&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3SwZP/btq6zRjz67i/iCGOX6sgyIXypS1LNmq9e1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3SwZP/btq6zRjz67i/iCGOX6sgyIXypS1LNmq9e1/img.png&quot; data-alt=&quot;https://stackoverflow.com/questions/29656136/is-there-a-system-call-service-routine-in-the-interrupt-vector&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3SwZP/btq6zRjz67i/iCGOX6sgyIXypS1LNmq9e1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3SwZP%2Fbtq6zRjz67i%2FiCGOX6sgyIXypS1LNmq9e1%2Fimg.png&quot; data-origin-width=&quot;1252&quot; data-origin-height=&quot;742&quot; width=&quot;623&quot; height=&quot;370&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://stackoverflow.com/questions/29656136/is-there-a-system-call-service-routine-in-the-interrupt-vector&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Operating System/Linux</category>
      <category>INTERRUPT</category>
      <category>Interrupt handler</category>
      <category>Linux Kernel</category>
      <category>Operating System</category>
      <category>리눅스 커널</category>
      <category>운영체제</category>
      <category>인터럽트</category>
      <category>인터럽트 핸들러</category>
      <author>r4v3n-k</author>
      <guid isPermaLink="true">https://movefast.tistory.com/346</guid>
      <comments>https://movefast.tistory.com/346#entry346comment</comments>
      <pubDate>Sat, 5 Jun 2021 10:12:10 +0900</pubDate>
    </item>
    <item>
      <title>리눅스 커널 - 주변장치 상호연결(PCI)</title>
      <link>https://movefast.tistory.com/345</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;본 글은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;http://wiki.kldp.org/Translations/html/The_Linux_Kernel-KLDP/The_Linux_Kernel-KLDP.html&quot;&gt;The Linux Kernel&lt;/a&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;을 정리한 것이며, 출처를 밝히지 않은 모든 이미지는 원글에 속한 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;PCI 주소 공간&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;PCI(Peripheral&amp;nbsp;Component&amp;nbsp;Interconnect)&lt;/b&gt; 시스템에 있는 여러 주변장치들을 구조화하고, 연결하여 효율적으로 관리하는 방법을 정의하는 표준&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;464&quot; height=&quot;368&quot; data-origin-width=&quot;464&quot; data-origin-height=&quot;368&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oGcBM/btq6AQjs4oa/Rwue6l0vZE4S9PyCP42KR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oGcBM/btq6AQjs4oa/Rwue6l0vZE4S9PyCP42KR0/img.png&quot; data-alt=&quot;PCI 기반 시스템 예&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oGcBM/btq6AQjs4oa/Rwue6l0vZE4S9PyCP42KR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoGcBM%2Fbtq6AQjs4oa%2FRwue6l0vZE4S9PyCP42KR0%2Fimg.png&quot; width=&quot;464&quot; height=&quot;368&quot; data-origin-width=&quot;464&quot; data-origin-height=&quot;368&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;PCI 기반 시스템 예&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 그림에서 CPU는 PCI 버스 0번에 연결되어 있고, PCI-PCI 브릿지는 PCI 버스 0번(1차 버스, primary)와 PCI 버스 1번(2차 버스, secondary)를 연결. 여기서 PCI-PCI 브릿지에서 CPU에 가깝게 연결된 버스를 upstream 이라 하며, CPU에 멀게 연결된 버스를 downstream 이라고 함. PCI-ISA 브릿지는 오래 전부터 사용되어온 ISA 장치(키보드, 마우스, 플로피 디스크를 제어하는 슈퍼 I/O 컨트롤러 칩 등)를 연결하기 위한 ISA 버스와 PCI 버스를 연결하는 장치&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디바이스 드라이버(커널 모듈)는 메인 보드에 있는 PCI 카드를 제어하고 PCI 장치와 서로 정보를 교환하기 위해 공유 메모리를 사용. 이 메모리에는 장치의 컨트롤러가 사용하는 제어 레지스터(control register)와 상태 레지스터(status register)가 존재&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어, PCI SCSI 디바이스 드라이버는 SCSI 디스크로 데이터를 쓰려고 할 때, 장치의 상태 레지스터를 읽어와 쓰기 작업이 가능한지 파악하며, 제어 레지스터에 값을 써서 장치를 동작시킴&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주변장치들은 각자 자신만의 메모리 공간(I/O 공간)을 가지며, CPU는 이 영역에 자유롭게 접근할 수 있으나, 장치가 시스템 메모리 공간에 접근하는 것은 직접 메모리 접근(Direct Memory Access, DMA) 채널을 이용해야 함&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ISA 장치는 ISA I/O와 ISA 메모리를 가짐&lt;/li&gt;
&lt;li&gt;PCI 장치는 PCI I/O, PCI 메모리, PCI 설정 공간(configuration space)를 가짐&lt;/li&gt;
&lt;li&gt;디바이스 드라이버는 PCI I/O와 PCI 메모리 주소공간을 사용하며, PCI 설정 공간의 경우 커널의 PCI 초기화 코드에서 사용&lt;/li&gt;
&lt;li&gt;장치들이 사용하는 메모리 공간은 가상 주소 공간에서 일부를 PCI 주소 공간으로 매핑하는 희소 주소 매핑(sparse address mapping) 방법으로 생성됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PCI I/O와 PCI 메모리 주소&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장치가 리눅스 커널에서 실행되는 디바이스 드라이버와 통신하기 위해 사용하는 메모리 공간&lt;/li&gt;
&lt;li&gt;PCI 시스템이 설정되고, PCI 설정 헤더에 있는 명령 항목에서 이들 주소 공간에 대한 접근을 허용할 때까지 아무도 이 공간에 접근할 수 없음.&lt;/li&gt;
&lt;li&gt;장치는 자신의 내부 레지스터를 PCI I/O 공간에 매핑하며, &amp;nbsp;해당 디바이스 드라이버는 장치를 제어하기 위해 레지스터를 읽고 씀&lt;/li&gt;
&lt;li&gt;비디오/오디오 드라이버는 데이터를 저장하기 위해 큰 용량의 PCI 메모리 공간을 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;PCI 설정 헤더&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;362&quot; height=&quot;487&quot; data-origin-width=&quot;415&quot; data-origin-height=&quot;586&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cK513t/btq6BaouTMN/mJjed6dcR5gm2pn233v5p1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cK513t/btq6BaouTMN/mJjed6dcR5gm2pn233v5p1/img.png&quot; data-alt=&quot;PCI Configuration Header&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cK513t/btq6BaouTMN/mJjed6dcR5gm2pn233v5p1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcK513t%2Fbtq6BaouTMN%2FmJjed6dcR5gm2pn233v5p1%2Fimg.png&quot; width=&quot;362&quot; height=&quot;487&quot; data-origin-width=&quot;415&quot; data-origin-height=&quot;586&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;PCI Configuration Header&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;모든 PCI 장치(PCI-PCI 브릿지 포함)는 PCI 설정 공간에서 PCI 설정 헤더(모든 헤더의 크기는 256바이트)를 가지는데, 이 자료구조는 시스템이 장치를 구별하고 제어하는데 사용되며, 헤더가 있는 정확한 위치는 PCI 배치도에서 장치가 위치한 곳에 따라 결정됨&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메인 보드에 있는 여러 PCI 슬롯 중 하나에 꽂을 때, 어떤 슬롯에 꽂느냐에 따라 PCI 설정 공간에서 각기 다른 위치에 헤더가 위치&lt;/li&gt;
&lt;li&gt;PCI 설정 헤더에 있는 설정 레지스터와 상태 레지스터를 이용해 장치를 설정&lt;/li&gt;
&lt;li&gt;첫번째 슬롯의 PCI 설정 헤더가 오프셋 0에 위치한다면, 두번째 슬롯의 헤더는 오프셋 256에 위치&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;시스템별로 PCI 설정 공간에 접근하는 하드웨어 메커니즘이 다르게 정의되어 있으며, 이에 따라 &lt;b&gt;PCI 설정 코드는 주어진 PCI 버스에 있어서 가능한 모든 PCI 설정 헤더를 검사하여 장치의 유무를 파악&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장치 식별자(Device Identification)&lt;/b&gt; 장치 자체를 나타내는 고유번호(고속 이더넷 장치의 경우 0x0009)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;제작자 식별자(Vendor Identification)&lt;/b&gt;&amp;nbsp;PCI 장치의 제작자를 나타내는 고유번호(인텔의 경우 0x8086)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상태(Status)&lt;/b&gt; 장치의 상태&lt;/li&gt;
&lt;li&gt;&lt;b&gt;명령(Command)&lt;/b&gt; 시스템은 이 항목에 값을 써서 장치의 PCI I/O 공간에 접근할 수 있고, 이를 이용해 장치를 제어&lt;/li&gt;
&lt;li&gt;&lt;b&gt;분류 코드(Class Code)&lt;/b&gt;&amp;nbsp;이 장치가 속한 장치의 유형을 구별&lt;/li&gt;
&lt;li&gt;&lt;b&gt;베이스 주소 레지스터(Base Address Register)&lt;/b&gt;&amp;nbsp;PCI I/O, PCI 메모리 공간의 유형과 크기, 위치를 지정하는데 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인터럽트 핀(Interrupt Pin)&lt;/b&gt;&amp;nbsp;PCI 장치가 사용하고 있는 인터럽트 핀
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PCI 카드에 있는 4개의 핀(표준으로 각각 A, B, C, D라고 명명)은 PCI 카드로부터 PCI 버스로 인터럽트를 전달&lt;/li&gt;
&lt;li&gt;보통 특정 장치에 있어서 인터럽트 핀은 직접 배선되어 부팅 시 그 장치는 그 핀을 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인터럽트 라인(Interrupt Line)&lt;/b&gt;&amp;nbsp;PCI 초기화 코드와 디바이스 드라이버, 리눅스의 이넡럽트 처리 서브시스템 사이에 인터럽트 핸들을 전달하기 위해 사용되며, 이 핸들러가 PCI 장치로부터 전달된 인터럽트를 리눅스 커널에 있는 올바른 디바이스 드라이버의 인터럽트 핸들러로 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;PCI-ISA 브릿지&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PCI I/O와 PCI 메모리 공간으로의 접근을 ISA I/O와 ISA 메모리 공간으로의 접근으로 변환해주는 장치
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오래전부터 사용해온 ISA 장치를 지원하는 역할&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;PCI 규약에서는 PCI I/O와 PCI 메모리 공간에서 아래 영역을 ISA 시스템의 주변장치가 사용하도록 하며, 하나의 PCI-ISA 브릿지를 통해 PCI 메모리읮 주소로 접근하면 이 아래 영역의 주소로 변환&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;PCI-PCI 브릿지&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 PCI 버스가 지원가능한 PCI 장치 개수는 전기적인 제한이 있어, 더 많은 PCI 장치를 지원하려면 PCI-PCI 브릿지를 이용하여 PCI 버스를 추가&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PCI 설정 사이클(Configuration Cycle)&lt;/b&gt;&amp;nbsp;PCI 초기화 전에 PCI 장치들을 설정하기 위해 사용하는 특별한 주소&lt;/li&gt;
&lt;li&gt;PCI 초기화 코드가 메인 PCI 버스(0번)에 있지 않는 장치들에 접근하려면 브릿지가 자신의 1차 PCI 버스에서 2차 PCI 버스로 설정 사이클을 넘길지 결정하는 메커니즘이 필요&lt;/li&gt;
&lt;li&gt;PCI 규약에서는 2가지 형식의 PCI 설정 주소를 정의
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;0번 타입 PCI 설정 사이클&lt;/b&gt;&amp;nbsp;PCI 버스 번호가 없으며, 모든 장치는 같은 PCI 버스에 대한 PCI 설정 주소로 해석&lt;/li&gt;
&lt;li&gt;&lt;b&gt;1번 타입 PCI 설정 사이클&lt;/b&gt;&amp;nbsp;PCI 버스 번호가 있으며, 이 주소는 PCI-PCI 브릿지만 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;336&quot; height=&quot;75&quot; data-origin-width=&quot;415&quot; data-origin-height=&quot;93&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpnhvx/btq6AP555RZ/mMic8kJJcQEaxFhLlZUKLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpnhvx/btq6AP555RZ/mMic8kJJcQEaxFhLlZUKLK/img.png&quot; data-alt=&quot;0번 타입 PCI 설정 사이클&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpnhvx/btq6AP555RZ/mMic8kJJcQEaxFhLlZUKLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbpnhvx%2Fbtq6AP555RZ%2FmMic8kJJcQEaxFhLlZUKLK%2Fimg.png&quot; width=&quot;336&quot; height=&quot;75&quot; data-origin-width=&quot;415&quot; data-origin-height=&quot;93&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;0번 타입 PCI 설정 사이클&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;332&quot; height=&quot;63&quot; data-origin-width=&quot;415&quot; data-origin-height=&quot;80&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bERNIe/btq6APLO3T4/NXLQHmp7OzdT00jKV8rPF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bERNIe/btq6APLO3T4/NXLQHmp7OzdT00jKV8rPF1/img.png&quot; data-alt=&quot;1번 타입 PCI 설정 사이클&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bERNIe/btq6APLO3T4/NXLQHmp7OzdT00jKV8rPF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbERNIe%2Fbtq6APLO3T4%2FNXLQHmp7OzdT00jKV8rPF1%2Fimg.png&quot; width=&quot;332&quot; height=&quot;63&quot; data-origin-width=&quot;415&quot; data-origin-height=&quot;80&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1번 타입 PCI 설정 사이클&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 PCI-PCI 브릿지는 &lt;b&gt;종속 버스(subordinate bus) 번호&lt;/b&gt;를 가지는데, 이 번호는 2차 PCI 버스 너머 다운스트림으로 연결된 모든 PCI 버스들 중 최대 버스 번호를 의미&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모든 PCI-PCI 브릿지는 1번 타입 설정 사이클을 받으면, 다운스트림으로 보낼 지 결정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지정된 버스 번호가 [브릿지의 2차 버스 번호, 종속 버스 번호] 사이에 있지 않으면, 1차 버스의 것으로 간주&lt;/li&gt;
&lt;li&gt;지정된 버스 번호가 2차 버스 번호와 일치하면 0번 타입 설정 명령으로 변환&lt;/li&gt;
&lt;li&gt;지정된 버스 번호가 (브릿지의 2차 버스 번호, 종속 버스 번호] 사이에 있으면, 주소를 바꾸지 않고 2차 버스로 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;예를 들어, 4개의 버스(0~3번)가 있고, 브릿지1은 0번과 1번, 브릿지2는 1번과 2번, 브릿지3은 1번과 3번 버스를 각각 연결한다고 가정. (2번과 3번 버스는 연결되어 있지 않은 상태) 이 때 3번 버스에 있는 장치A를 지정하려면
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU로부터 1번 타입 설정 사이클을 계산해서 0번 버스를 이용해 브릿지1로 전달&lt;/li&gt;
&lt;li&gt;브릿지1은 이를 바꾸지 않고 1번 버스로 전달&lt;/li&gt;
&lt;li&gt;브릿지2는 해당되지 않으므로 무시&lt;/li&gt;
&lt;li&gt;브릿지3은 0번 타입 설정 사이클로 변환한 뒤 3번 버스로 전달 --&amp;gt;&amp;nbsp;장치 응답&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;PCI-PCI 브릿지 너머에 있는 모든 PCI 버스의 번호는 브릿지의 2차 버스 번호와 종속 버스 번호 사이에 있어야 함. 만약 그렇지 않다면, 브릿지는 1번 타입 설정 사이클을 변환하지 못하거나 제대로 통과시키지 못하게 되고, 시스템은 PCI 장치를 찾지 못하거나 초기화할 수 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;PCI 초기화&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;PCI 디바이스 드라이버&lt;/b&gt;&amp;nbsp;0번 버스부터 PCI 시스템을 탐색하면서 시스템에 있는 브릿지 포함 모든 PCI 장치를 초기화
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;찾은 모든 브릿지에는 순서대로 번호가 부여되며, 해당 자료구조의 연결 리스트를 만들어서 시스템의 배치도를 저장&lt;/li&gt;
&lt;li&gt;유사 디바이스 드라이버(pseudo device driver)로, 실제 디바이스 드라이버 프로그램이 아니라 초기화 과정에서 호출되는 리눅스 커널 내부의 한 함수&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PCI BIOS&lt;/b&gt;&amp;nbsp;CPU가 모든 PCI 주소 공간을 제어할 수 있도록 함 (커널 코드와 디바이스 드라이버만 사용)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BIOS 서비스가 없는 64 비트 프로세서의 경우 동일한 일을 하는 코드가 커널 내부에 존재&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;리눅스 커널 PCI 자료구조
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;pci_dev 구조체&lt;/b&gt; (브릿지 포함) 각 PCI 장치를 나타냄&lt;/li&gt;
&lt;li&gt;&lt;b&gt;pci_bus 구조체&lt;/b&gt; PCI 버스를 나타냄&lt;/li&gt;
&lt;li&gt;최종 결과는 버스들의 트리 구조이며, 각 노드는 해당 버스에 연결된 여러 PCI 장치들을 가리킴&lt;/li&gt;
&lt;li&gt;PCI 버스는 PCI-PCI 브릿지를 통해서만 도달 가능 (첫번째 PCI 버스인 0번 버스는 제외). 따라서, 각 pci_bus 구조체는 접근할 때 거쳐야 하는 PCI-PCI 브릿지에 대한 포인터를 포함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PCI-PCI 브릿지 구조체는 연결된 PCI 버스와 부모 PCI 버스의 자식 노드&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;pci_devices 변수&lt;/b&gt;&amp;nbsp;시스템에 있는 모든 PCI 장치 리스트를 가리키는 포인터
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시스템에 있는 모든 PCI 장치는 자신의 pci_dev 구조체를 이 리스트에 추가함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;453&quot; height=&quot;670&quot; data-origin-width=&quot;493&quot; data-origin-height=&quot;729&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/djCEM1/btq6BDqEuDZ/u8jnEgKFe6Lrlvj7dZNmvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/djCEM1/btq6BDqEuDZ/u8jnEgKFe6Lrlvj7dZNmvK/img.png&quot; data-alt=&quot;PCI 커널 자료구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/djCEM1/btq6BDqEuDZ/u8jnEgKFe6Lrlvj7dZNmvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdjCEM1%2Fbtq6BDqEuDZ%2Fu8jnEgKFe6Lrlvj7dZNmvK%2Fimg.png&quot; width=&quot;453&quot; height=&quot;670&quot; data-origin-width=&quot;493&quot; data-origin-height=&quot;729&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;PCI 커널 자료구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;PCI 초기화 코드&lt;/b&gt;&amp;nbsp;깊이 우선 탐색(Depth First Search, DFS)으로 구현되어 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시스템에 있는 모든 PCI 장치(브릿지 포함)들을 탐색하기 위해 PCI BIOS 코드를 이용하여 현재 조사중인 PCI 버스의 모든 가능한 슬롯 각각이 점유되었는지 파악&lt;/li&gt;
&lt;li&gt;PCI 슬롯이 점유되었으면, 그 장치를 기술하는 pci_dev 구조체를 생성해서 pci_devices 가 가리키는 PCI 장치 리스트에 추가&lt;/li&gt;
&lt;li&gt;찾은 PCI 장치가 PCI-PCI 브릿지이면, pci_bus 구조체를 생성해서 브릿지에 대한 pci_dev 구조체를 참조하도록 하고, 브릿지에 연결된 다른 버스와도 연결
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장치 분류 코드(0x060400 고정)로 브릿지의 유무를 파악&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;커널은 자신이 찾은 PCI-PCI 브릿지의 다운스트림 방향으로 PCI 버스를 설정, 깊이 우선 탐색이 끝나면 너비 우선 탐색으로 진행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;530&quot; height=&quot;340&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;515&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yFydf/btq6BDYujfH/IuZXnyLYva3PGw3Kkwq9R1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yFydf/btq6BDYujfH/IuZXnyLYva3PGw3Kkwq9R1/img.png&quot; data-alt=&quot;PCI 시스템 설정: 1단계&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yFydf/btq6BDYujfH/IuZXnyLYva3PGw3Kkwq9R1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyFydf%2Fbtq6BDYujfH%2FIuZXnyLYva3PGw3Kkwq9R1%2Fimg.png&quot; width=&quot;530&quot; height=&quot;340&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;515&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;PCI 시스템 설정: 1단계&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;532&quot; height=&quot;341&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;514&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WsHus/btq6zsqPi9l/7CVKza9JaUGHJhuap2aOkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WsHus/btq6zsqPi9l/7CVKza9JaUGHJhuap2aOkK/img.png&quot; data-alt=&quot;PCI 시스템 설정: 2단계&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WsHus/btq6zsqPi9l/7CVKza9JaUGHJhuap2aOkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWsHus%2Fbtq6zsqPi9l%2F7CVKza9JaUGHJhuap2aOkK%2Fimg.png&quot; width=&quot;532&quot; height=&quot;341&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;514&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;PCI 시스템 설정: 2단계&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;531&quot; height=&quot;340&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;514&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1c3Eu/btq6w6aEYK0/NVrYz3YF5F8kkHkKcZPDSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1c3Eu/btq6w6aEYK0/NVrYz3YF5F8kkHkKcZPDSK/img.png&quot; data-alt=&quot;PCI 시스템 설정: 3단계&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1c3Eu/btq6w6aEYK0/NVrYz3YF5F8kkHkKcZPDSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1c3Eu%2Fbtq6w6aEYK0%2FNVrYz3YF5F8kkHkKcZPDSK%2Fimg.png&quot; width=&quot;531&quot; height=&quot;340&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;514&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;PCI 시스템 설정: 3단계&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;564&quot; height=&quot;361&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;513&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GlYhz/btq6APE6a4V/FVk9HnoEqSlNVXI8QEEBi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GlYhz/btq6APE6a4V/FVk9HnoEqSlNVXI8QEEBi0/img.png&quot; data-alt=&quot;PCI 시스템 설정: 4단계&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GlYhz/btq6APE6a4V/FVk9HnoEqSlNVXI8QEEBi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGlYhz%2Fbtq6APE6a4V%2FFVk9HnoEqSlNVXI8QEEBi0%2Fimg.png&quot; width=&quot;564&quot; height=&quot;361&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;513&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;PCI 시스템 설정: 4단계&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PCI-PCI 브릿지가 PCI I/O와 PCI 메모리 공간 및 PCI 설정 공간에 읽고 쓰려는 작업을 통과시키려면 4가지 정보가 필요
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;1차 버스(primary bus) 번호&lt;/b&gt;&amp;nbsp;PCI-PCI 브릿지에 upstream으로 연결된 버스 번호&lt;/li&gt;
&lt;li&gt;&lt;b&gt;2차 버스(secondary bus) 번호&lt;/b&gt;&amp;nbsp;PCI-PCI 브릿지에 downstream으로 연결된 버스 번호&lt;/li&gt;
&lt;li&gt;&lt;b&gt;종속 버스(subordinate bus) 번호&lt;/b&gt;&amp;nbsp;PCI-PCI 브릿지의 downstream 도달 가능한 버스들 중 최대 버스 번호&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PCI I/O와 PCI 메모리 윈도우&lt;/b&gt;&amp;nbsp;PCI-PCI 브릿지의 모든 downstream으로 연결된 장치들이 사용하는 PCI I/O와 PCI 메모리 공간의 윈도우에 대한 베이스 주소 및 크기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;PCI-PCI 브릿지 초기화 단계에서 종속 버스 번호는 바로 알 수 없기 때문에, 처음에는 DFS로 브릿지를 찾을 때마다 각 2차 버스 번호를 부여하고 종속 버스 번호에는 임시로 0xFF를 지정. CPU에서 가장 멀리 떨어진(downstream의 마지막) 브릿지로부터 되돌아올 때(백트래킹 과정에서) 종속 버스 번호에 도달가능한 최대 버스 번호를 부여&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;PCI Fixup&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;PCI 확정(Fixup)&lt;/b&gt;&amp;nbsp;시스템별로 다른 PCI 초기화의 종료 부분을 마무리짓는 작업&lt;/li&gt;
&lt;li&gt;인텔 기반 시스템은 부팅 시 실행되는 시스템 BIOS에서 이 작업을 진행하며 그 외 시스템에서는 커널에서 작업&lt;/li&gt;
&lt;li&gt;&lt;b&gt;각 장치에 PCI I/O와 PCI 메모리 공간을 할당&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장치가 사용할 메모리 공간의 크기를 탐색하기 위해, 각 장치의 베이스 주소 레지스터에 1을 써서 전달, 장치는 무관한 주소 비트를 0으로 설정해서 응답하는데 커널이 받은 값은 주소공간의 크기를 나타냄&lt;/li&gt;
&lt;li&gt;모든 주소 공간의 크기는 2의 배수이며, 이에 맞춰 자연스럽게 메모리 공간은&amp;nbsp;정렬되어 장치에 할당됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;394&quot; height=&quot;272&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;413&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Mpudc/btq6zWdRd3X/nOUlw29yHBhfdbNHEoNEJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Mpudc/btq6zWdRd3X/nOUlw29yHBhfdbNHEoNEJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Mpudc/btq6zWdRd3X/nOUlw29yHBhfdbNHEoNEJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMpudc%2Fbtq6zWdRd3X%2FnOUlw29yHBhfdbNHEoNEJk%2Fimg.png&quot; width=&quot;394&quot; height=&quot;272&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;413&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;커널은 어떤 주소 공간에 장치의 레지스터가 있어야 하는지를 알려주는데, 현재 버스의 모든 장치에 대해 각각 필요한 크기만큼 전역 PCI I/O와 메모리 베이스 주소를 이동시킴&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 버스의 모든 downstream 으로 연결된 버스들을 재귀적으로 찾아 공간을 할당&lt;/li&gt;
&lt;li&gt;전역 PCI I/O와 PCI 메모리 공간의 베이스 주소를 변경&lt;/li&gt;
&lt;li&gt;장치들의 주소 공간이 모든 upstream 으로 연결된 PCI-PCI 브릿지의 메모리 공간에 위치하게 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시스템에 있는 각 PCI-PCI 브릿지의 PCI I/O와 PCI 메모리 주소 윈도우를 설정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 있는 전역 PCI I/O와 PCI 메모리 베이스 주소를 4K 단위로 상대적 정렬 (1Mbytes 경계를 가짐)&lt;/li&gt;
&lt;li&gt;이 과정에서 현재 PCI-PCI 브릿지가 필요로 하는 윈도우의 베이스 주소 및 크기를 계산&lt;/li&gt;
&lt;li&gt;이 버스에 연결된 PCI-PCI 브릿지를 계속 탐색해서 베이스 주소와 크기를 지정&lt;/li&gt;
&lt;li&gt;PCI-PCI 브릿지에 대한 PCI I/O와 PCI 메모리 공간에 접근할 수 있도록 브릿지 기능 설정&lt;/li&gt;
&lt;li&gt;브릿지의 1차 PCI 버스에서 보이는 PCI I/O와 PCI 메모리 주소 중에서 윈도우 안에 있는 PCI I/O와 PCI 메모리 주소는 2차 버스가 사용하는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장치에 인터럽트 라인 값을 지정하여 그 장치의 인터럽트 처리를 제어할 수 있게 함&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Operating System/Linux</category>
      <category>Linux Kernel</category>
      <category>Operating System</category>
      <category>PCI</category>
      <category>PCI 버스</category>
      <category>PCI 장치</category>
      <category>PCI 초기화</category>
      <category>PCI 확정</category>
      <category>리눅스 커널</category>
      <category>운영체제</category>
      <category>주변장치 상호연결</category>
      <author>r4v3n-k</author>
      <guid isPermaLink="true">https://movefast.tistory.com/345</guid>
      <comments>https://movefast.tistory.com/345#entry345comment</comments>
      <pubDate>Fri, 4 Jun 2021 21:50:56 +0900</pubDate>
    </item>
    <item>
      <title>리눅스 커널 - 프로세스간 통신(IPC) 메커니즘</title>
      <link>https://movefast.tistory.com/344</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;본 글은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;http://wiki.kldp.org/Translations/html/The_Linux_Kernel-KLDP/The_Linux_Kernel-KLDP.html&quot;&gt;The Linux Kernel&lt;/a&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;을 정리한 것이며, 출처를 밝히지 않은 모든 이미지는 원글에 속한 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시그널(Signal)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;하나 이상의 프로세스들에게 비동기적인 이벤트(asynchronous event)를 전달하기 위해 사용&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;키보드 인터럽트로부터 발생&lt;/li&gt;
&lt;li&gt;프로세스가 존재하지 않는 가상 메모리 영역에 접근하는 경우 (SIGSEGV 시그널이 프로세스에게 전달됨)&lt;/li&gt;
&lt;li&gt;쉘이 자식 프로세스에게 작업 관리 명령을 보내는 경우: kill -NumSignal PID&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1156&quot; data-origin-height=&quot;1436&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dJQZrW/btq6pZinPv4/JRJS7kaBI8dYiMOAKiKK71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dJQZrW/btq6pZinPv4/JRJS7kaBI8dYiMOAKiKK71/img.png&quot; data-alt=&quot;http://liujunming.top/2018/12/29/Understanding-the-Linux-Kernel-读书笔记-Signals/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dJQZrW/btq6pZinPv4/JRJS7kaBI8dYiMOAKiKK71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdJQZrW%2Fbtq6pZinPv4%2FJRJS7kaBI8dYiMOAKiKK71%2Fimg.png&quot; data-origin-width=&quot;1156&quot; data-origin-height=&quot;1436&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;http://liujunming.top/2018/12/29/Understanding-the-Linux-Kernel-读书笔记-Signals/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본적으로 시그널 핸들러는 다음과 같은 4가지 동작 중 하나를 수행
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;terminate&lt;/b&gt; 프로세스 종료&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ignore&lt;/b&gt; 시그널 무시&lt;/li&gt;
&lt;li&gt;&lt;b&gt;terminate and core dump&lt;/b&gt; 프로세스가 종료되고 그 당시의 레지스터와 메모리를 덤프&lt;/li&gt;
&lt;li&gt;&lt;b&gt;stop or continue&lt;/b&gt; 프로세스 중단 또는 계속 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프로세스의 실행을 중단시키는 SIGSTOP 시그널과 프로세스를 종료시키는 SIGKILL 시그널은 무시할 수 없음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그 외에 모든 시그널은 무시할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;시그널이 여러 개 전달될 때, 임의의 순서로 전달되며, 핸들러로 처리할 때도 임의의 순서로 진행됨&lt;/li&gt;
&lt;li&gt;프로세스는 시스템 콜을 이용해서 시그널을 전달하거나 핸들링하는 등 시그널 관련 작업을 수행할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;672&quot; height=&quot;454&quot; data-origin-width=&quot;908&quot; data-origin-height=&quot;614&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b54f3J/btq6pZQdA5t/evMhPayUBAHu4GYXIXxuZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b54f3J/btq6pZQdA5t/evMhPayUBAHu4GYXIXxuZk/img.png&quot; data-alt=&quot;https://slideplayer.com/slide/8634584/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b54f3J/btq6pZQdA5t/evMhPayUBAHu4GYXIXxuZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb54f3J%2Fbtq6pZQdA5t%2FevMhPayUBAHu4GYXIXxuZk%2Fimg.png&quot; width=&quot;672&quot; height=&quot;454&quot; data-origin-width=&quot;908&quot; data-origin-height=&quot;614&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://slideplayer.com/slide/8634584/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;596&quot; height=&quot;464&quot; data-origin-width=&quot;1594&quot; data-origin-height=&quot;1240&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vyLGO/btq6uFbOxuz/fOpNYUnRRaSokWJswzHBdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vyLGO/btq6uFbOxuz/fOpNYUnRRaSokWJswzHBdK/img.png&quot; data-alt=&quot;https://medium.com/adamedelwiess/operating-system-13-signals-and-interrupts-f0943d8fe287&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vyLGO/btq6uFbOxuz/fOpNYUnRRaSokWJswzHBdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvyLGO%2Fbtq6uFbOxuz%2FfOpNYUnRRaSokWJswzHBdK%2Fimg.png&quot; width=&quot;596&quot; height=&quot;464&quot; data-origin-width=&quot;1594&quot; data-origin-height=&quot;1240&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://medium.com/adamedelwiess/operating-system-13-signals-and-interrupts-f0943d8fe287&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커널은 프로세스의 task_struct 구조체에 저장된 정보를 사용해서 시그널 기능을 처리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시그널의 개수는 프로세서의 워드(word) 크기에 제한되는데, 32비트 프로세서는 32개, 64비트 프로세서는 64개&lt;/li&gt;
&lt;li&gt;현재 처리 대기중인 시그널은 sig 항목에 비트를 1로 설정 (정수 자료형은 2^32 또는 2^64 비트, 프로세서마다 다름)&lt;/li&gt;
&lt;li&gt;블럭된 시그널은 signal_blocked 항목에 비트를 1로 설정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SIGSTOP과 SIGKILL을 제외한 모든 시그널은 블럭킹 가능&lt;/li&gt;
&lt;li&gt;블럭된 시그널이 발생하면, 블럭을 해제할 때까지 대기 상태&lt;/li&gt;
&lt;li&gt;블럭이 해제되면 핸들러가 호출됨&lt;/li&gt;
&lt;li&gt;핸들러가 종료되면, 커널은 blocked 항목을 원래 값으로 되돌려 놓기 위해 정리용 루틴을 호출하는데, 여기서 시그널을 받은 프로세스의 콜 스택(call stack)에 저장된 원래 blocked 값을 꺼내서 복구&lt;/li&gt;
&lt;li&gt;여러 개의 시그널 핸들러가 호출되는 경우, 이 루틴들은 콜 스택에 쌓여서 마지막에 정리용 루틴이 호출되도록 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;시그널 핸들러는 sigaction 구조체에서 참조하며, 각 시그널의 핸들러는 signal_struct 의 action 이라는 sigaction 구조체 배열에 시그널 번호를 인덱스로 저장되어 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;sigaction 구조체에서 sigflags 를 이용해 해당 시그널을 무시할 지 또는 커널이 시그널을 대신 처리할 지를 결정&lt;/li&gt;
&lt;li&gt;커널에 위임한다는 것은 기본 동작을 의미 (위의 4가지 동작 중 하나)&lt;/li&gt;
&lt;li&gt;시그널 핸들러는 시스템 콜로 변경할 수 있으며, 이 시스템 콜은 해당 시그널의 sigaction과 blocked 변수를 수정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;시그널 관련 시스템 콜 (&lt;a href=&quot;https://www.geeksforgeeks.org/signals-c-language/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;예제 코드&lt;/a&gt;)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;kill() 은 다른 프로세스로 시그널을 전달(프로세스 종료 아님)하며, signal() 은 해당 프로세스의 시그널 핸들러를 변경&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;811&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lxZKs/btq6u1r3giy/Jx0bg0YCzdjJfxEP9mtmR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lxZKs/btq6u1r3giy/Jx0bg0YCzdjJfxEP9mtmR0/img.png&quot; data-alt=&quot;http://liujunming.top/2018/12/29/Understanding-the-Linux-Kernel-读书笔记-Signals/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lxZKs/btq6u1r3giy/Jx0bg0YCzdjJfxEP9mtmR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlxZKs%2Fbtq6u1r3giy%2FJx0bg0YCzdjJfxEP9mtmR0%2Fimg.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;811&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;http://liujunming.top/2018/12/29/Understanding-the-Linux-Kernel-读书笔记-Signals/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;u&gt;커널과 관리자는 모든 프로세스에게 시그널을 전달할 수 있지만, 사용자 프로세스는 같은 uid, gid를 갖는 프로세스에게만 시그널을 보낼 수 있음&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;프로세스는 시그널을 받았을 때, 블럭킹 모드가 아니고 인터럽트 허용 상태에서 대기중이면, 실행중 상태가 되고 실행 큐에 추가되어 스케줄링에서 자신의 차례가 올 때까지 기다림 (실행중 상태라고 해서 CPU가 실행하는 것은 아님)&lt;/li&gt;
&lt;li&gt;&lt;u&gt;시그널은 즉시 프로세스에게 전달되는 것이 아니라, 해당 프로세스가 시스템 콜을 호출하고 유저 모드로 돌아오기 직전에 커널이 sig 항목과 signal_blocked 항목을 검사해서 해당 시그널이 블럭킹 모드가 아닐 때, 그 프로세스에게 전달&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;시그널 처리 코드는 현재 블럭되지 않은 시그널에 대해 sigaction 구조체에서 참조하는 루틴이 호출된 것
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 커널 기본 동작이 아닌 사용자가 정의한 함수를 가리킨다면, 유저 모드에서 그 함수를 호출하기 위해 프로세스의 스택과 레지스터를 조작 (for 최적화)&lt;/li&gt;
&lt;li&gt;프로세스의 프로그램 카운터를 시그널 처리 루틴의 주소로 지정하고 핸들러로 전달할 인자를 스택에 추가하거나 레지스터에 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;500px&quot; data-origin-width=&quot;793&quot; data-origin-height=&quot;519&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdN2qm/btq6pZJwh8g/lBkyjTtndKYwclgk2xTzGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdN2qm/btq6pZJwh8g/lBkyjTtndKYwclgk2xTzGK/img.png&quot; data-alt=&quot;https://ssup2.github.io/theory_analysis/Linux_Signal_Signal_Handler/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdN2qm/btq6pZJwh8g/lBkyjTtndKYwclgk2xTzGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdN2qm%2Fbtq6pZJwh8g%2FlBkyjTtndKYwclgk2xTzGK%2Fimg.png&quot; width=&quot;500px&quot; data-origin-width=&quot;793&quot; data-origin-height=&quot;519&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://ssup2.github.io/theory_analysis/Linux_Signal_Signal_Handler/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자식 프로세스를 생성할 때 SIGSTOP 시그널과 SIGCONT 시그널이 부모에서 자식으로 전달됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;339&quot; height=&quot;373&quot; data-fullsrc=&quot;/images/article/197/8283.1562685627.png&quot; data-origin-width=&quot;339&quot; data-origin-height=&quot;373&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m59f3/btq6vxxvaNl/6XdtcI6AFNduDObgDPu2bk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m59f3/btq6vxxvaNl/6XdtcI6AFNduDObgDPu2bk/img.png&quot; data-alt=&quot;https://devopedia.org/linux-signals&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m59f3/btq6vxxvaNl/6XdtcI6AFNduDObgDPu2bk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm59f3%2Fbtq6vxxvaNl%2F6XdtcI6AFNduDObgDPu2bk%2Fimg.png&quot; width=&quot;339&quot; height=&quot;373&quot; data-fullsrc=&quot;/images/article/197/8283.1562685627.png&quot; data-origin-width=&quot;339&quot; data-origin-height=&quot;373&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://devopedia.org/linux-signals&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;파이프(Pipe)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;575&quot; height=&quot;488&quot; data-origin-width=&quot;1204&quot; data-origin-height=&quot;1022&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5gC6v/btq6wavhRjF/As00VTIxKKuszsUfqyBDYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5gC6v/btq6wavhRjF/As00VTIxKKuszsUfqyBDYk/img.png&quot; data-alt=&quot;파이프를 사용하는 두 프로세스의 file 자료구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5gC6v/btq6wavhRjF/As00VTIxKKuszsUfqyBDYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5gC6v%2Fbtq6wavhRjF%2FAs00VTIxKKuszsUfqyBDYk%2Fimg.png&quot; width=&quot;575&quot; height=&quot;488&quot; data-origin-width=&quot;1204&quot; data-origin-height=&quot;1022&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;파이프를 사용하는 두 프로세스의 file 자료구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;파이프는 두 프로세스의 양방향 통신을 지원하는 메커니즘으로, 각 프로세스가 임시로 만들어진 VFS inode를&amp;nbsp;2개(읽기/쓰기)의 file 구조체에서 가리키는 것으로 구현 (여기서 VFS inode는 물리 페이지를 참조)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;file 구조체는 파일 연산 루틴 배열을 참조하는 포인터(f_op)를 가지며, 이는 파이프에 쓰는 함수에 대한 포인터와 파이프로부터 읽는 함수에 대한 포인터를 포함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파이프에 쓰고 읽을 때는 표준 라이브러리 함수를 사용하며, 함수에는 파일 기술자(file descriptor)를 넘김&lt;/li&gt;
&lt;li&gt;즉, f_op 가 참조하는 루틴 배열에는 파일 읽기, 쓰기 함수들이 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;u&gt;두 프로세스는 하나의 파이프에 대해 각각 읽는 프로세스와 쓰는 프로세스가 되며, 반대로 쓰는 프로세스와 읽는 프로세스가 되려면 파이프를 추가로 생성해야 함 (하나의 파이프에 동시에 읽고 쓰는 것이 가능하나 한 쪽이 쓰고 자신의 것을 읽으면 다른쪽은 블락됨)&lt;/u&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C언어에서 파이프는 부모-자식 관계의 두 프로세스일 때 아래 그림처럼 사용할 수 있는데, fd가 반드시 서로 반대인 것으로 읽고 써야하며, &lt;u&gt;서로 다른 프로세스의 경우 FIFO라는 named pipe를 사용&lt;/u&gt;해야 함&lt;/li&gt;
&lt;li&gt;그러나, 아래 그림과 같은 상황은 권장되지 않으며, 양방향 통신은 파이프 2개를 사용할 것&lt;/li&gt;
&lt;li&gt;파이썬에서는 Pipe() 객체를 생성하면 양방향으로 통신이 되는데 내부적으로는 위 설명과 같이 구현되어 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;348&quot; height=&quot;266&quot; data-origin-width=&quot;441&quot; data-origin-height=&quot;338&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p98rq/btq7biGpTjy/0I7Qn1T7ULHN2x1UDE0XP0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p98rq/btq7biGpTjy/0I7Qn1T7ULHN2x1UDE0XP0/img.jpg&quot; data-alt=&quot;https://www.geeksforgeeks.org/pipe-system-call/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p98rq/btq7biGpTjy/0I7Qn1T7ULHN2x1UDE0XP0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp98rq%2Fbtq7biGpTjy%2F0I7Qn1T7ULHN2x1UDE0XP0%2Fimg.jpg&quot; width=&quot;348&quot; height=&quot;266&quot; data-origin-width=&quot;441&quot; data-origin-height=&quot;338&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.geeksforgeeks.org/pipe-system-call/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;쓰는 프로세스가 파이프에 쓴 데이터는 공유 데이터 페이지에 복사되고, 읽는 프로세스는 공유 데이터 페이지로부터 자신의 가상 페이지로 데이터를 복사&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;쓰는 중에 읽어 오는 것을 막기 위해 파이프에 대한 접근은 동기화해주어야 하며, 읽는 프로세스와 쓰는 프로세스는 동시에 접근하지 않고 반드시 순서를 지킬 수 있도록 락(lock)과 대기 큐(waiting queue), 시그널(signal) 등을 사용&lt;/li&gt;
&lt;li&gt;파이프에 접근하는 프로세스는 다른 프로세스가 파이프에 락을 걸지 않았고 이용 가능한 상태(파이프에 쓰기 요청한 바이트들을 모두 쓸 공간이 있거나, 읽어올만큼 충분한 데이터가 있다면)라면 파이프에 락을 걸고 요청을 처리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;쓰는 프로세스는 쓸 데이터 바이트들을 프로세스의 주소공간에서 공유 데이터 페이지로 복사&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;읽는 프로세스는 읽어올 바이트만큼 데이터들을 공유 데이터 페이지에서 프로세스의 주소공간으로 복사&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;만약 파이프에 락이 걸려 있거나 이용 불가능한 상태라면, 현재 프로세스는 해당 파이프의 VFS inode 에서 참조하는 대기 큐(waiting queue)에 추가되어 대기 상태가 되고, 다른 프로세스를 실행하기 위해 스케줄러를 호출
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대기 중인 프로세스는 인터럽트 허용 상태이며, 파이프가 이용 가능할 때 시그널을 받아 실행됨&lt;/li&gt;
&lt;li&gt;읽는 프로세스는 파이프를 이용할 수 없다면 오류를 반환하는, 논블럭킹(non-blocking)으로 실행될 수 있음 (블럭킹 모드이면 대기 큐에 추가되어 잠듬)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;두 프로세스가 파이프를 통한 작업을 종료하면, 파이프의 VFS inode와 공유 데이터 페이지는 폐기됨&lt;/li&gt;
&lt;li&gt;리눅스는 지정 파이프(named pipe)도 지원하며, FIFO 구조로 파이프에 먼저 쓴 데이터는 읽을 때 먼저 나옴
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;FIFO는 임시적으로 생성된 것이 아니라 파일 시스템에 실재 존재하는 것이며, mkfifo 명령으로 생성 가능&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;프로세스는 접근 권한만 있다면 FIFO를 자유롭게 사용 가능&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;리눅스는 FIFO에 쓰는 프로세스가 없을 때 다른 프로세스가 이를 읽기 위해 열려고 하는 것이나, FIFO에 쓰는 프로세스가 FIFO에 쓰기를 하기 전에 읽는 프로세스가 읽으려고 하는 것 모두 처리함&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이를 제외하면, FIFO는 거의 파이프와 똑같은 방법으로 취급되며, 같은 자료구조와 연산을 사용&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시스템 V IPC 메커니즘&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;시스템 V IPC 방법들은 모두 똑같은 인증 방법을 공유&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메시지 큐, 세마포어, 공유 메모리가 해당됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;프로세스는 커널에 시스템 콜로 이들 자원을 가리키는 유일한 참조 식별자(reference identifier)를 전달하여 접근 가능&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;IPC 객체들에 접근할 때는 접근 권한(access permission)을 검사하며, 이는 파일에 대한 접근을 검사하는 것과 유사한 방식&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;IPC 객체에 대한 접근 권한은 시스템 콜을 통하여 객체의 생성자에 의해 지정&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;IPC 객체를 나타내는 커널 자료구조는 프로세스의 소유자와 생성자의 uid, gid와 이 객체에 대한 접근 모드(소유자, 그룹, 그밖에 대한) 및 IPC 객체의 키를 가진 ipc_perm 이라는 자료구조를 포함&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;키는 시스템 V IPC 객체의 참조 식별자를 찾는 한 방법으로 사용되며, &lt;span style=&quot;color: #000000;&quot;&gt;공용키와 개인키가 존재&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;공용키를 사용한다면, 시스템에 있는 어떤 프로세스든지 권한 검사를 통과한다면 시스템 V IPC 객체에 대한 참조 식별자를 찾을 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;IPC 객체는 키가 아니라 참조 식별자로만 참조 가능 (키로 참조 식별자를 찾으면, IPC 객체로 참조하는 것)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;메시지 큐(Message Queue)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;613&quot; height=&quot;413&quot; data-origin-width=&quot;1162&quot; data-origin-height=&quot;784&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLxTNT/btq6uEqsXxf/XMfVJpB1j48B5SnvC8skV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLxTNT/btq6uEqsXxf/XMfVJpB1j48B5SnvC8skV0/img.png&quot; data-alt=&quot;메시지 큐 커널 자료구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLxTNT/btq6uEqsXxf/XMfVJpB1j48B5SnvC8skV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLxTNT%2Fbtq6uEqsXxf%2FXMfVJpB1j48B5SnvC8skV0%2Fimg.png&quot; width=&quot;613&quot; height=&quot;413&quot; data-origin-width=&quot;1162&quot; data-origin-height=&quot;784&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;메시지 큐 커널 자료구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;하나 이상의 프로세스가 메시지를 쓰고, 하나 이상의 프로세스가 메시지를 읽으면서 여러 프로세스 사이의 양방향 통신을 지원&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;502&quot; height=&quot;217&quot; data-origin-width=&quot;976&quot; data-origin-height=&quot;422&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2QEiV/btq6sdtkzVX/36zVN4S2gHSGW6tAskurMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2QEiV/btq6sdtkzVX/36zVN4S2gHSGW6tAskurMk/img.png&quot; data-alt=&quot;http://docsplayer.org/109562214-Abstract-view-of-system-components.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2QEiV/btq6sdtkzVX/36zVN4S2gHSGW6tAskurMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2QEiV%2Fbtq6sdtkzVX%2F36zVN4S2gHSGW6tAskurMk%2Fimg.png&quot; width=&quot;502&quot; height=&quot;217&quot; data-origin-width=&quot;976&quot; data-origin-height=&quot;422&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;http://docsplayer.org/109562214-Abstract-view-of-system-components.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커널은 msqid_ds 구조체로 하나의 메시지 큐를 기술하며, 메시지 큐를 생성할 때마다 msqid_ds 구조체를 생성하여 msgque 배열에 이 구조체를 추가&lt;/li&gt;
&lt;li&gt;msqid_ds 구조체는 ipc 변수로 ipc_perm 구조체를 참조하며, 이 큐에 들어온 메시지에 대한 포인터들과 큐에 마지막으로 접근한 시간같은 큐 수정시간 등을 나타내는 변수들을 포함&lt;/li&gt;
&lt;li&gt;메시지 큐는 2개의 대기 큐를 가지며, 각각 읽는 프로세스들과 쓰는 프로세스들을 관리 (요청 순서대로 대기 큐에서 기다림)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;512&quot; height=&quot;331&quot; data-origin-width=&quot;350&quot; data-origin-height=&quot;226&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/30EBr/btq6vhhi52g/wtXACS6zKihfs6vnXug5qK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/30EBr/btq6vhhi52g/wtXACS6zKihfs6vnXug5qK/img.jpg&quot; data-alt=&quot;http://www.embeddedlinux.org.cn/rtconforembsys/5107final/LiB0042.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/30EBr/btq6vhhi52g/wtXACS6zKihfs6vnXug5qK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F30EBr%2Fbtq6vhhi52g%2FwtXACS6zKihfs6vnXug5qK%2Fimg.jpg&quot; width=&quot;512&quot; height=&quot;331&quot; data-origin-width=&quot;350&quot; data-origin-height=&quot;226&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;http://www.embeddedlinux.org.cn/rtconforembsys/5107final/LiB0042.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스가 큐에 접근할 때 프로세스의 euid, egid를 ipc_perm 구조체에 있는 모드(mode)와 비교하는 것으로 접근 권한을 검사&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;쓰는 프로세스의 경우, 메시지는 프로세스의 주소공간에서 msg 자료구조로 복사되고 메시지 큐의 마지막에 추가됨&lt;/span&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;각 메시지에는 응용프로그램 지정 타입(프로세스간에 서로 약속한 타입)을 포함&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;쓸 수 있는 메시지의 개수와 길이는 제한되며, 큐에 공간이 부족하면 프로세스는 메시지 큐의 쓰기 대기 큐(msqid_ds의 *wwait 항목)에 추가되고, 실행할 새로운 프로세스를 선택하기 위해 스케줄러를 호출 (큐에서 공간이 생기면 대기중에 실행중 상태가 됨)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;읽는 프로세스는 타입에 관계없이 큐에 있는 첫번째 메시지를 가져올 지, 또는 특정한 타입을 가진 메시지를 선택할 지 고를 수 있음&lt;/span&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;읽을 수 있는 메시지가 없으면, 프로세스는 메시지 큐의 읽기 대기 큐(msgq_id의 *rwait 항목)에 추가되고, 실행할 새로운 프로세스를 선택하기 위해 스케줄러를 호출 (큐에서 읽을 메시지가 생기면 대기중에서 실행중 상태가 됨)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;메시지 큐가 활용되는 적절한 예로, &lt;a href=&quot;https://www.geeksforgeeks.org/producer-consumer-problem-in-c/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;생산자-소비자 패턴(Producer-Consumer Pattern)&lt;/a&gt;이 있음&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;499&quot; data-origin-height=&quot;206&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/emUaUa/btq6rnbVCh4/Vebi97DEzp8qiczV6HoM6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/emUaUa/btq6rnbVCh4/Vebi97DEzp8qiczV6HoM6K/img.png&quot; data-alt=&quot;https://www.fatalerrors.org/a/producer-consumer-model.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/emUaUa/btq6rnbVCh4/Vebi97DEzp8qiczV6HoM6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FemUaUa%2Fbtq6rnbVCh4%2FVebi97DEzp8qiczV6HoM6K%2Fimg.png&quot; data-origin-width=&quot;499&quot; data-origin-height=&quot;206&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.fatalerrors.org/a/producer-consumer-model.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;세마포어(Semaphore)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;600&quot; height=&quot;439&quot; data-origin-width=&quot;1194&quot; data-origin-height=&quot;872&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcZ9aG/btq6vv0NVPS/Dt1eJVh8zB9KH61I0SXLf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcZ9aG/btq6vv0NVPS/Dt1eJVh8zB9KH61I0SXLf1/img.png&quot; data-alt=&quot;세마포어 커널 자료구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcZ9aG/btq6vv0NVPS/Dt1eJVh8zB9KH61I0SXLf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcZ9aG%2Fbtq6vv0NVPS%2FDt1eJVh8zB9KH61I0SXLf1%2Fimg.png&quot; width=&quot;600&quot; height=&quot;439&quot; data-origin-width=&quot;1194&quot; data-origin-height=&quot;872&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;세마포어 커널 자료구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;동시에 여러 프로세스가 접근할 때, 한 프로세스만 실행해야 하는 중요한 코드가 있는 임계 영역(&lt;a href=&quot;https://en.wikipedia.org/wiki/Critical_section&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;critical section&lt;/a&gt;)을 구현할 때 사용&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;세마포어의 가장 단순한 형태는 메모리의 어떤 위치에 있는 변수로, 그 값을 검사하고 설정(test and set)하는 연산을 하나 이상의 프로세스가 할 수 있고, 검사 및 설정 연산이 비선점형으로 절대 중단되지 않도록 원자적으로 처리하는 것&lt;/li&gt;
&lt;li&gt;&lt;u&gt;프로세스는 세마포어의 값을 감소시키거나 증가시킬 수 있으며, 다른 프로세스에 의해 세마포어가 특정 값이 되면, 현재 접근하는 프로세스는 대기 상태가 되어 세마포어가 이용가능할 때 깨어남&lt;/u&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어, 임계 영역에 접근할 때 프로세스 A가 세마포어를 1 -&amp;gt; 0 (특정 값) 으로 바꾸면, 다른 프로세스들은 감소시킬 때 (테스트 과정에서)&amp;nbsp;0 -&amp;gt; -1 이 되면서 세마포어가 0이 아니게 되므로 대기 상태가 됨&lt;/li&gt;
&lt;li&gt;프로세스 A가 작업을 끝내고 임계 영역을 벗어날 때 세마포어를 0 -&amp;gt; 1로 바꾸면, 대기 중이던 프로세스들이 실행중 상태가 되어 세마포어 값을 A처럼 바꾸고 작업&lt;/li&gt;
&lt;li&gt;세마포어도 종류가 있는데, 이진 세마포어는 흔히 뮤텍스로 알려져 있으며, 2가지 상태만 가지고, 위의 예시는 카운팅 세마포어라고 해서 임계 영역에 접근할 프로세스 수를 제한하는 것으로 특정 값은 대개 0이고, 최초 지정한 숫자만큼 프로세스가 임계 영역에 접근할 수 있음 (접근할 때마다 카운트 값이 증가하고 빠져나가면 감소)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #3c4043;&quot;&gt;커널 코드에서 세마포어 값을 검사하는 함수는 try_semop()이며, 세마포어 값을 바꾸는 함수는 do_semop()&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #3c4043;&quot;&gt;&lt;span style=&quot;caret-color: #3c4043;&quot;&gt;세마포어 객체는 semid_ds 구조체로 기술되며, semary 배열에 semid_ds 구조체의 포인터가 저장되어 있음&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #3c4043;&quot;&gt;&lt;span style=&quot;caret-color: #3c4043;&quot;&gt;semid_ds 구조체는 sem_nsems 만큼의 세마포어 배열에 있으며, sem_base가 배열의 주소를 가지고 있고, 배열의 각 원소는 sem 구조체이며 이 구조체가 하나의 세마포어를 나타냄&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #3c4043;&quot;&gt;&lt;span style=&quot;caret-color: #3c4043;&quot;&gt;세마포어 배열을 관리할 수 있는 권한을 가진 프로세스들은 시스템 콜로 한 번에 여러 개의 세마포어 연산을 지정할 수 있음&lt;/span&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #3c4043;&quot;&gt;&lt;span style=&quot;caret-color: #3c4043;&quot;&gt;각 연산은 세마포어 (배열에서의) 인덱스, 연산 값(현재 값에 추가될 숫자), 플래그 세트라는 3가지 인자를 받음&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #3c4043;&quot;&gt;&lt;span style=&quot;caret-color: #3c4043;&quot;&gt;커널은 모든 세마포어 연산을 성공할 수 있는지 테스트하며, &lt;span style=&quot;color: #000000;&quot;&gt;연산 값을 세마포어의 현재 값에 더한 값이 0 이상이거나, 연산 값과 세마포어의 현재 값이 모두 0일 때, 이 연산은 성공&lt;/span&gt;한 것으로 간주&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;만약 연산 중 하나라도 실패하면, 플래그에 블럭킹 모드를 지정한 경우 프로세스는 중단되고, 커널은 수행해야 할 세마포어 연산의 상태를 저장한 뒤, 현재 프로세스를 대기 큐에 추가. 이후 다른 프로세스를 실행하기 위해 스케줄러를 호출&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;세마포어의 대기 큐는 sem_pending 포인터로 관리되며, 프로세스를 추가할 때 새 sem_queue 구조체를 할당하여 큐에 추가&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;만약 모든 연산이 성공하여 프로세스가 중단될 필요가 없다면, 세마포어 배열의 올바른 세마포어에 그 연산을 적용&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이후, 대기 큐에서 기다리며 중단되어 있는 프로세스들에 대해 검사하기 위해 sem_pending 포인터로 하나씩 세마포어 연산을 테스트. 연산을 성공하면 sem_pending 이 참조하는 큐에서 해당 프로세스의 sem_queue 구조체를 제거하고 세마포어 배열에 있는 해당 세마포어에 연산을 적용&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;대기 중인 프로세스를 실행중 상태로 변경하여 다음 스케줄링에서 선택되게 함&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;sem_pending 에서 깨울 프로세스가 없을 때까지 위 과정을 반복&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #3c4043;&quot;&gt;&lt;span style=&quot;caret-color: #3c4043;&quot;&gt;&lt;b&gt;데드락(deadlock)&lt;/b&gt; 한&amp;nbsp;프로세스가&amp;nbsp;임계지역에&amp;nbsp;들어가면서&amp;nbsp;세마포어의&amp;nbsp;값을&amp;nbsp;바꾸었는데&amp;nbsp;프로세스가&amp;nbsp;잘못되거나&amp;nbsp;강제로&amp;nbsp;종료되어서&amp;nbsp;이&amp;nbsp;임계지역을&amp;nbsp;빠져나가지&amp;nbsp;못한&amp;nbsp;경우&lt;/span&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #3c4043;&quot;&gt;&lt;span style=&quot;caret-color: #3c4043;&quot;&gt;세마포어&amp;nbsp;배열에&amp;nbsp;대한&amp;nbsp;조정&amp;nbsp;리스트(sem_pending_last 포인터가 참조하는 큐)를&amp;nbsp;관리함으로써&amp;nbsp;방지&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #3c4043;&quot;&gt;&lt;span style=&quot;caret-color: #3c4043;&quot;&gt;이런&amp;nbsp;조정을&amp;nbsp;적용하면&amp;nbsp;그&amp;nbsp;프로세스가&amp;nbsp;세마포어&amp;nbsp;연산을&amp;nbsp;수행하기&amp;nbsp;이전의&amp;nbsp;상태로&amp;nbsp;되돌아감&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #3c4043;&quot;&gt;&lt;span style=&quot;caret-color: #3c4043;&quot;&gt;조정에&amp;nbsp;대한&amp;nbsp;것은&amp;nbsp;sem_undo 구조체로 기술하고,&amp;nbsp;이들은&amp;nbsp;semid_ds 구조체와 프로세스의&amp;nbsp;task_struct 구조체의 큐에 추가됨&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #3c4043;&quot;&gt;&lt;span style=&quot;caret-color: #3c4043;&quot;&gt;세마포어&amp;nbsp;배열에&amp;nbsp;있는&amp;nbsp;세마포어에&amp;nbsp;연산을&amp;nbsp;적용하면&amp;nbsp;연산 값을&amp;nbsp;반대로&amp;nbsp;한&amp;nbsp;값이&amp;nbsp;이&amp;nbsp;프로세스의&amp;nbsp;sem_undo 구조체에 저장됨&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #3c4043;&quot;&gt;&lt;span style=&quot;caret-color: #3c4043;&quot;&gt;기본적으로 프로세스가 sem_undo 구조체를 생성하지 않더라도 커널은 필요하면 생성함&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #3c4043;&quot;&gt;&lt;span style=&quot;caret-color: #3c4043;&quot;&gt;프로세스가&amp;nbsp;종료될 때, 커널은 sem_undo 구조체들을 가지고&amp;nbsp;세마포어&amp;nbsp;배열에&amp;nbsp;조정을&amp;nbsp;적용.&amp;nbsp;만약 세마포어 객체가&amp;nbsp;지워지면&amp;nbsp;프로세스의&amp;nbsp;task_struct의&amp;nbsp;큐&amp;nbsp;되어&amp;nbsp;있는&amp;nbsp;sem_undo&amp;nbsp;자료구조는 유지되나 세마포어&amp;nbsp;정리&amp;nbsp;코드는 sem_undo 구조체를&amp;nbsp;무시&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;u&gt;&lt;span style=&quot;color: #3c4043;&quot;&gt;&lt;span style=&quot;caret-color: #3c4043;&quot;&gt;데드락은 한&amp;nbsp;프로세스가&amp;nbsp;필요로&amp;nbsp;하는&amp;nbsp;자원을&amp;nbsp;다른&amp;nbsp;프로세스가&amp;nbsp;사용하고&amp;nbsp;있어&amp;nbsp;대기&amp;nbsp;상태로&amp;nbsp;갔는데,&amp;nbsp;나중에&amp;nbsp;그&amp;nbsp;프로세스가&amp;nbsp;앞의&amp;nbsp;프로세스가&amp;nbsp;점유하고&amp;nbsp;있는&amp;nbsp;자원을&amp;nbsp;필요로&amp;nbsp;하게&amp;nbsp;되어&amp;nbsp;프로세스들이&amp;nbsp;서로&amp;nbsp;상대가&amp;nbsp;자원&amp;nbsp;사용을&amp;nbsp;종료하기만을&amp;nbsp;기다리게&amp;nbsp;되는&amp;nbsp;상태일 때도 발생&lt;/span&gt;&lt;/span&gt;&lt;/u&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #3c4043;&quot;&gt;&lt;span style=&quot;caret-color: #3c4043;&quot;&gt;프로세스가&amp;nbsp;세마포어를&amp;nbsp;이용하여&amp;nbsp;임계지역으로&amp;nbsp;들어간&amp;nbsp;후&amp;nbsp;다시&amp;nbsp;세마포어를&amp;nbsp;얻으려고&amp;nbsp;할&amp;nbsp;때&amp;nbsp;자원&amp;nbsp;해제&amp;nbsp;등의&amp;nbsp;예외처리를&amp;nbsp;하거나,&amp;nbsp;꼬이지&amp;nbsp;않도록&amp;nbsp;점유하는&amp;nbsp;순서를&amp;nbsp;보장하여 해결 가능&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #3c4043;&quot;&gt;&lt;span style=&quot;caret-color: #3c4043;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;633&quot; height=&quot;382&quot; data-origin-width=&quot;1876&quot; data-origin-height=&quot;1132&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSCsCC/btq6rnwa8jU/DsfTb7aLL8MaHgneJHeL0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSCsCC/btq6rnwa8jU/DsfTb7aLL8MaHgneJHeL0K/img.png&quot; data-alt=&quot;https://www.slideshare.net/anniyappa/ipc-in-linux&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSCsCC/btq6rnwa8jU/DsfTb7aLL8MaHgneJHeL0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSCsCC%2Fbtq6rnwa8jU%2FDsfTb7aLL8MaHgneJHeL0K%2Fimg.png&quot; width=&quot;633&quot; height=&quot;382&quot; data-origin-width=&quot;1876&quot; data-origin-height=&quot;1132&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.slideshare.net/anniyappa/ipc-in-linux&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://slidetodoc.com/carnegie-mellon-synchronization-carnegie-mellon-single-and-multithreaded/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;RE: 쓰레드간 동기화는 뮤텍스(mutex)를 사용하며, 프로세스간 동기화는 세마포어(semaphore)를 사용&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;273&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKRNa1/btq6roaLkTd/1XOaK17RwclqOlQdB2ADx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKRNa1/btq6roaLkTd/1XOaK17RwclqOlQdB2ADx0/img.png&quot; data-alt=&quot;https://www.doomedraven.com/2011/11/python-threads-synchronization-locks.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKRNa1/btq6roaLkTd/1XOaK17RwclqOlQdB2ADx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKRNa1%2Fbtq6roaLkTd%2F1XOaK17RwclqOlQdB2ADx0%2Fimg.png&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;273&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.doomedraven.com/2011/11/python-threads-synchronization-locks.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;공유 메모리(Shared Memory)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-src=&quot;/images/shared-memory.png&quot; data-pagespeed-url-hash=&quot;2610854267&quot; data-pagespeed-onload=&quot;pagespeed.CriticalImages.checkImageForCriticality(this);&quot; data-pagespeed-loaded=&quot;1&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot; width=&quot;710&quot; height=&quot;355&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsWJGc/btq6uFbWpTR/LiZRXVnNVcTsJhIERoWXW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsWJGc/btq6uFbWpTR/LiZRXVnNVcTsJhIERoWXW0/img.png&quot; data-alt=&quot;https://www.softprayog.in/programming/interprocess-communication-using-system-v-shared-memory-in-linux&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsWJGc/btq6uFbWpTR/LiZRXVnNVcTsJhIERoWXW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsWJGc%2Fbtq6uFbWpTR%2FLiZRXVnNVcTsJhIERoWXW0%2Fimg.png&quot; data-src=&quot;/images/shared-memory.png&quot; data-pagespeed-url-hash=&quot;2610854267&quot; data-pagespeed-onload=&quot;pagespeed.CriticalImages.checkImageForCriticality(this);&quot; data-pagespeed-loaded=&quot;1&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot; width=&quot;710&quot; height=&quot;355&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.softprayog.in/programming/interprocess-communication-using-system-v-shared-memory-in-linux&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;520&quot; height=&quot;330&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;330&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chXUVd/btq6qnjgKCv/tLk1XICuHxcvUBq32oqoh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chXUVd/btq6qnjgKCv/tLk1XICuHxcvUBq32oqoh1/img.png&quot; data-alt=&quot;https://www.w3schools.in/operating-system-tutorial/interprocess-communication-ipc/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chXUVd/btq6qnjgKCv/tLk1XICuHxcvUBq32oqoh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchXUVd%2Fbtq6qnjgKCv%2FtLk1XICuHxcvUBq32oqoh1%2Fimg.png&quot; width=&quot;520&quot; height=&quot;330&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;330&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.w3schools.in/operating-system-tutorial/interprocess-communication-ipc/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;597&quot; height=&quot;392&quot; data-origin-width=&quot;1184&quot; data-origin-height=&quot;778&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ch98DF/btq6rohx3DH/pf6P8X65z8chjDLAKr2Vf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ch98DF/btq6rohx3DH/pf6P8X65z8chjDLAKr2Vf0/img.png&quot; data-alt=&quot;공유 메모리 커널 자료구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ch98DF/btq6rohx3DH/pf6P8X65z8chjDLAKr2Vf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fch98DF%2Fbtq6rohx3DH%2Fpf6P8X65z8chjDLAKr2Vf0%2Fimg.png&quot; width=&quot;597&quot; height=&quot;392&quot; data-origin-width=&quot;1184&quot; data-origin-height=&quot;778&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;공유 메모리 커널 자료구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;동일한 물리 메모리가 매핑된 가상 페이지를 이용하여 둘 이상의 프로세스가 통신하며,&amp;nbsp;각 프로세스의 페이지 테이블에는 공유 메모리 페이지의 PTE가 존재&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;IPC 객체와 마찬가지로 공유 메모리 영역으로의 접근은 키에 의해 제어되고 접근 권한을 검사함. 단,&amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;한 번 메모리가 공유되면 프로세스들이 이를 어떻게 사용하는지에 대해서 아무런 검사도 하지 않음. 따라서 세마포어 같은 것으로 메모리 접근을 동기화해야 함&lt;/span&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;공유 메모리를 생성한 프로세스가 이 메모리에 대한 접근권한과 키가 공용인지 개인용인지 제어&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;처음 공유 메모리를 생성하면 가상 주소공간에만 존재하는데, 생성한 프로세스가 충분한 권한이 있다면 물리 메모리에 로드 가능&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;공유 메모리는 shmid_ds 구조체로 기술되며, shm_segs 배열에 이 구조체를 저장. 각 shmid_ds 구조체는 &lt;span style=&quot;color: #000000;&quot;&gt;공유 메모리 영역이 얼마나 큰지, 얼마나 많은 프로세스가 사용하고 있으며, 공유 메모리가 프로세스의 주소공간에 어떻게 매핑되어 있는지에 대한 정보를 포함&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;메모리를 공유하길 바라는 각 프로세스들은 시스템 콜을 통해 가상 메모리에 연결&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;공유 메모리를 기술하는 새로운 vm_area_struct 구조체 생성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가상 주소공간에 공유 메모리의 위치를 지정하거나 운영체제가 임의의 빈 공간을 지정하도록 할 수 있음 (인자로 결정)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;새로 만들어진 vm_area_struct 구조체는 shmid_ds 구조체에서 참조하는 vm_area_struct 구조체 리스트에 추가&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;vm_next_shared 와 vm_prev_shared 포인터들은 공유 메모리의 vm_area_struct 구조체들을 서로 연결하는데 사용&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가상 메모리에 연결하는 과정(메모리 매핑)은 실제 물리 메모리를 할당하지 않으며, 처음으로 프로세스가 여기에 접근하려고 할 때 물리 페이지를 할당(요구 페이징)&lt;/span&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;프로세스가 공유하고 있는 가상 메모리의 한 페이지에 처음으로 접근을 시도하면 페이지 폴트가 발생&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;페이지 폴트를 처리할 때, 해당 vm_area_struct 구조체를 탐색하는데, 이 구조체에 공유 가상 메모리 관련 루틴 포인터가 존재&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;페이지 폴트 핸들러는 shmid_ds 구조체에서 PTE를 찾아보고, 공유 가상 메모리의 해당 페이지에 대한 PTE가 없으면 물리 메모리 할당 후 PTE 추가&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;다음 프로세스가 이 메모리에 접근하려고 할 때 페이지 폴트가 발생하는데, 공유 메모리의 vm_area_struct 에 있는 페이지 폴트 핸들러는 &lt;u&gt;이전에 새로 할당된 물리 페이지에 대한 PTE를 이 프로세스의 페이지 테이블에 추가, shmid_ds 구조체에도 추가&lt;/u&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;즉, 공유 메모리의 어떤 페이지에 접근하는 첫번째 프로세스는 물리 메모리를 할당하고, 다른 프로세스들이 여기에 접근할 때는 이를 자신의 가상 주소공간으로 접근할 수 있도록 페이지 테이블에 추가하는 것&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;공유 메모리로의 연결을 끊을 때는 해당 프로세스의 vm_area_struct 구조체들은 shmid_ds 구조체에서 제거되고 해제된 후, 페이지 테이블이 갱신됨&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마지막으로 메모리를 공유하고 있던 프로세스가 연결을 끊으면 물리 메모리에 존재하고 있는 모든 공유 메모리 페이지들은 해제되고, 이 공유 메모리를 나타내던 shmid_ds 구조체도 해제됨&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Operating System/Linux</category>
      <category>IPC</category>
      <category>Linux Kernel</category>
      <category>Operating System</category>
      <category>공유 메모리</category>
      <category>리눅스 커널</category>
      <category>메시지 큐</category>
      <category>뮤텍스</category>
      <category>세마포어</category>
      <category>운영체제</category>
      <category>프로세스간 통신</category>
      <author>r4v3n-k</author>
      <guid isPermaLink="true">https://movefast.tistory.com/344</guid>
      <comments>https://movefast.tistory.com/344#entry344comment</comments>
      <pubDate>Thu, 3 Jun 2021 19:31:56 +0900</pubDate>
    </item>
    <item>
      <title>리눅스 커널 - 프로세스와 쓰레드</title>
      <link>https://movefast.tistory.com/343</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;본 글은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;http://wiki.kldp.org/Translations/html/The_Linux_Kernel-KLDP/The_Linux_Kernel-KLDP.html&quot;&gt;The Linux Kernel&lt;/a&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;을 정리한 것이며, 출처를 밝히지 않은 모든 이미지는 원글에 속한 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로그램과 프로세스&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;프로그램&lt;/b&gt; 디스크에 실행 가능한 형태(Executable and Linking Format, ELF)로 저장되어 있는 기계어 명령과 자료의 집합&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로세스&lt;/b&gt;&amp;nbsp;실행중인 프로그램, 기계어 명령들을 실행함에 따라 끊임없이 변화하는 동적인 존재&lt;/li&gt;
&lt;li&gt;프로그램을 실행하면 프로세스의 가상 주소공간에는 프로그램의 명령어와 데이터 뿐만 아니라, 프로그램 카운터(PC), CPU 레지스터, 그리고 루틴 인자, 복귀 주소, 저장된 변수 같은 일시적인 데이터를 보관하는 스택(stack)도 포함됨&lt;/li&gt;
&lt;li&gt;운영체제에서 프로세스란 &lt;b&gt;각각 고유의 권한과 책임을 가지는 하나의 작업(task)&lt;/b&gt;이며, 각 프로세스는 자신의 가상 주소공간에서만 실행되는데, 커널의 도움을 받는다면 다른 프로세스와 상호작용(프로세스간 통신, IPC) 할 수 있음&lt;/li&gt;
&lt;li&gt;프로세스가 사용하는 시스템 자원은 크게 4가지
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;CPU 자원&lt;/b&gt;&amp;nbsp;명령을 수행하기 위해 일정한 시간이 프로세스마다 할당되어 CPU가 실행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메모리 자원&lt;/b&gt; 명령어와 데이터 등을 실행하려면 프로세스가 실행되는 부분을 물리 메모리에 로드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디스크 자원&lt;/b&gt; 파일 시스템의 파일들을 열고 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디바이스 드라이버&lt;/b&gt;&amp;nbsp;네트워크나 키보드 장치 같은 물리적인 장치를 직접적으로 또는 간접적으로 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;커널은 여러 시스템 자원을 관리하고, 프로세스들이 공평하게 자원을 사용할 수 있도록, 각 프로세스가 가지고 있는 시스템 자원을 추적하는데, 이를 위해 다양한 커널 자료구조가 생성되고 제거됨&lt;/li&gt;
&lt;li&gt;리눅스는 &lt;b&gt;멀티프로세싱(Multiprocessing)&lt;/b&gt; 운영체제이기 때문에, CPU에 코어가 둘 이상이면 각 코어가 항상 프로세스를 실행할 수 있도록 하여 CPU 사용을 극대화
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시스템 자원을 요청한 프로세스는 요청 결과를 얻기까지 대기해야 하는데, 그 시간 동안 CPU는 다른 프로세스를 실행&lt;/li&gt;
&lt;li&gt;유니프로세싱(Uniprocessing)의 경우, 반드시 하나의 프로세스만 종료될 때까지 실행되므로, 자원을 요청하면 CPU는 아무 것도 하지 않은 상태가 됨 (대기 시간을 낭비)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;리눅스는 실시간(real-time) 프로세스도 지원하며, 외부에서 발생하는 사건(event)에 매우 빨리 반응하기 위해 스케줄러는 일반 사용자 프로세스와는 다르게 취급하고 높은 우선순위를 부여함&lt;/li&gt;
&lt;li&gt;CPU가 다음에 실행할 프로세스를 선택하는 작업을 스케줄링(scheduling)이라고 하며, 커널 코드에서 스케줄러가 이를 수행함&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로세스&amp;nbsp;자료구조&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;602&quot; height=&quot;312&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;347&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dAcTDs/btq6qRCSf7w/QCQIaQHV0NnJHlBVHAY581/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dAcTDs/btq6qRCSf7w/QCQIaQHV0NnJHlBVHAY581/img.png&quot; data-alt=&quot;https://myaut.github.io/dtrace-stap-book/kernel/proc.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dAcTDs/btq6qRCSf7w/QCQIaQHV0NnJHlBVHAY581/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdAcTDs%2Fbtq6qRCSf7w%2FQCQIaQHV0NnJHlBVHAY581%2Fimg.png&quot; width=&quot;602&quot; height=&quot;312&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;347&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://myaut.github.io/dtrace-stap-book/kernel/proc.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;각 프로세스는 task_struct 구조체로 표현되며, task 배열은 task_struct 구조체의 포인터를 저장하여 프로세스들을 관리&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;시스템이 생성할 수 있는 최대 프로세스의 개수는 task 배열의 크기로 제한됨 (기본값 512)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;current 변수&lt;/b&gt;&amp;nbsp;현재 CPU가 실행하고 있는 프로세스를 참조하는 포인터&lt;/li&gt;
&lt;li&gt;task_struct의 state 변수는 실행되면서 상황에 따라 바뀌는 프로세스의 상태를 나타냄
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;new&lt;/b&gt; 프로세스가 생성된 상태&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ready&lt;/b&gt; 프로세스가 메모리에 로드되어 실행 준비가 된 상태&lt;/li&gt;
&lt;li&gt;&lt;b&gt;running&lt;/b&gt; 현재 CPU가 프로세스를 실행하고 있는 상태&lt;/li&gt;
&lt;li&gt;&lt;b&gt;waiting&lt;/b&gt; 프로세스가 이벤트나 시스템 자원을 기다리고 있는 상태&lt;/li&gt;
&lt;li&gt;&lt;b&gt;terminated&lt;/b&gt; 프로세스가 종료된 상태&lt;/li&gt;
&lt;li&gt;&lt;b&gt;blocked/suspend&lt;/b&gt; 스왑 아웃된 프로세스가 실행 준비가 되지 않은 상태&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ready/suspend&lt;/b&gt; 스왑 아웃된 프로세스가 실행 준비가 된 상태&lt;/li&gt;
&lt;li&gt;waiting 상태에 있는 프로세스들은 스왑 아웃하기 좋은 후보이기 때문에, 스와핑될 경우 blocked/suspend 상태가 됨&lt;/li&gt;
&lt;li&gt;블럭킹 모드에서 실행되면 해당 프로세스는 running -&amp;gt; waiting 상태가 되는 것이지 waiting -&amp;gt; blocked/suspend 상태가 되는 것이 아님
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스와핑된 상태에서 이벤트가 완료되면 blocked/suspend -&amp;gt; ready/suspend 상태가 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; srcset=&quot;https://slaystudy.com/wp-content/uploads/2020/07/2state2suspended2.png?ezimgfmt=ng:webp/ngcb1 801w, https://slaystudy.com/wp-content/uploads/2020/07/2state2suspended2-300x180.png?ezimgfmt=ng:webp/ngcb1 300w, https://slaystudy.com/wp-content/uploads/2020/07/2state2suspended2-768x461.png?ezimgfmt=ng:webp/ngcb1 768w&quot; width=&quot;801&quot; height=&quot;481&quot; data-ezsrcset=&quot;https://slaystudy.com/wp-content/uploads/2020/07/2state2suspended2.png?ezimgfmt=ng:webp/ngcb1 801w,https://slaystudy.com/wp-content/uploads/2020/07/2state2suspended2-300x180.png?ezimgfmt=ng:webp/ngcb1 300w,https://slaystudy.com/wp-content/uploads/2020/07/2state2suspended2-768x461.png?ezimgfmt=ng:webp/ngcb1 768w&quot; data-ezsrc=&quot;https://slaystudy.com/wp-content/uploads/2020/07/2state2suspended2.png?ezimgfmt=rs:801x481/rscb1/ng:webp/ngcb1&quot; data-origin-width=&quot;748&quot; data-origin-height=&quot;449&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oiFAw/btq6nBOCiD1/87lz9IiOPXCMKuonQFV1x1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oiFAw/btq6nBOCiD1/87lz9IiOPXCMKuonQFV1x1/img.webp&quot; data-alt=&quot;https://slaystudy.com/process-state-models-in-operating-system/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oiFAw/btq6nBOCiD1/87lz9IiOPXCMKuonQFV1x1/img.webp&quot; srcset=&quot;https://slaystudy.com/wp-content/uploads/2020/07/2state2suspended2.png?ezimgfmt=ng:webp/ngcb1 801w, https://slaystudy.com/wp-content/uploads/2020/07/2state2suspended2-300x180.png?ezimgfmt=ng:webp/ngcb1 300w, https://slaystudy.com/wp-content/uploads/2020/07/2state2suspended2-768x461.png?ezimgfmt=ng:webp/ngcb1 768w&quot; width=&quot;801&quot; height=&quot;481&quot; data-ezsrcset=&quot;https://slaystudy.com/wp-content/uploads/2020/07/2state2suspended2.png?ezimgfmt=ng:webp/ngcb1 801w,https://slaystudy.com/wp-content/uploads/2020/07/2state2suspended2-300x180.png?ezimgfmt=ng:webp/ngcb1 300w,https://slaystudy.com/wp-content/uploads/2020/07/2state2suspended2-768x461.png?ezimgfmt=ng:webp/ngcb1 768w&quot; data-ezsrc=&quot;https://slaystudy.com/wp-content/uploads/2020/07/2state2suspended2.png?ezimgfmt=rs:801x481/rscb1/ng:webp/ngcb1&quot; data-origin-width=&quot;748&quot; data-origin-height=&quot;449&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://slaystudy.com/process-state-models-in-operating-system/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;475&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEw3v8/btq6mGilv6Q/DLhtjenzbbQrBK8a7uhokk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEw3v8/btq6mGilv6Q/DLhtjenzbbQrBK8a7uhokk/img.png&quot; data-alt=&quot;https://www.javatpoint.com/os-process-states&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEw3v8/btq6mGilv6Q/DLhtjenzbbQrBK8a7uhokk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEw3v8%2Fbtq6mGilv6Q%2FDLhtjenzbbQrBK8a7uhokk%2Fimg.png&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;475&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.javatpoint.com/os-process-states&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;좀비 프로세스&lt;/b&gt;&amp;nbsp;정지된 프로세스이지만, 어떤 이유로 여전히 task 배열에 task_struct 구조체가 남아있는 프로세스 (자원 낭비)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로세스 식별자(Process Identifier, PID)&lt;/b&gt; 시스템의 모든 프로세스는 각자의 고유한 식별자를 가지며, 이는 task 벡터의 인덱스와는 다름. 식별자는 사용자 식별자와 그룹 식별자로 나뉘는데, 이는 &lt;u&gt;각 프로세스가 시스템 파일이나 장치에 접근할 때 제어하는 용도&lt;/u&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리눅스에서 시스템의 모든 파일들은 소유권과 접근 권한을 가짐&lt;/li&gt;
&lt;li&gt;사용자 종류: 소유자, 프로세스 그룹, 모든 프로세스&lt;/li&gt;
&lt;li&gt;접근 권한 종류: 읽기, 쓰기, 실행&lt;/li&gt;
&lt;li&gt;각 사용자 계층은 서로 다른 권한을 가질 수 있음. 예를 들어, 소유자는 읽기/쓰기 가능인데 그룹은 읽기만 허용하는 경우&lt;/li&gt;
&lt;li&gt;chown 명령어는 파일의 소유권을 변경하며, chmod 명령어는 파일의 접근 권한을 변경&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;258&quot; width=&quot;569&quot; height=&quot;121&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bk4XpW/btq6qm4eaYu/gICcDOyQUltk7lrDXB3nR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bk4XpW/btq6qm4eaYu/gICcDOyQUltk7lrDXB3nR1/img.png&quot; data-alt=&quot;ls -l 명령어를 실행한 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bk4XpW/btq6qm4eaYu/gICcDOyQUltk7lrDXB3nR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbk4XpW%2Fbtq6qm4eaYu%2FgICcDOyQUltk7lrDXB3nR1%2Fimg.png&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;258&quot; width=&quot;569&quot; height=&quot;121&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ls -l 명령어를 실행한 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;File Mode 와 Owner 사이의 숫자 3은 하드 링크의 개수로, 몇 번 복사되었는지를 나타냄&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; srcset=&quot;https://www.booleanworld.com/wp-content/uploads/2018/04/classes.png?ezimgfmt=ng:webp/ngcb5 750w, https://www.booleanworld.com/wp-content/uploads/2018/04/classes-300x83.png?ezimgfmt=ng:webp/ngcb5 300w, https://www.booleanworld.com/wp-content/uploads/2018/04/classes-300x83@2x.png?ezimgfmt=ng:webp/ngcb5 600w&quot; width=&quot;461&quot; height=&quot;128&quot; data-ezsrcset=&quot;https://www.booleanworld.com/wp-content/uploads/2018/04/classes.png?ezimgfmt=ng:webp/ngcb5 750w,https://www.booleanworld.com/wp-content/uploads/2018/04/classes-300x83.png?ezimgfmt=ng:webp/ngcb5 300w,https://www.booleanworld.com/wp-content/uploads/2018/04/classes-300x83@2x.png?ezimgfmt=ng:webp/ngcb5 600w&quot; data-ezsrc=&quot;https://www.booleanworld.com/wp-content/uploads/2018/04/classes.png?ezimgfmt=rs:720x200/rscb5/ng:webp/ngcb5&quot; data-origin-width=&quot;748&quot; data-origin-height=&quot;207&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oTSng/btq6qoOsYUe/LJ3yP28JkAZRlGhFrKRWlK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oTSng/btq6qoOsYUe/LJ3yP28JkAZRlGhFrKRWlK/img.webp&quot; data-alt=&quot;https://www.booleanworld.com/introduction-linux-file-permissions/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oTSng/btq6qoOsYUe/LJ3yP28JkAZRlGhFrKRWlK/img.webp&quot; srcset=&quot;https://www.booleanworld.com/wp-content/uploads/2018/04/classes.png?ezimgfmt=ng:webp/ngcb5 750w, https://www.booleanworld.com/wp-content/uploads/2018/04/classes-300x83.png?ezimgfmt=ng:webp/ngcb5 300w, https://www.booleanworld.com/wp-content/uploads/2018/04/classes-300x83@2x.png?ezimgfmt=ng:webp/ngcb5 600w&quot; width=&quot;461&quot; height=&quot;128&quot; data-ezsrcset=&quot;https://www.booleanworld.com/wp-content/uploads/2018/04/classes.png?ezimgfmt=ng:webp/ngcb5 750w,https://www.booleanworld.com/wp-content/uploads/2018/04/classes-300x83.png?ezimgfmt=ng:webp/ngcb5 300w,https://www.booleanworld.com/wp-content/uploads/2018/04/classes-300x83@2x.png?ezimgfmt=ng:webp/ngcb5 600w&quot; data-ezsrc=&quot;https://www.booleanworld.com/wp-content/uploads/2018/04/classes.png?ezimgfmt=rs:720x200/rscb5/ng:webp/ngcb5&quot; data-origin-width=&quot;748&quot; data-origin-height=&quot;207&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.booleanworld.com/introduction-linux-file-permissions/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; srcset=&quot;https://www.booleanworld.com/wp-content/uploads/2018/04/43260_115.png?ezimgfmt=ng:webp/ngcb5 495w, https://www.booleanworld.com/wp-content/uploads/2018/04/43260_115-300x228.png?ezimgfmt=ng:webp/ngcb5 300w&quot; width=&quot;237&quot; height=&quot;180&quot; data-ezsrcset=&quot;https://www.booleanworld.com/wp-content/uploads/2018/04/43260_115.png?ezimgfmt=ng:webp/ngcb5 495w,https://www.booleanworld.com/wp-content/uploads/2018/04/43260_115-300x228.png?ezimgfmt=ng:webp/ngcb5 300w&quot; data-ezsrc=&quot;https://www.booleanworld.com/wp-content/uploads/2018/04/43260_115.png?ezimgfmt=rs:495x376/rscb5/ng:webp/ngcb5&quot; data-origin-width=&quot;748&quot; data-origin-height=&quot;568&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcgyzw/btq6qo11jNq/UykH2aThGAZCpzyA0Z6SOk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcgyzw/btq6qo11jNq/UykH2aThGAZCpzyA0Z6SOk/img.webp&quot; data-alt=&quot;chmod 755 file_name ; 명령어를 실행하면 위의 권한을 가지게 됨&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcgyzw/btq6qo11jNq/UykH2aThGAZCpzyA0Z6SOk/img.webp&quot; srcset=&quot;https://www.booleanworld.com/wp-content/uploads/2018/04/43260_115.png?ezimgfmt=ng:webp/ngcb5 495w, https://www.booleanworld.com/wp-content/uploads/2018/04/43260_115-300x228.png?ezimgfmt=ng:webp/ngcb5 300w&quot; width=&quot;237&quot; height=&quot;180&quot; data-ezsrcset=&quot;https://www.booleanworld.com/wp-content/uploads/2018/04/43260_115.png?ezimgfmt=ng:webp/ngcb5 495w,https://www.booleanworld.com/wp-content/uploads/2018/04/43260_115-300x228.png?ezimgfmt=ng:webp/ngcb5 300w&quot; data-ezsrc=&quot;https://www.booleanworld.com/wp-content/uploads/2018/04/43260_115.png?ezimgfmt=rs:495x376/rscb5/ng:webp/ngcb5&quot; data-origin-width=&quot;748&quot; data-origin-height=&quot;568&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;chmod 755 file_name ; 명령어를 실행하면 위의 권한을 가지게 됨&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;task_struct 구조체는 4 쌍의 사용자 식별자와 그룹 식별자를 저장하고 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;uid, gid&lt;/b&gt;&amp;nbsp;프로세스를 실행시킨 사용자의 식별자와 그룹 식별자&lt;/li&gt;
&lt;li&gt;&lt;b&gt;effective uid, gid (euid, egid)&lt;/b&gt;&amp;nbsp;프로세스의 uid, gid를 디스크의 실행 이미지의 uid, gid로 변경시키는 &lt;u&gt;setuid 프로그램&lt;/u&gt;의 사용자 식별자와 그룹 식별자&lt;/li&gt;
&lt;li&gt;&lt;b&gt;file system uid, gid&lt;/b&gt;&amp;nbsp;프로세스가 &lt;u&gt;파일 시스템에 자원을 요청할 때 접근 권한을 검사&lt;/u&gt;하기 위해 사용하는 uid, gid로, euid, egid와 동일
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어, 원격에서 마운트된 파일 시스템에서 사용자 모드인 NFS 서버가 파일에 접근할 때, 서버가 아닌 특정 프로세스로서 파일을 접근하기 위해 file system uid, gid 만 변경 (euid, egid 변경하지 않음)&lt;/li&gt;
&lt;li&gt;사용자가 NFS 서버에 kill 시그널을 보내는 등 악의적인 공격을 행할 경우 kill 시그널은 특정 euid, egid 를 가진 프로세스에게만 전달되기 때문에 euid, egid가 수정되지 않게 하여 이 공격을 방지할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;saved uid, gid&lt;/b&gt;&amp;nbsp;시스템 콜을 이용하여 프로세스의 uid, gid를 바꾸는 프로그램이 사용하는 uid, gid로, 원래의 uid, gid가 바뀌어 있는 동안 &lt;u&gt;실제 이전의 uid, gid를 저장하는 용도&lt;/u&gt;로 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시간과 타이머&lt;/b&gt;&amp;nbsp;커널은 각 프로세스의 생성 시간과 프로세스가 사용한 CPU 시간을 관리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;매 클럭 틱마다 현재 프로세스가 커널 모드와 유저 모드에서 사용한 시간의 양을 jiffies 단위로 계산하여 갱신&lt;/li&gt;
&lt;li&gt;프로세스가 직접 지정하여 사용할 수 있는 간격 타이머(interval timer)도 지원하며, 이 시간이 만료되면 프로세스는 자신에게 시그널을 보낼 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;real&amp;nbsp;timer tick&lt;/b&gt;&amp;nbsp;만료 시 프로세스는 SIGALRM 시그널을 받음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;virtual timer tick&lt;/b&gt;&amp;nbsp;만료 시 프로세스는 SIGVTALRM 시그널을 받음 (프로세스가 수행한 시간)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;profile timer tick&lt;/b&gt;&amp;nbsp;만료 시 프로세스는 SIGPROF 시그널을 받음 (프로세스가 수행한 시간과 프로세스의 다른 한편에서 시스템이 수행한 시간을 합친 것)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;하나 또는 모든 간격 타이머가 실행될 수 있으며, 커널은 task_struct에 필요한 모든 정보를 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;커널 스레드와 데몬을 제외한 프로세스들은 각자의 가상 주소공간에서 실행되는데, task_struct 의 mm_struct 구조체가 이를 참조&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로세서 고유 컨텍스트(Processor Specific Context)&lt;/b&gt; 프로세스는 실행될 때마다 CPU의 레지스터와 메모리 공간에 임시 데이터를 보관하는 스택을 사용하는데, 프로세스가 중단될 때 이 데이터들은 task_struct에 저장되었다가 재실행되면 이 정보로부터 컨텍스트를 복구함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이렇게 CPU가 프로세스를 번갈아 실행하는 것을 &lt;a href=&quot;https://nesoy.github.io/articles/2018-11/Context-Switching&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;문맥 교환(Context Switching)&lt;/a&gt;이라고 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1534&quot; data-origin-height=&quot;726&quot; width=&quot;615&quot; height=&quot;291&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ti6fW/btq6q1saTQt/xWggKcrwYHVWB6X6GVaXx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ti6fW/btq6q1saTQt/xWggKcrwYHVWB6X6GVaXx1/img.png&quot; data-alt=&quot;https://slidetodoc.com/carnegie-mellon-processes-slides-adapted-from-randy-bryant/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ti6fW/btq6q1saTQt/xWggKcrwYHVWB6X6GVaXx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fti6fW%2Fbtq6q1saTQt%2FxWggKcrwYHVWB6X6GVaXx1%2Fimg.png&quot; data-origin-width=&quot;1534&quot; data-origin-height=&quot;726&quot; width=&quot;615&quot; height=&quot;291&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://slidetodoc.com/carnegie-mellon-processes-slides-adapted-from-randy-bryant/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;551&quot; data-origin-height=&quot;622&quot; width=&quot;710&quot; height=&quot;801&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDAC9H/btq6qgXht9V/3sepinu7q7Y24vouksvuPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDAC9H/btq6qgXht9V/3sepinu7q7Y24vouksvuPk/img.png&quot; data-alt=&quot;http://sop.upv.es/gii-dso/en/t3-procesos-en-linux/gen-t3-procesos-en-linux.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDAC9H/btq6qgXht9V/3sepinu7q7Y24vouksvuPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDAC9H%2Fbtq6qgXht9V%2F3sepinu7q7Y24vouksvuPk%2Fimg.png&quot; data-origin-width=&quot;551&quot; data-origin-height=&quot;622&quot; width=&quot;710&quot; height=&quot;801&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;http://sop.upv.es/gii-dso/en/t3-procesos-en-linux/gen-t3-procesos-en-linux.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로세스의 파일 연산&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;758&quot; height=&quot;598&quot; data-origin-width=&quot;1494&quot; data-origin-height=&quot;1178&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bReCSY/btq6sjTqJHZ/ZLPOCZSf6VnT52Wr3OonSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bReCSY/btq6sjTqJHZ/ZLPOCZSf6VnT52Wr3OonSK/img.png&quot; data-alt=&quot;fs 포인터 변수 및 files 포인터 변수&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bReCSY/btq6sjTqJHZ/ZLPOCZSf6VnT52Wr3OonSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbReCSY%2Fbtq6sjTqJHZ%2FZLPOCZSf6VnT52Wr3OonSK%2Fimg.png&quot; width=&quot;758&quot; height=&quot;598&quot; data-origin-width=&quot;1494&quot; data-origin-height=&quot;1178&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;fs 포인터 변수 및 files 포인터 변수&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커널은 프로세스가 접근하는 파일 시스템을 관리하기 위해 task_struct 구조체에 &lt;b&gt;fs와 files 포인터&lt;/b&gt;를 이용&lt;/li&gt;
&lt;li&gt;fs 는 fs_struct 구조체를 참조하는 포인터 변수로, fs_struct 구조체는 새로운 파일이 만들어질 때의 기본 모드를 나타내는 umask와 해당 프로세스의 VFS inode에 대한 포인터 두 개를 포함&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;VFS inode 는 디스크를 추상화한 가상 파일 시스템에서 사용하는 파일 식별자 (리눅스는 파일, 디렉토리, 장치 모두 파일로 관리하며, inode 는 파일과 일대일 대응 관계)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;첫번째 VFS inode는 프로세스의 루트 디렉토리(홈 디렉토리)를 가리키며, 두번째 VFS inode는 현재 디렉토리(pwd 명령어로 확인 가능)를 참조&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;각 VFS inode 마다 count 항목으로 몇 개의 프로세스가 그 파일을 참조하고 있는지 파악&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;어떤 디렉토리나 그 디렉토리의 하위 디렉토리가 한 프로세스의 현재 디렉토리로 설정되었다면, 그 디렉토리는 삭제 불가&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;files 는 files_struct 구조체를 참조하는 포인터 변수로, 현재 프로세스가 사용하고 있는 모든 파일들에 대한 정보를 저장&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;리눅스에서는 파일, 디렉토리, 단말 입출력, 물리 장치 모두 파일로 처리되며, 각 파일은 자신을 나타내는 기술자(file descriptor, fd)를 가지며, files_struct 구조체에서는 파일을 기술하는 file 구조체에 대한 포인터(fd)를 최대 256개까지 저장 가능&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;file 구조체는 &lt;span style=&quot;color: #000000;&quot;&gt;파일이 만들어질 때의 모드(읽기 전용, 읽고 쓰기, 쓰기 전용)인 f_mode 항목과 다음 번에 읽거나 쓸 위치를 나타내는 f_pos 항목, 그리고 그 파일에 해당하는 VFS inode인 f_inode 항목 등 파일 연산에 필요한 정보를 가짐&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;f_op 항목은은 그 파일에 대한 작업을 수행하는 루틴들의 주소를 저장한 배열을 참조&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;프로세스는 처음 실행될 때 세개의 파일 기술자가 열려 있다고 가정: &lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;표준 입력(fd=0), 표준 출력(fd=1), 표준 에러(fd=2)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프로세스는 파일 시스템에 접근할 때, 열린 파일 기술자(file descriptor)에 대한 포인터와 두 개의 VFS inode 포인터를 이용&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로세스의 가상 메모리&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;802&quot; height=&quot;549&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;1096&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mIMAq/btq6qhhKYrU/QY2XCeeSWUbZ9fRCxpR2e0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mIMAq/btq6qhhKYrU/QY2XCeeSWUbZ9fRCxpR2e0/img.png&quot; data-alt=&quot;프로세스의 가상 메모리를 관리하는 자료구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mIMAq/btq6qhhKYrU/QY2XCeeSWUbZ9fRCxpR2e0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmIMAq%2Fbtq6qhhKYrU%2FQY2XCeeSWUbZ9fRCxpR2e0%2Fimg.png&quot; width=&quot;802&quot; height=&quot;549&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;1096&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;프로세스의 가상 메모리를 관리하는 자료구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그램을 실행하면, 커널은 task_struct 구조체를 생성해서 프로세스에 필요한 정보를 초기화한 뒤 커널 자료구조에 이를 추가&lt;/li&gt;
&lt;li&gt;프로세스가 사용할 가상 주소공간은 메모리 매핑 과정에서 초기화되며, 크게 3개의 영역으로 나눌 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;로드된 프로그램의 이미지&lt;/b&gt; &lt;span style=&quot;color: #000000;&quot;&gt;실행 코드 및 데이터, 그리고 가상 메모리에 로드하기 위해 필요한 모든 정보&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공유 라이브러리&lt;/b&gt;&amp;nbsp;표준&amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;파일 연산과 같이 공통적으로 쓰이는 코드의 라이브러리를 사용&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;공유하고 있는 모든 프로세스의 가상 메모리에는, 물리 메모리에 있는 이 라이브러리와 연결된, 가상 페이지가 존재&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가상 메모리 추가 할당&lt;/b&gt; &lt;span style=&quot;color: #000000;&quot;&gt;읽고 있는 파일의 내용을 담기 위하여 등 새로 할당된 가상 메모리를 프로세스의 가상 메모리와 연결&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://movefast.tistory.com/341&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;메모리 매핑으로 가상 주소공간이 생성되면, 프로세스가 접근하는 부분만 실제로 물리 메모리에 로드(요구 페이징)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;커널은 프로세스의 코드와 데이터를 곧바로 실제 메모리에 로드하는 대신, 프로세스의 페이지 테이블을 수정하여 가상 영역에는 존재하고 있지만 실제로는 메모리에 있지는 않다고 표시&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;요구 페이징에 의해 페이지 폴트가 발생하면, 프로세스는 폴트가 발생한 가상 주소와 폴트의 원인은 커널에게 통보하고, 커널은 페이지 폴트 핸들러를 호출&lt;/span&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;유효한 가상 주소인데 빈 물리 페이지가 없다면, 페이지 교체를 위한 스와핑&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;유효한 가상주소인데 빈 물리 페이지가 있다면, 물리 메모리에 로드&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;유효하지 않은 가상 주소이면 세그멘테이션 폴트 시그널을 프로세스에 전달 (프로세스는 이를 처리하는 핸들러가 정의되어 있지 않으면 기본 동작으로 종료함)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;CPU는 페이지 폴트가 발생한 명령어부터 프로세스를 다시 실행&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;하나의 가상 페이지는 하나의 vm_area_struct 구조체에 대응되며, 이 구조체의 리스트를 mm_struct 구조체가 참조하는데, 커널은 task_struct 구조체에서 mm_struct 구조체의 포인터를 이용해 프로세스의 가상 메모리를 관리&lt;/li&gt;
&lt;li&gt;mm_struct 구조체는 페이지 테이블에 대한 포인터와 로드된 프로그램의 실행 이미지를 가리키는 포인터를 별도로 가지고 있음&lt;/li&gt;
&lt;li&gt;커널은 프로세스의 &lt;u&gt;가상 메모리에 대한 연산을 vm_area_struct 에 있는 vm_ops 가 참조하는 루틴을 실행시켜 처리&lt;/u&gt;하는데, 페이지 폴트, 스와핑 등이 있으며, 이러한 인터페이스 추상화는 하드웨어 장치 종류와 무관하게 가상 메모리를 일관성있게 처리함&lt;/li&gt;
&lt;li&gt;vm_area_struct 구조체의 리스트는 빈번한 탐색 과정에서 시간 복잡도를 줄이기 위해 &lt;a href=&quot;https://en.wikipedia.org/wiki/AVL_tree&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AVL 트리&lt;/a&gt;로 구현되었음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;왼쪽 포인터가 가리키는 노드는 더 낮은 가상 주소를 가지며, 오른쪽 포인터가 가리키는 노드는 더 높은 가상 주소를 가짐&lt;/li&gt;
&lt;li&gt;AVL 트리는 균형 이진 트리로, 삽입/삭제 시 어떤 두 서브트리의 높이차도 1을 넘지 않도록 추가적인 처리(트리 회전)가 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;259&quot; height=&quot;146&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;180&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tkO0z/btq6pVfa2ML/Bkar0AM5pqSsmL8yuip5OK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tkO0z/btq6pVfa2ML/Bkar0AM5pqSsmL8yuip5OK/img.gif&quot; data-alt=&quot;https://en.wikipedia.org/wiki/AVL_tree&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tkO0z/btq6pVfa2ML/Bkar0AM5pqSsmL8yuip5OK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/tkO0z/btq6pVfa2ML/Bkar0AM5pqSsmL8yuip5OK/img.gif&quot; width=&quot;259&quot; height=&quot;146&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;180&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://en.wikipedia.org/wiki/AVL_tree&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가상 메모리를 추가로 할당할 때, 커널은 먼저 vm_area_struct 구조체를 생성한 뒤 mm_struct 에 있는 mmap 포인터가 참조하는 리스트에 생성한 것을 추가하며, 이후 해당 공간에서 작업(읽기/쓰기/실행)하게 되면 페이지 폴트가 발생하고 커널은 해당 페이지를 물리 메모리에 로드한 후 페이지 테이블을 갱신한 뒤 프로세스를 재개&lt;/li&gt;
&lt;li&gt;로드된 프로그램의 실행 이미지는 초기화된 데이터, 초기화되지 않은 데이터, 텍스트(코드) 영역을 포함, 별도로 프로세스가 실행 중 데이터를 보관하기 위해 힙과 스택이 할당됨. 힙과 스택은 서로 마주보고 증가하며 스택은 높은 주소에서 낮은 주소로 증가&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;926&quot; width=&quot;419&quot; height=&quot;387&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Gm0da/btq6qTnog3W/WCQtnTusoH7mo6Hur05ms0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Gm0da/btq6qTnog3W/WCQtnTusoH7mo6Hur05ms0/img.png&quot; data-alt=&quot;https://slidetodoc.com/carnegie-mellon-processes-slides-adapted-from-randy-bryant/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Gm0da/btq6qTnog3W/WCQtnTusoH7mo6Hur05ms0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGm0da%2Fbtq6qTnog3W%2FWCQtnTusoH7mo6Hur05ms0%2Fimg.png&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;926&quot; width=&quot;419&quot; height=&quot;387&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://slidetodoc.com/carnegie-mellon-processes-slides-adapted-from-randy-bryant/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;621&quot; height=&quot;564&quot; data-origin-width=&quot;587&quot; data-origin-height=&quot;533&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I83Px/btq6oDeO67X/yrstpl0jZQWie3ilw1FyKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I83Px/btq6oDeO67X/yrstpl0jZQWie3ilw1FyKk/img.png&quot; data-alt=&quot;https://stackoverflow.com/questions/7746238/a-processs-files-the-relation-between-files-in-mm-struct-and-files-struct&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I83Px/btq6oDeO67X/yrstpl0jZQWie3ilw1FyKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI83Px%2Fbtq6oDeO67X%2Fyrstpl0jZQWie3ilw1FyKk%2Fimg.png&quot; width=&quot;621&quot; height=&quot;564&quot; data-origin-width=&quot;587&quot; data-origin-height=&quot;533&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://stackoverflow.com/questions/7746238/a-processs-files-the-relation-between-files-in-mm-struct-and-files-struct&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;쓰레드&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;619&quot; height=&quot;452&quot; data-origin-width=&quot;1409&quot; data-origin-height=&quot;1028&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/djkNYg/btq6oB9fbhC/2sQ6aa3rvhukOKTkRfSrX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/djkNYg/btq6oB9fbhC/2sQ6aa3rvhukOKTkRfSrX0/img.png&quot; data-alt=&quot;https://www.researchgate.net/figure/Linux-task-struct-structure-with-PCX-fields_fig21_308737624&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/djkNYg/btq6oB9fbhC/2sQ6aa3rvhukOKTkRfSrX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdjkNYg%2Fbtq6oB9fbhC%2F2sQ6aa3rvhukOKTkRfSrX0%2Fimg.png&quot; width=&quot;619&quot; height=&quot;452&quot; data-origin-width=&quot;1409&quot; data-origin-height=&quot;1028&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.researchgate.net/figure/Linux-task-struct-structure-with-PCX-fields_fig21_308737624&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스는 실행중인 프로그램으로, 운영체제에서 작업의 단위이며, &lt;b&gt;쓰레드(Thread)&lt;/b&gt;는 &lt;b&gt;프로세스에서 작업을 수행하는 흐름&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;프로세스는 생성과 동시에 단 하나의 쓰레드를 가지므로, 기본적으로 싱글 쓰레딩으로 작업을 처리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쓰레드 정보는 task_struct 구조체에서 thread_info 가 참조하는 자료구조에 저장됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프로세스는 쓰레드를 추가로 생성할 수 있으며, &lt;b&gt;멀티 쓰레딩(Multi-Threading)&lt;/b&gt;은 둘 이상의 쓰레드로 작업을 처리하는 것을 의미&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;228&quot; data-origin-height=&quot;308&quot; width=&quot;186&quot; height=&quot;251&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xHEC2/btq6p9K8IRy/SLJSnlKBt8hGte9P0V3T5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xHEC2/btq6p9K8IRy/SLJSnlKBt8hGte9P0V3T5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xHEC2/btq6p9K8IRy/SLJSnlKBt8hGte9P0V3T5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxHEC2%2Fbtq6p9K8IRy%2FSLJSnlKBt8hGte9P0V3T5K%2Fimg.png&quot; data-origin-width=&quot;228&quot; data-origin-height=&quot;308&quot; width=&quot;186&quot; height=&quot;251&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;544&quot; width=&quot;485&quot; height=&quot;452&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0uNam/btq6ud6zT9Q/KnMWsaQzH1Ojfll2B6QmLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0uNam/btq6ud6zT9Q/KnMWsaQzH1Ojfll2B6QmLK/img.png&quot; data-alt=&quot;https://slidetodoc.com/carnegie-mellon-threads-some-of-the-slides-are/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0uNam/btq6ud6zT9Q/KnMWsaQzH1Ojfll2B6QmLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0uNam%2Fbtq6ud6zT9Q%2FKnMWsaQzH1Ojfll2B6QmLK%2Fimg.png&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;544&quot; width=&quot;485&quot; height=&quot;452&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://slidetodoc.com/carnegie-mellon-threads-some-of-the-slides-are/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 쓰레드는 별도의 스택과 레지스터 정보를 가지며, 이를 제외한 프로세스의 메모리 공간을 모든 쓰레드가 공유
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://modoocode.com/270&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;둘 이상의 쓰레드가 같은 메모리 영역에 접근할 때, 접근하는 순서에 따라 결과가 달라지는 문제(경쟁 조건, race condition)가 발생한다면, 이 영역을 임계 영역(critical section)으로 보고, 단일 쓰레드만이 접근할 수 있도록 락(lock)을 걸어야 함&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;락 변수로는 뮤텍스(mutex)가 있는데, 락을 점유한 쓰레드가 락을 해제하기 까지 임계 영역이 되며, 그 락을 원하는 다른 쓰레드는 모두 대기 상태가 됨. 락을 해제하는 순간 임의의 쓰레드가 접근하게 됨&lt;/li&gt;
&lt;li&gt;예를 들어, 어떤 쓰레드는 읽기를 하고 어떤 쓰레드는 쓰기를 할 때, 쓰기가 원자적으로 끝나기 전에 읽는 상황이 발생할 수 있는데 락 변수를 사용해서 완전히 쓰기가 끝나기 까지 어떤 쓰레드도 읽지 못하도록 할 수 있음&lt;/li&gt;
&lt;li&gt;락 변수를 사용할 때는 데드락(deadlock)에 주의해야 하는데, 데드락 문제는 락을 점유하려하는 모든 프로세스나 쓰레드가 대기 상태에 있는 것이며, 락을 점유한 쓰레드가 비정상 종료되어 락이 해제되지 않거나, 락 변수를 둘 이상 사용했을 때 락을 점유하는 순서가 두 쓰레드가 엇갈리는 경우 주로 발생함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쓰레드1은 어떤 임계 영역에 락 변수를 M1 -&amp;gt; M2 순서로 점유하려 하는데, 동시에 쓰레드2가 M2 -&amp;gt; M1 순서로 점유하게 된다면 데드락이 발생함&lt;/li&gt;
&lt;li&gt;락 변수를 사용할 때 주의하거나 위와 같은 상황에 한 쪽에서 락을 양보할 수 있도록 구현해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;248&quot; data-origin-height=&quot;306&quot; width=&quot;215&quot; height=&quot;265&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CHOve/btq6p0m5w3y/0O6X1m6KYFlkymEzTjnBaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CHOve/btq6p0m5w3y/0O6X1m6KYFlkymEzTjnBaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CHOve/btq6p0m5w3y/0O6X1m6KYFlkymEzTjnBaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCHOve%2Fbtq6p0m5w3y%2F0O6X1m6KYFlkymEzTjnBaK%2Fimg.png&quot; data-origin-width=&quot;248&quot; data-origin-height=&quot;306&quot; width=&quot;215&quot; height=&quot;265&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쓰레드도 CPU가 프로그램 카운터에 따라 명령어를 실행하는 구조이기 때문에 여러 쓰레드를 번갈아 실행하는 것을 문맥 교환(Context Switching)이라고 하며, 프로세스의 문맥 교환이 가상 메모리를 저장하고 복구해야 하는 반면, 쓰레드의 문맥 교환은 사전에 작업했던 정보가 상대적으로 적어 비용이 적게 듬
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;PCB(Process Control Block)&lt;/b&gt; 프로세스의 작업 상태를 저장하는 커널 메모리 공간&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TCB(Thread Control Block)&lt;/b&gt; 쓰레드의 작업 상태를 저장하는 커널 메모리 공간&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;554&quot; data-origin-height=&quot;438&quot; width=&quot;370&quot; height=&quot;293&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byNIq6/btq6qnJaH4E/9ljwGLQ9IU0YPx6dql70Kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byNIq6/btq6qnJaH4E/9ljwGLQ9IU0YPx6dql70Kk/img.png&quot; data-alt=&quot;https://slidetodoc.com/carnegie-mellon-threads-some-of-the-slides-are/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byNIq6/btq6qnJaH4E/9ljwGLQ9IU0YPx6dql70Kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyNIq6%2Fbtq6qnJaH4E%2F9ljwGLQ9IU0YPx6dql70Kk%2Fimg.png&quot; data-origin-width=&quot;554&quot; data-origin-height=&quot;438&quot; width=&quot;370&quot; height=&quot;293&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://slidetodoc.com/carnegie-mellon-threads-some-of-the-slides-are/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스케줄링&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리눅스에서는 선점형(preemptive)과 비선점형(non-preemptive) 스케줄링을 모두 지원&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모든 프로세스는 타임 슬라이스(time slice) 단위로 CPU 시간을 할당받으며, 현재 실행중인 프로세스는 그 시간동안 어떤 다른 프로세스에 의해 선점되지 않음(non-preemptive). 그 시간이 끝나면 CPU는 실행 가능한 프로세스들 중 가치 있는 것을 선택해 실행(preemptive)하고 해당 프로세스는 차례가 올 때까지 대기 큐에 추가되어 대기&lt;/b&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/라운드_로빈_스케줄링&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;라운드 로빈 스케줄링&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;선점형과 비선점형을 혼합해서 사용하는 이유: 프로세스는 시스템 콜을 호출해서 자원을 요청하게 되는데, 결과를 받기까지 대기 상태가 되고, 이런 시간이 길어질수록 CPU 시간을 낭비하기 때문에, 공정하게 CPU 시간을 분할하여 그 시간이 만료되면 다른 프로세스가 실행되게 한 것 (CPU 사용의 극대화)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;정해진 시간 동안 프로세스가 CPU를 내놓을 수는 있음. &lt;span style=&quot;color: #000000;&quot;&gt;schedule(), sleep_on(), interruptible_sleep_on() 등의 함수를 부르지 않으면&lt;/span&gt;&amp;nbsp;시스템 콜이 다른 프로세스에 의해 중단되지 않음&lt;/li&gt;
&lt;li&gt;가치 있는 프로세스를 골라 실행하는 일은 스케줄러(schedular)가 수행하는데, 공정하게 CPU 시간을 할당하기 위해 task_struct 구조체에 있는 각 프로세스에 대한 정보를 이용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;policy&lt;/b&gt;&amp;nbsp;그 프로세스에 적용될 스케줄링 정책&lt;/li&gt;
&lt;li&gt;&lt;b&gt;priority&lt;/b&gt;&amp;nbsp;프로세스가 스케줄링될 때 우선순위, 프로세스가 실행될 수 있는 시간(jiffies 단위)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;rt_priority&lt;/b&gt;&amp;nbsp;실시간 프로세스들간의 상대적 우선순위&lt;/li&gt;
&lt;li&gt;&lt;b&gt;counter&lt;/b&gt;&amp;nbsp;프로세스가 실행될 수 있는 시간으로, 처음 실행될 때 priority 값으로 설정되며, 클럭 틱에 따라 감소&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;실시간 프로세스는 일반 프로세스보다 우선순위가 높기 때문에, 스케줄링 정책을 라운드 로빈과 FIFO 방식 중 하나를 선택할 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;라운드 로빈 스케줄링으로 할 경우, 정해진 시간 만큼만 실행되는 것이고, 자신의 차례가 올 때 까지 대기한 후 실행됨&lt;/li&gt;
&lt;li&gt;FIFO 스케줄링으로 할 경우, 실시간 프로세스들만 있는 대기 큐에 삽입되어 자신의 차례가 올 때까지 대기한 후 실행됨&lt;/li&gt;
&lt;li&gt;일반 프로세스와 실시간 프로세스 둘 다 실행 대기중이라면, 실시간 프로세스가 항상 먼저 실행됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;스케줄러가 실행되는 상황
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 프로세스를 대기 큐에 넣은 직후&lt;/li&gt;
&lt;li&gt;시스템 콜이 끝난 직후&lt;/li&gt;
&lt;li&gt;프로세스가 커널 모드에서 유저 모드로 바뀌기 직전&lt;/li&gt;
&lt;li&gt;시스템의 타이머가 현재 프로세스의 counter를 0으로 설정한 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커널 작업(kernel work)&lt;/b&gt;&amp;nbsp;인터럽트가 발생하면, 인터럽트 모드가 지속되는 동안 다른 인터럽트를 받지 않기 때문에 오래 걸리지만 나중에 해도 되는 작업을 하반부 핸들러(bottom half handler)나 작업 큐(task queue)에 추가해서 인터럽트 핸들링 이후 스케줄러에 의해 루틴이 실행되도록 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;462&quot; height=&quot;101&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;105&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cn8Vn0/btq6p0VjUik/7TKXnUUrvUhbG9DcMaqSWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cn8Vn0/btq6p0VjUik/7TKXnUUrvUhbG9DcMaqSWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cn8Vn0/btq6p0VjUik/7TKXnUUrvUhbG9DcMaqSWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcn8Vn0%2Fbtq6p0VjUik%2F7TKXnUUrvUhbG9DcMaqSWK%2Fimg.png&quot; width=&quot;462&quot; height=&quot;101&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;105&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;현재 프로세스는 다른 프로세스가 선택되기전에 다음과 같이 처리되어야 함&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 현재 프로세스가 라운드 로빈 정책이면, 현재 프로세스는 실행 큐에 추가됨&lt;/li&gt;
&lt;li&gt;만약 인터럽트 허용 상태인데 이전 스케줄링 후에 시그널을 받은 경우, 실행중 상태로 변경&lt;/li&gt;
&lt;li&gt;만약 정해진 시간이 만료되었다면, 실행중 상태로 변경&lt;/li&gt;
&lt;li&gt;이미 실행중 상태이면 그대로 유지&lt;/li&gt;
&lt;li&gt;실행 큐에서 실행중이거나 인터럽트 허용이 아닌 프로세스들을 제거 (다음 스케줄링에서 제외한다는 의미)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실행 큐에 있는 프로세스들 중 수행할 프로세스를 탐색 (실시간 프로세스는 일반 프로세스보다 높은 가중치를 가짐)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;보통 프로세스의 가중치는 counter 값이지만, 실시간 프로세스는 counter + 1000 을 가중치로 가짐&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;주어진 타임 슬라이스를 어느 정도 소모한 (즉 counter값이 감소한) 현재 프로세스는 시스템의 같은 우선순위를 가진 다른 프로세스들보다 불리함&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;여러 프로세스가 동일한 우선순위를 가지면, 실행 큐에서 앞에 위치한 프로세스를 선택 (현재 프로세스는 실행 큐에 추가됨)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;마지막으로 수행할 프로세스가 현재 프로세스가 아니면, 프로세스를 교체(swap)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 프로세스를 중단할 때, 프로그램 카운터와 같은 레지스터 정보 등의 모든 기계적인 상태를 task_struct에 저장&lt;/li&gt;
&lt;li&gt;실행될 프로세스의 모든 기계적인 상태를 복구하는데, CPU 레지스터 등 바뀌는데 하드웨어의 도움이 필요&lt;/li&gt;
&lt;li&gt;교체할 두 프로세스들의 메모리에 더티 페이지가 있으면 페이지 테이블 엔트리를 갱신해주어야 하는데, 이는 아키텍처마다 다름&lt;/li&gt;
&lt;li&gt;TLB를 사용하는 프로세서의 경우, 현재 프로세스에 속하는 캐시된 페이지 테이블 엔트리들을 모두 제거&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;멀티프로세서 시스템에서는 각 CPU별로 현재 프로세스와 idle 프로세스를 관리(CPU마다 하나의 idle 프로세스가 존재)해야 하며, 각 프로세스의 task_struct 구조체에는 자신이 현재 실행되고 있는 프로세서 번호(processor)와 마지막으로 실행되었던 프로세서 번호(last_processor)가 저장되어 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리눅스는 task_struct 구조체에 있는 processor_mask 를 이용하여 각 프로세스를 특정 CPU에서만 (혹은 여러 개) 실행되도록 제한할 수 있음. 예를 들어, 비트 N이 켜져 있으면 N번째 CPU 에서만 실행하는 것&lt;/li&gt;
&lt;li&gt;이는 이전 실행과 현재 실행이 다른 프로세서에서 이루어질 때 성능상의 오버헤드를 줄이기 위한 것으로,&amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;스케줄러가 실행할 새로운 프로세스를 고를 때 processor_mask에 현재 프로세서의 번호가 설정되어 있지 않은 프로세스는 고려하지 않음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; srcset=&quot;https://www.itrelease.com/wp-content/uploads/2020/06/Multiprocessor-System.png 596w, https://www.itrelease.com/wp-content/uploads/2020/06/Multiprocessor-System-300x225.png 300w, https://www.itrelease.com/wp-content/uploads/2020/06/Multiprocessor-System-200x150.png 200w, https://www.itrelease.com/wp-content/uploads/2020/06/Multiprocessor-System-360x270.png 360w, https://www.itrelease.com/wp-content/uploads/2020/06/Multiprocessor-System-545x409.png 545w&quot; width=&quot;596&quot; height=&quot;447&quot; data-origin-width=&quot;748&quot; data-origin-height=&quot;561&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oFuej/btq6oCU62xb/j5EYBeQ4Nk3hiBRNJZmbN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oFuej/btq6oCU62xb/j5EYBeQ4Nk3hiBRNJZmbN1/img.png&quot; data-alt=&quot;https://www.itrelease.com/2020/06/advantages-and-disadvantages-of-multiprocessor-systems/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oFuej/btq6oCU62xb/j5EYBeQ4Nk3hiBRNJZmbN1/img.png&quot; srcset=&quot;https://www.itrelease.com/wp-content/uploads/2020/06/Multiprocessor-System.png 596w, https://www.itrelease.com/wp-content/uploads/2020/06/Multiprocessor-System-300x225.png 300w, https://www.itrelease.com/wp-content/uploads/2020/06/Multiprocessor-System-200x150.png 200w, https://www.itrelease.com/wp-content/uploads/2020/06/Multiprocessor-System-360x270.png 360w, https://www.itrelease.com/wp-content/uploads/2020/06/Multiprocessor-System-545x409.png 545w&quot; width=&quot;596&quot; height=&quot;447&quot; data-origin-width=&quot;748&quot; data-origin-height=&quot;561&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.itrelease.com/2020/06/advantages-and-disadvantages-of-multiprocessor-systems/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로세스의 생성&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시스템이 처음 시작될 때 커널 모드에 있으며, 단 하나의 프로세스만 존재하는데, 초기화의 마지막 단계에서 이 프로세스는 init 이라고 하는 커널 쓰레드를 시작한 후 아무 것도 하지 않는 루프(idle 프로세스)를 실행 (언제나 할 일이 없으면 idle 프로세스가 실행됨)&lt;/li&gt;
&lt;li&gt;다른 프로세스들이 생성되면 모두 초기 프로세스의 task_struct 구조체에 저장되며, 지금까지 설명한 프로세스는 사실상 초기 프로세스의 init 커널 쓰레드에서 파생된 것으로 init 커널 쓰레드를 init 프로세스라고도 함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;init 커널 쓰레드(또는 프로세스)&lt;/b&gt;는 시스템의 첫번째 프로세스(PID=1)로, 시스템 초기화의 일부를 담당하며 &amp;nbsp;시스템 콘솔을 열고 루트 파일 시스템을 마운트 하는 등의 초기화 프로그램들을 실행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;새 프로세스들은 이전 프로세스 또는 현재 프로세스를 복제한 것으로, 시스템 콜(fork 또는 clone)을 호출하여 커널 모드에서 수행&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새 프로세스가 생성되면 task_struct 구조체가 물리 메모리에 할당되고, 하나 이상의 물리 페이지가 새 프로세스의 (사용자와 커널) 스택으로 할당됨&lt;/li&gt;
&lt;li&gt;새 task_struct 구조체는 task 배열에 추가되고, &lt;u&gt;복제 대상이 된 프로세스의 task_struct 구조체 내용을 새 task_struct 구조체로 복사&lt;/u&gt;하는데, 처음에 mm_struct 구조체(프로세스의 가상 주소공간을 나타내는 자료구조)는 복사되지 않음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;u&gt;&lt;span style=&quot;color: #000000;&quot;&gt;즉, 새 프로세스의 task_struct 구조체는 mm_struct 에 대한 포인터를 가지는데 원래 프로세스의 구조체를 참조&lt;/span&gt;&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;이는 &lt;span style=&quot;color: #000000;&quot;&gt;프로세스를 복제할 때, 별도의 복사본을 사용하지 않고 자원(프로세스의 파일들, 시그널 핸들러, 가상 메모리 등)을 공유하려는 목적이며, mm_struct 구조체에 count 변수는 공유중인 프로세스의 개수를 나타내는데 0이 되면 메모리를 해제&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;새 프로세스는 새로운 식별자를 부여받고 동시에 복제 대상이 된 프로세스의 식별자를 부모 식별자로 갖게 됨&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;task_struct는 모두, 부모 프로세스, 형제(sibling, 부모가 같은 프로세스 들) 프로세스, 자신의 자식(child) 프로세스들에 대한 포인터를 가짐&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Copy-On-Write&lt;/b&gt;&amp;nbsp;프로세스를 복제한 뒤, 두 프로세스 중 하나가 가상 페이지에 쓰기 작업을 하면 해당 페이지를 복사
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;쓰기 가능한 영역이라도, 아직 수정되지 않은 영역은 두 프로세스 사이에서 공유되며 실행 코드와 같은 읽기 전용은 항상 공유&lt;/li&gt;
&lt;li&gt;처음에는 쓸 수 있는 영역들의 페이지 테이블 엔트리(PTE)는 읽기 전용으로 표시되며, vm_area_struct에서 copy-on-write으로 표시&lt;/li&gt;
&lt;li&gt;쓰기 작업이 일어나면 페이지 폴트가 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1436&quot; data-origin-height=&quot;896&quot; width=&quot;637&quot; height=&quot;398&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bumiNx/btq6vg966Tp/t1OTotgmnSJ5KH5iyXnyW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bumiNx/btq6vg966Tp/t1OTotgmnSJ5KH5iyXnyW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bumiNx/btq6vg966Tp/t1OTotgmnSJ5KH5iyXnyW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbumiNx%2Fbtq6vg966Tp%2Ft1OTotgmnSJ5KH5iyXnyW0%2Fimg.png&quot; data-origin-width=&quot;1436&quot; data-origin-height=&quot;896&quot; width=&quot;637&quot; height=&quot;398&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1402&quot; data-origin-height=&quot;886&quot; width=&quot;624&quot; height=&quot;394&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUKJ5h/btq6p9E6Jz1/XgULXoLV3kG5mBTVRrqKZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUKJ5h/btq6p9E6Jz1/XgULXoLV3kG5mBTVRrqKZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUKJ5h/btq6p9E6Jz1/XgULXoLV3kG5mBTVRrqKZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUKJ5h%2Fbtq6p9E6Jz1%2FXgULXoLV3kG5mBTVRrqKZ0%2Fimg.png&quot; data-origin-width=&quot;1402&quot; data-origin-height=&quot;886&quot; width=&quot;624&quot; height=&quot;394&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1442&quot; data-origin-height=&quot;876&quot; width=&quot;646&quot; height=&quot;393&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zjJlo/btq6pWzhuE8/5FADALQGD91kZCiKct1XtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zjJlo/btq6pWzhuE8/5FADALQGD91kZCiKct1XtK/img.png&quot; data-alt=&quot;https://slidetodoc.com/carnegie-mellon-memory-management-and-virtual-memory-some/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zjJlo/btq6pWzhuE8/5FADALQGD91kZCiKct1XtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzjJlo%2Fbtq6pWzhuE8%2F5FADALQGD91kZCiKct1XtK%2Fimg.png&quot; data-origin-width=&quot;1442&quot; data-origin-height=&quot;876&quot; width=&quot;646&quot; height=&quot;393&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://slidetodoc.com/carnegie-mellon-memory-management-and-virtual-memory-some/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로그램 실행&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리눅스에서&amp;nbsp;cd나 pwd 같은 적은 수의 내부에 직접 구현된 명령어들은 쉘(shell)이라는 명령어 해석기(command interpreter)에 의해 실행되는데, 쉘은 환경변수 PATH에서 저장된 프로세스의 찾기 경로(search path)에서 같은 이름을 가진 실행 이미지를 찾은 뒤, 이를 메모리에 로드하여 실행&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;쉘은 찾기 경로에 없는 프로그램도 실행할 수 있으며, 이를 위해 커널은 컴파일 과정에서 여러 이진 포맷을 리스트로 가지게 되는데, 이진 파일을 실행하면 각 이진 포맷을 하나씩 시도&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;654&quot; height=&quot;189&quot; data-origin-width=&quot;609&quot; data-origin-height=&quot;176&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c7Fl36/btq6vgvwGJu/KWVU4HzzkBI9wqY6tLJON0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c7Fl36/btq6vgvwGJu/KWVU4HzzkBI9wqY6tLJON0/img.png&quot; data-alt=&quot;이진 포맷 리스트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c7Fl36/btq6vgvwGJu/KWVU4HzzkBI9wqY6tLJON0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc7Fl36%2Fbtq6vgvwGJu%2FKWVU4HzzkBI9wqY6tLJON0%2Fimg.png&quot; width=&quot;654&quot; height=&quot;189&quot; data-origin-width=&quot;609&quot; data-origin-height=&quot;176&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이진 포맷 리스트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실행 파일은 (파이썬 또는 쉘 스크립트 같은) 스크립트 파일도 포함되며, 이 파일들은 처리할 수 있는 올바른 해석기를 이진 포맷 목록에서 탐색하여 실행 (요약: 인터프리터 탐색 --&amp;gt; 쉘이 자기 자신을 fork --&amp;gt; 인터프리터로 실행 이미지 교체)&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;쉘은 실행 이미지를 메모리에 로드하면, fork 메커니즘을 이용하여 자기자신을 복제한 뒤 쉘 이미지를 찾았던 실행 이미지로 교체&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실행 이미지 교체 시스템 콜은 exec 계열 명령어를 사용&lt;/li&gt;
&lt;li&gt;아무런 옵션이 없으면 쉘은 자식 프로세스가 종료될 때까지 기다림&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;567&quot; data-origin-height=&quot;411&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dErLWW/btq6pIHKpmc/kMAKdJSm35uUDh3OsJZKwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dErLWW/btq6pIHKpmc/kMAKdJSm35uUDh3OsJZKwK/img.png&quot; data-alt=&quot;https://www.bogotobogo.com/Linux/linux_process_and_signals.php&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dErLWW/btq6pIHKpmc/kMAKdJSm35uUDh3OsJZKwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdErLWW%2Fbtq6pIHKpmc%2FkMAKdJSm35uUDh3OsJZKwK%2Fimg.png&quot; data-origin-width=&quot;567&quot; data-origin-height=&quot;411&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.bogotobogo.com/Linux/linux_process_and_signals.php&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; srcset=&quot;https://eyelublog.files.wordpress.com/2013/03/screen-shot-2013-03-17-at-9-35-59-pm.png 624w, https://eyelublog.files.wordpress.com/2013/03/screen-shot-2013-03-17-at-9-35-59-pm.png?w=111 111w, https://eyelublog.files.wordpress.com/2013/03/screen-shot-2013-03-17-at-9-35-59-pm.png?w=223 223w&quot; data-attachment-id=&quot;472&quot; data-permalink=&quot;https://eyelublog.wordpress.com/2013/03/17/the-linux-programming-interface-%e7%ac%94%e8%ae%b0-%e5%85%ad/screen-shot-2013-03-17-at-9-35-59-pm/&quot; data-orig-file=&quot;https://eyelublog.files.wordpress.com/2013/03/screen-shot-2013-03-17-at-9-35-59-pm.png&quot; data-orig-size=&quot;624,840&quot; data-comments-opened=&quot;1&quot; data-image-meta=&quot;{&quot; data-image-title=&quot;Screen Shot 2013-03-17 at 9.35.59 PM&quot; data-medium-file=&quot;https://eyelublog.files.wordpress.com/2013/03/screen-shot-2013-03-17-at-9-35-59-pm.png?w=223&quot; data-large-file=&quot;https://eyelublog.files.wordpress.com/2013/03/screen-shot-2013-03-17-at-9-35-59-pm.png?w=624&quot; data-origin-width=&quot;748&quot; data-origin-height=&quot;1006&quot; width=&quot;552&quot; height=&quot;743&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/H63Rg/btq6pUOZd2C/v7rzznj0dz3K8jIqNm0Zs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/H63Rg/btq6pUOZd2C/v7rzznj0dz3K8jIqNm0Zs0/img.png&quot; data-alt=&quot;https://eyelublog.wordpress.com/2013/03/17/the-linux-programming-interface-笔记-六/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/H63Rg/btq6pUOZd2C/v7rzznj0dz3K8jIqNm0Zs0/img.png&quot; srcset=&quot;https://eyelublog.files.wordpress.com/2013/03/screen-shot-2013-03-17-at-9-35-59-pm.png 624w, https://eyelublog.files.wordpress.com/2013/03/screen-shot-2013-03-17-at-9-35-59-pm.png?w=111 111w, https://eyelublog.files.wordpress.com/2013/03/screen-shot-2013-03-17-at-9-35-59-pm.png?w=223 223w&quot; data-attachment-id=&quot;472&quot; data-permalink=&quot;https://eyelublog.wordpress.com/2013/03/17/the-linux-programming-interface-%e7%ac%94%e8%ae%b0-%e5%85%ad/screen-shot-2013-03-17-at-9-35-59-pm/&quot; data-orig-file=&quot;https://eyelublog.files.wordpress.com/2013/03/screen-shot-2013-03-17-at-9-35-59-pm.png&quot; data-orig-size=&quot;624,840&quot; data-comments-opened=&quot;1&quot; data-image-meta=&quot;{&quot; data-image-title=&quot;Screen Shot 2013-03-17 at 9.35.59 PM&quot; data-medium-file=&quot;https://eyelublog.files.wordpress.com/2013/03/screen-shot-2013-03-17-at-9-35-59-pm.png?w=223&quot; data-large-file=&quot;https://eyelublog.files.wordpress.com/2013/03/screen-shot-2013-03-17-at-9-35-59-pm.png?w=624&quot; data-origin-width=&quot;748&quot; data-origin-height=&quot;1006&quot; width=&quot;552&quot; height=&quot;743&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://eyelublog.wordpress.com/2013/03/17/the-linux-programming-interface-笔记-六/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쉘은 자식 프로세스를 생성하면 포그라운드(foreground) 프로세스로 실행되기 때문에 자식 프로세스가 사용자와 대화식으로 작업하게 되어 쉘과 작업할 수 없다는 문제가 생김. 자식 프로세스를 백그라운드(background)로 돌리게 되면, 프로세스가 시작되서 종료될 때까지 쉘은 어떤 영향도 받지 않음 (터미널에 입출력하는 게 있다면 단말 입출력이 공유될 수 있음, e.g., 명령어 입력 중에 출력)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쉘에서 자식 프로세스를 생성한 후 Ctrl + Z 를 누르면 쉘은 자식 프로세스에게 SIGSTOP 시그널을 보내서 자식 프로세스가 suspend 상태가 되게 하는데, 쉘에서 bg 명령어를 실행하면 SIGCONT 시그널을 보내 자식 프로세스가 백그라운드(background)에서 실행됨&lt;/li&gt;
&lt;li&gt;쉘에서 작업 후 fg 명령어를 실행하면&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;nbsp;포그라운드로 돌림&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;쉘에서 명령어를 실행할 때 맨 뒤에 &amp;amp; 를 붙이면 자동으로 백그라운드로 실행시켜줌&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Executable and Linkable Format, ELF&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1208&quot; data-origin-height=&quot;900&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8caxO/btq6uEjoS02/GyskQT3aDcy3ddARUxGNy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8caxO/btq6uEjoS02/GyskQT3aDcy3ddARUxGNy1/img.png&quot; data-alt=&quot;일반적으로 리눅스에서 지원하는 이진 포맷은 .out 확장자와 ELF 바이너리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8caxO/btq6uEjoS02/GyskQT3aDcy3ddARUxGNy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8caxO%2Fbtq6uEjoS02%2FGyskQT3aDcy3ddARUxGNy1%2Fimg.png&quot; data-origin-width=&quot;1208&quot; data-origin-height=&quot;900&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;일반적으로 리눅스에서 지원하는 이진 포맷은 .out 확장자와 ELF 바이너리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ELF 실행 파일(실행 이미지)은 텍스트라고 불리는 실행 코드와 데이터를 포함하며, 실행 이미지 안에 있는 테이블은 프로세스의 가상 메모리에 어떻게 프로그램 코드를 로드할 지를 기술 (바이너리 자체가 그대로 메모리에 로드되는 것이 아님)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://recipes.egloos.com/5011946&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;링크(link)는 정적 링크와 동적 링크로 나뉘며, 정적 링크된 실행 이미지는 링킹할 때 포함한 다른 실행 파일의 루틴들을 모두 하나의 파일에 합친 것이며, 동적 링크의 경우 실행 중에 공유 라이브러리 같은 이미 메모리에 있는 루틴들의 오프셋만 포함&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동적 라이브러리란 동적 링크된 실행 이미지가 사용하는 루틴들의 집합이며, 만약 커널 메모리 공간에 이 루틴들의 실행 코드가 적재되지 않았다면 세그멘테이션 폴트가 발생&lt;/li&gt;
&lt;li&gt;링커는 동적 라이브러리의 진입점(entry point)에서의 오프셋을 저장하며, 로더가 처음에 실행할 때 동적 라이브러리의 베이스 주소를 계산&lt;/li&gt;
&lt;li&gt;CPU가 동적 라이브러리의 함수에 점프하려고 할 때, 베이스 주소와 오프셋을 더해서 실제 메모리 주소를 계산&lt;/li&gt;
&lt;li&gt;링커(linker)는 리눅스에서 ld 명령어로 실행할 수 있으며, 인자로 넘긴 프로그램이 실행될 때 메모리에서의 배치도와 처음 수행할 코드의 메모리에서의 주소를 지정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;위 그림의 오른쪽은 ELF 실행 이미지이며, 2개의 물리적 헤더를 가짐
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;첫번째 물리적 헤더는 이미지에서 실행 코드를 기술
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이는&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 가상 주소 0x8048000에서 시작하고 65532 바이트를 가짐&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;정적 링크이므로, printf() 함수에 대한 라이브러리 코드를 모두 가짐&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이미지의 진입점(entry point), &lt;b&gt;즉 프로그램에서 처음 실행하는 명령은 이미지의 시작 주소가 아니라 가상 주소 0x8048090 (e_entry)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 코드는 두번째 물리적 헤더를 로드한 직후에 바로 시작&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;두번째 물리적 헤더는 프로그램에서의 데이터를 기술
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가상 메모리의 0x8059BB8 위치에 로드 (이 데이터는 읽거나 쓸 수 있음)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;파일에서 데이터의 크기는 2200바이트(p_filesz)인데 반해, 메모리에서의 &lt;span style=&quot;color: #000000;&quot;&gt;크기(p_memsz)는 4248바이트&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;처음 2200바이트는 미리 초기화된 데이터&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다음에 있는 2048바이트는 실행 코드가 초기화할 데이터(BSD, 초기화되지 않은 데이터)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ELF 실행 이미지를 메모리에 로드한다는 의미는, 프로세스의 vm_area_struct 리스트와 해당되는 페이지 테이블들을 셋업하는 과정이며, 이후 요구 페이징에 의해 페이지 폴트가 발생하면 프로그램의 코드와 데이터의 필요한 일부만 물리 메모리에 로드&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Operating System/Linux</category>
      <category>Copy On Write</category>
      <category>Linux Kernel</category>
      <category>Operating System</category>
      <category>Process</category>
      <category>thread</category>
      <category>가상 메모리</category>
      <category>리눅스 커널</category>
      <category>쓰레드</category>
      <category>운영체제</category>
      <category>프로세스</category>
      <author>r4v3n-k</author>
      <guid isPermaLink="true">https://movefast.tistory.com/343</guid>
      <comments>https://movefast.tistory.com/343#entry343comment</comments>
      <pubDate>Wed, 2 Jun 2021 20:58:09 +0900</pubDate>
    </item>
  </channel>
</rss>