Re: Inconsistent directory information

Sushil Agrawal (sushil@cse.iitk.ac.in)
Thu, 16 Sep 1999 04:14:58 +0530 (IST)


On Tue, 14 Sep 1999, Jim Nance wrote:

> Hello All,
> I found a linux quirk I thought I would mention. I dont think it really
> hurts anything, but its kind of wierd. I went to a mount point and ran the
> commands:
>
> mount .
> ls
>
> which is to say I mounted a directory over my CWD and then tried to list
> the contents of my CWD. What I get is:
>
> ls: lost+found: No such file or directory
> ls: configfile: No such file or directory
> ls: buildLibs.sh: No such file or directory
> ls: buildLizzard.sh: No such file or directory
> ls: runLizzard.sh: No such file or directory
> ls: gdbscript: No such file or directory
> ls: prefix: No such file or directory
> ls: mozbuild: No such file or directory
>
> All these files are in the directory that was mounted on top of the CWD.
> It looks like some system call is looking at the new directory and some
> system call is looking at the old directory.
>
> Interestingly if I run "strace ls" then ls sees all the files in the new
> directory.
>
> Like I said I dont think this is a bug, but it is kind of wierd.
>
> Jim
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.rutgers.edu
> Please read the FAQ at http://www.tux.org/lkml/
>

Hi,

Following is a possible explanation :

FIRST RUN : mounting nfs directory .
---------
$ cd /tmp/tmp1
$ mount host1:/ . /* mount / on host1 onto /tmp/tmp1
$ ls -l /* will do a lstat (ls --color=auto also does lstat)

# In the following output, the erro message "No Such File ..." is
# from the ls command. The second output
# "real_lookup : lookup = 0xc013f0a0" is the message that i
# printed from the kernel in the real_lookup() function which was
# called by lookup_dentry() function. It says that the lookup
# inode operation
# associated with the inode of tmp1 (ie tmp1->i_op->lookup() ) is
# ext2_lookup(); 0xc013f0a0 is
# the address of the ext2_lookup() function which was statically
# compiled into the kernel. This means tmp1 is covered by a nfs
# directory (in the run above) but its i_op->lookup field is the old one
# i.e of ext2_lookup and thus the lookup() which is called from real_lookup()
# is the ext2_lookup() instead of nfs_lookup()
# . Ext2_lookup() returns error because the old tmp1 is now covered.
# See also the SECOND RUN below.

ls: lost+found: No such file or directory
<0>real_lookup : lookup = 0xc013f0a0
ls: tmp: No such file or directory
<0>real_lookup : lookup = 0xc013f0a0
ls: dev: No such file or directory
<0>real_lookup : lookup = 0xc013f0a0
ls: etc: No such file or directory
<0>real_lookup : lookup = 0xc013f0a0
ls: var: No such file or directory
<0>real_lookup : lookup = 0xc013f0a0
ls: proc: No such file or directory
<0>real_lookup : lookup = 0xc013f0a0
ls: bin: No such file or directory
<0>real_lookup : lookup = 0xc013f0a0
ls: boot: No such file or directory
<0>real_lookup : lookup = 0xc013f0a0

SECOND RUN
----------
$ cd ..
$ cd tmp1
$ ls -l
# In the following we again see two outputs. The directory listing
# is from the ls which is the listing of the root on host1( succeeded this time ). # The second
# one line output is what i have printed inside the kernel in the
# follow_mount() function which is called from lookup_dentry()
# function. When we cd to tmp1, the lookup_dentry() function calls
# follow_mount() function which copies the inode of
# the root of the covering file system , sb->s_root, (in this
# case inode for the host1:/ ) into the inode of the covered
# directory (tmp1 in this case) and with this tmp1 gets the
# nfs inode with i_op initialized to nfs_dir_inode_operations which
# contains the nfs_lookup() function pointer (loaded dynamically at address
# 0xc2842f14 as can be seen in the output) . The nfs_lookup now
# sends a lookup request to host1 and gets the listing.

follow_mount : old_follow = 0xc013f0a0, new_follow = 0xc2842f14

drwxr-xr-x 2 root root 2048 Jan 1 1996 bin
drwxr-xr-x 2 root root 1024 Jan 1 1996 boot
drwxr-xr-x 6 root root 25600 Jan 31 1996 dev
drwxr-xr-x 34 root root 3072 Jan 31 1996 etc
drwxr-xr-x 3 root root 1024 Jan 6 1996 home
drwxr-xr-x 4 root root 3072 Jan 1 1996 lib
drwxr-xr-x 2 root root 1024 Jan 31 1996 lost+found
drwxr-xr-x 2 root root 1024 May 11 07:20 misc
drwxr-xr-x 5 root root 1024 Jan 1 1996 mnt
drwxr-xr-x 2 root root 1024 Jan 1 1996 proc
drwxr-x--- 12 root root 1024 Jan 31 1996 root
drwxr-xr-x 3 root root 3072 Jan 1 1996 sbin
drwxr-xr-x 2 root root 1024 Jan 1 1996 tmp
drwxr-xr-x 19 root root 1024 Jan 1 1996 usr

One thing remains is that how ls gets the list of files in the first place because i_op is not proper. The answer is that ls calls open(".". ...) system call. The sys_open interface function calls lookup_dentry which calls follow_mount() and returns the correct inode. But the
current->fs->pwd still points to the old inode! The ls then calls getdents() passing it the fd
returned by open and gets the files because the inode corresponding to this fd is the new inode. Ls then calls lstat for each file returned by getdents(). But sys_lstat calls lookup_dentry() which again goes through the same old current->fs->pwd inode and the real_lookup() calls
ext2_lookup() which fails to find the files.

I think sys_mount() is the best place to check whether the dir_name (the directory to be
covered) is "." and do appropriate action at this time. Propagating this task further down
will make it difficult because the functions there are general functions called from many diffrent places (for ex. we cannot check this in lookup_dentry() because it is called from open, lstat etc. and "." in these cases is perfectly fine).

- Sushil.

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/