Skip to content

Commit

Permalink
NFSv4: fix open failure with O_ACCMODE flag
Browse files Browse the repository at this point in the history
open() with O_ACCMODE|O_DIRECT flags secondly will fail.

Reproducer:
  1. mount -t nfs -o vers=4.2 $server_ip:/ /mnt/
  2. fd = open("/mnt/file", O_ACCMODE|O_DIRECT|O_CREAT)
  3. close(fd)
  4. fd = open("/mnt/file", O_ACCMODE|O_DIRECT)

Server nfsd4_decode_share_access() will fail with error nfserr_bad_xdr when
client use incorrect share access mode of 0.

Fix this by using NFS4_SHARE_ACCESS_BOTH share access mode in client,
just like firstly opening.

Fixes: ce4ef7c ("NFS: Split out NFS v4 file operations")
Signed-off-by: ChenXiaoSong <chenxiaosong2@huawei.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
  • Loading branch information
ChenXiaoSong authored and Trond Myklebust committed Mar 30, 2022
1 parent ab0fc21 commit b243874
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 12 deletions.
10 changes: 0 additions & 10 deletions fs/nfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1991,16 +1991,6 @@ const struct dentry_operations nfs4_dentry_operations = {
};
EXPORT_SYMBOL_GPL(nfs4_dentry_operations);

static fmode_t flags_to_mode(int flags)
{
fmode_t res = (__force fmode_t)flags & FMODE_EXEC;
if ((flags & O_ACCMODE) != O_WRONLY)
res |= FMODE_READ;
if ((flags & O_ACCMODE) != O_RDONLY)
res |= FMODE_WRITE;
return res;
}

static struct nfs_open_context *create_nfs_open_context(struct dentry *dentry, int open_flags, struct file *filp)
{
return alloc_nfs_open_context(dentry, flags_to_mode(open_flags), filp);
Expand Down
10 changes: 10 additions & 0 deletions fs/nfs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ static inline bool nfs_lookup_is_soft_revalidate(const struct dentry *dentry)
return true;
}

static inline fmode_t flags_to_mode(int flags)
{
fmode_t res = (__force fmode_t)flags & FMODE_EXEC;
if ((flags & O_ACCMODE) != O_WRONLY)
res |= FMODE_READ;
if ((flags & O_ACCMODE) != O_RDONLY)
res |= FMODE_WRITE;
return res;
}

/*
* Note: RFC 1813 doesn't limit the number of auth flavors that
* a server can return, so make something up.
Expand Down
6 changes: 4 additions & 2 deletions fs/nfs/nfs4file.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ nfs4_file_open(struct inode *inode, struct file *filp)
struct dentry *parent = NULL;
struct inode *dir;
unsigned openflags = filp->f_flags;
fmode_t f_mode;
struct iattr attr;
int err;

Expand All @@ -50,16 +51,17 @@ nfs4_file_open(struct inode *inode, struct file *filp)
if (err)
return err;

f_mode = filp->f_mode;
if ((openflags & O_ACCMODE) == 3)
openflags--;
f_mode |= flags_to_mode(openflags);

/* We can't create new files here */
openflags &= ~(O_CREAT|O_EXCL);

parent = dget_parent(dentry);
dir = d_inode(parent);

ctx = alloc_nfs_open_context(file_dentry(filp), filp->f_mode, filp);
ctx = alloc_nfs_open_context(file_dentry(filp), f_mode, filp);
err = PTR_ERR(ctx);
if (IS_ERR(ctx))
goto out;
Expand Down

0 comments on commit b243874

Please sign in to comment.