From patchwork Mon Dec 27 19:04:57 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Trond Myklebust X-Patchwork-Id: 12700016 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A5060C433EF for ; Mon, 27 Dec 2021 19:11:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230163AbhL0TLe (ORCPT ); Mon, 27 Dec 2021 14:11:34 -0500 Received: from ams.source.kernel.org ([145.40.68.75]:45252 "EHLO ams.source.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230510AbhL0TLd (ORCPT ); Mon, 27 Dec 2021 14:11:33 -0500 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 765D1B81144 for ; Mon, 27 Dec 2021 19:11:32 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id DB6B5C36AEA; Mon, 27 Dec 2021 19:11:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1640632291; bh=jW3o+Y7QNxe9LqB8UZWWE7G4YIBzkiHs6AU1ziioXZ8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Iixa9/P5rK4cMq10ztvzxe8kEc3jmIFSHzmgCC427wqwLt+FHhlXaRua+xP//dw5C +mWGj6RqD4jRWfy90Af2IcHIVCuqmr2CxORXk2nf12ciJfIpsRvnMqo0vDmTGZ0jJ2 3FSju1C+DzHT24/NnTiPAz1uciIcCXOa6ISjnm0GI9YQ8jTNH0foLhRuH5S/W+oItm q2ETzmFL9wk68wM6Lf7+RSRRF8pq81hVzxFumK0wG3/FbIjeCFhEUcu01xbxNW/wZ7 TzKpHoy45LZrNj68FxCe9RGvYL3NTUPLJqw47ARWC7//YNokGhf3NkniK+m5P8dPJx OqfqhvSTG8e+g== From: trondmy@kernel.org To: Anna Schumaker Cc: linux-nfs@vger.kernel.org Subject: [PATCH v2 1/8] NFS: Expand the type of nfs_fattr->valid Date: Mon, 27 Dec 2021 14:04:57 -0500 Message-Id: <20211227190504.309612-2-trondmy@kernel.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211227190504.309612-1-trondmy@kernel.org> References: <20211227190504.309612-1-trondmy@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org From: Trond Myklebust We need to be able to track more than 32 attributes per inode. Signed-off-by: Trond Myklebust Signed-off-by: Lance Shelton Signed-off-by: Trond Myklebust --- 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 \ From patchwork Mon Dec 27 19:04:58 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Trond Myklebust X-Patchwork-Id: 12700018 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3BE19C433F5 for ; Mon, 27 Dec 2021 19:11:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231307AbhL0TLf (ORCPT ); Mon, 27 Dec 2021 14:11:35 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58348 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231200AbhL0TLf (ORCPT ); Mon, 27 Dec 2021 14:11:35 -0500 Received: from sin.source.kernel.org (sin.source.kernel.org [IPv6:2604:1380:40e1:4800::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AA9DFC06173E for ; Mon, 27 Dec 2021 11:11:34 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sin.source.kernel.org (Postfix) with ESMTPS id 2AA6FCE114B for ; Mon, 27 Dec 2021 19:11:33 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 67858C36AEC; Mon, 27 Dec 2021 19:11:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1640632291; bh=O5YT/FOTCSe0an4CaWKzPFvNsly5YLxV7SWVj+pEVUM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qD0vK9Ig9kR0cCWe+/PEcqx/OOIiBHwg2xcP60jD9Teq/E66ei+oV1Jhx90NmVES2 pQV1ElK42VVRbn+v0HLDHQcfKdLmXHoJ2JQ63u1CEhWxZWzOoU0utge98TxWoI3NVf Ctp10j1DZuYWgJTBp5Pb5ehqtdPwYRTcdXq/7DE6pW+W/pmDQEdKvII1zQ9NihJuVt SNCFjdbo4vCFm3bdtHeLzCKQj2bMP+uGna5GGxqB3f+I2K1hr++sx3DWTVDrirpPBN roZcaSpkNwBN6UIz8ZZt0/8mvWOtbAT3bLcuHiJqYRf49Ao/kCsqe9fGt4kfL8JqV0 A+lVf/EOPp8pQ== From: trondmy@kernel.org To: Anna Schumaker Cc: linux-nfs@vger.kernel.org Subject: [PATCH v2 2/8] nfs: Add timecreate to nfs inode Date: Mon, 27 Dec 2021 14:04:58 -0500 Message-Id: <20211227190504.309612-3-trondmy@kernel.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211227190504.309612-2-trondmy@kernel.org> References: <20211227190504.309612-1-trondmy@kernel.org> <20211227190504.309612-2-trondmy@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org From: Anne Marie Merritt 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 Signed-off-by: Lance Shelton Signed-off-by: Trond Myklebust --- 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) /* From patchwork Mon Dec 27 19:04:59 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Trond Myklebust X-Patchwork-Id: 12700017 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5BB17C433FE for ; Mon, 27 Dec 2021 19:11:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230510AbhL0TLe (ORCPT ); Mon, 27 Dec 2021 14:11:34 -0500 Received: from ams.source.kernel.org ([145.40.68.75]:45260 "EHLO ams.source.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231200AbhL0TLe (ORCPT ); Mon, 27 Dec 2021 14:11:34 -0500 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 6BFE3B81148 for ; Mon, 27 Dec 2021 19:11:33 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id D6A72C36AED; Mon, 27 Dec 2021 19:11:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1640632292; bh=PlBAEStFqj2AjhFSgj+8SvvyMQgNls6jBnDftH2hE5s=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CisosqmWr117BAJULCJxrcfIy4EW7pEY3oieixY7eo6oRCCfNxAVEZLX5aeC6ew26 3F1yM0FcpDhwQb/X2a2PkZ+Q9QZlkvHMSm1zQ9UdHWwlbVPkHEslvtRNoT/hYYNult OnytkdXU1VCc65UnBzXJPh7VYV5r/LD5WCHDknPDd6IAbUwvXVsPYBxrMP2chc6WVT e+vDE+nUG2ZjxdfgSpbDdQpfhHbZT8XuX9Qf/NoVoSnGDPfT30qh+CGYIftlsWVf+l wRjeGiwVaf/IXmJisZBvBx9tJ3rrCOg6e49wIFDLOxh7CAquWMcNdIrW1XvK9p+nJB TJSMgtSIxWQ/g== From: trondmy@kernel.org To: Anna Schumaker Cc: linux-nfs@vger.kernel.org Subject: [PATCH v2 3/8] NFS: Return the file btime in the statx results when appropriate Date: Mon, 27 Dec 2021 14:04:59 -0500 Message-Id: <20211227190504.309612-4-trondmy@kernel.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211227190504.309612-3-trondmy@kernel.org> References: <20211227190504.309612-1-trondmy@kernel.org> <20211227190504.309612-2-trondmy@kernel.org> <20211227190504.309612-3-trondmy@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org From: Trond Myklebust If the server supports the NFSv4.x "create_time" attribute, then return it as part of the statx results. Signed-off-by: Trond Myklebust --- 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( From patchwork Mon Dec 27 19:05:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Trond Myklebust X-Patchwork-Id: 12700020 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 65A95C433EF for ; Mon, 27 Dec 2021 19:11:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231433AbhL0TLh (ORCPT ); Mon, 27 Dec 2021 14:11:37 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58350 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231200AbhL0TLf (ORCPT ); Mon, 27 Dec 2021 14:11:35 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7A39FC06173E for ; Mon, 27 Dec 2021 11:11:35 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 0A7FAB80D8E for ; Mon, 27 Dec 2021 19:11:34 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 628E0C36AEE; Mon, 27 Dec 2021 19:11:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1640632292; bh=mBY94kq1kn6ti5GvmuAWBYXtg2MZhtDx/DpPCKTfwSU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XgdFByFe277TifQttNwPQzp/djSAdaw8IM8brGzXupzQzY6IooKnptoIVppfjMGfi lHocREticArrUIrHSqh1GAxM43J4LG7LzAOkU+IljvXIVWSgWIkEtdGrBFKkReXwnt RusGJrJtQKFY/uEyDB65r6CuGZIMqqlwZGdKJNdAc2RxEQiuLBLqQJo0MqGYy21YVB yItukppbdZTnXQgkkVtmSRRDNK87ZCv35BL+idu14ZB/O0wcPEctAFlnhvfeK9lmVa ucPSyEPnhzXLgeQX6wJluGuzZaEGb/H7THGLSxQ4B/0Q6tnrb1aVCQeynE2ocAOZ9h HB1/5vmXPlolg== From: trondmy@kernel.org To: Anna Schumaker Cc: linux-nfs@vger.kernel.org Subject: [PATCH v2 4/8] nfs: Add 'archive', 'hidden' and 'system' fields to nfs inode Date: Mon, 27 Dec 2021 14:05:00 -0500 Message-Id: <20211227190504.309612-5-trondmy@kernel.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211227190504.309612-4-trondmy@kernel.org> References: <20211227190504.309612-1-trondmy@kernel.org> <20211227190504.309612-2-trondmy@kernel.org> <20211227190504.309612-3-trondmy@kernel.org> <20211227190504.309612-4-trondmy@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org From: Anne Marie Merritt 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 Signed-off-by: Lance Shelton Signed-off-by: Trond Myklebust --- 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) /* From patchwork Mon Dec 27 19:05:01 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Trond Myklebust X-Patchwork-Id: 12700021 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EA8C9C4332F for ; Mon, 27 Dec 2021 19:11:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231394AbhL0TLi (ORCPT ); Mon, 27 Dec 2021 14:11:38 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58352 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231428AbhL0TLg (ORCPT ); Mon, 27 Dec 2021 14:11:36 -0500 Received: from sin.source.kernel.org (sin.source.kernel.org [IPv6:2604:1380:40e1:4800::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 497F2C061401 for ; Mon, 27 Dec 2021 11:11:36 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sin.source.kernel.org (Postfix) with ESMTPS id BF74FCE1065 for ; Mon, 27 Dec 2021 19:11:34 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id ED1FDC36AE7; Mon, 27 Dec 2021 19:11:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1640632293; bh=sQJ8odAgCH9G88ulZCmcn2Y+uOpDQxMbfsFZ1CHWCps=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FYkowB2uTZTZJImLAEzPdY1HvWkAnP+X918/jiTuFzVuQ3c0c11GwMBux2hUQJ4zp qFAGGkDTTobp1tZkkoIwugPs0mBFuyFyXdBaYXF+liHtL33+MoWNUibXtKOXbAGHsd Bgt/F60/XWwZ1OCXhu5MZWKQbPIV/65rANPUrkLsZmt7FEYAiGuXqDHzLhlJu4o74d 7EiuDmbiQrfxhR4SCUT5fLEN2wnkj/GcChgn34h6L64JfABubcjO7HxGzDtE9sbxXA pT6wseYHcpNWxJ9/CA49fmZSBEJkSDQaShDeS/F2PpNeaCbAsUNg1dZsNqtz+4bGtN rf5Sta6kJvQSA== From: trondmy@kernel.org To: Anna Schumaker Cc: linux-nfs@vger.kernel.org Subject: [PATCH v2 5/8] nfs: Add 'time backup' to nfs inode Date: Mon, 27 Dec 2021 14:05:01 -0500 Message-Id: <20211227190504.309612-6-trondmy@kernel.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211227190504.309612-5-trondmy@kernel.org> References: <20211227190504.309612-1-trondmy@kernel.org> <20211227190504.309612-2-trondmy@kernel.org> <20211227190504.309612-3-trondmy@kernel.org> <20211227190504.309612-4-trondmy@kernel.org> <20211227190504.309612-5-trondmy@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org From: Anne Marie Merritt Add tracking of the NFSv4 'time backup' attribute, along with corresponding bitfields, request, and decode xdr routines. Signed-off-by: Anne Marie Merritt Signed-off-by: Lance Shelton Signed-off-by: Trond Myklebust --- 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) /* From patchwork Mon Dec 27 19:05:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Trond Myklebust X-Patchwork-Id: 12700019 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 942B5C433FE for ; Mon, 27 Dec 2021 19:11:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231200AbhL0TLi (ORCPT ); Mon, 27 Dec 2021 14:11:38 -0500 Received: from ams.source.kernel.org ([145.40.68.75]:45280 "EHLO ams.source.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231394AbhL0TLg (ORCPT ); Mon, 27 Dec 2021 14:11:36 -0500 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 00746B81144 for ; Mon, 27 Dec 2021 19:11:35 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7EEA7C36AEA; Mon, 27 Dec 2021 19:11:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1640632293; bh=MjUByfu3U69mq7jbVbeQ255Ffo1A+X4mvQj8BtMkhg4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bGGoyOMjDAfPZnVYKWCs0td6W2o8rXMPrSE8gPVo9TgLZ/ioFNNX0eW6dq+0lGyOS Snrc10jOnEaGVn2idlx1UdT/KwQu7DY7YwOMFAAjLWsau3TcusjM46NvyTRhJ7l92q VnWpmGrgS5DPuGAoTH6NYFOkZENqWz7rn8EppGpJvfd92LoSYb9gS9eLmk9txKwO0e RQ2n4QNdsp3tlPiqdwpjMHrs6G+rP1K8zn+BqS8nhw9Ds9XjCmooW+qZtx69VDo8am JLtjXzRbR6HCqFbdqbXBdIa5Pesqh4MqHVFmRN7bGbKIbw/6t7pXMqBs0RO9+DD06O /9KadJTwlmB2A== From: trondmy@kernel.org To: Anna Schumaker Cc: linux-nfs@vger.kernel.org Subject: [PATCH v2 6/8] NFSv4: Support the offline bit Date: Mon, 27 Dec 2021 14:05:02 -0500 Message-Id: <20211227190504.309612-7-trondmy@kernel.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211227190504.309612-6-trondmy@kernel.org> References: <20211227190504.309612-1-trondmy@kernel.org> <20211227190504.309612-2-trondmy@kernel.org> <20211227190504.309612-3-trondmy@kernel.org> <20211227190504.309612-4-trondmy@kernel.org> <20211227190504.309612-5-trondmy@kernel.org> <20211227190504.309612-6-trondmy@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org From: Trond Myklebust Add tracking of the NFSv4 'offline' attribute. Signed-off-by: Trond Myklebust Signed-off-by: Lance Shelton Signed-off-by: Trond Myklebust --- 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. From patchwork Mon Dec 27 19:05:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Trond Myklebust X-Patchwork-Id: 12700023 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8F7FBC433F5 for ; Mon, 27 Dec 2021 19:11:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231463AbhL0TLi (ORCPT ); Mon, 27 Dec 2021 14:11:38 -0500 Received: from ams.source.kernel.org ([145.40.68.75]:45276 "EHLO ams.source.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231358AbhL0TLg (ORCPT ); Mon, 27 Dec 2021 14:11:36 -0500 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id B33B7B81148 for ; Mon, 27 Dec 2021 19:11:34 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 15868C36AEC; Mon, 27 Dec 2021 19:11:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1640632294; bh=/bCzGcoRaTtjdBK5oZaxmBRvH6J4+pqPfY9R+5C8kHY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=W8Is4LL0r3rPBVhyAUrPm1eXAakoBpL1uAtDUeJ6V7GtAGONnBX56yGjCMj83IuPW f9vNcqnac61fFKVnF/tMV76CVdbSY1U69Rmwoms7FQXpuJk5x49m/CaaaZNw7qyohd Yg7Dsdcc0cajiEwCR8N1ycl6lUWWKOGgXcLOHIG8ge7BXonskf4kG19GN0CLOlnSZr 3vIJ5k37LhDogncKGkGWM0yPf/elRWDjChi8Aac4auios/MuB7Tl6nQGNBb9SRKx8a 4A0h+OPdvo8GxuoYhBUxeHb2JqNHdNzMToCiRwc7fRukkGe2K6v0II9DUBN/uzKlQb BqHRK6pHrsdLw== From: trondmy@kernel.org To: Anna Schumaker Cc: linux-nfs@vger.kernel.org Subject: [PATCH v2 7/8] NFS: Support statx_get and statx_set ioctls Date: Mon, 27 Dec 2021 14:05:03 -0500 Message-Id: <20211227190504.309612-8-trondmy@kernel.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211227190504.309612-7-trondmy@kernel.org> References: <20211227190504.309612-1-trondmy@kernel.org> <20211227190504.309612-2-trondmy@kernel.org> <20211227190504.309612-3-trondmy@kernel.org> <20211227190504.309612-4-trondmy@kernel.org> <20211227190504.309612-5-trondmy@kernel.org> <20211227190504.309612-6-trondmy@kernel.org> <20211227190504.309612-7-trondmy@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org From: Richard Sharpe 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 Signed-off-by: Lance Shelton Signed-off-by: Trond Myklebust --- 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 #include #include +#include +#include #include #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 +#include +#include #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 From patchwork Mon Dec 27 19:05:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Trond Myklebust X-Patchwork-Id: 12700022 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AA6FBC43219 for ; Mon, 27 Dec 2021 19:11:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231358AbhL0TLj (ORCPT ); Mon, 27 Dec 2021 14:11:39 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58364 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231442AbhL0TLi (ORCPT ); Mon, 27 Dec 2021 14:11:38 -0500 Received: from sin.source.kernel.org (sin.source.kernel.org [IPv6:2604:1380:40e1:4800::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ED893C061401 for ; Mon, 27 Dec 2021 11:11:37 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sin.source.kernel.org (Postfix) with ESMTPS id 6846BCE1087 for ; Mon, 27 Dec 2021 19:11:36 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id A3A35C36AEB; Mon, 27 Dec 2021 19:11:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1640632294; bh=riGLkxdzmqOCC7x/23VqVAqyxw2YxqSLpFjUliqJAW8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ONjnvkqZIvLOb8cINTwztG+lcxeXyHtxjTf7Qdn/lEjUJ55PmbvYMxUR6xL+Q0tXn ls1Q6QyG6iy1zKXRErPMjUvmXoRz7t346EQWooNtC09gmwJBSHcv5iFF38V9J6Ybpd loz2rXQfBsZmw3OoQievamSpyJlhsxfjikeBdWs9rWb5h6882cMAeevYbma2n2lBuZ A7+K4LqJLx9K6Y+EK7yKjrXl1N3aPSPtD/rnjrK2X9bSzxaaadhluOQ3kVYiHxdOF6 1GdIPCFhuZxGvxwRg6BwVsfrZ/FN07eMb7DuZSB2t8CuI4kdWHPp7vanyKc2+ZV6+F 3lsdimFgbqQ1A== From: trondmy@kernel.org To: Anna Schumaker Cc: linux-nfs@vger.kernel.org Subject: [PATCH v2 8/8] NFSv4: Add an ioctl to allow retrieval of the NFS raw ACCESS mask Date: Mon, 27 Dec 2021 14:05:04 -0500 Message-Id: <20211227190504.309612-9-trondmy@kernel.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211227190504.309612-8-trondmy@kernel.org> References: <20211227190504.309612-1-trondmy@kernel.org> <20211227190504.309612-2-trondmy@kernel.org> <20211227190504.309612-3-trondmy@kernel.org> <20211227190504.309612-4-trondmy@kernel.org> <20211227190504.309612-5-trondmy@kernel.org> <20211227190504.309612-6-trondmy@kernel.org> <20211227190504.309612-7-trondmy@kernel.org> <20211227190504.309612-8-trondmy@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org From: Trond Myklebust Signed-off-by: Trond Myklebust --- 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