• Mindscape ๐Ÿ”ฅ
    • Playlist ๐ŸŽง
  • Algorithm

    • 1018๋ฒˆ: ์ฒด์ŠคํŒ ๋‹ค์‹œ ์น ํ•˜๊ธฐ
    • 1966๋ฒˆ: ํ”„๋ฆฐํ„ฐ ํ
    • Python ์‹œ๊ฐ„ ์ดˆ๊ณผ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•œ ํŒ
    • C++ std::vector ์‚ฌ์šฉ๋ฒ• ์ •๋ฆฌ
    • Vim ์‚ฌ์šฉ ๋งค๋‰ด์–ผ
  • Ubuntu

    • ๋ฆฌ๋ˆ…์Šค ์šฐ๋ถ„ํˆฌ GRUB ํฐํŠธ ๋ณ€๊ฒฝ
    • ์šฐ๋ถ„ํˆฌ ์ด๋ฏธ์ง€ ๋น„๋””์˜ค ์ธ๋„ค์ผ(๋ฏธ๋ฆฌ๋ณด๊ธฐ) ์•ˆ ๋ณด์ž„ ๋ฌธ์ œ ํ•ด๊ฒฐ
    • Wine ํ™˜๊ฒฝ์—์„œ ์นด์นด์˜คํ†ก ์‹คํ–‰ ์‹œ explorer.exe ๋œจ์ง€ ์•Š๊ฒŒ ํ•˜๋Š” ๋ฒ•
    • ์šฐ๋ถ„ํˆฌ Wine ์นด์นด์˜คํ†ก ์‚ฌ์ง„ ์ด๋ฏธ์ง€ ์Šคํฌ๋ฆฐ์ƒท ๋ถ™์—ฌ๋„ฃ๊ธฐ
    • Wine ์นด์นด์˜คํ†ก ์ด๋ชจ์ง€ ๊นจ์ง ๋ฌธ์ œ ํ•ด๊ฒฐ
    • Ubuntu ์œˆ๋„์šฐ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋„๊ธฐ
  • Wellness

    • ์ฐจ์ „์žํ”ผ (Psyllium Husk)
    • ์—‘์ŠคํŠธ๋ผ ๋ฒ„์ง„ ์˜ฌ๋ฆฌ๋ธŒ์œ  (Extra Virgin Olive Oil)
    • ์ž๊ฐ€๋น„๊ฐ•์„ธ์ฒ™ (Nasal Irrigation)
    • QCY HT08 (MeloBuds Pro Plus)
    • ์ฝ˜์„œํƒ€ (Concerta)
    • ์ธ๋ฐ๋†€ (Inderal)
    • ์„คํŠธ๋ž„๋ฆฐ (Sertraline)
    • ๋ฉœ๋ผํ† ๋‹Œ (Melatonin)
    • ์น˜๊ฒฝ๋ถ€ ๋งˆ๋ชจ์ฆ
    • ๋ฐ”๋ฒจ ์Šค์ฟผํŠธ (Barbell Squat)
  • Humanities

    • Nordvik, Russia
    • North Sentinel Island
    • ๋กฑ๊ณ ๋กฑ๊ณ (Rongorongo)
    • ๋ฐ”๋กœํฌ ์Œ์•… (Baroque Music)
  • Design

    • ๊ตฌ๊ธ€์˜ ์•„์ด์ฝ˜ ๋Œ€๊ฐœํŽธ โ€” 6๋…„ ๋งŒ์˜ ์‹ค์ˆ˜ ์ธ์ •
    • ์ œ๋Ÿด๋“œ ์  ํƒ€ โ€” ๋Ÿญ์…”๋ฆฌ ์Šคํฌ์ธ  ์›Œ์น˜์˜ ์ฐฝ์‹œ์ž
    • ๋ฐ”์šฐํ•˜์šฐ์Šค โ€” ํ˜„๋Œ€ ๋””์ž์ธ์˜ ์›์ 
  • Brands

    • NOMOS Glashรผtte
    • Frรฉdรฉrique Constant
    • KZ (Knowledge Zenith)
    • ์—์ŠคํŠธ๋ผ (AESTURA)
    • JINHAO (้‡‘่ฑช)
    • Herman Miller
    • ๋ฐ์Šค์ปค (DESKER)
    • ๋ฌด์‹ ์‚ฌ ์Šคํƒ ๋‹ค๋“œ (Musinsa Standard)
  • Finance

    • ํ˜„๋Œ€์นด๋“œ ZERO โ€” Edition2 vs Edition3 ๋น„๊ต
    • ์‹ ํ•œ์นด๋“œ ์ฒ˜์Œ
    • S&P 500 ETF ํˆฌ์ž ๊ฐ€์ด๋“œ
    • ํŒŒํ‚นํ†ต์žฅ vs CMA ํ†ต์žฅ
    • ๋ฒ„ํฌ์…” ํ•ด์„œ์›จ์ด (Berkshire Hathaway)
    • ๋น„ํŠธ์ฝ”์ธ(Bitcoin)
  • Products

    • ์˜ค๋””์˜ค ์ธํ„ฐํŽ˜์ด์Šค (Audio Interface)
    • ์ฟ ๋ฃจํ† ๊ฐ€ (KURUTOGA)
    • CX31993 DAC ๋™๊ธ€
    • ํด๋ Œ์ง• ๋ฐ€ํฌ (Cleansing Milk)
    • ํ”ผ์ ฏ ํ† ์ด (Fidget Toy)
    • ThinkPad
  • Programming Languages

    • 8.0. Statement Level Control Structures
    • 8. Subprogram
    • 9. Implementing Subprogram
    • 10.1. Abstract Data Types and Encapsulation Constructs
    • 10.2. Support for Object Oriented Programming
    • 11. Concurrency
    • 12. FPL (1)
    • 13. FPL (2)
    • 14. Exception Handling and Event Handling
    • Final Exam

Project 3: Virtual Memory & File system - wiki

์ž‘์„ฑ 2026. 6. 12.ยท์ˆ˜์ • 2026. 6. 12.

1. Design

1.1. Project overview

์ด wiki๋Š” xv6-riscv ๊ธฐ๋ฐ˜ ์šด์˜์ฒด์ œ์— ๊ฐ€์ƒ ๋ฉ”๋ชจ๋ฆฌ์™€ ํŒŒ์ผ ์‹œ์Šคํ…œ ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•œ ๊ณผ์ •์„ ์ •๋ฆฌํ•œ๋‹ค.
๋ณธ Project์˜ ๋ชฉํ‘œ๋Š” ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจยท์ €์žฅ ์šฉ๋Ÿ‰ยทํŒŒ์ผ ์ฐธ์กฐ ์œ ์—ฐ์„ฑ์„ ๊ฐœ์„ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

  • copy-on-write(COW) fork
    • ๊ธฐ์กด xv6๋Š” fork ์‹œ ์‚ฌ์šฉ์ž ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ „๋ถ€ ๋ณต์‚ฌ โ†’ ๊ณผ๋„ํ•œ ๋ฉ”๋ชจ๋ฆฌ ์†Œ๋น„
    • ํ•ด๊ฒฐ: parent-child๊ฐ€ page๋ฅผ ๊ณต์œ ํ•˜๊ณ  ์ฒซ write ์‹œ์—๋งŒ ๋ณต์‚ฌ
  • large file support
    • ์ตœ๋Œ€ 268 KB ํ•œ๊ณ„(12 direct + 1 indirect)
    • ํ•ด๊ฒฐ: double-indirect ๋ ˆ์ด์•„์›ƒ ๋„์ž… โ†’ ์•ฝ 66 MB๊นŒ์ง€ ํŒŒ์ผ ์ƒ์„ฑยท์ ‘๊ทผ ๊ฐ€๋Šฅ
  • symbolic link
    • hard link๋งŒ ์ œ๊ณต, ๊ฒฝ๋กœ-๊ธฐ๋ฐ˜ ๋งํฌ๊ฐ€ ๋ถ€์žฌ
    • ํ•ด๊ฒฐ: UNIX-style symlink ๊ตฌํ˜„ + link-chain ํ•ด์„(๊นŠ์ด ์ œํ•œ 10๋‹จ๊ณ„)
๊ธฐ๋Šฅ๊ธฐ์กด ํ•œ๊ณ„ํ™•์žฅ ๋ชฉํ‘œ
Copy-on-Writefork ์‹œ ์ „์ฒด ๋ฉ”๋ชจ๋ฆฌ ๋ณต์‚ฌ๊ณต์œ  ํ›„ ์ฒซ write ๋•Œ๋งŒ ๋ณต์‚ฌ
Large file268 KB ์ตœ๋Œ€ ํฌ๊ธฐ66 MB ์ง€์›(double-indirect)
Symbolic linkhard link๋งŒ ์ง€์›๊ฒฝ๋กœ ๊ธฐ๋ฐ˜ symlink + loop ๋ฐฉ์ง€

๋ณธ ๊ตฌํ˜„์€ xv6์˜ ์›ํ˜• ๊ตฌ์กฐ๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•˜์˜€์œผ๋ฉฐ, ๊ฐ ๊ธฐ๋Šฅ๋ณ„ ํ…Œ์ŠคํŠธ ํ”„๋กœ๊ทธ๋žจ์„ ํ†ตํ•ด ์•ˆ์ •์„ฑ๊ณผ ์ •ํ™•์„ฑ์„ ํ™•์ธํ•˜์˜€๋‹ค.
์ด wiki๋Š” ํ…Œ์ŠคํŠธ ์„ค๋ช… โ†’ ๊ตฌํ˜„ ์„ธ๋ถ€ ์‚ฌํ•ญ โ†’ ๊ฒฐ๊ณผ ๋ฐ ๋ฌธ์ œ ํ•ด๊ฒฐ ์ˆœ์„œ๋กœ ์„œ์ˆ ํ•ด ์ตœ์ข… ์™„์„ฑ๋„๋ฅผ ์ž…์ฆํ•˜๊ฒŒ ๋œ๋‹ค.


1.2. Design principles and requirement strategy

1.2.1. On-demand page duplication

  • uvmcopy์—์„œ writable page์˜ PTE_W๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  PTE_COW๋ฅผ ์„ธํŒ…ํ•ด parent, child๊ฐ€ ๊ฐ™์€ physical page๋ฅผ read-only๋กœ ๊ณต์œ ํ•œ๋‹ค.
  • write fault๋Š” usertrap์—์„œ ๊ฐ์ง€ํ•˜๋ฉฐ, ref-count > 1์ด๋ฉด ์ƒˆ page๋ฅผ kalloc ํ›„ ๋ณต์‚ฌ, ref-count == 1์ด๋ฉด flag๋งŒ ๊ฐฑ์‹ ํ•ด write-enable ํ•œ๋‹ค.

1.2.2. Page reference accounting

  • ref_counts[PHYSTOP/PGSIZE] ์ „์—ญ ๋ฐฐ์—ด๋กœ ๋ชจ๋“  physical page ์‚ฌ์šฉ ๊ฐœ์ˆ˜๋ฅผ ์ถ”์ ํ•œ๋‹ค.
  • inc_ref / kfree๋กœ ์ฆ๊ฐ€ยท๊ฐ์†Œํ•˜๋ฉฐ 0์ผ ๋•Œ๋งŒ free list์— ๋ฐ˜ํ™˜ํ•ด leak์„ ๋ฐฉ์ง€ํ•œ๋‹ค.

1.2.3. TLB consistency on permission change

  • RISC-V์—๋Š” x86 CR0.WP๊ฐ€ ์—†์œผ๋ฏ€๋กœ, write-protect ํ›„ ๋ฐ˜๋“œ์‹œ sfence_vma๋ฅผ ํ˜ธ์ถœํ•ด ์‚ฌ์šฉ์ž TLB๋ฅผ flushํ•œ๋‹ค.

1.2.4. Double-indirect block layout

  • NDIRECT๋ฅผ 11๋กœ ์ค„์ด๊ณ  addrs[11] (single), addrs[12] (double) ๋‘ ํฌ์ธํ„ฐ๋ฅผ ์˜ˆ์•ฝํ•œ๋‹ค.
  • bmap๋Š” three-tier lookup (direct โ†’ single โ†’ double) ๋กœ์ง์„ ๊ฐ€์ง„๋‹ค.
  • MAXFILE = 11 + 256 + 256ยฒ ๊ณ„์‚ฐ์œผ๋กœ bigfile ํ…Œ์ŠคํŠธ(65 803 blocks)๋ฅผ ์ปค๋ฒ„ํ•œ๋‹ค.

1.2.5. Metadata integrity via write-ahead logging

  • indirect ํ…Œ์ด๋ธ”์„ ์ˆ˜์ •ํ•  ๋•Œ๋งˆ๋‹ค log_write(bp) ํ˜ธ์ถœ ํ›„ brelse(bp)๋กœ ํ•ด์ œํ•ด log ์ผ๊ด€์„ฑ์„ ๋ณด์žฅํ•œ๋‹ค.

1.2.6. Safe truncation path

  • itrunc๋Š” direct โ†’ single โ†’ double ์„ธ ๋‹จ๊ณ„์— ๋Œ€ํ•ด ์—ญ์ˆœ์œผ๋กœ bfree๋ฅผ ํ˜ธ์ถœํ•ด orphan block์„ ๋‚จ๊ธฐ์ง€ ์•Š๋Š”๋‹ค.

1.2.7. Path-level symbolic link

  • ์ƒˆ๋กœ์šด inode type T_SYMLINK์„ ์ถ”๊ฐ€ํ•˜๊ณ , link ํŒŒ์ผ์— target ๊ฒฝ๋กœ ๋ฌธ์ž์—ด์„ ์ €์žฅํ•œ๋‹ค.
  • sys_open์€ ์ตœ๋Œ€ MAX_SYMLINK_LOOPS (10) ๊นŠ์ด๊นŒ์ง€ ์žฌ๊ท€ ํ•ด์„ํ•˜๋ฉฐ, O_NOFOLLOW๊ฐ€ ์žˆ์œผ๋ฉด ๋งํฌ ์ž์ฒด๋ฅผ ์—ฐ๋‹ค.

1.2.8. Loop and broken-link defense

  • depth ์นด์šดํ„ฐ๋กœ ์ˆœํ™˜ ๋งํฌ๋ฅผ ์ฐจ๋‹จํ•˜๊ณ , target ๋ฏธ์กด์žฌ ์‹œ open ์‹คํŒจ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

1.2.9. Concurrency safety

  • symlink ์ƒ์„ฑยท์‚ญ์ œ๋Š” begin_op()/end_op() ํŠธ๋žœ์žญ์…˜ ๋‚ด๋ถ€์—์„œ inode lock์„ ๋๊นŒ์ง€ ์œ ์ง€ํ•ด race condition์„ ๋ฐฉ์ง€ํ•œ๋‹ค.

1.3. Design key summary

ElementImplementation strategy summary
Page sharinguvmcopy โ†’ PTE_COW flag + read-only
Fault handlingusertrap branch for scause==store fault
Ref countinc_ref, get_ref, kfree guard == 0
Double-indirect layoutaddrs[NDIRECT+2] + 3-level bmap
MAXFILE ๊ณ„์‚ฐ11 + 256 + 256ยฒ = 65 803 blocks
Log consistency๊ฐ level ๋ณ€๊ฒฝ ์งํ›„ log_write(bp)
Symlink syscallsys_symlink(target, path) + T_SYMLINK inode
Link resolutionsys_open loop, depth โ‰ค 10, O_NOFOLLOW support
Concurrencyinode lock + write-ahead log around link ops

์ด ์„ค๊ณ„์— ๋”ฐ๋ผ COW, large file, symbolic link ์„ธ ๊ธฐ๋Šฅ์„ ๊ธฐ์กด xv6 ์ฝ”๋“œ์™€ ํ˜ธํ™˜๋˜๋„๋ก ํ†ตํ•ฉํ–ˆ์œผ๋ฉฐ, ๊ฐ๊ฐ cowtest, bigfile, symlinktest๋ฅผ ์™„์ „ ํ†ต๊ณผํ•˜๊ณ  ๋ชฉํ‘œ ์š”๊ตฌ์‚ฌํ•ญ์„ ์ถฉ์กฑํ•˜๊ฒŒ ๋œ๋‹ค.

2. TEST ํŒŒ์ผ์— ๋Œ€ํ•œ ์„ค๋ช…

2.1. /user/cowtest.c

์ด ํ”„๋กœ๊ทธ๋žจ์€ copy-on-write fork ๊ธฐ๋Šฅ์„ ํ…Œ์ŠคํŠธํ•˜๋Š” user space ํ”„๋กœ๊ทธ๋žจ์ด๋‹ค.

์ฃผ์š” ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • simpletest
    ์ „์ฒด physical memory์˜ 2/3 ๊ฐ€๋Ÿ‰์„ sbrk๋กœ ํ• ๋‹นํ•˜๊ณ  fork๋ฅผ ์ˆ˜ํ–‰ํ•˜์—ฌ, parent์™€ child๊ฐ€ page๋ฅผ ๊ณต์œ ํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. copy-on-write์ด ๊ตฌํ˜„๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด fork ์‹คํŒจ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

  • threetest
    3๊ฐœ์˜ process๊ฐ€ ๊ฐ์ž COW page์— write๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉฐ ์‹ค์ œ๋กœ page๊ฐ€ copy๋˜๊ณ  free๋˜๋Š”์ง€๋ฅผ ํ™•์ธํ•œ๋‹ค. ๋‚ด์šฉ ๋ถˆ์ผ์น˜๋‚˜ memory leak์ด ์—†์–ด์•ผ ํ†ต๊ณผ๋œ๋‹ค.

  • filetest
    pipe์™€ fork๋ฅผ ํ†ตํ•ด copyout ๋™์ž‘ ์ค‘ page fault๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๋Š”์ง€๋ฅผ ๊ฒ€์ฆํ•œ๋‹ค. parent์˜ buf๊ฐ€ child์— ์˜ํ•ด ์˜ค์—ผ๋˜์ง€ ์•Š์•„์•ผ ์„ฑ๊ณต์ด๋‹ค.

uint64 phys_size = PHYSTOP - KERNBASE;
int sz = (phys_size / 3) * 2;
char *p = sbrk(sz);
int pid = fork();

์ด ํ…Œ์ŠคํŠธ๋“ค์€ fork์˜ ์„ฑ๋Šฅ ์ตœ์ ํ™”์™€ memory isolation์˜ ์ •ํ™•์„ฑ์„ ์ ๊ฒ€ํ•˜๋Š” ๋ฐ ํ•ต์‹ฌ์ ์ธ ์—ญํ• ์„ ํ•œ๋‹ค.


2.2. /user/bigfile.c

์ด ํ…Œ์ŠคํŠธ ํ”„๋กœ๊ทธ๋žจ์€ xv6 ํŒŒ์ผ system์—์„œ large file์„ ์ƒ์„ฑํ•˜๊ณ , ๋ฐ์ดํ„ฐ๋ฅผ block ๋‹จ์œ„๋กœ ์—ฐ์†์ ์œผ๋กœ ์“ฐ๊ณ  readํ•˜์—ฌ data integrity๋ฅผ ๊ฒ€์ฆํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

์ฃผ์š” ๋™์ž‘ ๊ณผ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • "big.file"์ด๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ file์„ O_CREATE | O_WRONLY flag๋ฅผ ์‚ฌ์šฉํ•ด openํ•˜๊ณ  write๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  • block ํฌ๊ธฐ(BSIZE)๋งŒํผ buf๋ฅผ ์ค€๋น„ํ•˜๊ณ , ๊ฐ block์— ๋ฒˆํ˜ธ๋ฅผ ๊ธฐ๋กํ•œ ํ›„ ๋ฐ˜๋ณต์ ์œผ๋กœ file์— ์“ด๋‹ค.
  • ์ด 65803๊ฐœ์˜ block์ด write๋˜์–ด์•ผ ํ•˜๋ฉฐ, ์ค‘๊ฐ„๋งˆ๋‹ค ์ง„ํ–‰ ์ƒํ™ฉ์„ ์ถœ๋ ฅํ•œ๋‹ค.
  • write ์™„๋ฃŒ ํ›„ file์„ closeํ•˜๊ณ  O_RDONLY flag๋กœ ๋‹ค์‹œ openํ•˜์—ฌ read๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ , ์ €์žฅ๋œ ๊ฐ’์ด block ๋ฒˆํ˜ธ์™€ ์ผ์น˜ํ•˜๋Š”์ง€ ๊ฒ€์ฆํ•œ๋‹ค.
  • ๋ชจ๋“  ๊ฒ€์‚ฌ๊ฐ€ ํ†ต๊ณผ๋˜๋ฉด ์„ฑ๊ณต ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•˜๊ณ  exitํ•œ๋‹ค.

์ด ํ…Œ์ŠคํŠธ๋Š” doubly-indirect block ๊ธฐ๋Šฅ์ด ์ ์šฉ๋œ file system์ด ์‹ค์ œ๋กœ large file์„ ์•ˆ์ •์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•˜๋Š” ๋ฐ ๋ชฉ์ ์ด ์žˆ๋‹ค.

fd = open("big.file", O_CREATE | O_WRONLY);
...
while(1){
  *(int*)buf = blocks;
  int cc = write(fd, buf, sizeof(buf));
  if(cc <= 0)
    break;
  blocks++;
}

2.3. /user/symlinktest.c

์ด ํ”„๋กœ๊ทธ๋žจ์€ symbolic link ๊ธฐ๋Šฅ์„ ๊ฒ€์ฆํ•˜๋Š” user space ํ…Œ์ŠคํŠธ ํ”„๋กœ๊ทธ๋žจ์ด๋‹ค.

์ฃผ์š” ํ…Œ์ŠคํŠธ ๊ตฌ์„ฑ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • testsymlink
    testsymlink ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ๋งŒ๋“ค๊ณ , file์„ ํ•˜๋‚˜ ์ƒ์„ฑํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  symlink system call์„ ์ด์šฉํ•ด ํ•ด๋‹น file์„ target์œผ๋กœ ํ•˜๋Š” link file์„ ์ƒ์„ฑํ•œ๋‹ค. ์ดํ›„ read ๋™์ž‘์ด ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ณ , link๊ฐ€ T_SYMLINK ํƒ€์ž…์œผ๋กœ ์ธ์‹๋˜๋Š”์ง€๋„ stat์œผ๋กœ ๊ฒ€์ฆํ•œ๋‹ค.
    ์ดํ›„ ์›๋ณธ file์„ unlinkํ•œ ๋’ค broken link์— ์ ‘๊ทผ์ด ์ฐจ๋‹จ๋˜๋Š”์ง€, ๋‹ค์‹œ ์›ํ˜• loop ๊ตฌ์กฐ๋ฅผ ๊ฐ–๋Š” link๋ฅผ ๋งŒ๋“ค์—ˆ์„ ๋•Œ open ์‹œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
    ๋งˆ์ง€๋ง‰์œผ๋กœ ์—ฌ๋Ÿฌ ๋‹จ๊ณ„์˜ link chain์„ ์ƒ์„ฑํ•œ ๋’ค, chain์˜ ์‹œ์ž‘์ ์„ ํ†ตํ•ด ๋ file์— ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ์ง€๋„ ๊ฒ€์‚ฌํ•œ๋‹ค.

  • concur
    ์—ฌ๋Ÿฌ process๊ฐ€ ๋™์‹œ์— symlink๋ฅผ ์ƒ์„ฑํ•˜๊ณ  unlink๋ฅผ ๋ฐ˜๋ณตํ•˜๋Š” ์ƒํ™ฉ์„ ๋งŒ๋“ค์–ด race condition์ด๋‚˜ consistency ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”์ง€ ๊ฒ€์ฆํ•œ๋‹ค. ๊ฐ process๋Š” ๋™์ผํ•œ target์— ๋Œ€ํ•ด ๋ฐ˜๋ณต์ ์œผ๋กœ symlink/unlink๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.

r = symlink("/testsymlink/a", "/testsymlink/b");
...
if(st.type != T_SYMLINK)
  fail("not a symlink");

์ด test๋Š” symbolic link์˜ ์ƒ์„ฑ, ์‚ญ์ œ, ๊ฒฝ๋กœ ํ•ด์„, cycle ์ฒ˜๋ฆฌ, broken link ๋ฐ ๋™์‹œ ์ ‘๊ทผ ๋ฌธ์ œ๋ฅผ ์ข…ํ•ฉ์ ์œผ๋กœ ๊ฒ€์ฆํ•˜๊ฒŒ ๋œ๋‹ค.

3. Implementation

3.1. Copy-on-Write fork ๊ตฌํ˜„

copy-on-write(COW)๋Š” parent์™€ child๊ฐ€ ๊ฐ™์€ physical page๋ฅผ ๊ณต์œ ํ•˜๋‹ค๊ฐ€ ์ฒ˜์Œ์œผ๋กœ write๋ฅผ ์‹œ๋„ํ•˜๋Š” ์ˆœ๊ฐ„์—๋งŒ page๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ„๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. ๊ตฌํ˜„์€ ์„ธ ๊ฐ€์ง€ ๋ถ€๋ถ„์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.

  1. fork ์‹œ ๊ณต์œ  page ์„ค์ •
  2. user mode write fault ์ฒ˜๋ฆฌ
  3. physical page reference count ๊ด€๋ฆฌ

3.1.1. uvmcopy์—์„œ ํŽ˜์ด์ง€ ๊ณต์œ  ์„ค์ •

uvmcopy๋Š” parent์˜ pagetable์„ ์ˆœํšŒํ•˜๋ฉด์„œ writable page๋ฅผ read-only๋กœ ๋ฐ”๊พธ๊ณ  PTE_COW flag๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค. ์ดํ›„ ๋™์ผํ•œ physical page๋ฅผ child pagetable์— ๋งคํ•‘ํ•˜๊ณ , ref count๋ฅผ ์ฆ๊ฐ€์‹œํ‚จ๋‹ค.

// kernel/vm.c
if(*pte & PTE_W){
  *pte &= ~PTE_W;     // read-only
  *pte |= PTE_COW;    // cow ํ‘œ์‹œ
  if(mappages(new, i, PGSIZE, pa, PTE_FLAGS(*pte)) != 0){
    *pte |= PTE_W;    // ์‹คํŒจ ์‹œ ๋ณต๊ตฌ
    *pte &= ~PTE_COW;
    goto err;
  }
} else {
  mappages(new, i, PGSIZE, pa, PTE_FLAGS(*pte));
}
inc_ref((void*)pa);   // ๊ณต์œ  page ref count++ ํ•˜๊ฒŒ ๋จ..

์ด ๊ณผ์ •์œผ๋กœ parent์™€ child๋Š” ๊ฐ™์€ physical page๋ฅผ read-only๋กœ ๋ฐ”๋ผ๋ณด๋ฉฐ, write ์‹œ fault๊ฐ€ ๋ฐœ์ƒํ•˜๋„๋ก ์ค€๋น„๋œ๋‹ค.


3.1.2. usertrap์—์„œ write fault ์ฒ˜๋ฆฌ

user mode์—์„œ write fault๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด usertrap์ด COW ์—ฌ๋ถ€๋ฅผ ํŒ์ •ํ•œ๋‹ค. ํ•ด๋‹น page๊ฐ€ PTE_COW์ด๊ณ  ๊ณต์œ  ref count๊ฐ€ 2 ์ด์ƒ์ด๋ฉด ์ƒˆ page๋ฅผ ํ• ๋‹นํ•ด ๋‚ด์šฉ์„ ๋ณต์‚ฌํ•œ ๋’ค child ์ชฝ์œผ๋กœ๋งŒ writable ๋งคํ•‘์„ ๋งŒ๋“ ๋‹ค. ref count๊ฐ€ 1์ด๋ฉด ๊ฐ™์€ page๋ฅผ ๊ทธ๋Œ€๋กœ writable๋กœ ์ „ํ™˜ํ•œ๋‹ค.

// kernel/trap.c
if(r_scause() == 15){                 // store fault
  uint64 va = r_stval();
  pte_t *pte = walk(p->pagetable, va, 0);
  if((*pte & PTE_COW) && (*pte & PTE_V) && (*pte & PTE_U)){
    uint64 pa = PTE2PA(*pte);
    if(get_ref((void*)pa) > 1){       // ๊ณต์œ  page
      char *mem = kalloc();
      memmove(mem, (char*)pa, PGSIZE);
      uvmunmap(p->pagetable, PGROUNDDOWN(va), 1, 1);
      mappages(p->pagetable, PGROUNDDOWN(va), PGSIZE,
               (uint64)mem, PTE_R|PTE_W|PTE_X|PTE_U);
    } else {                          // ๋‹จ๋… page
      *pte |= PTE_W;
      *pte &= ~PTE_COW;
    }
    goto trapret;
  }
}

์ด logic ๋•๋ถ„์— write๋ฅผ ์‹œ๋„ํ•œ process๋งŒ ์ƒˆ page๋ฅผ ๊ฐ–๊ฒŒ ๋˜๊ณ , ๋‚˜๋จธ์ง€ ํ”„๋กœ์„ธ์Šค๋Š” ์›๋ณธ page๋ฅผ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•œ๋‹ค.


3.1.3. kalloc / kfree์—์„œ reference count ๊ด€๋ฆฌ

physical page๋ณ„ ์‚ฌ์šฉ ๊ฐœ์ˆ˜๋ฅผ ref_counts[] ๋ฐฐ์—ด๋กœ ๊ด€๋ฆฌํ•œ๋‹ค. ์ƒˆ page๋ฅผ ํ• ๋‹นํ•˜๋ฉด ref count๋ฅผ 1๋กœ ์„ค์ •ํ•˜๊ณ , page๋ฅผ ๊ณต์œ ํ•  ๋•Œ inc_ref๋กœ ์ฆ๊ฐ€์‹œํ‚จ๋‹ค. kfree๋Š” ref count๊ฐ€ 0์ด ๋  ๋•Œ๋งŒ ์‹ค์ œ free list์— ๋ฐ˜ํ™˜ํ•œ๋‹ค.

// kalloc.c
void inc_ref(void *pa){
  ref_counts[(uint64)pa / PGSIZE]++;
}

void kfree(void *pa){
  uint *ref = &ref_counts[(uint64)pa / PGSIZE];
  *ref -= 1;
  if(*ref == 0){
    memset(pa, 1, PGSIZE);
    ((struct run*)pa)->next = kmem.freelist;
    kmem.freelist = (struct run*)pa;
  }
}

์ดˆ๊ธฐํ™” ์‹œ ๋ชจ๋“  usable page์˜ ref count๋ฅผ 1๋กœ ์„ค์ •ํ•œ ๋’ค freerange์—์„œ kfree๋ฅผ ํ˜ธ์ถœํ•ด free list์— ๋„ฃ๋Š”๋‹ค.


3.1.4. ์—ฐ๋™ ๊ฒฐ๊ณผ

  • cowtest์˜ simpletest, threetest, filetest๊ฐ€ ๋ชจ๋‘ pass๋œ๋‹ค.
  • parent์™€ child์˜ write ๋™์ž‘์ด ์„œ๋กœ ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์œผ๋ฉฐ, ์—ฌ์ „ํžˆ read-only page๋ฅผ ๊ณต์œ ํ•จ์œผ๋กœ์จ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ํฌ๊ฒŒ ๊ฐ์†Œํ•œ๋‹ค.
  • ref count ๊ด€๋ฆฌ๋กœ page ๋ˆ„์ˆ˜ ์—†์ด exit ํ›„ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ํšŒ์ˆ˜๋œ๋‹ค.

copy-on-write fork ๊ตฌํ˜„์€ ์œ„ ์„ธ ๋ถ€๋ถ„์ด ๋งž๋ฌผ๋ ค ๋™์ž‘ํ•˜๋ฉฐ, xv6์˜ ๊ธฐ๋ณธ fork ๋Œ€๋น„ ์„ฑ๋Šฅ๊ณผ ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚จ๋‹ค.

3.2. Large file ์ง€์› ๊ตฌํ˜„

large file์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด inode์˜ block address ๊ตฌ์กฐ๋ฅผ direct + single indirect + double indirect 3๋‹จ๊ณ„๋กœ ํ™•์žฅํ–ˆ๋‹ค. bigfile ํ…Œ์ŠคํŠธ๊ฐ€ ์š”๊ตฌํ•˜๋Š” 65803๊ฐœ block์„ ์ •ํ™•ํžˆ ์ง€์›ํ•˜๋„๋ก ์ƒ์ˆ˜๋ฅผ ์žฌ์กฐ์ •ํ•˜๊ณ , bmap์™€ itrunc๋ฅผ ์ˆ˜์ •ํ•ด block ํ• ๋‹นยทํ•ด์ œ๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค.


3.2.1. ํ•ต์‹ฌ ๋งคํฌ๋กœ ๋ณ€๊ฒฝ

// kernel/param.h
#define FSSIZE 262656      // file system ์ „์ฒด block ์ˆ˜

// kernel/fs.h
#define NDIRECT 11         // direct pointer 11๊ฐœ
#define NINDIRECT (BSIZE / sizeof(uint))     // 256
#define MAXFILE (NDIRECT + NINDIRECT + NINDIRECT*NINDIRECT)   // 11 + 256 + 65536
  • direct pointer๋ฅผ 11๊ฐœ๋กœ ์ค„์—ฌ addrs[NDIRECT+2] ๋ฐฐ์—ด์˜ ๋งˆ์ง€๋ง‰ ๋‘ ์นธ์„ single indirect, double indirect pointer๋กœ ์‚ฌ์šฉํ•œ๋‹ค.
  • MAXFILE์„ double indirect ๋ฒ”์œ„๊นŒ์ง€ ๊ณ„์‚ฐํ•ด bigfile ํ…Œ์ŠคํŠธ์˜ block ์ˆ˜์™€ ์ผ์น˜์‹œํ‚จ๋‹ค.

3.2.2. dinode ๊ตฌ์กฐ

struct dinode {
  short type;
  short major;
  short minor;
  short nlink;
  uint  size;
  uint  addrs[NDIRECT+2];   // [0..10] direct, [11] single, [12] double
};

3.2.3. bmap ์ˆ˜์ •

double indirect ๋ถ„๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•ด ๋‘ ๋‹จ๊ณ„๋กœ block์„ ํ• ๋‹นยทํƒ์ƒ‰ํ•œ๋‹ค.

// kernel/fs.c (๋ฐœ์ทŒ)
bn -= NINDIRECT;
// double indirect
if(bn < NINDIRECT * NINDIRECT){
  // 1๋‹จ๊ณ„: double indirect pointer๊ฐ€ ์—†์œผ๋ฉด ํ• ๋‹น
  if((addr = ip->addrs[NDIRECT+1]) == 0){
    addr = balloc(ip->dev);
    ip->addrs[NDIRECT+1] = addr;
  }
  // 2๋‹จ๊ณ„: first level index ๊ณ„์‚ฐ
  bp = bread(ip->dev, addr);
  a  = (uint*)bp->data;
  if((addr = a[bn / NINDIRECT]) == 0){
    addr = balloc(ip->dev);
    a[bn / NINDIRECT] = addr;
    log_write(bp);
  }
  brelse(bp);
  // 3๋‹จ๊ณ„: second level index
  bp = bread(ip->dev, addr);
  a  = (uint*)bp->data;
  if((addr = a[bn % NINDIRECT]) == 0){
    addr = balloc(ip->dev);
    a[bn % NINDIRECT] = addr;
    log_write(bp);
  }
  brelse(bp);
  return addr;
}

๋™์ž‘ ์ˆœ์„œ

  • double indirect pointer๊ฐ€ ์—†์œผ๋ฉด ์ƒˆ block์„ ํ• ๋‹นํ•œ๋‹ค.
  • ์ฒซ ๋ฒˆ์งธ ๋ ˆ๋ฒจ ๋ฐฐ์—ด์„ ๊ฐ€์ ธ์™€ index๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ , ๋‘ ๋ฒˆ์งธ ๋ ˆ๋ฒจ ๋ฐฐ์—ด block์„ ํ• ๋‹นโ€ง๊ธฐ๋กํ•œ๋‹ค.
  • ๋‘ ๋ฒˆ์งธ ๋ ˆ๋ฒจ ๋ฐฐ์—ด์—์„œ ์‹ค์ œ data block์„ ํ• ๋‹นํ•ด ๋ฐ˜ํ™˜ํ•œ๋‹ค.

3.2.4. itrunc ๊ฐœ๋… ์š”์•ฝ

itrunc๋Š” direct, single indirect, double indirect ๋ธ”๋ก์„ ๋ชจ๋‘ ์ˆœํšŒํ•˜๋ฉฐ bfree๋ฅผ ํ˜ธ์ถœํ•ด ํ•ด์ œํ•œ๋‹ค.
double indirect๋Š” ๋‘ ๋‹จ๊ณ„์— ๊ฑธ์ณ bread โ†’ loop โ†’ bfree ์ˆœ์œผ๋กœ ์žฌ๊ท€์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค.


3.2.5. bigfile ํ…Œ์ŠคํŠธ์™€์˜ ์ •ํ•ฉ์„ฑ

  • bigfile.c๋Š” MAXFILE์— ํ•ด๋‹นํ•˜๋Š” 65803 block์„ ์ˆœ์ฐจ writeํ•œ ๋’ค read๋กœ ๊ฒ€์ฆํ•œ๋‹ค.
  • double indirect ๋ถ„๊ธฐ์™€ ์ƒ์ˆ˜ ์กฐ์ •์œผ๋กœ write loop๊ฐ€ block ํ• ๋‹น ์˜ค๋ฅ˜ ์—†์ด ์™„๋ฃŒ๋œ๋‹ค.
  • read ๋‹จ๊ณ„์—์„œ block ๋ฒˆํ˜ธ์™€ data๊ฐ€ ์ผ์น˜ํ•ด ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ์ด ๋ณด์žฅ๋œ๋‹ค.

์ด๋กœ์จ xv6 file system์€ ์•ฝ 66 MB(65803 * 1024) ๊ทœ๋ชจ์˜ ํŒŒ์ผ๊นŒ์ง€ ์•ˆ์ •์ ์œผ๋กœ ์ €์žฅยท์ฝ๊ธฐํ•  ์ˆ˜ ์žˆ๋‹ค.

3.3. Symbolic link ๊ตฌํ˜„

symbolic link์€ ํŒŒ์ผ ์ด๋ฆ„ ๋Œ€์‹  ๊ฒฝ๋กœ ๋ฌธ์ž์—ด์„ ์ €์žฅํ•ด ๋‹ค๋ฅธ ํŒŒ์ผ์„ ๊ฐ„์ ‘ ์ฐธ์กฐํ•˜๋Š” inode์ด๋‹ค.
๊ตฌํ˜„์€ inode type ์ถ”๊ฐ€, sys_symlink ์‹œ์Šคํ…œ์ฝœ ์ •์˜, sys_open์˜ ๊ฒฝ๋กœ ํ•ด์„ ํ™•์žฅ, ๊ทธ๋ฆฌ๊ณ  ๋ฃจํ”„ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•œ ๊นŠ์ด ์ œํ•œ์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.


3.3.1. ์ฃผ์š” ์ƒ์ˆ˜ ๋ฐ ํƒ€์ž…

  • T_SYMLINK ํŒŒ์ผ ํƒ€์ž…์„ inode์™€ stat ๊ตฌ์กฐ์— ์ถ”๊ฐ€
  • MAX_SYMLINK_LOOPS ์ƒ์ˆ˜๋ฅผ 10์œผ๋กœ ์ •์˜ํ•ด ๋ฌดํ•œ ์ˆœํ™˜์„ ๋ฐฉ์ง€
  • stat, user.h, ์‹œ์Šคํ…œ์ฝœ ๋ฒˆํ˜ธ ํ…Œ์ด๋ธ”์— ํƒ€์ž…โ€งํ•จ์ˆ˜โ€ง๋ฒˆํ˜ธ๋ฅผ ๋ชจ๋‘ ๋ฐ˜์˜
#define T_SYMLINK 4        // kernel/fs.h, kernel/stat.h
#define MAX_SYMLINK_LOOPS 10
#define SYS_symlink 22     // syscall ๋ฒˆํ˜ธ

3.3.2. sys_symlink

sys_symlink(const char *target, const char *linkpath)๋Š” ๋‹ค์Œ ์ˆœ์„œ๋กœ ๋™์ž‘ํ•œ๋‹ค.

  1. create(linkpath, T_SYMLINK, 0, 0) ํ˜ธ์ถœ๋กœ ๋นˆ symlink inode ์ƒ์„ฑ
  2. writei๋กœ target ๊ฒฝ๋กœ ๋ฌธ์ž์—ด์„ inode ๋ฐ์ดํ„ฐ ์˜์—ญ์— ๊ธฐ๋ก
  3. ์ž‘์—… ์‹คํŒจ ์‹œ iunlockput ํ›„ -1 ๋ฐ˜ํ™˜
if((ip = create(path, T_SYMLINK, 0, 0)) == 0)
  return -1;
if(writei(ip, 0, (uint64)target, 0, strlen(target)) < strlen(target))
  return -1;

3.3.3. ys_open์˜ ๊ฒฝ๋กœ ํ•ด์„

open ์‹œ symlink๋ฅผ ์ž๋™์œผ๋กœ ๋”ฐ๋ผ๊ฐ€๋„๋ก while ๋ฃจํ”„๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

  • ์ตœ๋Œ€ MAX_SYMLINK_DEPTH๋งŒํผ ๋ฐ˜๋ณตํ•˜๋ฉฐ namei๋กœ ํ˜„์žฌ ๊ฒฝ๋กœ๋ฅผ lookup
  • inode๊ฐ€ T_SYMLINK, O_NOFOLLOW๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ
    • symlink ํŒŒ์ผ์—์„œ target ๊ฒฝ๋กœ ๋ฌธ์ž์—ด์„ ์ฝ์–ด path ๋ณ€์ˆ˜์— ๋ณต์‚ฌ
    • ๊นŠ์ด ์นด์šดํŠธ๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๊ณ  ๋ฃจํ”„ ์žฌ์‹œ์ž‘
  • depth ์ดˆ๊ณผ ์‹œ ์‹คํŒจ
for(int depth = 0; depth < MAX_SYMLINK_DEPTH; depth++){
  if((ip = namei(path)) == 0){
    if(omode & O_CREATE)
      ip = create(path, T_FILE, 0, 0);
    else
      return -1;
  } else
    ilock(ip);

  if(ip->type == T_SYMLINK && !(omode & O_NOFOLLOW)){
    char link_target[MAXPATH];
    int len = readi(ip, 0, (uint64)link_target, 0, MAXPATH - 1);
    iunlockput(ip);
    link_target[len] = '\0';
    safestrcpy(path, link_target, MAXPATH);
    continue;          // ๋‹ค์‹œ ํ•ด์„
  }
  goto found;          // ์‹ค์ œ ํŒŒ์ผ ๋„์ฐฉ
}

3.3.4. create ํ•จ์ˆ˜ ํ˜ธํ™˜์„ฑ

create๋Š” ๊ธฐ์กด T_FILEโ€†ยทโ€†T_DIRยทT_DEVICE ๋กœ์ง์„ ์œ ์ง€ํ•˜๋ฉฐ, T_SYMLINK๋ฅผ ์ถ”๊ฐ€ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์•˜๋‹ค. symlink ์ƒ์„ฑ ์‹œ ๋ณ„๋„ ์ดˆ๊ธฐํ™”๋Š” ํ•„์š” ์—†๊ณ , nlink๋Š” 1๋กœ ์„ค์ •ํ•œ ๋’ค dirlink๋กœ ๋””๋ ‰ํ† ๋ฆฌ์— ๋“ฑ๋กํ•œ๋‹ค.


3.3.5. ์ „์ฒด์ ์ธ ๋™์ž‘ ๊ณผ์ •

  • symlink target link ๋ช…๋ น์ด ๋“ค์–ด์˜ค๋ฉด sys_symlink๊ฐ€ link ํŒŒ์ผ์„ ๋งŒ๋“ค๊ณ  target ๊ฒฝ๋กœ๋ฅผ ๋‚ด์šฉ์œผ๋กœ ๊ธฐ๋กํ•œ๋‹ค.
  • ์ดํ›„ open(link) ํ˜ธ์ถœ์€ ๋ฃจํ”„๋ฅผ ๋Œ๋ฉฐ symlink ํŒŒ์ผ์„ ์—ด๊ณ  target ๋ฌธ์ž์—ด์„ ์ฝ์–ด ๋‹ค์‹œ namei๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค.
  • ์ตœ๋Œ€ 10๋‹จ๊ณ„๊นŒ์ง€ link chain์„ ๋”ฐ๋ผ๊ฐ€๋ฉฐ, cycle์ด๊ฑฐ๋‚˜ ๊นŠ์ด ์ดˆ๊ณผ ์‹œ ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • O_NOFOLLOW flag๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด symlink ์ž์ฒด๋ฅผ ์—ด ์ˆ˜ ์žˆ๋‹ค.

์ด ๋ฐฉ์‹์œผ๋กœ symlinktest์˜ link ์ƒ์„ฑ, loop ๊ฐ์ง€, broken link ์ฒ˜๋ฆฌ, ๋™์‹œ์„ฑ(createโ€†ยทโ€†unlink race) ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ๋ชจ๋‘ ํ†ต๊ณผ๋œ๋‹ค.

4. Results

4.1. cowtest.c

4.1.1. Sub-test comparison

Sub-testExpected referenceActual outputAnalysis & reasoningVerdict
simpletestsimple: okidenticalCOW page๋Š” ๋ณต์‚ฌ ์—†์ด ๊ณต์œ , ref count +1/-1 ์ •์ƒpass
threetest (ร—3)์„ธ ์ค„ ๋ชจ๋‘ three: okidentical์„ธ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋™์‹œ์— write โ†’ ๊ณต์œ  page ๋ณต์‚ฌ ํ›„ free, ref count leak ์—†์Œpass
filetestfile: ok ๋ฐ ๋งˆ์ง€๋ง‰ ALL COW TESTS PASSEDidenticalcopyout๊ฐ€ COW page๋ฅผ ์ง์ ‘ ์ฒ˜๋ฆฌํ•˜๋„๋ก ์ˆ˜์ •ํ•˜์—ฌ pipe alloc ์„ฑ๊ณตpass

โ†’ ๋ฉ”๋ชจ๋ฆฌ ๊ณต์œ ยท๋ณต์‚ฌยทํ•ด์ œ ์ „ ๊ณผ์ •์ด ๋ชจ๋‘ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•œ๋‹ค.


4.2. bigfile.c

ํ•ญ๋ชฉExpectedActual๋ถ„์„
Blocks written65 80365 803double-indirect bmap๊ฐ€ ์ „์ฒด ํ• ๋‹น ๋ฒ”์œ„ ์ฒ˜๋ฆฌ
Verification readall matchall matchblock ๋ฒˆํ˜ธ์™€ ๋ฐ์ดํ„ฐ ์ผ์น˜, ๋ฌด๊ฒฐ์„ฑ ๊ฒ€์ฆ ํ†ต๊ณผ
Runtime (QEMU)์ˆ˜ ๋ถ„์•ฝ 20 ๋ถ„๋™๊ธฐ์‹ log I/O ์ง€์—ฐ ํ—ˆ์šฉ ๋ฒ”์œ„

โ†’ 66 MB๊ธ‰ file์„ ์˜ค๋ฅ˜ ์—†์ด write-read ํ–ˆ์œผ๋ฏ€๋กœ large-file ํ™•์žฅ์ด ์„ฑ๊ณต์ ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.


4.3. symlinktest.c

Sub-testObservationExplanationVerdict
Basic link (bโ†’a)b ํƒ€์ž… T_SYMLINK, ์ฝ์œผ๋ฉด 'a'create๊ฐ€ T_SYMLINK ์ „๋‹ฌ, target ๊ฒฝ๋กœ ์ €์žฅpass
Broken link์›๋ณธ a ์‚ญ์ œ ํ›„ open(b) ์‹คํŒจsys_open์ด depth loop ๋‚ด์—์„œ inode ๋ฏธ์กด์žฌ ์‹œ ์—๋Ÿฌ ๋ฐ˜ํ™˜pass
Cyclic link (aโ†”b)open(b) ์˜ค๋ฅ˜ ๋ฐ˜ํ™˜depth ์นด์šดํ„ฐ 10 ๋„๋‹ฌ ํ›„ ๋ฃจํ”„ ๊ฐ์ง€pass
Chain (1โ†’2โ†’3โ†’4)write via 1, read via 4 ๋™์ผ ๋ฌธ์ž4-step ํ•ด์„์ด MAX_SYMLINK_LOOPS-์•ˆ์— ์™„๋ฃŒpass
Concurrency๋‘ child ๋ชจ๋‘ ์ •์ƒ ์ข…๋ฃŒinode lock + log write ๋กœ race condition ๋ฐฉ์ง€pass

โ†’ ๋งํฌ ์ƒ์„ฑยท์‚ญ์ œยทํ•ด์„ยท๋™์‹œ์„ฑ์ด ๋ชจ๋‘ ์š”๊ตฌ ์กฐ๊ฑด์„ ์ถฉ์กฑํ•œ๋‹ค.


4.4. Completion process

  1. make qemu
  2. QEMU shell:
xv6 kernel is booting

init: starting sh
$ cowtest
simple: ok
simple: ok
three: ok
three: ok
three: ok
file: ok
ALL COW TESTS PASSED
$ bigfile
..................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
wrote 65803 blocks
bigfile done; ok
$ symlinktest
Start: test symlinks
test symlinks: ok
Start: test concurrent symlinks
test concurrent symlinks: ok
$ 
  1. ์„ธ test ๋ชจ๋‘ โ€ฆ ok / PASSED ์ถœ๋ ฅ๋˜์—ˆ์Œ.

screenshot


4.5. Program-flow snapshot ๊ธฐ๋Šฅ๋ณ„ ๋™์ž‘ ํ๋ฆ„ ์š”์•ฝ

  • COW : fork โ†’ uvmcopy(PTE_COW) โ†’ write fault โ†’ usertrap โ†’ kalloc+copy โ†’ resume
  • Large file : write loop โ†’ bmap(directโ†’singleโ†’double) โ†’ log_write โ†’ disk
  • Symlink : sys_open โ†’ namei โ†’ ilock โ†’ type check โ†’ readi(target) โ†’ namei retry (โ‰ค10)

5. Troubleshooting

5.1. Copy-on-Write troubleshooting

5.1.1. Initial symptom

simpletest, threetest๋Š” ํ†ต๊ณผํ–ˆ์œผ๋‚˜ filetest์—์„œ file: pipe() failed ๋ฉ”์‹œ์ง€ ๋ฐœ์ƒ.

5.1.2. Hypotheses

  • Memory leak : pipealloc ๋‚ด๋ถ€ kalloc ์‹คํŒจ ๊ฐ€๋Šฅ์„ฑ โ†’ ๋””๋ฒ„๊ทธ ๋กœ๊ทธ ์ถ”๊ฐ€, ๋ฏธ์ถœ๋ ฅ.
  • File structure exhaustion : filealloc ์‹คํŒจ ๊ฐ€๋Šฅ์„ฑ โ†’ ๋””๋ฒ„๊ทธ ๋กœ๊ทธ ์ถ”๊ฐ€, ๋ฏธ์ถœ๋ ฅ.

5.1.3. Root cause

  • pipe๋Š” fd ๋ฒˆํ˜ธ๋ฅผ user ๋ฐฐ์—ด์— ๋ณต์‚ฌํ•˜๊ธฐ ์œ„ํ•ด copyout ํ˜ธ์ถœ.
  • parent page๋Š” PTE_COW + read-only.
  • ๊ธฐ์กด copyout์€ PTE_W๊ฐ€ ๊บผ์ง„ ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋‚˜๋ฉด ์ฆ‰์‹œ -1 ๋ฐ˜ํ™˜ โ†’ pipealloc ์‹คํŒจ.
// old copyout (excerpt)
if((*pte & PTE_W) == 0)
  return -1;          // write-protect โ†’ ์ฆ‰์‹œ ์‹คํŒจ

5.1.4. Fix

copyout์ด PTE_COW ํ”Œ๋ž˜๊ทธ๋ฅผ ๊ฐ์ง€ํ•˜๋ฉด ์ง์ ‘ COW page ๋ณต์‚ฌ ํ›„ ์žฌ์‹œ๋„.

// kernel/vm.c (core patch)
if((*pte & PTE_COW) && !(*pte & PTE_W)){
  if(copy_cow_page(pagetable, va) < 0)
    return -1;
}

5.1.5. Result

pipe ์„ฑ๊ณต โ†’ filetest ok โ†’ ์ตœ์ข… ALL COW TESTS PASSED.


5.2. Large-file troubleshooting

5.2.1. Symptom 1

wrote 268 blocks ํ›„ file is too small ์˜ค๋ฅ˜.

5.2.2. Cause 1

NDIRECT๊ฐ€ 12๋กœ ๋‚จ์•„ double-indirect ํฌ์ธํ„ฐ ๋ฏธ์‚ฌ์šฉ.

5.2.3. Fix 1

NDIRECT โ†’ 11, addrs[NDIRECT+2]๋กœ ๊ตฌ์กฐ์ฒด ๊ฐฑ์‹  โ†’ double-indirect ํ™œ์„ฑํ™”.


5.2.4. Symptom 2

mkfs assertion (BSIZE % sizeof(struct dinode)) == 0 ์‹คํŒจ.

5.2.5. Cause 2

struct dinode ํฌ๊ธฐ๊ฐ€ 64 B ๋ฐฐ์ˆ˜ ์•„๋‹˜.

5.2.6. Fix 2

๋ฐฐ์—ด ํฌ๊ธฐ ์กฐ์ •์œผ๋กœ 64 B ์ •๋ ฌ ํ™•๋ณด โ†’ ์ด๋ฏธ์ง€ ์ƒ์„ฑ ์„ฑ๊ณต.


5.2.7. Symptom 3

bigfile ์‹คํ–‰ ์‹œ๊ฐ„์ด ๊ณผ๋„(QEMU + sync log).

5.2.8. Work-around

๋Œ€๊ธฐ ํ›„ wrote 65803 blocks / bigfile done; ok ์ถœ๋ ฅ.


5.3. Symlink troubleshooting

5.3.1. Initial compile errors

๋ฏธ์ •์˜ ์ƒ์ˆ˜ยท์ค‘๋ณต statยท๋ฏธ๋“ฑ๋ก syscall ๋“ฑ.

5.3.2. Fix steps

์ƒ์ˆ˜ ์ •์˜, ํ•จ์ˆ˜ ์›ํ˜• ์ถ”๊ฐ€, syscall.h / syscall.c / usys.pl ๊ฐฑ์‹ ,
ulib.c ์ค‘๋ณต stat ์ œ๊ฑฐ ๋“ฑ์œผ๋กœ ์ปดํŒŒ์ผ ์™„๋ฃŒ.


5.3.3. Runtime error A โ€” FAILURE: b isn't a symlink

  • Cause : create()๊ฐ€ T_SYMLINK๋ฅผ ๋ฌด์‹œํ•˜๊ณ  T_FILE๋กœ ํ• ๋‹น.
  • Fix : ialloc(dev, type)๋กœ ํƒ€์ž… ๊ทธ๋Œ€๋กœ ์ „๋‹ฌ.

5.3.4. Runtime error B โ€” broken link panic

  • Cause : sys_open์ด depth / O_NOFOLLOW ์ฒดํฌ ์—†์ด ์žฌํ•ด์„.
  • Fix : ๊นŠ์ด ์นด์šดํ„ฐ(โ‰ค10) ๋ฐ O_NOFOLLOW ๋ถ„๊ธฐ ์ถ”๊ฐ€.

5.3.5. Runtime error C โ€” concurrent unlink panic

  • Cause : sys_symlink๊ฐ€ write ์ค‘ lock ํ•ด์ œ โ†’ race.
  • Fix : writei ์™„๋ฃŒ ํ›„ iunlockput; ๊ฐ ๋‹จ๊ณ„ log_write ํ˜ธ์ถœ.

5.3.6. Result

symlinktest์˜ basicยทbrokenยทloopยทconcurrent ์‹œ๋‚˜๋ฆฌ์˜ค ๋ชจ๋‘ ok ์ถœ๋ ฅ.

6. Additional Content

6.1. Reference notes for COW / Large file / Symbolic link implementation in xv6-riscv

  • RISC-V์—๋Š” CR0(Write Protect) ๋น„ํŠธ๊ฐ€ ์—†์œผ๋ฏ€๋กœ, ํŽ˜์ด์ง€๋ฅผ read-only๋กœ ๋งŒ๋“œ๋Š” ์ž‘์—…์€ PTE_W ํด๋ฆฌ์–ด + TLB flush๋กœ๋งŒ ์™„๊ฒฐ๋œ๋‹ค.
  • double-indirect block ๊ตฌํ˜„ ์‹œ balloc์œผ๋กœ ํ• ๋‹น๋ฐ›์€ ๋‘ ๋ฒˆ์งธ ๋ ˆ๋ฒจ ๋ธ”๋ก์„ ๋ฐ˜๋“œ์‹œ log_write ํ›„ brelseํ•ด์•ผ log ์ผ๊ด€์„ฑ์ด ์œ ์ง€๋œ๋‹ค.
  • symlink ํ•ด์„์€ namei์™€ ๋™์ผํ•œ ์ž ๊ธˆ ์ˆœ์„œ๋ฅผ ๋”ฐ๋ผ์•ผ deadlock์„ ํ”ผํ•  ์ˆ˜ ์žˆ๋‹ค. ํŠนํžˆ sys_open ๋ฃจํ”„ ๋‚ด๋ถ€์—์„œ ilock(ip) ํ›„ readi๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ log transaction์ด ์—ด๋ฆฐ ์ƒํƒœ์—ฌ์•ผ ํ•œ๋‹ค.
์ตœ๊ทผ ์ˆ˜์ •: 26. 6. 12. ์˜คํ›„ 3:28
Contributors: kmbzn, Claude Sonnet 4.6

BUILT WITH

CloudflareNode.jsGitHubGitVue.jsJavaScriptVSCodenpm

All trademarks and logos are property of their respective owners.
ยฉ 2026 kmbzn ยท MIT License