NFS problems?

Matt Brown (matt@eigen.co.uk)
Thu, 14 Aug 1997 17:43:01 +0100


I wrote earlier:
> I sent a quick mail a few days ago to this list about NFS problems I
> was experiencing, without much detail as I hadn't time to look into
> it. I've now got a bit more information, so here it is. I don't
> unfortunately know much about how NFS works, so I can't tell what
> causes the problem.

Having had more time today than I thought I'd have, I've tracked down
the problem.

It's all caused by the bizarre mode that RCS 'ci' opens its lock file
with, and the interactions of that with NFS's stateless protocol. 'ci'
uses

open(lockfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0444);

Note the redundant use of O_TRUNC with O_EXCL; if the function can
only succeed if there's no existing file, why truncate it? The file
will already be zero length. Note also the creation of a file without
write permission (mode 0444) but specifying O_WRONLY.

After entering sys_open and then do_open, control passes into the
function open_namei in namei.c. Here's the important bits (code
abridged to an outline for clarity).

struct dentry * open_namei(const char * pathname, int flag, int mode)
{
...
if (flag & O_CREAT) {
if (dentry->d_inode) {
...
} else if (IS_RDONLY(dir))
...
else if (!dir->i_op || !dir->i_op->create)
...
else if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) == 0) {
...
created here -> error = dir->i_op->create(dir, dentry, mode);
...
}
if (error)
goto exit;
}
...
if (flag & O_TRUNC) {
...
if (!error) {
...
fails here-> error = do_truncate(inode, 0);
}
if (error)
goto exit;
} else
...
exit:
dput(dentry);
return ERR_PTR(error);
}

As you can see, the code attempts to do the truncate *even though the
combination of O_CREAT|O_EXCL means the file is guaranteed to be zero
length anyway*. This causes no problem with local filesystems -- the
open mode is not examined in do_truncate for them, since we already
have an open inode -- but on an NFS filesystem, permission to alter
the length of the file is checked on the remote system. Since the
file is mode 444, this is of course denied since the user does not
have write access.

So the problem is due to:
1) Bizarre open modes
2) open_namei() not looking for O_CREAT|O_EXCL before trying to
truncate
3) Permission to change a file's length checked despite the fact
that the length is not going to change
4) Stateless nature of NFS means that the only way to check whether
the user is allowed to truncate the file is to look at the current
open modes -- even though on a local filesystem, only the modes in
effect *at the time of opening* would matter.

Opinions, please -- where's the best place to fix this?

-Matt