NFS bug (2.1.49): nfs_symlink() broken

Claus-Justus Heine (Heine@physik.rwth-aachen.de)
16 Aug 1997 18:21:15 +0200


The following has already been posted to this list by me. The bug is
still there in 2.1.50, and the patch included below still fixes it.

Hi!

There is a bug in fs/nfs/dir.c, in the function nfs_symlink(). The
problem is, that "nfs_proc_symlink()" does NOT return the file
attributes of the symlink created on the server side, and
"nfs_symlink()" tries to do a "nfs_fhget()" with those un-initialized
"fattr" variable. Thus, trying a

ln -s /tmp/foo /tmp/fii
ls -l /tmp

creates really _funny_ results. The patch below "fixes" the
problem.

On a first glimpse, I tried to call nfs_fhget() with the fattr
argument set to NULL, which results in nfs_fhget() trying to fetch the
file attributes from the server, but that didn't work.

What did work was a call to "nfs_lookup()" for the newly created
symlink. Now, the patch below simply drops the dentry for the newly
created symlink, which effectively results in calling nfs_lookup()
later, as the cached lookup of the dentry will fail after the d_drop().

Maybe my fix is broken, but it seems to work.

Cheers

Claus

--- linux-2.1.49/fs/nfs/dir.c Thu Aug 14 02:40:23 1997
+++ linux-2.1.49-nfs-swap/fs/nfs/dir.c Thu Aug 14 01:57:43 1997
@@ -555,9 +564,6 @@
static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{
struct nfs_sattr sattr;
- struct nfs_fattr fattr;
- struct nfs_fh fhandle;
- struct inode * inode;
int error;

dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
@@ -584,12 +590,16 @@
if (error)
return error;

- inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
- if (!inode)
- return -EACCES;
-
nfs_invalidate_dircache(dir);
- d_instantiate(dentry, inode);
+ /* this looks _funny_ doesn't it? But: nfs_proc_symlynk()
+ * only fills in sattr, not fattr. Thus nfs_fhget() cannot be
+ * called, it would be pointless, without a valid fattr
+ * argument. Other possibility: call nfs_proc_lookup()
+ * HERE. But why? If somebody wants to reference this
+ * symlink, the cached_lookup() will fail, and
+ * nfs_proc_symlink() will be called anyway.
+ */
+ d_drop(dentry);
return 0;
}