[Yaffs] YAFFS readdir rewind causing endless listings

Top Page
Attachments:
Message as email
+ (text/plain)
Delete this message
Reply to this message
Author: Andrew McKay
Date:  
To: yaffs
Subject: [Yaffs] YAFFS readdir rewind causing endless listings
Hi,

I'm having some issues with YAFFS and directories with quite a few files in them
(110+ files). When I do an ls in the directory the system locks up and
eventually ls dies with an out of memory error. If a find is executed in the
directory then the files repeat endlessly. Since ls buffers everything before
outputting the files, it locks up because it the readdir function never returns
NULL.

I am running a newish kernel, but definitely not the latest. 2.6.20.4.

I have added trace code to my kernel in VFS and YAFFS, and also the EXT2 file
system to get an understanding of what's going on. I have noticed that
yaffs_readdir will be called once will call filldir several times to fill a
buffer up for glibc's readdir system call. Normally when all the files fit into
one buffer, every things works fine. When the directory listing gets big enough
that it needs to call yaffs_readdir twice, the offset pointer gets reset to the
beginning of the directory and re-lists the files again. It continues doing
this in a loop and the directory listing looks infinite.

It seems the action of rewinding the directory if the file pointer and inode
pointer versions differ is not the correct solution. I have added trace code
and confirmed that when the following if statement is entered the directory
listing starts from the beginning.

   if (f->f_version != inode->i_version) {
     offset = 2;
     f->f_pos = offset;
     f->f_version = inode->i_version;
   }


I traced within ext2 as well to see what action it takes. It has similar code
that looks something like:

   int need_revalidate = filp->f_version != inode->i_version;
   if (unlikely(need_revalidate)) {
     if (offset) {
       offset = ext2_validate_entry(kaddr, offset, chunk_mask);
       filp->f_pos = (n<<PAGE_CACHE_SHIFT) + offset;
     }
     filp->f_version = inode->i_version;
     need_revalidate = 0;
   }


Tracing this code I found that offset was not set back to the beginning, it was
still the same number of directories into reading the directory.

I think that the action that YAFFS is taking in resetting the offset is
incorrect. Has this bug been found by someone else before? If so what was the
appropriate fix for it? Does YAFFS need a similar function to
ext2_validate_entry that returns the correct offset? I haven't had time to look
into what ext2_validate_entry actually accomplishes yet. But that is my next step.

Any further insight into what is going wrong would be greatly appreciated.

Thanks for your time,
Andrew McKay
Iders Inc.