> -----Original Message----- > From: Diego Santa Cruz > Sent: 02 March 2021 10:02 > To: 'Trond Myklebust' <trond.myklebust@xxxxxxxxxxxxxxx>; > 'anna.schumaker@xxxxxxxxxx' <anna.schumaker@xxxxxxxxxx> > Cc: 'linux-nfs@xxxxxxxxxxxxxxx' <linux-nfs@xxxxxxxxxxxxxxx>; 'linux- > kernel@xxxxxxxxxxxxxxx' <linux-kernel@xxxxxxxxxxxxxxx> > Subject: symlinkat() behavior with NFS depends on dentry being on cache or > not > > Hello, > > [resending as plain-text, sorry for the noise] > > I noticed that the symlinkat() syscall changes behavior when the newpath > (i.e. link name) has a trailing slash and is the path to a directory residing on > NFS depending on this path being in the dentry cache or not. I stumbled > upon this in the context of a Yocto / OE-Core system where I updated > coreutils from version 8.30 to 8.31. This creates problems with ln in coreutils > in 8.31. I am currently using kernel 5.4.90. > > What I observe is that sylinkat("name", AT_FDCWD, > "/path/to/nfs/existing/dir/") returns ENOENT when > "/path/to/nfs/existing/dir/" is not in the dentry cache but EEXIST when it is, > but only when "/path/to/nfs/existing/dir/" is on NFS (NFSv3 in my case). > Note that if I remove the trailing slash from the newpath argument then it > returns EEXIST in all cases. > > Following change > https://github.com/coreutils/coreutils/commit/571f63f5010b047a8a32503040 > 53f05949faded4 in coreutils this makes "ln -sf name > /path/to/nfs/existing/dir/" sometimes fail with a "cannot overwrite > directory" error (when the path is not in the dentry cache). There was no > problem before this change because ln did a stat of the link name path > before calling symlinkat, so the entry was in the dentry cache when symlinkat > executes. > Any feedback on this problem I'm seeing? Or should I report it using Bugzilla at https://bugzilla.kernel.org/ instead? Or elsewhere? > I have created a simple program to reproduce this more easily, which I have > attached. > > To reproduce do this. > - Compile the attached symlinkat.c > - Mount a NFSv3 filesystem at /mnt > - mkdir /mnt/test > - To test the error with no dentry cache and trailing slash: > sync; echo 3 > /proc/sys/vm/drop_caches; ./symlinkat name /mnt/test/ > symlinkat name /mnt/test/ failed: No such file or directory (2) > - To test with the dentry cache: > ls -d /mnt/test/; ./symlinkat name /mnt/test/ > symlinkat name /mnt/test/ failed: File exists (17) > - To test the error with no dentry cache and no trailing slash: > sync; echo 3 > /proc/sys/vm/drop_caches; ./symlinkat name /mnt/test > symlinkat name /mnt/test failed: File exists (17) > > Although I'm no kernel expert, from what I've understood of the kernel > code this seems to be a bad interaction between the generic fs handling in > fs/namei.c and the NFS client implementation. The filename_create() > function will call __lookup_hash() after setting LOOKUP_EXCL in the flags and > if there is no dentry cache for the path then nfs_lookup() will be called, will > notice this flag in the nfs_is_exclusive_create() test, optimize away the > lookup and not fill d_inode in the dentry. When execution returns to > filename_create() the special casing will notice that is_dir is not set and > last.name has a trailing slash and thus returns ENOENT. Looking for > LOOKUP_EXCL usage in the kernel only NFS does this kind of optimization in > current kernels, but in 3.5 and older the same optimization was also done by > CIFS. > > According to the symlink and symlinkat man pages ENOENT is returned when > a directory component of newpath does not exist or is a dangling symbolic > link, which is not the case here. > > What would be the best course of action to address this issue? > > Thanks, > > Diego > -- > Diego Santa Cruz, PhD > Technology Architect > spinetix.com -- Diego Santa Cruz, PhD Technology Architect spinetix.com