Bug 9366

Summary: BFS: Directory entries stored in the last directory block are handled incorrectly.
Product: File System Reporter: Dmitri Vorobiev (dmitri.vorobiev)
Component: OtherAssignee: Dmitri Vorobiev (dmitri.vorobiev)
Status: RESOLVED CODE_FIX    
Severity: high CC: dmitri.vorobiev
Priority: P1    
Hardware: All   
OS: Linux   
Kernel Version: 2.6.24-rc2 Subsystem:
Regression: --- Bisected commit-id:

Description Dmitri Vorobiev 2007-11-13 07:33:09 UTC
Most recent kernel where this bug did not occur: 2.6.6
Distribution: this bug does not depend on distribution.
Hardware Environment: x86
Software Environment:

>>>

# lsmod
Module                  Size  Used by
bfs                    14008  1
#

<<<

Problem Description:

An error in the bfs_add_entry() function leads to inaproppriate handling of directory entries if the latter entries reside in the last block allocated for the directory.

Steps to reproduce:

1. Format a BFS partition allowing 512 directory entries in the root directory. This is the default value for the mkfs utility shipped with the UnixWare 7.1.1 operating system. Two directory entries are thereby occupied by the "." and ".." entries leaving 510 entries for regular files.

2. Use the following command to create 511 files in the BFS root directory:

>>>

debian:/mnt# for i in `seq 1 511`; do echo "$i" > $i; done

<<<

3. Unmount the BFS partition and then mount it again:

>>>

debian:~/bfs# umount /mnt
debian:~/bfs# mount -t bfs /dev/loop0 /mnt/

<<<

4. See that the file with the name `479' disappeared from the filesystem:

debian:~/bfs# cd /mnt
debian:/mnt# cat 479
cat: 479: No such file or directory

>>>
Comment 1 Dmitri Vorobiev 2007-11-13 07:35:11 UTC
If the root directory is full and an attempt is made to create another directory entry, the following code in the bfs_add_entry() function

>>>

if (block==eblock && off>=eoff) {
	/* Do not read/interpret the garbage in the end of eblock. */
	de->ino = 0;
}

<<<

makes the function believe that the directory entry at the offset 0 of the last block allocated for the directory is not used. This code snippet silently deletes the directory entry, which occupies the direntry slot in the beginning of the last directory block and replaces it with another one. The blocks occupied by the "unlinked" inode are thereby lost.

The erroneous code was introduced in the context of the patch submitted in this LKML message:

http://lkml.org/lkml/2004/5/4/205

Not only this code snippet introduces a bug, but also the intention behind it is erroneous: indeed, there can be no "garbage" directory entries, but any directory entry with nonzero `ino' field should be valid.
Comment 2 Dmitri Vorobiev 2007-11-13 07:36:47 UTC
I am working on a fix, and am planning to submit a patch.
Comment 3 Dmitri Vorobiev 2007-11-13 08:48:31 UTC
The patch proposed in the following LKML message

http://lkml.org/lkml/2007/11/13/185

fixes the error reported in the context of this bug. What follows is a console session, which proves that the error is gone:

>>>

debian:~# mount -t bfs /dev/loop0 /mnt
debian:~# cd /mnt/
debian:/mnt# for i in `seq 1 511`; do echo "$i" > $i; done
-bash: 511: No space left on device
debian:/mnt# cd
debian:~# umount /mnt
debian:~# mount -t bfs /dev/loop0 /mnt/
debian:~# cd /mnt
debian:/mnt# cat 479
479
debian:/mnt#

<<<
Comment 4 Dmitri Vorobiev 2007-11-13 12:01:56 UTC
Merged in -mm tree, so I am closing this bug.