Skip to content
isdnetworks
Go back

같은 쓰기를 두 방식으로 했다

펌웨어 스크립트의 두 분기를 나란히 놓아 봤다.

보드 A

mount -t jffs2 /dev/mtdblock4 /mnt/upgrade/
cd /mnt/upgrade/upgrade
rm -rf ./c5/*
cd $path
cp -rf ./c5/* /mnt/upgrade/upgrade
flash_erase /dev/mtd2 0x0 0x1
nandwrite -p -s 0x0 /dev/mtd2 /mnt/upgrade/upgrade/upgrade-marker.bin
sync
umount /dev/mtdblock4

보드 B

flash_erase /dev/mtd0 0x0 0x80
nandwrite -p -s 0x0 /dev/mtd0 ./BOOT.bin
... (네  반복)
flash_erase /dev/mtd0 0x1040000 0x1
nandwrite -p -s 0x1040000 /dev/mtd0 ./upgrade-marker.bin
sync

같은 장비의 같은 작업인데 방식이 다르다.

Table of contents

Open Table of contents

두 분기를 나란히 놓았다

A는 플래시를 mount 한다. 마운트하고 옛 파일을 지우고 새 파일을 복사하고 언마운트한다.

B는 장치에 바로 쓴다. flash_erase 로 지우고 nandwrite 로 쓰는 것을 네 번 반복한다.

한쪽은 파일 복사고 다른 쪽은 블록 단위 쓰기다. 결과적으로 같은 장비가 새 펌웨어로 뜨는데 거기까지 가는 길이 다르다.

A는 복사하고 B는 직접 쓴다

왜 다른지를 각 분기가 다루는 파일 목록에서 찾았다. A 쪽은 이랬다.

angstrom_rootfs.jffs2
soc_system.rbf
upgrade-marker.bin

부트로더도 커널도 없다. FPGA 설정인 soc_system.rbf 와 루트 이미지뿐이라 파일로 두고 다음 부팅에 읽히면 되는 것들이다.

B는 부트로더와 디바이스트리와 커널을 바꾼다. 이것들은 파일이 아니라 특정 주소에 있어야 하는데 부트로더가 그 주소를 읽기 때문이다.

주소에서 읽히는 것은 마운트해서 파일로 넣을 수 없다. 넣어 봐야 읽는 쪽이 그 자리를 안 본다.

원인 — 대상에 따른 방식 차이

정리하면 이렇게 된다.

[파일로 읽히는 것]   마운트 → 복사
[주소에서 읽히는 것]  직접 쓰기

어떻게 읽히느냐가 어떻게 쓰느냐를 정한다. 쓰는 쪽의 취향이 아니라 읽는 쪽의 요구가 방식을 고른 것이다.

그래서 두 분기가 다른 것은 일관성이 없어서가 아니었다. 담는 것이 다르니 담는 방식도 다른 것이다.

마커는 양쪽 다 직접 썼다

그런데 A 안에서도 마커만은 직접 쓴다.

cp -rf ./c5/* /mnt/upgrade/upgrade     # 파일 복사
flash_erase /dev/mtd2 0x0 0x1          # 여기부터 직접
nandwrite -p -s 0x0 /dev/mtd2 .../upgrade-marker.bin

cp 로 파일을 복사하다가 마커 차례에서 flash_erasenandwrite 로 바뀐다. 한 분기 안에 두 방식이 섞여 있는 셈이다.

마운트를 이미 해 둔 상태이므로 마커도 파일로 복사할 수 있었을 텐데 그렇게 안 했다. 앞의 규칙을 그대로 적용하면 이유가 나온다.

전체 흐름 — 읽는 시점과 저장 위치

마커를 읽는 쪽이 파일시스템을 안 거친다.

[파일시스템이 뜨기 전]  마커를 읽어야 함

파일로 두면 못 읽음

특정 주소에 둠

읽는 시점이 파일시스템보다 앞이다. 부팅 초기에 이 값을 보고 업그레이드가 끝났는지를 판단해야 하는데 그때는 아직 마운트가 안 돼 있다.

앞의 정리에 한 줄이 더 붙는다. 부팅 초기에 읽히면 주소에 두고 나중에 읽히면 파일로 둔다.

대상의 종류가 아니라 읽히는 시점이 자리를 정한 것이다. 마커는 A에서도 B에서도 같은 이유로 같은 방식이 된다.

언마운트 전에 동기화한다

A 끝에 두 줄이 붙어 있다.

sync
umount /dev/mtdblock4

umount 가 알아서 반영할 텐데 sync 가 앞에 따로 있다. 중복처럼 보인다.

다만 umount 는 실패할 수 있다. 그 자리를 누가 쓰고 있으면 안 풀린다.

[sync 먼저]  umount 가 실패해도 데이터는 반영됨
[umount 만]  실패하면 반영도 안 될 수 있음

실패해도 내용은 남기려는 것으로 보인다. 성공하는 경로에서는 한 번 더 하는 셈이고 실패하는 경로에서만 값을 한다.

지우고 복사하는 이유

A에 지우기와 복사가 나란히 있다.

cd /mnt/upgrade/upgrade
rm -rf ./c5/*
cd $path
cp -rf ./c5/* /mnt/upgrade/upgrade

rm -rf 로 먼저 비우고 cp -rf 로 새것을 넣는다. 덮어써도 될 것 같은데 지우는 단계를 굳이 둔다.

덮어쓰기는 새 패키지에 없는 옛 파일을 남긴다. 판이 올라가면서 파일 목록이 바뀌면 지난 판의 잔여물이 섞이는데 그것이 겉으로는 안 보인다.

공간도 문제다. 지우고 쓰면 한 시점에 필요한 자리가 줄어드는데 저장 자리가 작은 장비에서는 그 차이가 크다.

주의 — 상대 경로와 경로 오가기

이 대목에서 cd 가 두 번 나온다.

path=$(pwd)          # 맨 위에서 저장
...
cd /mnt/upgrade/upgrade
...
cd $path             # 돌아옴

맨 위에서 pwdpath 에 저장해 두고 마운트 지점으로 갔다가 다시 돌아온다. 상대 경로를 쓰기 때문에 생긴 왕복이다.

cp -rf ./c5/*./c5 는 패키지를 푼 자리 기준이라 다른 데로 갔다 오면 안 맞는다. 그래서 돌아오는 cd 가 반드시 필요하다.

절대 경로였으면 이 왕복이 필요 없었다.

cp -rf $path/c5/* /mnt/upgrade/upgrade

path 를 이미 저장해 뒀으니 그것을 쓰면 어디서 실행해도 같다. cd 로 오가는 것보다 이쪽이 읽기도 쉽고 중간에 cd 가 실패했을 때의 위험도 없다.

정리


Share this post on:

Previous Post
패킷망과 신호망을 잇는다
Next Post
100%가 안 되면 어디까지 되는지