Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[solved] what's the step-by-step execution flow of the command "$ echo hi > x" #11

Open
OccupyMars2025 opened this issue Mar 30, 2024 · 1 comment

Comments

@OccupyMars2025
Copy link
Owner

OccupyMars2025 commented Mar 30, 2024

step 1: make clean

step 2: make CPUS=1 qemu-gdb

step 3: disable all interrupts

(gdb) p/x $sstatus
(gdb) set $sstatus=a new value

step 4: (gdb) info threads, only one thread

How the ">" symbol works

https://pdos.csail.mit.edu/6.1810/2023/lec/l-fs.txt

If I break at user/echo.c:main, I only see "echo", "hi" in argv, and argc is 2, where does the " > x " part go ?

===============================

// kernel/trap.c
usertrap() {
   ...
    intr_on();

    syscall();
   ...
}

before sys_write is run, the interrupt is enabled, so after breaking at sys_write, you had better use set $sstatus = a new value to modify the register sstatus to disable all interrupts (timer interrupt is annoying when debugging) , but this method seems not working ???

1. indeed, this method can disable timer interrupt

2. After I set the value of $sstatus to disable interrupts (refer to intr_off()), I come across another interrupt kernel/trap.c:devintr() ==> virtio_disk_intr() , why ???

there are several CPUs, so modifying the sstatus to disable interrupts only works on one CPU ???

(gdb) info threads 
  Id   Target Id                    Frame 
* 1    Thread 1.1 (CPU#0 [running]) acquire (lk=lk@entry=0x8000e478 <proc+22080>)
    at kernel/spinlock.c:63
  2    Thread 1.2 (CPU#1 [running]) 0x00000000800067bc in release (
    lk=lk@entry=0x8000b398 <proc+9568>) at kernel/spinlock.c:98
  3    Thread 1.3 (CPU#2 [running]) 0x00000000800024b8 in bwrite (
    b=b@entry=0x8000eed8 <bcache+1152>) at kernel/bio.c:118

solution:

https://pdos.csail.mit.edu/6.1810/2023/labs/traps.html

It will be easier to look at traps with gdb if you tell qemu to use only one CPU, which you can do by running
    make CPUS=1 qemu-gdb

===============================

when you enter "make qemu-gdb", you can see the following infomation about file system:

nmeta 46 (boot, super, log blocks 30 inode blocks 13, bitmap blocks 1) blocks 1954 total 2000
balloc: first 915 blocks have been allocated
balloc: write bitmap block at sector 45

==============================

// In writei(), after executing bmap(), we have the "log"
(gdb) p log
$24 = {lock = {locked = 0, name = 0x800084f0 "log", cpu = 0x0, nts = 0, n = 46}, 
  start = 2, size = 30, outstanding = 1, committing = 0, dev = 1, lh = {n = 2, block = {
      45, 915, 32, 0 <repeats 27 times>}}}

log.lh.block[0] is 45 which indicates the 45th block that stores the bitmap, log.lh.block[1] is 915 which indicates the 915-th block that stores data

=============================

In writei(), after executing either_copyin(), we can see that "hi" has been written into bp->data, (bp->blockno is 915)

(gdb) p *bp
$36 = {valid = 1, disk = 0, dev = 1, blockno = 915, lock = {locked = 1, lk = {locked = 0, 
      name = 0x80008540 "sleep lock", cpu = 0x0, nts = 0, n = 7}, 
    name = 0x800083d0 "buffer", pid = 3}, refcnt = 2, prev = 0x800104b8 <bcache+6752>, 
  next = 0x8000ea78 <bcache+32>, data = "hi", '\000' <repeats 1021 times>}

===========================

after kernel/fs.c: writei() ---> iupdate() ----> log_write(), now log.lh.n is 3, log.lh.block[2] is 33 which indicates the 33-th block contains the dinode that is updated

(gdb) p log
$77 = {lock = {locked = 0, name = 0x800084f0 "log", cpu = 0x0, nts = 0, n = 48}, 
  start = 2, size = 30, outstanding = 1, committing = 0, dev = 1, lh = {n = 3, block = {
      45, 915, 33, 0 <repeats 27 times>}}}

==========================

now we get kernel/file.c:filewrite() ---> end_op() ---> commit()

in write_log():

copy from the buffer of block 45(bitmap)  to block 3 (log)
copy from the buffer of block 915(data block containing "hi")  to block 4 (log)
copy from the buffer of block 33(dinode block)  to block 5 (log)

in write_head():

copy log.lh to block 2

in install_trans(int recovering):

copy from block 3 to block 45
copy from block 4 to block 915
copy from block 5 to block 33

then erase the transaction from the log

    log.lh.n = 0;
    write_head();
@OccupyMars2025
Copy link
Owner Author

OccupyMars2025 commented Mar 31, 2024

How the ">" symbol works

If I break at user/sh.c:main, I can see how the entered command is processed by the shell

// user/sh.c
step 1:
 parseredirs()  --->  case '>'
step 2:
runcmd() 
  case REDIR:
    rcmd = (struct redircmd*)cmd;
    close(rcmd->fd);
    if(open(rcmd->file, rcmd->mode) < 0){
      fprintf(2, "open %s failed\n", rcmd->file);
      exit(1);
    }
    runcmd(rcmd->cmd);
    break;

actually it is:
close(1)
open("x", ...)
runcmd( "echo hi")

In step 2, open("x", ...) also modifies the file system, let's check it, switch to kernel/kernel, set a breakpoint at usertrap or sys_open

@OccupyMars2025 OccupyMars2025 changed the title [not solved] what's the step-by-step execution flow of the command "$ echo hi > x" [solved] what's the step-by-step execution flow of the command "$ echo hi > x" Mar 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant