Re: [Yaffs] YAFFS readdir rewind causing endless listings

Top Page
Attachments:
Message as email
+ (text/plain)
Delete this message
Reply to this message
Author: Rong Shen
Date:  
To: Andrew McKay
CC: yaffs
Subject: Re: [Yaffs] YAFFS readdir rewind causing endless listings
On Fri, Nov 14, 2008 at 5:43 AM, Andrew McKay <> wrote:
>> While I was debugging my issue posted in "a bug regarding when space
>> running out - shown in example",
>> I managed to narrow it down to the same issue described here. I'm
>> using 2.4.30 kernel with the latest Yaffs2
>> cvs check out, hopefully my discussion will still apply here.
>
> I have a newer kernel, and your patch won't compile with it, so I have a
> couple of quick questions.


Yes, my patch is for 2.4 kernels.

>
>>
>> My tracing showed the endless loop is caused by,
>
> Good job tracing and understanding that. I was heading down that road, but
> got lost along the way. I don't have enough understanding of Linux file
> systems to feel confident making changes like this. But I thought that
> there could be a similar solution to this.
>
>> 1. busybox calls to readdir()
>
> ...
>
>> 4. default_llseek() sets file->f_version to ++event, which causes it
>> no longer same as inode->i_version, which
>> then hits Todd's patch in yaffs_readdir() and causes yaffs_readdir()
>> to list the directory files from the beginning,
>> over and over again.
>
> My default_llseek() sets file->f_version to 0. I guess this changed with
> newer kernels?
>


In the later kernels, they seem to have got rid of the global event variable, or
maybe use for other purpose. But the idea of tracking directory changes with
f_version and i_version should remain the same.


>> This issue only happens if the listed directory has too many files to
>> be returned in one yaffs_readdir() call.
>
>> So here comes my proposal to solve the endless listing issue, It's
>> actually pretty simple - define a llssek() on directory
>> operation. What I did for my 2.4 kernel was just copying
>> generic_file_llseek(), deleting the line changing f_version, and
>> pasting
>> the rest to yaffs_fs.c, shown below.
>
> Seems to make sense.
>
>
>> Comments?
>
> Since your patch doesn't compile for newer kernels, I'll attach my patch for
> a 2.6.20.4 Kernel. Exactly same method of fixing it as yours. I've tested
> it and not found any issues with it. I'm going to the kernel on some of the
> other developers systems and see how it works out there.


Nice to here it also works for you. Thanks.

> retrieving revision 1.1.8.1.24.1
> diff -u -r1.1.8.1.24.1 yaffs_fs.c
> --- yaffs_fs.c  5 Sep 2008 19:36:29 -0000       1.1.8.1.24.1
> +++ yaffs_fs.c  13 Nov 2008 18:38:16 -0000
> @@ -137,6 +137,7 @@
>  static int yaffs_sync_object(struct file *file, struct dentry *dentry,
>                             int datasync);

>
> +static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int
> origin);
> static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
>
>  #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
> @@ -280,6 +281,7 @@
>        .read = generic_read_dir,
>        .readdir = yaffs_readdir,
>        .fsync = yaffs_sync_object,
> +       .llseek = yaffs_dir_llseek,
>  };

>
>  static struct super_operations yaffs_super_ops = {
> @@ -910,6 +912,29 @@
>        return nWritten == 0 ? -ENOSPC : nWritten;
>  }

>
> +static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int
> origin)
> +{
> +       long long retval;
> +
> +       lock_kernel();
> +       switch (origin) {
> +               case 2:
> +                       offset += i_size_read(file->f_path.dentry->d_inode);
> +                       break;
> +               case 1:
> +                       offset += file->f_pos;
> +       }
> +       retval = -EINVAL;
> +       if (offset >= 0) {
> +               if (offset != file->f_pos) {
> +                       file->f_pos = offset;
> +               }
> +               retval = offset;
> +       }
> +       unlock_kernel();
> +       return retval;
> +}
> +
>  static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
>  {
>        yaffs_Object *obj;

>
>
>
> Andrew
>


Rong