Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 19 May 2000 16:19:43 -0400 (EDT)
From:      Zhihui Zhang <zzhang@cs.binghamton.edu>
To:        freebsd-hackers@freebsd.org, freebsd-fs@freebsd.org
Subject:   A possible bug in directory lookup code?
Message-ID:  <Pine.SOL.4.21.0005191536030.8332-100000@sol.cs.binghamton.edu>

next in thread | raw e-mail | index | archive | help

I think I may have found a bug in the directory lookup code in FreeBSD
4.0-Release, although it does not affect normal user.  Please be patient
and read on. The test code I am using and its result as follows:

# cat test.c
#include <stdio.h>
#include <errno.h>
main()
{
        int error;
        error = rename("dir1", "dir2/.");
        printf("error = %d, errno = %d\n", error, errno);
}
# mkdir dir1
# mkdir dir2
# cc test.c
# ./a.out
error = -1, errno = 66

The error code returned is 66 - ENOTEMPTY not the expected 22 - EINVAL.

Why do I expect EINVAL error?  This is because the following code:

(1) In ufs_lookup(), we have the following code for the RENAME case: 

       if (dp->i_number == dp->i_ino)
                return (EISDIR);

This code is never executed when you are looking for dot.

(2) In rename() system call, we have the following bogus code:
		
       if ((error = namei(&tond)) != 0) {
                /* Translate error code for rename("dir1", "dir2/."). */
                if (error == EISDIR && fvp->v_type == VDIR)
                        error = EINVAL;  <-- should change to 22 here!
                NDFREE(&fromnd, NDF_ONLY_PNBUF);
                vrele(fromnd.ni_dvp);
                vrele(fvp);
                goto out1;
        }

See the bogus comment "Translate error ...", that is exactly what I am
using in my test.c code.

How does this happen (return 66 instead of 22)?  I use remote debugging to
find out.  In vfs_cache_lookup() (invoked by VOP_LOOKUP()), it calls
cache_lookup(), which returns -1 as a dot hit.  Then because of the
following code:

        if (pdp == vdp) {   /* lookup on "." */
                VREF(vdp);
                error = 0;

namei() succeeds on "dir2/." lookup (error = 0). Next, when ufs_rename()
is called, the tdvp and tvp are the same vnode! This will make
ufs_dirempty() return 0 (even if the directory dir2/. is empty!) and
ENOTEMPTY will be set to the variable error.

IMHO, this is not the correct way to handle this in the kernel.  But the
net result from the point of the view of the user is the same (the atomic
rename fails).  It just makes things very confusing. ufs_dirempty() should
not return 0 when the directory is empty.

BTW, when I use gdb to do remote debugging, the gdb sometimes fails to
display the correct line that is being executed.  I wonder what's wrong.

Any insights in appreciated.

-Zhihui



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.SOL.4.21.0005191536030.8332-100000>