All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/8] Support btime and other NFSv4 specific attributes
@ 2021-12-27 19:04 trondmy
  2021-12-27 19:04 ` [PATCH v2 1/8] NFS: Expand the type of nfs_fattr->valid trondmy
  0 siblings, 1 reply; 14+ messages in thread
From: trondmy @ 2021-12-27 19:04 UTC (permalink / raw)
  To: Anna Schumaker; +Cc: linux-nfs

From: Trond Myklebust <trond.myklebust@hammerspace.com>

NFSv4 has support for a number of extra attributes that are of interest
to Samba when it is used to re-export a filesystem to Windows clients.
Aside from the btime, which is of interest in statx(), Windows clients
have an interest in determining the status of the 'hidden', and 'system'
flags.
Backup programs want to read the 'archive' flags and the 'time backup'
attribute.
Finally, the 'offline' flag can tell whether or not a file needs to be
staged by an HSM system before it can be read or written to.

The patch series also adds an ioctl() to allow userspace retrieval and
setting of these attributes where appropriate. It also adds an ioctl()
to allow retrieval of the raw NFSv4 ACCESS information, to allow more
fine grained determination of the user's access rights to a file or
directory. All of this information is of use for Samba.


- v2: Rebase on top of Anna's linux-next

Anne Marie Merritt (3):
  nfs: Add timecreate to nfs inode
  nfs: Add 'archive', 'hidden' and 'system' fields to nfs inode
  nfs: Add 'time backup' to nfs inode

Richard Sharpe (1):
  NFS: Support statx_get and statx_set ioctls

Trond Myklebust (4):
  NFS: Expand the type of nfs_fattr->valid
  NFS: Return the file btime in the statx results when appropriate
  NFSv4: Support the offline bit
  NFSv4: Add an ioctl to allow retrieval of the NFS raw ACCESS mask

 fs/nfs/dir.c              |  71 ++---
 fs/nfs/getroot.c          |   3 +-
 fs/nfs/inode.c            | 147 +++++++++-
 fs/nfs/internal.h         |  10 +
 fs/nfs/nfs3proc.c         |   1 +
 fs/nfs/nfs4_fs.h          |  31 +++
 fs/nfs/nfs4file.c         | 550 ++++++++++++++++++++++++++++++++++++++
 fs/nfs/nfs4proc.c         | 175 +++++++++++-
 fs/nfs/nfs4trace.h        |   8 +-
 fs/nfs/nfs4xdr.c          | 240 +++++++++++++++--
 fs/nfs/nfstrace.c         |   5 +
 fs/nfs/nfstrace.h         |   9 +-
 fs/nfs/proc.c             |   1 +
 include/linux/nfs4.h      |   1 +
 include/linux/nfs_fs.h    |  15 ++
 include/linux/nfs_fs_sb.h |   2 +-
 include/linux/nfs_xdr.h   |  80 ++++--
 include/uapi/linux/nfs.h  | 101 +++++++
 18 files changed, 1355 insertions(+), 95 deletions(-)

-- 
2.33.1


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v2 1/8] NFS: Expand the type of nfs_fattr->valid
  2021-12-27 19:04 [PATCH v2 0/8] Support btime and other NFSv4 specific attributes trondmy
@ 2021-12-27 19:04 ` trondmy
  2021-12-27 19:04   ` [PATCH v2 2/8] nfs: Add timecreate to nfs inode trondmy
  0 siblings, 1 reply; 14+ messages in thread
From: trondmy @ 2021-12-27 19:04 UTC (permalink / raw)
  To: Anna Schumaker; +Cc: linux-nfs

From: Trond Myklebust <trond.myklebust@primarydata.com>

We need to be able to track more than 32 attributes per inode.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Lance Shelton <lance.shelton@hammerspace.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
---
 fs/nfs/inode.c            |  5 ++--
 include/linux/nfs_fs_sb.h |  2 +-
 include/linux/nfs_xdr.h   | 54 +++++++++++++++++++--------------------
 3 files changed, 31 insertions(+), 30 deletions(-)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index fda530d5e764..897dec07cf4b 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -2001,10 +2001,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 	bool attr_changed = false;
 	bool have_delegation;
 
-	dfprintk(VFS, "NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%x)\n",
+	dfprintk(VFS, "NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%lx)\n",
 			__func__, inode->i_sb->s_id, inode->i_ino,
 			nfs_display_fhandle_hash(NFS_FH(inode)),
-			atomic_read(&inode->i_count), fattr->valid);
+			atomic_read(&inode->i_count),
+			(unsigned long)fattr->valid);
 
 	if (!(fattr->valid & NFS_ATTR_FATTR_FILEID)) {
 		/* Only a mounted-on-fileid? Just exit */
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 2a9acbfe00f0..8468206fb535 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -157,8 +157,8 @@ struct nfs_server {
 #define NFS_MOUNT_WRITE_EAGER		0x01000000
 #define NFS_MOUNT_WRITE_WAIT		0x02000000
 
-	unsigned int		fattr_valid;	/* Valid attributes */
 	unsigned int		caps;		/* server capabilities */
+	__u64			fattr_valid;	/* Valid attributes */
 	unsigned int		rsize;		/* read size */
 	unsigned int		rpages;		/* read size (in pages) */
 	unsigned int		wsize;		/* write size */
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 9102bdaa3faa..6e604d6a3e6d 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -45,7 +45,7 @@ struct nfs4_threshold {
 };
 
 struct nfs_fattr {
-	unsigned int		valid;		/* which fields are valid */
+	__u64			valid;		/* which fields are valid */
 	umode_t			mode;
 	__u32			nlink;
 	kuid_t			uid;
@@ -80,32 +80,32 @@ struct nfs_fattr {
 	struct nfs4_label	*label;
 };
 
-#define NFS_ATTR_FATTR_TYPE		(1U << 0)
-#define NFS_ATTR_FATTR_MODE		(1U << 1)
-#define NFS_ATTR_FATTR_NLINK		(1U << 2)
-#define NFS_ATTR_FATTR_OWNER		(1U << 3)
-#define NFS_ATTR_FATTR_GROUP		(1U << 4)
-#define NFS_ATTR_FATTR_RDEV		(1U << 5)
-#define NFS_ATTR_FATTR_SIZE		(1U << 6)
-#define NFS_ATTR_FATTR_PRESIZE		(1U << 7)
-#define NFS_ATTR_FATTR_BLOCKS_USED	(1U << 8)
-#define NFS_ATTR_FATTR_SPACE_USED	(1U << 9)
-#define NFS_ATTR_FATTR_FSID		(1U << 10)
-#define NFS_ATTR_FATTR_FILEID		(1U << 11)
-#define NFS_ATTR_FATTR_ATIME		(1U << 12)
-#define NFS_ATTR_FATTR_MTIME		(1U << 13)
-#define NFS_ATTR_FATTR_CTIME		(1U << 14)
-#define NFS_ATTR_FATTR_PREMTIME		(1U << 15)
-#define NFS_ATTR_FATTR_PRECTIME		(1U << 16)
-#define NFS_ATTR_FATTR_CHANGE		(1U << 17)
-#define NFS_ATTR_FATTR_PRECHANGE	(1U << 18)
-#define NFS_ATTR_FATTR_V4_LOCATIONS	(1U << 19)
-#define NFS_ATTR_FATTR_V4_REFERRAL	(1U << 20)
-#define NFS_ATTR_FATTR_MOUNTPOINT	(1U << 21)
-#define NFS_ATTR_FATTR_MOUNTED_ON_FILEID (1U << 22)
-#define NFS_ATTR_FATTR_OWNER_NAME	(1U << 23)
-#define NFS_ATTR_FATTR_GROUP_NAME	(1U << 24)
-#define NFS_ATTR_FATTR_V4_SECURITY_LABEL (1U << 25)
+#define NFS_ATTR_FATTR_TYPE		BIT_ULL(0)
+#define NFS_ATTR_FATTR_MODE		BIT_ULL(1)
+#define NFS_ATTR_FATTR_NLINK		BIT_ULL(2)
+#define NFS_ATTR_FATTR_OWNER		BIT_ULL(3)
+#define NFS_ATTR_FATTR_GROUP		BIT_ULL(4)
+#define NFS_ATTR_FATTR_RDEV		BIT_ULL(5)
+#define NFS_ATTR_FATTR_SIZE		BIT_ULL(6)
+#define NFS_ATTR_FATTR_PRESIZE		BIT_ULL(7)
+#define NFS_ATTR_FATTR_BLOCKS_USED	BIT_ULL(8)
+#define NFS_ATTR_FATTR_SPACE_USED	BIT_ULL(9)
+#define NFS_ATTR_FATTR_FSID		BIT_ULL(10)
+#define NFS_ATTR_FATTR_FILEID		BIT_ULL(11)
+#define NFS_ATTR_FATTR_ATIME		BIT_ULL(12)
+#define NFS_ATTR_FATTR_MTIME		BIT_ULL(13)
+#define NFS_ATTR_FATTR_CTIME		BIT_ULL(14)
+#define NFS_ATTR_FATTR_PREMTIME		BIT_ULL(15)
+#define NFS_ATTR_FATTR_PRECTIME		BIT_ULL(16)
+#define NFS_ATTR_FATTR_CHANGE		BIT_ULL(17)
+#define NFS_ATTR_FATTR_PRECHANGE	BIT_ULL(18)
+#define NFS_ATTR_FATTR_V4_LOCATIONS	BIT_ULL(19)
+#define NFS_ATTR_FATTR_V4_REFERRAL	BIT_ULL(20)
+#define NFS_ATTR_FATTR_MOUNTPOINT	BIT_ULL(21)
+#define NFS_ATTR_FATTR_MOUNTED_ON_FILEID BIT_ULL(22)
+#define NFS_ATTR_FATTR_OWNER_NAME	BIT_ULL(23)
+#define NFS_ATTR_FATTR_GROUP_NAME	BIT_ULL(24)
+#define NFS_ATTR_FATTR_V4_SECURITY_LABEL BIT_ULL(25)
 
 #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
 		| NFS_ATTR_FATTR_MODE \
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 2/8] nfs: Add timecreate to nfs inode
  2021-12-27 19:04 ` [PATCH v2 1/8] NFS: Expand the type of nfs_fattr->valid trondmy
@ 2021-12-27 19:04   ` trondmy
  2021-12-27 19:04     ` [PATCH v2 3/8] NFS: Return the file btime in the statx results when appropriate trondmy
  0 siblings, 1 reply; 14+ messages in thread
From: trondmy @ 2021-12-27 19:04 UTC (permalink / raw)
  To: Anna Schumaker; +Cc: linux-nfs

From: Anne Marie Merritt <annemarie.merritt@primarydata.com>

Add tracking of the create time (a.k.a. btime) along with corresponding
bitfields, request, and decode xdr routines.

Signed-off-by: Anne Marie Merritt <annemarie.merritt@primarydata.com>
Signed-off-by: Lance Shelton <lance.shelton@hammerspace.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
---
 fs/nfs/inode.c          | 28 ++++++++++++++++++++++------
 fs/nfs/nfs4proc.c       | 15 +++++++++++++--
 fs/nfs/nfs4xdr.c        | 24 ++++++++++++++++++++++++
 fs/nfs/nfstrace.h       |  3 ++-
 include/linux/nfs_fs.h  |  7 +++++++
 include/linux/nfs_xdr.h |  3 +++
 6 files changed, 71 insertions(+), 9 deletions(-)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 897dec07cf4b..908a62d6a29c 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -201,6 +201,7 @@ void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
 		if (!(flags & NFS_INO_REVAL_FORCED))
 			flags &= ~(NFS_INO_INVALID_MODE |
 				   NFS_INO_INVALID_OTHER |
+				   NFS_INO_INVALID_BTIME |
 				   NFS_INO_INVALID_XATTR);
 		flags &= ~(NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_SIZE);
 	} else if (flags & NFS_INO_REVAL_PAGECACHE)
@@ -521,6 +522,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 		memset(&inode->i_atime, 0, sizeof(inode->i_atime));
 		memset(&inode->i_mtime, 0, sizeof(inode->i_mtime));
 		memset(&inode->i_ctime, 0, sizeof(inode->i_ctime));
+		memset(&nfsi->btime, 0, sizeof(nfsi->btime));
 		inode_set_iversion_raw(inode, 0);
 		inode->i_size = 0;
 		clear_nlink(inode);
@@ -544,6 +546,10 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 			inode->i_ctime = fattr->ctime;
 		else if (fattr_supported & NFS_ATTR_FATTR_CTIME)
 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_CTIME);
+		if (fattr->valid & NFS_ATTR_FATTR_BTIME)
+			nfsi->btime = fattr->btime;
+		else if (fattr_supported & NFS_ATTR_FATTR_BTIME)
+			nfs_set_cache_invalid(inode, NFS_INO_INVALID_BTIME);
 		if (fattr->valid & NFS_ATTR_FATTR_CHANGE)
 			inode_set_iversion_raw(inode, fattr->change_attr);
 		else
@@ -1801,7 +1807,7 @@ static int nfs_inode_finish_partial_attr_update(const struct nfs_fattr *fattr,
 		NFS_INO_INVALID_ATIME | NFS_INO_INVALID_CTIME |
 		NFS_INO_INVALID_MTIME | NFS_INO_INVALID_SIZE |
 		NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_OTHER |
-		NFS_INO_INVALID_NLINK;
+		NFS_INO_INVALID_NLINK | NFS_INO_INVALID_BTIME;
 	unsigned long cache_validity = NFS_I(inode)->cache_validity;
 	enum nfs4_change_attr_type ctype = NFS_SERVER(inode)->change_attr_type;
 
@@ -2052,10 +2058,13 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 	nfsi->read_cache_jiffies = fattr->time_start;
 
 	save_cache_validity = nfsi->cache_validity;
-	nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR
-			| NFS_INO_INVALID_ATIME
-			| NFS_INO_REVAL_FORCED
-			| NFS_INO_INVALID_BLOCKS);
+	nfsi->cache_validity &=
+		~(NFS_INO_INVALID_ATIME | NFS_INO_REVAL_FORCED |
+		  NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_CTIME |
+		  NFS_INO_INVALID_MTIME | NFS_INO_INVALID_SIZE |
+		  NFS_INO_INVALID_OTHER | NFS_INO_INVALID_BLOCKS |
+		  NFS_INO_INVALID_NLINK | NFS_INO_INVALID_MODE |
+		  NFS_INO_INVALID_BTIME);
 
 	/* Do atomic weak cache consistency updates */
 	nfs_wcc_update_inode(inode, fattr);
@@ -2085,7 +2094,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 					| NFS_INO_INVALID_BLOCKS
 					| NFS_INO_INVALID_NLINK
 					| NFS_INO_INVALID_MODE
-					| NFS_INO_INVALID_OTHER;
+					| NFS_INO_INVALID_OTHER
+					| NFS_INO_INVALID_BTIME;
 				if (S_ISDIR(inode->i_mode))
 					nfs_force_lookup_revalidate(inode);
 				attr_changed = true;
@@ -2116,6 +2126,12 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 		nfsi->cache_validity |=
 			save_cache_validity & NFS_INO_INVALID_CTIME;
 
+	if (fattr->valid & NFS_ATTR_FATTR_BTIME)
+		nfsi->btime = fattr->btime;
+	else if (fattr_supported & NFS_ATTR_FATTR_BTIME)
+		nfsi->cache_validity |=
+			save_cache_validity & NFS_INO_INVALID_BTIME;
+
 	/* Check if our cached file size is stale */
 	if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
 		new_isize = nfs_size_to_loff_t(fattr->size);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 5d9ff01ddf46..be8eeb22b35f 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -208,6 +208,7 @@ const u32 nfs4_fattr_bitmap[3] = {
 	| FATTR4_WORD1_RAWDEV
 	| FATTR4_WORD1_SPACE_USED
 	| FATTR4_WORD1_TIME_ACCESS
+	| FATTR4_WORD1_TIME_CREATE
 	| FATTR4_WORD1_TIME_METADATA
 	| FATTR4_WORD1_TIME_MODIFY
 	| FATTR4_WORD1_MOUNTED_ON_FILEID,
@@ -229,6 +230,7 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
 	| FATTR4_WORD1_RAWDEV
 	| FATTR4_WORD1_SPACE_USED
 	| FATTR4_WORD1_TIME_ACCESS
+	| FATTR4_WORD1_TIME_CREATE
 	| FATTR4_WORD1_TIME_METADATA
 	| FATTR4_WORD1_TIME_MODIFY,
 	FATTR4_WORD2_MDSTHRESHOLD
@@ -308,6 +310,9 @@ static void nfs4_bitmap_copy_adjust(__u32 *dst, const __u32 *src,
 		dst[1] &= ~FATTR4_WORD1_MODE;
 	if (!(cache_validity & NFS_INO_INVALID_OTHER))
 		dst[1] &= ~(FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP);
+
+	if (!(cache_validity & NFS_INO_INVALID_BTIME))
+		dst[1] &= ~FATTR4_WORD1_TIME_CREATE;
 }
 
 static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry,
@@ -1233,8 +1238,8 @@ nfs4_update_changeattr_locked(struct inode *inode,
 				NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL |
 				NFS_INO_INVALID_SIZE | NFS_INO_INVALID_OTHER |
 				NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_NLINK |
-				NFS_INO_INVALID_MODE | NFS_INO_INVALID_XATTR |
-				NFS_INO_REVAL_PAGECACHE;
+				NFS_INO_INVALID_MODE | NFS_INO_INVALID_BTIME |
+				NFS_INO_INVALID_XATTR | NFS_INO_REVAL_PAGECACHE;
 		nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
 	}
 	nfsi->attrtimeo_timestamp = jiffies;
@@ -3893,6 +3898,10 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
 			server->fattr_valid &= ~NFS_ATTR_FATTR_CTIME;
 		if (!(res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY))
 			server->fattr_valid &= ~NFS_ATTR_FATTR_MTIME;
+		if (!(res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY))
+			server->fattr_valid &= ~NFS_ATTR_FATTR_MTIME;
+		if (!(res.attr_bitmask[1] & FATTR4_WORD1_TIME_CREATE))
+			server->fattr_valid &= ~NFS_ATTR_FATTR_BTIME;
 		memcpy(server->attr_bitmask_nl, res.attr_bitmask,
 				sizeof(server->attr_bitmask));
 		server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
@@ -5450,6 +5459,8 @@ static void nfs4_bitmask_set(__u32 bitmask[NFS4_BITMASK_SZ], const __u32 *src,
 		bitmask[1] |= FATTR4_WORD1_TIME_MODIFY;
 	if (cache_validity & NFS_INO_INVALID_BLOCKS)
 		bitmask[1] |= FATTR4_WORD1_SPACE_USED;
+	if (cache_validity & NFS_INO_INVALID_BTIME)
+		bitmask[1] |= FATTR4_WORD1_TIME_CREATE;
 
 	if (cache_validity & NFS_INO_INVALID_SIZE)
 		bitmask[0] |= FATTR4_WORD0_SIZE;
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 801119b7a596..33ab1377f443 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -1616,6 +1616,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
 		attrs[1] |= FATTR4_WORD1_MODE|FATTR4_WORD1_NUMLINKS|FATTR4_WORD1_OWNER|
 			FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV|
 			FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS|
+			FATTR4_WORD1_TIME_CREATE |
 			FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
 		attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
 		dircount >>= 1;
@@ -4121,6 +4122,24 @@ static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, str
 	return status;
 }
 
+static int decode_attr_time_create(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec64 *time)
+{
+	int status = 0;
+
+	time->tv_sec = 0;
+	time->tv_nsec = 0;
+	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_CREATE - 1U)))
+		return -EIO;
+	if (likely(bitmap[1] & FATTR4_WORD1_TIME_CREATE)) {
+		status = decode_attr_time(xdr, time);
+		if (status == 0)
+			status = NFS_ATTR_FATTR_BTIME;
+		bitmap[1] &= ~FATTR4_WORD1_TIME_CREATE;
+	}
+	dprintk("%s: btime=%lld\n", __func__, time->tv_sec);
+	return status;
+}
+
 static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec64 *time)
 {
 	int status = 0;
@@ -4678,6 +4697,11 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
 		goto xdr_error;
 	fattr->valid |= status;
 
+	status = decode_attr_time_create(xdr, bitmap, &fattr->btime);
+	if (status < 0)
+		goto xdr_error;
+	fattr->valid |= status;
+
 	status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime);
 	if (status < 0)
 		goto xdr_error;
diff --git a/fs/nfs/nfstrace.h b/fs/nfs/nfstrace.h
index b3aee261801e..cba86d167c38 100644
--- a/fs/nfs/nfstrace.h
+++ b/fs/nfs/nfstrace.h
@@ -33,7 +33,8 @@
 			{ NFS_INO_INVALID_BLOCKS, "INVALID_BLOCKS" }, \
 			{ NFS_INO_INVALID_XATTR, "INVALID_XATTR" }, \
 			{ NFS_INO_INVALID_NLINK, "INVALID_NLINK" }, \
-			{ NFS_INO_INVALID_MODE, "INVALID_MODE" })
+			{ NFS_INO_INVALID_MODE, "INVALID_MODE" }, \
+			{ NFS_INO_INVALID_BTIME, "INVALID_BTIME" })
 
 #define nfs_show_nfsi_flags(v) \
 	__print_flags(v, "|", \
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 450e393d4bf2..8d944d399b17 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -138,6 +138,12 @@ struct nfs_inode {
 	unsigned long		flags;			/* atomic bit ops */
 	unsigned long		cache_validity;		/* bit mask */
 
+	/*
+	 * NFS Attributes not included in struct inode
+	 */
+
+	struct timespec64	btime;
+
 	/*
 	 * read_cache_jiffies is when we started read-caching this inode.
 	 * attrtimeo is for how long the cached information is assumed
@@ -260,6 +266,7 @@ struct nfs4_copy_state {
 #define NFS_INO_INVALID_XATTR	BIT(15)		/* xattrs are invalid */
 #define NFS_INO_INVALID_NLINK	BIT(16)		/* cached nlinks is invalid */
 #define NFS_INO_INVALID_MODE	BIT(17)		/* cached mode is invalid */
+#define NFS_INO_INVALID_BTIME	BIT(18)		/* cached btime is invalid */
 
 #define NFS_INO_INVALID_ATTR	(NFS_INO_INVALID_CHANGE \
 		| NFS_INO_INVALID_CTIME \
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 6e604d6a3e6d..8e8ff5def523 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -67,6 +67,7 @@ struct nfs_fattr {
 	struct timespec64	atime;
 	struct timespec64	mtime;
 	struct timespec64	ctime;
+	struct timespec64	btime;
 	__u64			change_attr;	/* NFSv4 change attribute */
 	__u64			pre_change_attr;/* pre-op NFSv4 change attribute */
 	__u64			pre_size;	/* pre_op_attr.size	  */
@@ -106,6 +107,7 @@ struct nfs_fattr {
 #define NFS_ATTR_FATTR_OWNER_NAME	BIT_ULL(23)
 #define NFS_ATTR_FATTR_GROUP_NAME	BIT_ULL(24)
 #define NFS_ATTR_FATTR_V4_SECURITY_LABEL BIT_ULL(25)
+#define NFS_ATTR_FATTR_BTIME		BIT_ULL(26)
 
 #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
 		| NFS_ATTR_FATTR_MODE \
@@ -126,6 +128,7 @@ struct nfs_fattr {
 		| NFS_ATTR_FATTR_SPACE_USED)
 #define NFS_ATTR_FATTR_V4 (NFS_ATTR_FATTR \
 		| NFS_ATTR_FATTR_SPACE_USED \
+		| NFS_ATTR_FATTR_BTIME \
 		| NFS_ATTR_FATTR_V4_SECURITY_LABEL)
 
 /*
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 3/8] NFS: Return the file btime in the statx results when appropriate
  2021-12-27 19:04   ` [PATCH v2 2/8] nfs: Add timecreate to nfs inode trondmy
@ 2021-12-27 19:04     ` trondmy
  2021-12-27 19:05       ` [PATCH v2 4/8] nfs: Add 'archive', 'hidden' and 'system' fields to nfs inode trondmy
  0 siblings, 1 reply; 14+ messages in thread
From: trondmy @ 2021-12-27 19:04 UTC (permalink / raw)
  To: Anna Schumaker; +Cc: linux-nfs

From: Trond Myklebust <trond.myklebust@hammerspace.com>

If the server supports the NFSv4.x "create_time" attribute, then return
it as part of the statx results.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
---
 fs/nfs/inode.c     | 15 +++++++++++++--
 fs/nfs/nfs4trace.h |  3 ++-
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 908a62d6a29c..94268cab7613 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -815,6 +815,7 @@ static void nfs_readdirplus_parent_cache_hit(struct dentry *dentry)
 
 static u32 nfs_get_valid_attrmask(struct inode *inode)
 {
+	u64 fattr_valid = NFS_SERVER(inode)->fattr_valid;
 	unsigned long cache_validity = READ_ONCE(NFS_I(inode)->cache_validity);
 	u32 reply_mask = STATX_INO | STATX_TYPE;
 
@@ -834,6 +835,9 @@ static u32 nfs_get_valid_attrmask(struct inode *inode)
 		reply_mask |= STATX_UID | STATX_GID;
 	if (!(cache_validity & NFS_INO_INVALID_BLOCKS))
 		reply_mask |= STATX_BLOCKS;
+	if (!(cache_validity & NFS_INO_INVALID_BTIME) &&
+	    (fattr_valid & NFS_ATTR_FATTR_BTIME))
+		reply_mask |= STATX_BTIME;
 	return reply_mask;
 }
 
@@ -842,6 +846,7 @@ int nfs_getattr(struct user_namespace *mnt_userns, const struct path *path,
 {
 	struct inode *inode = d_inode(path->dentry);
 	struct nfs_server *server = NFS_SERVER(inode);
+	u64 fattr_valid = server->fattr_valid;
 	unsigned long cache_validity;
 	int err = 0;
 	bool force_sync = query_flags & AT_STATX_FORCE_SYNC;
@@ -851,7 +856,10 @@ int nfs_getattr(struct user_namespace *mnt_userns, const struct path *path,
 
 	request_mask &= STATX_TYPE | STATX_MODE | STATX_NLINK | STATX_UID |
 			STATX_GID | STATX_ATIME | STATX_MTIME | STATX_CTIME |
-			STATX_INO | STATX_SIZE | STATX_BLOCKS;
+			STATX_INO | STATX_SIZE | STATX_BLOCKS | STATX_BTIME;
+
+	if (!(fattr_valid & NFS_ATTR_FATTR_BTIME))
+		request_mask &= ~STATX_BTIME;
 
 	if ((query_flags & AT_STATX_DONT_SYNC) && !force_sync) {
 		nfs_readdirplus_parent_cache_hit(path->dentry);
@@ -882,7 +890,7 @@ int nfs_getattr(struct user_namespace *mnt_userns, const struct path *path,
 	/* Is the user requesting attributes that might need revalidation? */
 	if (!(request_mask & (STATX_MODE|STATX_NLINK|STATX_ATIME|STATX_CTIME|
 					STATX_MTIME|STATX_UID|STATX_GID|
-					STATX_SIZE|STATX_BLOCKS)))
+					STATX_SIZE|STATX_BLOCKS|STATX_BTIME)))
 		goto out_no_revalidate;
 
 	/* Check whether the cached attributes are stale */
@@ -905,6 +913,8 @@ int nfs_getattr(struct user_namespace *mnt_userns, const struct path *path,
 		do_update |= cache_validity & NFS_INO_INVALID_OTHER;
 	if (request_mask & STATX_BLOCKS)
 		do_update |= cache_validity & NFS_INO_INVALID_BLOCKS;
+	if (request_mask & STATX_BTIME)
+		do_update |= cache_validity & NFS_INO_INVALID_BTIME;
 
 	if (do_update) {
 		/* Update the attribute cache */
@@ -925,6 +935,7 @@ int nfs_getattr(struct user_namespace *mnt_userns, const struct path *path,
 	stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode));
 	if (S_ISDIR(inode->i_mode))
 		stat->blksize = NFS_SERVER(inode)->dtsize;
+	stat->btime = NFS_I(inode)->btime;
 out:
 	trace_nfs_getattr_exit(inode, err);
 	return err;
diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h
index 6ee6ad3674a2..186b851be5ba 100644
--- a/fs/nfs/nfs4trace.h
+++ b/fs/nfs/nfs4trace.h
@@ -30,7 +30,8 @@
 		{ NFS_ATTR_FATTR_CTIME, "CTIME" }, \
 		{ NFS_ATTR_FATTR_CHANGE, "CHANGE" }, \
 		{ NFS_ATTR_FATTR_OWNER_NAME, "OWNER_NAME" }, \
-		{ NFS_ATTR_FATTR_GROUP_NAME, "GROUP_NAME" })
+		{ NFS_ATTR_FATTR_GROUP_NAME, "GROUP_NAME" }, \
+		{ NFS_ATTR_FATTR_BTIME, "BTIME" })
 
 DECLARE_EVENT_CLASS(nfs4_clientid_event,
 		TP_PROTO(
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 4/8] nfs: Add 'archive', 'hidden' and 'system' fields to nfs inode
  2021-12-27 19:04     ` [PATCH v2 3/8] NFS: Return the file btime in the statx results when appropriate trondmy
@ 2021-12-27 19:05       ` trondmy
  2021-12-27 19:05         ` [PATCH v2 5/8] nfs: Add 'time backup' " trondmy
  0 siblings, 1 reply; 14+ messages in thread
From: trondmy @ 2021-12-27 19:05 UTC (permalink / raw)
  To: Anna Schumaker; +Cc: linux-nfs

From: Anne Marie Merritt <annemarie.merritt@primarydata.com>

Add tracking of the Windows 'archive', 'hidden' and 'system' attributes,
along with corresponding bitfields, request, and decode xdr routines.

Signed-off-by: Anne Marie Merritt <annemarie.merritt@primarydata.com>
Signed-off-by: Lance Shelton <lance.shelton@hammerspace.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
---
 fs/nfs/inode.c          |  42 +++++++++++++++--
 fs/nfs/nfs4proc.c       |  26 ++++++++++-
 fs/nfs/nfs4trace.h      |   5 +-
 fs/nfs/nfs4xdr.c        | 100 +++++++++++++++++++++++++++++++++++++---
 fs/nfs/nfstrace.h       |   3 +-
 include/linux/nfs_fs.h  |   5 ++
 include/linux/nfs_xdr.h |  12 +++++
 7 files changed, 179 insertions(+), 14 deletions(-)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 94268cab7613..9f138dc1880d 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -202,6 +202,7 @@ void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
 			flags &= ~(NFS_INO_INVALID_MODE |
 				   NFS_INO_INVALID_OTHER |
 				   NFS_INO_INVALID_BTIME |
+				   NFS_INO_INVALID_WINATTR |
 				   NFS_INO_INVALID_XATTR);
 		flags &= ~(NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_SIZE);
 	} else if (flags & NFS_INO_REVAL_PAGECACHE)
@@ -523,6 +524,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 		memset(&inode->i_mtime, 0, sizeof(inode->i_mtime));
 		memset(&inode->i_ctime, 0, sizeof(inode->i_ctime));
 		memset(&nfsi->btime, 0, sizeof(nfsi->btime));
+		nfsi->archive = 0;
+		nfsi->hidden = 0;
+		nfsi->system = 0;
 		inode_set_iversion_raw(inode, 0);
 		inode->i_size = 0;
 		clear_nlink(inode);
@@ -550,6 +554,18 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 			nfsi->btime = fattr->btime;
 		else if (fattr_supported & NFS_ATTR_FATTR_BTIME)
 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_BTIME);
+		if (fattr->valid & NFS_ATTR_FATTR_ARCHIVE)
+			nfsi->archive = (fattr->hsa_flags & NFS_HSA_ARCHIVE) ? 1 : 0;
+		else if (fattr_supported & NFS_ATTR_FATTR_ARCHIVE)
+			nfs_set_cache_invalid(inode, NFS_INO_INVALID_WINATTR);
+		if (fattr->valid & NFS_ATTR_FATTR_HIDDEN)
+			nfsi->hidden = (fattr->hsa_flags & NFS_HSA_HIDDEN) ? 1 : 0;
+		else if (fattr_supported & NFS_ATTR_FATTR_HIDDEN)
+			nfs_set_cache_invalid(inode, NFS_INO_INVALID_WINATTR);
+		if (fattr->valid & NFS_ATTR_FATTR_SYSTEM)
+			nfsi->system = (fattr->hsa_flags & NFS_HSA_SYSTEM) ? 1 : 0;
+		else if (fattr_supported & NFS_ATTR_FATTR_SYSTEM)
+			nfs_set_cache_invalid(inode, NFS_INO_INVALID_WINATTR);
 		if (fattr->valid & NFS_ATTR_FATTR_CHANGE)
 			inode_set_iversion_raw(inode, fattr->change_attr);
 		else
@@ -1818,7 +1834,8 @@ static int nfs_inode_finish_partial_attr_update(const struct nfs_fattr *fattr,
 		NFS_INO_INVALID_ATIME | NFS_INO_INVALID_CTIME |
 		NFS_INO_INVALID_MTIME | NFS_INO_INVALID_SIZE |
 		NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_OTHER |
-		NFS_INO_INVALID_NLINK | NFS_INO_INVALID_BTIME;
+		NFS_INO_INVALID_NLINK | NFS_INO_INVALID_BTIME |
+		NFS_INO_INVALID_WINATTR;
 	unsigned long cache_validity = NFS_I(inode)->cache_validity;
 	enum nfs4_change_attr_type ctype = NFS_SERVER(inode)->change_attr_type;
 
@@ -2075,7 +2092,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 		  NFS_INO_INVALID_MTIME | NFS_INO_INVALID_SIZE |
 		  NFS_INO_INVALID_OTHER | NFS_INO_INVALID_BLOCKS |
 		  NFS_INO_INVALID_NLINK | NFS_INO_INVALID_MODE |
-		  NFS_INO_INVALID_BTIME);
+		  NFS_INO_INVALID_BTIME | NFS_INO_INVALID_WINATTR);
 
 	/* Do atomic weak cache consistency updates */
 	nfs_wcc_update_inode(inode, fattr);
@@ -2106,7 +2123,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 					| NFS_INO_INVALID_NLINK
 					| NFS_INO_INVALID_MODE
 					| NFS_INO_INVALID_OTHER
-					| NFS_INO_INVALID_BTIME;
+					| NFS_INO_INVALID_BTIME
+					| NFS_INO_INVALID_WINATTR;
 				if (S_ISDIR(inode->i_mode))
 					nfs_force_lookup_revalidate(inode);
 				attr_changed = true;
@@ -2143,6 +2161,24 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 		nfsi->cache_validity |=
 			save_cache_validity & NFS_INO_INVALID_BTIME;
 
+	if (fattr->valid & NFS_ATTR_FATTR_ARCHIVE)
+		nfsi->archive = (fattr->hsa_flags & NFS_HSA_ARCHIVE) ? 1 : 0;
+	else if (fattr_supported & NFS_ATTR_FATTR_ARCHIVE)
+		nfsi->cache_validity |=
+			save_cache_validity & NFS_INO_INVALID_WINATTR;
+
+	if (fattr->valid & NFS_ATTR_FATTR_HIDDEN)
+		nfsi->hidden = (fattr->hsa_flags & NFS_HSA_HIDDEN) ? 1 : 0;
+	else if (fattr_supported & NFS_ATTR_FATTR_HIDDEN)
+		nfsi->cache_validity |=
+			save_cache_validity & NFS_INO_INVALID_WINATTR;
+
+	if (fattr->valid & NFS_ATTR_FATTR_SYSTEM)
+		nfsi->system = (fattr->hsa_flags & NFS_HSA_SYSTEM) ? 1 : 0;
+	else if (fattr_supported & NFS_ATTR_FATTR_SYSTEM)
+		nfsi->cache_validity |=
+			save_cache_validity & NFS_INO_INVALID_WINATTR;
+
 	/* Check if our cached file size is stale */
 	if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
 		new_isize = nfs_size_to_loff_t(fattr->size);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index be8eeb22b35f..99c7cf5944f8 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -200,13 +200,16 @@ const u32 nfs4_fattr_bitmap[3] = {
 	| FATTR4_WORD0_CHANGE
 	| FATTR4_WORD0_SIZE
 	| FATTR4_WORD0_FSID
-	| FATTR4_WORD0_FILEID,
+	| FATTR4_WORD0_ARCHIVE
+	| FATTR4_WORD0_FILEID
+	| FATTR4_WORD0_HIDDEN,
 	FATTR4_WORD1_MODE
 	| FATTR4_WORD1_NUMLINKS
 	| FATTR4_WORD1_OWNER
 	| FATTR4_WORD1_OWNER_GROUP
 	| FATTR4_WORD1_RAWDEV
 	| FATTR4_WORD1_SPACE_USED
+	| FATTR4_WORD1_SYSTEM
 	| FATTR4_WORD1_TIME_ACCESS
 	| FATTR4_WORD1_TIME_CREATE
 	| FATTR4_WORD1_TIME_METADATA
@@ -222,13 +225,16 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
 	| FATTR4_WORD0_CHANGE
 	| FATTR4_WORD0_SIZE
 	| FATTR4_WORD0_FSID
-	| FATTR4_WORD0_FILEID,
+	| FATTR4_WORD0_ARCHIVE
+	| FATTR4_WORD0_FILEID
+	| FATTR4_WORD0_HIDDEN,
 	FATTR4_WORD1_MODE
 	| FATTR4_WORD1_NUMLINKS
 	| FATTR4_WORD1_OWNER
 	| FATTR4_WORD1_OWNER_GROUP
 	| FATTR4_WORD1_RAWDEV
 	| FATTR4_WORD1_SPACE_USED
+	| FATTR4_WORD1_SYSTEM
 	| FATTR4_WORD1_TIME_ACCESS
 	| FATTR4_WORD1_TIME_CREATE
 	| FATTR4_WORD1_TIME_METADATA
@@ -313,6 +319,11 @@ static void nfs4_bitmap_copy_adjust(__u32 *dst, const __u32 *src,
 
 	if (!(cache_validity & NFS_INO_INVALID_BTIME))
 		dst[1] &= ~FATTR4_WORD1_TIME_CREATE;
+
+	if (!(cache_validity & NFS_INO_INVALID_WINATTR)) {
+		dst[0] &= ~(FATTR4_WORD0_ARCHIVE | FATTR4_WORD0_HIDDEN);
+		dst[1] &= ~FATTR4_WORD1_SYSTEM;
+	}
 }
 
 static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry,
@@ -1239,6 +1250,7 @@ nfs4_update_changeattr_locked(struct inode *inode,
 				NFS_INO_INVALID_SIZE | NFS_INO_INVALID_OTHER |
 				NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_NLINK |
 				NFS_INO_INVALID_MODE | NFS_INO_INVALID_BTIME |
+				NFS_INO_INVALID_WINATTR |
 				NFS_INO_INVALID_XATTR | NFS_INO_REVAL_PAGECACHE;
 		nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
 	}
@@ -3878,8 +3890,12 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
 		if (res.attr_bitmask[2] & FATTR4_WORD2_SECURITY_LABEL)
 			server->caps |= NFS_CAP_SECURITY_LABEL;
 #endif
+		if (!(res.attr_bitmask[0] & FATTR4_WORD0_ARCHIVE))
+			server->fattr_valid &= ~NFS_ATTR_FATTR_ARCHIVE;
 		if (!(res.attr_bitmask[0] & FATTR4_WORD0_FILEID))
 			server->fattr_valid &= ~NFS_ATTR_FATTR_FILEID;
+		if (!(res.attr_bitmask[0] & FATTR4_WORD0_HIDDEN))
+			server->fattr_valid &= ~NFS_ATTR_FATTR_HIDDEN;
 		if (!(res.attr_bitmask[1] & FATTR4_WORD1_MODE))
 			server->fattr_valid &= ~NFS_ATTR_FATTR_MODE;
 		if (!(res.attr_bitmask[1] & FATTR4_WORD1_NUMLINKS))
@@ -3902,6 +3918,8 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
 			server->fattr_valid &= ~NFS_ATTR_FATTR_MTIME;
 		if (!(res.attr_bitmask[1] & FATTR4_WORD1_TIME_CREATE))
 			server->fattr_valid &= ~NFS_ATTR_FATTR_BTIME;
+		if (!(res.attr_bitmask[1] & FATTR4_WORD1_SYSTEM))
+			server->fattr_valid &= ~NFS_ATTR_FATTR_SYSTEM;
 		memcpy(server->attr_bitmask_nl, res.attr_bitmask,
 				sizeof(server->attr_bitmask));
 		server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
@@ -5461,6 +5479,10 @@ static void nfs4_bitmask_set(__u32 bitmask[NFS4_BITMASK_SZ], const __u32 *src,
 		bitmask[1] |= FATTR4_WORD1_SPACE_USED;
 	if (cache_validity & NFS_INO_INVALID_BTIME)
 		bitmask[1] |= FATTR4_WORD1_TIME_CREATE;
+	if (cache_validity & NFS_INO_INVALID_WINATTR) {
+		bitmask[0] |= FATTR4_WORD0_ARCHIVE | FATTR4_WORD0_HIDDEN;
+		bitmask[1] |= FATTR4_WORD1_SYSTEM;
+	}
 
 	if (cache_validity & NFS_INO_INVALID_SIZE)
 		bitmask[0] |= FATTR4_WORD0_SIZE;
diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h
index 186b851be5ba..babcd3207e8f 100644
--- a/fs/nfs/nfs4trace.h
+++ b/fs/nfs/nfs4trace.h
@@ -31,7 +31,10 @@
 		{ NFS_ATTR_FATTR_CHANGE, "CHANGE" }, \
 		{ NFS_ATTR_FATTR_OWNER_NAME, "OWNER_NAME" }, \
 		{ NFS_ATTR_FATTR_GROUP_NAME, "GROUP_NAME" }, \
-		{ NFS_ATTR_FATTR_BTIME, "BTIME" })
+		{ NFS_ATTR_FATTR_BTIME, "BTIME" }, \
+		{ NFS_ATTR_FATTR_HIDDEN, "HIDDEN" }, \
+		{ NFS_ATTR_FATTR_SYSTEM, "SYSTEM" }, \
+		{ NFS_ATTR_FATTR_ARCHIVE, "ARCHIVE" })
 
 DECLARE_EVENT_CLASS(nfs4_clientid_event,
 		TP_PROTO(
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 33ab1377f443..2131754e64f0 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -1611,13 +1611,17 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
 	unsigned int i;
 
 	if (readdir->plus) {
-		attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE|
-			FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE|FATTR4_WORD0_FILEID;
-		attrs[1] |= FATTR4_WORD1_MODE|FATTR4_WORD1_NUMLINKS|FATTR4_WORD1_OWNER|
-			FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV|
-			FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS|
-			FATTR4_WORD1_TIME_CREATE |
-			FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
+		attrs[0] |= FATTR4_WORD0_TYPE | FATTR4_WORD0_CHANGE |
+			    FATTR4_WORD0_SIZE| FATTR4_WORD0_FSID |
+			    FATTR4_WORD0_ARCHIVE | FATTR4_WORD0_FILEHANDLE |
+			    FATTR4_WORD0_FILEID | FATTR4_WORD0_HIDDEN;
+		attrs[1] |= FATTR4_WORD1_MODE | FATTR4_WORD1_NUMLINKS |
+			    FATTR4_WORD1_OWNER| FATTR4_WORD1_OWNER_GROUP |
+			    FATTR4_WORD1_RAWDEV | FATTR4_WORD1_SPACE_USED |
+			    FATTR4_WORD1_SYSTEM | FATTR4_WORD1_TIME_ACCESS |
+			    FATTR4_WORD1_TIME_CREATE |
+			    FATTR4_WORD1_TIME_METADATA |
+			    FATTR4_WORD1_TIME_MODIFY;
 		attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
 		dircount >>= 1;
 	}
@@ -3534,6 +3538,28 @@ static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint
 	return 0;
 }
 
+static int decode_attr_archive(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+{
+	int status = 0;
+	__be32 *p;
+
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_ARCHIVE - 1U)))
+		return -EIO;
+	if (likely(bitmap[0] & FATTR4_WORD0_ARCHIVE)) {
+		p = xdr_inline_decode(xdr, 4);
+		if (unlikely(!p))
+			return -EIO;
+		if (be32_to_cpup(p))
+			*res |= NFS_HSA_ARCHIVE;
+		else
+			*res &= ~NFS_HSA_ARCHIVE;
+		bitmap[0] &= ~FATTR4_WORD0_ARCHIVE;
+		status = NFS_ATTR_FATTR_ARCHIVE;
+	}
+	dprintk("%s: archive file: =%s\n", __func__, (*res & NFS_HSA_ARCHIVE) == 0 ? "false" : "true");
+	return status;
+}
+
 static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
 {
 	__be32 *p;
@@ -3751,6 +3777,28 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st
 	goto out;
 }
 
+static int decode_attr_hidden(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+{
+	int status = 0;
+	__be32 *p;
+
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_HIDDEN - 1U)))
+		return -EIO;
+	if (likely(bitmap[0] & FATTR4_WORD0_HIDDEN)) {
+		p = xdr_inline_decode(xdr, 4);
+		if (unlikely(!p))
+			return -EIO;
+		if (be32_to_cpup(p))
+			*res |= NFS_HSA_HIDDEN;
+		else
+			*res &= ~NFS_HSA_HIDDEN;
+		bitmap[0] &= ~FATTR4_WORD0_HIDDEN;
+		status = NFS_ATTR_FATTR_HIDDEN;
+	}
+	dprintk("%s: hidden file: =%s\n", __func__, (*res & NFS_HSA_HIDDEN) == 0 ? "false" : "true");
+	return status;
+}
+
 static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
 {
 	__be32 *p;
@@ -4082,6 +4130,28 @@ static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint
 	return ret;
 }
 
+static int decode_attr_system(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+{
+	int status = 0;
+	__be32 *p;
+
+	if (unlikely(bitmap[1] & (FATTR4_WORD1_SYSTEM - 1U)))
+		return -EIO;
+	if (likely(bitmap[1] & FATTR4_WORD1_SYSTEM)) {
+		p = xdr_inline_decode(xdr, 4);
+		if (unlikely(!p))
+			return -EIO;
+		if (be32_to_cpup(p))
+			*res |= NFS_HSA_SYSTEM;
+		else
+			*res &= ~NFS_HSA_SYSTEM;
+		bitmap[1] &= ~FATTR4_WORD1_SYSTEM;
+		status = NFS_ATTR_FATTR_SYSTEM;
+	}
+	dprintk("%s: system file: =%s\n", __func__, (*res & NFS_HSA_HIDDEN) == 0 ? "false" : "true");
+	return status;
+}
+
 static __be32 *
 xdr_decode_nfstime4(__be32 *p, struct timespec64 *t)
 {
@@ -4641,6 +4711,12 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
 	if (status < 0)
 		goto xdr_error;
 
+	fattr->hsa_flags = 0;
+	status = decode_attr_archive(xdr, bitmap, &fattr->hsa_flags);
+	if (status < 0)
+		goto xdr_error;
+	fattr->valid |= status;
+
 	status = decode_attr_filehandle(xdr, bitmap, fh);
 	if (status < 0)
 		goto xdr_error;
@@ -4655,6 +4731,11 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
 		goto xdr_error;
 	fattr->valid |= status;
 
+	status = decode_attr_hidden(xdr, bitmap, &fattr->hsa_flags);
+	if (status < 0)
+		goto xdr_error;
+	fattr->valid |= status;
+
 	status = -EIO;
 	if (unlikely(bitmap[0]))
 		goto xdr_error;
@@ -4692,6 +4773,11 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
 		goto xdr_error;
 	fattr->valid |= status;
 
+	status = decode_attr_system(xdr, bitmap, &fattr->hsa_flags);
+	if (status < 0)
+		goto xdr_error;
+	fattr->valid |= status;
+
 	status = decode_attr_time_access(xdr, bitmap, &fattr->atime);
 	if (status < 0)
 		goto xdr_error;
diff --git a/fs/nfs/nfstrace.h b/fs/nfs/nfstrace.h
index cba86d167c38..2ef7cff8a4ba 100644
--- a/fs/nfs/nfstrace.h
+++ b/fs/nfs/nfstrace.h
@@ -34,7 +34,8 @@
 			{ NFS_INO_INVALID_XATTR, "INVALID_XATTR" }, \
 			{ NFS_INO_INVALID_NLINK, "INVALID_NLINK" }, \
 			{ NFS_INO_INVALID_MODE, "INVALID_MODE" }, \
-			{ NFS_INO_INVALID_BTIME, "INVALID_BTIME" })
+			{ NFS_INO_INVALID_BTIME, "INVALID_BTIME" }, \
+			{ NFS_INO_INVALID_WINATTR, "INVALID_WINATTR" })
 
 #define nfs_show_nfsi_flags(v) \
 	__print_flags(v, "|", \
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 8d944d399b17..34288dcf8547 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -144,6 +144,10 @@ struct nfs_inode {
 
 	struct timespec64	btime;
 
+	unsigned char		archive : 1;
+	unsigned char		hidden : 1;
+	unsigned char		system : 1;
+
 	/*
 	 * read_cache_jiffies is when we started read-caching this inode.
 	 * attrtimeo is for how long the cached information is assumed
@@ -267,6 +271,7 @@ struct nfs4_copy_state {
 #define NFS_INO_INVALID_NLINK	BIT(16)		/* cached nlinks is invalid */
 #define NFS_INO_INVALID_MODE	BIT(17)		/* cached mode is invalid */
 #define NFS_INO_INVALID_BTIME	BIT(18)		/* cached btime is invalid */
+#define NFS_INO_INVALID_WINATTR	BIT(19)		/* cached windows attr is invalid */
 
 #define NFS_INO_INVALID_ATTR	(NFS_INO_INVALID_CHANGE \
 		| NFS_INO_INVALID_CTIME \
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 8e8ff5def523..308324d197f4 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -17,6 +17,11 @@
 
 #define NFS_BITMASK_SZ		3
 
+/* HIDDEN, SYSTEM bitfields in hsa_flags in nfs_fattr */
+#define NFS_HSA_HIDDEN		BIT(0)
+#define NFS_HSA_SYSTEM		BIT(1)
+#define NFS_HSA_ARCHIVE		BIT(2)
+
 struct nfs4_string {
 	unsigned int len;
 	char *data;
@@ -68,6 +73,7 @@ struct nfs_fattr {
 	struct timespec64	mtime;
 	struct timespec64	ctime;
 	struct timespec64	btime;
+	__u32			hsa_flags;	/* hidden, system, archive flags bitfield */
 	__u64			change_attr;	/* NFSv4 change attribute */
 	__u64			pre_change_attr;/* pre-op NFSv4 change attribute */
 	__u64			pre_size;	/* pre_op_attr.size	  */
@@ -108,6 +114,9 @@ struct nfs_fattr {
 #define NFS_ATTR_FATTR_GROUP_NAME	BIT_ULL(24)
 #define NFS_ATTR_FATTR_V4_SECURITY_LABEL BIT_ULL(25)
 #define NFS_ATTR_FATTR_BTIME		BIT_ULL(26)
+#define NFS_ATTR_FATTR_HIDDEN           BIT_ULL(27)
+#define NFS_ATTR_FATTR_SYSTEM           BIT_ULL(28)
+#define NFS_ATTR_FATTR_ARCHIVE          BIT_ULL(29)
 
 #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
 		| NFS_ATTR_FATTR_MODE \
@@ -129,6 +138,9 @@ struct nfs_fattr {
 #define NFS_ATTR_FATTR_V4 (NFS_ATTR_FATTR \
 		| NFS_ATTR_FATTR_SPACE_USED \
 		| NFS_ATTR_FATTR_BTIME \
+		| NFS_ATTR_FATTR_HIDDEN \
+		| NFS_ATTR_FATTR_SYSTEM \
+		| NFS_ATTR_FATTR_ARCHIVE \
 		| NFS_ATTR_FATTR_V4_SECURITY_LABEL)
 
 /*
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 5/8] nfs: Add 'time backup' to nfs inode
  2021-12-27 19:05       ` [PATCH v2 4/8] nfs: Add 'archive', 'hidden' and 'system' fields to nfs inode trondmy
@ 2021-12-27 19:05         ` trondmy
  2021-12-27 19:05           ` [PATCH v2 6/8] NFSv4: Support the offline bit trondmy
  0 siblings, 1 reply; 14+ messages in thread
From: trondmy @ 2021-12-27 19:05 UTC (permalink / raw)
  To: Anna Schumaker; +Cc: linux-nfs

From: Anne Marie Merritt <annemarie.merritt@primarydata.com>

Add tracking of the NFSv4 'time backup' attribute, along with
corresponding bitfields, request, and decode xdr routines.

Signed-off-by: Anne Marie Merritt <annemarie.merritt@primarydata.com>
Signed-off-by: Lance Shelton <lance.shelton@hammerspace.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
---
 fs/nfs/inode.c          | 11 +++++++++++
 fs/nfs/nfs4proc.c       |  8 ++++++--
 fs/nfs/nfs4trace.h      |  3 ++-
 fs/nfs/nfs4xdr.c        | 24 ++++++++++++++++++++++++
 include/linux/nfs_fs.h  |  1 +
 include/linux/nfs_xdr.h |  3 +++
 6 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 9f138dc1880d..4673b091ea31 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -524,6 +524,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 		memset(&inode->i_mtime, 0, sizeof(inode->i_mtime));
 		memset(&inode->i_ctime, 0, sizeof(inode->i_ctime));
 		memset(&nfsi->btime, 0, sizeof(nfsi->btime));
+		memset(&nfsi->timebackup, 0, sizeof(nfsi->timebackup));
 		nfsi->archive = 0;
 		nfsi->hidden = 0;
 		nfsi->system = 0;
@@ -554,6 +555,10 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 			nfsi->btime = fattr->btime;
 		else if (fattr_supported & NFS_ATTR_FATTR_BTIME)
 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_BTIME);
+		if (fattr->valid & NFS_ATTR_FATTR_TIME_BACKUP)
+			nfsi->timebackup = fattr->time_backup;
+		else if (fattr_supported & NFS_ATTR_FATTR_TIME_BACKUP)
+			nfs_set_cache_invalid(inode, NFS_INO_INVALID_WINATTR);
 		if (fattr->valid & NFS_ATTR_FATTR_ARCHIVE)
 			nfsi->archive = (fattr->hsa_flags & NFS_HSA_ARCHIVE) ? 1 : 0;
 		else if (fattr_supported & NFS_ATTR_FATTR_ARCHIVE)
@@ -2161,6 +2166,12 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 		nfsi->cache_validity |=
 			save_cache_validity & NFS_INO_INVALID_BTIME;
 
+	if (fattr->valid & NFS_ATTR_FATTR_TIME_BACKUP)
+		nfsi->timebackup = fattr->time_backup;
+	else if (fattr_supported & NFS_ATTR_FATTR_TIME_BACKUP)
+		nfsi->cache_validity |=
+			save_cache_validity & NFS_INO_INVALID_WINATTR;
+
 	if (fattr->valid & NFS_ATTR_FATTR_ARCHIVE)
 		nfsi->archive = (fattr->hsa_flags & NFS_HSA_ARCHIVE) ? 1 : 0;
 	else if (fattr_supported & NFS_ATTR_FATTR_ARCHIVE)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 99c7cf5944f8..4e6cc54016ba 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -211,6 +211,7 @@ const u32 nfs4_fattr_bitmap[3] = {
 	| FATTR4_WORD1_SPACE_USED
 	| FATTR4_WORD1_SYSTEM
 	| FATTR4_WORD1_TIME_ACCESS
+	| FATTR4_WORD1_TIME_BACKUP
 	| FATTR4_WORD1_TIME_CREATE
 	| FATTR4_WORD1_TIME_METADATA
 	| FATTR4_WORD1_TIME_MODIFY
@@ -236,6 +237,7 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
 	| FATTR4_WORD1_SPACE_USED
 	| FATTR4_WORD1_SYSTEM
 	| FATTR4_WORD1_TIME_ACCESS
+	| FATTR4_WORD1_TIME_BACKUP
 	| FATTR4_WORD1_TIME_CREATE
 	| FATTR4_WORD1_TIME_METADATA
 	| FATTR4_WORD1_TIME_MODIFY,
@@ -322,7 +324,7 @@ static void nfs4_bitmap_copy_adjust(__u32 *dst, const __u32 *src,
 
 	if (!(cache_validity & NFS_INO_INVALID_WINATTR)) {
 		dst[0] &= ~(FATTR4_WORD0_ARCHIVE | FATTR4_WORD0_HIDDEN);
-		dst[1] &= ~FATTR4_WORD1_SYSTEM;
+		dst[1] &= ~(FATTR4_WORD1_SYSTEM | FATTR4_WORD1_TIME_BACKUP);
 	}
 }
 
@@ -3916,6 +3918,8 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
 			server->fattr_valid &= ~NFS_ATTR_FATTR_MTIME;
 		if (!(res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY))
 			server->fattr_valid &= ~NFS_ATTR_FATTR_MTIME;
+		if (!(res.attr_bitmask[1] & FATTR4_WORD1_TIME_BACKUP))
+			server->fattr_valid &= ~NFS_ATTR_FATTR_TIME_BACKUP;
 		if (!(res.attr_bitmask[1] & FATTR4_WORD1_TIME_CREATE))
 			server->fattr_valid &= ~NFS_ATTR_FATTR_BTIME;
 		if (!(res.attr_bitmask[1] & FATTR4_WORD1_SYSTEM))
@@ -5481,7 +5485,7 @@ static void nfs4_bitmask_set(__u32 bitmask[NFS4_BITMASK_SZ], const __u32 *src,
 		bitmask[1] |= FATTR4_WORD1_TIME_CREATE;
 	if (cache_validity & NFS_INO_INVALID_WINATTR) {
 		bitmask[0] |= FATTR4_WORD0_ARCHIVE | FATTR4_WORD0_HIDDEN;
-		bitmask[1] |= FATTR4_WORD1_SYSTEM;
+		bitmask[1] |= FATTR4_WORD1_SYSTEM | FATTR4_WORD1_TIME_BACKUP;
 	}
 
 	if (cache_validity & NFS_INO_INVALID_SIZE)
diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h
index babcd3207e8f..5e72639b469e 100644
--- a/fs/nfs/nfs4trace.h
+++ b/fs/nfs/nfs4trace.h
@@ -34,7 +34,8 @@
 		{ NFS_ATTR_FATTR_BTIME, "BTIME" }, \
 		{ NFS_ATTR_FATTR_HIDDEN, "HIDDEN" }, \
 		{ NFS_ATTR_FATTR_SYSTEM, "SYSTEM" }, \
-		{ NFS_ATTR_FATTR_ARCHIVE, "ARCHIVE" })
+		{ NFS_ATTR_FATTR_ARCHIVE, "ARCHIVE" }, \
+		{ NFS_ATTR_FATTR_TIME_BACKUP, "TIME_BACKUP" })
 
 DECLARE_EVENT_CLASS(nfs4_clientid_event,
 		TP_PROTO(
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 2131754e64f0..280df43c5bf2 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -1619,6 +1619,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
 			    FATTR4_WORD1_OWNER| FATTR4_WORD1_OWNER_GROUP |
 			    FATTR4_WORD1_RAWDEV | FATTR4_WORD1_SPACE_USED |
 			    FATTR4_WORD1_SYSTEM | FATTR4_WORD1_TIME_ACCESS |
+			    FATTR4_WORD1_TIME_BACKUP |
 			    FATTR4_WORD1_TIME_CREATE |
 			    FATTR4_WORD1_TIME_METADATA |
 			    FATTR4_WORD1_TIME_MODIFY;
@@ -4192,6 +4193,24 @@ static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, str
 	return status;
 }
 
+static int decode_attr_time_backup(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec64 *time)
+{
+	int status = 0;
+
+	time->tv_sec = 0;
+	time->tv_nsec = 0;
+	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_BACKUP - 1U)))
+		return -EIO;
+	if (likely(bitmap[1] & FATTR4_WORD1_TIME_BACKUP)) {
+		status = decode_attr_time(xdr, time);
+		if (status == 0)
+			status = NFS_ATTR_FATTR_TIME_BACKUP;
+		bitmap[1] &= ~FATTR4_WORD1_TIME_BACKUP;
+	}
+	dprintk("%s: time_backup=%ld\n", __func__, (long)time->tv_sec);
+	return status;
+}
+
 static int decode_attr_time_create(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec64 *time)
 {
 	int status = 0;
@@ -4783,6 +4802,11 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
 		goto xdr_error;
 	fattr->valid |= status;
 
+	status = decode_attr_time_backup(xdr, bitmap, &fattr->time_backup);
+	if (status < 0)
+		goto xdr_error;
+	fattr->valid |= status;
+
 	status = decode_attr_time_create(xdr, bitmap, &fattr->btime);
 	if (status < 0)
 		goto xdr_error;
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 34288dcf8547..1839fed16b18 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -143,6 +143,7 @@ struct nfs_inode {
 	 */
 
 	struct timespec64	btime;
+	struct timespec64	timebackup;
 
 	unsigned char		archive : 1;
 	unsigned char		hidden : 1;
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 308324d197f4..dedc7e0bf2b9 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -73,6 +73,7 @@ struct nfs_fattr {
 	struct timespec64	mtime;
 	struct timespec64	ctime;
 	struct timespec64	btime;
+	struct timespec64	time_backup;
 	__u32			hsa_flags;	/* hidden, system, archive flags bitfield */
 	__u64			change_attr;	/* NFSv4 change attribute */
 	__u64			pre_change_attr;/* pre-op NFSv4 change attribute */
@@ -117,6 +118,7 @@ struct nfs_fattr {
 #define NFS_ATTR_FATTR_HIDDEN           BIT_ULL(27)
 #define NFS_ATTR_FATTR_SYSTEM           BIT_ULL(28)
 #define NFS_ATTR_FATTR_ARCHIVE          BIT_ULL(29)
+#define NFS_ATTR_FATTR_TIME_BACKUP      BIT_ULL(30)
 
 #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
 		| NFS_ATTR_FATTR_MODE \
@@ -141,6 +143,7 @@ struct nfs_fattr {
 		| NFS_ATTR_FATTR_HIDDEN \
 		| NFS_ATTR_FATTR_SYSTEM \
 		| NFS_ATTR_FATTR_ARCHIVE \
+		| NFS_ATTR_FATTR_TIME_BACKUP \
 		| NFS_ATTR_FATTR_V4_SECURITY_LABEL)
 
 /*
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 6/8] NFSv4: Support the offline bit
  2021-12-27 19:05         ` [PATCH v2 5/8] nfs: Add 'time backup' " trondmy
@ 2021-12-27 19:05           ` trondmy
  2021-12-27 19:05             ` [PATCH v2 7/8] NFS: Support statx_get and statx_set ioctls trondmy
  2022-01-07 14:23             ` [PATCH v2 6/8] NFSv4: Support the offline bit Anna Schumaker
  0 siblings, 2 replies; 14+ messages in thread
From: trondmy @ 2021-12-27 19:05 UTC (permalink / raw)
  To: Anna Schumaker; +Cc: linux-nfs

From: Trond Myklebust <trond.myklebust@primarydata.com>

Add tracking of the NFSv4 'offline' attribute.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Lance Shelton <lance.shelton@hammerspace.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
---
 fs/nfs/inode.c          | 11 +++++++++++
 fs/nfs/nfs4proc.c       |  6 ++++++
 fs/nfs/nfs4trace.h      |  3 ++-
 fs/nfs/nfs4xdr.c        | 31 ++++++++++++++++++++++++++++++-
 include/linux/nfs4.h    |  1 +
 include/linux/nfs_fs.h  |  1 +
 include/linux/nfs_xdr.h |  5 ++++-
 7 files changed, 55 insertions(+), 3 deletions(-)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 4673b091ea31..33f4410190b6 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -528,6 +528,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 		nfsi->archive = 0;
 		nfsi->hidden = 0;
 		nfsi->system = 0;
+		nfsi->offline = 0;
 		inode_set_iversion_raw(inode, 0);
 		inode->i_size = 0;
 		clear_nlink(inode);
@@ -606,6 +607,10 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 		} else if (fattr_supported & NFS_ATTR_FATTR_SPACE_USED &&
 			   fattr->size != 0)
 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_BLOCKS);
+		if (fattr->valid & NFS_ATTR_FATTR_OFFLINE)
+			nfsi->offline = (fattr->hsa_flags & NFS_HSA_OFFLINE) ? 1 : 0;
+		else if (fattr_supported & NFS_ATTR_FATTR_OFFLINE)
+			nfs_set_cache_invalid(inode, NFS_INO_INVALID_WINATTR);
 
 		nfs_setsecurity(inode, fattr);
 
@@ -2274,6 +2279,12 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 		nfsi->cache_validity |=
 			save_cache_validity & NFS_INO_INVALID_BLOCKS;
 
+	if (fattr->valid & NFS_ATTR_FATTR_OFFLINE)
+		nfsi->offline = (fattr->hsa_flags & NFS_HSA_OFFLINE) ? 1 : 0;
+	else if (fattr_supported & NFS_ATTR_FATTR_OFFLINE)
+		nfsi->cache_validity |=
+			save_cache_validity & NFS_INO_INVALID_WINATTR;
+
 	/* Update attrtimeo value if we're out of the unstable period */
 	if (attr_changed) {
 		nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 4e6cc54016ba..713a71fb3020 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -219,6 +219,7 @@ const u32 nfs4_fattr_bitmap[3] = {
 #ifdef CONFIG_NFS_V4_SECURITY_LABEL
 	FATTR4_WORD2_SECURITY_LABEL
 #endif
+	| FATTR4_WORD2_OFFLINE
 };
 
 static const u32 nfs4_pnfs_open_bitmap[3] = {
@@ -245,6 +246,7 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
 #ifdef CONFIG_NFS_V4_SECURITY_LABEL
 	| FATTR4_WORD2_SECURITY_LABEL
 #endif
+	| FATTR4_WORD2_OFFLINE
 };
 
 static const u32 nfs4_open_noattr_bitmap[3] = {
@@ -325,6 +327,7 @@ static void nfs4_bitmap_copy_adjust(__u32 *dst, const __u32 *src,
 	if (!(cache_validity & NFS_INO_INVALID_WINATTR)) {
 		dst[0] &= ~(FATTR4_WORD0_ARCHIVE | FATTR4_WORD0_HIDDEN);
 		dst[1] &= ~(FATTR4_WORD1_SYSTEM | FATTR4_WORD1_TIME_BACKUP);
+		dst[2] &= ~FATTR4_WORD2_OFFLINE;
 	}
 }
 
@@ -3927,6 +3930,8 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
 		memcpy(server->attr_bitmask_nl, res.attr_bitmask,
 				sizeof(server->attr_bitmask));
 		server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
+		if (!(res.attr_bitmask[2] & FATTR4_WORD2_OFFLINE))
+			server->fattr_valid &= ~NFS_ATTR_FATTR_OFFLINE;
 
 		memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask));
 		server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
@@ -5486,6 +5491,7 @@ static void nfs4_bitmask_set(__u32 bitmask[NFS4_BITMASK_SZ], const __u32 *src,
 	if (cache_validity & NFS_INO_INVALID_WINATTR) {
 		bitmask[0] |= FATTR4_WORD0_ARCHIVE | FATTR4_WORD0_HIDDEN;
 		bitmask[1] |= FATTR4_WORD1_SYSTEM | FATTR4_WORD1_TIME_BACKUP;
+		bitmask[2] |= FATTR4_WORD2_OFFLINE;
 	}
 
 	if (cache_validity & NFS_INO_INVALID_SIZE)
diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h
index 5e72639b469e..02c78d66c36d 100644
--- a/fs/nfs/nfs4trace.h
+++ b/fs/nfs/nfs4trace.h
@@ -35,7 +35,8 @@
 		{ NFS_ATTR_FATTR_HIDDEN, "HIDDEN" }, \
 		{ NFS_ATTR_FATTR_SYSTEM, "SYSTEM" }, \
 		{ NFS_ATTR_FATTR_ARCHIVE, "ARCHIVE" }, \
-		{ NFS_ATTR_FATTR_TIME_BACKUP, "TIME_BACKUP" })
+		{ NFS_ATTR_FATTR_TIME_BACKUP, "TIME_BACKUP" }, \
+		{ NFS_ATTR_FATTR_OFFLINE, "OFFLINE" })
 
 DECLARE_EVENT_CLASS(nfs4_clientid_event,
 		TP_PROTO(
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 280df43c5bf2..a45872f860ec 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -1623,7 +1623,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
 			    FATTR4_WORD1_TIME_CREATE |
 			    FATTR4_WORD1_TIME_METADATA |
 			    FATTR4_WORD1_TIME_MODIFY;
-		attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
+		attrs[2] |= FATTR4_WORD2_SECURITY_LABEL | FATTR4_WORD2_OFFLINE;
 		dircount >>= 1;
 	}
 	/* Use mounted_on_fileid only if the server supports it */
@@ -4354,6 +4354,29 @@ static int decode_attr_xattrsupport(struct xdr_stream *xdr, uint32_t *bitmap,
 	return 0;
 }
 
+static int decode_attr_offline(struct xdr_stream *xdr, uint32_t *bitmap,
+			       uint32_t *res, uint64_t *flags)
+{
+	int status = 0;
+	__be32 *p;
+
+	if (unlikely(bitmap[2] & (FATTR4_WORD2_OFFLINE - 1U)))
+		return -EIO;
+	if (likely(bitmap[2] & FATTR4_WORD2_OFFLINE)) {
+		p = xdr_inline_decode(xdr, 4);
+		if (unlikely(!p))
+			return -EIO;
+		if (be32_to_cpup(p))
+			*res |= NFS_HSA_OFFLINE;
+		else
+			*res &= ~NFS_HSA_OFFLINE;
+		bitmap[2] &= ~FATTR4_WORD2_OFFLINE;
+		*flags |= NFS_ATTR_FATTR_OFFLINE;
+	}
+	dprintk("%s: system file: =%s\n", __func__, (*res & NFS_HSA_OFFLINE) == 0 ? "false" : "true");
+	return status;
+}
+
 static int verify_attr_len(struct xdr_stream *xdr, unsigned int savep, uint32_t attrlen)
 {
 	unsigned int attrwords = XDR_QUADLEN(attrlen);
@@ -4842,6 +4865,12 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
 		fattr->valid |= status;
 	}
 
+	status = decode_attr_offline(xdr, bitmap, &fattr->hsa_flags,
+				     &fattr->valid);
+	if (status < 0)
+		goto xdr_error;
+
+	status = 0;
 xdr_error:
 	dprintk("%s: xdr returned %d\n", __func__, -status);
 	return status;
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 5662d8be04eb..817b349c24ca 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -460,6 +460,7 @@ enum lock_type4 {
 #define FATTR4_WORD2_SECURITY_LABEL     (1UL << 16)
 #define FATTR4_WORD2_MODE_UMASK		(1UL << 17)
 #define FATTR4_WORD2_XATTR_SUPPORT	(1UL << 18)
+#define FATTR4_WORD2_OFFLINE		(1UL << 19)
 
 /* MDS threshold bitmap bits */
 #define THRESHOLD_RD                    (1UL << 0)
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 1839fed16b18..61f852ebb0a4 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -148,6 +148,7 @@ struct nfs_inode {
 	unsigned char		archive : 1;
 	unsigned char		hidden : 1;
 	unsigned char		system : 1;
+	unsigned char		offline : 1;
 
 	/*
 	 * read_cache_jiffies is when we started read-caching this inode.
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index dedc7e0bf2b9..f5588bc22cb1 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -21,6 +21,7 @@
 #define NFS_HSA_HIDDEN		BIT(0)
 #define NFS_HSA_SYSTEM		BIT(1)
 #define NFS_HSA_ARCHIVE		BIT(2)
+#define NFS_HSA_OFFLINE		BIT(3)
 
 struct nfs4_string {
 	unsigned int len;
@@ -119,6 +120,7 @@ struct nfs_fattr {
 #define NFS_ATTR_FATTR_SYSTEM           BIT_ULL(28)
 #define NFS_ATTR_FATTR_ARCHIVE          BIT_ULL(29)
 #define NFS_ATTR_FATTR_TIME_BACKUP      BIT_ULL(30)
+#define NFS_ATTR_FATTR_OFFLINE          BIT_ULL(31)
 
 #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
 		| NFS_ATTR_FATTR_MODE \
@@ -144,7 +146,8 @@ struct nfs_fattr {
 		| NFS_ATTR_FATTR_SYSTEM \
 		| NFS_ATTR_FATTR_ARCHIVE \
 		| NFS_ATTR_FATTR_TIME_BACKUP \
-		| NFS_ATTR_FATTR_V4_SECURITY_LABEL)
+		| NFS_ATTR_FATTR_V4_SECURITY_LABEL \
+		| NFS_ATTR_FATTR_OFFLINE)
 
 /*
  * Maximal number of supported layout drivers.
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 7/8] NFS: Support statx_get and statx_set ioctls
  2021-12-27 19:05           ` [PATCH v2 6/8] NFSv4: Support the offline bit trondmy
@ 2021-12-27 19:05             ` trondmy
  2021-12-27 19:05               ` [PATCH v2 8/8] NFSv4: Add an ioctl to allow retrieval of the NFS raw ACCESS mask trondmy
  2022-01-07 14:23             ` [PATCH v2 6/8] NFSv4: Support the offline bit Anna Schumaker
  1 sibling, 1 reply; 14+ messages in thread
From: trondmy @ 2021-12-27 19:05 UTC (permalink / raw)
  To: Anna Schumaker; +Cc: linux-nfs

From: Richard Sharpe <richard.sharpe@primarydata.com>

Add support for returning all of the Windows attributes with a statx
ioctl.
Add support for setting all of the Windows attributes using an ioctl.

Signed-off-by: Richard Sharpe <richard.sharpe@primarydata.com>
Signed-off-by: Lance Shelton <lance.shelton@hammerspace.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
---
 fs/nfs/dir.c             |  24 +-
 fs/nfs/getroot.c         |   3 +-
 fs/nfs/inode.c           |  41 +++-
 fs/nfs/internal.h        |   8 +
 fs/nfs/nfs3proc.c        |   1 +
 fs/nfs/nfs4_fs.h         |  31 +++
 fs/nfs/nfs4file.c        | 511 +++++++++++++++++++++++++++++++++++++++
 fs/nfs/nfs4proc.c        | 124 ++++++++++
 fs/nfs/nfs4xdr.c         |  63 ++++-
 fs/nfs/nfstrace.c        |   5 +
 fs/nfs/nfstrace.h        |   5 +
 fs/nfs/proc.c            |   1 +
 include/linux/nfs_fs.h   |   1 +
 include/linux/nfs_xdr.h  |   3 +
 include/uapi/linux/nfs.h |  90 +++++++
 15 files changed, 887 insertions(+), 24 deletions(-)

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 9883f72fdb6f..10a6484c59d3 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -48,11 +48,6 @@
 
 /* #define NFS_DEBUG_VERBOSE 1 */
 
-static int nfs_opendir(struct inode *, struct file *);
-static int nfs_closedir(struct inode *, struct file *);
-static int nfs_readdir(struct file *, struct dir_context *);
-static int nfs_fsync_dir(struct file *, loff_t, loff_t, int);
-static loff_t nfs_llseek_dir(struct file *, loff_t, int);
 static void nfs_readdir_clear_array(struct page*);
 
 const struct file_operations nfs_dir_operations = {
@@ -63,6 +58,7 @@ const struct file_operations nfs_dir_operations = {
 	.release	= nfs_closedir,
 	.fsync		= nfs_fsync_dir,
 };
+EXPORT_SYMBOL_GPL(nfs_dir_operations);
 
 const struct address_space_operations nfs_dir_aops = {
 	.freepage = nfs_readdir_clear_array,
@@ -104,8 +100,7 @@ static void put_nfs_open_dir_context(struct inode *dir, struct nfs_open_dir_cont
 /*
  * Open file
  */
-static int
-nfs_opendir(struct inode *inode, struct file *filp)
+int nfs_opendir(struct inode *inode, struct file *filp)
 {
 	int res = 0;
 	struct nfs_open_dir_context *ctx;
@@ -123,13 +118,14 @@ nfs_opendir(struct inode *inode, struct file *filp)
 out:
 	return res;
 }
+EXPORT_SYMBOL_GPL(nfs_opendir);
 
-static int
-nfs_closedir(struct inode *inode, struct file *filp)
+int nfs_closedir(struct inode *inode, struct file *filp)
 {
 	put_nfs_open_dir_context(file_inode(filp), filp->private_data);
 	return 0;
 }
+EXPORT_SYMBOL_GPL(nfs_closedir);
 
 struct nfs_cache_array_entry {
 	u64 cookie;
@@ -1064,7 +1060,7 @@ static int uncached_readdir(struct nfs_readdir_descriptor *desc)
    last cookie cache takes care of the common case of reading the
    whole directory.
  */
-static int nfs_readdir(struct file *file, struct dir_context *ctx)
+int nfs_readdir(struct file *file, struct dir_context *ctx)
 {
 	struct dentry	*dentry = file_dentry(file);
 	struct inode	*inode = d_inode(dentry);
@@ -1157,8 +1153,9 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
 	dfprintk(FILE, "NFS: readdir(%pD2) returns %d\n", file, res);
 	return res;
 }
+EXPORT_SYMBOL_GPL(nfs_readdir);
 
-static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int whence)
+loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int whence)
 {
 	struct nfs_open_dir_context *dir_ctx = filp->private_data;
 
@@ -1196,19 +1193,20 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int whence)
 	spin_unlock(&filp->f_lock);
 	return offset;
 }
+EXPORT_SYMBOL_GPL(nfs_llseek_dir);
 
 /*
  * All directory operations under NFS are synchronous, so fsync()
  * is a dummy operation.
  */
-static int nfs_fsync_dir(struct file *filp, loff_t start, loff_t end,
-			 int datasync)
+int nfs_fsync_dir(struct file *filp, loff_t start, loff_t end, int datasync)
 {
 	dfprintk(FILE, "NFS: fsync dir(%pD2) datasync %d\n", filp, datasync);
 
 	nfs_inc_stats(file_inode(filp), NFSIOS_VFSFSYNC);
 	return 0;
 }
+EXPORT_SYMBOL_GPL(nfs_fsync_dir);
 
 /**
  * nfs_force_lookup_revalidate - Mark the directory as having changed
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 11ff2b2e060f..f872970d6240 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -127,7 +127,8 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
 	if (server->caps & NFS_CAP_SECURITY_LABEL)
 		kflags |= SECURITY_LSM_NATIVE_LABELS;
 	if (ctx->clone_data.sb) {
-		if (d_inode(fc->root)->i_fop != &nfs_dir_operations) {
+		if (d_inode(fc->root)->i_fop !=
+		    server->nfs_client->rpc_ops->dir_ops) {
 			error = -ESTALE;
 			goto error_splat_root;
 		}
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 33f4410190b6..8da662a4953d 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -108,6 +108,7 @@ u64 nfs_compat_user_ino64(u64 fileid)
 		ino ^= fileid >> (sizeof(fileid)-sizeof(ino)) * 8;
 	return ino;
 }
+EXPORT_SYMBOL_GPL(nfs_compat_user_ino64);
 
 int nfs_drop_inode(struct inode *inode)
 {
@@ -501,7 +502,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 			nfs_inode_init_regular(nfsi);
 		} else if (S_ISDIR(inode->i_mode)) {
 			inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops;
-			inode->i_fop = &nfs_dir_operations;
+			inode->i_fop = NFS_SB(sb)->nfs_client->rpc_ops->dir_ops;
 			inode->i_data.a_ops = &nfs_dir_aops;
 			nfs_inode_init_dir(nfsi);
 			/* Deal with crossing mountpoints */
@@ -867,6 +868,44 @@ static u32 nfs_get_valid_attrmask(struct inode *inode)
 	return reply_mask;
 }
 
+static int nfs_getattr_revalidate_force(struct dentry *dentry)
+{
+	struct inode *inode = d_inode(dentry);
+	struct nfs_server *server = NFS_SERVER(inode);
+
+	if (!(server->flags & NFS_MOUNT_NOAC))
+		nfs_readdirplus_parent_cache_miss(dentry);
+	else
+		nfs_readdirplus_parent_cache_hit(dentry);
+	return __nfs_revalidate_inode(server, inode);
+}
+
+static int nfs_getattr_revalidate_none(struct dentry *dentry)
+{
+	nfs_readdirplus_parent_cache_hit(dentry);
+	return NFS_STALE(d_inode(dentry)) ? -ESTALE : 0;
+}
+
+static int nfs_getattr_revalidate_maybe(struct dentry *dentry,
+					unsigned long flags)
+{
+	if (nfs_check_cache_invalid(d_inode(dentry), flags))
+		return nfs_getattr_revalidate_force(dentry);
+	return nfs_getattr_revalidate_none(dentry);
+}
+
+int nfs_getattr_revalidate(const struct path *path,
+			   unsigned long flags,
+			   unsigned int query_flags)
+{
+	if (query_flags & AT_STATX_FORCE_SYNC)
+		return nfs_getattr_revalidate_force(path->dentry);
+	if (!(query_flags & AT_STATX_DONT_SYNC))
+		return nfs_getattr_revalidate_maybe(path->dentry, flags);
+	return nfs_getattr_revalidate_none(path->dentry);
+}
+EXPORT_SYMBOL_GPL(nfs_getattr_revalidate);
+
 int nfs_getattr(struct user_namespace *mnt_userns, const struct path *path,
 		struct kstat *stat, u32 request_mask, unsigned int query_flags)
 {
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 12f6acb483bb..9602a886f0f0 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -366,6 +366,12 @@ extern struct nfs_client *nfs_init_client(struct nfs_client *clp,
 			   const struct nfs_client_initdata *);
 
 /* dir.c */
+int nfs_opendir(struct inode *, struct file *);
+int nfs_closedir(struct inode *, struct file *);
+int nfs_readdir(struct file *file, struct dir_context *ctx);
+int nfs_fsync_dir(struct file *, loff_t, loff_t, int);
+loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int whence);
+
 extern void nfs_advise_use_readdirplus(struct inode *dir);
 extern void nfs_force_use_readdirplus(struct inode *dir);
 extern unsigned long nfs_access_cache_count(struct shrinker *shrink,
@@ -411,6 +417,8 @@ extern void nfs_set_cache_invalid(struct inode *inode, unsigned long flags);
 extern bool nfs_check_cache_invalid(struct inode *, unsigned long);
 extern int nfs_wait_bit_killable(struct wait_bit_key *key, int mode);
 extern int nfs_wait_atomic_killable(atomic_t *p, unsigned int mode);
+extern int nfs_getattr_revalidate(const struct path *path, unsigned long flags,
+				  unsigned int query_flags);
 
 /* super.c */
 extern const struct super_operations nfs_sops;
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 1597eef40d54..ea3afdc8a58b 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -1019,6 +1019,7 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
 	.dir_inode_ops	= &nfs3_dir_inode_operations,
 	.file_inode_ops	= &nfs3_file_inode_operations,
 	.file_ops	= &nfs_file_operations,
+	.dir_ops	= &nfs_dir_operations,
 	.nlmclnt_ops	= &nlmclnt_fl_close_lock_ops,
 	.getroot	= nfs3_proc_get_root,
 	.submount	= nfs_submount,
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index ed5eaca6801e..9f21d8520e99 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -248,6 +248,34 @@ struct nfs4_opendata {
 	int rpc_status;
 };
 
+struct nfs4_statx {
+	int		real_fd;		/* real FD to use,
+						   -1 means use current file */
+	__u32		fa_options;		/* statx flags */
+	__u64		fa_request[2];		/* Attributes requested */
+	__u64		fa_valid[2];		/* Attributes set */
+
+	struct timespec64 fa_time_backup;	/* Backup time */
+	struct timespec64 fa_btime;		/* Birth time */
+	/* Flag attributes */
+	__u64 fa_flags;
+	struct timespec64 fa_atime;		/* Access time */
+	struct timespec64 fa_mtime;		/* Modify time */
+	struct timespec64 fa_ctime;		/* Change time */
+	kuid_t		fa_owner_uid;		/* Owner User ID */
+	kgid_t		fa_group_gid;		/* Primary Group ID */
+        /* Normal stat fields after this */
+	__u32	 	fa_mode;		/* Mode */
+	unsigned int 	fa_nlink;
+	__u32		fa_blksize;
+	__u32		fa_spare;		/* Alignment */
+	__u64		fa_ino;
+	dev_t		fa_dev;
+	dev_t		fa_rdev;
+	loff_t		fa_size;
+	__u64		fa_blocks;
+};
+
 struct nfs4_add_xprt_data {
 	struct nfs_client	*clp;
 	const struct cred	*cred;
@@ -315,6 +343,9 @@ extern int nfs4_set_rw_stateid(nfs4_stateid *stateid,
 		const struct nfs_open_context *ctx,
 		const struct nfs_lock_context *l_ctx,
 		fmode_t fmode);
+int nfs4_set_nfs4_statx(struct inode *inode,
+		struct nfs4_statx *statx,
+		struct nfs_fattr *fattr);
 extern int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
 			     struct nfs_fattr *fattr, struct inode *inode);
 extern int update_open_stateid(struct nfs4_state *state,
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index e79ae4cbc395..494ebc7cd1c0 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -9,6 +9,8 @@
 #include <linux/falloc.h>
 #include <linux/mount.h>
 #include <linux/nfs_fs.h>
+#include <linux/time32.h>
+#include <linux/compat.h>
 #include <linux/nfs_ssc.h>
 #include "delegation.h"
 #include "internal.h"
@@ -132,6 +134,503 @@ nfs4_file_flush(struct file *file, fl_owner_t id)
 	return filemap_check_wb_err(file->f_mapping, since);
 }
 
+static int nfs_get_timespec64(struct timespec64 *ts,
+			      const struct nfs_ioctl_timespec __user *uts)
+{
+	__s64 dummy;
+	if (unlikely(get_user(dummy, &uts->tv_sec) != 0))
+		return EFAULT;
+	ts->tv_sec = dummy;
+	if (unlikely(get_user(dummy, &uts->tv_nsec) != 0))
+		return EFAULT;
+	ts->tv_nsec = dummy;
+	return 0;
+}
+
+static int nfs_put_timespec64(const struct timespec64 *ts,
+			      struct nfs_ioctl_timespec __user *uts)
+{
+	__s64 dummy;
+
+	dummy = ts->tv_sec;
+	if (unlikely(put_user(dummy, &uts->tv_sec) != 0))
+		return EFAULT;
+	dummy = ts->tv_nsec;
+	if (unlikely(put_user(dummy, &uts->tv_nsec) != 0))
+		return EFAULT;
+	return 0;
+}
+
+static struct file *nfs4_get_real_file(struct file *src, unsigned int fd)
+{
+	struct file *filp = fget_raw(fd);
+	int ret = -EBADF;
+
+	if (!filp)
+		goto out;
+	/* Validate that the files share the same underlying filesystem */
+	ret = -EXDEV;
+	if (file_inode(filp)->i_sb != file_inode(src)->i_sb)
+		goto out_put;
+	return filp;
+out_put:
+	fput(filp);
+out:
+	return ERR_PTR(ret);
+}
+
+static unsigned long nfs4_statx_request_to_cache_validity(__u64 request,
+							  u64 fattr_supported)
+{
+	unsigned long ret = 0;
+
+	if (request & NFS_FA_VALID_ATIME)
+		ret |= NFS_INO_INVALID_ATIME;
+	if (request & NFS_FA_VALID_CTIME)
+		ret |= NFS_INO_INVALID_CTIME;
+	if (request & NFS_FA_VALID_MTIME)
+		ret |= NFS_INO_INVALID_MTIME;
+	if (request & NFS_FA_VALID_SIZE)
+		ret |= NFS_INO_INVALID_SIZE;
+
+	if (request & NFS_FA_VALID_MODE)
+		ret |= NFS_INO_INVALID_MODE;
+	if (request & (NFS_FA_VALID_OWNER | NFS_FA_VALID_OWNER_GROUP))
+		ret |= NFS_INO_INVALID_OTHER;
+
+	if (request & NFS_FA_VALID_NLINK)
+		ret |= NFS_INO_INVALID_NLINK;
+	if (request & NFS_FA_VALID_BLOCKS)
+		ret |= NFS_INO_INVALID_BLOCKS;
+
+	if (request & NFS_FA_VALID_TIME_CREATE)
+		ret |= NFS_INO_INVALID_BTIME;
+
+	if (request & NFS_FA_VALID_ARCHIVE) {
+		if (fattr_supported & NFS_ATTR_FATTR_ARCHIVE)
+			ret |= NFS_INO_INVALID_WINATTR;
+		else if (fattr_supported & NFS_ATTR_FATTR_TIME_BACKUP)
+			ret |= NFS_INO_INVALID_WINATTR | NFS_INO_INVALID_MTIME;
+	}
+	if (request & (NFS_FA_VALID_TIME_BACKUP | NFS_FA_VALID_HIDDEN |
+		       NFS_FA_VALID_SYSTEM | NFS_FA_VALID_OFFLINE))
+		ret |= NFS_INO_INVALID_WINATTR;
+
+	return ret ? (ret | NFS_INO_INVALID_CHANGE) : 0;
+}
+
+static long nfs4_ioctl_file_statx_get(struct file *dst_file,
+				      struct nfs_ioctl_nfs4_statx __user *uarg)
+{
+	struct nfs4_statx args = {
+		.real_fd = -1,
+		.fa_valid = { 0 },
+	};
+	struct inode *inode;
+	struct nfs_inode *nfsi;
+	struct nfs_server *server;
+	u64 fattr_supported;
+	unsigned long reval_attr;
+	unsigned int reval_flags;
+	__u32 tmp;
+	int ret;
+
+	/*
+	 * We get the first word from the uarg as it tells us whether
+	 * to use the passed in struct file or use that fd to find the
+	 * struct file.
+	 */
+	if (get_user(args.real_fd, &uarg->real_fd))
+		return -EFAULT;
+
+	if (get_user(args.fa_options, &uarg->fa_options))
+		return -EFAULT;
+
+	if (get_user(args.fa_request[0], &uarg->fa_request[0]))
+		return -EFAULT;
+
+	if (args.real_fd >= 0) {
+		dst_file = nfs4_get_real_file(dst_file, args.real_fd);
+		if (IS_ERR(dst_file))
+			return PTR_ERR(dst_file);
+	}
+
+	/*
+	 * Backward compatibility: we stole the top 32 bits of 'real_fd'
+	 * to create the fa_options field, so if its value is -1, then
+	 * assume it is the high word of (__s64)real_fd == -1, and just
+	 * set it to zero.
+	 */
+	if (args.fa_options == 0xFFFF)
+		args.fa_options = 0;
+
+	inode = file_inode(dst_file);
+	nfsi = NFS_I(inode);
+	server = NFS_SERVER(inode);
+	fattr_supported = server->fattr_valid;
+
+	trace_nfs_ioctl_file_statx_get_enter(inode);
+
+	if (args.fa_options & NFS_FA_OPTIONS_FORCE_SYNC)
+		reval_flags = AT_STATX_FORCE_SYNC;
+	else if (args.fa_options & NFS_FA_OPTIONS_DONT_SYNC)
+		reval_flags = AT_STATX_DONT_SYNC;
+	else
+		reval_flags = AT_STATX_SYNC_AS_STAT;
+
+	reval_attr = nfs4_statx_request_to_cache_validity(args.fa_request[0],
+							  fattr_supported);
+
+	if ((reval_attr & (NFS_INO_INVALID_CTIME | NFS_INO_INVALID_MTIME)) &&
+	    reval_flags != AT_STATX_DONT_SYNC && S_ISREG(inode->i_mode)) {
+		ret = filemap_write_and_wait(inode->i_mapping);
+		if (ret)
+			goto out;
+	}
+
+	if ((dst_file->f_path.mnt->mnt_flags & MNT_NOATIME) ||
+	    ((dst_file->f_path.mnt->mnt_flags & MNT_NODIRATIME) &&
+	     S_ISDIR(inode->i_mode)))
+		reval_attr &= ~NFS_INO_INVALID_ATIME;
+
+	ret = nfs_getattr_revalidate(&dst_file->f_path, reval_attr,
+				     reval_flags);
+	if (ret != 0)
+		goto out;
+
+	ret = -EFAULT;
+	if ((fattr_supported & NFS_ATTR_FATTR_OWNER) &&
+	    (args.fa_request[0] & NFS_FA_VALID_OWNER)) {
+		tmp = from_kuid_munged(current_user_ns(), inode->i_uid);
+		if (unlikely(put_user(tmp, &uarg->fa_owner_uid) != 0))
+			goto out;
+		args.fa_valid[0] |= NFS_FA_VALID_OWNER;
+	}
+
+	if ((fattr_supported & NFS_ATTR_FATTR_GROUP) &&
+	    (args.fa_request[0] & NFS_FA_VALID_OWNER_GROUP)) {
+		tmp = from_kgid_munged(current_user_ns(), inode->i_gid);
+		if (unlikely(put_user(tmp, &uarg->fa_group_gid) != 0))
+			goto out;
+		args.fa_valid[0] |= NFS_FA_VALID_OWNER_GROUP;
+	}
+
+	if ((fattr_supported & NFS_ATTR_FATTR_TIME_BACKUP) &&
+	    (args.fa_request[0] & NFS_FA_VALID_TIME_BACKUP)) {
+		if (nfs_put_timespec64(&nfsi->timebackup, &uarg->fa_time_backup))
+			goto out;
+		args.fa_valid[0] |= NFS_FA_VALID_TIME_BACKUP;
+	}
+
+	if ((fattr_supported & NFS_ATTR_FATTR_BTIME) &&
+	    (args.fa_request[0] & NFS_FA_VALID_TIME_CREATE)) {
+		if (nfs_put_timespec64(&nfsi->btime, &uarg->fa_btime))
+			goto out;
+		args.fa_valid[0] |= NFS_FA_VALID_TIME_CREATE;
+	}
+
+	/* atime, mtime, and ctime are all stored in the regular inode,
+	 * not the nfs inode.
+	 */
+	if ((fattr_supported & NFS_ATTR_FATTR_ATIME) &&
+	    (args.fa_request[0] & NFS_FA_VALID_ATIME)) {
+		if (nfs_put_timespec64(&inode->i_atime, &uarg->fa_atime))
+			goto out;
+		args.fa_valid[0] |= NFS_FA_VALID_ATIME;
+	}
+
+	if ((fattr_supported & NFS_ATTR_FATTR_MTIME) &&
+	    (args.fa_request[0] & NFS_FA_VALID_MTIME)) {
+		if (nfs_put_timespec64(&inode->i_mtime, &uarg->fa_mtime))
+                        goto out;
+		args.fa_valid[0] |= NFS_FA_VALID_MTIME;
+	}
+
+	if ((fattr_supported & NFS_ATTR_FATTR_CTIME) &&
+	    (args.fa_request[0] & NFS_FA_VALID_CTIME)) {
+		if (nfs_put_timespec64(&inode->i_ctime, &uarg->fa_ctime))
+			goto out;
+		args.fa_valid[0] |= NFS_FA_VALID_CTIME;
+	}
+
+        /*
+         * It looks like PDFS does not support or properly handle the
+         * archive bit.
+         */
+	if ((fattr_supported & NFS_ATTR_FATTR_ARCHIVE) &&
+	    (args.fa_request[0] & NFS_FA_VALID_ARCHIVE)) {
+		if (nfsi->archive)
+			args.fa_flags |= NFS_FA_FLAG_ARCHIVE;
+		args.fa_valid[0] |= NFS_FA_VALID_ARCHIVE;
+	}
+
+	if ((fattr_supported & NFS_ATTR_FATTR_TIME_BACKUP) &&
+	    (args.fa_request[0] & NFS_FA_VALID_ARCHIVE)) {
+		if (timespec64_compare(&inode->i_mtime, &nfsi->timebackup) > 0)
+			args.fa_flags |= NFS_FA_FLAG_ARCHIVE;
+		args.fa_valid[0] |= NFS_FA_VALID_ARCHIVE;
+	}
+
+	if ((fattr_supported & NFS_ATTR_FATTR_HIDDEN) &&
+	    (args.fa_request[0] & NFS_FA_VALID_HIDDEN)) {
+		if (nfsi->hidden)
+			args.fa_flags |= NFS_FA_FLAG_HIDDEN;
+		args.fa_valid[0] |= NFS_FA_VALID_HIDDEN;
+	}
+	if ((fattr_supported & NFS_ATTR_FATTR_SYSTEM) &&
+	    (args.fa_request[0] & NFS_FA_VALID_SYSTEM)) {
+		if (nfsi->system)
+			args.fa_flags |= NFS_FA_FLAG_SYSTEM;
+		args.fa_valid[0] |= NFS_FA_VALID_SYSTEM;
+	}
+
+	if ((fattr_supported & NFS_ATTR_FATTR_OFFLINE) &&
+	    (args.fa_request[0] & NFS_FA_VALID_OFFLINE)) {
+		if (nfsi->offline)
+			args.fa_flags |= NFS_FA_FLAG_OFFLINE;
+		args.fa_valid[0] |= NFS_FA_VALID_OFFLINE;
+	}
+
+	if ((args.fa_valid[0] & (NFS_FA_VALID_ARCHIVE |
+				NFS_FA_VALID_HIDDEN |
+				NFS_FA_VALID_SYSTEM |
+				NFS_FA_VALID_OFFLINE)) &&
+	    put_user(args.fa_flags, &uarg->fa_flags))
+		goto out;
+
+	if ((fattr_supported & NFS_ATTR_FATTR_MODE) &&
+	    (args.fa_request[0] & NFS_FA_VALID_MODE)) {
+		tmp = inode->i_mode;
+		/* This is an unsigned short we put into an __u32 */
+		if (unlikely(put_user(tmp, &uarg->fa_mode) != 0))
+			goto out;
+		args.fa_valid[0] |= NFS_FA_VALID_MODE;
+	}
+
+	if ((fattr_supported & NFS_ATTR_FATTR_NLINK) &&
+	    (args.fa_request[0] & NFS_FA_VALID_NLINK)) {
+		tmp = inode->i_nlink;
+		if (unlikely(put_user(tmp, &uarg->fa_nlink) != 0))
+			goto out;
+		args.fa_valid[0] |= NFS_FA_VALID_NLINK;
+	}
+
+	if (args.fa_request[0] & NFS_FA_VALID_BLKSIZE) {
+		tmp = i_blocksize(inode);
+		if (S_ISDIR(inode->i_mode))
+			tmp = NFS_SERVER(inode)->dtsize;
+		if (unlikely(put_user(tmp, &uarg->fa_blksize) != 0))
+			goto out;
+		args.fa_valid[0] |= NFS_FA_VALID_BLKSIZE;
+	}
+
+	if (args.fa_request[0] & NFS_FA_VALID_INO) {
+		__u64 ino = nfs_compat_user_ino64(NFS_FILEID(inode));
+		if (unlikely(put_user(ino, &uarg->fa_ino) != 0))
+			goto out;
+		args.fa_valid[0] |= NFS_FA_VALID_INO;
+	}
+
+	if (args.fa_request[0] & NFS_FA_VALID_DEV) {
+		tmp = inode->i_sb->s_dev;
+		if (unlikely(put_user(tmp, &uarg->fa_dev) != 0))
+			goto out;
+		args.fa_valid[0] |= NFS_FA_VALID_DEV;
+	}
+
+	if ((fattr_supported & NFS_ATTR_FATTR_RDEV) &&
+	    (args.fa_request[0] & NFS_FA_VALID_RDEV)) {
+		tmp = inode->i_rdev;
+		if (unlikely(put_user(tmp, &uarg->fa_rdev) != 0))
+			goto out;
+		args.fa_valid[0] |= NFS_FA_VALID_RDEV;
+	}
+
+	if ((fattr_supported & NFS_ATTR_FATTR_SIZE) &&
+	    (args.fa_request[0] & NFS_FA_VALID_SIZE)) {
+		__s64 size = i_size_read(inode);
+		if (unlikely(put_user(size, &uarg->fa_size) != 0))
+			goto out;
+		args.fa_valid[0] |= NFS_FA_VALID_SIZE;
+	}
+
+	if ((fattr_supported &
+	     (NFS_ATTR_FATTR_BLOCKS_USED | NFS_ATTR_FATTR_SPACE_USED)) &&
+	    (args.fa_request[0] & NFS_FA_VALID_BLOCKS)) {
+		__s64 blocks = inode->i_blocks;
+		if (unlikely(put_user(blocks, &uarg->fa_blocks) != 0))
+			goto out;
+		args.fa_valid[0] |= NFS_FA_VALID_BLOCKS;
+	}
+
+	if (unlikely(put_user(args.fa_valid[0], &uarg->fa_valid[0]) != 0))
+		goto out;
+	if (unlikely(put_user(args.fa_valid[1], &uarg->fa_valid[1]) != 0))
+		goto out;
+
+	ret = 0;
+out:
+	if (args.real_fd >= 0)
+		fput(dst_file);
+	trace_nfs_ioctl_file_statx_get_exit(inode, ret);
+	return ret;
+}
+
+static long nfs4_ioctl_file_statx_set(struct file *dst_file,
+				      struct nfs_ioctl_nfs4_statx __user *uarg)
+{
+	struct nfs4_statx args = {
+		.real_fd = -1,
+		.fa_valid = { 0 },
+	};
+	struct nfs_fattr *fattr = nfs_alloc_fattr();
+	struct inode *inode;
+	/*
+	 * If you need a different error code below, you need to set it
+	 */
+	int ret = -EFAULT;
+
+	if (fattr == NULL)
+		return -ENOMEM;
+
+	/*
+	 * We get the first u64 word from the uarg as it tells us whether
+	 * to use the passed in struct file or use that fd to find the
+	 * struct file.
+	 */
+	if (get_user(args.real_fd, &uarg->real_fd))
+		goto out_free;
+
+	if (args.real_fd >= 0) {
+		dst_file = nfs4_get_real_file(dst_file, args.real_fd);
+		if (IS_ERR(dst_file)) {
+			ret = PTR_ERR(dst_file);
+			goto out_free;
+		}
+	}
+	inode = file_inode(dst_file);
+	trace_nfs_ioctl_file_statx_set_enter(inode);
+
+	inode_lock(inode);
+
+	/* Write all dirty data */
+	if (S_ISREG(inode->i_mode)) {
+		ret = nfs_sync_inode(inode);
+		if (ret)
+			goto out;
+	}
+
+	ret = -EFAULT;
+	if (get_user(args.fa_valid[0], &uarg->fa_valid[0]))
+		goto out;
+	args.fa_valid[0] &= NFS_FA_VALID_ALL_ATTR_0;
+
+	if (args.fa_valid[0] & NFS_FA_VALID_OWNER) {
+		uid_t uid;
+
+		if (unlikely(get_user(uid, &uarg->fa_owner_uid) != 0))
+			goto out;
+		args.fa_owner_uid = make_kuid(current_user_ns(), uid);
+		if (!uid_valid(args.fa_owner_uid)) {
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
+	if (args.fa_valid[0] & NFS_FA_VALID_OWNER_GROUP) {
+		gid_t gid;
+
+		if (unlikely(get_user(gid, &uarg->fa_group_gid) != 0))
+			goto out;
+		args.fa_group_gid = make_kgid(current_user_ns(), gid);
+		if (!gid_valid(args.fa_group_gid)) {
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
+	if ((args.fa_valid[0] & (NFS_FA_VALID_ARCHIVE |
+					NFS_FA_VALID_HIDDEN |
+					NFS_FA_VALID_SYSTEM)) &&
+	    get_user(args.fa_flags, &uarg->fa_flags))
+		goto out;
+
+	if ((args.fa_valid[0] & NFS_FA_VALID_TIME_CREATE) &&
+	    nfs_get_timespec64(&args.fa_btime, &uarg->fa_btime))
+		goto out;
+
+	if ((args.fa_valid[0] & NFS_FA_VALID_ATIME) &&
+	    nfs_get_timespec64(&args.fa_atime, &uarg->fa_atime))
+		goto out;
+
+	if ((args.fa_valid[0] & NFS_FA_VALID_MTIME) &&
+	    nfs_get_timespec64(&args.fa_mtime, &uarg->fa_mtime))
+		goto out;
+
+	if (args.fa_valid[0] & NFS_FA_VALID_TIME_BACKUP) {
+		if (nfs_get_timespec64(&args.fa_time_backup, &uarg->fa_time_backup))
+			goto out;
+	} else if ((args.fa_valid[0] & NFS_FA_VALID_ARCHIVE) &&
+			!(NFS_SERVER(inode)->fattr_valid & NFS_ATTR_FATTR_ARCHIVE)) {
+		args.fa_valid[0] |= NFS_FA_VALID_TIME_BACKUP;
+		if (!(args.fa_flags & NFS_FA_FLAG_ARCHIVE)) {
+			nfs_revalidate_inode(inode, NFS_INO_INVALID_MTIME);
+			args.fa_time_backup.tv_sec = inode->i_mtime.tv_sec;
+			args.fa_time_backup.tv_nsec = inode->i_mtime.tv_nsec;
+		} else if (args.fa_valid[0] & NFS_FA_VALID_TIME_CREATE)
+			args.fa_time_backup = args.fa_btime;
+		else {
+			nfs_revalidate_inode(inode, NFS_INO_INVALID_BTIME);
+			args.fa_time_backup = NFS_I(inode)->btime;
+		}
+	}
+
+        if (args.fa_valid[0] & NFS_FA_VALID_SIZE) {
+		if (copy_from_user(&args.fa_size, &uarg->fa_size,
+					sizeof(args.fa_size)))
+			goto out;
+		ret = inode_newsize_ok(inode,args.fa_size);
+		if (ret)
+			goto out;
+		if (args.fa_size == i_size_read(inode))
+			args.fa_valid[0] &= ~NFS_FA_VALID_SIZE;
+	}
+
+	/*
+	 * No need to update the inode because that is done in nfs4_set_nfs4_statx
+	 */
+	ret = nfs4_set_nfs4_statx(inode, &args, fattr);
+
+out:
+	inode_unlock(inode);
+	if (args.real_fd >= 0)
+		fput(dst_file);
+	trace_nfs_ioctl_file_statx_set_exit(inode, ret);
+out_free:
+	nfs_free_fattr(fattr);
+	return ret;
+}
+
+static long nfs4_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	long ret;
+
+	switch (cmd) {
+	case NFS_IOC_FILE_STATX_GET:
+		ret = nfs4_ioctl_file_statx_get(file, argp);
+		break;
+	case NFS_IOC_FILE_STATX_SET:
+		ret = nfs4_ioctl_file_statx_set(file, argp);
+		break;
+	default:
+		ret = -ENOIOCTLCMD;
+	}
+
+	dprintk("%s: file=%pD2, cmd=%u, ret=%ld\n", __func__, file, cmd, ret);
+	return ret;
+}
+
 #ifdef CONFIG_NFS_V4_2
 static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
 				      struct file *file_out, loff_t pos_out,
@@ -187,6 +686,7 @@ static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
 	return ret;
 }
 
+
 static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
 				    struct file *file_out, loff_t pos_out,
 				    size_t count, unsigned int flags)
@@ -461,4 +961,15 @@ const struct file_operations nfs4_file_operations = {
 #else
 	.llseek		= nfs_file_llseek,
 #endif
+	.unlocked_ioctl	= nfs4_ioctl,
+};
+
+const struct file_operations nfs4_dir_operations = {
+	.llseek		= nfs_llseek_dir,
+	.read		= generic_read_dir,
+	.iterate_shared	= nfs_readdir,
+	.open		= nfs_opendir,
+	.release	= nfs_closedir,
+	.fsync		= nfs_fsync_dir,
+	.unlocked_ioctl	= nfs4_ioctl,
 };
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 713a71fb3020..db09371a4fda 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -7961,6 +7961,129 @@ static int _nfs41_proc_get_locations(struct inode *inode,
 
 #endif	/* CONFIG_NFS_V4_1 */
 
+static int _nfs4_set_nfs4_statx(struct inode *inode,
+		struct nfs4_statx *statx,
+		struct nfs_fattr *fattr)
+{
+	const __u64 statx_win = NFS_FA_VALID_TIME_CREATE |
+				NFS_FA_VALID_TIME_BACKUP |
+				NFS_FA_VALID_ARCHIVE | NFS_FA_VALID_HIDDEN |
+				NFS_FA_VALID_SYSTEM;
+	struct iattr sattr = {0};
+	struct nfs_server *server = NFS_SERVER(inode);
+	__u32 bitmask[3];
+	struct nfs_setattrargs arg = {
+		.fh             = NFS_FH(inode),
+		.iap            = &sattr,
+		.server		= server,
+		.bitmask	= bitmask,
+		.statx		= statx,
+	};
+	struct nfs_setattrres res = {
+		.fattr		= fattr,
+		.server		= server,
+	};
+	struct rpc_message msg = {
+		.rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
+		.rpc_argp       = &arg,
+		.rpc_resp       = &res,
+	};
+	int status;
+
+	nfs4_bitmap_copy_adjust(
+		bitmask, server->attr_bitmask, inode,
+		NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_CTIME |
+			NFS_INO_INVALID_SIZE | NFS_INO_INVALID_OTHER |
+			NFS_INO_INVALID_BTIME | NFS_INO_INVALID_WINATTR);
+	/* Use the iattr structure to set atime and mtime since handling already
+	 * exists for them using the iattr struct in the encode_attrs()
+	 * (xdr encoding) routine.
+	 */
+	if (statx && (statx->fa_valid[0] & NFS_FA_VALID_MTIME)) {
+		sattr.ia_valid |= ATTR_MTIME_SET;
+		sattr.ia_mtime.tv_sec = statx->fa_mtime.tv_sec;
+		sattr.ia_mtime.tv_nsec = statx->fa_mtime.tv_nsec;
+	}
+
+	if (statx && (statx->fa_valid[0] & NFS_FA_VALID_ATIME)) {
+		sattr.ia_valid |= ATTR_ATIME_SET;
+		sattr.ia_atime.tv_sec = statx->fa_atime.tv_sec;
+		sattr.ia_atime.tv_nsec = statx->fa_atime.tv_nsec;
+	}
+
+	if (statx && (statx->fa_valid[0] & NFS_FA_VALID_OWNER)) {
+		sattr.ia_valid |= ATTR_UID;
+		sattr.ia_uid = statx->fa_owner_uid;
+	}
+
+	if (statx && (statx->fa_valid[0] & NFS_FA_VALID_OWNER_GROUP)) {
+		sattr.ia_valid |= ATTR_GID;
+		sattr.ia_gid = statx->fa_group_gid;
+	}
+
+	if (statx && (statx->fa_valid[0] & NFS_FA_VALID_SIZE)) {
+		sattr.ia_valid |= ATTR_SIZE;
+		sattr.ia_size = statx->fa_size;
+	}
+
+	nfs4_stateid_copy(&arg.stateid, &zero_stateid);
+
+	status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
+	if (!status) {
+		if (statx->fa_valid[0] & statx_win) {
+			struct nfs_inode *nfsi = NFS_I(inode);
+
+			spin_lock(&inode->i_lock);
+			if (statx->fa_valid[0] & NFS_FA_VALID_TIME_CREATE)
+				nfsi->btime = statx->fa_btime;
+			if (statx->fa_valid[0] & NFS_FA_VALID_TIME_BACKUP)
+				nfsi->timebackup = statx->fa_time_backup;
+			if (statx->fa_valid[0] & NFS_FA_VALID_ARCHIVE)
+				nfsi->archive = (statx->fa_flags &
+						 NFS_FA_FLAG_ARCHIVE) != 0;
+			if (statx->fa_valid[0] & NFS_FA_VALID_SYSTEM)
+				nfsi->system = (statx->fa_flags &
+						NFS_FA_FLAG_SYSTEM) != 0;
+			if (statx->fa_valid[0] & NFS_FA_VALID_HIDDEN)
+				nfsi->hidden = (statx->fa_flags &
+						NFS_FA_FLAG_HIDDEN) != 0;
+			if (statx->fa_valid[0] & NFS_FA_VALID_OFFLINE)
+				nfsi->offline = (statx->fa_flags &
+						 NFS_FA_FLAG_OFFLINE) != 0;
+
+			nfsi->cache_validity &= ~NFS_INO_INVALID_CTIME;
+			if (fattr->valid & NFS_ATTR_FATTR_CTIME)
+				inode->i_ctime = fattr->ctime;
+			else
+				nfs_set_cache_invalid(
+					inode, NFS_INO_INVALID_CHANGE |
+						   NFS_INO_INVALID_CTIME);
+			spin_unlock(&inode->i_lock);
+		}
+
+		nfs_setattr_update_inode(inode, &sattr, fattr);
+	} else
+		dprintk("%s failed: %d\n", __func__, status);
+
+	return status;
+}
+
+int nfs4_set_nfs4_statx(struct inode *inode,
+		struct nfs4_statx *statx,
+		struct nfs_fattr *fattr)
+{
+	struct nfs4_exception exception = { };
+	struct nfs_server *server = NFS_SERVER(inode);
+	int err;
+
+	do {
+		err = nfs4_handle_exception(server,
+				_nfs4_set_nfs4_statx(inode, statx, fattr),
+				&exception);
+	} while (exception.retry);
+	return err;
+}
+
 /**
  * nfs4_proc_get_locations - discover locations for a migrated FSID
  * @inode: inode on FSID that is migrating
@@ -10421,6 +10544,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
 	.dir_inode_ops	= &nfs4_dir_inode_operations,
 	.file_inode_ops	= &nfs4_file_inode_operations,
 	.file_ops	= &nfs4_file_operations,
+	.dir_ops	= &nfs4_dir_operations,
 	.getroot	= nfs4_proc_get_root,
 	.submount	= nfs4_submount,
 	.try_get_tree	= nfs4_try_get_tree,
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index a45872f860ec..05a1f9fdf65d 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -129,12 +129,15 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
 				nfs4_fattr_value_maxsz)
 #define decode_getattr_maxsz    (op_decode_hdr_maxsz + nfs4_fattr_maxsz)
 #define encode_attrs_maxsz	(nfs4_fattr_bitmap_maxsz + \
-				 1 + 2 + 1 + \
+				 1 + 2 + 1 + 1 + 1 + \
 				nfs4_owner_maxsz + \
 				nfs4_group_maxsz + \
-				nfs4_label_maxsz + \
+				1 + \
+				1 + nfstime4_maxsz + \
+				nfstime4_maxsz + nfstime4_maxsz + \
 				1 + nfstime4_maxsz + \
-				1 + nfstime4_maxsz)
+				nfs4_label_maxsz + \
+				2)
 #define encode_savefh_maxsz     (op_encode_hdr_maxsz)
 #define decode_savefh_maxsz     (op_decode_hdr_maxsz)
 #define encode_restorefh_maxsz  (op_encode_hdr_maxsz)
@@ -1081,6 +1084,7 @@ xdr_encode_nfstime4(__be32 *p, const struct timespec64 *t)
 static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
 				const struct nfs4_label *label,
 				const umode_t *umask,
+				const struct nfs4_statx *statx,
 				const struct nfs_server *server,
 				const uint32_t attrmask[])
 {
@@ -1153,6 +1157,34 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
 		}
 	}
 
+	if (statx && (statx->fa_valid[0] & NFS_FA_VALID_TIME_BACKUP) &&
+	    (attrmask[1] & FATTR4_WORD1_TIME_BACKUP)) {
+		bmval[1] |= FATTR4_WORD1_TIME_BACKUP;
+		len += (nfstime4_maxsz << 2);
+	}
+	if (statx && (statx->fa_valid[0] & NFS_FA_VALID_TIME_CREATE) &&
+	    (attrmask[1] & FATTR4_WORD1_TIME_CREATE)) {
+		bmval[1] |= FATTR4_WORD1_TIME_CREATE;
+		len += (nfstime4_maxsz << 2);
+	}
+
+	if (statx && (statx->fa_valid[0] & NFS_FA_VALID_ARCHIVE) &&
+	   (attrmask[0] & FATTR4_WORD0_ARCHIVE)) {
+		bmval[0] |= FATTR4_WORD0_ARCHIVE;
+		len += 4;
+	}
+	if (statx && (statx->fa_valid[0] & NFS_FA_VALID_HIDDEN) &&
+	   (attrmask[0] & FATTR4_WORD0_HIDDEN)) {
+		bmval[0] |= FATTR4_WORD0_HIDDEN;
+		len += 4;
+	}
+
+	if (statx && (statx->fa_valid[0] & NFS_FA_VALID_SYSTEM) &&
+	   (attrmask[1] & FATTR4_WORD1_SYSTEM)) {
+		bmval[1] |= FATTR4_WORD1_SYSTEM;
+		len += 4;
+	}
+
 	if (label && (attrmask[2] & FATTR4_WORD2_SECURITY_LABEL)) {
 		len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2);
 		bmval[2] |= FATTR4_WORD2_SECURITY_LABEL;
@@ -1163,12 +1195,21 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
 
 	if (bmval[0] & FATTR4_WORD0_SIZE)
 		p = xdr_encode_hyper(p, iap->ia_size);
+	if (bmval[0] & FATTR4_WORD0_ARCHIVE)
+		*p++ = (statx->fa_flags & NFS_FA_FLAG_ARCHIVE) ?
+			cpu_to_be32(1) : cpu_to_be32(0);
+	if (bmval[0] & FATTR4_WORD0_HIDDEN)
+		*p++ = (statx->fa_flags & NFS_FA_FLAG_HIDDEN) ?
+			cpu_to_be32(1) : cpu_to_be32(0);
 	if (bmval[1] & FATTR4_WORD1_MODE)
 		*p++ = cpu_to_be32(iap->ia_mode & S_IALLUGO);
 	if (bmval[1] & FATTR4_WORD1_OWNER)
 		p = xdr_encode_opaque(p, owner_name, owner_namelen);
 	if (bmval[1] & FATTR4_WORD1_OWNER_GROUP)
 		p = xdr_encode_opaque(p, owner_group, owner_grouplen);
+	if (bmval[1] & FATTR4_WORD1_SYSTEM)
+		*p++ = (statx->fa_flags & NFS_FA_FLAG_SYSTEM) ?
+			cpu_to_be32(1) : cpu_to_be32(0);
 	if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) {
 		if (iap->ia_valid & ATTR_ATIME_SET) {
 			*p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
@@ -1176,6 +1217,10 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
 		} else
 			*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
 	}
+	if (bmval[1] & FATTR4_WORD1_TIME_BACKUP)
+		p = xdr_encode_nfstime4(p, &statx->fa_time_backup);
+	if (bmval[1] & FATTR4_WORD1_TIME_CREATE)
+		p = xdr_encode_nfstime4(p, &statx->fa_btime);
 	if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
 		if (iap->ia_valid & ATTR_MTIME_SET) {
 			*p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
@@ -1248,7 +1293,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *
 
 	encode_string(xdr, create->name->len, create->name->name);
 	encode_attrs(xdr, create->attrs, create->label, &create->umask,
-			create->server, create->server->attr_bitmask);
+		     NULL, create->server, create->server->attr_bitmask);
 }
 
 static void encode_getattr(struct xdr_stream *xdr,
@@ -1434,12 +1479,12 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
 	case NFS4_CREATE_UNCHECKED:
 		*p = cpu_to_be32(NFS4_CREATE_UNCHECKED);
 		encode_attrs(xdr, arg->u.attrs, arg->label, &arg->umask,
-				arg->server, arg->server->attr_bitmask);
+			     NULL, arg->server, arg->server->attr_bitmask);
 		break;
 	case NFS4_CREATE_GUARDED:
 		*p = cpu_to_be32(NFS4_CREATE_GUARDED);
 		encode_attrs(xdr, arg->u.attrs, arg->label, &arg->umask,
-				arg->server, arg->server->attr_bitmask);
+			     NULL, arg->server, arg->server->attr_bitmask);
 		break;
 	case NFS4_CREATE_EXCLUSIVE:
 		*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE);
@@ -1449,7 +1494,7 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
 		*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1);
 		encode_nfs4_verifier(xdr, &arg->u.verifier);
 		encode_attrs(xdr, arg->u.attrs, arg->label, &arg->umask,
-				arg->server, arg->server->exclcreat_bitmask);
+			     NULL, arg->server, arg->server->exclcreat_bitmask);
 	}
 }
 
@@ -1712,8 +1757,8 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs
 {
 	encode_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr);
 	encode_nfs4_stateid(xdr, &arg->stateid);
-	encode_attrs(xdr, arg->iap, arg->label, NULL, server,
-			server->attr_bitmask);
+	encode_attrs(xdr, arg->iap, arg->label, NULL, arg->statx, server,
+		     server->attr_bitmask);
 }
 
 static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr)
diff --git a/fs/nfs/nfstrace.c b/fs/nfs/nfstrace.c
index 5d1bfccbb4da..0b88deb0216e 100644
--- a/fs/nfs/nfstrace.c
+++ b/fs/nfs/nfstrace.c
@@ -9,6 +9,11 @@
 #define CREATE_TRACE_POINTS
 #include "nfstrace.h"
 
+EXPORT_TRACEPOINT_SYMBOL_GPL(nfs_ioctl_file_statx_get_enter);
+EXPORT_TRACEPOINT_SYMBOL_GPL(nfs_ioctl_file_statx_get_exit);
+EXPORT_TRACEPOINT_SYMBOL_GPL(nfs_ioctl_file_statx_set_enter);
+EXPORT_TRACEPOINT_SYMBOL_GPL(nfs_ioctl_file_statx_set_exit);
+
 EXPORT_TRACEPOINT_SYMBOL_GPL(nfs_fsync_enter);
 EXPORT_TRACEPOINT_SYMBOL_GPL(nfs_fsync_exit);
 EXPORT_TRACEPOINT_SYMBOL_GPL(nfs_xdr_status);
diff --git a/fs/nfs/nfstrace.h b/fs/nfs/nfstrace.h
index 2ef7cff8a4ba..b67dd087fb47 100644
--- a/fs/nfs/nfstrace.h
+++ b/fs/nfs/nfstrace.h
@@ -166,6 +166,11 @@ DEFINE_NFS_INODE_EVENT_DONE(nfs_fsync_exit);
 DEFINE_NFS_INODE_EVENT(nfs_access_enter);
 DEFINE_NFS_INODE_EVENT_DONE(nfs_set_cache_invalid);
 
+DEFINE_NFS_INODE_EVENT(nfs_ioctl_file_statx_get_enter);
+DEFINE_NFS_INODE_EVENT_DONE(nfs_ioctl_file_statx_get_exit);
+DEFINE_NFS_INODE_EVENT(nfs_ioctl_file_statx_set_enter);
+DEFINE_NFS_INODE_EVENT_DONE(nfs_ioctl_file_statx_set_exit);
+
 TRACE_EVENT(nfs_access_exit,
 		TP_PROTO(
 			const struct inode *inode,
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 73dcaa99fa9b..8fd96d93630a 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -717,6 +717,7 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
 	.dir_inode_ops	= &nfs_dir_inode_operations,
 	.file_inode_ops	= &nfs_file_inode_operations,
 	.file_ops	= &nfs_file_operations,
+	.dir_ops	= &nfs_dir_operations,
 	.getroot	= nfs_proc_get_root,
 	.submount	= nfs_submount,
 	.try_get_tree	= nfs_try_get_tree,
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 61f852ebb0a4..7a134e4c03e8 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -503,6 +503,7 @@ extern __be32 root_nfs_parse_addr(char *name); /*__init*/
 extern const struct file_operations nfs_file_operations;
 #if IS_ENABLED(CONFIG_NFS_V4)
 extern const struct file_operations nfs4_file_operations;
+extern const struct file_operations nfs4_dir_operations;
 #endif /* CONFIG_NFS_V4 */
 extern const struct address_space_operations nfs_file_aops;
 extern const struct address_space_operations nfs_dir_aops;
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index f5588bc22cb1..9b0a56c11ca9 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -812,6 +812,7 @@ struct nfs_createargs {
 	struct iattr *		sattr;
 };
 
+struct nfs4_statx;
 struct nfs_setattrargs {
 	struct nfs4_sequence_args 	seq_args;
 	struct nfs_fh *                 fh;
@@ -820,6 +821,7 @@ struct nfs_setattrargs {
 	const struct nfs_server *	server; /* Needed for name mapping */
 	const u32 *			bitmask;
 	const struct nfs4_label		*label;
+	const struct nfs4_statx		*statx;
 };
 
 struct nfs_setaclargs {
@@ -1744,6 +1746,7 @@ struct nfs_rpc_ops {
 	const struct inode_operations *dir_inode_ops;
 	const struct inode_operations *file_inode_ops;
 	const struct file_operations *file_ops;
+	const struct file_operations *dir_ops;
 	const struct nlmclnt_operations *nlmclnt_ops;
 
 	int	(*getroot) (struct nfs_server *, struct nfs_fh *,
diff --git a/include/uapi/linux/nfs.h b/include/uapi/linux/nfs.h
index 946cb62d64b0..df87da39bc43 100644
--- a/include/uapi/linux/nfs.h
+++ b/include/uapi/linux/nfs.h
@@ -9,6 +9,8 @@
 #define _UAPI_LINUX_NFS_H
 
 #include <linux/types.h>
+#include <asm/byteorder.h>
+#include <linux/time.h>
 
 #define NFS_PROGRAM	100003
 #define NFS_PORT	2049
@@ -35,6 +37,94 @@
 
 #define NFS_PIPE_DIRNAME "nfs"
 
+/* NFS ioctls */
+#define NFS_IOC_FILE_STATX_GET	_IOR('N', 2, struct nfs_ioctl_nfs4_statx)
+#define NFS_IOC_FILE_STATX_SET	_IOW('N', 3, struct nfs_ioctl_nfs4_statx)
+
+/* Options for struct nfs_ioctl_nfs4_statx */
+#define NFS_FA_OPTIONS_SYNC_AS_STAT			0x0000
+#define NFS_FA_OPTIONS_FORCE_SYNC			0x2000 /* See statx */
+#define NFS_FA_OPTIONS_DONT_SYNC			0x4000 /* See statx */
+
+#define NFS_FA_VALID_TIME_CREATE			0x00001UL
+#define NFS_FA_VALID_TIME_BACKUP			0x00002UL
+#define NFS_FA_VALID_ARCHIVE				0x00004UL
+#define NFS_FA_VALID_HIDDEN				0x00008UL
+#define NFS_FA_VALID_SYSTEM				0x00010UL
+#define NFS_FA_VALID_OWNER				0x00020UL
+#define NFS_FA_VALID_OWNER_GROUP			0x00040UL
+#define NFS_FA_VALID_ATIME				0x00080UL
+#define NFS_FA_VALID_MTIME				0x00100UL
+#define NFS_FA_VALID_CTIME				0x00200UL
+#define NFS_FA_VALID_OFFLINE				0x00400UL
+#define NFS_FA_VALID_MODE				0x00800UL
+#define NFS_FA_VALID_NLINK				0x01000UL
+#define NFS_FA_VALID_BLKSIZE				0x02000UL
+#define NFS_FA_VALID_INO				0x04000UL
+#define NFS_FA_VALID_DEV				0x08000UL
+#define NFS_FA_VALID_RDEV				0x10000UL
+#define NFS_FA_VALID_SIZE				0x20000UL
+#define NFS_FA_VALID_BLOCKS				0x40000UL
+
+#define NFS_FA_VALID_ALL_ATTR_0 ( NFS_FA_VALID_TIME_CREATE | \
+		NFS_FA_VALID_TIME_BACKUP | \
+		NFS_FA_VALID_ARCHIVE | \
+		NFS_FA_VALID_HIDDEN | \
+		NFS_FA_VALID_SYSTEM | \
+		NFS_FA_VALID_OWNER | \
+		NFS_FA_VALID_OWNER_GROUP | \
+		NFS_FA_VALID_ATIME | \
+		NFS_FA_VALID_MTIME | \
+		NFS_FA_VALID_CTIME | \
+		NFS_FA_VALID_OFFLINE | \
+		NFS_FA_VALID_MODE | \
+		NFS_FA_VALID_NLINK | \
+		NFS_FA_VALID_BLKSIZE | \
+		NFS_FA_VALID_INO | \
+		NFS_FA_VALID_DEV | \
+		NFS_FA_VALID_RDEV | \
+		NFS_FA_VALID_SIZE | \
+		NFS_FA_VALID_BLOCKS)
+
+#define NFS_FA_FLAG_ARCHIVE				(1UL << 0)
+#define NFS_FA_FLAG_HIDDEN				(1UL << 1)
+#define NFS_FA_FLAG_SYSTEM				(1UL << 2)
+#define NFS_FA_FLAG_OFFLINE				(1UL << 3)
+
+struct nfs_ioctl_timespec {
+	__s64		tv_sec;
+	__s64		tv_nsec;
+};
+
+struct nfs_ioctl_nfs4_statx {
+	__s32		real_fd;		/* real FD to use,
+						   -1 means use current file */
+	__u32		fa_options;
+
+	__u64		fa_request[2];		/* Attributes to retrieve */
+	__u64		fa_valid[2];		/* Attributes set */
+
+	struct nfs_ioctl_timespec fa_time_backup;/* Backup time */
+	struct nfs_ioctl_timespec fa_btime;     /* Birth time */
+	__u64		fa_flags;		/* Flag attributes */
+	/* Ordinary attributes follow */
+	struct nfs_ioctl_timespec fa_atime;	/* Access time */
+	struct nfs_ioctl_timespec fa_mtime;	/* Modify time */
+	struct nfs_ioctl_timespec fa_ctime;	/* Change time */
+	__u32		fa_owner_uid;		/* Owner User ID */
+	__u32		fa_group_gid;		/* Primary Group ID */
+	__u32		fa_mode;		/* Mode */
+	__u32	 	fa_nlink;
+	__u32		fa_blksize;
+	__u32		fa_spare;		/* Alignment */
+	__u64		fa_ino;
+	__u32		fa_dev;
+	__u32		fa_rdev;
+	__s64		fa_size;
+	__s64		fa_blocks;
+	__u64 		fa_padding[4];
+};
+
 /*
  * NFS stats. The good thing with these values is that NFSv3 errors are
  * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 8/8] NFSv4: Add an ioctl to allow retrieval of the NFS raw ACCESS mask
  2021-12-27 19:05             ` [PATCH v2 7/8] NFS: Support statx_get and statx_set ioctls trondmy
@ 2021-12-27 19:05               ` trondmy
  0 siblings, 0 replies; 14+ messages in thread
From: trondmy @ 2021-12-27 19:05 UTC (permalink / raw)
  To: Anna Schumaker; +Cc: linux-nfs

From: Trond Myklebust <trond.myklebust@hammerspace.com>

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
---
 fs/nfs/dir.c             | 47 ++++++++++++++++++++++++----------------
 fs/nfs/internal.h        |  2 ++
 fs/nfs/nfs4file.c        | 39 +++++++++++++++++++++++++++++++++
 include/uapi/linux/nfs.h | 11 ++++++++++
 4 files changed, 80 insertions(+), 19 deletions(-)

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 10a6484c59d3..e8e6a2f7de1f 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -2907,36 +2907,30 @@ void nfs_access_set_mask(struct nfs_access_entry *entry, u32 access_result)
 }
 EXPORT_SYMBOL_GPL(nfs_access_set_mask);
 
-static int nfs_do_access(struct inode *inode, const struct cred *cred, int mask)
+int nfs_get_access(struct inode *inode, const struct cred *cred,
+		   struct nfs_access_entry *cache, bool may_block)
 {
-	struct nfs_access_entry cache;
-	bool may_block = (mask & MAY_NOT_BLOCK) == 0;
-	int cache_mask = -1;
 	int status;
 
-	trace_nfs_access_enter(inode);
-
-	status = nfs_access_get_cached(inode, cred, &cache.mask, may_block);
+	status = nfs_access_get_cached(inode, cred, &cache->mask, may_block);
 	if (status == 0)
-		goto out_cached;
+		return 0;
 
-	status = -ECHILD;
 	if (!may_block)
-		goto out;
-
+		return -ECHILD;
 	/*
 	 * Determine which access bits we want to ask for...
 	 */
-	cache.mask = NFS_ACCESS_READ | NFS_ACCESS_MODIFY | NFS_ACCESS_EXTEND;
+	cache->mask = NFS_ACCESS_READ | NFS_ACCESS_MODIFY | NFS_ACCESS_EXTEND;
 	if (nfs_server_capable(inode, NFS_CAP_XATTR)) {
-		cache.mask |= NFS_ACCESS_XAREAD | NFS_ACCESS_XAWRITE |
+		cache->mask |= NFS_ACCESS_XAREAD | NFS_ACCESS_XAWRITE |
 		    NFS_ACCESS_XALIST;
 	}
 	if (S_ISDIR(inode->i_mode))
-		cache.mask |= NFS_ACCESS_DELETE | NFS_ACCESS_LOOKUP;
+		cache->mask |= NFS_ACCESS_DELETE | NFS_ACCESS_LOOKUP;
 	else
-		cache.mask |= NFS_ACCESS_EXECUTE;
-	status = NFS_PROTO(inode)->access(inode, &cache, cred);
+		cache->mask |= NFS_ACCESS_EXECUTE;
+	status = NFS_PROTO(inode)->access(inode, cache, cred);
 	if (status != 0) {
 		if (status == -ESTALE) {
 			if (!S_ISDIR(inode->i_mode))
@@ -2944,10 +2938,25 @@ static int nfs_do_access(struct inode *inode, const struct cred *cred, int mask)
 			else
 				nfs_zap_caches(inode);
 		}
-		goto out;
+		return status;
 	}
-	nfs_access_add_cache(inode, &cache, cred);
-out_cached:
+	nfs_access_add_cache(inode, cache, cred);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nfs_get_access);
+
+static int nfs_do_access(struct inode *inode, const struct cred *cred, int mask)
+{
+	struct nfs_access_entry cache;
+	bool may_block = (mask & MAY_NOT_BLOCK) == 0;
+	int cache_mask = -1;
+	int status;
+
+	trace_nfs_access_enter(inode);
+
+	status = nfs_get_access(inode, cred, &cache, may_block);
+	if (status < 0)
+		goto out;
 	cache_mask = nfs_access_calc_mask(cache.mask, inode->i_mode);
 	if ((mask & ~cache_mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) != 0)
 		status = -EACCES;
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 9602a886f0f0..9b8fd2247533 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -392,6 +392,8 @@ int nfs_mknod(struct user_namespace *, struct inode *, struct dentry *, umode_t,
 	      dev_t);
 int nfs_rename(struct user_namespace *, struct inode *, struct dentry *,
 	       struct inode *, struct dentry *, unsigned int);
+int nfs_get_access(struct inode *inode, const struct cred *cred,
+		   struct nfs_access_entry *cache, bool may_block);
 
 /* file.c */
 int nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync);
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index 494ebc7cd1c0..ccf70d26c5c4 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -611,6 +611,42 @@ static long nfs4_ioctl_file_statx_set(struct file *dst_file,
 	return ret;
 }
 
+static long
+nfs4_ioctl_file_access_get(struct file *file,
+			   struct nfs_ioctl_nfs4_access __user *uarg)
+{
+	struct inode *inode = file_inode(file);
+	struct nfs_access_entry cache;
+	__u64 ac_flags;
+	const struct cred *old_cred;
+	struct cred *override_cred;
+	long ret;
+
+	if (!NFS_PROTO(inode)->access)
+		return -ENOTSUPP;
+
+	if (get_user(ac_flags, &uarg->ac_flags))
+		return -EFAULT;
+
+	override_cred = prepare_creds();
+	if (!override_cred)
+		return -ENOMEM;
+
+	if (!(ac_flags & NFS_AC_FLAG_EACCESS)) {
+		override_cred->fsuid = override_cred->uid;
+		override_cred->fsgid = override_cred->gid;
+	}
+	old_cred = override_creds(override_cred);
+
+	ret = nfs_get_access(inode, override_cred, &cache, true);
+	if (!ret && unlikely(put_user(cache.mask, &uarg->ac_mask) != 0))
+		ret = -EFAULT;
+
+	revert_creds(old_cred);
+	put_cred(override_cred);
+	return ret;
+}
+
 static long nfs4_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	void __user *argp = (void __user *)arg;
@@ -623,6 +659,9 @@ static long nfs4_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	case NFS_IOC_FILE_STATX_SET:
 		ret = nfs4_ioctl_file_statx_set(file, argp);
 		break;
+	case NFS_IOC_FILE_ACCESS_GET:
+		ret = nfs4_ioctl_file_access_get(file, argp);
+		break;
 	default:
 		ret = -ENOIOCTLCMD;
 	}
diff --git a/include/uapi/linux/nfs.h b/include/uapi/linux/nfs.h
index df87da39bc43..b1e50f14db18 100644
--- a/include/uapi/linux/nfs.h
+++ b/include/uapi/linux/nfs.h
@@ -41,6 +41,8 @@
 #define NFS_IOC_FILE_STATX_GET	_IOR('N', 2, struct nfs_ioctl_nfs4_statx)
 #define NFS_IOC_FILE_STATX_SET	_IOW('N', 3, struct nfs_ioctl_nfs4_statx)
 
+#define NFS_IOC_FILE_ACCESS_GET	_IOR('N', 4, struct nfs_ioctl_nfs4_access)
+
 /* Options for struct nfs_ioctl_nfs4_statx */
 #define NFS_FA_OPTIONS_SYNC_AS_STAT			0x0000
 #define NFS_FA_OPTIONS_FORCE_SYNC			0x2000 /* See statx */
@@ -125,6 +127,15 @@ struct nfs_ioctl_nfs4_statx {
 	__u64 		fa_padding[4];
 };
 
+struct nfs_ioctl_nfs4_access {
+	/* input */
+	__u64		ac_flags;		/* operation flags */
+	/* output */
+	__u64		ac_mask;		/* NFS raw ACCESS reply mask */
+};
+
+#define NFS_AC_FLAG_EACCESS (1UL << 0)
+
 /*
  * NFS stats. The good thing with these values is that NFSv3 errors are
  * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 6/8] NFSv4: Support the offline bit
  2021-12-27 19:05           ` [PATCH v2 6/8] NFSv4: Support the offline bit trondmy
  2021-12-27 19:05             ` [PATCH v2 7/8] NFS: Support statx_get and statx_set ioctls trondmy
@ 2022-01-07 14:23             ` Anna Schumaker
  2022-01-07 14:26               ` Trond Myklebust
  2022-01-07 14:31               ` Anna Schumaker
  1 sibling, 2 replies; 14+ messages in thread
From: Anna Schumaker @ 2022-01-07 14:23 UTC (permalink / raw)
  To: trondmy; +Cc: Linux NFS Mailing List

Hi Trond,

On Tue, Dec 28, 2021 at 3:03 AM <trondmy@kernel.org> wrote:
>
> From: Trond Myklebust <trond.myklebust@primarydata.com>
>
> Add tracking of the NFSv4 'offline' attribute.
>
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> Signed-off-by: Lance Shelton <lance.shelton@hammerspace.com>
> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
> ---
>  fs/nfs/inode.c          | 11 +++++++++++
>  fs/nfs/nfs4proc.c       |  6 ++++++
>  fs/nfs/nfs4trace.h      |  3 ++-
>  fs/nfs/nfs4xdr.c        | 31 ++++++++++++++++++++++++++++++-
>  include/linux/nfs4.h    |  1 +
>  include/linux/nfs_fs.h  |  1 +
>  include/linux/nfs_xdr.h |  5 ++++-
>  7 files changed, 55 insertions(+), 3 deletions(-)
>
> diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> index 4673b091ea31..33f4410190b6 100644
> --- a/fs/nfs/inode.c
> +++ b/fs/nfs/inode.c
> @@ -528,6 +528,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
>                 nfsi->archive = 0;
>                 nfsi->hidden = 0;
>                 nfsi->system = 0;
> +               nfsi->offline = 0;
>                 inode_set_iversion_raw(inode, 0);
>                 inode->i_size = 0;
>                 clear_nlink(inode);
> @@ -606,6 +607,10 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
>                 } else if (fattr_supported & NFS_ATTR_FATTR_SPACE_USED &&
>                            fattr->size != 0)
>                         nfs_set_cache_invalid(inode, NFS_INO_INVALID_BLOCKS);
> +               if (fattr->valid & NFS_ATTR_FATTR_OFFLINE)
> +                       nfsi->offline = (fattr->hsa_flags & NFS_HSA_OFFLINE) ? 1 : 0;
> +               else if (fattr_supported & NFS_ATTR_FATTR_OFFLINE)
> +                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_WINATTR);
>
>                 nfs_setsecurity(inode, fattr);
>
> @@ -2274,6 +2279,12 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
>                 nfsi->cache_validity |=
>                         save_cache_validity & NFS_INO_INVALID_BLOCKS;
>
> +       if (fattr->valid & NFS_ATTR_FATTR_OFFLINE)
> +               nfsi->offline = (fattr->hsa_flags & NFS_HSA_OFFLINE) ? 1 : 0;
> +       else if (fattr_supported & NFS_ATTR_FATTR_OFFLINE)
> +               nfsi->cache_validity |=
> +                       save_cache_validity & NFS_INO_INVALID_WINATTR;
> +
>         /* Update attrtimeo value if we're out of the unstable period */
>         if (attr_changed) {
>                 nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
> diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> index 4e6cc54016ba..713a71fb3020 100644
> --- a/fs/nfs/nfs4proc.c
> +++ b/fs/nfs/nfs4proc.c
> @@ -219,6 +219,7 @@ const u32 nfs4_fattr_bitmap[3] = {
>  #ifdef CONFIG_NFS_V4_SECURITY_LABEL
>         FATTR4_WORD2_SECURITY_LABEL
>  #endif
> +       | FATTR4_WORD2_OFFLINE
>  };

This won't compile if CONFIG_NFS_V4_SECURITY_LABEL=n:

fs/nfs/nfs4proc.c:218:9: error: expected expression before ‘|’ token
  218 |         | FATTR4_WORD2_OFFLINE
      |         ^
make[2]: *** [scripts/Makefile.build:287: fs/nfs/nfs4proc.o] Error 1
make[1]: *** [scripts/Makefile.build:549: fs/nfs] Error 2
make: *** [Makefile:1846: fs] Error 2
make: *** Waiting for unfinished jobs....

Anna

>
>  static const u32 nfs4_pnfs_open_bitmap[3] = {
> @@ -245,6 +246,7 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
>  #ifdef CONFIG_NFS_V4_SECURITY_LABEL
>         | FATTR4_WORD2_SECURITY_LABEL
>  #endif
> +       | FATTR4_WORD2_OFFLINE
>  };
>
>  static const u32 nfs4_open_noattr_bitmap[3] = {
> @@ -325,6 +327,7 @@ static void nfs4_bitmap_copy_adjust(__u32 *dst, const __u32 *src,
>         if (!(cache_validity & NFS_INO_INVALID_WINATTR)) {
>                 dst[0] &= ~(FATTR4_WORD0_ARCHIVE | FATTR4_WORD0_HIDDEN);
>                 dst[1] &= ~(FATTR4_WORD1_SYSTEM | FATTR4_WORD1_TIME_BACKUP);
> +               dst[2] &= ~FATTR4_WORD2_OFFLINE;
>         }
>  }
>
> @@ -3927,6 +3930,8 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
>                 memcpy(server->attr_bitmask_nl, res.attr_bitmask,
>                                 sizeof(server->attr_bitmask));
>                 server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
> +               if (!(res.attr_bitmask[2] & FATTR4_WORD2_OFFLINE))
> +                       server->fattr_valid &= ~NFS_ATTR_FATTR_OFFLINE;
>
>                 memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask));
>                 server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
> @@ -5486,6 +5491,7 @@ static void nfs4_bitmask_set(__u32 bitmask[NFS4_BITMASK_SZ], const __u32 *src,
>         if (cache_validity & NFS_INO_INVALID_WINATTR) {
>                 bitmask[0] |= FATTR4_WORD0_ARCHIVE | FATTR4_WORD0_HIDDEN;
>                 bitmask[1] |= FATTR4_WORD1_SYSTEM | FATTR4_WORD1_TIME_BACKUP;
> +               bitmask[2] |= FATTR4_WORD2_OFFLINE;
>         }
>
>         if (cache_validity & NFS_INO_INVALID_SIZE)
> diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h
> index 5e72639b469e..02c78d66c36d 100644
> --- a/fs/nfs/nfs4trace.h
> +++ b/fs/nfs/nfs4trace.h
> @@ -35,7 +35,8 @@
>                 { NFS_ATTR_FATTR_HIDDEN, "HIDDEN" }, \
>                 { NFS_ATTR_FATTR_SYSTEM, "SYSTEM" }, \
>                 { NFS_ATTR_FATTR_ARCHIVE, "ARCHIVE" }, \
> -               { NFS_ATTR_FATTR_TIME_BACKUP, "TIME_BACKUP" })
> +               { NFS_ATTR_FATTR_TIME_BACKUP, "TIME_BACKUP" }, \
> +               { NFS_ATTR_FATTR_OFFLINE, "OFFLINE" })
>
>  DECLARE_EVENT_CLASS(nfs4_clientid_event,
>                 TP_PROTO(
> diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
> index 280df43c5bf2..a45872f860ec 100644
> --- a/fs/nfs/nfs4xdr.c
> +++ b/fs/nfs/nfs4xdr.c
> @@ -1623,7 +1623,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
>                             FATTR4_WORD1_TIME_CREATE |
>                             FATTR4_WORD1_TIME_METADATA |
>                             FATTR4_WORD1_TIME_MODIFY;
> -               attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
> +               attrs[2] |= FATTR4_WORD2_SECURITY_LABEL | FATTR4_WORD2_OFFLINE;
>                 dircount >>= 1;
>         }
>         /* Use mounted_on_fileid only if the server supports it */
> @@ -4354,6 +4354,29 @@ static int decode_attr_xattrsupport(struct xdr_stream *xdr, uint32_t *bitmap,
>         return 0;
>  }
>
> +static int decode_attr_offline(struct xdr_stream *xdr, uint32_t *bitmap,
> +                              uint32_t *res, uint64_t *flags)
> +{
> +       int status = 0;
> +       __be32 *p;
> +
> +       if (unlikely(bitmap[2] & (FATTR4_WORD2_OFFLINE - 1U)))
> +               return -EIO;
> +       if (likely(bitmap[2] & FATTR4_WORD2_OFFLINE)) {
> +               p = xdr_inline_decode(xdr, 4);
> +               if (unlikely(!p))
> +                       return -EIO;
> +               if (be32_to_cpup(p))
> +                       *res |= NFS_HSA_OFFLINE;
> +               else
> +                       *res &= ~NFS_HSA_OFFLINE;
> +               bitmap[2] &= ~FATTR4_WORD2_OFFLINE;
> +               *flags |= NFS_ATTR_FATTR_OFFLINE;
> +       }
> +       dprintk("%s: system file: =%s\n", __func__, (*res & NFS_HSA_OFFLINE) == 0 ? "false" : "true");
> +       return status;
> +}
> +
>  static int verify_attr_len(struct xdr_stream *xdr, unsigned int savep, uint32_t attrlen)
>  {
>         unsigned int attrwords = XDR_QUADLEN(attrlen);
> @@ -4842,6 +4865,12 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
>                 fattr->valid |= status;
>         }
>
> +       status = decode_attr_offline(xdr, bitmap, &fattr->hsa_flags,
> +                                    &fattr->valid);
> +       if (status < 0)
> +               goto xdr_error;
> +
> +       status = 0;
>  xdr_error:
>         dprintk("%s: xdr returned %d\n", __func__, -status);
>         return status;
> diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
> index 5662d8be04eb..817b349c24ca 100644
> --- a/include/linux/nfs4.h
> +++ b/include/linux/nfs4.h
> @@ -460,6 +460,7 @@ enum lock_type4 {
>  #define FATTR4_WORD2_SECURITY_LABEL     (1UL << 16)
>  #define FATTR4_WORD2_MODE_UMASK                (1UL << 17)
>  #define FATTR4_WORD2_XATTR_SUPPORT     (1UL << 18)
> +#define FATTR4_WORD2_OFFLINE           (1UL << 19)
>
>  /* MDS threshold bitmap bits */
>  #define THRESHOLD_RD                    (1UL << 0)
> diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
> index 1839fed16b18..61f852ebb0a4 100644
> --- a/include/linux/nfs_fs.h
> +++ b/include/linux/nfs_fs.h
> @@ -148,6 +148,7 @@ struct nfs_inode {
>         unsigned char           archive : 1;
>         unsigned char           hidden : 1;
>         unsigned char           system : 1;
> +       unsigned char           offline : 1;
>
>         /*
>          * read_cache_jiffies is when we started read-caching this inode.
> diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
> index dedc7e0bf2b9..f5588bc22cb1 100644
> --- a/include/linux/nfs_xdr.h
> +++ b/include/linux/nfs_xdr.h
> @@ -21,6 +21,7 @@
>  #define NFS_HSA_HIDDEN         BIT(0)
>  #define NFS_HSA_SYSTEM         BIT(1)
>  #define NFS_HSA_ARCHIVE                BIT(2)
> +#define NFS_HSA_OFFLINE                BIT(3)
>
>  struct nfs4_string {
>         unsigned int len;
> @@ -119,6 +120,7 @@ struct nfs_fattr {
>  #define NFS_ATTR_FATTR_SYSTEM           BIT_ULL(28)
>  #define NFS_ATTR_FATTR_ARCHIVE          BIT_ULL(29)
>  #define NFS_ATTR_FATTR_TIME_BACKUP      BIT_ULL(30)
> +#define NFS_ATTR_FATTR_OFFLINE          BIT_ULL(31)
>
>  #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
>                 | NFS_ATTR_FATTR_MODE \
> @@ -144,7 +146,8 @@ struct nfs_fattr {
>                 | NFS_ATTR_FATTR_SYSTEM \
>                 | NFS_ATTR_FATTR_ARCHIVE \
>                 | NFS_ATTR_FATTR_TIME_BACKUP \
> -               | NFS_ATTR_FATTR_V4_SECURITY_LABEL)
> +               | NFS_ATTR_FATTR_V4_SECURITY_LABEL \
> +               | NFS_ATTR_FATTR_OFFLINE)
>
>  /*
>   * Maximal number of supported layout drivers.
> --
> 2.33.1
>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 6/8] NFSv4: Support the offline bit
  2022-01-07 14:23             ` [PATCH v2 6/8] NFSv4: Support the offline bit Anna Schumaker
@ 2022-01-07 14:26               ` Trond Myklebust
  2022-01-07 14:31               ` Anna Schumaker
  1 sibling, 0 replies; 14+ messages in thread
From: Trond Myklebust @ 2022-01-07 14:26 UTC (permalink / raw)
  To: anna.schumaker, trondmy; +Cc: linux-nfs

On Fri, 2022-01-07 at 09:23 -0500, Anna Schumaker wrote:
> Hi Trond,
> 
> On Tue, Dec 28, 2021 at 3:03 AM <trondmy@kernel.org> wrote:
> > 
> > From: Trond Myklebust <trond.myklebust@primarydata.com>
> > 
> > Add tracking of the NFSv4 'offline' attribute.
> > 
> > Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> > Signed-off-by: Lance Shelton <lance.shelton@hammerspace.com>
> > Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
> > ---
> >  fs/nfs/inode.c          | 11 +++++++++++
> >  fs/nfs/nfs4proc.c       |  6 ++++++
> >  fs/nfs/nfs4trace.h      |  3 ++-
> >  fs/nfs/nfs4xdr.c        | 31 ++++++++++++++++++++++++++++++-
> >  include/linux/nfs4.h    |  1 +
> >  include/linux/nfs_fs.h  |  1 +
> >  include/linux/nfs_xdr.h |  5 ++++-
> >  7 files changed, 55 insertions(+), 3 deletions(-)
> > 
> > diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> > index 4673b091ea31..33f4410190b6 100644
> > --- a/fs/nfs/inode.c
> > +++ b/fs/nfs/inode.c
> > @@ -528,6 +528,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh
> > *fh, struct nfs_fattr *fattr)
> >                 nfsi->archive = 0;
> >                 nfsi->hidden = 0;
> >                 nfsi->system = 0;
> > +               nfsi->offline = 0;
> >                 inode_set_iversion_raw(inode, 0);
> >                 inode->i_size = 0;
> >                 clear_nlink(inode);
> > @@ -606,6 +607,10 @@ nfs_fhget(struct super_block *sb, struct
> > nfs_fh *fh, struct nfs_fattr *fattr)
> >                 } else if (fattr_supported &
> > NFS_ATTR_FATTR_SPACE_USED &&
> >                            fattr->size != 0)
> >                         nfs_set_cache_invalid(inode,
> > NFS_INO_INVALID_BLOCKS);
> > +               if (fattr->valid & NFS_ATTR_FATTR_OFFLINE)
> > +                       nfsi->offline = (fattr->hsa_flags &
> > NFS_HSA_OFFLINE) ? 1 : 0;
> > +               else if (fattr_supported & NFS_ATTR_FATTR_OFFLINE)
> > +                       nfs_set_cache_invalid(inode,
> > NFS_INO_INVALID_WINATTR);
> > 
> >                 nfs_setsecurity(inode, fattr);
> > 
> > @@ -2274,6 +2279,12 @@ static int nfs_update_inode(struct inode
> > *inode, struct nfs_fattr *fattr)
> >                 nfsi->cache_validity |=
> >                         save_cache_validity &
> > NFS_INO_INVALID_BLOCKS;
> > 
> > +       if (fattr->valid & NFS_ATTR_FATTR_OFFLINE)
> > +               nfsi->offline = (fattr->hsa_flags &
> > NFS_HSA_OFFLINE) ? 1 : 0;
> > +       else if (fattr_supported & NFS_ATTR_FATTR_OFFLINE)
> > +               nfsi->cache_validity |=
> > +                       save_cache_validity &
> > NFS_INO_INVALID_WINATTR;
> > +
> >         /* Update attrtimeo value if we're out of the unstable
> > period */
> >         if (attr_changed) {
> >                 nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
> > diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> > index 4e6cc54016ba..713a71fb3020 100644
> > --- a/fs/nfs/nfs4proc.c
> > +++ b/fs/nfs/nfs4proc.c
> > @@ -219,6 +219,7 @@ const u32 nfs4_fattr_bitmap[3] = {
> >  #ifdef CONFIG_NFS_V4_SECURITY_LABEL
> >         FATTR4_WORD2_SECURITY_LABEL
> >  #endif
> > +       | FATTR4_WORD2_OFFLINE
> >  };
> 
> This won't compile if CONFIG_NFS_V4_SECURITY_LABEL=n:
> 
> fs/nfs/nfs4proc.c:218:9: error: expected expression before ‘|’ token
>   218 |         | FATTR4_WORD2_OFFLINE

Oh... Can you fix it up by just moving that '|' inside the #ifdef?



-- 
Trond Myklebust
Linux NFS client maintainer, Hammerspace
trond.myklebust@hammerspace.com



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 6/8] NFSv4: Support the offline bit
  2022-01-07 14:23             ` [PATCH v2 6/8] NFSv4: Support the offline bit Anna Schumaker
  2022-01-07 14:26               ` Trond Myklebust
@ 2022-01-07 14:31               ` Anna Schumaker
  2022-01-07 14:36                 ` Trond Myklebust
  1 sibling, 1 reply; 14+ messages in thread
From: Anna Schumaker @ 2022-01-07 14:31 UTC (permalink / raw)
  To: trondmy; +Cc: Linux NFS Mailing List

On Fri, Jan 7, 2022 at 9:23 AM Anna Schumaker <anna.schumaker@netapp.com> wrote:
>
> Hi Trond,
>
> On Tue, Dec 28, 2021 at 3:03 AM <trondmy@kernel.org> wrote:
> >
> > From: Trond Myklebust <trond.myklebust@primarydata.com>
> >
> > Add tracking of the NFSv4 'offline' attribute.
> >
> > Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> > Signed-off-by: Lance Shelton <lance.shelton@hammerspace.com>
> > Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
> > ---
> >  fs/nfs/inode.c          | 11 +++++++++++
> >  fs/nfs/nfs4proc.c       |  6 ++++++
> >  fs/nfs/nfs4trace.h      |  3 ++-
> >  fs/nfs/nfs4xdr.c        | 31 ++++++++++++++++++++++++++++++-
> >  include/linux/nfs4.h    |  1 +
> >  include/linux/nfs_fs.h  |  1 +
> >  include/linux/nfs_xdr.h |  5 ++++-
> >  7 files changed, 55 insertions(+), 3 deletions(-)
> >
> > diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> > index 4673b091ea31..33f4410190b6 100644
> > --- a/fs/nfs/inode.c
> > +++ b/fs/nfs/inode.c
> > @@ -528,6 +528,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
> >                 nfsi->archive = 0;
> >                 nfsi->hidden = 0;
> >                 nfsi->system = 0;
> > +               nfsi->offline = 0;
> >                 inode_set_iversion_raw(inode, 0);
> >                 inode->i_size = 0;
> >                 clear_nlink(inode);
> > @@ -606,6 +607,10 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
> >                 } else if (fattr_supported & NFS_ATTR_FATTR_SPACE_USED &&
> >                            fattr->size != 0)
> >                         nfs_set_cache_invalid(inode, NFS_INO_INVALID_BLOCKS);
> > +               if (fattr->valid & NFS_ATTR_FATTR_OFFLINE)
> > +                       nfsi->offline = (fattr->hsa_flags & NFS_HSA_OFFLINE) ? 1 : 0;
> > +               else if (fattr_supported & NFS_ATTR_FATTR_OFFLINE)
> > +                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_WINATTR);
> >
> >                 nfs_setsecurity(inode, fattr);
> >
> > @@ -2274,6 +2279,12 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
> >                 nfsi->cache_validity |=
> >                         save_cache_validity & NFS_INO_INVALID_BLOCKS;
> >
> > +       if (fattr->valid & NFS_ATTR_FATTR_OFFLINE)
> > +               nfsi->offline = (fattr->hsa_flags & NFS_HSA_OFFLINE) ? 1 : 0;
> > +       else if (fattr_supported & NFS_ATTR_FATTR_OFFLINE)
> > +               nfsi->cache_validity |=
> > +                       save_cache_validity & NFS_INO_INVALID_WINATTR;
> > +
> >         /* Update attrtimeo value if we're out of the unstable period */
> >         if (attr_changed) {
> >                 nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
> > diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> > index 4e6cc54016ba..713a71fb3020 100644
> > --- a/fs/nfs/nfs4proc.c
> > +++ b/fs/nfs/nfs4proc.c
> > @@ -219,6 +219,7 @@ const u32 nfs4_fattr_bitmap[3] = {
> >  #ifdef CONFIG_NFS_V4_SECURITY_LABEL
> >         FATTR4_WORD2_SECURITY_LABEL
> >  #endif
> > +       | FATTR4_WORD2_OFFLINE
> >  };
>
> This won't compile if CONFIG_NFS_V4_SECURITY_LABEL=n:
>
> fs/nfs/nfs4proc.c:218:9: error: expected expression before ‘|’ token
>   218 |         | FATTR4_WORD2_OFFLINE
>       |         ^
> make[2]: *** [scripts/Makefile.build:287: fs/nfs/nfs4proc.o] Error 1
> make[1]: *** [scripts/Makefile.build:549: fs/nfs] Error 2
> make: *** [Makefile:1846: fs] Error 2
> make: *** Waiting for unfinished jobs....

I can fix it up by doing:

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 5d3dd647dbf6..9bd7a785eb1b 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -212,10 +212,10 @@ const u32 nfs4_fattr_bitmap[3] = {
        | FATTR4_WORD1_TIME_METADATA
        | FATTR4_WORD1_TIME_MODIFY
        | FATTR4_WORD1_MOUNTED_ON_FILEID,
+       FATTR4_WORD2_OFFLINE
 #ifdef CONFIG_NFS_V4_SECURITY_LABEL
-       FATTR4_WORD2_SECURITY_LABEL
+       | FATTR4_WORD2_SECURITY_LABEL
 #endif
-       | FATTR4_WORD2_OFFLINE
 };

 static const u32 nfs4_pnfs_open_bitmap[3] = {

If that works for you I can squash it into your patch in my tree

Anna

>
> Anna
>
> >
> >  static const u32 nfs4_pnfs_open_bitmap[3] = {
> > @@ -245,6 +246,7 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
> >  #ifdef CONFIG_NFS_V4_SECURITY_LABEL
> >         | FATTR4_WORD2_SECURITY_LABEL
> >  #endif
> > +       | FATTR4_WORD2_OFFLINE
> >  };
> >
> >  static const u32 nfs4_open_noattr_bitmap[3] = {
> > @@ -325,6 +327,7 @@ static void nfs4_bitmap_copy_adjust(__u32 *dst, const __u32 *src,
> >         if (!(cache_validity & NFS_INO_INVALID_WINATTR)) {
> >                 dst[0] &= ~(FATTR4_WORD0_ARCHIVE | FATTR4_WORD0_HIDDEN);
> >                 dst[1] &= ~(FATTR4_WORD1_SYSTEM | FATTR4_WORD1_TIME_BACKUP);
> > +               dst[2] &= ~FATTR4_WORD2_OFFLINE;
> >         }
> >  }
> >
> > @@ -3927,6 +3930,8 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
> >                 memcpy(server->attr_bitmask_nl, res.attr_bitmask,
> >                                 sizeof(server->attr_bitmask));
> >                 server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
> > +               if (!(res.attr_bitmask[2] & FATTR4_WORD2_OFFLINE))
> > +                       server->fattr_valid &= ~NFS_ATTR_FATTR_OFFLINE;
> >
> >                 memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask));
> >                 server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
> > @@ -5486,6 +5491,7 @@ static void nfs4_bitmask_set(__u32 bitmask[NFS4_BITMASK_SZ], const __u32 *src,
> >         if (cache_validity & NFS_INO_INVALID_WINATTR) {
> >                 bitmask[0] |= FATTR4_WORD0_ARCHIVE | FATTR4_WORD0_HIDDEN;
> >                 bitmask[1] |= FATTR4_WORD1_SYSTEM | FATTR4_WORD1_TIME_BACKUP;
> > +               bitmask[2] |= FATTR4_WORD2_OFFLINE;
> >         }
> >
> >         if (cache_validity & NFS_INO_INVALID_SIZE)
> > diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h
> > index 5e72639b469e..02c78d66c36d 100644
> > --- a/fs/nfs/nfs4trace.h
> > +++ b/fs/nfs/nfs4trace.h
> > @@ -35,7 +35,8 @@
> >                 { NFS_ATTR_FATTR_HIDDEN, "HIDDEN" }, \
> >                 { NFS_ATTR_FATTR_SYSTEM, "SYSTEM" }, \
> >                 { NFS_ATTR_FATTR_ARCHIVE, "ARCHIVE" }, \
> > -               { NFS_ATTR_FATTR_TIME_BACKUP, "TIME_BACKUP" })
> > +               { NFS_ATTR_FATTR_TIME_BACKUP, "TIME_BACKUP" }, \
> > +               { NFS_ATTR_FATTR_OFFLINE, "OFFLINE" })
> >
> >  DECLARE_EVENT_CLASS(nfs4_clientid_event,
> >                 TP_PROTO(
> > diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
> > index 280df43c5bf2..a45872f860ec 100644
> > --- a/fs/nfs/nfs4xdr.c
> > +++ b/fs/nfs/nfs4xdr.c
> > @@ -1623,7 +1623,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
> >                             FATTR4_WORD1_TIME_CREATE |
> >                             FATTR4_WORD1_TIME_METADATA |
> >                             FATTR4_WORD1_TIME_MODIFY;
> > -               attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
> > +               attrs[2] |= FATTR4_WORD2_SECURITY_LABEL | FATTR4_WORD2_OFFLINE;
> >                 dircount >>= 1;
> >         }
> >         /* Use mounted_on_fileid only if the server supports it */
> > @@ -4354,6 +4354,29 @@ static int decode_attr_xattrsupport(struct xdr_stream *xdr, uint32_t *bitmap,
> >         return 0;
> >  }
> >
> > +static int decode_attr_offline(struct xdr_stream *xdr, uint32_t *bitmap,
> > +                              uint32_t *res, uint64_t *flags)
> > +{
> > +       int status = 0;
> > +       __be32 *p;
> > +
> > +       if (unlikely(bitmap[2] & (FATTR4_WORD2_OFFLINE - 1U)))
> > +               return -EIO;
> > +       if (likely(bitmap[2] & FATTR4_WORD2_OFFLINE)) {
> > +               p = xdr_inline_decode(xdr, 4);
> > +               if (unlikely(!p))
> > +                       return -EIO;
> > +               if (be32_to_cpup(p))
> > +                       *res |= NFS_HSA_OFFLINE;
> > +               else
> > +                       *res &= ~NFS_HSA_OFFLINE;
> > +               bitmap[2] &= ~FATTR4_WORD2_OFFLINE;
> > +               *flags |= NFS_ATTR_FATTR_OFFLINE;
> > +       }
> > +       dprintk("%s: system file: =%s\n", __func__, (*res & NFS_HSA_OFFLINE) == 0 ? "false" : "true");
> > +       return status;
> > +}
> > +
> >  static int verify_attr_len(struct xdr_stream *xdr, unsigned int savep, uint32_t attrlen)
> >  {
> >         unsigned int attrwords = XDR_QUADLEN(attrlen);
> > @@ -4842,6 +4865,12 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
> >                 fattr->valid |= status;
> >         }
> >
> > +       status = decode_attr_offline(xdr, bitmap, &fattr->hsa_flags,
> > +                                    &fattr->valid);
> > +       if (status < 0)
> > +               goto xdr_error;
> > +
> > +       status = 0;
> >  xdr_error:
> >         dprintk("%s: xdr returned %d\n", __func__, -status);
> >         return status;
> > diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
> > index 5662d8be04eb..817b349c24ca 100644
> > --- a/include/linux/nfs4.h
> > +++ b/include/linux/nfs4.h
> > @@ -460,6 +460,7 @@ enum lock_type4 {
> >  #define FATTR4_WORD2_SECURITY_LABEL     (1UL << 16)
> >  #define FATTR4_WORD2_MODE_UMASK                (1UL << 17)
> >  #define FATTR4_WORD2_XATTR_SUPPORT     (1UL << 18)
> > +#define FATTR4_WORD2_OFFLINE           (1UL << 19)
> >
> >  /* MDS threshold bitmap bits */
> >  #define THRESHOLD_RD                    (1UL << 0)
> > diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
> > index 1839fed16b18..61f852ebb0a4 100644
> > --- a/include/linux/nfs_fs.h
> > +++ b/include/linux/nfs_fs.h
> > @@ -148,6 +148,7 @@ struct nfs_inode {
> >         unsigned char           archive : 1;
> >         unsigned char           hidden : 1;
> >         unsigned char           system : 1;
> > +       unsigned char           offline : 1;
> >
> >         /*
> >          * read_cache_jiffies is when we started read-caching this inode.
> > diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
> > index dedc7e0bf2b9..f5588bc22cb1 100644
> > --- a/include/linux/nfs_xdr.h
> > +++ b/include/linux/nfs_xdr.h
> > @@ -21,6 +21,7 @@
> >  #define NFS_HSA_HIDDEN         BIT(0)
> >  #define NFS_HSA_SYSTEM         BIT(1)
> >  #define NFS_HSA_ARCHIVE                BIT(2)
> > +#define NFS_HSA_OFFLINE                BIT(3)
> >
> >  struct nfs4_string {
> >         unsigned int len;
> > @@ -119,6 +120,7 @@ struct nfs_fattr {
> >  #define NFS_ATTR_FATTR_SYSTEM           BIT_ULL(28)
> >  #define NFS_ATTR_FATTR_ARCHIVE          BIT_ULL(29)
> >  #define NFS_ATTR_FATTR_TIME_BACKUP      BIT_ULL(30)
> > +#define NFS_ATTR_FATTR_OFFLINE          BIT_ULL(31)
> >
> >  #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
> >                 | NFS_ATTR_FATTR_MODE \
> > @@ -144,7 +146,8 @@ struct nfs_fattr {
> >                 | NFS_ATTR_FATTR_SYSTEM \
> >                 | NFS_ATTR_FATTR_ARCHIVE \
> >                 | NFS_ATTR_FATTR_TIME_BACKUP \
> > -               | NFS_ATTR_FATTR_V4_SECURITY_LABEL)
> > +               | NFS_ATTR_FATTR_V4_SECURITY_LABEL \
> > +               | NFS_ATTR_FATTR_OFFLINE)
> >
> >  /*
> >   * Maximal number of supported layout drivers.
> > --
> > 2.33.1
> >

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 6/8] NFSv4: Support the offline bit
  2022-01-07 14:31               ` Anna Schumaker
@ 2022-01-07 14:36                 ` Trond Myklebust
  2022-01-07 20:36                   ` Anna Schumaker
  0 siblings, 1 reply; 14+ messages in thread
From: Trond Myklebust @ 2022-01-07 14:36 UTC (permalink / raw)
  To: anna.schumaker, trondmy; +Cc: linux-nfs

On Fri, 2022-01-07 at 09:31 -0500, Anna Schumaker wrote:
> On Fri, Jan 7, 2022 at 9:23 AM Anna Schumaker
> <anna.schumaker@netapp.com> wrote:
> > 
> > Hi Trond,
> > 
> > On Tue, Dec 28, 2021 at 3:03 AM <trondmy@kernel.org> wrote:
> > > 
> > > From: Trond Myklebust <trond.myklebust@primarydata.com>
> > > 
> > > Add tracking of the NFSv4 'offline' attribute.
> > > 
> > > Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> > > Signed-off-by: Lance Shelton <lance.shelton@hammerspace.com>
> > > Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
> > > ---
> > >  fs/nfs/inode.c          | 11 +++++++++++
> > >  fs/nfs/nfs4proc.c       |  6 ++++++
> > >  fs/nfs/nfs4trace.h      |  3 ++-
> > >  fs/nfs/nfs4xdr.c        | 31 ++++++++++++++++++++++++++++++-
> > >  include/linux/nfs4.h    |  1 +
> > >  include/linux/nfs_fs.h  |  1 +
> > >  include/linux/nfs_xdr.h |  5 ++++-
> > >  7 files changed, 55 insertions(+), 3 deletions(-)
> > > 
> > > diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> > > index 4673b091ea31..33f4410190b6 100644
> > > --- a/fs/nfs/inode.c
> > > +++ b/fs/nfs/inode.c
> > > @@ -528,6 +528,7 @@ nfs_fhget(struct super_block *sb, struct
> > > nfs_fh *fh, struct nfs_fattr *fattr)
> > >                 nfsi->archive = 0;
> > >                 nfsi->hidden = 0;
> > >                 nfsi->system = 0;
> > > +               nfsi->offline = 0;
> > >                 inode_set_iversion_raw(inode, 0);
> > >                 inode->i_size = 0;
> > >                 clear_nlink(inode);
> > > @@ -606,6 +607,10 @@ nfs_fhget(struct super_block *sb, struct
> > > nfs_fh *fh, struct nfs_fattr *fattr)
> > >                 } else if (fattr_supported &
> > > NFS_ATTR_FATTR_SPACE_USED &&
> > >                            fattr->size != 0)
> > >                         nfs_set_cache_invalid(inode,
> > > NFS_INO_INVALID_BLOCKS);
> > > +               if (fattr->valid & NFS_ATTR_FATTR_OFFLINE)
> > > +                       nfsi->offline = (fattr->hsa_flags &
> > > NFS_HSA_OFFLINE) ? 1 : 0;
> > > +               else if (fattr_supported &
> > > NFS_ATTR_FATTR_OFFLINE)
> > > +                       nfs_set_cache_invalid(inode,
> > > NFS_INO_INVALID_WINATTR);
> > > 
> > >                 nfs_setsecurity(inode, fattr);
> > > 
> > > @@ -2274,6 +2279,12 @@ static int nfs_update_inode(struct inode
> > > *inode, struct nfs_fattr *fattr)
> > >                 nfsi->cache_validity |=
> > >                         save_cache_validity &
> > > NFS_INO_INVALID_BLOCKS;
> > > 
> > > +       if (fattr->valid & NFS_ATTR_FATTR_OFFLINE)
> > > +               nfsi->offline = (fattr->hsa_flags &
> > > NFS_HSA_OFFLINE) ? 1 : 0;
> > > +       else if (fattr_supported & NFS_ATTR_FATTR_OFFLINE)
> > > +               nfsi->cache_validity |=
> > > +                       save_cache_validity &
> > > NFS_INO_INVALID_WINATTR;
> > > +
> > >         /* Update attrtimeo value if we're out of the unstable
> > > period */
> > >         if (attr_changed) {
> > >                 nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
> > > diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> > > index 4e6cc54016ba..713a71fb3020 100644
> > > --- a/fs/nfs/nfs4proc.c
> > > +++ b/fs/nfs/nfs4proc.c
> > > @@ -219,6 +219,7 @@ const u32 nfs4_fattr_bitmap[3] = {
> > >  #ifdef CONFIG_NFS_V4_SECURITY_LABEL
> > >         FATTR4_WORD2_SECURITY_LABEL
> > >  #endif
> > > +       | FATTR4_WORD2_OFFLINE
> > >  };
> > 
> > This won't compile if CONFIG_NFS_V4_SECURITY_LABEL=n:
> > 
> > fs/nfs/nfs4proc.c:218:9: error: expected expression before ‘|’
> > token
> >   218 |         | FATTR4_WORD2_OFFLINE
> >       |         ^
> > make[2]: *** [scripts/Makefile.build:287: fs/nfs/nfs4proc.o] Error
> > 1
> > make[1]: *** [scripts/Makefile.build:549: fs/nfs] Error 2
> > make: *** [Makefile:1846: fs] Error 2
> > make: *** Waiting for unfinished jobs....
> 
> I can fix it up by doing:
> 
> diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> index 5d3dd647dbf6..9bd7a785eb1b 100644
> --- a/fs/nfs/nfs4proc.c
> +++ b/fs/nfs/nfs4proc.c
> @@ -212,10 +212,10 @@ const u32 nfs4_fattr_bitmap[3] = {
>         | FATTR4_WORD1_TIME_METADATA
>         | FATTR4_WORD1_TIME_MODIFY
>         | FATTR4_WORD1_MOUNTED_ON_FILEID,
> +       FATTR4_WORD2_OFFLINE
>  #ifdef CONFIG_NFS_V4_SECURITY_LABEL
> -       FATTR4_WORD2_SECURITY_LABEL
> +       | FATTR4_WORD2_SECURITY_LABEL
>  #endif
> -       | FATTR4_WORD2_OFFLINE
>  };
> 
>  static const u32 nfs4_pnfs_open_bitmap[3] = {
> 
> If that works for you I can squash it into your patch in my tree

Sure. I was thinking the opposite, but this works too.

i.e. my suggestion was just

#ifdef CONFIG_NFS_V4_SECURITY_LABEL
        FATTR4_WORD2_SECURITY_LABEL |
#endif
        FATTR4_WORD2_OFFLINE

However there is no functional difference between the two, so let's go
with yours.

> 
> Anna
> 
> > 
> > Anna
> > 
> > > 
> > >  static const u32 nfs4_pnfs_open_bitmap[3] = {
> > > @@ -245,6 +246,7 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
> > >  #ifdef CONFIG_NFS_V4_SECURITY_LABEL
> > >         | FATTR4_WORD2_SECURITY_LABEL
> > >  #endif
> > > +       | FATTR4_WORD2_OFFLINE
> > >  };
> > > 
> > >  static const u32 nfs4_open_noattr_bitmap[3] = {
> > > @@ -325,6 +327,7 @@ static void nfs4_bitmap_copy_adjust(__u32
> > > *dst, const __u32 *src,
> > >         if (!(cache_validity & NFS_INO_INVALID_WINATTR)) {
> > >                 dst[0] &= ~(FATTR4_WORD0_ARCHIVE |
> > > FATTR4_WORD0_HIDDEN);
> > >                 dst[1] &= ~(FATTR4_WORD1_SYSTEM |
> > > FATTR4_WORD1_TIME_BACKUP);
> > > +               dst[2] &= ~FATTR4_WORD2_OFFLINE;
> > >         }
> > >  }
> > > 
> > > @@ -3927,6 +3930,8 @@ static int _nfs4_server_capabilities(struct
> > > nfs_server *server, struct nfs_fh *f
> > >                 memcpy(server->attr_bitmask_nl, res.attr_bitmask,
> > >                                 sizeof(server->attr_bitmask));
> > >                 server->attr_bitmask_nl[2] &=
> > > ~FATTR4_WORD2_SECURITY_LABEL;
> > > +               if (!(res.attr_bitmask[2] &
> > > FATTR4_WORD2_OFFLINE))
> > > +                       server->fattr_valid &=
> > > ~NFS_ATTR_FATTR_OFFLINE;
> > > 
> > >                 memcpy(server->cache_consistency_bitmask,
> > > res.attr_bitmask, sizeof(server->cache_consistency_bitmask));
> > >                 server->cache_consistency_bitmask[0] &=
> > > FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
> > > @@ -5486,6 +5491,7 @@ static void nfs4_bitmask_set(__u32
> > > bitmask[NFS4_BITMASK_SZ], const __u32 *src,
> > >         if (cache_validity & NFS_INO_INVALID_WINATTR) {
> > >                 bitmask[0] |= FATTR4_WORD0_ARCHIVE |
> > > FATTR4_WORD0_HIDDEN;
> > >                 bitmask[1] |= FATTR4_WORD1_SYSTEM |
> > > FATTR4_WORD1_TIME_BACKUP;
> > > +               bitmask[2] |= FATTR4_WORD2_OFFLINE;
> > >         }
> > > 
> > >         if (cache_validity & NFS_INO_INVALID_SIZE)
> > > diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h
> > > index 5e72639b469e..02c78d66c36d 100644
> > > --- a/fs/nfs/nfs4trace.h
> > > +++ b/fs/nfs/nfs4trace.h
> > > @@ -35,7 +35,8 @@
> > >                 { NFS_ATTR_FATTR_HIDDEN, "HIDDEN" }, \
> > >                 { NFS_ATTR_FATTR_SYSTEM, "SYSTEM" }, \
> > >                 { NFS_ATTR_FATTR_ARCHIVE, "ARCHIVE" }, \
> > > -               { NFS_ATTR_FATTR_TIME_BACKUP, "TIME_BACKUP" })
> > > +               { NFS_ATTR_FATTR_TIME_BACKUP, "TIME_BACKUP" }, \
> > > +               { NFS_ATTR_FATTR_OFFLINE, "OFFLINE" })
> > > 
> > >  DECLARE_EVENT_CLASS(nfs4_clientid_event,
> > >                 TP_PROTO(
> > > diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
> > > index 280df43c5bf2..a45872f860ec 100644
> > > --- a/fs/nfs/nfs4xdr.c
> > > +++ b/fs/nfs/nfs4xdr.c
> > > @@ -1623,7 +1623,7 @@ static void encode_readdir(struct
> > > xdr_stream *xdr, const struct nfs4_readdir_arg
> > >                             FATTR4_WORD1_TIME_CREATE |
> > >                             FATTR4_WORD1_TIME_METADATA |
> > >                             FATTR4_WORD1_TIME_MODIFY;
> > > -               attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
> > > +               attrs[2] |= FATTR4_WORD2_SECURITY_LABEL |
> > > FATTR4_WORD2_OFFLINE;
> > >                 dircount >>= 1;
> > >         }
> > >         /* Use mounted_on_fileid only if the server supports it
> > > */
> > > @@ -4354,6 +4354,29 @@ static int decode_attr_xattrsupport(struct
> > > xdr_stream *xdr, uint32_t *bitmap,
> > >         return 0;
> > >  }
> > > 
> > > +static int decode_attr_offline(struct xdr_stream *xdr, uint32_t
> > > *bitmap,
> > > +                              uint32_t *res, uint64_t *flags)
> > > +{
> > > +       int status = 0;
> > > +       __be32 *p;
> > > +
> > > +       if (unlikely(bitmap[2] & (FATTR4_WORD2_OFFLINE - 1U)))
> > > +               return -EIO;
> > > +       if (likely(bitmap[2] & FATTR4_WORD2_OFFLINE)) {
> > > +               p = xdr_inline_decode(xdr, 4);
> > > +               if (unlikely(!p))
> > > +                       return -EIO;
> > > +               if (be32_to_cpup(p))
> > > +                       *res |= NFS_HSA_OFFLINE;
> > > +               else
> > > +                       *res &= ~NFS_HSA_OFFLINE;
> > > +               bitmap[2] &= ~FATTR4_WORD2_OFFLINE;
> > > +               *flags |= NFS_ATTR_FATTR_OFFLINE;
> > > +       }
> > > +       dprintk("%s: system file: =%s\n", __func__, (*res &
> > > NFS_HSA_OFFLINE) == 0 ? "false" : "true");
> > > +       return status;
> > > +}
> > > +
> > >  static int verify_attr_len(struct xdr_stream *xdr, unsigned int
> > > savep, uint32_t attrlen)
> > >  {
> > >         unsigned int attrwords = XDR_QUADLEN(attrlen);
> > > @@ -4842,6 +4865,12 @@ static int decode_getfattr_attrs(struct
> > > xdr_stream *xdr, uint32_t *bitmap,
> > >                 fattr->valid |= status;
> > >         }
> > > 
> > > +       status = decode_attr_offline(xdr, bitmap, &fattr-
> > > >hsa_flags,
> > > +                                    &fattr->valid);
> > > +       if (status < 0)
> > > +               goto xdr_error;
> > > +
> > > +       status = 0;
> > >  xdr_error:
> > >         dprintk("%s: xdr returned %d\n", __func__, -status);
> > >         return status;
> > > diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
> > > index 5662d8be04eb..817b349c24ca 100644
> > > --- a/include/linux/nfs4.h
> > > +++ b/include/linux/nfs4.h
> > > @@ -460,6 +460,7 @@ enum lock_type4 {
> > >  #define FATTR4_WORD2_SECURITY_LABEL     (1UL << 16)
> > >  #define FATTR4_WORD2_MODE_UMASK                (1UL << 17)
> > >  #define FATTR4_WORD2_XATTR_SUPPORT     (1UL << 18)
> > > +#define FATTR4_WORD2_OFFLINE           (1UL << 19)
> > > 
> > >  /* MDS threshold bitmap bits */
> > >  #define THRESHOLD_RD                    (1UL << 0)
> > > diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
> > > index 1839fed16b18..61f852ebb0a4 100644
> > > --- a/include/linux/nfs_fs.h
> > > +++ b/include/linux/nfs_fs.h
> > > @@ -148,6 +148,7 @@ struct nfs_inode {
> > >         unsigned char           archive : 1;
> > >         unsigned char           hidden : 1;
> > >         unsigned char           system : 1;
> > > +       unsigned char           offline : 1;
> > > 
> > >         /*
> > >          * read_cache_jiffies is when we started read-caching
> > > this inode.
> > > diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
> > > index dedc7e0bf2b9..f5588bc22cb1 100644
> > > --- a/include/linux/nfs_xdr.h
> > > +++ b/include/linux/nfs_xdr.h
> > > @@ -21,6 +21,7 @@
> > >  #define NFS_HSA_HIDDEN         BIT(0)
> > >  #define NFS_HSA_SYSTEM         BIT(1)
> > >  #define NFS_HSA_ARCHIVE                BIT(2)
> > > +#define NFS_HSA_OFFLINE                BIT(3)
> > > 
> > >  struct nfs4_string {
> > >         unsigned int len;
> > > @@ -119,6 +120,7 @@ struct nfs_fattr {
> > >  #define NFS_ATTR_FATTR_SYSTEM           BIT_ULL(28)
> > >  #define NFS_ATTR_FATTR_ARCHIVE          BIT_ULL(29)
> > >  #define NFS_ATTR_FATTR_TIME_BACKUP      BIT_ULL(30)
> > > +#define NFS_ATTR_FATTR_OFFLINE          BIT_ULL(31)
> > > 
> > >  #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
> > >                 | NFS_ATTR_FATTR_MODE \
> > > @@ -144,7 +146,8 @@ struct nfs_fattr {
> > >                 | NFS_ATTR_FATTR_SYSTEM \
> > >                 | NFS_ATTR_FATTR_ARCHIVE \
> > >                 | NFS_ATTR_FATTR_TIME_BACKUP \
> > > -               | NFS_ATTR_FATTR_V4_SECURITY_LABEL)
> > > +               | NFS_ATTR_FATTR_V4_SECURITY_LABEL \
> > > +               | NFS_ATTR_FATTR_OFFLINE)
> > > 
> > >  /*
> > >   * Maximal number of supported layout drivers.
> > > --
> > > 2.33.1
> > > 

-- 
Trond Myklebust
Linux NFS client maintainer, Hammerspace
trond.myklebust@hammerspace.com



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 6/8] NFSv4: Support the offline bit
  2022-01-07 14:36                 ` Trond Myklebust
@ 2022-01-07 20:36                   ` Anna Schumaker
  0 siblings, 0 replies; 14+ messages in thread
From: Anna Schumaker @ 2022-01-07 20:36 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: trondmy, linux-nfs

On Fri, Jan 7, 2022 at 3:17 PM Trond Myklebust <trondmy@hammerspace.com> wrote:
>
> On Fri, 2022-01-07 at 09:31 -0500, Anna Schumaker wrote:
> > On Fri, Jan 7, 2022 at 9:23 AM Anna Schumaker
> > <anna.schumaker@netapp.com> wrote:
> > >
> > > Hi Trond,
> > >
> > > On Tue, Dec 28, 2021 at 3:03 AM <trondmy@kernel.org> wrote:
> > > >
> > > > From: Trond Myklebust <trond.myklebust@primarydata.com>
> > > >
> > > > Add tracking of the NFSv4 'offline' attribute.
> > > >
> > > > Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> > > > Signed-off-by: Lance Shelton <lance.shelton@hammerspace.com>
> > > > Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
> > > > ---
> > > >  fs/nfs/inode.c          | 11 +++++++++++
> > > >  fs/nfs/nfs4proc.c       |  6 ++++++
> > > >  fs/nfs/nfs4trace.h      |  3 ++-
> > > >  fs/nfs/nfs4xdr.c        | 31 ++++++++++++++++++++++++++++++-
> > > >  include/linux/nfs4.h    |  1 +
> > > >  include/linux/nfs_fs.h  |  1 +
> > > >  include/linux/nfs_xdr.h |  5 ++++-
> > > >  7 files changed, 55 insertions(+), 3 deletions(-)
> > > >
> > > > diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> > > > index 4673b091ea31..33f4410190b6 100644
> > > > --- a/fs/nfs/inode.c
> > > > +++ b/fs/nfs/inode.c
> > > > @@ -528,6 +528,7 @@ nfs_fhget(struct super_block *sb, struct
> > > > nfs_fh *fh, struct nfs_fattr *fattr)
> > > >                 nfsi->archive = 0;
> > > >                 nfsi->hidden = 0;
> > > >                 nfsi->system = 0;
> > > > +               nfsi->offline = 0;
> > > >                 inode_set_iversion_raw(inode, 0);
> > > >                 inode->i_size = 0;
> > > >                 clear_nlink(inode);
> > > > @@ -606,6 +607,10 @@ nfs_fhget(struct super_block *sb, struct
> > > > nfs_fh *fh, struct nfs_fattr *fattr)
> > > >                 } else if (fattr_supported &
> > > > NFS_ATTR_FATTR_SPACE_USED &&
> > > >                            fattr->size != 0)
> > > >                         nfs_set_cache_invalid(inode,
> > > > NFS_INO_INVALID_BLOCKS);
> > > > +               if (fattr->valid & NFS_ATTR_FATTR_OFFLINE)
> > > > +                       nfsi->offline = (fattr->hsa_flags &
> > > > NFS_HSA_OFFLINE) ? 1 : 0;
> > > > +               else if (fattr_supported &
> > > > NFS_ATTR_FATTR_OFFLINE)
> > > > +                       nfs_set_cache_invalid(inode,
> > > > NFS_INO_INVALID_WINATTR);
> > > >
> > > >                 nfs_setsecurity(inode, fattr);
> > > >
> > > > @@ -2274,6 +2279,12 @@ static int nfs_update_inode(struct inode
> > > > *inode, struct nfs_fattr *fattr)
> > > >                 nfsi->cache_validity |=
> > > >                         save_cache_validity &
> > > > NFS_INO_INVALID_BLOCKS;
> > > >
> > > > +       if (fattr->valid & NFS_ATTR_FATTR_OFFLINE)
> > > > +               nfsi->offline = (fattr->hsa_flags &
> > > > NFS_HSA_OFFLINE) ? 1 : 0;
> > > > +       else if (fattr_supported & NFS_ATTR_FATTR_OFFLINE)
> > > > +               nfsi->cache_validity |=
> > > > +                       save_cache_validity &
> > > > NFS_INO_INVALID_WINATTR;
> > > > +
> > > >         /* Update attrtimeo value if we're out of the unstable
> > > > period */
> > > >         if (attr_changed) {
> > > >                 nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
> > > > diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> > > > index 4e6cc54016ba..713a71fb3020 100644
> > > > --- a/fs/nfs/nfs4proc.c
> > > > +++ b/fs/nfs/nfs4proc.c
> > > > @@ -219,6 +219,7 @@ const u32 nfs4_fattr_bitmap[3] = {
> > > >  #ifdef CONFIG_NFS_V4_SECURITY_LABEL
> > > >         FATTR4_WORD2_SECURITY_LABEL
> > > >  #endif
> > > > +       | FATTR4_WORD2_OFFLINE
> > > >  };
> > >
> > > This won't compile if CONFIG_NFS_V4_SECURITY_LABEL=n:
> > >
> > > fs/nfs/nfs4proc.c:218:9: error: expected expression before ‘|’
> > > token
> > >   218 |         | FATTR4_WORD2_OFFLINE
> > >       |         ^
> > > make[2]: *** [scripts/Makefile.build:287: fs/nfs/nfs4proc.o] Error
> > > 1
> > > make[1]: *** [scripts/Makefile.build:549: fs/nfs] Error 2
> > > make: *** [Makefile:1846: fs] Error 2
> > > make: *** Waiting for unfinished jobs....
> >
> > I can fix it up by doing:
> >
> > diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> > index 5d3dd647dbf6..9bd7a785eb1b 100644
> > --- a/fs/nfs/nfs4proc.c
> > +++ b/fs/nfs/nfs4proc.c
> > @@ -212,10 +212,10 @@ const u32 nfs4_fattr_bitmap[3] = {
> >         | FATTR4_WORD1_TIME_METADATA
> >         | FATTR4_WORD1_TIME_MODIFY
> >         | FATTR4_WORD1_MOUNTED_ON_FILEID,
> > +       FATTR4_WORD2_OFFLINE
> >  #ifdef CONFIG_NFS_V4_SECURITY_LABEL
> > -       FATTR4_WORD2_SECURITY_LABEL
> > +       | FATTR4_WORD2_SECURITY_LABEL
> >  #endif
> > -       | FATTR4_WORD2_OFFLINE
> >  };
> >
> >  static const u32 nfs4_pnfs_open_bitmap[3] = {
> >
> > If that works for you I can squash it into your patch in my tree
>
> Sure. I was thinking the opposite, but this works too.
>
> i.e. my suggestion was just
>
> #ifdef CONFIG_NFS_V4_SECURITY_LABEL
>         FATTR4_WORD2_SECURITY_LABEL |
> #endif
>         FATTR4_WORD2_OFFLINE
>
> However there is no functional difference between the two, so let's go
> with yours.

Thanks for taking a quick look!

Anna

>
> >
> > Anna
> >
> > >
> > > Anna
> > >
> > > >
> > > >  static const u32 nfs4_pnfs_open_bitmap[3] = {
> > > > @@ -245,6 +246,7 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
> > > >  #ifdef CONFIG_NFS_V4_SECURITY_LABEL
> > > >         | FATTR4_WORD2_SECURITY_LABEL
> > > >  #endif
> > > > +       | FATTR4_WORD2_OFFLINE
> > > >  };
> > > >
> > > >  static const u32 nfs4_open_noattr_bitmap[3] = {
> > > > @@ -325,6 +327,7 @@ static void nfs4_bitmap_copy_adjust(__u32
> > > > *dst, const __u32 *src,
> > > >         if (!(cache_validity & NFS_INO_INVALID_WINATTR)) {
> > > >                 dst[0] &= ~(FATTR4_WORD0_ARCHIVE |
> > > > FATTR4_WORD0_HIDDEN);
> > > >                 dst[1] &= ~(FATTR4_WORD1_SYSTEM |
> > > > FATTR4_WORD1_TIME_BACKUP);
> > > > +               dst[2] &= ~FATTR4_WORD2_OFFLINE;
> > > >         }
> > > >  }
> > > >
> > > > @@ -3927,6 +3930,8 @@ static int _nfs4_server_capabilities(struct
> > > > nfs_server *server, struct nfs_fh *f
> > > >                 memcpy(server->attr_bitmask_nl, res.attr_bitmask,
> > > >                                 sizeof(server->attr_bitmask));
> > > >                 server->attr_bitmask_nl[2] &=
> > > > ~FATTR4_WORD2_SECURITY_LABEL;
> > > > +               if (!(res.attr_bitmask[2] &
> > > > FATTR4_WORD2_OFFLINE))
> > > > +                       server->fattr_valid &=
> > > > ~NFS_ATTR_FATTR_OFFLINE;
> > > >
> > > >                 memcpy(server->cache_consistency_bitmask,
> > > > res.attr_bitmask, sizeof(server->cache_consistency_bitmask));
> > > >                 server->cache_consistency_bitmask[0] &=
> > > > FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
> > > > @@ -5486,6 +5491,7 @@ static void nfs4_bitmask_set(__u32
> > > > bitmask[NFS4_BITMASK_SZ], const __u32 *src,
> > > >         if (cache_validity & NFS_INO_INVALID_WINATTR) {
> > > >                 bitmask[0] |= FATTR4_WORD0_ARCHIVE |
> > > > FATTR4_WORD0_HIDDEN;
> > > >                 bitmask[1] |= FATTR4_WORD1_SYSTEM |
> > > > FATTR4_WORD1_TIME_BACKUP;
> > > > +               bitmask[2] |= FATTR4_WORD2_OFFLINE;
> > > >         }
> > > >
> > > >         if (cache_validity & NFS_INO_INVALID_SIZE)
> > > > diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h
> > > > index 5e72639b469e..02c78d66c36d 100644
> > > > --- a/fs/nfs/nfs4trace.h
> > > > +++ b/fs/nfs/nfs4trace.h
> > > > @@ -35,7 +35,8 @@
> > > >                 { NFS_ATTR_FATTR_HIDDEN, "HIDDEN" }, \
> > > >                 { NFS_ATTR_FATTR_SYSTEM, "SYSTEM" }, \
> > > >                 { NFS_ATTR_FATTR_ARCHIVE, "ARCHIVE" }, \
> > > > -               { NFS_ATTR_FATTR_TIME_BACKUP, "TIME_BACKUP" })
> > > > +               { NFS_ATTR_FATTR_TIME_BACKUP, "TIME_BACKUP" }, \
> > > > +               { NFS_ATTR_FATTR_OFFLINE, "OFFLINE" })
> > > >
> > > >  DECLARE_EVENT_CLASS(nfs4_clientid_event,
> > > >                 TP_PROTO(
> > > > diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
> > > > index 280df43c5bf2..a45872f860ec 100644
> > > > --- a/fs/nfs/nfs4xdr.c
> > > > +++ b/fs/nfs/nfs4xdr.c
> > > > @@ -1623,7 +1623,7 @@ static void encode_readdir(struct
> > > > xdr_stream *xdr, const struct nfs4_readdir_arg
> > > >                             FATTR4_WORD1_TIME_CREATE |
> > > >                             FATTR4_WORD1_TIME_METADATA |
> > > >                             FATTR4_WORD1_TIME_MODIFY;
> > > > -               attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
> > > > +               attrs[2] |= FATTR4_WORD2_SECURITY_LABEL |
> > > > FATTR4_WORD2_OFFLINE;
> > > >                 dircount >>= 1;
> > > >         }
> > > >         /* Use mounted_on_fileid only if the server supports it
> > > > */
> > > > @@ -4354,6 +4354,29 @@ static int decode_attr_xattrsupport(struct
> > > > xdr_stream *xdr, uint32_t *bitmap,
> > > >         return 0;
> > > >  }
> > > >
> > > > +static int decode_attr_offline(struct xdr_stream *xdr, uint32_t
> > > > *bitmap,
> > > > +                              uint32_t *res, uint64_t *flags)
> > > > +{
> > > > +       int status = 0;
> > > > +       __be32 *p;
> > > > +
> > > > +       if (unlikely(bitmap[2] & (FATTR4_WORD2_OFFLINE - 1U)))
> > > > +               return -EIO;
> > > > +       if (likely(bitmap[2] & FATTR4_WORD2_OFFLINE)) {
> > > > +               p = xdr_inline_decode(xdr, 4);
> > > > +               if (unlikely(!p))
> > > > +                       return -EIO;
> > > > +               if (be32_to_cpup(p))
> > > > +                       *res |= NFS_HSA_OFFLINE;
> > > > +               else
> > > > +                       *res &= ~NFS_HSA_OFFLINE;
> > > > +               bitmap[2] &= ~FATTR4_WORD2_OFFLINE;
> > > > +               *flags |= NFS_ATTR_FATTR_OFFLINE;
> > > > +       }
> > > > +       dprintk("%s: system file: =%s\n", __func__, (*res &
> > > > NFS_HSA_OFFLINE) == 0 ? "false" : "true");
> > > > +       return status;
> > > > +}
> > > > +
> > > >  static int verify_attr_len(struct xdr_stream *xdr, unsigned int
> > > > savep, uint32_t attrlen)
> > > >  {
> > > >         unsigned int attrwords = XDR_QUADLEN(attrlen);
> > > > @@ -4842,6 +4865,12 @@ static int decode_getfattr_attrs(struct
> > > > xdr_stream *xdr, uint32_t *bitmap,
> > > >                 fattr->valid |= status;
> > > >         }
> > > >
> > > > +       status = decode_attr_offline(xdr, bitmap, &fattr-
> > > > >hsa_flags,
> > > > +                                    &fattr->valid);
> > > > +       if (status < 0)
> > > > +               goto xdr_error;
> > > > +
> > > > +       status = 0;
> > > >  xdr_error:
> > > >         dprintk("%s: xdr returned %d\n", __func__, -status);
> > > >         return status;
> > > > diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
> > > > index 5662d8be04eb..817b349c24ca 100644
> > > > --- a/include/linux/nfs4.h
> > > > +++ b/include/linux/nfs4.h
> > > > @@ -460,6 +460,7 @@ enum lock_type4 {
> > > >  #define FATTR4_WORD2_SECURITY_LABEL     (1UL << 16)
> > > >  #define FATTR4_WORD2_MODE_UMASK                (1UL << 17)
> > > >  #define FATTR4_WORD2_XATTR_SUPPORT     (1UL << 18)
> > > > +#define FATTR4_WORD2_OFFLINE           (1UL << 19)
> > > >
> > > >  /* MDS threshold bitmap bits */
> > > >  #define THRESHOLD_RD                    (1UL << 0)
> > > > diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
> > > > index 1839fed16b18..61f852ebb0a4 100644
> > > > --- a/include/linux/nfs_fs.h
> > > > +++ b/include/linux/nfs_fs.h
> > > > @@ -148,6 +148,7 @@ struct nfs_inode {
> > > >         unsigned char           archive : 1;
> > > >         unsigned char           hidden : 1;
> > > >         unsigned char           system : 1;
> > > > +       unsigned char           offline : 1;
> > > >
> > > >         /*
> > > >          * read_cache_jiffies is when we started read-caching
> > > > this inode.
> > > > diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
> > > > index dedc7e0bf2b9..f5588bc22cb1 100644
> > > > --- a/include/linux/nfs_xdr.h
> > > > +++ b/include/linux/nfs_xdr.h
> > > > @@ -21,6 +21,7 @@
> > > >  #define NFS_HSA_HIDDEN         BIT(0)
> > > >  #define NFS_HSA_SYSTEM         BIT(1)
> > > >  #define NFS_HSA_ARCHIVE                BIT(2)
> > > > +#define NFS_HSA_OFFLINE                BIT(3)
> > > >
> > > >  struct nfs4_string {
> > > >         unsigned int len;
> > > > @@ -119,6 +120,7 @@ struct nfs_fattr {
> > > >  #define NFS_ATTR_FATTR_SYSTEM           BIT_ULL(28)
> > > >  #define NFS_ATTR_FATTR_ARCHIVE          BIT_ULL(29)
> > > >  #define NFS_ATTR_FATTR_TIME_BACKUP      BIT_ULL(30)
> > > > +#define NFS_ATTR_FATTR_OFFLINE          BIT_ULL(31)
> > > >
> > > >  #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
> > > >                 | NFS_ATTR_FATTR_MODE \
> > > > @@ -144,7 +146,8 @@ struct nfs_fattr {
> > > >                 | NFS_ATTR_FATTR_SYSTEM \
> > > >                 | NFS_ATTR_FATTR_ARCHIVE \
> > > >                 | NFS_ATTR_FATTR_TIME_BACKUP \
> > > > -               | NFS_ATTR_FATTR_V4_SECURITY_LABEL)
> > > > +               | NFS_ATTR_FATTR_V4_SECURITY_LABEL \
> > > > +               | NFS_ATTR_FATTR_OFFLINE)
> > > >
> > > >  /*
> > > >   * Maximal number of supported layout drivers.
> > > > --
> > > > 2.33.1
> > > >
>
> --
> Trond Myklebust
> Linux NFS client maintainer, Hammerspace
> trond.myklebust@hammerspace.com
>
>

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2022-01-07 20:36 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-27 19:04 [PATCH v2 0/8] Support btime and other NFSv4 specific attributes trondmy
2021-12-27 19:04 ` [PATCH v2 1/8] NFS: Expand the type of nfs_fattr->valid trondmy
2021-12-27 19:04   ` [PATCH v2 2/8] nfs: Add timecreate to nfs inode trondmy
2021-12-27 19:04     ` [PATCH v2 3/8] NFS: Return the file btime in the statx results when appropriate trondmy
2021-12-27 19:05       ` [PATCH v2 4/8] nfs: Add 'archive', 'hidden' and 'system' fields to nfs inode trondmy
2021-12-27 19:05         ` [PATCH v2 5/8] nfs: Add 'time backup' " trondmy
2021-12-27 19:05           ` [PATCH v2 6/8] NFSv4: Support the offline bit trondmy
2021-12-27 19:05             ` [PATCH v2 7/8] NFS: Support statx_get and statx_set ioctls trondmy
2021-12-27 19:05               ` [PATCH v2 8/8] NFSv4: Add an ioctl to allow retrieval of the NFS raw ACCESS mask trondmy
2022-01-07 14:23             ` [PATCH v2 6/8] NFSv4: Support the offline bit Anna Schumaker
2022-01-07 14:26               ` Trond Myklebust
2022-01-07 14:31               ` Anna Schumaker
2022-01-07 14:36                 ` Trond Myklebust
2022-01-07 20:36                   ` Anna Schumaker

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.