Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safely writing to compact flash on embedded Linux

I'm developing an embedded Linux system that runs from compact flash and tmpfs. The flash is mounted read-only and should normally stay that way, but occasionally I need to write something to the flash.

What precautions should I take when writing to flash (through a PATA interface)? For reasons I can't recall, I'm using an ext4 filesystem mounted with barrier=1,data=ordered,nodelalloc,noatime,ro Is any of that a horrible idea? The system needs to boot quickly with zero intervention. I'm tempted to do tune2fs -c 0 -i 0. Is that an even worse idea?

Also, when I write something, I obviously need to remount the flash read-write, perform the write, then remount read-only. The problem is that there are several different processes (both c++ binary and shell scripts) that may need to do this. Clearly having each process indiscriminately remount the filesystem read-only when it's done is a bad idea.

What's the best way to coordinate this? flock looks promising; is that the best way to go and what do I need to be worried about? I don't want a stale lock to block writes or leave the filesystem writable indefinitely.

To clarify: By "occasional" writing, I mean the system could go for years without needing to write anything. When something does get written, it's maybe a couple hundred bytes. In the mean time, the system needs to endure unpredictable power cycles without any intervention.

like image 664
eater Avatar asked Jan 23 '11 20:01

eater


3 Answers

Making ext4 safe

ext4 is not really ideal for this; your worst-case scenario is always going to be that the power fails while your partition is RW and corrupts the filesystem.

Even though they're designed for raw NAND devices, a logging filesystem like jffs2 or yaffs might still be useful. They have the useful characteristic that their on-disk format looks more like a list rather than a tree, so newer data tends to be packed more closely and thus less likely to trash the relatively static parts of the filesystem.

I can't comment on how to make ext4 'safe' under these circumstances; both the filesystem structure and fsck are unaware of the common failure modes of flash devices (notably, that during any write there's a long period where a whole block of data is invalid.) This behaviour is, of course, specific to the controller on the CF card, so it's not very predictable anyway.

The safest and most predictable way that I can think of is the same flip-buffer data layout used in smaller embedded devices. That is, you have two writable areas (two partitions.) At any given time, at least one of them must be consistent. When you want to write, pick the older of the two. If you power up and detect an inconsistency in buffer A, copy the contents of buffer B across (and don't allow any writes to B in the meantime.)

Managing mount/remount

I would write a daemon that manages the unmount/remount on behalf of all of the processes on the system. This has a number of advantages:

  • you separate out the umount/remount logic and only have to implement it once
  • processes that want to write don't need root privileges
  • you can build in some sort of watchdog to ensure that the partition is not left RW for too long. If it is, you can kill the offending process (potentially rolling back) and remount-RO.
  • you can measure how long you're mounted RW, which gives you some idea of the risk involved per update
like image 188
Ian Howson Avatar answered Nov 11 '22 22:11

Ian Howson


I made an embedded system running from a 4GB CF card. I setup it up with 3 partitions:

  • /boot; ext2; ~128MB
  • root; squashfs; 500MB (since it's not writable, there is no way to accidentally put it in write mode.)
  • /data; ext2; ~3.5GB any data that I want to save

I'm using ext2 because I believe any of the journaling FS will actually cause more blocks to be modified for each write. Also there is no point running a flash file system on CF card because the system does not have direct access to the flash blocks. The CF card contains its own block mapping logic internally.

like image 22
cmcginty Avatar answered Nov 12 '22 00:11

cmcginty


Since you are using CF, the wear leveling is most probably built in and so you will get no benefit using a file-system like yaffs2, jffs2 etc that have wear leveling built in. In-fact most wear leveling file-systems are not recommended for CF cards that have wear leveling built in. You though need a file-system that has built in journaling so that you can safely go through power on-off cycles without a system corruption. There are two options there - picking a file-system with journaling or picking a db (assuming the writes are db centric) with wear leveling like sqlite. For the file-system, you can go with either ext3 or ext4 though personally I recommend ext3 as ext4 is still known to have bugs that can give you a headache. I would also recommend like others to have two partitions, one pure read-only using a filesystem like squashfs, cramfs and the other read-write using ext3.

Having said that, I am not sure if your device has built in EEPROM, but if it has and you just need to write a few hundred bytes every few years, the simplest configuration would be to use a single read only filesyetem with EEPROM as your data area for those few hundred bytes.

like image 24
Pankaj Avatar answered Nov 11 '22 22:11

Pankaj