* [PATCH v2 1/7] nfsd: add pragma public to delegated timestamp types
2024-08-26 12:46 [PATCH v2 0/7] nfsd: implement the "delstid" draft Jeff Layton
@ 2024-08-26 12:46 ` Jeff Layton
2024-08-26 12:46 ` [PATCH v2 2/7] nfs_common: make nfs4.h include generated nfs4_1.h Jeff Layton
` (5 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Jeff Layton @ 2024-08-26 12:46 UTC (permalink / raw)
To: Chuck Lever, Neil Brown, Olga Kornievskaia, Dai Ngo, Tom Talpey,
Trond Myklebust, Anna Schumaker, Olga Kornievskaia,
Alexander Viro, Christian Brauner, Jan Kara, Jonathan Corbet
Cc: Tom Haynes, linux-kernel, linux-nfs, linux-fsdevel, linux-doc,
Jeff Layton
In a later patch we're going to need the ability to decode the delegated
timestamp fields. Make the decoders available for the delgated
timestamp types, and regenerate the source and header files.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
fs/nfsd/nfs4_1.x | 2 ++
fs/nfsd/nfs4xdr_gen.c | 10 +++++-----
fs/nfsd/nfs4xdr_gen.h | 8 +++++++-
3 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/fs/nfsd/nfs4_1.x b/fs/nfsd/nfs4_1.x
index d2fde450de5e..fc37d1ecba0f 100644
--- a/fs/nfsd/nfs4_1.x
+++ b/fs/nfsd/nfs4_1.x
@@ -150,6 +150,8 @@ const OPEN4_RESULT_NO_OPEN_STATEID = 0x00000010;
*/
typedef nfstime4 fattr4_time_deleg_access;
typedef nfstime4 fattr4_time_deleg_modify;
+pragma public fattr4_time_deleg_access;
+pragma public fattr4_time_deleg_modify;
%/*
diff --git a/fs/nfsd/nfs4xdr_gen.c b/fs/nfsd/nfs4xdr_gen.c
index c22372144a57..0816cfa530e0 100644
--- a/fs/nfsd/nfs4xdr_gen.c
+++ b/fs/nfsd/nfs4xdr_gen.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
// Generated by xdrgen. Manual edits will be lost.
-// XDR specification modification time: Fri Aug 23 17:28:09 2024
+// XDR specification modification time: Fri Aug 23 18:57:46 2024
#include "nfs4xdr_gen.h"
@@ -120,13 +120,13 @@ xdrgen_decode_fattr4_open_arguments(struct xdr_stream *xdr, fattr4_open_argument
return xdrgen_decode_open_arguments4(xdr, ptr);
};
-static bool __maybe_unused
+bool
xdrgen_decode_fattr4_time_deleg_access(struct xdr_stream *xdr, fattr4_time_deleg_access *ptr)
{
return xdrgen_decode_nfstime4(xdr, ptr);
};
-static bool __maybe_unused
+bool
xdrgen_decode_fattr4_time_deleg_modify(struct xdr_stream *xdr, fattr4_time_deleg_modify *ptr)
{
return xdrgen_decode_nfstime4(xdr, ptr);
@@ -223,13 +223,13 @@ xdrgen_encode_fattr4_open_arguments(struct xdr_stream *xdr, const fattr4_open_ar
return xdrgen_encode_open_arguments4(xdr, value);
};
-static bool __maybe_unused
+bool
xdrgen_encode_fattr4_time_deleg_access(struct xdr_stream *xdr, const fattr4_time_deleg_access *value)
{
return xdrgen_encode_nfstime4(xdr, value);
};
-static bool __maybe_unused
+bool
xdrgen_encode_fattr4_time_deleg_modify(struct xdr_stream *xdr, const fattr4_time_deleg_modify *value)
{
return xdrgen_encode_nfstime4(xdr, value);
diff --git a/fs/nfsd/nfs4xdr_gen.h b/fs/nfsd/nfs4xdr_gen.h
index 48da108a2427..e79935f973ff 100644
--- a/fs/nfsd/nfs4xdr_gen.h
+++ b/fs/nfsd/nfs4xdr_gen.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Generated by xdrgen. Manual edits will be lost. */
-/* XDR specification modification time: Fri Aug 23 17:28:09 2024 */
+/* XDR specification modification time: Fri Aug 23 18:57:46 2024 */
#ifndef _LINUX_NFS4_XDRGEN_H
#define _LINUX_NFS4_XDRGEN_H
@@ -88,8 +88,14 @@ enum { OPEN4_SHARE_ACCESS_WANT_OPEN_XOR_DELEGATION = 0x200000 };
enum { OPEN4_RESULT_NO_OPEN_STATEID = 0x00000010 };
typedef struct nfstime4 fattr4_time_deleg_access;
+bool xdrgen_decode_fattr4_time_deleg_access(struct xdr_stream *xdr, fattr4_time_deleg_access *ptr);
+bool xdrgen_encode_fattr4_time_deleg_access(struct xdr_stream *xdr, const fattr4_time_deleg_access *value);
+
typedef struct nfstime4 fattr4_time_deleg_modify;
+bool xdrgen_decode_fattr4_time_deleg_modify(struct xdr_stream *xdr, fattr4_time_deleg_modify *ptr);
+bool xdrgen_encode_fattr4_time_deleg_modify(struct xdr_stream *xdr, const fattr4_time_deleg_modify *value);
+
enum { FATTR4_TIME_DELEG_ACCESS = 84 };
--
2.46.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v2 2/7] nfs_common: make nfs4.h include generated nfs4_1.h
2024-08-26 12:46 [PATCH v2 0/7] nfsd: implement the "delstid" draft Jeff Layton
2024-08-26 12:46 ` [PATCH v2 1/7] nfsd: add pragma public to delegated timestamp types Jeff Layton
@ 2024-08-26 12:46 ` Jeff Layton
2024-08-26 12:46 ` [PATCH v2 3/7] nfsd: add support for FATTR4_OPEN_ARGUMENTS Jeff Layton
` (4 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Jeff Layton @ 2024-08-26 12:46 UTC (permalink / raw)
To: Chuck Lever, Neil Brown, Olga Kornievskaia, Dai Ngo, Tom Talpey,
Trond Myklebust, Anna Schumaker, Olga Kornievskaia,
Alexander Viro, Christian Brauner, Jan Kara, Jonathan Corbet
Cc: Tom Haynes, linux-kernel, linux-nfs, linux-fsdevel, linux-doc,
Jeff Layton
Long term, we'd like to move to autogenerating a lot of our XDR code.
Both the client and server include include/linux/nfs4.h. That file is
hand-rolled and some of the symbols in it conflict with the
autogenerated symbols from the spec.
Move nfs4_1.x to Documentation/sunrpc/xdr. Create a new
include/linux/sunrpc/xdrgen directory in which we can keep autogenerated
header files. Move the new, generated nfs4xdr_gen.h file to nfs4_1.h in
that directory. Have include/linux/nfs4.h include the newly renamed file
and then remove conflicting definitions from it and nfs_xdr.h.
For now, the .x file from which we're generating the header is fairly
small and just covers the delstid draft, but we can expand that in the
future and just remove conflicting definitions as we go.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
{fs/nfsd => Documentation/sunrpc/xdr}/nfs4_1.x | 0
fs/nfsd/nfs4xdr_gen.c | 2 +-
include/linux/nfs4.h | 7 +------
include/linux/nfs_xdr.h | 5 -----
fs/nfsd/nfs4xdr_gen.h => include/linux/sunrpc/xdrgen/nfs4_1.h | 6 +++---
5 files changed, 5 insertions(+), 15 deletions(-)
diff --git a/fs/nfsd/nfs4_1.x b/Documentation/sunrpc/xdr/nfs4_1.x
similarity index 100%
rename from fs/nfsd/nfs4_1.x
rename to Documentation/sunrpc/xdr/nfs4_1.x
diff --git a/fs/nfsd/nfs4xdr_gen.c b/fs/nfsd/nfs4xdr_gen.c
index 0816cfa530e0..3e55dd1e6530 100644
--- a/fs/nfsd/nfs4xdr_gen.c
+++ b/fs/nfsd/nfs4xdr_gen.c
@@ -2,7 +2,7 @@
// Generated by xdrgen. Manual edits will be lost.
// XDR specification modification time: Fri Aug 23 18:57:46 2024
-#include "nfs4xdr_gen.h"
+#include <linux/sunrpc/xdrgen/nfs4.h>
static bool __maybe_unused
xdrgen_decode_int64_t(struct xdr_stream *xdr, int64_t *ptr)
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 8d7430d9f218..b90719244775 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -17,6 +17,7 @@
#include <linux/uidgid.h>
#include <uapi/linux/nfs4.h>
#include <linux/sunrpc/msg_prot.h>
+#include <linux/sunrpc/xdrgen/nfs4_1.h>
enum nfs4_acl_whotype {
NFS4_ACL_WHO_NAMED = 0,
@@ -512,12 +513,6 @@ enum {
FATTR4_XATTR_SUPPORT = 82,
};
-enum {
- FATTR4_TIME_DELEG_ACCESS = 84,
- FATTR4_TIME_DELEG_MODIFY = 85,
- FATTR4_OPEN_ARGUMENTS = 86,
-};
-
/*
* The following internal definitions enable processing the above
* attribute bits within 32-bit word boundaries.
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 45623af3e7b8..d3fe47baf110 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1315,11 +1315,6 @@ struct nfs4_fsid_present_res {
#endif /* CONFIG_NFS_V4 */
-struct nfstime4 {
- u64 seconds;
- u32 nseconds;
-};
-
#ifdef CONFIG_NFS_V4_1
struct pnfs_commit_bucket {
diff --git a/fs/nfsd/nfs4xdr_gen.h b/include/linux/sunrpc/xdrgen/nfs4_1.h
similarity index 96%
rename from fs/nfsd/nfs4xdr_gen.h
rename to include/linux/sunrpc/xdrgen/nfs4_1.h
index e79935f973ff..0272c2ee8739 100644
--- a/fs/nfsd/nfs4xdr_gen.h
+++ b/include/linux/sunrpc/xdrgen/nfs4_1.h
@@ -2,8 +2,8 @@
/* Generated by xdrgen. Manual edits will be lost. */
/* XDR specification modification time: Fri Aug 23 18:57:46 2024 */
-#ifndef _LINUX_NFS4_XDRGEN_H
-#define _LINUX_NFS4_XDRGEN_H
+#ifndef _LINUX_XDRGEN_NFS4_H
+#define _LINUX_XDRGEN_NFS4_H
#include <linux/types.h>
#include <linux/sunrpc/svc.h>
@@ -103,4 +103,4 @@ enum { FATTR4_TIME_DELEG_MODIFY = 85 };
enum { OPEN4_SHARE_ACCESS_WANT_DELEG_TIMESTAMPS = 0x100000 };
-#endif /* _LINUX_NFS4_XDRGEN_H */
+#endif /* _LINUX_XDRGEN_NFS4_H */
--
2.46.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v2 3/7] nfsd: add support for FATTR4_OPEN_ARGUMENTS
2024-08-26 12:46 [PATCH v2 0/7] nfsd: implement the "delstid" draft Jeff Layton
2024-08-26 12:46 ` [PATCH v2 1/7] nfsd: add pragma public to delegated timestamp types Jeff Layton
2024-08-26 12:46 ` [PATCH v2 2/7] nfs_common: make nfs4.h include generated nfs4_1.h Jeff Layton
@ 2024-08-26 12:46 ` Jeff Layton
2024-08-26 12:46 ` [PATCH v2 4/7] nfsd: implement OPEN_ARGS_SHARE_ACCESS_WANT_OPEN_XOR_DELEGATION Jeff Layton
` (3 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Jeff Layton @ 2024-08-26 12:46 UTC (permalink / raw)
To: Chuck Lever, Neil Brown, Olga Kornievskaia, Dai Ngo, Tom Talpey,
Trond Myklebust, Anna Schumaker, Olga Kornievskaia,
Alexander Viro, Christian Brauner, Jan Kara, Jonathan Corbet
Cc: Tom Haynes, linux-kernel, linux-nfs, linux-fsdevel, linux-doc,
Jeff Layton
Add support for FATTR4_OPEN_ARGUMENTS. This a new mechanism for the
client to discover what OPEN features the server supports.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
fs/nfsd/Makefile | 2 +-
fs/nfsd/nfs4xdr.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
fs/nfsd/nfsd.h | 3 ++-
3 files changed, 52 insertions(+), 2 deletions(-)
diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile
index b8736a82e57c..d6ab3ae7d0a0 100644
--- a/fs/nfsd/Makefile
+++ b/fs/nfsd/Makefile
@@ -18,7 +18,7 @@ nfsd-$(CONFIG_NFSD_V2) += nfsproc.o nfsxdr.o
nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o
nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
- nfs4acl.o nfs4callback.o nfs4recover.o
+ nfs4acl.o nfs4callback.o nfs4recover.o nfs4xdr_gen.o
nfsd-$(CONFIG_NFSD_PNFS) += nfs4layouts.o
nfsd-$(CONFIG_NFSD_BLOCKLAYOUT) += blocklayout.o blocklayoutxdr.o
nfsd-$(CONFIG_NFSD_SCSILAYOUT) += blocklayout.o blocklayoutxdr.o
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index f118921250c3..1c8219ea8af7 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3399,6 +3399,54 @@ static __be32 nfsd4_encode_fattr4_xattr_support(struct xdr_stream *xdr,
return nfsd4_encode_bool(xdr, err == 0);
}
+#define NFSD_OA_SHARE_ACCESS (BIT(OPEN_ARGS_SHARE_ACCESS_READ) | \
+ BIT(OPEN_ARGS_SHARE_ACCESS_WRITE) | \
+ BIT(OPEN_ARGS_SHARE_ACCESS_BOTH))
+
+#define NFSD_OA_SHARE_DENY (BIT(OPEN_ARGS_SHARE_DENY_NONE) | \
+ BIT(OPEN_ARGS_SHARE_DENY_READ) | \
+ BIT(OPEN_ARGS_SHARE_DENY_WRITE) | \
+ BIT(OPEN_ARGS_SHARE_DENY_BOTH))
+
+#define NFSD_OA_SHARE_ACCESS_WANT (BIT(OPEN_ARGS_SHARE_ACCESS_WANT_ANY_DELEG) | \
+ BIT(OPEN_ARGS_SHARE_ACCESS_WANT_NO_DELEG) | \
+ BIT(OPEN_ARGS_SHARE_ACCESS_WANT_CANCEL))
+
+#define NFSD_OA_OPEN_CLAIM (BIT(OPEN_ARGS_OPEN_CLAIM_NULL) | \
+ BIT(OPEN_ARGS_OPEN_CLAIM_PREVIOUS) | \
+ BIT(OPEN_ARGS_OPEN_CLAIM_DELEGATE_CUR) | \
+ BIT(OPEN_ARGS_OPEN_CLAIM_DELEGATE_PREV)| \
+ BIT(OPEN_ARGS_OPEN_CLAIM_FH) | \
+ BIT(OPEN_ARGS_OPEN_CLAIM_DELEG_CUR_FH) | \
+ BIT(OPEN_ARGS_OPEN_CLAIM_DELEG_PREV_FH))
+
+#define NFSD_OA_CREATE_MODE (BIT(OPEN_ARGS_CREATEMODE_UNCHECKED4) | \
+ BIT(OPEN_ARGS_CREATE_MODE_GUARDED) | \
+ BIT(OPEN_ARGS_CREATEMODE_EXCLUSIVE4) | \
+ BIT(OPEN_ARGS_CREATE_MODE_EXCLUSIVE4_1))
+
+static uint32_t oa_share_access = NFSD_OA_SHARE_ACCESS;
+static uint32_t oa_share_deny = NFSD_OA_SHARE_DENY;
+static uint32_t oa_share_access_want = NFSD_OA_SHARE_ACCESS_WANT;
+static uint32_t oa_open_claim = NFSD_OA_OPEN_CLAIM;
+static uint32_t oa_create_mode = NFSD_OA_CREATE_MODE;
+
+static const struct open_arguments4 nfsd_open_arguments = {
+ .oa_share_access = { .count = 1, .element = &oa_share_access },
+ .oa_share_deny = { .count = 1, .element = &oa_share_deny },
+ .oa_share_access_want = { .count = 1, .element = &oa_share_access_want },
+ .oa_open_claim = { .count = 1, .element = &oa_open_claim },
+ .oa_create_mode = { .count = 1, .element = &oa_create_mode },
+};
+
+static __be32 nfsd4_encode_fattr4_open_arguments(struct xdr_stream *xdr,
+ const struct nfsd4_fattr_args *args)
+{
+ if (!xdrgen_encode_fattr4_open_arguments(xdr, &nfsd_open_arguments))
+ return nfserr_resource;
+ return nfs_ok;
+}
+
static const nfsd4_enc_attr nfsd4_enc_fattr4_encode_ops[] = {
[FATTR4_SUPPORTED_ATTRS] = nfsd4_encode_fattr4_supported_attrs,
[FATTR4_TYPE] = nfsd4_encode_fattr4_type,
@@ -3499,6 +3547,7 @@ static const nfsd4_enc_attr nfsd4_enc_fattr4_encode_ops[] = {
[FATTR4_MODE_UMASK] = nfsd4_encode_fattr4__noop,
[FATTR4_XATTR_SUPPORT] = nfsd4_encode_fattr4_xattr_support,
+ [FATTR4_OPEN_ARGUMENTS] = nfsd4_encode_fattr4_open_arguments,
};
/*
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 4ccbf014a2c7..c98fb104ba7d 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -454,7 +454,8 @@ enum {
(NFSD4_1_SUPPORTED_ATTRS_WORD2 | \
FATTR4_WORD2_MODE_UMASK | \
NFSD4_2_SECURITY_ATTRS | \
- FATTR4_WORD2_XATTR_SUPPORT)
+ FATTR4_WORD2_XATTR_SUPPORT | \
+ FATTR4_WORD2_OPEN_ARGUMENTS)
extern const u32 nfsd_suppattrs[3][3];
--
2.46.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v2 4/7] nfsd: implement OPEN_ARGS_SHARE_ACCESS_WANT_OPEN_XOR_DELEGATION
2024-08-26 12:46 [PATCH v2 0/7] nfsd: implement the "delstid" draft Jeff Layton
` (2 preceding siblings ...)
2024-08-26 12:46 ` [PATCH v2 3/7] nfsd: add support for FATTR4_OPEN_ARGUMENTS Jeff Layton
@ 2024-08-26 12:46 ` Jeff Layton
2024-08-26 12:46 ` [PATCH v2 5/7] fs: add an ATTR_CTIME_DLG flag Jeff Layton
` (2 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Jeff Layton @ 2024-08-26 12:46 UTC (permalink / raw)
To: Chuck Lever, Neil Brown, Olga Kornievskaia, Dai Ngo, Tom Talpey,
Trond Myklebust, Anna Schumaker, Olga Kornievskaia,
Alexander Viro, Christian Brauner, Jan Kara, Jonathan Corbet
Cc: Tom Haynes, linux-kernel, linux-nfs, linux-fsdevel, linux-doc,
Jeff Layton
Allow clients to request getting a delegation xor an open stateid if a
delegation isn't available. This allows the client to avoid sending a
final CLOSE for the (useless) open stateid, when it is granted a
delegation.
This is done by moving the increment of the open stateid and unlocking
of the st_mutex until after we acquire a delegation. If we get a
delegation, we zero out the op_stateid field and set the NO_OPEN_STATEID
flag. If the open stateid was brand new, then unhash it too in this case
since it won't be needed.
If we can't get a delegation or the new flag wasn't requested, then just
increment and copy the open stateid as usual.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
fs/nfsd/nfs4state.c | 28 ++++++++++++++++++++++++----
fs/nfsd/nfs4xdr.c | 5 +++--
include/uapi/linux/nfs4.h | 7 +++++--
3 files changed, 32 insertions(+), 8 deletions(-)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 9fe67c412f9b..b544320246bf 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -6029,6 +6029,17 @@ static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open,
*/
}
+/* Are we only returning a delegation stateid? */
+static bool open_xor_delegation(struct nfsd4_open *open)
+{
+ if (!(open->op_deleg_want & OPEN4_SHARE_ACCESS_WANT_OPEN_XOR_DELEGATION))
+ return false;
+ if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ &&
+ open->op_delegate_type != NFS4_OPEN_DELEGATE_WRITE)
+ return false;
+ return true;
+}
+
/**
* nfsd4_process_open2 - finish open processing
* @rqstp: the RPC transaction being executed
@@ -6051,6 +6062,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
struct nfs4_delegation *dp = NULL;
__be32 status;
bool new_stp = false;
+ bool deleg_only = false;
/*
* Lookup file; if found, lookup stateid and check open request,
@@ -6105,9 +6117,6 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
open->op_odstate = NULL;
}
- nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid);
- mutex_unlock(&stp->st_mutex);
-
if (nfsd4_has_session(&resp->cstate)) {
if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) {
open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
@@ -6121,7 +6130,18 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
* OPEN succeeds even if we fail.
*/
nfs4_open_delegation(open, stp, &resp->cstate.current_fh);
+ deleg_only = open_xor_delegation(open);
nodeleg:
+ if (deleg_only) {
+ memcpy(&open->op_stateid, &zero_stateid, sizeof(open->op_stateid));
+ open->op_rflags |= OPEN4_RESULT_NO_OPEN_STATEID;
+ if (new_stp)
+ release_open_stateid(stp);
+ } else {
+ nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid);
+ }
+ mutex_unlock(&stp->st_mutex);
+
status = nfs_ok;
trace_nfsd_open(&stp->st_stid.sc_stateid);
out:
@@ -6137,7 +6157,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
/*
* To finish the open response, we just need to set the rflags.
*/
- open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX;
+ open->op_rflags |= NFS4_OPEN_RESULT_LOCKTYPE_POSIX;
if (nfsd4_has_session(&resp->cstate))
open->op_rflags |= NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK;
else if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED))
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 1c8219ea8af7..8266f910d847 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1066,7 +1066,7 @@ static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *sh
return nfs_ok;
if (!argp->minorversion)
return nfserr_bad_xdr;
- switch (w & NFS4_SHARE_WANT_MASK) {
+ switch (w & NFS4_SHARE_WANT_TYPE_MASK) {
case NFS4_SHARE_WANT_NO_PREFERENCE:
case NFS4_SHARE_WANT_READ_DELEG:
case NFS4_SHARE_WANT_WRITE_DELEG:
@@ -3410,7 +3410,8 @@ static __be32 nfsd4_encode_fattr4_xattr_support(struct xdr_stream *xdr,
#define NFSD_OA_SHARE_ACCESS_WANT (BIT(OPEN_ARGS_SHARE_ACCESS_WANT_ANY_DELEG) | \
BIT(OPEN_ARGS_SHARE_ACCESS_WANT_NO_DELEG) | \
- BIT(OPEN_ARGS_SHARE_ACCESS_WANT_CANCEL))
+ BIT(OPEN_ARGS_SHARE_ACCESS_WANT_CANCEL) | \
+ BIT(OPEN_ARGS_SHARE_ACCESS_WANT_OPEN_XOR_DELEGATION))
#define NFSD_OA_OPEN_CLAIM (BIT(OPEN_ARGS_OPEN_CLAIM_NULL) | \
BIT(OPEN_ARGS_OPEN_CLAIM_PREVIOUS) | \
diff --git a/include/uapi/linux/nfs4.h b/include/uapi/linux/nfs4.h
index caf4db2fcbb9..4273e0249fcb 100644
--- a/include/uapi/linux/nfs4.h
+++ b/include/uapi/linux/nfs4.h
@@ -58,7 +58,7 @@
#define NFS4_SHARE_DENY_BOTH 0x0003
/* nfs41 */
-#define NFS4_SHARE_WANT_MASK 0xFF00
+#define NFS4_SHARE_WANT_TYPE_MASK 0xFF00
#define NFS4_SHARE_WANT_NO_PREFERENCE 0x0000
#define NFS4_SHARE_WANT_READ_DELEG 0x0100
#define NFS4_SHARE_WANT_WRITE_DELEG 0x0200
@@ -66,13 +66,16 @@
#define NFS4_SHARE_WANT_NO_DELEG 0x0400
#define NFS4_SHARE_WANT_CANCEL 0x0500
-#define NFS4_SHARE_WHEN_MASK 0xF0000
+#define NFS4_SHARE_WHEN_MASK 0xF0000
#define NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL 0x10000
#define NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED 0x20000
+#define NFS4_SHARE_WANT_MOD_MASK 0xF00000
#define NFS4_SHARE_WANT_DELEG_TIMESTAMPS 0x100000
#define NFS4_SHARE_WANT_OPEN_XOR_DELEGATION 0x200000
+#define NFS4_SHARE_WANT_MASK (NFS4_SHARE_WANT_TYPE_MASK | NFS4_SHARE_WANT_MOD_MASK)
+
#define NFS4_CDFC4_FORE 0x1
#define NFS4_CDFC4_BACK 0x2
#define NFS4_CDFC4_BOTH 0x3
--
2.46.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v2 5/7] fs: add an ATTR_CTIME_DLG flag
2024-08-26 12:46 [PATCH v2 0/7] nfsd: implement the "delstid" draft Jeff Layton
` (3 preceding siblings ...)
2024-08-26 12:46 ` [PATCH v2 4/7] nfsd: implement OPEN_ARGS_SHARE_ACCESS_WANT_OPEN_XOR_DELEGATION Jeff Layton
@ 2024-08-26 12:46 ` Jeff Layton
2024-08-26 13:08 ` Christian Brauner
2024-08-26 12:46 ` [PATCH v2 6/7] nfsd: drop the ncf_cb_bmap field Jeff Layton
2024-08-26 12:46 ` [PATCH v2 7/7] nfsd: add support for delegated timestamps Jeff Layton
6 siblings, 1 reply; 10+ messages in thread
From: Jeff Layton @ 2024-08-26 12:46 UTC (permalink / raw)
To: Chuck Lever, Neil Brown, Olga Kornievskaia, Dai Ngo, Tom Talpey,
Trond Myklebust, Anna Schumaker, Olga Kornievskaia,
Alexander Viro, Christian Brauner, Jan Kara, Jonathan Corbet
Cc: Tom Haynes, linux-kernel, linux-nfs, linux-fsdevel, linux-doc,
Jeff Layton
When updating the ctime on an inode for a setattr with a multigrain
filesystem, we usually want to take the latest time we can get for the
ctime. The exception to this rule is when there is a nfsd write
delegation and the server is proxying timestamps from the client.
When nfsd gets a CB_GETATTR response, we want to update the timestamp
value in the inode to the values that the client is tracking. The client
doesn't send a ctime value (since that's always determined by the
exported filesystem), but it does send a mtime value. In the case where
it does, then we may also need to update the ctime to a value
commensurate with that.
Add a ATTR_CTIME_DELEG flag, which tells the underlying setattr
machinery to respect that value and not to set it to the current time.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
fs/attr.c | 10 +++++++++-
include/linux/fs.h | 1 +
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/fs/attr.c b/fs/attr.c
index 7144b207e715..0eb7b228b94d 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -295,7 +295,15 @@ static void setattr_copy_mgtime(struct inode *inode, const struct iattr *attr)
return;
}
- now = inode_set_ctime_current(inode);
+ /*
+ * In the case of an update for a write delegation, we must respect
+ * the value in ia_ctime and not use the current time.
+ */
+ if (ia_valid & ATTR_CTIME_DLG)
+ inode_set_ctime_to_ts(inode, attr->ia_ctime);
+ else
+ now = inode_set_ctime_current(inode);
+
if (ia_valid & ATTR_ATIME_SET)
inode_set_atime_to_ts(inode, attr->ia_atime);
else if (ia_valid & ATTR_ATIME)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 7c1da3c687bd..43a802b2cb0d 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -211,6 +211,7 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
#define ATTR_TIMES_SET (1 << 16)
#define ATTR_TOUCH (1 << 17)
#define ATTR_DELEG (1 << 18) /* Delegated attrs (don't break) */
+#define ATTR_CTIME_DLG (1 << 19) /* Delegation in effect */
/*
* Whiteout is represented by a char device. The following constants define the
--
2.46.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v2 5/7] fs: add an ATTR_CTIME_DLG flag
2024-08-26 12:46 ` [PATCH v2 5/7] fs: add an ATTR_CTIME_DLG flag Jeff Layton
@ 2024-08-26 13:08 ` Christian Brauner
2024-08-26 13:16 ` Jeff Layton
0 siblings, 1 reply; 10+ messages in thread
From: Christian Brauner @ 2024-08-26 13:08 UTC (permalink / raw)
To: Jeff Layton
Cc: Chuck Lever, Neil Brown, Olga Kornievskaia, Dai Ngo, Tom Talpey,
Trond Myklebust, Anna Schumaker, Olga Kornievskaia,
Alexander Viro, Jan Kara, Jonathan Corbet, Tom Haynes,
linux-kernel, linux-nfs, linux-fsdevel, linux-doc
On Mon, Aug 26, 2024 at 08:46:15AM GMT, Jeff Layton wrote:
> When updating the ctime on an inode for a setattr with a multigrain
> filesystem, we usually want to take the latest time we can get for the
> ctime. The exception to this rule is when there is a nfsd write
> delegation and the server is proxying timestamps from the client.
>
> When nfsd gets a CB_GETATTR response, we want to update the timestamp
> value in the inode to the values that the client is tracking. The client
> doesn't send a ctime value (since that's always determined by the
> exported filesystem), but it does send a mtime value. In the case where
> it does, then we may also need to update the ctime to a value
> commensurate with that.
>
> Add a ATTR_CTIME_DELEG flag, which tells the underlying setattr
Fwiw: disconnect between commit message and actually used ATTR_CTIME_DLG.
> machinery to respect that value and not to set it to the current time.
>
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
Are you set on sending us on a mission to free up ATTR_* bits after
freeing up FMODE_* bits? ;)
If there's going to be more ATTR_*DELEG* flags that modify the
behavior when delegation is in effect then we could consider adding
another unsigned int ia_deleg field to struct iattr so that you can check:
if (ia_valid & ATTR_CTIME) {
if (unlikely(iattr->ia_deleg & ATTR_CTIME))
// do some special stuff
else
// do the regular stuff
}
or some such variant.
> fs/attr.c | 10 +++++++++-
> include/linux/fs.h | 1 +
> 2 files changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/fs/attr.c b/fs/attr.c
> index 7144b207e715..0eb7b228b94d 100644
> --- a/fs/attr.c
> +++ b/fs/attr.c
> @@ -295,7 +295,15 @@ static void setattr_copy_mgtime(struct inode *inode, const struct iattr *attr)
> return;
> }
>
> - now = inode_set_ctime_current(inode);
> + /*
> + * In the case of an update for a write delegation, we must respect
> + * the value in ia_ctime and not use the current time.
> + */
> + if (ia_valid & ATTR_CTIME_DLG)
> + inode_set_ctime_to_ts(inode, attr->ia_ctime);
> + else
> + now = inode_set_ctime_current(inode);
> +
> if (ia_valid & ATTR_ATIME_SET)
> inode_set_atime_to_ts(inode, attr->ia_atime);
> else if (ia_valid & ATTR_ATIME)
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 7c1da3c687bd..43a802b2cb0d 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -211,6 +211,7 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
> #define ATTR_TIMES_SET (1 << 16)
> #define ATTR_TOUCH (1 << 17)
> #define ATTR_DELEG (1 << 18) /* Delegated attrs (don't break) */
> +#define ATTR_CTIME_DLG (1 << 19) /* Delegation in effect */
What's the interaction between ATTR_DELEG and ATTR_CTIME_DLG? I think
that's potentially confusing.
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v2 5/7] fs: add an ATTR_CTIME_DLG flag
2024-08-26 13:08 ` Christian Brauner
@ 2024-08-26 13:16 ` Jeff Layton
0 siblings, 0 replies; 10+ messages in thread
From: Jeff Layton @ 2024-08-26 13:16 UTC (permalink / raw)
To: Christian Brauner
Cc: Chuck Lever, Neil Brown, Olga Kornievskaia, Dai Ngo, Tom Talpey,
Trond Myklebust, Anna Schumaker, Olga Kornievskaia,
Alexander Viro, Jan Kara, Jonathan Corbet, Tom Haynes,
linux-kernel, linux-nfs, linux-fsdevel, linux-doc
On Mon, 2024-08-26 at 15:08 +0200, Christian Brauner wrote:
> On Mon, Aug 26, 2024 at 08:46:15AM GMT, Jeff Layton wrote:
> > When updating the ctime on an inode for a setattr with a multigrain
> > filesystem, we usually want to take the latest time we can get for the
> > ctime. The exception to this rule is when there is a nfsd write
> > delegation and the server is proxying timestamps from the client.
> >
> > When nfsd gets a CB_GETATTR response, we want to update the timestamp
> > value in the inode to the values that the client is tracking. The client
> > doesn't send a ctime value (since that's always determined by the
> > exported filesystem), but it does send a mtime value. In the case where
> > it does, then we may also need to update the ctime to a value
> > commensurate with that.
> >
> > Add a ATTR_CTIME_DELEG flag, which tells the underlying setattr
>
> Fwiw: disconnect between commit message and actually used ATTR_CTIME_DLG.
>
Thanks, will fix.
> > machinery to respect that value and not to set it to the current time.
> >
> > Signed-off-by: Jeff Layton <jlayton@kernel.org>
> > ---
>
> Are you set on sending us on a mission to free up ATTR_* bits after
> freeing up FMODE_* bits? ;)
>
Those aren't usually allocated from the heap, so I wouldn't bother, but
I get the jest.
> If there's going to be more ATTR_*DELEG* flags that modify the
> behavior when delegation is in effect then we could consider adding
> another unsigned int ia_deleg field to struct iattr so that you can check:
>
> if (ia_valid & ATTR_CTIME) {
> if (unlikely(iattr->ia_deleg & ATTR_CTIME))
> // do some special stuff
> else
> // do the regular stuff
> }
>
> or some such variant.
>
I don't forsee other flags being needed, but you never know. For now I
wouldn't bother.
> > fs/attr.c | 10 +++++++++-
> > include/linux/fs.h | 1 +
> > 2 files changed, 10 insertions(+), 1 deletion(-)
> >
> > diff --git a/fs/attr.c b/fs/attr.c
> > index 7144b207e715..0eb7b228b94d 100644
> > --- a/fs/attr.c
> > +++ b/fs/attr.c
> > @@ -295,7 +295,15 @@ static void setattr_copy_mgtime(struct inode *inode, const struct iattr *attr)
> > return;
> > }
> >
> > - now = inode_set_ctime_current(inode);
> > + /*
> > + * In the case of an update for a write delegation, we must respect
> > + * the value in ia_ctime and not use the current time.
> > + */
> > + if (ia_valid & ATTR_CTIME_DLG)
> > + inode_set_ctime_to_ts(inode, attr->ia_ctime);
> > + else
> > + now = inode_set_ctime_current(inode);
> > +
> > if (ia_valid & ATTR_ATIME_SET)
> > inode_set_atime_to_ts(inode, attr->ia_atime);
> > else if (ia_valid & ATTR_ATIME)
> > diff --git a/include/linux/fs.h b/include/linux/fs.h
> > index 7c1da3c687bd..43a802b2cb0d 100644
> > --- a/include/linux/fs.h
> > +++ b/include/linux/fs.h
> > @@ -211,6 +211,7 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
> > #define ATTR_TIMES_SET (1 << 16)
> > #define ATTR_TOUCH (1 << 17)
> > #define ATTR_DELEG (1 << 18) /* Delegated attrs (don't break) */
> > +#define ATTR_CTIME_DLG (1 << 19) /* Delegation in effect */
>
> What's the interaction between ATTR_DELEG and ATTR_CTIME_DLG? I think
> that's potentially confusing.
>
Now that you mention it, I suppose we could just key off of ATTR_DELEG
instead of declaring a new flag. That should be simpler to reason out
for everyone. I'll respin this along those lines instead.
Thanks for the review!
--
Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 6/7] nfsd: drop the ncf_cb_bmap field
2024-08-26 12:46 [PATCH v2 0/7] nfsd: implement the "delstid" draft Jeff Layton
` (4 preceding siblings ...)
2024-08-26 12:46 ` [PATCH v2 5/7] fs: add an ATTR_CTIME_DLG flag Jeff Layton
@ 2024-08-26 12:46 ` Jeff Layton
2024-08-26 12:46 ` [PATCH v2 7/7] nfsd: add support for delegated timestamps Jeff Layton
6 siblings, 0 replies; 10+ messages in thread
From: Jeff Layton @ 2024-08-26 12:46 UTC (permalink / raw)
To: Chuck Lever, Neil Brown, Olga Kornievskaia, Dai Ngo, Tom Talpey,
Trond Myklebust, Anna Schumaker, Olga Kornievskaia,
Alexander Viro, Christian Brauner, Jan Kara, Jonathan Corbet
Cc: Tom Haynes, linux-kernel, linux-nfs, linux-fsdevel, linux-doc,
Jeff Layton
This is always the same value, and in a later patch we're going to need
to set bits in WORD2. We can simplify this code and save a little space
in the delegation too. Just hardcode the bitmap in the callback encode
function.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
fs/nfsd/nfs4callback.c | 5 ++++-
fs/nfsd/nfs4state.c | 1 -
fs/nfsd/state.h | 1 -
3 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index d756f443fc44..988232086589 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -364,10 +364,13 @@ encode_cb_getattr4args(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr,
struct nfs4_delegation *dp =
container_of(fattr, struct nfs4_delegation, dl_cb_fattr);
struct knfsd_fh *fh = &dp->dl_stid.sc_file->fi_fhandle;
+ u32 bmap[1];
+
+ bmap[0] = FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE;
encode_nfs_cb_opnum4(xdr, OP_CB_GETATTR);
encode_nfs_fh4(xdr, fh);
- encode_bitmap4(xdr, fattr->ncf_cb_bmap, ARRAY_SIZE(fattr->ncf_cb_bmap));
+ encode_bitmap4(xdr, bmap, ARRAY_SIZE(bmap));
hdr->nops++;
}
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index b544320246bf..f353aeb4cc0a 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1182,7 +1182,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp,
nfsd4_init_cb(&dp->dl_cb_fattr.ncf_getattr, dp->dl_stid.sc_client,
&nfsd4_cb_getattr_ops, NFSPROC4_CLNT_CB_GETATTR);
dp->dl_cb_fattr.ncf_file_modified = false;
- dp->dl_cb_fattr.ncf_cb_bmap[0] = FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE;
get_nfs4_file(fp);
dp->dl_stid.sc_file = fp;
return dp;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index ec4559ecd193..65691457d9ba 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -137,7 +137,6 @@ struct nfs4_cpntf_state {
struct nfs4_cb_fattr {
struct nfsd4_callback ncf_getattr;
u32 ncf_cb_status;
- u32 ncf_cb_bmap[1];
/* from CB_GETATTR reply */
u64 ncf_cb_change;
--
2.46.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v2 7/7] nfsd: add support for delegated timestamps
2024-08-26 12:46 [PATCH v2 0/7] nfsd: implement the "delstid" draft Jeff Layton
` (5 preceding siblings ...)
2024-08-26 12:46 ` [PATCH v2 6/7] nfsd: drop the ncf_cb_bmap field Jeff Layton
@ 2024-08-26 12:46 ` Jeff Layton
6 siblings, 0 replies; 10+ messages in thread
From: Jeff Layton @ 2024-08-26 12:46 UTC (permalink / raw)
To: Chuck Lever, Neil Brown, Olga Kornievskaia, Dai Ngo, Tom Talpey,
Trond Myklebust, Anna Schumaker, Olga Kornievskaia,
Alexander Viro, Christian Brauner, Jan Kara, Jonathan Corbet
Cc: Tom Haynes, linux-kernel, linux-nfs, linux-fsdevel, linux-doc,
Jeff Layton
Add support for the delegated timestamps on write delegations. This
allows the server to proxy timestamps from the delegation holder to
other clients that are doing GETATTRs vs. the same inode.
Add a new flag to nfs4_delegation for indicating that the client can
provide timestamps in the CB_GETATTR response. Set that when the client
sets the appropriate flag in the open request.
Add timespec64 fields to nfs4_cb_fattr and decode the timestamps into
those. Vet those timestamps according to the delstid spec and update
the inode attrs if necessary.
For multigrain timestamps, ensure that we accept the client's version of
the ctime instead of updating to the latest clock as we normally would.
That should be fine since the client holds a delegation, and nothing
else will be making changes.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
fs/nfsd/nfs4callback.c | 42 +++++++++++++++++++++---
fs/nfsd/nfs4state.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++----
fs/nfsd/nfs4xdr.c | 1 +
fs/nfsd/nfsd.h | 3 +-
fs/nfsd/state.h | 3 ++
fs/nfsd/xdr4cb.h | 10 ++++--
6 files changed, 130 insertions(+), 15 deletions(-)
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 988232086589..d5004790f2b1 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -93,12 +93,35 @@ static int decode_cb_fattr4(struct xdr_stream *xdr, uint32_t *bitmap,
{
fattr->ncf_cb_change = 0;
fattr->ncf_cb_fsize = 0;
+ fattr->ncf_cb_atime.tv_sec = 0;
+ fattr->ncf_cb_atime.tv_nsec = 0;
+ fattr->ncf_cb_mtime.tv_sec = 0;
+ fattr->ncf_cb_mtime.tv_nsec = 0;
+
if (bitmap[0] & FATTR4_WORD0_CHANGE)
if (xdr_stream_decode_u64(xdr, &fattr->ncf_cb_change) < 0)
return -NFSERR_BAD_XDR;
if (bitmap[0] & FATTR4_WORD0_SIZE)
if (xdr_stream_decode_u64(xdr, &fattr->ncf_cb_fsize) < 0)
return -NFSERR_BAD_XDR;
+ if (bitmap[2] & FATTR4_WORD2_TIME_DELEG_ACCESS) {
+ fattr4_time_deleg_access access;
+
+ if (!xdrgen_decode_fattr4_time_deleg_access(xdr, &access))
+ return -NFSERR_BAD_XDR;
+ fattr->ncf_cb_atime.tv_sec = access.seconds;
+ fattr->ncf_cb_atime.tv_nsec = access.nseconds;
+
+ }
+ if (bitmap[2] & FATTR4_WORD2_TIME_DELEG_MODIFY) {
+ fattr4_time_deleg_modify modify;
+
+ if (!xdrgen_decode_fattr4_time_deleg_modify(xdr, &modify))
+ return -NFSERR_BAD_XDR;
+ fattr->ncf_cb_mtime.tv_sec = modify.seconds;
+ fattr->ncf_cb_mtime.tv_nsec = modify.nseconds;
+
+ }
return 0;
}
@@ -364,13 +387,18 @@ encode_cb_getattr4args(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr,
struct nfs4_delegation *dp =
container_of(fattr, struct nfs4_delegation, dl_cb_fattr);
struct knfsd_fh *fh = &dp->dl_stid.sc_file->fi_fhandle;
- u32 bmap[1];
+ u32 bmap[3];
+ u32 bmap_size = 1;
bmap[0] = FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE;
-
+ if (dp->dl_deleg_ts) {
+ bmap[1] = 0;
+ bmap[2] = FATTR4_WORD2_TIME_DELEG_ACCESS | FATTR4_WORD2_TIME_DELEG_MODIFY;
+ bmap_size = 3;
+ }
encode_nfs_cb_opnum4(xdr, OP_CB_GETATTR);
encode_nfs_fh4(xdr, fh);
- encode_bitmap4(xdr, bmap, ARRAY_SIZE(bmap));
+ encode_bitmap4(xdr, bmap, bmap_size);
hdr->nops++;
}
@@ -595,7 +623,7 @@ static int nfs4_xdr_dec_cb_getattr(struct rpc_rqst *rqstp,
struct nfs4_cb_compound_hdr hdr;
int status;
u32 bitmap[3] = {0};
- u32 attrlen;
+ u32 attrlen, maxlen;
struct nfs4_cb_fattr *ncf =
container_of(cb, struct nfs4_cb_fattr, ncf_getattr);
@@ -614,7 +642,11 @@ static int nfs4_xdr_dec_cb_getattr(struct rpc_rqst *rqstp,
return -NFSERR_BAD_XDR;
if (xdr_stream_decode_u32(xdr, &attrlen) < 0)
return -NFSERR_BAD_XDR;
- if (attrlen > (sizeof(ncf->ncf_cb_change) + sizeof(ncf->ncf_cb_fsize)))
+ maxlen = sizeof(ncf->ncf_cb_change) + sizeof(ncf->ncf_cb_fsize);
+ if (bitmap[2] != 0)
+ maxlen += (sizeof(ncf->ncf_cb_mtime.tv_sec) +
+ sizeof(ncf->ncf_cb_mtime.tv_nsec)) * 2;
+ if (attrlen > maxlen)
return -NFSERR_BAD_XDR;
status = decode_cb_fattr4(xdr, bitmap, ncf);
return status;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index f353aeb4cc0a..ea63c4f0ef0a 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5975,6 +5975,8 @@ nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid));
+ if (open->op_deleg_want & NFS4_SHARE_WANT_DELEG_TIMESTAMPS)
+ dp->dl_deleg_ts = true;
if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) {
open->op_delegate_type = NFS4_OPEN_DELEGATE_WRITE;
trace_nfsd_deleg_write(&dp->dl_stid.sc_stateid);
@@ -8819,6 +8821,83 @@ nfsd4_get_writestateid(struct nfsd4_compound_state *cstate,
get_stateid(cstate, &u->write.wr_stateid);
}
+/**
+ * set_cb_time - vet and set the timespec for a cb_getattr update
+ * @cb: timestamp from the CB_GETATTR response
+ * @orig: original timestamp in the inode
+ * @now: current time
+ *
+ * Given a timestamp in a CB_GETATTR response, check it against the
+ * current timestamp in the inode and the current time. Returns true
+ * if the inode's timestamp needs to be updated, and false otherwise.
+ * @cb may also be changed if the timestamp needs to be clamped.
+ */
+static bool set_cb_time(struct timespec64 *cb, const struct timespec64 *orig,
+ const struct timespec64 *now)
+{
+
+ /*
+ * "When the time presented is before the original time, then the
+ * update is ignored." Also no need to update if there is no change.
+ */
+ if (timespec64_compare(cb, orig) <= 0)
+ return false;
+
+ /*
+ * "When the time presented is in the future, the server can either
+ * clamp the new time to the current time, or it may
+ * return NFS4ERR_DELAY to the client, allowing it to retry."
+ */
+ if (timespec64_compare(cb, now) > 0) {
+ /* clamp it */
+ *cb = *now;
+ }
+
+ return true;
+}
+
+static int cb_getattr_update_times(struct dentry *dentry, struct nfs4_delegation *dp)
+{
+ struct timespec64 now = current_time(d_inode(dentry));
+ struct nfs4_cb_fattr *ncf = &dp->dl_cb_fattr;
+ struct inode *inode = d_inode(dentry);
+ struct iattr attrs = { };
+ int ret;
+
+ if (dp->dl_deleg_ts) {
+ struct timespec64 atime = inode_get_atime(inode);
+ struct timespec64 mtime = inode_get_mtime(inode);
+
+ attrs.ia_atime = ncf->ncf_cb_atime;
+ attrs.ia_mtime = ncf->ncf_cb_mtime;
+
+ if (set_cb_time(&attrs.ia_atime, &atime, &now))
+ attrs.ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
+
+ if (set_cb_time(&attrs.ia_mtime, &mtime, &now)) {
+ struct timespec64 ctime = inode_get_ctime(inode);
+
+ attrs.ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
+ if (timespec64_compare(&attrs.ia_mtime, &ctime) > 0) {
+ attrs.ia_valid |= ATTR_CTIME | ATTR_CTIME_DLG;
+ attrs.ia_ctime = attrs.ia_mtime;
+ }
+ }
+ } else {
+ attrs.ia_valid |= ATTR_MTIME | ATTR_CTIME;
+ attrs.ia_mtime = attrs.ia_ctime = now;
+ }
+
+ if (!attrs.ia_valid)
+ return 0;
+
+ attrs.ia_valid |= ATTR_DELEG;
+ inode_lock(inode);
+ ret = notify_change(&nop_mnt_idmap, dentry, &attrs, NULL);
+ inode_unlock(inode);
+ return ret;
+}
+
/**
* nfsd4_deleg_getattr_conflict - Recall if GETATTR causes conflict
* @rqstp: RPC transaction context
@@ -8846,7 +8925,6 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct dentry *dentry,
struct file_lock_context *ctx;
struct nfs4_cb_fattr *ncf;
struct file_lease *fl;
- struct iattr attrs;
*modified = false;
ctx = locks_inode_context(inode);
@@ -8905,11 +8983,7 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct dentry *dentry,
* not update the file's metadata with the client's
* modified size
*/
- attrs.ia_mtime = attrs.ia_ctime = current_time(inode);
- attrs.ia_valid = ATTR_MTIME | ATTR_CTIME | ATTR_DELEG;
- inode_lock(inode);
- err = notify_change(&nop_mnt_idmap, dentry, &attrs, NULL);
- inode_unlock(inode);
+ err = cb_getattr_update_times(dentry, dp);
if (err) {
nfs4_put_stid(&dp->dl_stid);
return nfserrno(err);
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 8266f910d847..c79f7402bc30 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3411,6 +3411,7 @@ static __be32 nfsd4_encode_fattr4_xattr_support(struct xdr_stream *xdr,
#define NFSD_OA_SHARE_ACCESS_WANT (BIT(OPEN_ARGS_SHARE_ACCESS_WANT_ANY_DELEG) | \
BIT(OPEN_ARGS_SHARE_ACCESS_WANT_NO_DELEG) | \
BIT(OPEN_ARGS_SHARE_ACCESS_WANT_CANCEL) | \
+ BIT(OPEN_ARGS_SHARE_ACCESS_WANT_DELEG_TIMESTAMPS) | \
BIT(OPEN_ARGS_SHARE_ACCESS_WANT_OPEN_XOR_DELEGATION))
#define NFSD_OA_OPEN_CLAIM (BIT(OPEN_ARGS_OPEN_CLAIM_NULL) | \
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index c98fb104ba7d..2d89b82e5453 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -421,7 +421,8 @@ enum {
| FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_CREATE \
| FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID)
-#define NFSD4_SUPPORTED_ATTRS_WORD2 0
+#define NFSD4_SUPPORTED_ATTRS_WORD2 (FATTR4_WORD2_TIME_DELEG_MODIFY | \
+ FATTR4_WORD2_TIME_DELEG_ACCESS)
/* 4.1 */
#ifdef CONFIG_NFSD_PNFS
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 65691457d9ba..b2ffb7d36721 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -141,6 +141,8 @@ struct nfs4_cb_fattr {
/* from CB_GETATTR reply */
u64 ncf_cb_change;
u64 ncf_cb_fsize;
+ struct timespec64 ncf_cb_mtime;
+ struct timespec64 ncf_cb_atime;
unsigned long ncf_cb_flags;
bool ncf_file_modified;
@@ -184,6 +186,7 @@ struct nfs4_delegation {
int dl_retries;
struct nfsd4_callback dl_recall;
bool dl_recalled;
+ bool dl_deleg_ts;
/* for CB_GETATTR */
struct nfs4_cb_fattr dl_cb_fattr;
diff --git a/fs/nfsd/xdr4cb.h b/fs/nfsd/xdr4cb.h
index e8b00309c449..f1a315cd31b7 100644
--- a/fs/nfsd/xdr4cb.h
+++ b/fs/nfsd/xdr4cb.h
@@ -59,16 +59,20 @@
* 1: CB_GETATTR opcode (32-bit)
* N: file_handle
* 1: number of entry in attribute array (32-bit)
- * 1: entry 0 in attribute array (32-bit)
+ * 3: entry 0-2 in attribute array (32-bit * 3)
*/
#define NFS4_enc_cb_getattr_sz (cb_compound_enc_hdr_sz + \
cb_sequence_enc_sz + \
- 1 + enc_nfs4_fh_sz + 1 + 1)
+ 1 + enc_nfs4_fh_sz + 1 + 3)
/*
* 4: fattr_bitmap_maxsz
* 1: attribute array len
* 2: change attr (64-bit)
* 2: size (64-bit)
+ * 2: atime.seconds (64-bit)
+ * 1: atime.nanoseconds (32-bit)
+ * 2: mtime.seconds (64-bit)
+ * 1: mtime.nanoseconds (32-bit)
*/
#define NFS4_dec_cb_getattr_sz (cb_compound_dec_hdr_sz + \
- cb_sequence_dec_sz + 4 + 1 + 2 + 2 + op_dec_sz)
+ cb_sequence_dec_sz + 4 + 1 + 2 + 2 + 2 + 1 + 2 + 1 + op_dec_sz)
--
2.46.0
^ permalink raw reply related [flat|nested] 10+ messages in thread