From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga09.intel.com ([134.134.136.24]) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1YNH8F-0003ud-2q for linux-mtd@lists.infradead.org; Mon, 16 Feb 2015 08:34:20 +0000 Message-ID: <1424075632.2573.225.camel@sauron.fi.intel.com> Subject: Re: UBIFS handling of erased page errors From: Artem Bityutskiy Reply-To: dedekind1@gmail.com To: Iwo Mergler Date: Mon, 16 Feb 2015 10:33:52 +0200 In-Reply-To: References: Content-Type: text/plain; charset="UTF-8" Mime-Version: 1.0 Content-Transfer-Encoding: 7bit Cc: "linux-mtd@lists.infradead.org" List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Hi Iwo, On Mon, 2015-02-16 at 17:35 +1100, Iwo Mergler wrote: > I've noticed that it is possible for UBIFS to become read-only > after an ECC error when reading an erased page. Yep, the assumption we have had was that erased regions are ready to use and free of bit-flips. > This strikes my as odd - the page was erased, so it doesn't > contain important filesystem information. I expected UBI > to deal with this - torture the block, retire it if necessary. I guess this is what it will do if the driver returns -EIO when write() is invoked. > Does this remount behaviour make sense? Yes, this is a healthy reaction to an unexpected error. Better than ignore it. So the answer is - it does make sense. But I guess what you actually meant is more like "is this behaviour ideal?" or "could we do better?". I think yes, we could do better. > Could someone give > me an example where remounting read-only would serve a data > integrity purpose under those circumstances? The point here is that "those circumstances" are not programmed into UBIFS logic. Therefore, UBIFS uses its default "unexpected error" logic. > > [ 96.830000] UBI warning: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 352:4096, read only 126976 bytes, retry > > [ 96.890000] UBI warning: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 352:4096, read only 126976 bytes, retry > > [ 96.970000] UBI warning: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 352:4096, read only 126976 bytes, retry > > [ 97.070000] UBI error: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 352:4096, read 126976 bytes > > [ 97.080000] [] (unwind_backtrace+0x0/0x11c) from [] (ubi_io_read+0x210/0x320) > > [ 97.090000] [] (ubi_io_read+0x210/0x320) from [] (ubi_eba_read_leb+0x354/0x488) > > [ 97.100000] [] (ubi_eba_read_leb+0x354/0x488) from [] (ubi_leb_read+0x108/0x170) > > [ 97.110000] [] (ubi_leb_read+0x108/0x170) from [] (ubifs_leb_read+0x28/0x88) > > [ 97.120000] [] (ubifs_leb_read+0x28/0x88) from [] (ubifs_start_scan+0xb4/0x13c) > > [ 97.120000] [] (ubifs_start_scan+0xb4/0x13c) from [] (ubifs_scan+0x28/0x330) > > [ 97.130000] [] (ubifs_scan+0x28/0x330) from [] (layout_in_gaps+0x100/0x528) > > [ 97.140000] [] (layout_in_gaps+0x100/0x528) from [] (ubifs_tnc_start_commit+0x6dc/0x760) > > [ 97.150000] [] (ubifs_tnc_start_commit+0x6dc/0x760) from [] (do_commit+0x1f8/0x884) > > [ 97.160000] [] (do_commit+0x1f8/0x884) from [] (ubifs_sync_fs+0x64/0x88) > > [ 97.170000] [] (ubifs_sync_fs+0x64/0x88) from [] (sync_fs_one_sb+0x28/0x2c) > > [ 97.180000] [] (sync_fs_one_sb+0x28/0x2c) from [] (iterate_supers+0x6c/0xa8) > > [ 97.190000] [] (iterate_supers+0x6c/0xa8) from [] (sys_sync+0x44/0x90) > > [ 97.200000] [] (sys_sync+0x44/0x90) from [] (ret_fast_syscall+0x0/0x2c) > > [ 97.220000] UBIFS error (pid 278): ubifs_scan: corrupt empty space at LEB 732:60500 > > [ 97.230000] UBIFS error (pid 278): ubifs_scanned_corruption: corruption at LEB 732:60500 > > [ 97.230000] UBIFS error (pid 278): ubifs_scanned_corruption: first 8192 bytes from LEB 732:60500 > > [ 97.240000] 00000000: ffffffbf ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ................................ > ... ^ Bit error > > [ 97.260000] UBIFS error (pid 278): ubifs_scan: LEB 732 scanning failed > > [ 97.260000] UBIFS error (pid 278): do_commit: commit failed, error -117 > > [ 97.270000] UBIFS warning (pid 278): ubifs_ro_mode: switched to read-only mode, error -117 So here UBIFS scans an LEB. It encounters an ECC error. Ideally, it should: 1. Keep scanning 2. Pick all good nodes 3. Look at the error, figure out that this is just corrupt free page at the end of LEB 4. Recover the LEB. I think step 3 should be implemented. Right now it will not even go to the step #2. > Now, the real reason for this was a buggy MTD driver, which didn't > handle bit errors in erased pages at all. It's quite traditional, I've > seen variations of such bugs in several different MTD drivers. Yes, many people told this. The easiest solution for everyone so far was to fix/hack the driver. UBIFS assumes free space is ECC-protected. You need to either satisfy this assumption or improve UBIFS to not assume it. > But that doesn't mean that real ECC errors in erased pages are > impossible. So I've added some code to deliberately cause such > errors, in an attempt to reproduce the one above. > I was, so far, unable to reproduce the error on the above code > path - in most cases, the block got tortured and marked as bad, > no read-only mount. Your back-trace shows a very rare case. A sync operation caused writes. This caused commit. Commit started laying out indexing nodes. Namely, it started finding out where in the flash indexing data will be written. And the situation was rare and unfortunate, so there was very little free space on flash, not enough to write indexing nodes. But there was a lot of dirty space. So UBIFS used the "in-the-gaps" method for writing indexing nodes (we cannot do the traditional GC in this case). The method is about picking an indexing LEB which contains some used data, but also has a lot of dirty data (the gaps in this case), and the method is about putting the new index nodes into those gaps. Anyway, the method found such an LEB, and started scanning it. And there you hit the error. This situation is quite rare, because "in-the-gaps" is the last resort slow method. To trigger it more often, you need to use a nearly full file-system. Or, just force the in-the-gap method, there is a debugfs knob for this. Just switch it on and UBIFS will choose the slow in-the-gaps a lot more often. HTH, Artem.