NFSv4: Add CB_GETATTR support for delegated attributes

When the client holds an attribute delegation, the server may retrieve
all the timestamps through a CB_GETATTR callback.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Lance Shelton <lance.shelton@hammerspace.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
This commit is contained in:
Trond Myklebust 2024-06-16 21:21:23 -04:00 committed by Anna Schumaker
parent 90f9ae7442
commit 43df7110f4
3 changed files with 49 additions and 9 deletions

View File

@ -46,14 +46,15 @@ struct cb_compound_hdr_res {
struct cb_getattrargs { struct cb_getattrargs {
struct nfs_fh fh; struct nfs_fh fh;
uint32_t bitmap[2]; uint32_t bitmap[3];
}; };
struct cb_getattrres { struct cb_getattrres {
__be32 status; __be32 status;
uint32_t bitmap[2]; uint32_t bitmap[3];
uint64_t size; uint64_t size;
uint64_t change_attr; uint64_t change_attr;
struct timespec64 atime;
struct timespec64 ctime; struct timespec64 ctime;
struct timespec64 mtime; struct timespec64 mtime;
}; };

View File

@ -37,7 +37,7 @@ __be32 nfs4_callback_getattr(void *argp, void *resp,
if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */ if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */
goto out; goto out;
res->bitmap[0] = res->bitmap[1] = 0; memset(res->bitmap, 0, sizeof(res->bitmap));
res->status = htonl(NFS4ERR_BADHANDLE); res->status = htonl(NFS4ERR_BADHANDLE);
dprintk_rcu("NFS: GETATTR callback request from %s\n", dprintk_rcu("NFS: GETATTR callback request from %s\n",
@ -59,12 +59,16 @@ __be32 nfs4_callback_getattr(void *argp, void *resp,
res->change_attr = delegation->change_attr; res->change_attr = delegation->change_attr;
if (nfs_have_writebacks(inode)) if (nfs_have_writebacks(inode))
res->change_attr++; res->change_attr++;
res->atime = inode_get_atime(inode);
res->ctime = inode_get_ctime(inode); res->ctime = inode_get_ctime(inode);
res->mtime = inode_get_mtime(inode); res->mtime = inode_get_mtime(inode);
res->bitmap[0] = (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE) & res->bitmap[0] = (FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE) &
args->bitmap[0]; args->bitmap[0];
res->bitmap[1] = (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY) & res->bitmap[1] = (FATTR4_WORD1_TIME_ACCESS |
args->bitmap[1]; FATTR4_WORD1_TIME_METADATA |
FATTR4_WORD1_TIME_MODIFY) & args->bitmap[1];
res->bitmap[2] = (FATTR4_WORD2_TIME_DELEG_ACCESS |
FATTR4_WORD2_TIME_DELEG_MODIFY) & args->bitmap[2];
res->status = 0; res->status = 0;
out_iput: out_iput:
rcu_read_unlock(); rcu_read_unlock();

View File

@ -25,8 +25,9 @@
#define CB_OP_GETATTR_BITMAP_MAXSZ (4 * 4) // bitmap length, 3 bitmaps #define CB_OP_GETATTR_BITMAP_MAXSZ (4 * 4) // bitmap length, 3 bitmaps
#define CB_OP_GETATTR_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ #define CB_OP_GETATTR_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \
CB_OP_GETATTR_BITMAP_MAXSZ + \ CB_OP_GETATTR_BITMAP_MAXSZ + \
/* change, size, ctime, mtime */\ /* change, size, atime, ctime,
(2 + 2 + 3 + 3) * 4) * mtime, deleg_atime, deleg_mtime */\
(2 + 2 + 3 + 3 + 3 + 3 + 3) * 4)
#define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) #define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
#if defined(CONFIG_NFS_V4_1) #if defined(CONFIG_NFS_V4_1)
@ -635,6 +636,13 @@ static __be32 encode_attr_time(struct xdr_stream *xdr, const struct timespec64 *
return 0; return 0;
} }
static __be32 encode_attr_atime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec64 *time)
{
if (!(bitmap[1] & FATTR4_WORD1_TIME_ACCESS))
return 0;
return encode_attr_time(xdr,time);
}
static __be32 encode_attr_ctime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec64 *time) static __be32 encode_attr_ctime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec64 *time)
{ {
if (!(bitmap[1] & FATTR4_WORD1_TIME_METADATA)) if (!(bitmap[1] & FATTR4_WORD1_TIME_METADATA))
@ -649,6 +657,24 @@ static __be32 encode_attr_mtime(struct xdr_stream *xdr, const uint32_t *bitmap,
return encode_attr_time(xdr,time); return encode_attr_time(xdr,time);
} }
static __be32 encode_attr_delegatime(struct xdr_stream *xdr,
const uint32_t *bitmap,
const struct timespec64 *time)
{
if (!(bitmap[2] & FATTR4_WORD2_TIME_DELEG_ACCESS))
return 0;
return encode_attr_time(xdr,time);
}
static __be32 encode_attr_delegmtime(struct xdr_stream *xdr,
const uint32_t *bitmap,
const struct timespec64 *time)
{
if (!(bitmap[2] & FATTR4_WORD2_TIME_DELEG_MODIFY))
return 0;
return encode_attr_time(xdr,time);
}
static __be32 encode_compound_hdr_res(struct xdr_stream *xdr, struct cb_compound_hdr_res *hdr) static __be32 encode_compound_hdr_res(struct xdr_stream *xdr, struct cb_compound_hdr_res *hdr)
{ {
__be32 status; __be32 status;
@ -697,12 +723,21 @@ static __be32 encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr,
if (unlikely(status != 0)) if (unlikely(status != 0))
goto out; goto out;
status = encode_attr_size(xdr, res->bitmap, res->size); status = encode_attr_size(xdr, res->bitmap, res->size);
if (unlikely(status != 0))
goto out;
status = encode_attr_atime(xdr, res->bitmap, &res->atime);
if (unlikely(status != 0)) if (unlikely(status != 0))
goto out; goto out;
status = encode_attr_ctime(xdr, res->bitmap, &res->ctime); status = encode_attr_ctime(xdr, res->bitmap, &res->ctime);
if (unlikely(status != 0)) if (unlikely(status != 0))
goto out; goto out;
status = encode_attr_mtime(xdr, res->bitmap, &res->mtime); status = encode_attr_mtime(xdr, res->bitmap, &res->mtime);
if (unlikely(status != 0))
goto out;
status = encode_attr_delegatime(xdr, res->bitmap, &res->atime);
if (unlikely(status != 0))
goto out;
status = encode_attr_delegmtime(xdr, res->bitmap, &res->mtime);
*savep = htonl((unsigned int)((char *)xdr->p - (char *)(savep+1))); *savep = htonl((unsigned int)((char *)xdr->p - (char *)(savep+1)));
out: out:
return status; return status;