LINUX.ORG.RU

Старое дерево mtdblock после затирания mtd

 , ,


0

1

Есть флеш-память FM25Q128A-SOB-T-G, на которой «размечены» несколько mtd разделов. mtd3 содержит jffs2 файловую систему. Во время работы ОС необходимо перезаписать данный раздел новым образом jffs2 с бэкапом некоторых файлов с текущего раздела - считай обновить.
Делаю:

  1. переход в ramfs, бэкап пары файлов, kill процессов занятых mtdblock3;
  2. удачный чистый umount без -l/r;
  3. flash_erase -j /dev/mtd3 0x0 0x0

На этой стадии при попытке примонтировать mtdblock3 получаю прежнее дерево папок. При попытке обращения к файлу ругается на несоответствие CRC32. Брал дамп с mtd3 - flash_erase точно отрабатывает и затирает раздел.
Получается, mtdblock3 не хочет «обновить кэш» из реального mtd3. Как его можно заставить принимать актуальное состояние mtd3? Или я что-то упускаю?

Ответ на: комментарий от annulen

Ядро не имеет поддержки ubifs. Пересобрать/нести с собой модуль можно, но пока-что оттестирована и удовлетворяла потребности jffs2. Если уж не решиться, тогда придёт черёд другой fs.

Kass_Martin
() автор топика
Последнее исправление: Kass_Martin (всего исправлений: 1)

Прилагаю части кода, которыми всё делается:

  1. chroot
#!/bin/sh

WORKSPACE="$(dirname $(readlink -f $0))"

source "${WORKSPACE}/upgrade.include"

RAMFS_MP="/tmp"
ROOT_MP_PIECE="mnt/root"
DATA_MP_PIECE="mnt/data"
VENDOR=$(chip_vendor)
RAMFS_TAR_PATH="${WORKSPACE}/${RAMFS_TAR}"
RAMFS_MP_SIZE=$((20 * 1024 * 1024))
UPGRADE_SCRIPT="upgrade-process.sh"

...остановка софта и через lsof поиск зависимых от mtd устройств процессов...

echo "Preparing ramfs..."
mkdir -p "$RAMFS_MP"

if mountpoint -q "$RAMFS_MP";
then
    mount -o remount,size=$RAMFS_MP_SIZE "$RAMFS_MP"
else
    mount -t tmpfs -o size=$RAMFS_MP_SIZE tmpfs "$RAMFS_MP"
fi

tar xfa "$RAMFS_TAR_PATH" -C "$RAMFS_MP"
rm -f "$RAMFS_TAR_PATH"

cp -a /bin/${VENDOR}*           "${RAMFS_MP}/bin/" &>/dev/null
cp -a /bin/led_control          "${RAMFS_MP}/bin/" &>/dev/null
cp -a /bin/reset_button_state   "${RAMFS_MP}/bin/" &>/dev/null
cp -a /etc/passwd               "${RAMFS_MP}/etc/"
# cp -a /etc/fw_env.config        "${RAMFS_MP}/etc/"

echo "Switching to ramfs..."
cd "$RAMFS_MP"
chmod a+x "$UPGRADE_SCRIPT"
# pivot_root . "${RAMFS_MP}/${ROOT_MP_PIECE}"
mount --rbind / mnt/root
# exec 
chroot . bash -c "/$UPGRADE_SCRIPT"
  1. процесс перезаписи
#!/bin/sh

WORKSPACE="/"

source "${WORKSPACE}/upgrade.include"

# $1 - tag for print
# $2 - mtd index number
# $3 - binary name in $FIRMWARE_TAR
# $4 - backup function name
# $5 - restore function name
upgrade() {
    local tag="$1"
    local dev="/dev/mtd${2}"
    local bin="$3"
    local backup_fun="$4"
    local restore_fun="$5"
    
    if test_firmware_entry "$bin"; 
    then 
        print_j "$tag" "Upgrade begin..."
        
        print_j "$tag" "Binary extraction..."
        extract_firmware_file "$bin" || error "Binary extraction failed!"
        
        print_j "$tag" "Binary md5 check..."
        md5test "$bin" || error "Binary md5 sum check failed!"
        
        if [ -n "$backup_fun" ];
        then
            print_j "$tag" "Backuping data..."
            $backup_fun
        fi
        
        print_j "$tag" "Erasing ${dev} & writing ${bin}..."
        #flashcp -v -A "$bin" "$dev" || error "Binary write failed!"
        flash_erase -j "$dev" 0x0 0x0 || error "Erase failed!"
        nandwrite "$dev" "$bin" || error "Write failed!"
        
        if [ -n "$restore_fun" ];
        then 
            print_j "$tag" "Restoring data..."
            $restore_fun
        fi
        
        print_j "$tag" "Cleaning..."
        delete_extracted_file "$bin"
        
        print_j "$tag" "Upgrade done!"
    fi
    
    true
}

OVERLAY_MP="/mnt/overlay"
FIRMWARE_TAR_PATH="${WORKSPACE}/${FIRMWARE_TAR}"

mount -t proc proc "/proc"
mount -o remount,ro "${ROOTFS_MP}/mnt/overlay/upper"
mount -o remount,ro "${ROOTFS_MP}/mnt/overlay"
mount -o remount,ro "$ROOTFS_MP"
mount --move "${ROOTFS_MP}/dev" "/dev"
mount --move "${ROOTFS_MP}/sys" "/sys"
mount --move "${ROOTFS_MP}/var" "/var"
mount --move "${ROOTFS_MP}/run" "/run"
umount "${ROOTFS_MP}/tmp"
umount "${ROOTFS_MP}/proc"
mkdir -p "/mnt/overlay"
mount --move "${ROOTFS_MP}/mnt/overlay" "$OVERLAY_MP"
umount "$ROOTFS_MP"
umount "${OVERLAY_MP}/upper"
umount "${OVERLAY_MP}/lower"
umount "$OVERLAY_MP"
sleep 1

cd "$WORKSPACE"

echo "Installation begin..."

upgrade "UBOOT"  0 "uboot.bin"      uboot_backup    uboot_restore
upgrade "KERNEL" 1 "kernel.uImage"  kernel_backup   kernel_restore
upgrade "ROOTFS" 2 "rootfs.jffs2"   rootfs_backup   rootfs_restore
upgrade "DATAFS" 3 "datafs.jffs2"   datafs_backup   datafs_restore

echo "Installation end."
sleep 1

echo "Rebooting..."
reboot

sleep 10
Kass_Martin
() автор топика
Ответ на: комментарий от Dark_SavanT

Ну, я же не просто так это решил тоже)

mount -t jffs2 /dev/mtd3 /mnt/data/
mount: mounting /dev/mtd3 on /mnt/data/ failed: Block device required
Kass_Martin
() автор топика
Последнее исправление: Kass_Martin (всего исправлений: 1)
Ответ на: комментарий от Dark_SavanT

Что flash_erase + nandwrite, что flashcp делают своё дело на отлично и после проверки самих разделов nanddump’ом всё чётко(md5 сумму проверяю). После перезагрузки всё работает. Проблема в восстановлении бэкапа после залива - mtdblock не видит изменений mtd.

Kass_Martin
() автор топика
Ответ на: комментарий от Kass_Martin

А так, выглядит как бага в ядре, но которую за ненадобностью никто не правит.

ничего другого я по итогу сказать не могу. Версию ядра хоть укажи заодно, может у тебя там окаменелость какая.

Dark_SavanT ★★★★★
()
Ответ на: комментарий от Dark_SavanT

4.9.37

Сейчас попробовал сделать всё то же самое загрузившись сразу в ramfs обновления после старта - всё заработало как надо, стёрлось и записалось.
Значит, при chroot’e что-то удерживает mtdblock от обновления кэша после обычной работы ОС.
Что самое интересное, umount всех разделов и прошлого рута происходит без проблем и lsof не находит никаких открытых файлов к разделу и флешке в принципе.

Kass_Martin
() автор топика
Ответ на: комментарий от annulen

Собрал

./mount -t jffs2 /dev/mtd3 /mnt/data
./mount: /mnt/data: /dev/mtd3 is not a block device.
       dmesg(1) may have more information after failed mount system call.

В /proc/kmsg ничего нового.
P.S.: mtdX - символьные, mtdblockХ - блочные устройства, если что.

Kass_Martin
() автор топика
Ответ на: комментарий от Kass_Martin

Думаю flash_erase и nandwrite пишут мимо блочного кэша и не инвалидируют его. А файловая система, в частности jffs2, читает/пишет через блочный кэш. Попробуй инвалидировать блочный кэш вручную после flash_erase или nandwrite. echo 3 > /proc/sys/vm/drop_caches.

iliyap ★★★★★
()
Ответ на: комментарий от annulen

Не понял что имеется ввиду под name_of_device в доке, но если ./mount -t jffs2 mtd3 /mnt/data - монтирует и там прошлая структура. Видимо, неявно обращается к mtdblock или что-то подобное.

Kass_Martin
() автор топика

Всем спасибо за мозговой штурм.
По всей видимости от обновления кэша удерживает какой-то старый маунт(хоть всё и отмонтировалось без ошибок). Искать что удерживает займёт много времени - буду менять разметку с учётом запуска из-под initrd.

Kass_Martin
() автор топика