On Wed, 2023-08-02 at 09:29 -0700, dai.ngo@xxxxxxxxxx wrote:
On 8/1/23 6:33 AM, Jeff Layton wrote:It doesn't. The original open is to write the data for the file being
I noticed that xfstests generic/001 was failing against linux-next nfsd.not sure why the client opens the source file of a COPY operation with
The client would request a OPEN4_SHARE_ACCESS_WRITE open, and the server
would hand out a write delegation. The client would then try to use that
write delegation as the source stateid in a COPY
OPEN4_SHARE_ACCESS_WRITE?
copied. It then opens the file again for READ, but since it has a write
delegation, it doesn't need to talk to the server at all -- it can just
use that stateid for later operations.
The server must allow the client to use a write delegation for reador CLONE operation, andIf the server does not allow client to use write delegation for the
the server would respond with NFS4ERR_STALE.
READ, should the correct error return be NFS4ERR_OPENMODE?
operations. It's required by the spec, AFAIU.
The error in this case was just bogus. The vfs copy routine would return
-EBADF since the file didn't have FMODE_READ, and the nfs server would
translate that into NFS4ERR_STALE.
Probably there is a better v4 error code that we could translate EBADF
to, but with this patch it shouldn't be a problem any longer.
Why? Per RFC 8881:The problem is that the struct file associated with the delegation doesDoes this mean OPEN4_SHARE_ACCESS_WRITE do not get a write delegation?
not necessarily have read permissions. It's handing out a write
delegation on what is effectively an O_WRONLY open. RFC 8881 states:
"An OPEN_DELEGATE_WRITE delegation allows the client to handle, on its
own, all opens."
Given that the client didn't request any read permissions, and that nfsd
didn't check for any, it seems wrong to give out a write delegation.
Only hand out a write delegation if we have a O_RDWR descriptor
available. If it fails to find an appropriate write descriptor, go
ahead and try for a read delegation if NFS4_SHARE_ACCESS_READ was
requested.
This fixes xfstest generic/001.
Closes: https://bugzilla.linux-nfs.org/show_bug.cgi?id=412
Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx>
---
Changes in v2:
- Rework the logic when finding struct file for the delegation. The
earlier patch might still have attached a O_WRONLY file to the deleg
in some cases, and could still have handed out a write delegation on
an O_WRONLY OPEN request in some cases.
---
fs/nfsd/nfs4state.c | 29 ++++++++++++++++++-----------
1 file changed, 18 insertions(+), 11 deletions(-)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index ef7118ebee00..e79d82fd05e7 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5449,7 +5449,7 @@ nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
struct nfs4_file *fp = stp->st_stid.sc_file;
struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate;
struct nfs4_delegation *dp;
- struct nfsd_file *nf;
+ struct nfsd_file *nf = NULL;
struct file_lock *fl;
u32 dl_type;
@@ -5461,21 +5461,28 @@ nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
if (fp->fi_had_conflict)
return ERR_PTR(-EAGAIN);
- if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) {
- nf = find_writeable_file(fp);
+ /*
+ * Try for a write delegation first. We need an O_RDWR file
+ * since a write delegation allows the client to perform any open
+ * from its cache.
+ */
+ if ((open->op_share_access & NFS4_SHARE_ACCESS_BOTH) == NFS4_SHARE_ACCESS_BOTH) {
+ nf = nfsd_file_get(fp->fi_fds[O_RDWR]);
dl_type = NFS4_OPEN_DELEGATE_WRITE;
- } else {
It does not seem right.
-Dai
"An OPEN_DELEGATE_WRITE delegation allows the client to handle, on its
own, all opens."
All opens. That includes read opens.
An OPEN4_SHARE_ACCESS_WRITE open will succeed on a file to which the
user has no read permissions. Therefore, we can't grant a write
delegation since can't guarantee that the user is allowed to do that.
+ }
+
+ /*
+ * If the file is being opened O_RDONLY or we couldn't get a O_RDWR
+ * file for some reason, then try for a read deleg instead.
+ */
+ if (!nf && (open->op_share_access & NFS4_SHARE_ACCESS_READ)) {
nf = find_readable_file(fp);
dl_type = NFS4_OPEN_DELEGATE_READ;
}
- if (!nf) {
- /*
- * We probably could attempt another open and get a read
- * delegation, but for now, don't bother until the
- * client actually sends us one.
- */
+
+ if (!nf)
return ERR_PTR(-EAGAIN);
- }
+
spin_lock(&state_lock);
spin_lock(&fp->fi_lock);
if (nfs4_delegation_exists(clp, fp))
---
base-commit: a734662572708cf062e974f659ae50c24fc1ad17
change-id: 20230731-wdeleg-bbdb6b25a3c6
Best regards,