Date: Thu, 06 Dec 2007 16:01:50 +0100 From: julien.bellang@free.fr To: freebsd-fs@freebsd.org Subject: Re: FSCK doesn't correct file size when INCORRECT BLOCK COUNT is found Message-ID: <1196953310.47580ede28676@imp.free.fr> In-Reply-To: <1196788555.47558b4bab0ab@imp.free.fr> References: <1196788555.47558b4bab0ab@imp.free.fr>
next in thread | previous in thread | raw e-mail | index | archive | help
Hi, Finally I understood why FSCK_UFS failed to correct corrupted files which had been in write progress whereas the power was shut down. 1) First some information about the file corrupted : In my case the Files System has the following characteristics - the write cache is activated on the hard drive - the SoftUpdate option is activated - the FS is mount with the default option noasync In this condition, when the power is cut off as a file is being written, at restart the file is corrupted in the following way : - in the inode metadata : the FILESIZE and the BLOCKCOUNT field are corresponding to the final value waited for the file - in the inode the list of BLOCKS is not up to date (seem pretty normal as the written process was not achieved), and the list is made of holes (EMPTY BLOCK, null block reference) that are not necessarily at the end of the list. 2) How FSCK treats these files : When computing on such a file, when FSCK finds a hole in a regular file's inode Block list, it skips it and doesn't increment the block count. BUT if the inode isn't associated to a directory, FSCK DOESN'T consider this hole as a default. Indeed, I think it may be possible that an application voluntary creates such a file. However after having checking the inode block list, FSCK's function checkinode() finds that the Block count calculated doesn't correspond to the inode BLOCKCOUNT field and only proposes to correct this field and doesn't correct the SIZE field. The problem for the end user, is that as the file seems to have the right Size, he's not able to know that the write process was not actually ended normally (I'm exactly in this situation) and thus that he will use a corrupted file. 3) A proposed solution : I'm working on a workaround in FSCK (and it seems to work fine in my case) that truncates the file with hole as soon as the first hole is discovered, and modifies the inode SIZE and BLOCKCOUNT field in consequence. However I have in mind that such a patch may be a problem for File that were voluntary created with hole. Maybe the solution is to pass a new option to FSCK, or only truncate the File if the BLOCKCOUNT is inconsistent. Is anyone interesting by this work and could react to this analyse ? Especially, I'm interesting to know in which known cases applications or system may be able to generate regular File containing hole. Thanks, Julien Bellanger ______________________________________________________ Selon julien.bellang@free.fr: > > Hi, > > I'm working on a system installed in an environnement where power is cut off > many time a week. This system is based on i386 FreeBSD 6.2 OS. > > I'm using FS UFS2 with SoftUpdate Activated. > > After such power shutdown, when I restart I've got some corrupted files that > FSCK_UFS doesn't entirely resolve. > > For these files FSCK resolves the following error : > /dev/ad0s1f: INCORRECT BLOCK COUNT I=3132417 (512992 should be 459392) > (CORRECTED) > > But actually these file still inconsistency in my point of view as the file > size > field doesn't reflect the number of block reference in its inode. > > Regards to fsck_ffs sources, It seems that FSCK checks the validity of block > pointer (!= 0) in the inode block list only for directory inode but not for > regular file. > In my case, as the number of block adress to check in the inode is deduced > from > the file size, and the file size is greater than the number of really > allocated > blocks I obtain many NULL block pointer. > > Does anyone have an idea why the NULL pointer are accepted by FSCK for > regular > file and it doesn't try to adjust the file size ? > > file fsck_ffs/inode.c, iblocks(), line 208 > > line 153: static int > 154: iblock(struct inodesc *idesc, long ilevel, off_t isize) > { > . > . > . > 197: if (IBLK(bp, i)) { > idesc->id_blkno = IBLK(bp, i); > if (ilevel == 0) > n = (*func)(idesc); > else > n = iblock(idesc, ilevel, isize); > if (n & STOP) { > bp->b_flags &= ~B_INUSE; > return (n); > } > } else { > 208: if (idesc->id_type == DATA && isize > 0) { > /* An empty block in a directory XXX */ > getpathname(pathbuf, idesc->id_number, > idesc->id_number); > pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", > pathbuf); > if (reply("ADJUST LENGTH") == 1) { > dp = ginode(idesc->id_number); > DIP_SET(dp, di_size, > DIP(dp, di_size) - isize); > isize = 0; > printf( > "YOU MUST RERUN FSCK > AFTERWARDS\n"); > rerun = 1; > inodirty(); > bp->b_flags &= ~B_INUSE; > return(STOP); > } > } > } > . > . > . > } > > Thanks, > > Julien > > > _______________________________________________ > freebsd-fs@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-fs > To unsubscribe, send any mail to "freebsd-fs-unsubscribe@freebsd.org" >
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1196953310.47580ede28676>