Hello

Charles P. Wright wrote:
> Vladimir,
> 
> We actually came across this while working on Unionfs in the kernel,
> which uses lseek to inquire about directory positions and then resume
> directory reading operations (much like nfsd does).
> 

Ok, please try whether the attached patch makes reiser4 to behave similar to 
others.


> I've attached a user space program that demonstrates the behavior.
> 
> The relevant strace entries are:
> open("/mnt/r4/", O_RDONLY)              = 3
> getdents(3, /* 5 entries */, 268)       = 80
> lseek(3, 0, SEEK_CUR)                   = -1 ENOENT
> lseek(3, 4294967295, SEEK_SET)          = -1 EINVAL
> 
> The third line is the one of concern.
> 
> The same program run on another file system yields a trace like:
> open("/mnt", O_RDONLY)                  = 3
> getdents(3, /* 4 entries */, 268)       = 68
> lseek(3, 0, SEEK_CUR)                   = 2147483647
> lseek(3, 2147483647, SEEK_SET)          = 2147483647
> 
> Charles
> 
> On Mon, 2005-08-22 at 20:19 +0400, Vladimir V. Saveliev wrote:
>>Hello
>>
>>Charles P. Wright wrote:
>>>Hello,
>>>
>>>I've noticed that Reiser4's behavior deviates from other file systems
>>>when seeking with directories.  After reading a directory, if you run
>>>vfs_lseek(dir, 0, SEEK_CUR), then -ENOENT is returned.   This means that
>>>you can't pass the identifier back to vfs_lseek with SEEK_SET.
>>>
>>Would you please send your test program?
>>
>>------------------------------------------------------------------------
>>
>>#include <stdio.h>
>>#include <linux/types.h>
>>#include <linux/unistd.h>
>>#include <linux/dirent.h>
>>#include <sys/types.h>
>>#include <fcntl.h>
>>#include <sys/errno.h>
>>#include <unistd.h>
>>#include <stdlib.h>
>>
>>_syscall3(int, getdents, uint, fd, struct dirent *, dirp, uint, count);
>>
>>int main(int argc, char *argv[])
>>{
>>      struct dirent dirent;
>>      int fd;
>>      int nread;
>>      struct dirent *p;
>>      off_t offset;
>>
>>      if (argc != 2) {
>>              fprintf(stderr, "No dir specified\n");
>>              exit(1);
>>      }
>>
>>      if ((fd = open(argv[1], O_RDONLY)) < 0) {
>>              fprintf(stderr, "Could not open directory %s\n", argv[1]);
>>              exit(2);
>>      }
>>
>>      while ((nread = getdents(fd, &dirent, sizeof(dirent))) > 0) {
>>              p = &dirent;
>>              while (nread > 0) {
>>                      printf("d_reclen = %d, d_name = %s, d_off = %lu\n", 
>> p->d_reclen, p->d_name, p->d_off);
>>                      nread -= p->d_reclen;
>>                      p = (struct dirent *)((char *)p + p->d_reclen);
>>              }
>>              offset = lseek(fd, 0, SEEK_CUR);
>>              printf("Offset is %llu\n", offset);

offset is off_t. off_t is long int in this program.
You should have therefore
printf("Offset is %ld\n", offset);

>>              if (lseek(fd, offset, SEEK_SET) < 0) {
>>                      perror("lseek");
>>                      exit(1);
>>              }
>>      }
>>      exit(0);
>>}

This patch changes lseek part the end of reiser4 directory to not return ENOENT.


 fs/reiser4/plugin/dir/dir.c |    9 ++++++---
 1 files changed, 6 insertions(+), 3 deletions(-)

diff -puN fs/reiser4/plugin/dir/dir.c~reiser4-fix-llseek 
fs/reiser4/plugin/dir/dir.c
--- linux-2.6.12-rc6-mm1/fs/reiser4/plugin/dir/dir.c~reiser4-fix-llseek 
2005-08-23 15:22:43.363256896 +0400
+++ linux-2.6.12-rc6-mm1-vs/fs/reiser4/plugin/dir/dir.c 2005-08-23 
15:59:29.523105778 +0400
@@ -854,7 +854,10 @@ dir_rewind(struct file *dir, readdir_pos
                memset(pos, 0, sizeof *pos);
                return dir_go_to(dir, pos, tap);
        } else if (destination >= inode->i_size)
-               return RETERR(-ENOENT);
+               /* seek past the end of directory */
+               dir->f_pos = inode->i_size;
+               return 0;
+       }
 
        if (shift < 0) {
                /* I am afraid of negative numbers */
@@ -1629,7 +1632,7 @@ readdir_common(struct file *f /* directo
 
  repeat:
        result = dir_readdir_init(f, &tap, &pos);
-       if (result == 0) {
+       if (result == 0 && f->f_pos != inode->i_size) {
                result = tap_load(&tap);
                /* scan entries one by one feeding them to @filld */
                while (result == 0) {
@@ -1669,7 +1672,7 @@ readdir_common(struct file *f /* directo
 
                if (result >= 0)
                        f->f_version = inode->i_version;
-       } else if (result == -E_NO_NEIGHBOR || result == -ENOENT)
+       } else if (result == -E_NO_NEIGHBOR || f->f_pos == inode->i_size || 
result == -ENOENT)
                result = 0;
        tap_done(&tap);
        detach_fsdata(f);

_

Reply via email to