From 15d1975b7279693d6f09398e0e2e31aca2310275 Mon Sep 17 00:00:00 2001 From: Dai Ngo Date: Wed, 30 Aug 2023 16:46:58 -0700 Subject: NFSD: initialize copy->cp_clp early in nfsd4_copy for use by trace point Prepare for adding server copy trace points. Signed-off-by: Dai Ngo Tested-by: Chen Hanxiao Signed-off-by: Chuck Lever --- fs/nfsd/nfs4proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 4199ede0583c..c27f2fdcea32 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1798,6 +1798,7 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, __be32 status; struct nfsd4_copy *async_copy = NULL; + copy->cp_clp = cstate->clp; if (nfsd4_ssc_is_inter(copy)) { if (!inter_copy_offload_enable || nfsd4_copy_is_sync(copy)) { status = nfserr_notsupp; @@ -1812,7 +1813,6 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, return status; } - copy->cp_clp = cstate->clp; memcpy(©->fh, &cstate->current_fh.fh_handle, sizeof(struct knfsd_fh)); if (nfsd4_copy_is_async(copy)) { -- cgit v1.2.3 From 5896a8705461052bfc2dcd7cf5909eaf3cecaa92 Mon Sep 17 00:00:00 2001 From: Dai Ngo Date: Thu, 31 Aug 2023 12:35:47 -0700 Subject: NFSD: add trace points to track server copy progress Add trace points on destination server to track inter and intra server copy operations. Signed-off-by: Dai Ngo Tested-by: Chen Hanxiao Signed-off-by: Chuck Lever --- fs/nfsd/nfs4proc.c | 12 ++++++-- fs/nfsd/trace.h | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index c27f2fdcea32..580c5f592408 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1760,6 +1760,7 @@ static int nfsd4_do_async_copy(void *data) struct nfsd4_copy *copy = (struct nfsd4_copy *)data; __be32 nfserr; + trace_nfsd_copy_do_async(copy); if (nfsd4_ssc_is_inter(copy)) { struct file *filp; @@ -1800,17 +1801,23 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, copy->cp_clp = cstate->clp; if (nfsd4_ssc_is_inter(copy)) { + trace_nfsd_copy_inter(copy); if (!inter_copy_offload_enable || nfsd4_copy_is_sync(copy)) { status = nfserr_notsupp; goto out; } status = nfsd4_setup_inter_ssc(rqstp, cstate, copy); - if (status) + if (status) { + trace_nfsd_copy_done(copy, status); return nfserr_offload_denied; + } } else { + trace_nfsd_copy_intra(copy); status = nfsd4_setup_intra_ssc(rqstp, cstate, copy); - if (status) + if (status) { + trace_nfsd_copy_done(copy, status); return status; + } } memcpy(©->fh, &cstate->current_fh.fh_handle, @@ -1847,6 +1854,7 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, copy->nf_dst->nf_file, true); } out: + trace_nfsd_copy_done(copy, status); release_copy_files(copy); return status; out_err: diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 803904348871..fbc0ccb40424 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -1863,6 +1863,93 @@ TRACE_EVENT(nfsd_end_grace, ) ); +DECLARE_EVENT_CLASS(nfsd_copy_class, + TP_PROTO( + const struct nfsd4_copy *copy + ), + TP_ARGS(copy), + TP_STRUCT__entry( + __field(bool, intra) + __field(bool, async) + __field(u32, src_cl_boot) + __field(u32, src_cl_id) + __field(u32, src_so_id) + __field(u32, src_si_generation) + __field(u32, dst_cl_boot) + __field(u32, dst_cl_id) + __field(u32, dst_so_id) + __field(u32, dst_si_generation) + __field(u64, src_cp_pos) + __field(u64, dst_cp_pos) + __field(u64, cp_count) + __sockaddr(addr, sizeof(struct sockaddr_in6)) + ), + TP_fast_assign( + const stateid_t *src_stp = ©->cp_src_stateid; + const stateid_t *dst_stp = ©->cp_dst_stateid; + + __entry->intra = test_bit(NFSD4_COPY_F_INTRA, ©->cp_flags); + __entry->async = !test_bit(NFSD4_COPY_F_SYNCHRONOUS, ©->cp_flags); + __entry->src_cl_boot = src_stp->si_opaque.so_clid.cl_boot; + __entry->src_cl_id = src_stp->si_opaque.so_clid.cl_id; + __entry->src_so_id = src_stp->si_opaque.so_id; + __entry->src_si_generation = src_stp->si_generation; + __entry->dst_cl_boot = dst_stp->si_opaque.so_clid.cl_boot; + __entry->dst_cl_id = dst_stp->si_opaque.so_clid.cl_id; + __entry->dst_so_id = dst_stp->si_opaque.so_id; + __entry->dst_si_generation = dst_stp->si_generation; + __entry->src_cp_pos = copy->cp_src_pos; + __entry->dst_cp_pos = copy->cp_dst_pos; + __entry->cp_count = copy->cp_count; + __assign_sockaddr(addr, ©->cp_clp->cl_addr, + sizeof(struct sockaddr_in6)); + ), + TP_printk("client=%pISpc intra=%d async=%d " + "src_stateid[si_generation:0x%x cl_boot:0x%x cl_id:0x%x so_id:0x%x] " + "dst_stateid[si_generation:0x%x cl_boot:0x%x cl_id:0x%x so_id:0x%x] " + "cp_src_pos=%llu cp_dst_pos=%llu cp_count=%llu", + __get_sockaddr(addr), __entry->intra, __entry->async, + __entry->src_si_generation, __entry->src_cl_boot, + __entry->src_cl_id, __entry->src_so_id, + __entry->dst_si_generation, __entry->dst_cl_boot, + __entry->dst_cl_id, __entry->dst_so_id, + __entry->src_cp_pos, __entry->dst_cp_pos, __entry->cp_count + ) +); + +#define DEFINE_COPY_EVENT(name) \ +DEFINE_EVENT(nfsd_copy_class, nfsd_copy_##name, \ + TP_PROTO(const struct nfsd4_copy *copy), \ + TP_ARGS(copy)) + +DEFINE_COPY_EVENT(inter); +DEFINE_COPY_EVENT(intra); +DEFINE_COPY_EVENT(do_async); + +TRACE_EVENT(nfsd_copy_done, + TP_PROTO( + const struct nfsd4_copy *copy, + __be32 status + ), + TP_ARGS(copy, status), + TP_STRUCT__entry( + __field(int, status) + __field(bool, intra) + __field(bool, async) + __sockaddr(addr, sizeof(struct sockaddr_in6)) + ), + TP_fast_assign( + __entry->status = be32_to_cpu(status); + __entry->intra = test_bit(NFSD4_COPY_F_INTRA, ©->cp_flags); + __entry->async = !test_bit(NFSD4_COPY_F_SYNCHRONOUS, ©->cp_flags); + __assign_sockaddr(addr, ©->cp_clp->cl_addr, + sizeof(struct sockaddr_in6)); + ), + TP_printk("addr=%pISpc status=%d intra=%d async=%d ", + __get_sockaddr(addr), __entry->status, __entry->intra, __entry->async + ) +); + #endif /* _NFSD_TRACE_H */ #undef TRACE_INCLUDE_PATH -- cgit v1.2.3 From d59b3515ab021e010fdc58a8f445ea62dd2f7f4c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 11 Sep 2023 14:30:27 -0400 Subject: nfsd: Handle EOPENSTALE correctly in the filecache The nfsd_open code handles EOPENSTALE correctly, by retrying the call to fh_verify() and __nfsd_open(). However the filecache just drops the error on the floor, and immediately returns nfserr_stale to the caller. This patch ensures that we propagate the EOPENSTALE code back to nfsd_file_do_acquire, and that we handle it correctly. Fixes: 65294c1f2c5e ("nfsd: add a new struct file caching facility to nfsd") Signed-off-by: Trond Myklebust Reviewed-by: Jeff Layton Message-Id: <20230911183027.11372-1-trond.myklebust@hammerspace.com> Signed-off-by: Chuck Lever --- fs/nfsd/filecache.c | 27 +++++++++++++++++++-------- fs/nfsd/vfs.c | 28 +++++++++++++--------------- fs/nfsd/vfs.h | 4 ++-- 3 files changed, 34 insertions(+), 25 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c index ee9c923192e0..07bf219f9ae4 100644 --- a/fs/nfsd/filecache.c +++ b/fs/nfsd/filecache.c @@ -989,22 +989,21 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, unsigned char need = may_flags & NFSD_FILE_MAY_MASK; struct net *net = SVC_NET(rqstp); struct nfsd_file *new, *nf; - const struct cred *cred; + bool stale_retry = true; bool open_retry = true; struct inode *inode; __be32 status; int ret; +retry: status = fh_verify(rqstp, fhp, S_IFREG, may_flags|NFSD_MAY_OWNER_OVERRIDE); if (status != nfs_ok) return status; inode = d_inode(fhp->fh_dentry); - cred = get_current_cred(); -retry: rcu_read_lock(); - nf = nfsd_file_lookup_locked(net, cred, inode, need, want_gc); + nf = nfsd_file_lookup_locked(net, current_cred(), inode, need, want_gc); rcu_read_unlock(); if (nf) { @@ -1026,7 +1025,7 @@ retry: rcu_read_lock(); spin_lock(&inode->i_lock); - nf = nfsd_file_lookup_locked(net, cred, inode, need, want_gc); + nf = nfsd_file_lookup_locked(net, current_cred(), inode, need, want_gc); if (unlikely(nf)) { spin_unlock(&inode->i_lock); rcu_read_unlock(); @@ -1058,6 +1057,7 @@ wait_for_construction: goto construction_err; } open_retry = false; + fh_put(fhp); goto retry; } this_cpu_inc(nfsd_file_cache_hits); @@ -1074,7 +1074,6 @@ out: nfsd_file_check_write_error(nf); *pnf = nf; } - put_cred(cred); trace_nfsd_file_acquire(rqstp, inode, may_flags, nf, status); return status; @@ -1088,8 +1087,20 @@ open_file: status = nfs_ok; trace_nfsd_file_opened(nf, status); } else { - status = nfsd_open_verified(rqstp, fhp, may_flags, - &nf->nf_file); + ret = nfsd_open_verified(rqstp, fhp, may_flags, + &nf->nf_file); + if (ret == -EOPENSTALE && stale_retry) { + stale_retry = false; + nfsd_file_unhash(nf); + clear_and_wake_up_bit(NFSD_FILE_PENDING, + &nf->nf_flags); + if (refcount_dec_and_test(&nf->nf_ref)) + nfsd_file_free(nf); + nf = NULL; + fh_put(fhp); + goto retry; + } + status = nfserrno(ret); trace_nfsd_file_open(nf, status); } } else diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 48260cf68fde..3e9a84392092 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -823,7 +823,7 @@ int nfsd_open_break_lease(struct inode *inode, int access) * and additional flags. * N.B. After this call fhp needs an fh_put */ -static __be32 +static int __nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int may_flags, struct file **filp) { @@ -831,14 +831,12 @@ __nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, struct inode *inode; struct file *file; int flags = O_RDONLY|O_LARGEFILE; - __be32 err; - int host_err = 0; + int host_err = -EPERM; path.mnt = fhp->fh_export->ex_path.mnt; path.dentry = fhp->fh_dentry; inode = d_inode(path.dentry); - err = nfserr_perm; if (IS_APPEND(inode) && (may_flags & NFSD_MAY_WRITE)) goto out; @@ -847,7 +845,7 @@ __nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, host_err = nfsd_open_break_lease(inode, may_flags); if (host_err) /* NOMEM or WOULDBLOCK */ - goto out_nfserr; + goto out; if (may_flags & NFSD_MAY_WRITE) { if (may_flags & NFSD_MAY_READ) @@ -859,13 +857,13 @@ __nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, file = dentry_open(&path, flags, current_cred()); if (IS_ERR(file)) { host_err = PTR_ERR(file); - goto out_nfserr; + goto out; } host_err = ima_file_check(file, may_flags); if (host_err) { fput(file); - goto out_nfserr; + goto out; } if (may_flags & NFSD_MAY_64BIT_COOKIE) @@ -874,10 +872,8 @@ __nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, file->f_mode |= FMODE_32BITHASH; *filp = file; -out_nfserr: - err = nfserrno(host_err); out: - return err; + return host_err; } __be32 @@ -885,6 +881,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int may_flags, struct file **filp) { __be32 err; + int host_err; bool retried = false; validate_process_creds(); @@ -904,12 +901,13 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, retry: err = fh_verify(rqstp, fhp, type, may_flags); if (!err) { - err = __nfsd_open(rqstp, fhp, type, may_flags, filp); - if (err == nfserr_stale && !retried) { + host_err = __nfsd_open(rqstp, fhp, type, may_flags, filp); + if (host_err == -EOPENSTALE && !retried) { retried = true; fh_put(fhp); goto retry; } + err = nfserrno(host_err); } validate_process_creds(); return err; @@ -922,13 +920,13 @@ retry: * @may_flags: internal permission flags * @filp: OUT: open "struct file *" * - * Returns an nfsstat value in network byte order. + * Returns zero on success, or a negative errno value. */ -__be32 +int nfsd_open_verified(struct svc_rqst *rqstp, struct svc_fh *fhp, int may_flags, struct file **filp) { - __be32 err; + int err; validate_process_creds(); err = __nfsd_open(rqstp, fhp, S_IFREG, may_flags, filp); diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index a6890ea7b765..e3c29596f4df 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h @@ -104,8 +104,8 @@ __be32 nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, int nfsd_open_break_lease(struct inode *, int); __be32 nfsd_open(struct svc_rqst *, struct svc_fh *, umode_t, int, struct file **); -__be32 nfsd_open_verified(struct svc_rqst *, struct svc_fh *, - int, struct file **); +int nfsd_open_verified(struct svc_rqst *rqstp, struct svc_fh *fhp, + int may_flags, struct file **filp); __be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, loff_t offset, unsigned long *count, -- cgit v1.2.3 From 1b2021bdeeca12364ad0fa7aac9ddba5cae964f3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 11 Sep 2023 14:43:57 -0400 Subject: nfsd: Don't reset the write verifier on a commit EAGAIN If fsync() is returning EAGAIN, then we can assume that the filesystem being exported is something like NFS with the 'softerr' mount option enabled, and that it is just asking us to replay the fsync() operation at a later date. If we see an ESTALE, then ditto: the file is gone, so there is no danger of losing the error. For those cases, do not reset the write verifier. A write verifier change has a global effect, causing retransmission by all clients of all uncommitted unstable writes for all files, so it is worth mitigating where possible. Link: https://lore.kernel.org/linux-nfs/20230911184357.11739-1-trond.myklebust@hammerspace.com/ Signed-off-by: Trond Myklebust Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/vfs.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 3e9a84392092..5bf3cffde831 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -337,6 +337,24 @@ out: return err; } +static void +commit_reset_write_verifier(struct nfsd_net *nn, struct svc_rqst *rqstp, + int err) +{ + switch (err) { + case -EAGAIN: + case -ESTALE: + /* + * Neither of these are the result of a problem with + * durable storage, so avoid a write verifier reset. + */ + break; + default: + nfsd_reset_write_verifier(nn); + trace_nfsd_writeverf_reset(nn, rqstp, err); + } +} + /* * Commit metadata changes to stable storage. */ @@ -647,8 +665,7 @@ __be32 nfsd4_clone_file_range(struct svc_rqst *rqstp, &nfsd4_get_cstate(rqstp)->current_fh, dst_pos, count, status); - nfsd_reset_write_verifier(nn); - trace_nfsd_writeverf_reset(nn, rqstp, status); + commit_reset_write_verifier(nn, rqstp, status); ret = nfserrno(status); } } @@ -1170,8 +1187,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, host_err = vfs_iter_write(file, &iter, &pos, flags); file_end_write(file); if (host_err < 0) { - nfsd_reset_write_verifier(nn); - trace_nfsd_writeverf_reset(nn, rqstp, host_err); + commit_reset_write_verifier(nn, rqstp, host_err); goto out_nfserr; } *cnt = host_err; @@ -1183,10 +1199,8 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, if (stable && use_wgather) { host_err = wait_for_concurrent_writes(file); - if (host_err < 0) { - nfsd_reset_write_verifier(nn); - trace_nfsd_writeverf_reset(nn, rqstp, host_err); - } + if (host_err < 0) + commit_reset_write_verifier(nn, rqstp, host_err); } out_nfserr: @@ -1329,8 +1343,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, err = nfserr_notsupp; break; default: - nfsd_reset_write_verifier(nn); - trace_nfsd_writeverf_reset(nn, rqstp, err2); + commit_reset_write_verifier(nn, rqstp, err2); err = nfserrno(err2); } } else -- cgit v1.2.3 From 2dd10de8e6bcbacf85ad758b904543c294820c63 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 12 Sep 2023 17:53:18 -0400 Subject: lockd: introduce safe async lock op This patch reverts mostly commit 40595cdc93ed ("nfs: block notification on fs with its own ->lock") and introduces an EXPORT_OP_ASYNC_LOCK export flag to signal that the "own ->lock" implementation supports async lock requests. The only main user is DLM that is used by GFS2 and OCFS2 filesystem. Those implement their own lock() implementation and return FILE_LOCK_DEFERRED as return value. Since commit 40595cdc93ed ("nfs: block notification on fs with its own ->lock") the DLM implementation were never updated. This patch should prepare for DLM to set the EXPORT_OP_ASYNC_LOCK export flag and update the DLM plock implementation regarding to it. Acked-by: Jeff Layton Signed-off-by: Alexander Aring Signed-off-by: Chuck Lever --- Documentation/filesystems/nfs/exporting.rst | 7 +++++++ fs/lockd/svclock.c | 4 +--- fs/nfsd/nfs4state.c | 10 +++++++--- include/linux/exportfs.h | 14 ++++++++++++++ 4 files changed, 29 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/Documentation/filesystems/nfs/exporting.rst b/Documentation/filesystems/nfs/exporting.rst index 4b30daee399a..198d805d611c 100644 --- a/Documentation/filesystems/nfs/exporting.rst +++ b/Documentation/filesystems/nfs/exporting.rst @@ -241,3 +241,10 @@ following flags are defined: all of an inode's dirty data on last close. Exports that behave this way should set EXPORT_OP_FLUSH_ON_CLOSE so that NFSD knows to skip waiting for writeback when closing such files. + + EXPORT_OP_ASYNC_LOCK - Indicates a capable filesystem to do async lock + requests from lockd. Only set EXPORT_OP_ASYNC_LOCK if the filesystem has + it's own ->lock() functionality as core posix_lock_file() implementation + has no async lock request handling yet. For more information about how to + indicate an async lock request from a ->lock() file_operations struct, see + fs/locks.c and comment for the function vfs_lock_file(). diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 43aeba9de55c..d500e32ebb18 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -481,9 +481,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, struct nlm_host *host, struct nlm_lock *lock, int wait, struct nlm_cookie *cookie, int reclaim) { -#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) struct inode *inode = nlmsvc_file_inode(file); -#endif struct nlm_block *block = NULL; int error; int mode; @@ -497,7 +495,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, (long long)lock->fl.fl_end, wait); - if (nlmsvc_file_file(file)->f_op->lock) { + if (!exportfs_lock_op_is_async(inode->i_sb->s_export_op)) { async_block = wait; wait = 0; } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 8534693eb6a4..7cabe882724e 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -7487,6 +7487,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_blocked_lock *nbl = NULL; struct file_lock *file_lock = NULL; struct file_lock *conflock = NULL; + struct super_block *sb; __be32 status = 0; int lkflg; int err; @@ -7508,6 +7509,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, dprintk("NFSD: nfsd4_lock: permission denied!\n"); return status; } + sb = cstate->current_fh.fh_dentry->d_sb; if (lock->lk_is_new) { if (nfsd4_has_session(cstate)) @@ -7559,7 +7561,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, fp = lock_stp->st_stid.sc_file; switch (lock->lk_type) { case NFS4_READW_LT: - if (nfsd4_has_session(cstate)) + if (nfsd4_has_session(cstate) || + exportfs_lock_op_is_async(sb->s_export_op)) fl_flags |= FL_SLEEP; fallthrough; case NFS4_READ_LT: @@ -7571,7 +7574,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, fl_type = F_RDLCK; break; case NFS4_WRITEW_LT: - if (nfsd4_has_session(cstate)) + if (nfsd4_has_session(cstate) || + exportfs_lock_op_is_async(sb->s_export_op)) fl_flags |= FL_SLEEP; fallthrough; case NFS4_WRITE_LT: @@ -7599,7 +7603,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, * for file locks), so don't attempt blocking lock notifications * on those filesystems: */ - if (nf->nf_file->f_op->lock) + if (!exportfs_lock_op_is_async(sb->s_export_op)) fl_flags &= ~FL_SLEEP; nbl = find_or_allocate_block(lock_sop, &fp->fi_fhandle, nn); diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h index 11fbd0ee1370..6dd993240fcc 100644 --- a/include/linux/exportfs.h +++ b/include/linux/exportfs.h @@ -224,9 +224,23 @@ struct export_operations { atomic attribute updates */ #define EXPORT_OP_FLUSH_ON_CLOSE (0x20) /* fs flushes file data on close */ +#define EXPORT_OP_ASYNC_LOCK (0x40) /* fs can do async lock request */ unsigned long flags; }; +/** + * exportfs_lock_op_is_async() - export op supports async lock operation + * @export_ops: the nfs export operations to check + * + * Returns true if the nfs export_operations structure has + * EXPORT_OP_ASYNC_LOCK in their flags set + */ +static inline bool +exportfs_lock_op_is_async(const struct export_operations *export_ops) +{ + return export_ops->flags & EXPORT_OP_ASYNC_LOCK; +} + extern int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid, int *max_len, struct inode *parent, int flags); -- cgit v1.2.3 From b743612c0aaa49a781f1f0c760e35d7298b5c5b4 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 12 Sep 2023 17:53:19 -0400 Subject: lockd: don't call vfs_lock_file() for pending requests This patch returns nlm_lck_blocked in nlmsvc_lock() when an asynchronous lock request is pending. During testing I ran into the case with the side-effects that lockd is waiting for only one lm_grant() callback because it's already part of the nlm_blocked list. If another asynchronous for the same nlm_block is triggered two lm_grant() callbacks will occur but lockd was only waiting for one. To avoid any change of existing users this handling will only being made when export_op_support_safe_async_lock() returns true. Reviewed-by: Jeff Layton Signed-off-by: Alexander Aring Signed-off-by: Chuck Lever --- fs/lockd/svclock.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index d500e32ebb18..c313622a9578 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -541,6 +541,22 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, goto out; } + spin_lock(&nlm_blocked_lock); + /* + * If this is a lock request for an already pending + * lock request we return nlm_lck_blocked without calling + * vfs_lock_file() again. Otherwise we have two pending + * requests on the underlaying ->lock() implementation but + * only one nlm_block to being granted by lm_grant(). + */ + if (exportfs_lock_op_is_async(inode->i_sb->s_export_op) && + !list_empty(&block->b_list)) { + spin_unlock(&nlm_blocked_lock); + ret = nlm_lck_blocked; + goto out; + } + spin_unlock(&nlm_blocked_lock); + if (!wait) lock->fl.fl_flags &= ~FL_SLEEP; mode = lock_to_openmode(&lock->fl); @@ -553,13 +569,6 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, ret = nlm_granted; goto out; case -EAGAIN: - /* - * If this is a blocking request for an - * already pending lock request then we need - * to put it back on lockd's block list - */ - if (wait) - break; ret = async_block ? nlm_lck_blocked : nlm_lck_denied; goto out; case FILE_LOCK_DEFERRED: -- cgit v1.2.3 From afb13302aa664170684c76b0c12ece37b4e91d12 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 12 Sep 2023 17:53:20 -0400 Subject: lockd: fix race in async lock request handling This patch fixes a race in async lock request handling between adding the relevant struct nlm_block to nlm_blocked list after the request was sent by vfs_lock_file() and nlmsvc_grant_deferred() does a lookup of the nlm_block in the nlm_blocked list. It could be that the async request is completed before the nlm_block was added to the list. This would end in a -ENOENT and a kernel log message of "lockd: grant for unknown block". To solve this issue we add the nlm_block before the vfs_lock_file() call to be sure it has been added when a possible nlmsvc_grant_deferred() is called. If the vfs_lock_file() results in an case when it wouldn't be added to nlm_blocked list, the nlm_block struct will be removed from this list again. Reviewed-by: Jeff Layton Signed-off-by: Alexander Aring Signed-off-by: Chuck Lever --- fs/lockd/svclock.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index c313622a9578..993999297e31 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -555,6 +555,9 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, ret = nlm_lck_blocked; goto out; } + + /* Append to list of blocked */ + nlmsvc_insert_block_locked(block, NLM_NEVER); spin_unlock(&nlm_blocked_lock); if (!wait) @@ -566,9 +569,12 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, dprintk("lockd: vfs_lock_file returned %d\n", error); switch (error) { case 0: + nlmsvc_remove_block(block); ret = nlm_granted; goto out; case -EAGAIN: + if (!wait) + nlmsvc_remove_block(block); ret = async_block ? nlm_lck_blocked : nlm_lck_denied; goto out; case FILE_LOCK_DEFERRED: @@ -579,17 +585,16 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, ret = nlmsvc_defer_lock_rqst(rqstp, block); goto out; case -EDEADLK: + nlmsvc_remove_block(block); ret = nlm_deadlock; goto out; default: /* includes ENOLCK */ + nlmsvc_remove_block(block); ret = nlm_lck_denied_nolocks; goto out; } ret = nlm_lck_blocked; - - /* Append to list of blocked */ - nlmsvc_insert_block(block, NLM_NEVER); out: mutex_unlock(&file->f_mutex); nlmsvc_release_block(block); -- cgit v1.2.3 From e70da17633ee9457cae39e4f5f2fc5efafb7a99b Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 12 Sep 2023 17:53:21 -0400 Subject: lockd: add doc to enable EXPORT_OP_ASYNC_LOCK This patch adds a note to enable EXPORT_OP_ASYNC_LOCK for asynchronous lock request handling. Reviewed-by: Jeff Layton Signed-off-by: Alexander Aring Signed-off-by: Chuck Lever --- fs/locks.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/locks.c b/fs/locks.c index 76ad05f8070a..d4e49a990a8d 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -2264,11 +2264,13 @@ out: * To avoid blocking kernel daemons, such as lockd, that need to acquire POSIX * locks, the ->lock() interface may return asynchronously, before the lock has * been granted or denied by the underlying filesystem, if (and only if) - * lm_grant is set. Callers expecting ->lock() to return asynchronously - * will only use F_SETLK, not F_SETLKW; they will set FL_SLEEP if (and only if) - * the request is for a blocking lock. When ->lock() does return asynchronously, - * it must return FILE_LOCK_DEFERRED, and call ->lm_grant() when the lock - * request completes. + * lm_grant is set. Additionally EXPORT_OP_ASYNC_LOCK in export_operations + * flags need to be set. + * + * Callers expecting ->lock() to return asynchronously will only use F_SETLK, + * not F_SETLKW; they will set FL_SLEEP if (and only if) the request is for a + * blocking lock. When ->lock() does return asynchronously, it must return + * FILE_LOCK_DEFERRED, and call ->lm_grant() when the lock request completes. * If the request is for non-blocking lock the file system should return * FILE_LOCK_DEFERRED then try to get the lock and call the callback routine * with the result. If the request timed out the callback routine will return a -- cgit v1.2.3 From 6ed8cdf967f7e9fc96cd1c129719ef99db2f9afc Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 11 Sep 2023 10:38:51 -0400 Subject: SUNRPC: Clean up bc_svc_process() The test robot complained that, in some build configurations, the @error variable in bc_svc_process's only caller is set but never used. This happens because dprintk() is the only consumer of that value. - Remove the dprintk() call sites in favor of the svc_process tracepoint - The @error variable and the return value of bc_svc_process() are now unused, so get rid of them. - The @serv parameter is set to rqstp->rq_serv by the only caller, and bc_svc_process() then uses it only to set rqstp->rq_serv. It can be removed. - Rename bc_svc_process() according to the convention that globally-visible RPC server functions have names that begin with "svc_"; and because it is globally-visible, give it a proper kdoc comment. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202308121314.HA8Rq2XG-lkp@intel.com/ Signed-off-by: Chuck Lever --- fs/nfs/callback.c | 6 +----- include/linux/sunrpc/svc.h | 3 +-- net/sunrpc/svc.c | 38 ++++++++++++-------------------------- 3 files changed, 14 insertions(+), 33 deletions(-) (limited to 'fs') diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 466ebf1d41b2..272e6d2bb478 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -95,7 +95,6 @@ nfs41_callback_svc(void *vrqstp) struct svc_rqst *rqstp = vrqstp; struct svc_serv *serv = rqstp->rq_server; struct rpc_rqst *req; - int error; DEFINE_WAIT(wq); set_freezable(); @@ -109,10 +108,7 @@ nfs41_callback_svc(void *vrqstp) list_del(&req->rq_bc_list); spin_unlock_bh(&serv->sv_cb_lock); finish_wait(&serv->sv_cb_waitq, &wq); - dprintk("Invoking bc_svc_process()\n"); - error = bc_svc_process(serv, req, rqstp); - dprintk("bc_svc_process() returned w/ error code= %d\n", - error); + svc_process_bc(req, rqstp); } else { spin_unlock_bh(&serv->sv_cb_lock); if (!kthread_should_stop()) diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index dbf5b21feafe..0cdca5960171 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -413,8 +413,7 @@ struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int); int svc_pool_stats_open(struct svc_serv *serv, struct file *file); void svc_process(struct svc_rqst *rqstp); -int bc_svc_process(struct svc_serv *, struct rpc_rqst *, - struct svc_rqst *); +void svc_process_bc(struct rpc_rqst *req, struct svc_rqst *rqstp); int svc_register(const struct svc_serv *, struct net *, const int, const unsigned short, const unsigned short); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 812fda9d45dd..a3d031deb1ec 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -1544,24 +1544,20 @@ out_drop: } #if defined(CONFIG_SUNRPC_BACKCHANNEL) -/* - * Process a backchannel RPC request that arrived over an existing - * outbound connection +/** + * svc_process_bc - process a reverse-direction RPC request + * @req: RPC request to be used for client-side processing + * @rqstp: server-side execution context + * */ -int -bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, - struct svc_rqst *rqstp) +void svc_process_bc(struct rpc_rqst *req, struct svc_rqst *rqstp) { struct rpc_task *task; int proc_error; - int error; - - dprintk("svc: %s(%p)\n", __func__, req); /* Build the svc_rqst used by the common processing routine */ rqstp->rq_xid = req->rq_xid; rqstp->rq_prot = req->rq_xprt->prot; - rqstp->rq_server = serv; rqstp->rq_bc_net = req->rq_xprt->xprt_net; rqstp->rq_addrlen = sizeof(req->rq_xprt->addr); @@ -1590,10 +1586,8 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, * been processed by the caller. */ svcxdr_init_decode(rqstp); - if (!xdr_inline_decode(&rqstp->rq_arg_stream, XDR_UNIT * 2)) { - error = -EINVAL; - goto out; - } + if (!xdr_inline_decode(&rqstp->rq_arg_stream, XDR_UNIT * 2)) + return; /* Parse and execute the bc call */ proc_error = svc_process_common(rqstp); @@ -1602,26 +1596,18 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, if (!proc_error) { /* Processing error: drop the request */ xprt_free_bc_request(req); - error = -EINVAL; - goto out; + return; } /* Finally, send the reply synchronously */ memcpy(&req->rq_snd_buf, &rqstp->rq_res, sizeof(req->rq_snd_buf)); task = rpc_run_bc_task(req); - if (IS_ERR(task)) { - error = PTR_ERR(task); - goto out; - } + if (IS_ERR(task)) + return; WARN_ON_ONCE(atomic_read(&task->tk_count) != 1); - error = task->tk_status; rpc_put_task(task); - -out: - dprintk("svc: %s(), error=%d\n", __func__, error); - return error; } -EXPORT_SYMBOL_GPL(bc_svc_process); +EXPORT_SYMBOL_GPL(svc_process_bc); #endif /* CONFIG_SUNRPC_BACKCHANNEL */ /** -- cgit v1.2.3 From 063ab935a48b3a2854f433957adbb2bde396ed22 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 11 Sep 2023 10:38:58 -0400 Subject: SUNRPC: integrate back-channel processing with svc_recv() Using svc_recv() for (NFSv4.1) back-channel handling means we have just one mechanism for waking threads. Also change kthread_freezable_should_stop() in nfs4_callback_svc() to kthread_should_stop() as used elsewhere. kthread_freezable_should_stop() effectively adds a try_to_freeze() call, and svc_recv() already contains that at an appropriate place. Signed-off-by: NeilBrown Cc: Trond Myklebust Cc: Anna Schumaker Signed-off-by: Chuck Lever --- fs/nfs/callback.c | 42 ++------------------------------------- include/linux/sunrpc/svc.h | 2 -- net/sunrpc/backchannel_rqst.c | 8 +++----- net/sunrpc/svc.c | 2 +- net/sunrpc/svc_xprt.c | 27 +++++++++++++++++++++++++ net/sunrpc/xprtrdma/backchannel.c | 2 +- 6 files changed, 34 insertions(+), 49 deletions(-) (limited to 'fs') diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 272e6d2bb478..42a0c2f1e785 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -78,7 +78,7 @@ nfs4_callback_svc(void *vrqstp) set_freezable(); - while (!kthread_freezable_should_stop(NULL)) + while (!kthread_should_stop()) svc_recv(rqstp); svc_exit_thread(rqstp); @@ -86,41 +86,6 @@ nfs4_callback_svc(void *vrqstp) } #if defined(CONFIG_NFS_V4_1) -/* - * The callback service for NFSv4.1 callbacks - */ -static int -nfs41_callback_svc(void *vrqstp) -{ - struct svc_rqst *rqstp = vrqstp; - struct svc_serv *serv = rqstp->rq_server; - struct rpc_rqst *req; - DEFINE_WAIT(wq); - - set_freezable(); - - while (!kthread_freezable_should_stop(NULL)) { - prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_IDLE); - spin_lock_bh(&serv->sv_cb_lock); - if (!list_empty(&serv->sv_cb_list)) { - req = list_first_entry(&serv->sv_cb_list, - struct rpc_rqst, rq_bc_list); - list_del(&req->rq_bc_list); - spin_unlock_bh(&serv->sv_cb_lock); - finish_wait(&serv->sv_cb_waitq, &wq); - svc_process_bc(req, rqstp); - } else { - spin_unlock_bh(&serv->sv_cb_lock); - if (!kthread_should_stop()) - schedule(); - finish_wait(&serv->sv_cb_waitq, &wq); - } - } - - svc_exit_thread(rqstp); - return 0; -} - static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, struct svc_serv *serv) { @@ -233,10 +198,7 @@ static struct svc_serv *nfs_callback_create_svc(int minorversion) cb_info->users); threadfn = nfs4_callback_svc; -#if defined(CONFIG_NFS_V4_1) - if (minorversion) - threadfn = nfs41_callback_svc; -#else +#if !defined(CONFIG_NFS_V4_1) if (minorversion) return ERR_PTR(-ENOTSUPP); #endif diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 0cdca5960171..acbe1314febd 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -92,8 +92,6 @@ struct svc_serv { * that arrive over the same * connection */ spinlock_t sv_cb_lock; /* protects the svc_cb_list */ - wait_queue_head_t sv_cb_waitq; /* sleep here if there are no - * entries in the svc_cb_list */ bool sv_bc_enabled; /* service uses backchannel */ #endif /* CONFIG_SUNRPC_BACKCHANNEL */ }; diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c index 65a6c6429a53..44b7c89a635f 100644 --- a/net/sunrpc/backchannel_rqst.c +++ b/net/sunrpc/backchannel_rqst.c @@ -349,10 +349,8 @@ found: } /* - * Add callback request to callback list. The callback - * service sleeps on the sv_cb_waitq waiting for new - * requests. Wake it up after adding enqueing the - * request. + * Add callback request to callback list. Wake a thread + * on the first pool (usually the only pool) to handle it. */ void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied) { @@ -371,6 +369,6 @@ void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied) xprt_get(xprt); spin_lock(&bc_serv->sv_cb_lock); list_add(&req->rq_bc_list, &bc_serv->sv_cb_list); - wake_up(&bc_serv->sv_cb_waitq); spin_unlock(&bc_serv->sv_cb_lock); + svc_pool_wake_idle_thread(&bc_serv->sv_pools[0]); } diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index a3d031deb1ec..b98a159eb17f 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -440,7 +440,6 @@ __svc_init_bc(struct svc_serv *serv) { INIT_LIST_HEAD(&serv->sv_cb_list); spin_lock_init(&serv->sv_cb_lock); - init_waitqueue_head(&serv->sv_cb_waitq); } #else static void @@ -718,6 +717,7 @@ void svc_pool_wake_idle_thread(struct svc_pool *pool) set_bit(SP_CONGESTED, &pool->sp_flags); } +EXPORT_SYMBOL_GPL(svc_pool_wake_idle_thread); static struct svc_pool * svc_pool_next(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state) diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 835160da3ad4..b057f1cbe7a1 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -719,6 +720,13 @@ rqst_should_sleep(struct svc_rqst *rqstp) if (freezing(current)) return false; +#if defined(CONFIG_SUNRPC_BACKCHANNEL) + if (svc_is_backchannel(rqstp)) { + if (!list_empty(&rqstp->rq_server->sv_cb_list)) + return false; + } +#endif + return true; } @@ -868,6 +876,25 @@ void svc_recv(struct svc_rqst *rqstp) trace_svc_xprt_dequeue(rqstp); svc_handle_xprt(rqstp, xprt); } + +#if defined(CONFIG_SUNRPC_BACKCHANNEL) + if (svc_is_backchannel(rqstp)) { + struct svc_serv *serv = rqstp->rq_server; + struct rpc_rqst *req; + + spin_lock_bh(&serv->sv_cb_lock); + req = list_first_entry_or_null(&serv->sv_cb_list, + struct rpc_rqst, rq_bc_list); + if (req) { + list_del(&req->rq_bc_list); + spin_unlock_bh(&serv->sv_cb_lock); + + svc_process_bc(req, rqstp); + return; + } + spin_unlock_bh(&serv->sv_cb_lock); + } +#endif } EXPORT_SYMBOL_GPL(svc_recv); diff --git a/net/sunrpc/xprtrdma/backchannel.c b/net/sunrpc/xprtrdma/backchannel.c index e4d84a13c566..bfc434ec52a7 100644 --- a/net/sunrpc/xprtrdma/backchannel.c +++ b/net/sunrpc/xprtrdma/backchannel.c @@ -267,7 +267,7 @@ void rpcrdma_bc_receive_call(struct rpcrdma_xprt *r_xprt, list_add(&rqst->rq_bc_list, &bc_serv->sv_cb_list); spin_unlock(&bc_serv->sv_cb_lock); - wake_up(&bc_serv->sv_cb_waitq); + svc_pool_wake_idle_thread(&bc_serv->sv_pools[0]); r_xprt->rx_stats.bcall_count++; return; -- cgit v1.2.3 From f4578ba11c4a211d45877babe56c84d922301576 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 11 Oct 2023 09:31:22 +1100 Subject: lockd: hold a reference to nlmsvc_serv while stopping the thread. Both nfsd and nfsv4-callback take a temporary reference to the svc_serv while calling svc_set_num_threads() to stop the last thread. lockd does not. This extra reference prevents the scv_serv from being freed when the last thread drops its reference count. This is not currently needed for lockd as the svc_serv is not accessed after the last thread is told to exit. However a future patch will require svc_exit_thread() to access the svc_serv after the svc_put() so it will need the code that calls svc_set_num_threads() to keep a reference and keep the svc_serv active. So copy the pattern from nfsd and nfsv4-cb to lockd, and take a reference around svc_set_num_threads(.., 0) Reviewed-by: Jeff Layton Tested-by: Jeff Layton Signed-off-by: NeilBrown Signed-off-by: Chuck Lever --- fs/lockd/svc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'fs') diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 6579948070a4..365cc7adff66 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -373,7 +373,9 @@ static void lockd_put(void) unregister_inet6addr_notifier(&lockd_inet6addr_notifier); #endif + svc_get(nlmsvc_serv); svc_set_num_threads(nlmsvc_serv, NULL, 0); + svc_put(nlmsvc_serv); timer_delete_sync(&nlmsvc_retry); nlmsvc_serv = NULL; dprintk("lockd_down: service destroyed\n"); -- cgit v1.2.3 From fa341560ca7458f4396d5a0771cb5f2358d8535d Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 11 Sep 2023 10:39:04 -0400 Subject: SUNRPC: change how svc threads are asked to exit. svc threads are currently stopped using kthread_stop(). This requires identifying a specific thread. However we don't care which thread stops, just as long as one does. So instead, set a flag in the svc_pool to say that a thread needs to die, and have each thread check this flag instead of calling kthread_should_stop(). The first thread to find and clear this flag then moves towards exiting. This removes an explicit dependency on sp_all_threads which will make a future patch simpler. Signed-off-by: NeilBrown Signed-off-by: Chuck Lever --- fs/lockd/svc.c | 5 ++--- fs/lockd/svclock.c | 5 ++--- fs/nfs/callback.c | 2 +- fs/nfsd/nfs4proc.c | 8 +++++--- fs/nfsd/nfssvc.c | 2 +- include/linux/lockd/lockd.h | 2 +- include/linux/sunrpc/svc.h | 26 +++++++++++++++++++++++++- net/sunrpc/svc.c | 43 +++++++++++++++++++++---------------------- net/sunrpc/svc_xprt.c | 7 +++---- 9 files changed, 61 insertions(+), 39 deletions(-) (limited to 'fs') diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 365cc7adff66..81be07c1d3d1 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -135,11 +134,11 @@ lockd(void *vrqstp) * The main request loop. We don't terminate until the last * NFS mount or NFS daemon has gone away. */ - while (!kthread_should_stop()) { + while (!svc_thread_should_stop(rqstp)) { /* update sv_maxconn if it has changed */ rqstp->rq_server->sv_maxconn = nlm_max_connections; - nlmsvc_retry_blocked(); + nlmsvc_retry_blocked(rqstp); svc_recv(rqstp); } if (nlmsvc_ops) diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 993999297e31..2dc10900ad1c 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #define NLMDBG_FACILITY NLMDBG_SVCLOCK @@ -1032,13 +1031,13 @@ retry_deferred_block(struct nlm_block *block) * be retransmitted. */ void -nlmsvc_retry_blocked(void) +nlmsvc_retry_blocked(struct svc_rqst *rqstp) { unsigned long timeout = MAX_SCHEDULE_TIMEOUT; struct nlm_block *block; spin_lock(&nlm_blocked_lock); - while (!list_empty(&nlm_blocked) && !kthread_should_stop()) { + while (!list_empty(&nlm_blocked) && !svc_thread_should_stop(rqstp)) { block = list_entry(nlm_blocked.next, struct nlm_block, b_list); if (block->b_when == NLM_NEVER) diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 42a0c2f1e785..4ffa1f469e90 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -78,7 +78,7 @@ nfs4_callback_svc(void *vrqstp) set_freezable(); - while (!kthread_should_stop()) + while (!svc_thread_should_stop(rqstp)) svc_recv(rqstp); svc_exit_thread(rqstp); diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 580c5f592408..d7e88c7beba3 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1329,7 +1329,8 @@ extern void nfs_sb_deactive(struct super_block *sb); * setup a work entry in the ssc delayed unmount list. */ static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, - struct nfsd4_ssc_umount_item **nsui) + struct nfsd4_ssc_umount_item **nsui, + struct svc_rqst *rqstp) { struct nfsd4_ssc_umount_item *ni = NULL; struct nfsd4_ssc_umount_item *work = NULL; @@ -1351,7 +1352,7 @@ try_again: spin_unlock(&nn->nfsd_ssc_lock); /* allow 20secs for mount/unmount for now - revisit */ - if (kthread_should_stop() || + if (svc_thread_should_stop(rqstp) || (schedule_timeout(20*HZ) == 0)) { finish_wait(&nn->nfsd_ssc_waitq, &wait); kfree(work); @@ -1467,7 +1468,7 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, goto out_free_rawdata; snprintf(dev_name, len + 5, "%s%s%s:/", startsep, ipaddr, endsep); - status = nfsd4_ssc_setup_dul(nn, ipaddr, nsui); + status = nfsd4_ssc_setup_dul(nn, ipaddr, nsui, rqstp); if (status) goto out_free_devname; if ((*nsui)->nsui_vfsmount) @@ -1642,6 +1643,7 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy, if (bytes_total == 0) bytes_total = ULLONG_MAX; do { + /* Only async copies can be stopped here */ if (kthread_should_stop()) break; bytes_copied = nfsd_copy_file_range(src, src_pos, dst, dst_pos, diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index c7af1095f6b5..0b03a2e50dee 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -957,7 +957,7 @@ nfsd(void *vrqstp) /* * The main request loop */ - while (!kthread_should_stop()) { + while (!svc_thread_should_stop(rqstp)) { /* Update sv_maxconn if it has changed */ rqstp->rq_server->sv_maxconn = nn->max_connections; diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 0f016d69c996..9f565416d186 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -282,7 +282,7 @@ __be32 nlmsvc_testlock(struct svc_rqst *, struct nlm_file *, struct nlm_host *, struct nlm_lock *, struct nlm_lock *, struct nlm_cookie *); __be32 nlmsvc_cancel_blocked(struct net *net, struct nlm_file *, struct nlm_lock *); -void nlmsvc_retry_blocked(void); +void nlmsvc_retry_blocked(struct svc_rqst *rqstp); void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *, nlm_host_match_fn_t match); void nlmsvc_grant_reply(struct nlm_cookie *, __be32); diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index acbe1314febd..0ec691070e27 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -50,6 +50,8 @@ struct svc_pool { enum { SP_TASK_PENDING, /* still work to do even if no xprt is queued */ SP_CONGESTED, /* all threads are busy, none idle */ + SP_NEED_VICTIM, /* One thread needs to agree to exit */ + SP_VICTIM_REMAINS, /* One thread needs to actually exit */ }; @@ -259,7 +261,7 @@ enum { RQ_DROPME, /* drop current reply */ RQ_SPLICE_OK, /* turned off in gss privacy to prevent * encrypting page cache pages */ - RQ_VICTIM, /* about to be shut down */ + RQ_VICTIM, /* Have agreed to shut down */ RQ_BUSY, /* request is busy */ RQ_DATA, /* request has data */ }; @@ -299,6 +301,28 @@ static inline struct sockaddr *svc_daddr(const struct svc_rqst *rqst) return (struct sockaddr *) &rqst->rq_daddr; } +/** + * svc_thread_should_stop - check if this thread should stop + * @rqstp: the thread that might need to stop + * + * To stop an svc thread, the pool flags SP_NEED_VICTIM and SP_VICTIM_REMAINS + * are set. The first thread which sees SP_NEED_VICTIM clears it, becoming + * the victim using this function. It should then promptly call + * svc_exit_thread() to complete the process, clearing SP_VICTIM_REMAINS + * so the task waiting for a thread to exit can wake and continue. + * + * Return values: + * %true: caller should invoke svc_exit_thread() + * %false: caller should do nothing + */ +static inline bool svc_thread_should_stop(struct svc_rqst *rqstp) +{ + if (test_and_clear_bit(SP_NEED_VICTIM, &rqstp->rq_pool->sp_flags)) + set_bit(RQ_VICTIM, &rqstp->rq_flags); + + return test_bit(RQ_VICTIM, &rqstp->rq_flags); +} + struct svc_deferred_req { u32 prot; /* protocol (UDP or TCP) */ struct svc_xprt *xprt; diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index b98a159eb17f..db579bbc0a0a 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -725,19 +725,22 @@ svc_pool_next(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state) return pool ? pool : &serv->sv_pools[(*state)++ % serv->sv_nrpools]; } -static struct task_struct * +static struct svc_pool * svc_pool_victim(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state) { unsigned int i; - struct task_struct *task = NULL; if (pool != NULL) { spin_lock_bh(&pool->sp_lock); + if (pool->sp_nrthreads) + goto found_pool; + spin_unlock_bh(&pool->sp_lock); + return NULL; } else { for (i = 0; i < serv->sv_nrpools; i++) { pool = &serv->sv_pools[--(*state) % serv->sv_nrpools]; spin_lock_bh(&pool->sp_lock); - if (!list_empty(&pool->sp_all_threads)) + if (pool->sp_nrthreads) goto found_pool; spin_unlock_bh(&pool->sp_lock); } @@ -745,16 +748,10 @@ svc_pool_victim(struct svc_serv *serv, struct svc_pool *pool, unsigned int *stat } found_pool: - if (!list_empty(&pool->sp_all_threads)) { - struct svc_rqst *rqstp; - - rqstp = list_entry(pool->sp_all_threads.next, struct svc_rqst, rq_all); - set_bit(RQ_VICTIM, &rqstp->rq_flags); - list_del_rcu(&rqstp->rq_all); - task = rqstp->rq_task; - } + set_bit(SP_VICTIM_REMAINS, &pool->sp_flags); + set_bit(SP_NEED_VICTIM, &pool->sp_flags); spin_unlock_bh(&pool->sp_lock); - return task; + return pool; } static int @@ -795,18 +792,16 @@ svc_start_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) static int svc_stop_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) { - struct svc_rqst *rqstp; - struct task_struct *task; unsigned int state = serv->sv_nrthreads-1; + struct svc_pool *victim; do { - task = svc_pool_victim(serv, pool, &state); - if (task == NULL) + victim = svc_pool_victim(serv, pool, &state); + if (!victim) break; - rqstp = kthread_data(task); - /* Did we lose a race to svo_function threadfn? */ - if (kthread_stop(task) == -EINTR) - svc_exit_thread(rqstp); + svc_pool_wake_idle_thread(victim); + wait_on_bit(&victim->sp_flags, SP_VICTIM_REMAINS, + TASK_IDLE); nrservs++; } while (nrservs < 0); return 0; @@ -926,8 +921,7 @@ svc_exit_thread(struct svc_rqst *rqstp) spin_lock_bh(&pool->sp_lock); pool->sp_nrthreads--; - if (!test_and_set_bit(RQ_VICTIM, &rqstp->rq_flags)) - list_del_rcu(&rqstp->rq_all); + list_del_rcu(&rqstp->rq_all); spin_unlock_bh(&pool->sp_lock); spin_lock_bh(&serv->sv_lock); @@ -938,6 +932,11 @@ svc_exit_thread(struct svc_rqst *rqstp) svc_rqst_free(rqstp); svc_put(serv); + /* That svc_put() cannot be the last, because the thread + * waiting for SP_VICTIM_REMAINS to clear must hold + * a reference. So it is still safe to access pool. + */ + clear_and_wake_up_bit(SP_VICTIM_REMAINS, &pool->sp_flags); } EXPORT_SYMBOL_GPL(svc_exit_thread); diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index b057f1cbe7a1..b8539545fefd 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -675,7 +674,7 @@ static bool svc_alloc_arg(struct svc_rqst *rqstp) continue; set_current_state(TASK_IDLE); - if (kthread_should_stop()) { + if (svc_thread_should_stop(rqstp)) { set_current_state(TASK_RUNNING); return false; } @@ -713,7 +712,7 @@ rqst_should_sleep(struct svc_rqst *rqstp) return false; /* are we shutting down? */ - if (kthread_should_stop()) + if (svc_thread_should_stop(rqstp)) return false; /* are we freezing? */ @@ -858,7 +857,7 @@ void svc_recv(struct svc_rqst *rqstp) clear_bit(SP_TASK_PENDING, &pool->sp_flags); - if (kthread_should_stop()) + if (svc_thread_should_stop(rqstp)) return; rqstp->rq_xprt = svc_xprt_dequeue(pool); -- cgit v1.2.3 From 2e8fc923fe476db8cab9b6458027eccb22f3b6e6 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 11 Sep 2023 10:40:09 -0400 Subject: SUNRPC: change sp_nrthreads to atomic_t Using an atomic_t avoids the need to take a spinlock (which can soon be removed). Choosing a thread to kill needs to be careful as we cannot set the "die now" bit atomically with the test on the count. Instead we temporarily increase the count. Signed-off-by: NeilBrown Signed-off-by: Chuck Lever --- fs/nfsd/nfssvc.c | 11 +++++------ include/linux/sunrpc/svc.h | 2 +- net/sunrpc/svc.c | 37 ++++++++++++++++++++----------------- 3 files changed, 26 insertions(+), 24 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 0b03a2e50dee..433154b9eee0 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -713,14 +713,13 @@ int nfsd_nrpools(struct net *net) int nfsd_get_nrthreads(int n, int *nthreads, struct net *net) { - int i = 0; struct nfsd_net *nn = net_generic(net, nfsd_net_id); + struct svc_serv *serv = nn->nfsd_serv; + int i; - if (nn->nfsd_serv != NULL) { - for (i = 0; i < nn->nfsd_serv->sv_nrpools && i < n; i++) - nthreads[i] = nn->nfsd_serv->sv_pools[i].sp_nrthreads; - } - + if (serv) + for (i = 0; i < serv->sv_nrpools && i < n; i++) + nthreads[i] = atomic_read(&serv->sv_pools[i].sp_nrthreads); return 0; } diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 7ff9fe785e49..9d0fcd6148ae 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -36,7 +36,7 @@ struct svc_pool { unsigned int sp_id; /* pool id; also node id on NUMA */ spinlock_t sp_lock; /* protects all fields */ struct lwq sp_xprts; /* pending transports */ - unsigned int sp_nrthreads; /* # of threads in pool */ + atomic_t sp_nrthreads; /* # of threads in pool */ struct list_head sp_all_threads; /* all server threads */ struct llist_head sp_idle_threads; /* idle server threads */ diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 244b5b9eba4d..0928d3f918b0 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -681,8 +681,8 @@ svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node) serv->sv_nrthreads += 1; spin_unlock_bh(&serv->sv_lock); + atomic_inc(&pool->sp_nrthreads); spin_lock_bh(&pool->sp_lock); - pool->sp_nrthreads++; list_add_rcu(&rqstp->rq_all, &pool->sp_all_threads); spin_unlock_bh(&pool->sp_lock); return rqstp; @@ -727,23 +727,24 @@ svc_pool_next(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state) } static struct svc_pool * -svc_pool_victim(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state) +svc_pool_victim(struct svc_serv *serv, struct svc_pool *target_pool, + unsigned int *state) { + struct svc_pool *pool; unsigned int i; +retry: + pool = target_pool; + if (pool != NULL) { - spin_lock_bh(&pool->sp_lock); - if (pool->sp_nrthreads) + if (atomic_inc_not_zero(&pool->sp_nrthreads)) goto found_pool; - spin_unlock_bh(&pool->sp_lock); return NULL; } else { for (i = 0; i < serv->sv_nrpools; i++) { pool = &serv->sv_pools[--(*state) % serv->sv_nrpools]; - spin_lock_bh(&pool->sp_lock); - if (pool->sp_nrthreads) + if (atomic_inc_not_zero(&pool->sp_nrthreads)) goto found_pool; - spin_unlock_bh(&pool->sp_lock); } return NULL; } @@ -751,8 +752,12 @@ svc_pool_victim(struct svc_serv *serv, struct svc_pool *pool, unsigned int *stat found_pool: set_bit(SP_VICTIM_REMAINS, &pool->sp_flags); set_bit(SP_NEED_VICTIM, &pool->sp_flags); - spin_unlock_bh(&pool->sp_lock); - return pool; + if (!atomic_dec_and_test(&pool->sp_nrthreads)) + return pool; + /* Nothing left in this pool any more */ + clear_bit(SP_NEED_VICTIM, &pool->sp_flags); + clear_bit(SP_VICTIM_REMAINS, &pool->sp_flags); + goto retry; } static int @@ -828,13 +833,10 @@ svc_stop_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) int svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) { - if (pool == NULL) { + if (!pool) nrservs -= serv->sv_nrthreads; - } else { - spin_lock_bh(&pool->sp_lock); - nrservs -= pool->sp_nrthreads; - spin_unlock_bh(&pool->sp_lock); - } + else + nrservs -= atomic_read(&pool->sp_nrthreads); if (nrservs > 0) return svc_start_kthreads(serv, pool, nrservs); @@ -921,10 +923,11 @@ svc_exit_thread(struct svc_rqst *rqstp) struct svc_pool *pool = rqstp->rq_pool; spin_lock_bh(&pool->sp_lock); - pool->sp_nrthreads--; list_del_rcu(&rqstp->rq_all); spin_unlock_bh(&pool->sp_lock); + atomic_dec(&pool->sp_nrthreads); + spin_lock_bh(&serv->sv_lock); serv->sv_nrthreads -= 1; spin_unlock_bh(&serv->sv_lock); -- cgit v1.2.3 From 738401a9bd1ac34ccd5723d69640a4adbb1a4bc0 Mon Sep 17 00:00:00 2001 From: Dai Ngo Date: Wed, 13 Sep 2023 16:38:20 -0700 Subject: NFSD: add support for CB_GETATTR callback Includes: . CB_GETATTR proc for nfs4_cb_procedures[] . XDR encoding and decoding function for CB_GETATTR request/reply . add nfs4_cb_fattr to nfs4_delegation for sending CB_GETATTR and store file attributes from client's reply. Signed-off-by: Dai Ngo Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4callback.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++- fs/nfsd/state.h | 14 ++++++++ fs/nfsd/xdr4cb.h | 18 ++++++++++ 3 files changed, 128 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 4039ffcf90ba..92bc109dabe6 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -84,7 +84,21 @@ static void encode_uint32(struct xdr_stream *xdr, u32 n) static void encode_bitmap4(struct xdr_stream *xdr, const __u32 *bitmap, size_t len) { - WARN_ON_ONCE(xdr_stream_encode_uint32_array(xdr, bitmap, len) < 0); + xdr_stream_encode_uint32_array(xdr, bitmap, len); +} + +static int decode_cb_fattr4(struct xdr_stream *xdr, uint32_t *bitmap, + struct nfs4_cb_fattr *fattr) +{ + fattr->ncf_cb_change = 0; + fattr->ncf_cb_fsize = 0; + if (bitmap[0] & FATTR4_WORD0_CHANGE) + if (xdr_stream_decode_u64(xdr, &fattr->ncf_cb_change) < 0) + return -NFSERR_BAD_XDR; + if (bitmap[0] & FATTR4_WORD0_SIZE) + if (xdr_stream_decode_u64(xdr, &fattr->ncf_cb_fsize) < 0) + return -NFSERR_BAD_XDR; + return 0; } /* @@ -357,6 +371,30 @@ encode_cb_recallany4args(struct xdr_stream *xdr, hdr->nops++; } +/* + * CB_GETATTR4args + * struct CB_GETATTR4args { + * nfs_fh4 fh; + * bitmap4 attr_request; + * }; + * + * The size and change attributes are the only one + * guaranteed to be serviced by the client. + */ +static void +encode_cb_getattr4args(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr, + struct nfs4_cb_fattr *fattr) +{ + struct nfs4_delegation *dp = + container_of(fattr, struct nfs4_delegation, dl_cb_fattr); + struct knfsd_fh *fh = &dp->dl_stid.sc_file->fi_fhandle; + + encode_nfs_cb_opnum4(xdr, OP_CB_GETATTR); + encode_nfs_fh4(xdr, fh); + encode_bitmap4(xdr, fattr->ncf_cb_bmap, ARRAY_SIZE(fattr->ncf_cb_bmap)); + hdr->nops++; +} + /* * CB_SEQUENCE4args * @@ -492,6 +530,26 @@ static void nfs4_xdr_enc_cb_null(struct rpc_rqst *req, struct xdr_stream *xdr, xdr_reserve_space(xdr, 0); } +/* + * 20.1. Operation 3: CB_GETATTR - Get Attributes + */ +static void nfs4_xdr_enc_cb_getattr(struct rpc_rqst *req, + struct xdr_stream *xdr, const void *data) +{ + const struct nfsd4_callback *cb = data; + struct nfs4_cb_fattr *ncf = + container_of(cb, struct nfs4_cb_fattr, ncf_getattr); + struct nfs4_cb_compound_hdr hdr = { + .ident = cb->cb_clp->cl_cb_ident, + .minorversion = cb->cb_clp->cl_minorversion, + }; + + encode_cb_compound4args(xdr, &hdr); + encode_cb_sequence4args(xdr, cb, &hdr); + encode_cb_getattr4args(xdr, &hdr, ncf); + encode_cb_nops(&hdr); +} + /* * 20.2. Operation 4: CB_RECALL - Recall a Delegation */ @@ -547,6 +605,42 @@ static int nfs4_xdr_dec_cb_null(struct rpc_rqst *req, struct xdr_stream *xdr, return 0; } +/* + * 20.1. Operation 3: CB_GETATTR - Get Attributes + */ +static int nfs4_xdr_dec_cb_getattr(struct rpc_rqst *rqstp, + struct xdr_stream *xdr, + void *data) +{ + struct nfsd4_callback *cb = data; + struct nfs4_cb_compound_hdr hdr; + int status; + u32 bitmap[3] = {0}; + u32 attrlen; + struct nfs4_cb_fattr *ncf = + container_of(cb, struct nfs4_cb_fattr, ncf_getattr); + + status = decode_cb_compound4res(xdr, &hdr); + if (unlikely(status)) + return status; + + status = decode_cb_sequence4res(xdr, cb); + if (unlikely(status || cb->cb_seq_status)) + return status; + + status = decode_cb_op_status(xdr, OP_CB_GETATTR, &cb->cb_status); + if (status) + return status; + if (xdr_stream_decode_uint32_array(xdr, bitmap, 3) < 0) + return -NFSERR_BAD_XDR; + if (xdr_stream_decode_u32(xdr, &attrlen) < 0) + return -NFSERR_BAD_XDR; + if (attrlen > (sizeof(ncf->ncf_cb_change) + sizeof(ncf->ncf_cb_fsize))) + return -NFSERR_BAD_XDR; + status = decode_cb_fattr4(xdr, bitmap, ncf); + return status; +} + /* * 20.2. Operation 4: CB_RECALL - Recall a Delegation */ @@ -855,6 +949,7 @@ static const struct rpc_procinfo nfs4_cb_procedures[] = { PROC(CB_NOTIFY_LOCK, COMPOUND, cb_notify_lock, cb_notify_lock), PROC(CB_OFFLOAD, COMPOUND, cb_offload, cb_offload), PROC(CB_RECALL_ANY, COMPOUND, cb_recall_any, cb_recall_any), + PROC(CB_GETATTR, COMPOUND, cb_getattr, cb_getattr), }; static unsigned int nfs4_cb_counts[ARRAY_SIZE(nfs4_cb_procedures)]; diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index cbddcf484dba..82718d42f3b2 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -117,6 +117,16 @@ struct nfs4_cpntf_state { time64_t cpntf_time; /* last time stateid used */ }; +struct nfs4_cb_fattr { + struct nfsd4_callback ncf_getattr; + u32 ncf_cb_status; + u32 ncf_cb_bmap[1]; + + /* from CB_GETATTR reply */ + u64 ncf_cb_change; + u64 ncf_cb_fsize; +}; + /* * Represents a delegation stateid. The nfs4_client holds references to these * and they are put when it is being destroyed or when the delegation is @@ -150,6 +160,9 @@ struct nfs4_delegation { int dl_retries; struct nfsd4_callback dl_recall; bool dl_recalled; + + /* for CB_GETATTR */ + struct nfs4_cb_fattr dl_cb_fattr; }; #define cb_to_delegation(cb) \ @@ -642,6 +655,7 @@ enum nfsd4_cb_op { NFSPROC4_CLNT_CB_SEQUENCE, NFSPROC4_CLNT_CB_NOTIFY_LOCK, NFSPROC4_CLNT_CB_RECALL_ANY, + NFSPROC4_CLNT_CB_GETATTR, }; /* Returns true iff a is later than b: */ diff --git a/fs/nfsd/xdr4cb.h b/fs/nfsd/xdr4cb.h index 0d39af1b00a0..e8b00309c449 100644 --- a/fs/nfsd/xdr4cb.h +++ b/fs/nfsd/xdr4cb.h @@ -54,3 +54,21 @@ #define NFS4_dec_cb_recall_any_sz (cb_compound_dec_hdr_sz + \ cb_sequence_dec_sz + \ op_dec_sz) + +/* + * 1: CB_GETATTR opcode (32-bit) + * N: file_handle + * 1: number of entry in attribute array (32-bit) + * 1: entry 0 in attribute array (32-bit) + */ +#define NFS4_enc_cb_getattr_sz (cb_compound_enc_hdr_sz + \ + cb_sequence_enc_sz + \ + 1 + enc_nfs4_fh_sz + 1 + 1) +/* + * 4: fattr_bitmap_maxsz + * 1: attribute array len + * 2: change attr (64-bit) + * 2: size (64-bit) + */ +#define NFS4_dec_cb_getattr_sz (cb_compound_dec_hdr_sz + \ + cb_sequence_dec_sz + 4 + 1 + 2 + 2 + op_dec_sz) -- cgit v1.2.3 From 6c41d9a9bd0298002805758216a9c44e38a8500d Mon Sep 17 00:00:00 2001 From: Dai Ngo Date: Wed, 13 Sep 2023 16:38:21 -0700 Subject: NFSD: handle GETATTR conflict with write delegation If the GETATTR request on a file that has write delegation in effect and the request attributes include the change info and size attribute then the request is handled as below: Server sends CB_GETATTR to client to get the latest change info and file size. If these values are the same as the server's cached values then the GETATTR proceeds as normal. If either the change info or file size is different from the server's cached values, or the file was already marked as modified, then: . update time_modify and time_metadata into file's metadata with current time . encode GETATTR as normal except the file size is encoded with the value returned from CB_GETATTR . mark the file as modified If the CB_GETATTR fails for any reasons, the delegation is recalled and NFS4ERR_DELAY is returned for the GETATTR. Signed-off-by: Dai Ngo Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4state.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++----- fs/nfsd/nfs4xdr.c | 10 ++++- fs/nfsd/state.h | 11 ++++- 3 files changed, 121 insertions(+), 14 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 7cabe882724e..07840ee721ef 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -127,6 +127,7 @@ static void free_session(struct nfsd4_session *); static const struct nfsd4_callback_ops nfsd4_cb_recall_ops; static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops; +static const struct nfsd4_callback_ops nfsd4_cb_getattr_ops; static struct workqueue_struct *laundry_wq; @@ -1187,6 +1188,10 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, dp->dl_recalled = false; nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, &nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL); + nfsd4_init_cb(&dp->dl_cb_fattr.ncf_getattr, dp->dl_stid.sc_client, + &nfsd4_cb_getattr_ops, NFSPROC4_CLNT_CB_GETATTR); + dp->dl_cb_fattr.ncf_file_modified = false; + dp->dl_cb_fattr.ncf_cb_bmap[0] = FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE; get_nfs4_file(fp); dp->dl_stid.sc_file = fp; return dp; @@ -2894,11 +2899,56 @@ nfsd4_cb_recall_any_release(struct nfsd4_callback *cb) spin_unlock(&nn->client_lock); } +static int +nfsd4_cb_getattr_done(struct nfsd4_callback *cb, struct rpc_task *task) +{ + struct nfs4_cb_fattr *ncf = + container_of(cb, struct nfs4_cb_fattr, ncf_getattr); + + ncf->ncf_cb_status = task->tk_status; + switch (task->tk_status) { + case -NFS4ERR_DELAY: + rpc_delay(task, 2 * HZ); + return 0; + default: + return 1; + } +} + +static void +nfsd4_cb_getattr_release(struct nfsd4_callback *cb) +{ + struct nfs4_cb_fattr *ncf = + container_of(cb, struct nfs4_cb_fattr, ncf_getattr); + struct nfs4_delegation *dp = + container_of(ncf, struct nfs4_delegation, dl_cb_fattr); + + nfs4_put_stid(&dp->dl_stid); + clear_bit(CB_GETATTR_BUSY, &ncf->ncf_cb_flags); + wake_up_bit(&ncf->ncf_cb_flags, CB_GETATTR_BUSY); +} + static const struct nfsd4_callback_ops nfsd4_cb_recall_any_ops = { .done = nfsd4_cb_recall_any_done, .release = nfsd4_cb_recall_any_release, }; +static const struct nfsd4_callback_ops nfsd4_cb_getattr_ops = { + .done = nfsd4_cb_getattr_done, + .release = nfsd4_cb_getattr_release, +}; + +void nfs4_cb_getattr(struct nfs4_cb_fattr *ncf) +{ + struct nfs4_delegation *dp = + container_of(ncf, struct nfs4_delegation, dl_cb_fattr); + + if (test_and_set_bit(CB_GETATTR_BUSY, &ncf->ncf_cb_flags)) + return; + refcount_inc(&dp->dl_stid.sc_count); + nfsd4_run_cb(&ncf->ncf_getattr); +} + static struct nfs4_client *create_client(struct xdr_netobj name, struct svc_rqst *rqstp, nfs4_verifier *verf) { @@ -5634,6 +5684,8 @@ nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp, struct svc_fh *parent = NULL; int cb_up; int status = 0; + struct kstat stat; + struct path path; cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); open->op_recall = 0; @@ -5671,6 +5723,18 @@ nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp, if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) { open->op_delegate_type = NFS4_OPEN_DELEGATE_WRITE; trace_nfsd_deleg_write(&dp->dl_stid.sc_stateid); + path.mnt = currentfh->fh_export->ex_path.mnt; + path.dentry = currentfh->fh_dentry; + if (vfs_getattr(&path, &stat, + (STATX_SIZE | STATX_CTIME | STATX_CHANGE_COOKIE), + AT_STATX_SYNC_AS_STAT)) { + nfs4_put_stid(&dp->dl_stid); + destroy_delegation(dp); + goto out_no_deleg; + } + dp->dl_cb_fattr.ncf_cur_fsize = stat.size; + dp->dl_cb_fattr.ncf_initial_cinfo = + nfsd4_change_attribute(&stat, d_inode(currentfh->fh_dentry)); } else { open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; trace_nfsd_deleg_read(&dp->dl_stid.sc_stateid); @@ -8407,6 +8471,8 @@ nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, * nfsd4_deleg_getattr_conflict - Recall if GETATTR causes conflict * @rqstp: RPC transaction context * @inode: file to be checked for a conflict + * @modified: return true if file was modified + * @size: new size of file if modified is true * * This function is called when there is a conflict between a write * delegation and a change/size GETATTR from another client. The server @@ -8415,21 +8481,23 @@ nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, * delegation before replying to the GETATTR. See RFC 8881 section * 18.7.4. * - * The current implementation does not support CB_GETATTR yet. However - * this can avoid recalling the delegation could be added in follow up - * work. - * * Returns 0 if there is no conflict; otherwise an nfs_stat * code is returned. */ __be32 -nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode) +nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode, + bool *modified, u64 *size) { - __be32 status; struct file_lock_context *ctx; - struct file_lock *fl; struct nfs4_delegation *dp; + struct nfs4_cb_fattr *ncf; + struct file_lock *fl; + struct iattr attrs; + __be32 status; + + might_sleep(); + *modified = false; ctx = locks_inode_context(inode); if (!ctx) return 0; @@ -8456,10 +8524,34 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode) break_lease: spin_unlock(&ctx->flc_lock); nfsd_stats_wdeleg_getattr_inc(); - status = nfserrno(nfsd_open_break_lease(inode, NFSD_MAY_READ)); - if (status != nfserr_jukebox || - !nfsd_wait_for_delegreturn(rqstp, inode)) - return status; + + dp = fl->fl_owner; + ncf = &dp->dl_cb_fattr; + nfs4_cb_getattr(&dp->dl_cb_fattr); + wait_on_bit(&ncf->ncf_cb_flags, CB_GETATTR_BUSY, TASK_INTERRUPTIBLE); + if (ncf->ncf_cb_status) { + status = nfserrno(nfsd_open_break_lease(inode, NFSD_MAY_READ)); + if (status != nfserr_jukebox || + !nfsd_wait_for_delegreturn(rqstp, inode)) + return status; + } + if (!ncf->ncf_file_modified && + (ncf->ncf_initial_cinfo != ncf->ncf_cb_change || + ncf->ncf_cur_fsize != ncf->ncf_cb_fsize)) + ncf->ncf_file_modified = true; + if (ncf->ncf_file_modified) { + /* + * The server would not update the file's metadata + * with the client's modified size. + */ + attrs.ia_mtime = attrs.ia_ctime = current_time(inode); + attrs.ia_valid = ATTR_MTIME | ATTR_CTIME; + setattr_copy(&nop_mnt_idmap, inode, &attrs); + mark_inode_dirty(inode); + ncf->ncf_cur_fsize = ncf->ncf_cb_fsize; + *size = ncf->ncf_cur_fsize; + *modified = true; + } return 0; } break; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 92c7dde148a4..0027c247a481 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2975,6 +2975,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, .dentry = dentry, }; struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); + bool file_modified; + u64 size = 0; BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1); BUG_ON(!nfsd_attrs_supported(minorversion, bmval)); @@ -2985,7 +2987,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & (FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE)) { - status = nfsd4_deleg_getattr_conflict(rqstp, d_inode(dentry)); + status = nfsd4_deleg_getattr_conflict(rqstp, d_inode(dentry), + &file_modified, &size); if (status) goto out; } @@ -3112,7 +3115,10 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, p = xdr_reserve_space(xdr, 8); if (!p) goto out_resource; - p = xdr_encode_hyper(p, stat.size); + if (file_modified) + p = xdr_encode_hyper(p, size); + else + p = xdr_encode_hyper(p, stat.size); } if (bmval0 & FATTR4_WORD0_LINK_SUPPORT) { p = xdr_reserve_space(xdr, 4); diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 82718d42f3b2..6bbb1d0276b4 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -125,8 +125,16 @@ struct nfs4_cb_fattr { /* from CB_GETATTR reply */ u64 ncf_cb_change; u64 ncf_cb_fsize; + + unsigned long ncf_cb_flags; + bool ncf_file_modified; + u64 ncf_initial_cinfo; + u64 ncf_cur_fsize; }; +/* bits for ncf_cb_flags */ +#define CB_GETATTR_BUSY 0 + /* * Represents a delegation stateid. The nfs4_client holds references to these * and they are put when it is being destroyed or when the delegation is @@ -748,5 +756,6 @@ static inline bool try_to_expire_client(struct nfs4_client *clp) } extern __be32 nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, - struct inode *inode); + struct inode *inode, bool *file_modified, u64 *size); +extern void nfs4_cb_getattr(struct nfs4_cb_fattr *ncf); #endif /* NFSD4_STATE_H */ -- cgit v1.2.3 From 13727f85b49babcc40db805118e665605cd040dc Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 11 Sep 2023 14:49:44 +0200 Subject: NFSD: introduce netlink stubs Generate stubs and uAPI for nfsd netlink protocol. For the moment, the new protocol has one operation: rpc_status. The generated header and source files are created by running: tools/net/ynl/ynl-regen.sh Tested-by: Jeff Layton Signed-off-by: Lorenzo Bianconi Acked-by: Jeff Layton Signed-off-by: Chuck Lever --- Documentation/netlink/specs/nfsd.yaml | 89 +++++++++++++++++++++++++++++++++++ fs/nfsd/Makefile | 3 +- fs/nfsd/netlink.c | 32 +++++++++++++ fs/nfsd/netlink.h | 22 +++++++++ fs/nfsd/nfsctl.c | 17 +++++++ include/uapi/linux/nfsd_netlink.h | 39 +++++++++++++++ 6 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 Documentation/netlink/specs/nfsd.yaml create mode 100644 fs/nfsd/netlink.c create mode 100644 fs/nfsd/netlink.h create mode 100644 include/uapi/linux/nfsd_netlink.h (limited to 'fs') diff --git a/Documentation/netlink/specs/nfsd.yaml b/Documentation/netlink/specs/nfsd.yaml new file mode 100644 index 000000000000..05acc73e2e33 --- /dev/null +++ b/Documentation/netlink/specs/nfsd.yaml @@ -0,0 +1,89 @@ +# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) + +name: nfsd +protocol: genetlink +uapi-header: linux/nfsd_netlink.h + +doc: NFSD configuration over generic netlink. + +attribute-sets: + - + name: rpc-status + attributes: + - + name: xid + type: u32 + byte-order: big-endian + - + name: flags + type: u32 + - + name: prog + type: u32 + - + name: version + type: u8 + - + name: proc + type: u32 + - + name: service_time + type: s64 + - + name: pad + type: pad + - + name: saddr4 + type: u32 + byte-order: big-endian + display-hint: ipv4 + - + name: daddr4 + type: u32 + byte-order: big-endian + display-hint: ipv4 + - + name: saddr6 + type: binary + display-hint: ipv6 + - + name: daddr6 + type: binary + display-hint: ipv6 + - + name: sport + type: u16 + byte-order: big-endian + - + name: dport + type: u16 + byte-order: big-endian + - + name: compound-ops + type: u32 + multi-attr: true + +operations: + list: + - + name: rpc-status-get + doc: dump pending nfsd rpc + attribute-set: rpc-status + dump: + pre: nfsd-nl-rpc-status-get-start + post: nfsd-nl-rpc-status-get-done + reply: + attributes: + - xid + - flags + - prog + - version + - proc + - service_time + - saddr4 + - daddr4 + - saddr6 + - daddr6 + - sport + - dport + - compound-ops diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile index 6fffc8f03f74..b8736a82e57c 100644 --- a/fs/nfsd/Makefile +++ b/fs/nfsd/Makefile @@ -12,7 +12,8 @@ nfsd-y += trace.o nfsd-y += nfssvc.o nfsctl.o nfsfh.o vfs.o \ export.o auth.o lockd.o nfscache.o \ - stats.o filecache.o nfs3proc.o nfs3xdr.o + stats.o filecache.o nfs3proc.o nfs3xdr.o \ + netlink.o nfsd-$(CONFIG_NFSD_V2) += nfsproc.o nfsxdr.o nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o diff --git a/fs/nfsd/netlink.c b/fs/nfsd/netlink.c new file mode 100644 index 000000000000..0e1d635ec5f9 --- /dev/null +++ b/fs/nfsd/netlink.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/nfsd.yaml */ +/* YNL-GEN kernel source */ + +#include +#include + +#include "netlink.h" + +#include + +/* Ops table for nfsd */ +static const struct genl_split_ops nfsd_nl_ops[] = { + { + .cmd = NFSD_CMD_RPC_STATUS_GET, + .start = nfsd_nl_rpc_status_get_start, + .dumpit = nfsd_nl_rpc_status_get_dumpit, + .done = nfsd_nl_rpc_status_get_done, + .flags = GENL_CMD_CAP_DUMP, + }, +}; + +struct genl_family nfsd_nl_family __ro_after_init = { + .name = NFSD_FAMILY_NAME, + .version = NFSD_FAMILY_VERSION, + .netnsok = true, + .parallel_ops = true, + .module = THIS_MODULE, + .split_ops = nfsd_nl_ops, + .n_split_ops = ARRAY_SIZE(nfsd_nl_ops), +}; diff --git a/fs/nfsd/netlink.h b/fs/nfsd/netlink.h new file mode 100644 index 000000000000..d83dd6bdee92 --- /dev/null +++ b/fs/nfsd/netlink.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/nfsd.yaml */ +/* YNL-GEN kernel header */ + +#ifndef _LINUX_NFSD_GEN_H +#define _LINUX_NFSD_GEN_H + +#include +#include + +#include + +int nfsd_nl_rpc_status_get_start(struct netlink_callback *cb); +int nfsd_nl_rpc_status_get_done(struct netlink_callback *cb); + +int nfsd_nl_rpc_status_get_dumpit(struct sk_buff *skb, + struct netlink_callback *cb); + +extern struct genl_family nfsd_nl_family; + +#endif /* _LINUX_NFSD_GEN_H */ diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 7ed02fb88a36..364ccd0be1c1 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -26,6 +26,7 @@ #include "pnfs.h" #include "filecache.h" #include "trace.h" +#include "netlink.h" /* * We have a single directory with several nodes in it. @@ -1495,6 +1496,22 @@ static int create_proc_exports_entry(void) unsigned int nfsd_net_id; +int nfsd_nl_rpc_status_get_start(struct netlink_callback *cb) +{ + return 0; +} + +int nfsd_nl_rpc_status_get_dumpit(struct sk_buff *skb, + struct netlink_callback *cb) +{ + return 0; +} + +int nfsd_nl_rpc_status_get_done(struct netlink_callback *cb) +{ + return 0; +} + /** * nfsd_net_init - Prepare the nfsd_net portion of a new net namespace * @net: a freshly-created network namespace diff --git a/include/uapi/linux/nfsd_netlink.h b/include/uapi/linux/nfsd_netlink.h new file mode 100644 index 000000000000..c8ae72466ee6 --- /dev/null +++ b/include/uapi/linux/nfsd_netlink.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/nfsd.yaml */ +/* YNL-GEN uapi header */ + +#ifndef _UAPI_LINUX_NFSD_H +#define _UAPI_LINUX_NFSD_H + +#define NFSD_FAMILY_NAME "nfsd" +#define NFSD_FAMILY_VERSION 1 + +enum { + NFSD_A_RPC_STATUS_XID = 1, + NFSD_A_RPC_STATUS_FLAGS, + NFSD_A_RPC_STATUS_PROG, + NFSD_A_RPC_STATUS_VERSION, + NFSD_A_RPC_STATUS_PROC, + NFSD_A_RPC_STATUS_SERVICE_TIME, + NFSD_A_RPC_STATUS_PAD, + NFSD_A_RPC_STATUS_SADDR4, + NFSD_A_RPC_STATUS_DADDR4, + NFSD_A_RPC_STATUS_SADDR6, + NFSD_A_RPC_STATUS_DADDR6, + NFSD_A_RPC_STATUS_SPORT, + NFSD_A_RPC_STATUS_DPORT, + NFSD_A_RPC_STATUS_COMPOUND_OPS, + + __NFSD_A_RPC_STATUS_MAX, + NFSD_A_RPC_STATUS_MAX = (__NFSD_A_RPC_STATUS_MAX - 1) +}; + +enum { + NFSD_CMD_RPC_STATUS_GET = 1, + + __NFSD_CMD_MAX, + NFSD_CMD_MAX = (__NFSD_CMD_MAX - 1) +}; + +#endif /* _UAPI_LINUX_NFSD_H */ -- cgit v1.2.3 From bd9d6a3efa9709e653aafbeb859289feccb8e70c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 11 Sep 2023 14:49:46 +0200 Subject: NFSD: add rpc_status netlink support Introduce rpc_status netlink support for NFSD in order to dump pending RPC requests debugging information from userspace. Closes: https://bugzilla.linux-nfs.org/show_bug.cgi?id=366 Tested-by: Jeff Layton Signed-off-by: Lorenzo Bianconi Signed-off-by: Chuck Lever --- fs/nfsd/nfsctl.c | 188 ++++++++++++++++++++++++++++++++++++++++++++- fs/nfsd/nfsd.h | 17 ++++ fs/nfsd/nfssvc.c | 15 ++++ fs/nfsd/state.h | 2 - include/linux/sunrpc/svc.h | 1 + 5 files changed, 220 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 364ccd0be1c1..739ed5bf71cd 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1496,19 +1496,200 @@ static int create_proc_exports_entry(void) unsigned int nfsd_net_id; +/** + * nfsd_nl_rpc_status_get_start - Prepare rpc_status_get dumpit + * @cb: netlink metadata and command arguments + * + * Return values: + * %0: The rpc_status_get command may proceed + * %-ENODEV: There is no NFSD running in this namespace + */ int nfsd_nl_rpc_status_get_start(struct netlink_callback *cb) { + struct nfsd_net *nn = net_generic(sock_net(cb->skb->sk), nfsd_net_id); + int ret = -ENODEV; + + mutex_lock(&nfsd_mutex); + if (nn->nfsd_serv) { + svc_get(nn->nfsd_serv); + ret = 0; + } + mutex_unlock(&nfsd_mutex); + + return ret; +} + +static int nfsd_genl_rpc_status_compose_msg(struct sk_buff *skb, + struct netlink_callback *cb, + struct nfsd_genl_rqstp *rqstp) +{ + void *hdr; + u32 i; + + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &nfsd_nl_family, 0, NFSD_CMD_RPC_STATUS_GET); + if (!hdr) + return -ENOBUFS; + + if (nla_put_be32(skb, NFSD_A_RPC_STATUS_XID, rqstp->rq_xid) || + nla_put_u32(skb, NFSD_A_RPC_STATUS_FLAGS, rqstp->rq_flags) || + nla_put_u32(skb, NFSD_A_RPC_STATUS_PROG, rqstp->rq_prog) || + nla_put_u32(skb, NFSD_A_RPC_STATUS_PROC, rqstp->rq_proc) || + nla_put_u8(skb, NFSD_A_RPC_STATUS_VERSION, rqstp->rq_vers) || + nla_put_s64(skb, NFSD_A_RPC_STATUS_SERVICE_TIME, + ktime_to_us(rqstp->rq_stime), + NFSD_A_RPC_STATUS_PAD)) + return -ENOBUFS; + + switch (rqstp->rq_saddr.sa_family) { + case AF_INET: { + const struct sockaddr_in *s_in, *d_in; + + s_in = (const struct sockaddr_in *)&rqstp->rq_saddr; + d_in = (const struct sockaddr_in *)&rqstp->rq_daddr; + if (nla_put_in_addr(skb, NFSD_A_RPC_STATUS_SADDR4, + s_in->sin_addr.s_addr) || + nla_put_in_addr(skb, NFSD_A_RPC_STATUS_DADDR4, + d_in->sin_addr.s_addr) || + nla_put_be16(skb, NFSD_A_RPC_STATUS_SPORT, + s_in->sin_port) || + nla_put_be16(skb, NFSD_A_RPC_STATUS_DPORT, + d_in->sin_port)) + return -ENOBUFS; + break; + } + case AF_INET6: { + const struct sockaddr_in6 *s_in, *d_in; + + s_in = (const struct sockaddr_in6 *)&rqstp->rq_saddr; + d_in = (const struct sockaddr_in6 *)&rqstp->rq_daddr; + if (nla_put_in6_addr(skb, NFSD_A_RPC_STATUS_SADDR6, + &s_in->sin6_addr) || + nla_put_in6_addr(skb, NFSD_A_RPC_STATUS_DADDR6, + &d_in->sin6_addr) || + nla_put_be16(skb, NFSD_A_RPC_STATUS_SPORT, + s_in->sin6_port) || + nla_put_be16(skb, NFSD_A_RPC_STATUS_DPORT, + d_in->sin6_port)) + return -ENOBUFS; + break; + } + } + + for (i = 0; i < rqstp->rq_opcnt; i++) + if (nla_put_u32(skb, NFSD_A_RPC_STATUS_COMPOUND_OPS, + rqstp->rq_opnum[i])) + return -ENOBUFS; + + genlmsg_end(skb, hdr); return 0; } +/** + * nfsd_nl_rpc_status_get_dumpit - Handle rpc_status_get dumpit + * @skb: reply buffer + * @cb: netlink metadata and command arguments + * + * Returns the size of the reply or a negative errno. + */ int nfsd_nl_rpc_status_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) { - return 0; + struct nfsd_net *nn = net_generic(sock_net(skb->sk), nfsd_net_id); + int i, ret, rqstp_index = 0; + + rcu_read_lock(); + + for (i = 0; i < nn->nfsd_serv->sv_nrpools; i++) { + struct svc_rqst *rqstp; + + if (i < cb->args[0]) /* already consumed */ + continue; + + rqstp_index = 0; + list_for_each_entry_rcu(rqstp, + &nn->nfsd_serv->sv_pools[i].sp_all_threads, + rq_all) { + struct nfsd_genl_rqstp genl_rqstp; + unsigned int status_counter; + + if (rqstp_index++ < cb->args[1]) /* already consumed */ + continue; + /* + * Acquire rq_status_counter before parsing the rqst + * fields. rq_status_counter is set to an odd value in + * order to notify the consumers the rqstp fields are + * meaningful. + */ + status_counter = + smp_load_acquire(&rqstp->rq_status_counter); + if (!(status_counter & 1)) + continue; + + genl_rqstp.rq_xid = rqstp->rq_xid; + genl_rqstp.rq_flags = rqstp->rq_flags; + genl_rqstp.rq_vers = rqstp->rq_vers; + genl_rqstp.rq_prog = rqstp->rq_prog; + genl_rqstp.rq_proc = rqstp->rq_proc; + genl_rqstp.rq_stime = rqstp->rq_stime; + genl_rqstp.rq_opcnt = 0; + memcpy(&genl_rqstp.rq_daddr, svc_daddr(rqstp), + sizeof(struct sockaddr)); + memcpy(&genl_rqstp.rq_saddr, svc_addr(rqstp), + sizeof(struct sockaddr)); + +#ifdef CONFIG_NFSD_V4 + if (rqstp->rq_vers == NFS4_VERSION && + rqstp->rq_proc == NFSPROC4_COMPOUND) { + /* NFSv4 compound */ + struct nfsd4_compoundargs *args; + int j; + + args = rqstp->rq_argp; + genl_rqstp.rq_opcnt = args->opcnt; + for (j = 0; j < genl_rqstp.rq_opcnt; j++) + genl_rqstp.rq_opnum[j] = + args->ops[j].opnum; + } +#endif /* CONFIG_NFSD_V4 */ + + /* + * Acquire rq_status_counter before reporting the rqst + * fields to the user. + */ + if (smp_load_acquire(&rqstp->rq_status_counter) != + status_counter) + continue; + + ret = nfsd_genl_rpc_status_compose_msg(skb, cb, + &genl_rqstp); + if (ret) + goto out; + } + } + + cb->args[0] = i; + cb->args[1] = rqstp_index; + ret = skb->len; +out: + rcu_read_unlock(); + + return ret; } +/** + * nfsd_nl_rpc_status_get_done - rpc_status_get dumpit post-processing + * @cb: netlink metadata and command arguments + * + * Return values: + * %0: Success + */ int nfsd_nl_rpc_status_get_done(struct netlink_callback *cb) { + mutex_lock(&nfsd_mutex); + nfsd_put(sock_net(cb->skb->sk)); + mutex_unlock(&nfsd_mutex); + return 0; } @@ -1606,6 +1787,10 @@ static int __init init_nfsd(void) retval = register_filesystem(&nfsd_fs_type); if (retval) goto out_free_all; + retval = genl_register_family(&nfsd_nl_family); + if (retval) + goto out_free_all; + return 0; out_free_all: nfsd4_destroy_laundry_wq(); @@ -1630,6 +1815,7 @@ out_free_slabs: static void __exit exit_nfsd(void) { + genl_unregister_family(&nfsd_nl_family); unregister_filesystem(&nfsd_fs_type); nfsd4_destroy_laundry_wq(); unregister_cld_notifier(); diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 11c14faa6c67..f5ff42f41ee7 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -62,6 +62,23 @@ struct readdir_cd { __be32 err; /* 0, nfserr, or nfserr_eof */ }; +/* Maximum number of operations per session compound */ +#define NFSD_MAX_OPS_PER_COMPOUND 50 + +struct nfsd_genl_rqstp { + struct sockaddr rq_daddr; + struct sockaddr rq_saddr; + unsigned long rq_flags; + ktime_t rq_stime; + __be32 rq_xid; + u32 rq_vers; + u32 rq_prog; + u32 rq_proc; + + /* NFSv4 compound */ + u32 rq_opcnt; + u32 rq_opnum[NFSD_MAX_OPS_PER_COMPOUND]; +}; extern struct svc_program nfsd_program; extern const struct svc_version nfsd_version2, nfsd_version3, nfsd_version4; diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 433154b9eee0..c5890cdfe97b 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -997,6 +997,15 @@ int nfsd_dispatch(struct svc_rqst *rqstp) if (!proc->pc_decode(rqstp, &rqstp->rq_arg_stream)) goto out_decode_err; + /* + * Release rq_status_counter setting it to an odd value after the rpc + * request has been properly parsed. rq_status_counter is used to + * notify the consumers if the rqstp fields are stable + * (rq_status_counter is odd) or not meaningful (rq_status_counter + * is even). + */ + smp_store_release(&rqstp->rq_status_counter, rqstp->rq_status_counter | 1); + rp = NULL; switch (nfsd_cache_lookup(rqstp, &rp)) { case RC_DOIT: @@ -1014,6 +1023,12 @@ int nfsd_dispatch(struct svc_rqst *rqstp) if (!proc->pc_encode(rqstp, &rqstp->rq_res_stream)) goto out_encode_err; + /* + * Release rq_status_counter setting it to an even value after the rpc + * request has been properly processed. + */ + smp_store_release(&rqstp->rq_status_counter, rqstp->rq_status_counter + 1); + nfsd_cache_update(rqstp, rp, rqstp->rq_cachetype, statp + 1); out_cached_reply: return 1; diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 6bbb1d0276b4..f96eaa8e9413 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -195,8 +195,6 @@ static inline struct nfs4_delegation *delegstateid(struct nfs4_stid *s) /* Maximum number of slots per session. 160 is useful for long haul TCP */ #define NFSD_MAX_SLOTS_PER_SESSION 160 -/* Maximum number of operations per session compound */ -#define NFSD_MAX_OPS_PER_COMPOUND 50 /* Maximum session per slot cache size */ #define NFSD_SLOT_CACHE_SIZE 2048 /* Maximum number of NFSD_SLOT_CACHE_SIZE slots per session */ diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index c1feaf0d1542..b10f987509cc 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -251,6 +251,7 @@ struct svc_rqst { * net namespace */ void ** rq_lease_breaker; /* The v4 client breaking a lease */ + unsigned int rq_status_counter; /* RPC processing counter */ }; /* bits for rq_flags */ -- cgit v1.2.3 From 6cc58291408bea96787d06ca3f5074fdfb3152ca Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:56:54 -0400 Subject: NFSD: Add simple u32, u64, and bool encoders The generic XDR encoders return a length or a negative errno. NFSv4 encoders want to know simply whether the encode ran out of stream buffer space. The return values for server-side encoding are either nfs_ok or nfserr_resource. So far I've found it adds a lot of duplicate code to try to use the generic XDR encoder utilities when encoding the simple data types in the NFSv4 operation encoders. Add a set of NFSv4-specific utilities that handle the basic XDR data types. These are added in xdr4.h so they might eventually be used by the callback server and pNFS driver encoders too. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/xdr4.h | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) (limited to 'fs') diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 9d918a79dc16..5c3eb3691f8b 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -50,6 +50,117 @@ #define HAS_CSTATE_FLAG(c, f) ((c)->sid_flags & (f)) #define CLEAR_CSTATE_FLAG(c, f) ((c)->sid_flags &= ~(f)) +/** + * nfsd4_encode_bool - Encode an XDR bool type result + * @xdr: target XDR stream + * @val: boolean value to encode + * + * Return values: + * %nfs_ok: @val encoded; @xdr advanced to next position + * %nfserr_resource: stream buffer space exhausted + */ +static __always_inline __be32 +nfsd4_encode_bool(struct xdr_stream *xdr, bool val) +{ + __be32 *p = xdr_reserve_space(xdr, XDR_UNIT); + + if (unlikely(p == NULL)) + return nfserr_resource; + *p = val ? xdr_one : xdr_zero; + return nfs_ok; +} + +/** + * nfsd4_encode_uint32_t - Encode an XDR uint32_t type result + * @xdr: target XDR stream + * @val: integer value to encode + * + * Return values: + * %nfs_ok: @val encoded; @xdr advanced to next position + * %nfserr_resource: stream buffer space exhausted + */ +static __always_inline __be32 +nfsd4_encode_uint32_t(struct xdr_stream *xdr, u32 val) +{ + __be32 *p = xdr_reserve_space(xdr, XDR_UNIT); + + if (unlikely(p == NULL)) + return nfserr_resource; + *p = cpu_to_be32(val); + return nfs_ok; +} + +/** + * nfsd4_encode_uint64_t - Encode an XDR uint64_t type result + * @xdr: target XDR stream + * @val: integer value to encode + * + * Return values: + * %nfs_ok: @val encoded; @xdr advanced to next position + * %nfserr_resource: stream buffer space exhausted + */ +static __always_inline __be32 +nfsd4_encode_uint64_t(struct xdr_stream *xdr, u64 val) +{ + __be32 *p = xdr_reserve_space(xdr, XDR_UNIT * 2); + + if (unlikely(p == NULL)) + return nfserr_resource; + put_unaligned_be64(val, p); + return nfs_ok; +} + +/** + * nfsd4_encode_opaque_fixed - Encode a fixed-length XDR opaque type result + * @xdr: target XDR stream + * @data: pointer to data + * @size: length of data in bytes + * + * Return values: + * %nfs_ok: @data encoded; @xdr advanced to next position + * %nfserr_resource: stream buffer space exhausted + */ +static __always_inline __be32 +nfsd4_encode_opaque_fixed(struct xdr_stream *xdr, const void *data, + size_t size) +{ + __be32 *p = xdr_reserve_space(xdr, xdr_align_size(size)); + size_t pad = xdr_pad_size(size); + + if (unlikely(p == NULL)) + return nfserr_resource; + memcpy(p, data, size); + if (pad) + memset((char *)p + size, 0, pad); + return nfs_ok; +} + +/** + * nfsd4_encode_opaque - Encode a variable-length XDR opaque type result + * @xdr: target XDR stream + * @data: pointer to data + * @size: length of data in bytes + * + * Return values: + * %nfs_ok: @data encoded; @xdr advanced to next position + * %nfserr_resource: stream buffer space exhausted + */ +static __always_inline __be32 +nfsd4_encode_opaque(struct xdr_stream *xdr, const void *data, size_t size) +{ + size_t pad = xdr_pad_size(size); + __be32 *p; + + p = xdr_reserve_space(xdr, XDR_UNIT + xdr_align_size(size)); + if (unlikely(p == NULL)) + return nfserr_resource; + *p++ = cpu_to_be32(size); + memcpy(p, data, size); + if (pad) + memset((char *)p + size, 0, pad); + return nfs_ok; +} + struct nfsd4_compound_state { struct svc_fh current_fh; struct svc_fh save_fh; -- cgit v1.2.3 From e64301f51b2ab4808180a3fb0731d4ed66836312 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:57:00 -0400 Subject: NFSD: Rename nfsd4_encode_bitmap() For alignment with the specification, the name of NFSD's encoder function should match the name of the XDR type. I've also replaced a few "naked integers" with symbolic constants that better reflect the usage of these values. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 0027c247a481..55a6d1b9da77 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2906,12 +2906,12 @@ static int nfsd4_get_mounted_on_ino(struct svc_export *exp, u64 *pino) } static __be32 -nfsd4_encode_bitmap(struct xdr_stream *xdr, u32 bmval0, u32 bmval1, u32 bmval2) +nfsd4_encode_bitmap4(struct xdr_stream *xdr, u32 bmval0, u32 bmval1, u32 bmval2) { __be32 *p; if (bmval2) { - p = xdr_reserve_space(xdr, 16); + p = xdr_reserve_space(xdr, XDR_UNIT * 4); if (!p) goto out_resource; *p++ = cpu_to_be32(3); @@ -2919,21 +2919,21 @@ nfsd4_encode_bitmap(struct xdr_stream *xdr, u32 bmval0, u32 bmval1, u32 bmval2) *p++ = cpu_to_be32(bmval1); *p++ = cpu_to_be32(bmval2); } else if (bmval1) { - p = xdr_reserve_space(xdr, 12); + p = xdr_reserve_space(xdr, XDR_UNIT * 3); if (!p) goto out_resource; *p++ = cpu_to_be32(2); *p++ = cpu_to_be32(bmval0); *p++ = cpu_to_be32(bmval1); } else { - p = xdr_reserve_space(xdr, 8); + p = xdr_reserve_space(xdr, XDR_UNIT * 2); if (!p) goto out_resource; *p++ = cpu_to_be32(1); *p++ = cpu_to_be32(bmval0); } - return 0; + return nfs_ok; out_resource: return nfserr_resource; } @@ -3049,7 +3049,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, } #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ - status = nfsd4_encode_bitmap(xdr, bmval0, bmval1, bmval2); + status = nfsd4_encode_bitmap4(xdr, bmval0, bmval1, bmval2); if (status) goto out; @@ -3449,7 +3449,7 @@ out_acl: supp[1] &= NFSD_SUPPATTR_EXCLCREAT_WORD1; supp[2] &= NFSD_SUPPATTR_EXCLCREAT_WORD2; - status = nfsd4_encode_bitmap(xdr, supp[0], supp[1], supp[2]); + status = nfsd4_encode_bitmap4(xdr, supp[0], supp[1], supp[2]); if (status) goto out; } @@ -3808,11 +3808,13 @@ nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create = &u->create; struct xdr_stream *xdr = resp->xdr; + /* cinfo */ nfserr = nfsd4_encode_change_info4(xdr, &create->cr_cinfo); if (nfserr) return nfserr; - return nfsd4_encode_bitmap(xdr, create->cr_bmval[0], - create->cr_bmval[1], create->cr_bmval[2]); + /* attrset */ + return nfsd4_encode_bitmap4(xdr, create->cr_bmval[0], + create->cr_bmval[1], create->cr_bmval[2]); } static __be32 @@ -3950,8 +3952,8 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, if (xdr_stream_encode_u32(xdr, open->op_rflags) < 0) return nfserr_resource; - nfserr = nfsd4_encode_bitmap(xdr, open->op_bmval[0], open->op_bmval[1], - open->op_bmval[2]); + nfserr = nfsd4_encode_bitmap4(xdr, open->op_bmval[0], + open->op_bmval[1], open->op_bmval[2]); if (nfserr) return nfserr; @@ -4535,14 +4537,14 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, break; case SP4_MACH_CRED: /* spo_must_enforce bitmap: */ - nfserr = nfsd4_encode_bitmap(xdr, + nfserr = nfsd4_encode_bitmap4(xdr, exid->spo_must_enforce[0], exid->spo_must_enforce[1], exid->spo_must_enforce[2]); if (nfserr) return nfserr; /* spo_must_allow bitmap: */ - nfserr = nfsd4_encode_bitmap(xdr, + nfserr = nfsd4_encode_bitmap4(xdr, exid->spo_must_allow[0], exid->spo_must_allow[1], exid->spo_must_allow[2]); -- cgit v1.2.3 From c3dcb45bcd071ae86821bfff428cd3b1ac38e6f0 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:57:07 -0400 Subject: NFSD: Clean up nfsd4_encode_setattr() De-duplicate the encoding of bitmap4 results in nfsd4_encode_setattr(). Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 55a6d1b9da77..df2383fbd0e7 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4433,34 +4433,25 @@ nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr, return nfsd4_do_encode_secinfo(xdr, secinfo->sin_exp); } -/* - * The SETATTR encode routine is special -- it always encodes a bitmap, - * regardless of the error status. - */ static __be32 nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, union nfsd4_op_u *u) { struct nfsd4_setattr *setattr = &u->setattr; - struct xdr_stream *xdr = resp->xdr; - __be32 *p; + __be32 status; - p = xdr_reserve_space(xdr, 16); - if (!p) - return nfserr_resource; - if (nfserr) { - *p++ = cpu_to_be32(3); - *p++ = cpu_to_be32(0); - *p++ = cpu_to_be32(0); - *p++ = cpu_to_be32(0); - } - else { - *p++ = cpu_to_be32(3); - *p++ = cpu_to_be32(setattr->sa_bmval[0]); - *p++ = cpu_to_be32(setattr->sa_bmval[1]); - *p++ = cpu_to_be32(setattr->sa_bmval[2]); + switch (nfserr) { + case nfs_ok: + /* attrsset */ + status = nfsd4_encode_bitmap4(resp->xdr, setattr->sa_bmval[0], + setattr->sa_bmval[1], + setattr->sa_bmval[2]); + break; + default: + /* attrsset */ + status = nfsd4_encode_bitmap4(resp->xdr, 0, 0, 0); } - return nfserr; + return status != nfs_ok ? status : nfserr; } static __be32 -- cgit v1.2.3 From 83ab8678ad0c6f27594c716cafe59c8bbd5e49ef Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:57:13 -0400 Subject: NFSD: Add struct nfsd4_fattr_args I'm about to split nfsd4_encode_fattr() into a number of smaller functions. Instead of passing a large number of arguments to each of the smaller functions, create a struct that can gather the common argument variables into something with a convenient handle on it. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 117 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 52 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index df2383fbd0e7..c77735989534 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2938,6 +2938,16 @@ out_resource: return nfserr_resource; } +struct nfsd4_fattr_args { + struct svc_fh *fhp; + struct kstat stat; + struct kstatfs statfs; + struct nfs4_acl *acl; + u64 size; + u32 rdattr_err; + bool contextsupport; +}; + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -2948,26 +2958,22 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, struct dentry *dentry, u32 *bmval, struct svc_rqst *rqstp, int ignore_crossmnt) { + struct nfsd4_fattr_args args; u32 bmval0 = bmval[0]; u32 bmval1 = bmval[1]; u32 bmval2 = bmval[2]; - struct kstat stat; struct svc_fh *tempfh = NULL; - struct kstatfs statfs; __be32 *p, *attrlen_p; int starting_len = xdr->buf->len; int attrlen_offset; u32 dummy; u64 dummy64; - u32 rdattr_err = 0; __be32 status; int err; - struct nfs4_acl *acl = NULL; #ifdef CONFIG_NFSD_V4_SECURITY_LABEL void *context = NULL; int contextlen; #endif - bool contextsupport = false; struct nfsd4_compoundres *resp = rqstp->rq_resp; u32 minorversion = resp->cstate.minorversion; struct path path = { @@ -2981,11 +2987,14 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1); BUG_ON(!nfsd_attrs_supported(minorversion, bmval)); + args.rdattr_err = 0; if (exp->ex_fslocs.migrated) { - status = fattr_handle_absent_fs(&bmval0, &bmval1, &bmval2, &rdattr_err); + status = fattr_handle_absent_fs(&bmval0, &bmval1, &bmval2, + &args.rdattr_err); if (status) goto out; } + args.size = 0; if (bmval0 & (FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE)) { status = nfsd4_deleg_getattr_conflict(rqstp, d_inode(dentry), &file_modified, &size); @@ -2993,19 +3002,21 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } - err = vfs_getattr(&path, &stat, + err = vfs_getattr(&path, &args.stat, STATX_BASIC_STATS | STATX_BTIME | STATX_CHANGE_COOKIE, AT_STATX_SYNC_AS_STAT); if (err) goto out_nfserr; - if (!(stat.result_mask & STATX_BTIME)) + args.size = file_modified ? size : args.stat.size; + + if (!(args.stat.result_mask & STATX_BTIME)) /* underlying FS does not offer btime so we can't share it */ bmval1 &= ~FATTR4_WORD1_TIME_CREATE; if ((bmval0 & (FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_MAXNAME)) || (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL))) { - err = vfs_statfs(&path, &statfs); + err = vfs_statfs(&path, &args.statfs); if (err) goto out_nfserr; } @@ -3018,10 +3029,13 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, status = fh_compose(tempfh, exp, dentry, NULL); if (status) goto out; - fhp = tempfh; - } + args.fhp = tempfh; + } else + args.fhp = fhp; + + args.acl = NULL; if (bmval0 & FATTR4_WORD0_ACL) { - err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl); + err = nfsd4_get_nfs4_acl(rqstp, dentry, &args.acl); if (err == -EOPNOTSUPP) bmval0 &= ~FATTR4_WORD0_ACL; else if (err == -EINVAL) { @@ -3031,6 +3045,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out_nfserr; } + args.contextsupport = false; + #ifdef CONFIG_NFSD_V4_SECURITY_LABEL if ((bmval2 & FATTR4_WORD2_SECURITY_LABEL) || bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) { @@ -3039,7 +3055,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, &context, &contextlen); else err = -EOPNOTSUPP; - contextsupport = (err == 0); + args.contextsupport = (err == 0); if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { if (err == -EOPNOTSUPP) bmval2 &= ~FATTR4_WORD2_SECURITY_LABEL; @@ -3065,7 +3081,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, if (!IS_POSIXACL(dentry->d_inode)) supp[0] &= ~FATTR4_WORD0_ACL; - if (!contextsupport) + if (!args.contextsupport) supp[2] &= ~FATTR4_WORD2_SECURITY_LABEL; if (!supp[2]) { p = xdr_reserve_space(xdr, 12); @@ -3088,7 +3104,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, p = xdr_reserve_space(xdr, 4); if (!p) goto out_resource; - dummy = nfs4_file_type(stat.mode); + dummy = nfs4_file_type(args.stat.mode); if (dummy == NF4BAD) { status = nfserr_serverfault; goto out; @@ -3109,16 +3125,13 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, p = xdr_reserve_space(xdr, 8); if (!p) goto out_resource; - p = encode_change(p, &stat, d_inode(dentry), exp); + p = encode_change(p, &args.stat, d_inode(dentry), exp); } if (bmval0 & FATTR4_WORD0_SIZE) { p = xdr_reserve_space(xdr, 8); if (!p) goto out_resource; - if (file_modified) - p = xdr_encode_hyper(p, size); - else - p = xdr_encode_hyper(p, stat.size); + p = xdr_encode_hyper(p, args.size); } if (bmval0 & FATTR4_WORD0_LINK_SUPPORT) { p = xdr_reserve_space(xdr, 4); @@ -3145,16 +3158,16 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, if (exp->ex_fslocs.migrated) { p = xdr_encode_hyper(p, NFS4_REFERRAL_FSID_MAJOR); p = xdr_encode_hyper(p, NFS4_REFERRAL_FSID_MINOR); - } else switch(fsid_source(fhp)) { + } else switch (fsid_source(args.fhp)) { case FSIDSOURCE_FSID: p = xdr_encode_hyper(p, (u64)exp->ex_fsid); p = xdr_encode_hyper(p, (u64)0); break; case FSIDSOURCE_DEV: *p++ = cpu_to_be32(0); - *p++ = cpu_to_be32(MAJOR(stat.dev)); + *p++ = cpu_to_be32(MAJOR(args.stat.dev)); *p++ = cpu_to_be32(0); - *p++ = cpu_to_be32(MINOR(stat.dev)); + *p++ = cpu_to_be32(MINOR(args.stat.dev)); break; case FSIDSOURCE_UUID: p = xdr_encode_opaque_fixed(p, exp->ex_uuid, @@ -3178,12 +3191,12 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, p = xdr_reserve_space(xdr, 4); if (!p) goto out_resource; - *p++ = cpu_to_be32(rdattr_err); + *p++ = cpu_to_be32(args.rdattr_err); } if (bmval0 & FATTR4_WORD0_ACL) { struct nfs4_ace *ace; - if (acl == NULL) { + if (args.acl == NULL) { p = xdr_reserve_space(xdr, 4); if (!p) goto out_resource; @@ -3194,9 +3207,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, p = xdr_reserve_space(xdr, 4); if (!p) goto out_resource; - *p++ = cpu_to_be32(acl->naces); + *p++ = cpu_to_be32(args.acl->naces); - for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) { + for (ace = args.acl->aces; ace < args.acl->aces + args.acl->naces; ace++) { p = xdr_reserve_space(xdr, 4*3); if (!p) goto out_resource; @@ -3242,35 +3255,35 @@ out_acl: *p++ = cpu_to_be32(1); } if (bmval0 & FATTR4_WORD0_FILEHANDLE) { - p = xdr_reserve_space(xdr, fhp->fh_handle.fh_size + 4); + p = xdr_reserve_space(xdr, args.fhp->fh_handle.fh_size + 4); if (!p) goto out_resource; - p = xdr_encode_opaque(p, &fhp->fh_handle.fh_raw, - fhp->fh_handle.fh_size); + p = xdr_encode_opaque(p, &args.fhp->fh_handle.fh_raw, + args.fhp->fh_handle.fh_size); } if (bmval0 & FATTR4_WORD0_FILEID) { p = xdr_reserve_space(xdr, 8); if (!p) goto out_resource; - p = xdr_encode_hyper(p, stat.ino); + p = xdr_encode_hyper(p, args.stat.ino); } if (bmval0 & FATTR4_WORD0_FILES_AVAIL) { p = xdr_reserve_space(xdr, 8); if (!p) goto out_resource; - p = xdr_encode_hyper(p, (u64) statfs.f_ffree); + p = xdr_encode_hyper(p, (u64) args.statfs.f_ffree); } if (bmval0 & FATTR4_WORD0_FILES_FREE) { p = xdr_reserve_space(xdr, 8); if (!p) goto out_resource; - p = xdr_encode_hyper(p, (u64) statfs.f_ffree); + p = xdr_encode_hyper(p, (u64) args.statfs.f_ffree); } if (bmval0 & FATTR4_WORD0_FILES_TOTAL) { p = xdr_reserve_space(xdr, 8); if (!p) goto out_resource; - p = xdr_encode_hyper(p, (u64) statfs.f_files); + p = xdr_encode_hyper(p, (u64) args.statfs.f_files); } if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) { status = nfsd4_encode_fs_locations(xdr, rqstp, exp); @@ -3299,7 +3312,7 @@ out_acl: p = xdr_reserve_space(xdr, 4); if (!p) goto out_resource; - *p++ = cpu_to_be32(statfs.f_namelen); + *p++ = cpu_to_be32(args.statfs.f_namelen); } if (bmval0 & FATTR4_WORD0_MAXREAD) { p = xdr_reserve_space(xdr, 8); @@ -3317,7 +3330,7 @@ out_acl: p = xdr_reserve_space(xdr, 4); if (!p) goto out_resource; - *p++ = cpu_to_be32(stat.mode & S_IALLUGO); + *p++ = cpu_to_be32(args.stat.mode & S_IALLUGO); } if (bmval1 & FATTR4_WORD1_NO_TRUNC) { p = xdr_reserve_space(xdr, 4); @@ -3329,15 +3342,15 @@ out_acl: p = xdr_reserve_space(xdr, 4); if (!p) goto out_resource; - *p++ = cpu_to_be32(stat.nlink); + *p++ = cpu_to_be32(args.stat.nlink); } if (bmval1 & FATTR4_WORD1_OWNER) { - status = nfsd4_encode_user(xdr, rqstp, stat.uid); + status = nfsd4_encode_user(xdr, rqstp, args.stat.uid); if (status) goto out; } if (bmval1 & FATTR4_WORD1_OWNER_GROUP) { - status = nfsd4_encode_group(xdr, rqstp, stat.gid); + status = nfsd4_encode_group(xdr, rqstp, args.stat.gid); if (status) goto out; } @@ -3345,44 +3358,44 @@ out_acl: p = xdr_reserve_space(xdr, 8); if (!p) goto out_resource; - *p++ = cpu_to_be32((u32) MAJOR(stat.rdev)); - *p++ = cpu_to_be32((u32) MINOR(stat.rdev)); + *p++ = cpu_to_be32((u32) MAJOR(args.stat.rdev)); + *p++ = cpu_to_be32((u32) MINOR(args.stat.rdev)); } if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) { p = xdr_reserve_space(xdr, 8); if (!p) goto out_resource; - dummy64 = (u64)statfs.f_bavail * (u64)statfs.f_bsize; + dummy64 = (u64)args.statfs.f_bavail * (u64)args.statfs.f_bsize; p = xdr_encode_hyper(p, dummy64); } if (bmval1 & FATTR4_WORD1_SPACE_FREE) { p = xdr_reserve_space(xdr, 8); if (!p) goto out_resource; - dummy64 = (u64)statfs.f_bfree * (u64)statfs.f_bsize; + dummy64 = (u64)args.statfs.f_bfree * (u64)args.statfs.f_bsize; p = xdr_encode_hyper(p, dummy64); } if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) { p = xdr_reserve_space(xdr, 8); if (!p) goto out_resource; - dummy64 = (u64)statfs.f_blocks * (u64)statfs.f_bsize; + dummy64 = (u64)args.statfs.f_blocks * (u64)args.statfs.f_bsize; p = xdr_encode_hyper(p, dummy64); } if (bmval1 & FATTR4_WORD1_SPACE_USED) { p = xdr_reserve_space(xdr, 8); if (!p) goto out_resource; - dummy64 = (u64)stat.blocks << 9; + dummy64 = (u64)args.stat.blocks << 9; p = xdr_encode_hyper(p, dummy64); } if (bmval1 & FATTR4_WORD1_TIME_ACCESS) { - status = nfsd4_encode_nfstime4(xdr, &stat.atime); + status = nfsd4_encode_nfstime4(xdr, &args.stat.atime); if (status) goto out; } if (bmval1 & FATTR4_WORD1_TIME_CREATE) { - status = nfsd4_encode_nfstime4(xdr, &stat.btime); + status = nfsd4_encode_nfstime4(xdr, &args.stat.btime); if (status) goto out; } @@ -3393,17 +3406,17 @@ out_acl: p = encode_time_delta(p, d_inode(dentry)); } if (bmval1 & FATTR4_WORD1_TIME_METADATA) { - status = nfsd4_encode_nfstime4(xdr, &stat.ctime); + status = nfsd4_encode_nfstime4(xdr, &args.stat.ctime); if (status) goto out; } if (bmval1 & FATTR4_WORD1_TIME_MODIFY) { - status = nfsd4_encode_nfstime4(xdr, &stat.mtime); + status = nfsd4_encode_nfstime4(xdr, &args.stat.mtime); if (status) goto out; } if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { - u64 ino = stat.ino; + u64 ino = args.stat.ino; p = xdr_reserve_space(xdr, 8); if (!p) @@ -3438,7 +3451,7 @@ out_acl: p = xdr_reserve_space(xdr, 4); if (!p) goto out_resource; - *p++ = cpu_to_be32(stat.blksize); + *p++ = cpu_to_be32(args.stat.blksize); } #endif /* CONFIG_NFSD_PNFS */ if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { @@ -3479,7 +3492,7 @@ out: if (context) security_release_secctx(context, contextlen); #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ - kfree(acl); + kfree(args.acl); if (tempfh) { fh_put(tempfh); kfree(tempfh); -- cgit v1.2.3 From c88cb4727a77220ba2bc8f09aa01ec2aeb0be033 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:57:19 -0400 Subject: NFSD: Add nfsd4_encode_fattr4__true() Add an encoding helper that encodes a single boolean "true" value. Attributes that always return "true" can use this helper. In a subsequent patch, this helper will be called from a bitmask loop, so it is given a standardized synopsis. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 55 +++++++++++++++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 28 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index c77735989534..4b0e2966aa12 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2948,6 +2948,12 @@ struct nfsd4_fattr_args { bool contextsupport; }; +static __be32 nfsd4_encode_fattr4__true(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_bool(xdr, true); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3134,16 +3140,14 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, p = xdr_encode_hyper(p, args.size); } if (bmval0 & FATTR4_WORD0_LINK_SUPPORT) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(1); + status = nfsd4_encode_fattr4__true(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_SYMLINK_SUPPORT) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(1); + status = nfsd4_encode_fattr4__true(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_NAMED_ATTR) { p = xdr_reserve_space(xdr, 4); @@ -3231,10 +3235,9 @@ out_acl: ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL : 0); } if (bmval0 & FATTR4_WORD0_CANSETTIME) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(1); + status = nfsd4_encode_fattr4__true(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_CASE_INSENSITIVE) { p = xdr_reserve_space(xdr, 4); @@ -3243,16 +3246,14 @@ out_acl: *p++ = cpu_to_be32(0); } if (bmval0 & FATTR4_WORD0_CASE_PRESERVING) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(1); + status = nfsd4_encode_fattr4__true(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_CHOWN_RESTRICTED) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(1); + status = nfsd4_encode_fattr4__true(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_FILEHANDLE) { p = xdr_reserve_space(xdr, args.fhp->fh_handle.fh_size + 4); @@ -3291,10 +3292,9 @@ out_acl: goto out; } if (bmval0 & FATTR4_WORD0_HOMOGENEOUS) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(1); + status = nfsd4_encode_fattr4__true(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_MAXFILESIZE) { p = xdr_reserve_space(xdr, 8); @@ -3333,10 +3333,9 @@ out_acl: *p++ = cpu_to_be32(args.stat.mode & S_IALLUGO); } if (bmval1 & FATTR4_WORD1_NO_TRUNC) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(1); + status = nfsd4_encode_fattr4__true(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval1 & FATTR4_WORD1_NUMLINKS) { p = xdr_reserve_space(xdr, 4); -- cgit v1.2.3 From 8c4422881f73d77a259352e0e93b7bdaf172768a Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:57:26 -0400 Subject: NFSD: Add nfsd4_encode_fattr4__false() Add an encoding helper that encodes a single boolean "false" value. Attributes that always return "false" can use this helper. In a subsequent patch, this helper will be called from a bitmask loop, so it is given a standardized synopsis. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 4b0e2966aa12..3160628ae0e4 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2954,6 +2954,12 @@ static __be32 nfsd4_encode_fattr4__true(struct xdr_stream *xdr, return nfsd4_encode_bool(xdr, true); } +static __be32 nfsd4_encode_fattr4__false(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_bool(xdr, false); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3150,10 +3156,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & FATTR4_WORD0_NAMED_ATTR) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(0); + status = nfsd4_encode_fattr4__false(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_FSID) { p = xdr_reserve_space(xdr, 16); @@ -3180,10 +3185,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, } } if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(0); + status = nfsd4_encode_fattr4__false(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_LEASE_TIME) { p = xdr_reserve_space(xdr, 4); @@ -3240,10 +3244,9 @@ out_acl: goto out; } if (bmval0 & FATTR4_WORD0_CASE_INSENSITIVE) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(0); + status = nfsd4_encode_fattr4__false(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_CASE_PRESERVING) { status = nfsd4_encode_fattr4__true(xdr, &args); -- cgit v1.2.3 From c9090e273300cd30dff05ce870a4c18f476a2f32 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:57:32 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_supported_attrs() Refactor the encoder for FATTR4_SUPPORTED_ATTRS into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 3160628ae0e4..c8fbfc175dab 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2939,7 +2939,9 @@ out_resource: } struct nfsd4_fattr_args { + struct svc_rqst *rqstp; struct svc_fh *fhp; + struct dentry *dentry; struct kstat stat; struct kstatfs statfs; struct nfs4_acl *acl; @@ -2960,6 +2962,22 @@ static __be32 nfsd4_encode_fattr4__false(struct xdr_stream *xdr, return nfsd4_encode_bool(xdr, false); } +static __be32 nfsd4_encode_fattr4_supported_attrs(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + struct nfsd4_compoundres *resp = args->rqstp->rq_resp; + u32 minorversion = resp->cstate.minorversion; + u32 supp[3]; + + memcpy(supp, nfsd_suppattrs[minorversion], sizeof(supp)); + if (!IS_POSIXACL(d_inode(args->dentry))) + supp[0] &= ~FATTR4_WORD0_ACL; + if (!args->contextsupport) + supp[2] &= ~FATTR4_WORD2_SECURITY_LABEL; + + return nfsd4_encode_bitmap4(xdr, supp[0], supp[1], supp[2]); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -2999,6 +3017,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1); BUG_ON(!nfsd_attrs_supported(minorversion, bmval)); + args.rqstp = rqstp; + args.dentry = dentry; + args.rdattr_err = 0; if (exp->ex_fslocs.migrated) { status = fattr_handle_absent_fs(&bmval0, &bmval1, &bmval2, @@ -3087,30 +3108,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out_resource; if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) { - u32 supp[3]; - - memcpy(supp, nfsd_suppattrs[minorversion], sizeof(supp)); - - if (!IS_POSIXACL(dentry->d_inode)) - supp[0] &= ~FATTR4_WORD0_ACL; - if (!args.contextsupport) - supp[2] &= ~FATTR4_WORD2_SECURITY_LABEL; - if (!supp[2]) { - p = xdr_reserve_space(xdr, 12); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(2); - *p++ = cpu_to_be32(supp[0]); - *p++ = cpu_to_be32(supp[1]); - } else { - p = xdr_reserve_space(xdr, 16); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(3); - *p++ = cpu_to_be32(supp[0]); - *p++ = cpu_to_be32(supp[1]); - *p++ = cpu_to_be32(supp[2]); - } + status = nfsd4_encode_fattr4_supported_attrs(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_TYPE) { p = xdr_reserve_space(xdr, 4); -- cgit v1.2.3 From b06cf3754523682ff92fbc0f7702c32a024a4819 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:57:39 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_type() Refactor the encoder for FATTR4_TYPE into a helper. In a subsequent patch, this helper will be called from a bitmask loop. In addition, restructure the code so that byte-swapping is done on constant values rather than at run time. Run-time swapping can be costly on some platforms, and "type" is a frequently-requested attribute. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 63 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 23 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index c8fbfc175dab..55fa9f69c1e6 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2792,20 +2792,6 @@ static __be32 nfsd4_encode_fs_locations(struct xdr_stream *xdr, return 0; } -static u32 nfs4_file_type(umode_t mode) -{ - switch (mode & S_IFMT) { - case S_IFIFO: return NF4FIFO; - case S_IFCHR: return NF4CHR; - case S_IFDIR: return NF4DIR; - case S_IFBLK: return NF4BLK; - case S_IFLNK: return NF4LNK; - case S_IFREG: return NF4REG; - case S_IFSOCK: return NF4SOCK; - default: return NF4BAD; - } -} - static inline __be32 nfsd4_encode_aclname(struct xdr_stream *xdr, struct svc_rqst *rqstp, struct nfs4_ace *ace) @@ -2978,6 +2964,44 @@ static __be32 nfsd4_encode_fattr4_supported_attrs(struct xdr_stream *xdr, return nfsd4_encode_bitmap4(xdr, supp[0], supp[1], supp[2]); } +static __be32 nfsd4_encode_fattr4_type(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + __be32 *p; + + p = xdr_reserve_space(xdr, XDR_UNIT); + if (!p) + return nfserr_resource; + + switch (args->stat.mode & S_IFMT) { + case S_IFIFO: + *p = cpu_to_be32(NF4FIFO); + break; + case S_IFCHR: + *p = cpu_to_be32(NF4CHR); + break; + case S_IFDIR: + *p = cpu_to_be32(NF4DIR); + break; + case S_IFBLK: + *p = cpu_to_be32(NF4BLK); + break; + case S_IFLNK: + *p = cpu_to_be32(NF4LNK); + break; + case S_IFREG: + *p = cpu_to_be32(NF4REG); + break; + case S_IFSOCK: + *p = cpu_to_be32(NF4SOCK); + break; + default: + return nfserr_serverfault; + } + + return nfs_ok; +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -2996,7 +3020,6 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, __be32 *p, *attrlen_p; int starting_len = xdr->buf->len; int attrlen_offset; - u32 dummy; u64 dummy64; __be32 status; int err; @@ -3113,15 +3136,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & FATTR4_WORD0_TYPE) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - dummy = nfs4_file_type(args.stat.mode); - if (dummy == NF4BAD) { - status = nfserr_serverfault; + status = nfsd4_encode_fattr4_type(xdr, &args); + if (status != nfs_ok) goto out; - } - *p++ = cpu_to_be32(dummy); } if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) { p = xdr_reserve_space(xdr, 4); -- cgit v1.2.3 From 36ed7e64947756baa69cfad323898b342bf71a02 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:57:45 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_fh_expire_type() Refactor the encoder for FATTR4_FH_EXPIRE_TYPE into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 55fa9f69c1e6..622f74b36d5e 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2927,6 +2927,7 @@ out_resource: struct nfsd4_fattr_args { struct svc_rqst *rqstp; struct svc_fh *fhp; + struct svc_export *exp; struct dentry *dentry; struct kstat stat; struct kstatfs statfs; @@ -3002,6 +3003,17 @@ static __be32 nfsd4_encode_fattr4_type(struct xdr_stream *xdr, return nfs_ok; } +static __be32 nfsd4_encode_fattr4_fh_expire_type(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + u32 mask; + + mask = NFS4_FH_PERSISTENT; + if (!(args->exp->ex_flags & NFSEXP_NOSUBTREECHECK)) + mask |= NFS4_FH_VOL_RENAME; + return nfsd4_encode_uint32_t(xdr, mask); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3041,6 +3053,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, BUG_ON(!nfsd_attrs_supported(minorversion, bmval)); args.rqstp = rqstp; + args.exp = exp; args.dentry = dentry; args.rdattr_err = 0; @@ -3141,14 +3154,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - if (exp->ex_flags & NFSEXP_NOSUBTREECHECK) - *p++ = cpu_to_be32(NFS4_FH_PERSISTENT); - else - *p++ = cpu_to_be32(NFS4_FH_PERSISTENT| - NFS4_FH_VOL_RENAME); + status = nfsd4_encode_fattr4_fh_expire_type(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_CHANGE) { p = xdr_reserve_space(xdr, 8); -- cgit v1.2.3 From 263453d9bb46ad42f03a0f86aafe580f1b0e9291 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:57:51 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_change() Refactor the encoder for FATTR4_CHANGE into a helper. In a subsequent patch, this helper will be called from a bitmask loop. The code is restructured a bit to use the modern xdr_stream flow, and the encoded cinfo value is made const so that callers of the encoders can be passed a const cinfo. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 56 ++++++++++++++++++++++++++++-------------------- fs/nfsd/nfsfh.c | 2 +- fs/nfsd/nfsfh.h | 3 ++- fs/nfsd/xdr4.h | 2 ++ include/linux/iversion.h | 2 +- 5 files changed, 39 insertions(+), 26 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 622f74b36d5e..c557d8ac0d38 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2530,17 +2530,6 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) return true; } -static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode, - struct svc_export *exp) -{ - if (exp->ex_flags & NFSEXP_V4ROOT) { - *p++ = cpu_to_be32(convert_to_wallclock(exp->cd->flush_time)); - *p++ = 0; - } else - p = xdr_encode_hyper(p, nfsd4_change_attribute(stat, inode)); - return p; -} - static __be32 nfsd4_encode_nfstime4(struct xdr_stream *xdr, struct timespec64 *tv) { @@ -2581,15 +2570,17 @@ static __be32 *encode_time_delta(__be32 *p, struct inode *inode) } static __be32 -nfsd4_encode_change_info4(struct xdr_stream *xdr, struct nfsd4_change_info *c) +nfsd4_encode_change_info4(struct xdr_stream *xdr, const struct nfsd4_change_info *c) { - if (xdr_stream_encode_bool(xdr, c->atomic) < 0) - return nfserr_resource; - if (xdr_stream_encode_u64(xdr, c->before_change) < 0) - return nfserr_resource; - if (xdr_stream_encode_u64(xdr, c->after_change) < 0) - return nfserr_resource; - return nfs_ok; + __be32 status; + + status = nfsd4_encode_bool(xdr, c->atomic); + if (status != nfs_ok) + return status; + status = nfsd4_encode_changeid4(xdr, c->before_change); + if (status != nfs_ok) + return status; + return nfsd4_encode_changeid4(xdr, c->after_change); } /* Encode as an array of strings the string given with components @@ -3014,6 +3005,26 @@ static __be32 nfsd4_encode_fattr4_fh_expire_type(struct xdr_stream *xdr, return nfsd4_encode_uint32_t(xdr, mask); } +static __be32 nfsd4_encode_fattr4_change(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + const struct svc_export *exp = args->exp; + u64 c; + + if (unlikely(exp->ex_flags & NFSEXP_V4ROOT)) { + u32 flush_time = convert_to_wallclock(exp->cd->flush_time); + + if (xdr_stream_encode_u32(xdr, flush_time) != XDR_UNIT) + return nfserr_resource; + if (xdr_stream_encode_u32(xdr, 0) != XDR_UNIT) + return nfserr_resource; + return nfs_ok; + } + + c = nfsd4_change_attribute(&args->stat, d_inode(args->dentry)); + return nfsd4_encode_changeid4(xdr, c); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3159,10 +3170,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & FATTR4_WORD0_CHANGE) { - p = xdr_reserve_space(xdr, 8); - if (!p) - goto out_resource; - p = encode_change(p, &args.stat, d_inode(dentry), exp); + status = nfsd4_encode_fattr4_change(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_SIZE) { p = xdr_reserve_space(xdr, 8); diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 355bf0db3235..dbfa0ac13564 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -771,7 +771,7 @@ enum fsid_source fsid_source(const struct svc_fh *fhp) * assume that the new change attr is always logged to stable storage in some * fashion before the results can be seen. */ -u64 nfsd4_change_attribute(struct kstat *stat, struct inode *inode) +u64 nfsd4_change_attribute(const struct kstat *stat, const struct inode *inode) { u64 chattr; diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h index 40426f899e76..6ebdf7ea27bf 100644 --- a/fs/nfsd/nfsfh.h +++ b/fs/nfsd/nfsfh.h @@ -293,7 +293,8 @@ static inline void fh_clear_pre_post_attrs(struct svc_fh *fhp) fhp->fh_pre_saved = false; } -u64 nfsd4_change_attribute(struct kstat *stat, struct inode *inode); +u64 nfsd4_change_attribute(const struct kstat *stat, + const struct inode *inode); __be32 __must_check fh_fill_pre_attrs(struct svc_fh *fhp); __be32 fh_fill_post_attrs(struct svc_fh *fhp); __be32 __must_check fh_fill_both_attrs(struct svc_fh *fhp); diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 5c3eb3691f8b..d6059b0549f5 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -110,6 +110,8 @@ nfsd4_encode_uint64_t(struct xdr_stream *xdr, u64 val) return nfs_ok; } +#define nfsd4_encode_changeid4(x, v) nfsd4_encode_uint64_t(x, v) + /** * nfsd4_encode_opaque_fixed - Encode a fixed-length XDR opaque type result * @xdr: target XDR stream diff --git a/include/linux/iversion.h b/include/linux/iversion.h index f174ff1b59ee..8f972eaca2ed 100644 --- a/include/linux/iversion.h +++ b/include/linux/iversion.h @@ -256,7 +256,7 @@ inode_peek_iversion(const struct inode *inode) * For filesystems without any sort of change attribute, the best we can * do is fake one up from the ctime: */ -static inline u64 time_to_chattr(struct timespec64 *t) +static inline u64 time_to_chattr(const struct timespec64 *t) { u64 chattr = t->tv_sec; -- cgit v1.2.3 From d0b28aadfd8d0836a9d9f6f9665925897e5223cb Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:57:58 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_size() Refactor the encoder for FATTR4_SIZE into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index c557d8ac0d38..d08e0dbe3dd4 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3025,6 +3025,12 @@ static __be32 nfsd4_encode_fattr4_change(struct xdr_stream *xdr, return nfsd4_encode_changeid4(xdr, c); } +static __be32 nfsd4_encode_fattr4_size(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_uint64_t(xdr, args->size); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3175,10 +3181,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & FATTR4_WORD0_SIZE) { - p = xdr_reserve_space(xdr, 8); - if (!p) - goto out_resource; - p = xdr_encode_hyper(p, args.size); + status = nfsd4_encode_fattr4_size(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_LINK_SUPPORT) { status = nfsd4_encode_fattr4__true(xdr, &args); -- cgit v1.2.3 From b6b6259590c5f6d1b2480285d4d5bc8e907caf8f Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:58:04 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_fsid() Refactor the encoder for FATTR4_FSID into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 58 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 22 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index d08e0dbe3dd4..aa3081ef65c5 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3031,6 +3031,39 @@ static __be32 nfsd4_encode_fattr4_size(struct xdr_stream *xdr, return nfsd4_encode_uint64_t(xdr, args->size); } +static __be32 nfsd4_encode_fattr4_fsid(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + __be32 *p; + + p = xdr_reserve_space(xdr, XDR_UNIT * 2 + XDR_UNIT * 2); + if (!p) + return nfserr_resource; + + if (unlikely(args->exp->ex_fslocs.migrated)) { + p = xdr_encode_hyper(p, NFS4_REFERRAL_FSID_MAJOR); + xdr_encode_hyper(p, NFS4_REFERRAL_FSID_MINOR); + return nfs_ok; + } + switch (fsid_source(args->fhp)) { + case FSIDSOURCE_FSID: + p = xdr_encode_hyper(p, (u64)args->exp->ex_fsid); + xdr_encode_hyper(p, (u64)0); + break; + case FSIDSOURCE_DEV: + *p++ = xdr_zero; + *p++ = cpu_to_be32(MAJOR(args->stat.dev)); + *p++ = xdr_zero; + *p = cpu_to_be32(MINOR(args->stat.dev)); + break; + case FSIDSOURCE_UUID: + xdr_encode_opaque_fixed(p, args->exp->ex_uuid, EX_UUID_LEN); + break; + } + + return nfs_ok; +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3201,28 +3234,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & FATTR4_WORD0_FSID) { - p = xdr_reserve_space(xdr, 16); - if (!p) - goto out_resource; - if (exp->ex_fslocs.migrated) { - p = xdr_encode_hyper(p, NFS4_REFERRAL_FSID_MAJOR); - p = xdr_encode_hyper(p, NFS4_REFERRAL_FSID_MINOR); - } else switch (fsid_source(args.fhp)) { - case FSIDSOURCE_FSID: - p = xdr_encode_hyper(p, (u64)exp->ex_fsid); - p = xdr_encode_hyper(p, (u64)0); - break; - case FSIDSOURCE_DEV: - *p++ = cpu_to_be32(0); - *p++ = cpu_to_be32(MAJOR(args.stat.dev)); - *p++ = cpu_to_be32(0); - *p++ = cpu_to_be32(MINOR(args.stat.dev)); - break; - case FSIDSOURCE_UUID: - p = xdr_encode_opaque_fixed(p, exp->ex_uuid, - EX_UUID_LEN); - break; - } + status = nfsd4_encode_fattr4_fsid(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) { status = nfsd4_encode_fattr4__false(xdr, &args); -- cgit v1.2.3 From 1252b283aae2b131f6d38fdff8792dfe9d4a536e Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:58:10 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_lease_time() Refactor the encoder for FATTR4_LEASE_TIME into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 16 +++++++++++----- fs/nfsd/xdr4.h | 2 ++ 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index aa3081ef65c5..308f0316b63f 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3064,6 +3064,14 @@ static __be32 nfsd4_encode_fattr4_fsid(struct xdr_stream *xdr, return nfs_ok; } +static __be32 nfsd4_encode_fattr4_lease_time(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + struct nfsd_net *nn = net_generic(SVC_NET(args->rqstp), nfsd_net_id); + + return nfsd4_encode_nfs_lease4(xdr, nn->nfsd4_lease); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3095,7 +3103,6 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, .mnt = exp->ex_path.mnt, .dentry = dentry, }; - struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); bool file_modified; u64 size = 0; @@ -3244,10 +3251,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & FATTR4_WORD0_LEASE_TIME) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(nn->nfsd4_lease); + status = nfsd4_encode_fattr4_lease_time(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) { p = xdr_reserve_space(xdr, 4); diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index d6059b0549f5..488ecdacc4c6 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -90,6 +90,8 @@ nfsd4_encode_uint32_t(struct xdr_stream *xdr, u32 val) return nfs_ok; } +#define nfsd4_encode_nfs_lease4(x, v) nfsd4_encode_uint32_t(x, v) + /** * nfsd4_encode_uint64_t - Encode an XDR uint64_t type result * @xdr: target XDR stream -- cgit v1.2.3 From 782448e1ec3ef1bd6f7a7ee29ca1fe11a14d9d5f Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:58:17 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_rdattr_error() Refactor the encoder for FATTR4_RDATTR_ERROR into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 308f0316b63f..8ec145f916b2 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3072,6 +3072,12 @@ static __be32 nfsd4_encode_fattr4_lease_time(struct xdr_stream *xdr, return nfsd4_encode_nfs_lease4(xdr, nn->nfsd4_lease); } +static __be32 nfsd4_encode_fattr4_rdattr_error(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_uint32_t(xdr, args->rdattr_err); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3256,10 +3262,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(args.rdattr_err); + status = nfsd4_encode_fattr4_rdattr_error(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_ACL) { struct nfs4_ace *ace; -- cgit v1.2.3 From 6515b7d71de72850143bdd996b032dbdffda0848 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:58:23 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_aclsupport() Refactor the encoder for FATTR4_ACLSUPPORT into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 8ec145f916b2..f7c5c0575237 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3078,6 +3078,17 @@ static __be32 nfsd4_encode_fattr4_rdattr_error(struct xdr_stream *xdr, return nfsd4_encode_uint32_t(xdr, args->rdattr_err); } +static __be32 nfsd4_encode_fattr4_aclsupport(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + u32 mask; + + mask = 0; + if (IS_POSIXACL(d_inode(args->dentry))) + mask = ACL4_SUPPORT_ALLOW_ACL | ACL4_SUPPORT_DENY_ACL; + return nfsd4_encode_uint32_t(xdr, mask); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3297,11 +3308,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, } out_acl: if (bmval0 & FATTR4_WORD0_ACLSUPPORT) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(IS_POSIXACL(dentry->d_inode) ? - ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL : 0); + status = nfsd4_encode_fattr4_aclsupport(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_CANSETTIME) { status = nfsd4_encode_fattr4__true(xdr, &args); -- cgit v1.2.3 From 0207ee08182f5232e6e289f73909f18fa0c1575b Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:58:30 -0400 Subject: NFSD: Add nfsd4_encode_nfsace4() Refactor the ACE encoding helper so that it can eventually be reused for encoding OPEN results that contain delegation ACEs. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 36 +++++++++++++++++++++--------------- fs/nfsd/xdr4.h | 3 +++ 2 files changed, 24 insertions(+), 15 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index f7c5c0575237..2ecdd1152125 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2783,16 +2783,29 @@ static __be32 nfsd4_encode_fs_locations(struct xdr_stream *xdr, return 0; } -static inline __be32 -nfsd4_encode_aclname(struct xdr_stream *xdr, struct svc_rqst *rqstp, - struct nfs4_ace *ace) +static __be32 nfsd4_encode_nfsace4(struct xdr_stream *xdr, struct svc_rqst *rqstp, + struct nfs4_ace *ace) { + __be32 status; + + /* type */ + status = nfsd4_encode_acetype4(xdr, ace->type); + if (status != nfs_ok) + return nfserr_resource; + /* flag */ + status = nfsd4_encode_aceflag4(xdr, ace->flag); + if (status != nfs_ok) + return nfserr_resource; + /* access mask */ + status = nfsd4_encode_acemask4(xdr, ace->access_mask & NFS4_ACE_MASK_ALL); + if (status != nfs_ok) + return nfserr_resource; + /* who */ if (ace->whotype != NFS4_ACL_WHO_NAMED) return nfs4_acl_write_who(xdr, ace->whotype); - else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) + if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) return nfsd4_encode_group(xdr, rqstp, ace->who_gid); - else - return nfsd4_encode_user(xdr, rqstp, ace->who_uid); + return nfsd4_encode_user(xdr, rqstp, ace->who_uid); } static inline __be32 @@ -3294,15 +3307,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, *p++ = cpu_to_be32(args.acl->naces); for (ace = args.acl->aces; ace < args.acl->aces + args.acl->naces; ace++) { - p = xdr_reserve_space(xdr, 4*3); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(ace->type); - *p++ = cpu_to_be32(ace->flag); - *p++ = cpu_to_be32(ace->access_mask & - NFS4_ACE_MASK_ALL); - status = nfsd4_encode_aclname(xdr, rqstp, ace); - if (status) + status = nfsd4_encode_nfsace4(xdr, args.rqstp, ace); + if (status != nfs_ok) goto out; } } diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 488ecdacc4c6..f0866a55fd91 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -90,6 +90,9 @@ nfsd4_encode_uint32_t(struct xdr_stream *xdr, u32 val) return nfs_ok; } +#define nfsd4_encode_aceflag4(x, v) nfsd4_encode_uint32_t(x, v) +#define nfsd4_encode_acemask4(x, v) nfsd4_encode_uint32_t(x, v) +#define nfsd4_encode_acetype4(x, v) nfsd4_encode_uint32_t(x, v) #define nfsd4_encode_nfs_lease4(x, v) nfsd4_encode_uint32_t(x, v) /** -- cgit v1.2.3 From 07455dc45d973beb898277a71a2131610ebd1756 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:58:36 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_acl() Refactor the encoder for FATTR4_ACL into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 2ecdd1152125..07a2e65da7d7 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3102,6 +3102,29 @@ static __be32 nfsd4_encode_fattr4_aclsupport(struct xdr_stream *xdr, return nfsd4_encode_uint32_t(xdr, mask); } +static __be32 nfsd4_encode_fattr4_acl(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + struct nfs4_acl *acl = args->acl; + struct nfs4_ace *ace; + __be32 status; + + /* nfsace4<> */ + if (!acl) { + if (xdr_stream_encode_u32(xdr, 0) != XDR_UNIT) + return nfserr_resource; + } else { + if (xdr_stream_encode_u32(xdr, acl->naces) != XDR_UNIT) + return nfserr_resource; + for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) { + status = nfsd4_encode_nfsace4(xdr, args->rqstp, ace); + if (status != nfs_ok) + return status; + } + } + return nfs_ok; +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3291,28 +3314,10 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & FATTR4_WORD0_ACL) { - struct nfs4_ace *ace; - - if (args.acl == NULL) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - - *p++ = cpu_to_be32(0); - goto out_acl; - } - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(args.acl->naces); - - for (ace = args.acl->aces; ace < args.acl->aces + args.acl->naces; ace++) { - status = nfsd4_encode_nfsace4(xdr, args.rqstp, ace); - if (status != nfs_ok) - goto out; - } + status = nfsd4_encode_fattr4_acl(xdr, &args); + if (status) + goto out; } -out_acl: if (bmval0 & FATTR4_WORD0_ACLSUPPORT) { status = nfsd4_encode_fattr4_aclsupport(xdr, &args); if (status != nfs_ok) -- cgit v1.2.3 From 3283bf64ef2d9c98399e37e64a5b8d9c57c80dfe Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:58:42 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_filehandle() Refactor the encoder for FATTR4_FILEHANDLE into a helper. In a subsequent patch, this helper will be called from a bitmask loop. We can de-duplicate the other filehandle encoder (in GETFH) using our new helper. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 07a2e65da7d7..9811b05619de 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2530,6 +2530,12 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) return true; } +static __be32 nfsd4_encode_nfs_fh4(struct xdr_stream *xdr, + struct knfsd_fh *fh_handle) +{ + return nfsd4_encode_opaque(xdr, fh_handle->fh_raw, fh_handle->fh_size); +} + static __be32 nfsd4_encode_nfstime4(struct xdr_stream *xdr, struct timespec64 *tv) { @@ -3125,6 +3131,12 @@ static __be32 nfsd4_encode_fattr4_acl(struct xdr_stream *xdr, return nfs_ok; } +static __be32 nfsd4_encode_fattr4_filehandle(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_nfs_fh4(xdr, &args->fhp->fh_handle); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3344,11 +3356,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & FATTR4_WORD0_FILEHANDLE) { - p = xdr_reserve_space(xdr, args.fhp->fh_handle.fh_size + 4); - if (!p) - goto out_resource; - p = xdr_encode_opaque(p, &args.fhp->fh_handle.fh_raw, - args.fhp->fh_handle.fh_size); + status = nfsd4_encode_fattr4_filehandle(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_FILEID) { p = xdr_reserve_space(xdr, 8); @@ -3933,18 +3943,11 @@ static __be32 nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, union nfsd4_op_u *u) { - struct svc_fh **fhpp = &u->getfh; struct xdr_stream *xdr = resp->xdr; - struct svc_fh *fhp = *fhpp; - unsigned int len; - __be32 *p; + struct svc_fh *fhp = u->getfh; - len = fhp->fh_handle.fh_size; - p = xdr_reserve_space(xdr, len + 4); - if (!p) - return nfserr_resource; - p = xdr_encode_opaque(p, &fhp->fh_handle.fh_raw, len); - return 0; + /* object */ + return nfsd4_encode_nfs_fh4(xdr, &fhp->fh_handle); } /* -- cgit v1.2.3 From eb7ece81d5fcd3d2bc54a33040967f24e7c5b317 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:58:49 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_fileid() Refactor the encoder for FATTR4_FILEID into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 9811b05619de..2f19f72c4407 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3137,6 +3137,12 @@ static __be32 nfsd4_encode_fattr4_filehandle(struct xdr_stream *xdr, return nfsd4_encode_nfs_fh4(xdr, &args->fhp->fh_handle); } +static __be32 nfsd4_encode_fattr4_fileid(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_uint64_t(xdr, args->stat.ino); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3361,10 +3367,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & FATTR4_WORD0_FILEID) { - p = xdr_reserve_space(xdr, 8); - if (!p) - goto out_resource; - p = xdr_encode_hyper(p, args.stat.ino); + status = nfsd4_encode_fattr4_fileid(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_FILES_AVAIL) { p = xdr_reserve_space(xdr, 8); -- cgit v1.2.3 From b0c3a5f8c8caf05196560a7edbc69e10f3497817 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:58:55 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_files_avail() Refactor the encoder for FATTR4_FILES_AVAIL into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 2f19f72c4407..5d57eca405e6 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3143,6 +3143,12 @@ static __be32 nfsd4_encode_fattr4_fileid(struct xdr_stream *xdr, return nfsd4_encode_uint64_t(xdr, args->stat.ino); } +static __be32 nfsd4_encode_fattr4_files_avail(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_uint64_t(xdr, args->statfs.f_ffree); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3372,10 +3378,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & FATTR4_WORD0_FILES_AVAIL) { - p = xdr_reserve_space(xdr, 8); - if (!p) - goto out_resource; - p = xdr_encode_hyper(p, (u64) args.statfs.f_ffree); + status = nfsd4_encode_fattr4_files_avail(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_FILES_FREE) { p = xdr_reserve_space(xdr, 8); -- cgit v1.2.3 From 74361e2b5d252ffda6d366548167ec1e8be4358f Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:59:01 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_files_free() Refactor the encoder for FATTR4_FILES_FREE into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 5d57eca405e6..6e21f0444f4e 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3149,6 +3149,12 @@ static __be32 nfsd4_encode_fattr4_files_avail(struct xdr_stream *xdr, return nfsd4_encode_uint64_t(xdr, args->statfs.f_ffree); } +static __be32 nfsd4_encode_fattr4_files_free(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_uint64_t(xdr, args->statfs.f_ffree); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3383,10 +3389,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & FATTR4_WORD0_FILES_FREE) { - p = xdr_reserve_space(xdr, 8); - if (!p) - goto out_resource; - p = xdr_encode_hyper(p, (u64) args.statfs.f_ffree); + status = nfsd4_encode_fattr4_files_free(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_FILES_TOTAL) { p = xdr_reserve_space(xdr, 8); -- cgit v1.2.3 From b56b75266300d5d4042678b6d65953ae94ec1486 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:59:08 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_files_total() Refactor the encoder for FATTR4_FILES_TOTAL into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 6e21f0444f4e..69fb7575e82e 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3155,6 +3155,12 @@ static __be32 nfsd4_encode_fattr4_files_free(struct xdr_stream *xdr, return nfsd4_encode_uint64_t(xdr, args->statfs.f_ffree); } +static __be32 nfsd4_encode_fattr4_files_total(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_uint64_t(xdr, args->statfs.f_files); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3394,10 +3400,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & FATTR4_WORD0_FILES_TOTAL) { - p = xdr_reserve_space(xdr, 8); - if (!p) - goto out_resource; - p = xdr_encode_hyper(p, (u64) args.statfs.f_files); + status = nfsd4_encode_fattr4_files_total(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) { status = nfsd4_encode_fs_locations(xdr, rqstp, exp); -- cgit v1.2.3 From a1469a370472fb77a1a5c3545e9c2d7fee8775c3 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:59:14 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_fs_locations() Refactor the encoder for FATTR4_FS_LOCATIONS into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 66 +++++++++++++++++++++++-------------------------------- 1 file changed, 28 insertions(+), 38 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 69fb7575e82e..ce0cfd51503e 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2658,9 +2658,6 @@ static __be32 nfsd4_encode_components(struct xdr_stream *xdr, char sep, return nfsd4_encode_components_esc(xdr, sep, components, 0, 0); } -/* - * encode a location element of a fs_locations structure - */ static __be32 nfsd4_encode_fs_location4(struct xdr_stream *xdr, struct nfsd4_fs_location *location) { @@ -2673,15 +2670,12 @@ static __be32 nfsd4_encode_fs_location4(struct xdr_stream *xdr, status = nfsd4_encode_components(xdr, '/', location->path); if (status) return status; - return 0; + return nfs_ok; } -/* - * Encode a path in RFC3530 'pathname4' format - */ -static __be32 nfsd4_encode_path(struct xdr_stream *xdr, - const struct path *root, - const struct path *path) +static __be32 nfsd4_encode_pathname4(struct xdr_stream *xdr, + const struct path *root, + const struct path *path) { struct path cur = *path; __be32 *p; @@ -2749,44 +2743,34 @@ out_free: return err; } -static __be32 nfsd4_encode_fsloc_fsroot(struct xdr_stream *xdr, - struct svc_rqst *rqstp, const struct path *path) +static __be32 nfsd4_encode_fs_locations4(struct xdr_stream *xdr, + struct svc_rqst *rqstp, + struct svc_export *exp) { + struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs; struct svc_export *exp_ps; - __be32 res; + unsigned int i; + __be32 status; + /* fs_root */ exp_ps = rqst_find_fsidzero_export(rqstp); if (IS_ERR(exp_ps)) return nfserrno(PTR_ERR(exp_ps)); - res = nfsd4_encode_path(xdr, &exp_ps->ex_path, path); + status = nfsd4_encode_pathname4(xdr, &exp_ps->ex_path, &exp->ex_path); exp_put(exp_ps); - return res; -} - -/* - * encode a fs_locations structure - */ -static __be32 nfsd4_encode_fs_locations(struct xdr_stream *xdr, - struct svc_rqst *rqstp, struct svc_export *exp) -{ - __be32 status; - int i; - __be32 *p; - struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs; - - status = nfsd4_encode_fsloc_fsroot(xdr, rqstp, &exp->ex_path); - if (status) + if (status != nfs_ok) return status; - p = xdr_reserve_space(xdr, 4); - if (!p) + + /* locations<> */ + if (xdr_stream_encode_u32(xdr, fslocs->locations_count) != XDR_UNIT) return nfserr_resource; - *p++ = cpu_to_be32(fslocs->locations_count); - for (i=0; ilocations_count; i++) { + for (i = 0; i < fslocs->locations_count; i++) { status = nfsd4_encode_fs_location4(xdr, &fslocs->locations[i]); - if (status) + if (status != nfs_ok) return status; } - return 0; + + return nfs_ok; } static __be32 nfsd4_encode_nfsace4(struct xdr_stream *xdr, struct svc_rqst *rqstp, @@ -3161,6 +3145,12 @@ static __be32 nfsd4_encode_fattr4_files_total(struct xdr_stream *xdr, return nfsd4_encode_uint64_t(xdr, args->statfs.f_files); } +static __be32 nfsd4_encode_fattr4_fs_locations(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_fs_locations4(xdr, args->rqstp, args->exp); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3405,8 +3395,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) { - status = nfsd4_encode_fs_locations(xdr, rqstp, exp); - if (status) + status = nfsd4_encode_fattr4_fs_locations(xdr, &args); + if (status != nfs_ok) goto out; } if (bmval0 & FATTR4_WORD0_HOMOGENEOUS) { -- cgit v1.2.3 From 7c605dccc551130975021a9b603b1766bf36d00e Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:59:20 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_maxfilesize() Refactor the encoder for FATTR4_MAXFILESIZE into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index ce0cfd51503e..8f1e7f3699c2 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3151,6 +3151,14 @@ static __be32 nfsd4_encode_fattr4_fs_locations(struct xdr_stream *xdr, return nfsd4_encode_fs_locations4(xdr, args->rqstp, args->exp); } +static __be32 nfsd4_encode_fattr4_maxfilesize(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + struct super_block *sb = args->exp->ex_path.mnt->mnt_sb; + + return nfsd4_encode_uint64_t(xdr, sb->s_maxbytes); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3405,10 +3413,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & FATTR4_WORD0_MAXFILESIZE) { - p = xdr_reserve_space(xdr, 8); - if (!p) - goto out_resource; - p = xdr_encode_hyper(p, exp->ex_path.mnt->mnt_sb->s_maxbytes); + status = nfsd4_encode_fattr4_maxfilesize(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_MAXLINK) { p = xdr_reserve_space(xdr, 4); -- cgit v1.2.3 From b066aa5ca3c8c5df9194cde8a07e896a96218426 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:59:27 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_maxlink() Refactor the encoder for FATTR4_MAXLINK into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 8f1e7f3699c2..1b3c2bad72dd 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3159,6 +3159,12 @@ static __be32 nfsd4_encode_fattr4_maxfilesize(struct xdr_stream *xdr, return nfsd4_encode_uint64_t(xdr, sb->s_maxbytes); } +static __be32 nfsd4_encode_fattr4_maxlink(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_uint32_t(xdr, 255); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3418,10 +3424,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & FATTR4_WORD0_MAXLINK) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(255); + status = nfsd4_encode_fattr4_maxlink(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_MAXNAME) { p = xdr_reserve_space(xdr, 4); -- cgit v1.2.3 From 9c1adaccd1657c3153454635890c5d49b3eabfc6 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:59:33 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_maxname() Refactor the encoder for FATTR4_MAXNAME into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 1b3c2bad72dd..7ded6d20d833 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3165,6 +3165,12 @@ static __be32 nfsd4_encode_fattr4_maxlink(struct xdr_stream *xdr, return nfsd4_encode_uint32_t(xdr, 255); } +static __be32 nfsd4_encode_fattr4_maxname(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_uint32_t(xdr, args->statfs.f_namelen); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3429,10 +3435,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & FATTR4_WORD0_MAXNAME) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(args.statfs.f_namelen); + status = nfsd4_encode_fattr4_maxname(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_MAXREAD) { p = xdr_reserve_space(xdr, 8); -- cgit v1.2.3 From c17195c3972b42745460f09b9778e8d9061762a4 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:59:39 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_maxread() Refactor the encoder for FATTR4_MAXREAD into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 7ded6d20d833..0280b12f603d 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3171,6 +3171,12 @@ static __be32 nfsd4_encode_fattr4_maxname(struct xdr_stream *xdr, return nfsd4_encode_uint32_t(xdr, args->statfs.f_namelen); } +static __be32 nfsd4_encode_fattr4_maxread(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_uint64_t(xdr, svc_max_payload(args->rqstp)); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3440,10 +3446,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & FATTR4_WORD0_MAXREAD) { - p = xdr_reserve_space(xdr, 8); - if (!p) - goto out_resource; - p = xdr_encode_hyper(p, (u64) svc_max_payload(rqstp)); + status = nfsd4_encode_fattr4_maxread(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval0 & FATTR4_WORD0_MAXWRITE) { p = xdr_reserve_space(xdr, 8); -- cgit v1.2.3 From 951378dc9698a34e28c6badccdf9e95f2d3cf5d1 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:59:46 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_maxwrite() Refactor the encoder for FATTR4_MAXWRITE into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 0280b12f603d..c9ff1091711c 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3177,6 +3177,12 @@ static __be32 nfsd4_encode_fattr4_maxread(struct xdr_stream *xdr, return nfsd4_encode_uint64_t(xdr, svc_max_payload(args->rqstp)); } +static __be32 nfsd4_encode_fattr4_maxwrite(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_uint64_t(xdr, svc_max_payload(args->rqstp)); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3451,10 +3457,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval0 & FATTR4_WORD0_MAXWRITE) { - p = xdr_reserve_space(xdr, 8); - if (!p) - goto out_resource; - p = xdr_encode_hyper(p, (u64) svc_max_payload(rqstp)); + status = nfsd4_encode_fattr4_maxwrite(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval1 & FATTR4_WORD1_MODE) { p = xdr_reserve_space(xdr, 4); -- cgit v1.2.3 From f4cf5042011223fcfec863ddd55e5cb6c4b50827 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:59:52 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_mode() Refactor the encoder for FATTR4_MODE into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 13 +++++++++---- fs/nfsd/xdr4.h | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index c9ff1091711c..105d51b517e5 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3183,6 +3183,12 @@ static __be32 nfsd4_encode_fattr4_maxwrite(struct xdr_stream *xdr, return nfsd4_encode_uint64_t(xdr, svc_max_payload(args->rqstp)); } +static __be32 nfsd4_encode_fattr4_mode(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_mode4(xdr, args->stat.mode & S_IALLUGO); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3462,10 +3468,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval1 & FATTR4_WORD1_MODE) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(args.stat.mode & S_IALLUGO); + status = nfsd4_encode_fattr4_mode(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval1 & FATTR4_WORD1_NO_TRUNC) { status = nfsd4_encode_fattr4__true(xdr, &args); diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index f0866a55fd91..52322acc1e9f 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -93,6 +93,7 @@ nfsd4_encode_uint32_t(struct xdr_stream *xdr, u32 val) #define nfsd4_encode_aceflag4(x, v) nfsd4_encode_uint32_t(x, v) #define nfsd4_encode_acemask4(x, v) nfsd4_encode_uint32_t(x, v) #define nfsd4_encode_acetype4(x, v) nfsd4_encode_uint32_t(x, v) +#define nfsd4_encode_mode4(x, v) nfsd4_encode_uint32_t(x, v) #define nfsd4_encode_nfs_lease4(x, v) nfsd4_encode_uint32_t(x, v) /** -- cgit v1.2.3 From 9f329fea25188def0a42bacd27894c877bb599c8 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 09:59:59 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_numlinks() Refactor the encoder for FATTR4_NUMLINKS into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 105d51b517e5..e1654b69506e 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3189,6 +3189,12 @@ static __be32 nfsd4_encode_fattr4_mode(struct xdr_stream *xdr, return nfsd4_encode_mode4(xdr, args->stat.mode & S_IALLUGO); } +static __be32 nfsd4_encode_fattr4_numlinks(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_uint32_t(xdr, args->stat.nlink); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3478,10 +3484,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval1 & FATTR4_WORD1_NUMLINKS) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(args.stat.nlink); + status = nfsd4_encode_fattr4_numlinks(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval1 & FATTR4_WORD1_OWNER) { status = nfsd4_encode_user(xdr, rqstp, args.stat.uid); -- cgit v1.2.3 From fa51a5201bb90a4cf291b5ad5f6ee1af8be5548c Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:00:05 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_owner() Refactor the encoder for FATTR4_OWNER into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index e1654b69506e..c4dfa41582be 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3195,6 +3195,12 @@ static __be32 nfsd4_encode_fattr4_numlinks(struct xdr_stream *xdr, return nfsd4_encode_uint32_t(xdr, args->stat.nlink); } +static __be32 nfsd4_encode_fattr4_owner(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_user(xdr, args->rqstp, args->stat.uid); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3489,8 +3495,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval1 & FATTR4_WORD1_OWNER) { - status = nfsd4_encode_user(xdr, rqstp, args.stat.uid); - if (status) + status = nfsd4_encode_fattr4_owner(xdr, &args); + if (status != nfs_ok) goto out; } if (bmval1 & FATTR4_WORD1_OWNER_GROUP) { -- cgit v1.2.3 From 62f31e56d51a10e5c8867d64c83a3679bc71184b Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:00:11 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_owner_group() Refactor the encoder for FATTR4_OWNER_GROUP into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index c4dfa41582be..e7cbb70959d8 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3201,6 +3201,12 @@ static __be32 nfsd4_encode_fattr4_owner(struct xdr_stream *xdr, return nfsd4_encode_user(xdr, args->rqstp, args->stat.uid); } +static __be32 nfsd4_encode_fattr4_owner_group(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_group(xdr, args->rqstp, args->stat.gid); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3500,8 +3506,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval1 & FATTR4_WORD1_OWNER_GROUP) { - status = nfsd4_encode_group(xdr, rqstp, args.stat.gid); - if (status) + status = nfsd4_encode_fattr4_owner_group(xdr, &args); + if (status != nfs_ok) goto out; } if (bmval1 & FATTR4_WORD1_RAWDEV) { -- cgit v1.2.3 From a460cda28e9b3709794932a0158d7ded57a32136 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:00:18 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_rawdev() Refactor the encoder for FATTR4_RAWDEV into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index e7cbb70959d8..94cddd768af8 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2550,6 +2550,17 @@ static __be32 nfsd4_encode_nfstime4(struct xdr_stream *xdr, return nfs_ok; } +static __be32 nfsd4_encode_specdata4(struct xdr_stream *xdr, + unsigned int major, unsigned int minor) +{ + __be32 status; + + status = nfsd4_encode_uint32_t(xdr, major); + if (status != nfs_ok) + return status; + return nfsd4_encode_uint32_t(xdr, minor); +} + /* * ctime (in NFSv4, time_metadata) is not writeable, and the client * doesn't really care what resolution could theoretically be stored by @@ -3207,6 +3218,13 @@ static __be32 nfsd4_encode_fattr4_owner_group(struct xdr_stream *xdr, return nfsd4_encode_group(xdr, args->rqstp, args->stat.gid); } +static __be32 nfsd4_encode_fattr4_rawdev(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_specdata4(xdr, MAJOR(args->stat.rdev), + MINOR(args->stat.rdev)); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3511,11 +3529,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval1 & FATTR4_WORD1_RAWDEV) { - p = xdr_reserve_space(xdr, 8); - if (!p) - goto out_resource; - *p++ = cpu_to_be32((u32) MAJOR(args.stat.rdev)); - *p++ = cpu_to_be32((u32) MINOR(args.stat.rdev)); + status = nfsd4_encode_fattr4_rawdev(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) { p = xdr_reserve_space(xdr, 8); -- cgit v1.2.3 From 83afa091795fffaa6d6322b87dc7d33d445cc1b2 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:00:24 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_space_avail() Refactor the encoder for FATTR4_SPACE_AVAIL into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 94cddd768af8..e46642427f26 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3225,6 +3225,14 @@ static __be32 nfsd4_encode_fattr4_rawdev(struct xdr_stream *xdr, MINOR(args->stat.rdev)); } +static __be32 nfsd4_encode_fattr4_space_avail(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + u64 avail = (u64)args->statfs.f_bavail * (u64)args->statfs.f_bsize; + + return nfsd4_encode_uint64_t(xdr, avail); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3534,11 +3542,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) { - p = xdr_reserve_space(xdr, 8); - if (!p) - goto out_resource; - dummy64 = (u64)args.statfs.f_bavail * (u64)args.statfs.f_bsize; - p = xdr_encode_hyper(p, dummy64); + status = nfsd4_encode_fattr4_space_avail(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval1 & FATTR4_WORD1_SPACE_FREE) { p = xdr_reserve_space(xdr, 8); -- cgit v1.2.3 From 74ebc697053244874bf78a5fe471bdddc150d8af Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:00:30 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_space_free() Refactor the encoder for FATTR4_SPACE_FREE into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index e46642427f26..094e28535ce3 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3233,6 +3233,14 @@ static __be32 nfsd4_encode_fattr4_space_avail(struct xdr_stream *xdr, return nfsd4_encode_uint64_t(xdr, avail); } +static __be32 nfsd4_encode_fattr4_space_free(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + u64 free = (u64)args->statfs.f_bfree * (u64)args->statfs.f_bsize; + + return nfsd4_encode_uint64_t(xdr, free); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3547,11 +3555,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval1 & FATTR4_WORD1_SPACE_FREE) { - p = xdr_reserve_space(xdr, 8); - if (!p) - goto out_resource; - dummy64 = (u64)args.statfs.f_bfree * (u64)args.statfs.f_bsize; - p = xdr_encode_hyper(p, dummy64); + status = nfsd4_encode_fattr4_space_free(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) { p = xdr_reserve_space(xdr, 8); -- cgit v1.2.3 From d0cde979e912706ab331b9d2ad31f311a9f35f80 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:00:37 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_space_total() Refactor the encoder for FATTR4_SPACE_TOTAL into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 094e28535ce3..cf90db96932c 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3241,6 +3241,14 @@ static __be32 nfsd4_encode_fattr4_space_free(struct xdr_stream *xdr, return nfsd4_encode_uint64_t(xdr, free); } +static __be32 nfsd4_encode_fattr4_space_total(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + u64 total = (u64)args->statfs.f_blocks * (u64)args->statfs.f_bsize; + + return nfsd4_encode_uint64_t(xdr, total); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3560,11 +3568,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) { - p = xdr_reserve_space(xdr, 8); - if (!p) - goto out_resource; - dummy64 = (u64)args.statfs.f_blocks * (u64)args.statfs.f_bsize; - p = xdr_encode_hyper(p, dummy64); + status = nfsd4_encode_fattr4_space_total(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval1 & FATTR4_WORD1_SPACE_USED) { p = xdr_reserve_space(xdr, 8); -- cgit v1.2.3 From 6d37ac3adb310dabe78e5ff0289f4bfeceda2114 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:00:43 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_space_used() Refactor the encoder for FATTR4_SPACE_USED into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index cf90db96932c..b8938521528f 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3249,6 +3249,12 @@ static __be32 nfsd4_encode_fattr4_space_total(struct xdr_stream *xdr, return nfsd4_encode_uint64_t(xdr, total); } +static __be32 nfsd4_encode_fattr4_space_used(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_uint64_t(xdr, (u64)args->stat.blocks << 9); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3267,7 +3273,6 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, __be32 *p, *attrlen_p; int starting_len = xdr->buf->len; int attrlen_offset; - u64 dummy64; __be32 status; int err; #ifdef CONFIG_NFSD_V4_SECURITY_LABEL @@ -3573,11 +3578,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval1 & FATTR4_WORD1_SPACE_USED) { - p = xdr_reserve_space(xdr, 8); - if (!p) - goto out_resource; - dummy64 = (u64)args.stat.blocks << 9; - p = xdr_encode_hyper(p, dummy64); + status = nfsd4_encode_fattr4_space_used(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval1 & FATTR4_WORD1_TIME_ACCESS) { status = nfsd4_encode_nfstime4(xdr, &args.stat.atime); -- cgit v1.2.3 From eed4d1adbbd268be2a5e75be770b58097d668982 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:00:50 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_time_access() Refactor the encoder for FATTR4_TIME_ACCESS into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index b8938521528f..a973cf186e58 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2536,16 +2536,16 @@ static __be32 nfsd4_encode_nfs_fh4(struct xdr_stream *xdr, return nfsd4_encode_opaque(xdr, fh_handle->fh_raw, fh_handle->fh_size); } +/* This is a frequently-encoded type; open-coded for speed */ static __be32 nfsd4_encode_nfstime4(struct xdr_stream *xdr, - struct timespec64 *tv) + const struct timespec64 *tv) { __be32 *p; p = xdr_reserve_space(xdr, XDR_UNIT * 3); if (!p) return nfserr_resource; - - p = xdr_encode_hyper(p, (s64)tv->tv_sec); + p = xdr_encode_hyper(p, tv->tv_sec); *p = cpu_to_be32(tv->tv_nsec); return nfs_ok; } @@ -3255,6 +3255,12 @@ static __be32 nfsd4_encode_fattr4_space_used(struct xdr_stream *xdr, return nfsd4_encode_uint64_t(xdr, (u64)args->stat.blocks << 9); } +static __be32 nfsd4_encode_fattr4_time_access(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_nfstime4(xdr, &args->stat.atime); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3583,7 +3589,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval1 & FATTR4_WORD1_TIME_ACCESS) { - status = nfsd4_encode_nfstime4(xdr, &args.stat.atime); + status = nfsd4_encode_fattr4_time_access(xdr, &args); if (status) goto out; } -- cgit v1.2.3 From 2e38722d4af86225d8ec524618036a03f0c98cc6 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:00:56 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_time_create() Refactor the encoder for FATTR4_TIME_CREATE into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index a973cf186e58..25cf492898ce 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3261,6 +3261,12 @@ static __be32 nfsd4_encode_fattr4_time_access(struct xdr_stream *xdr, return nfsd4_encode_nfstime4(xdr, &args->stat.atime); } +static __be32 nfsd4_encode_fattr4_time_create(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_nfstime4(xdr, &args->stat.btime); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3594,7 +3600,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval1 & FATTR4_WORD1_TIME_CREATE) { - status = nfsd4_encode_nfstime4(xdr, &args.stat.btime); + status = nfsd4_encode_fattr4_time_create(xdr, &args); if (status) goto out; } -- cgit v1.2.3 From 993474e8a60f01010f19ac008078c78ef25a84e7 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:01:02 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_time_delta() Refactor the encoder for FATTR4_TIME_DELTA into a helper. In a subsequent patch, this helper will be called from a bitmask loop. fattr4_time_delta is specified as an nfstime4, so de-duplicate this encoder. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 53 ++++++++++++++++++++++++----------------------------- 1 file changed, 24 insertions(+), 29 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 25cf492898ce..c3b21fca1688 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2561,31 +2561,6 @@ static __be32 nfsd4_encode_specdata4(struct xdr_stream *xdr, return nfsd4_encode_uint32_t(xdr, minor); } -/* - * ctime (in NFSv4, time_metadata) is not writeable, and the client - * doesn't really care what resolution could theoretically be stored by - * the filesystem. - * - * The client cares how close together changes can be while still - * guaranteeing ctime changes. For most filesystems (which have - * timestamps with nanosecond fields) that is limited by the resolution - * of the time returned from current_time() (which I'm assuming to be - * 1/HZ). - */ -static __be32 *encode_time_delta(__be32 *p, struct inode *inode) -{ - struct timespec64 ts; - u32 ns; - - ns = max_t(u32, NSEC_PER_SEC/HZ, inode->i_sb->s_time_gran); - ts = ns_to_timespec64(ns); - - p = xdr_encode_hyper(p, ts.tv_sec); - *p++ = cpu_to_be32(ts.tv_nsec); - - return p; -} - static __be32 nfsd4_encode_change_info4(struct xdr_stream *xdr, const struct nfsd4_change_info *c) { @@ -3267,6 +3242,27 @@ static __be32 nfsd4_encode_fattr4_time_create(struct xdr_stream *xdr, return nfsd4_encode_nfstime4(xdr, &args->stat.btime); } +/* + * ctime (in NFSv4, time_metadata) is not writeable, and the client + * doesn't really care what resolution could theoretically be stored by + * the filesystem. + * + * The client cares how close together changes can be while still + * guaranteeing ctime changes. For most filesystems (which have + * timestamps with nanosecond fields) that is limited by the resolution + * of the time returned from current_time() (which I'm assuming to be + * 1/HZ). + */ +static __be32 nfsd4_encode_fattr4_time_delta(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + const struct inode *inode = d_inode(args->dentry); + u32 ns = max_t(u32, NSEC_PER_SEC/HZ, inode->i_sb->s_time_gran); + struct timespec64 ts = ns_to_timespec64(ns); + + return nfsd4_encode_nfstime4(xdr, &ts); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3605,10 +3601,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval1 & FATTR4_WORD1_TIME_DELTA) { - p = xdr_reserve_space(xdr, 12); - if (!p) - goto out_resource; - p = encode_time_delta(p, d_inode(dentry)); + status = nfsd4_encode_fattr4_time_delta(xdr, &args); + if (status != nfs_ok) + goto out; } if (bmval1 & FATTR4_WORD1_TIME_METADATA) { status = nfsd4_encode_nfstime4(xdr, &args.stat.ctime); -- cgit v1.2.3 From 673720bc84bc9513a0488b7a3633a7c38a526ee5 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:01:09 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_time_metadata() Refactor the encoder for FATTR4_TIME_METADATA into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index c3b21fca1688..0cac15e3a82e 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3263,6 +3263,12 @@ static __be32 nfsd4_encode_fattr4_time_delta(struct xdr_stream *xdr, return nfsd4_encode_nfstime4(xdr, &ts); } +static __be32 nfsd4_encode_fattr4_time_metadata(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_nfstime4(xdr, &args->stat.ctime); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3606,7 +3612,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval1 & FATTR4_WORD1_TIME_METADATA) { - status = nfsd4_encode_nfstime4(xdr, &args.stat.ctime); + status = nfsd4_encode_fattr4_time_metadata(xdr, &args); if (status) goto out; } -- cgit v1.2.3 From d18286112de367ac19a6f1003299d6db013ca05b Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:01:15 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_time_modify() Refactor the encoder for FATTR4_TIME_MODIFY into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 0cac15e3a82e..a5b79cf623e6 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3269,6 +3269,12 @@ static __be32 nfsd4_encode_fattr4_time_metadata(struct xdr_stream *xdr, return nfsd4_encode_nfstime4(xdr, &args->stat.ctime); } +static __be32 nfsd4_encode_fattr4_time_modify(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_nfstime4(xdr, &args->stat.mtime); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3617,7 +3623,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval1 & FATTR4_WORD1_TIME_MODIFY) { - status = nfsd4_encode_nfstime4(xdr, &args.stat.mtime); + status = nfsd4_encode_fattr4_time_modify(xdr, &args); if (status) goto out; } -- cgit v1.2.3 From 1b9097e36688a5624a8db7db575030e25dcd075c Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:01:21 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_mounted_on_fileid() Refactor the encoder for FATTR4_MOUNTED_ON_FILEID into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index a5b79cf623e6..b840318beffa 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2915,6 +2915,7 @@ struct nfsd4_fattr_args { u64 size; u32 rdattr_err; bool contextsupport; + bool ignore_crossmnt; }; static __be32 nfsd4_encode_fattr4__true(struct xdr_stream *xdr, @@ -3275,6 +3276,23 @@ static __be32 nfsd4_encode_fattr4_time_modify(struct xdr_stream *xdr, return nfsd4_encode_nfstime4(xdr, &args->stat.mtime); } +static __be32 nfsd4_encode_fattr4_mounted_on_fileid(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + u64 ino; + int err; + + if (!args->ignore_crossmnt && + args->dentry == args->exp->ex_path.mnt->mnt_root) { + err = nfsd4_get_mounted_on_ino(args->exp, &ino); + if (err) + return nfserrno(err); + } else + ino = args->stat.ino; + + return nfsd4_encode_uint64_t(xdr, ino); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3314,6 +3332,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, args.rqstp = rqstp; args.exp = exp; args.dentry = dentry; + args.ignore_crossmnt = (ignore_crossmnt != 0); args.rdattr_err = 0; if (exp->ex_fslocs.migrated) { @@ -3628,23 +3647,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; } if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { - u64 ino = args.stat.ino; - - p = xdr_reserve_space(xdr, 8); - if (!p) - goto out_resource; - /* - * Get ino of mountpoint in parent filesystem, if not ignoring - * crossmount and this is the root of a cross-mounted - * filesystem. - */ - if (ignore_crossmnt == 0 && - dentry == exp->ex_path.mnt->mnt_root) { - err = nfsd4_get_mounted_on_ino(exp, &ino); - if (err) - goto out_nfserr; - } - p = xdr_encode_hyper(p, ino); + status = nfsd4_encode_fattr4_mounted_on_fileid(xdr, &args); + if (status != nfs_ok) + goto out; } #ifdef CONFIG_NFSD_PNFS if (bmval1 & FATTR4_WORD1_FS_LAYOUT_TYPES) { -- cgit v1.2.3 From e7a5b1b2ad8515ed6a093307318ebfd3bde6a54f Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:01:28 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_fs_layout_types() Refactor the encoder for FATTR4_FS_LAYOUT_TYPES into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index b840318beffa..36ef7b0795b1 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3293,6 +3293,28 @@ static __be32 nfsd4_encode_fattr4_mounted_on_fileid(struct xdr_stream *xdr, return nfsd4_encode_uint64_t(xdr, ino); } +#ifdef CONFIG_NFSD_PNFS + +static __be32 nfsd4_encode_fattr4_fs_layout_types(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + unsigned long mask = args->exp->ex_layout_types; + int i; + + /* Hamming weight of @mask is the number of layout types to return */ + if (xdr_stream_encode_u32(xdr, hweight_long(mask)) != XDR_UNIT) + return nfserr_resource; + for (i = LAYOUT_NFSV4_1_FILES; i < LAYOUT_TYPE_MAX; ++i) + if (mask & BIT(i)) { + /* layouttype4 */ + if (xdr_stream_encode_u32(xdr, i) != XDR_UNIT) + return nfserr_resource; + } + return nfs_ok; +} + +#endif + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3653,7 +3675,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, } #ifdef CONFIG_NFSD_PNFS if (bmval1 & FATTR4_WORD1_FS_LAYOUT_TYPES) { - status = nfsd4_encode_layout_types(xdr, exp->ex_layout_types); + status = nfsd4_encode_fattr4_fs_layout_types(xdr, &args); if (status) goto out; } -- cgit v1.2.3 From 4c15878e66db7eaba1968c4fb94a8cbd7c24c819 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:01:34 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_layout_types() Refactor the encoder for FATTR4_LAYOUT_TYPES into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 36ef7b0795b1..a6aa49777010 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2784,25 +2784,6 @@ static __be32 nfsd4_encode_nfsace4(struct xdr_stream *xdr, struct svc_rqst *rqst return nfsd4_encode_user(xdr, rqstp, ace->who_uid); } -static inline __be32 -nfsd4_encode_layout_types(struct xdr_stream *xdr, u32 layout_types) -{ - __be32 *p; - unsigned long i = hweight_long(layout_types); - - p = xdr_reserve_space(xdr, 4 + 4 * i); - if (!p) - return nfserr_resource; - - *p++ = cpu_to_be32(i); - - for (i = LAYOUT_NFSV4_1_FILES; i < LAYOUT_TYPE_MAX; ++i) - if (layout_types & (1 << i)) - *p++ = cpu_to_be32(i); - - return 0; -} - #define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \ FATTR4_WORD0_RDATTR_ERROR) #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID @@ -3313,6 +3294,24 @@ static __be32 nfsd4_encode_fattr4_fs_layout_types(struct xdr_stream *xdr, return nfs_ok; } +static __be32 nfsd4_encode_fattr4_layout_types(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + unsigned long mask = args->exp->ex_layout_types; + int i; + + /* Hamming weight of @mask is the number of layout types to return */ + if (xdr_stream_encode_u32(xdr, hweight_long(mask)) != XDR_UNIT) + return nfserr_resource; + for (i = LAYOUT_NFSV4_1_FILES; i < LAYOUT_TYPE_MAX; ++i) + if (mask & BIT(i)) { + /* layouttype4 */ + if (xdr_stream_encode_u32(xdr, i) != XDR_UNIT) + return nfserr_resource; + } + return nfs_ok; +} + #endif /* @@ -3681,7 +3680,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, } if (bmval2 & FATTR4_WORD2_LAYOUT_TYPES) { - status = nfsd4_encode_layout_types(xdr, exp->ex_layout_types); + status = nfsd4_encode_fattr4_layout_types(xdr, &args); if (status) goto out; } -- cgit v1.2.3 From 4c5847313b137ed7241e532d7f281c36a71055b0 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:01:40 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_layout_blksize() Refactor the encoder for FATTR4_LAYOUT_BLKSIZE into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index a6aa49777010..5d63ad47f507 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3312,6 +3312,12 @@ static __be32 nfsd4_encode_fattr4_layout_types(struct xdr_stream *xdr, return nfs_ok; } +static __be32 nfsd4_encode_fattr4_layout_blksize(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_uint32_t(xdr, args->stat.blksize); +} + #endif /* @@ -3686,10 +3692,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, } if (bmval2 & FATTR4_WORD2_LAYOUT_BLKSIZE) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(args.stat.blksize); + status = nfsd4_encode_fattr4_layout_blksize(xdr, &args); + if (status != nfs_ok) + goto out; } #endif /* CONFIG_NFSD_PNFS */ if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { -- cgit v1.2.3 From 345c3877d27d6f69d7236fd0f92d2201bd6bb335 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:01:47 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_suppattr_exclcreat() Refactor the encoder for FATTR4_SUPPATTR_EXCLCREAT into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 5d63ad47f507..a8cb44f320e8 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3320,6 +3320,20 @@ static __be32 nfsd4_encode_fattr4_layout_blksize(struct xdr_stream *xdr, #endif +static __be32 nfsd4_encode_fattr4_suppattr_exclcreat(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + struct nfsd4_compoundres *resp = args->rqstp->rq_resp; + u32 supp[3]; + + memcpy(supp, nfsd_suppattrs[resp->cstate.minorversion], sizeof(supp)); + supp[0] &= NFSD_SUPPATTR_EXCLCREAT_WORD0; + supp[1] &= NFSD_SUPPATTR_EXCLCREAT_WORD1; + supp[2] &= NFSD_SUPPATTR_EXCLCREAT_WORD2; + + return nfsd4_encode_bitmap4(xdr, supp[0], supp[1], supp[2]); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3698,14 +3712,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, } #endif /* CONFIG_NFSD_PNFS */ if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { - u32 supp[3]; - - memcpy(supp, nfsd_suppattrs[minorversion], sizeof(supp)); - supp[0] &= NFSD_SUPPATTR_EXCLCREAT_WORD0; - supp[1] &= NFSD_SUPPATTR_EXCLCREAT_WORD1; - supp[2] &= NFSD_SUPPATTR_EXCLCREAT_WORD2; - - status = nfsd4_encode_bitmap4(xdr, supp[0], supp[1], supp[2]); + status = nfsd4_encode_fattr4_suppattr_exclcreat(xdr, &args); if (status) goto out; } -- cgit v1.2.3 From f59388a579c6a395de8f7372b267d3abecd8d6bf Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:01:53 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_sec_label() Refactor the encoder for FATTR4_SEC_LABEL into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index a8cb44f320e8..4e64cae1dcee 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2894,6 +2894,10 @@ struct nfsd4_fattr_args { struct kstatfs statfs; struct nfs4_acl *acl; u64 size; +#ifdef CONFIG_NFSD_V4_SECURITY_LABEL + void *context; + int contextlen; +#endif u32 rdattr_err; bool contextsupport; bool ignore_crossmnt; @@ -3334,6 +3338,15 @@ static __be32 nfsd4_encode_fattr4_suppattr_exclcreat(struct xdr_stream *xdr, return nfsd4_encode_bitmap4(xdr, supp[0], supp[1], supp[2]); } +#ifdef CONFIG_NFSD_V4_SECURITY_LABEL +static __be32 nfsd4_encode_fattr4_sec_label(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfsd4_encode_security_label(xdr, args->rqstp, + args->context, args->contextlen); +} +#endif + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3354,10 +3367,6 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, int attrlen_offset; __be32 status; int err; -#ifdef CONFIG_NFSD_V4_SECURITY_LABEL - void *context = NULL; - int contextlen; -#endif struct nfsd4_compoundres *resp = rqstp->rq_resp; u32 minorversion = resp->cstate.minorversion; struct path path = { @@ -3436,11 +3445,12 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, args.contextsupport = false; #ifdef CONFIG_NFSD_V4_SECURITY_LABEL + args.context = NULL; if ((bmval2 & FATTR4_WORD2_SECURITY_LABEL) || bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) { if (exp->ex_flags & NFSEXP_SECURITY_LABEL) err = security_inode_getsecctx(d_inode(dentry), - &context, &contextlen); + &args.context, &args.contextlen); else err = -EOPNOTSUPP; args.contextsupport = (err == 0); @@ -3719,8 +3729,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, #ifdef CONFIG_NFSD_V4_SECURITY_LABEL if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { - status = nfsd4_encode_security_label(xdr, rqstp, context, - contextlen); + status = nfsd4_encode_fattr4_sec_label(xdr, &args); if (status) goto out; } @@ -3739,8 +3748,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, out: #ifdef CONFIG_NFSD_V4_SECURITY_LABEL - if (context) - security_release_secctx(context, contextlen); + if (args.context) + security_release_secctx(args.context, args.contextlen); #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ kfree(args.acl); if (tempfh) { -- cgit v1.2.3 From b3dbf4e4a2018e21503bc8326ceee5eb90f2966e Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:01:59 -0400 Subject: NFSD: Add nfsd4_encode_fattr4_xattr_support() Refactor the encoder for FATTR4_XATTR_SUPPORT into a helper. In a subsequent patch, this helper will be called from a bitmask loop. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 4e64cae1dcee..bd4e90c50cfd 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3347,6 +3347,14 @@ static __be32 nfsd4_encode_fattr4_sec_label(struct xdr_stream *xdr, } #endif +static __be32 nfsd4_encode_fattr4_xattr_support(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + int err = xattr_supports_user_prefix(d_inode(args->dentry)); + + return nfsd4_encode_bool(xdr, err == 0); +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3362,10 +3370,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, u32 bmval1 = bmval[1]; u32 bmval2 = bmval[2]; struct svc_fh *tempfh = NULL; - __be32 *p, *attrlen_p; int starting_len = xdr->buf->len; + __be32 *attrlen_p, status; int attrlen_offset; - __be32 status; int err; struct nfsd4_compoundres *resp = rqstp->rq_resp; u32 minorversion = resp->cstate.minorversion; @@ -3736,11 +3743,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, #endif if (bmval2 & FATTR4_WORD2_XATTR_SUPPORT) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - err = xattr_supports_user_prefix(d_inode(dentry)); - *p++ = cpu_to_be32(err == 0); + status = nfsd4_encode_fattr4_xattr_support(xdr, &args); + if (status != nfs_ok) + goto out; } *attrlen_p = cpu_to_be32(xdr->buf->len - attrlen_offset - XDR_UNIT); -- cgit v1.2.3 From fce7913b13d0270bcf926f986b7ef329e2e56eec Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:02:12 -0400 Subject: NFSD: Use a bitmask loop to encode FATTR4 results The fattr4 encoder is now structured like the COMPOUND op encoder: one function for each individual attribute, called by bit number. Benefits include: - The individual attributes are now guaranteed to be encoded in bitmask order into the send buffer - There can be no unwanted side effects between attribute encoders - The code now clearly documents which attributes are /not/ implemented on this server Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 433 ++++++++++++++++++------------------------------------ 1 file changed, 146 insertions(+), 287 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index bd4e90c50cfd..5c249d806153 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2903,6 +2903,15 @@ struct nfsd4_fattr_args { bool ignore_crossmnt; }; +typedef __be32(*nfsd4_enc_attr)(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args); + +static __be32 nfsd4_encode_fattr4__noop(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +{ + return nfs_ok; +} + static __be32 nfsd4_encode_fattr4__true(struct xdr_stream *xdr, const struct nfsd4_fattr_args *args) { @@ -3355,6 +3364,108 @@ static __be32 nfsd4_encode_fattr4_xattr_support(struct xdr_stream *xdr, return nfsd4_encode_bool(xdr, err == 0); } +static const nfsd4_enc_attr nfsd4_enc_fattr4_encode_ops[] = { + [FATTR4_SUPPORTED_ATTRS] = nfsd4_encode_fattr4_supported_attrs, + [FATTR4_TYPE] = nfsd4_encode_fattr4_type, + [FATTR4_FH_EXPIRE_TYPE] = nfsd4_encode_fattr4_fh_expire_type, + [FATTR4_CHANGE] = nfsd4_encode_fattr4_change, + [FATTR4_SIZE] = nfsd4_encode_fattr4_size, + [FATTR4_LINK_SUPPORT] = nfsd4_encode_fattr4__true, + [FATTR4_SYMLINK_SUPPORT] = nfsd4_encode_fattr4__true, + [FATTR4_NAMED_ATTR] = nfsd4_encode_fattr4__false, + [FATTR4_FSID] = nfsd4_encode_fattr4_fsid, + [FATTR4_UNIQUE_HANDLES] = nfsd4_encode_fattr4__true, + [FATTR4_LEASE_TIME] = nfsd4_encode_fattr4_lease_time, + [FATTR4_RDATTR_ERROR] = nfsd4_encode_fattr4_rdattr_error, + [FATTR4_ACL] = nfsd4_encode_fattr4_acl, + [FATTR4_ACLSUPPORT] = nfsd4_encode_fattr4_aclsupport, + [FATTR4_ARCHIVE] = nfsd4_encode_fattr4__noop, + [FATTR4_CANSETTIME] = nfsd4_encode_fattr4__true, + [FATTR4_CASE_INSENSITIVE] = nfsd4_encode_fattr4__false, + [FATTR4_CASE_PRESERVING] = nfsd4_encode_fattr4__true, + [FATTR4_CHOWN_RESTRICTED] = nfsd4_encode_fattr4__true, + [FATTR4_FILEHANDLE] = nfsd4_encode_fattr4_filehandle, + [FATTR4_FILEID] = nfsd4_encode_fattr4_fileid, + [FATTR4_FILES_AVAIL] = nfsd4_encode_fattr4_files_avail, + [FATTR4_FILES_FREE] = nfsd4_encode_fattr4_files_free, + [FATTR4_FILES_TOTAL] = nfsd4_encode_fattr4_files_total, + [FATTR4_FS_LOCATIONS] = nfsd4_encode_fattr4_fs_locations, + [FATTR4_HIDDEN] = nfsd4_encode_fattr4__noop, + [FATTR4_HOMOGENEOUS] = nfsd4_encode_fattr4__true, + [FATTR4_MAXFILESIZE] = nfsd4_encode_fattr4_maxfilesize, + [FATTR4_MAXLINK] = nfsd4_encode_fattr4_maxlink, + [FATTR4_MAXNAME] = nfsd4_encode_fattr4_maxname, + [FATTR4_MAXREAD] = nfsd4_encode_fattr4_maxread, + [FATTR4_MAXWRITE] = nfsd4_encode_fattr4_maxwrite, + [FATTR4_MIMETYPE] = nfsd4_encode_fattr4__noop, + [FATTR4_MODE] = nfsd4_encode_fattr4_mode, + [FATTR4_NO_TRUNC] = nfsd4_encode_fattr4__true, + [FATTR4_NUMLINKS] = nfsd4_encode_fattr4_numlinks, + [FATTR4_OWNER] = nfsd4_encode_fattr4_owner, + [FATTR4_OWNER_GROUP] = nfsd4_encode_fattr4_owner_group, + [FATTR4_QUOTA_AVAIL_HARD] = nfsd4_encode_fattr4__noop, + [FATTR4_QUOTA_AVAIL_SOFT] = nfsd4_encode_fattr4__noop, + [FATTR4_QUOTA_USED] = nfsd4_encode_fattr4__noop, + [FATTR4_RAWDEV] = nfsd4_encode_fattr4_rawdev, + [FATTR4_SPACE_AVAIL] = nfsd4_encode_fattr4_space_avail, + [FATTR4_SPACE_FREE] = nfsd4_encode_fattr4_space_free, + [FATTR4_SPACE_TOTAL] = nfsd4_encode_fattr4_space_total, + [FATTR4_SPACE_USED] = nfsd4_encode_fattr4_space_used, + [FATTR4_SYSTEM] = nfsd4_encode_fattr4__noop, + [FATTR4_TIME_ACCESS] = nfsd4_encode_fattr4_time_access, + [FATTR4_TIME_ACCESS_SET] = nfsd4_encode_fattr4__noop, + [FATTR4_TIME_BACKUP] = nfsd4_encode_fattr4__noop, + [FATTR4_TIME_CREATE] = nfsd4_encode_fattr4_time_create, + [FATTR4_TIME_DELTA] = nfsd4_encode_fattr4_time_delta, + [FATTR4_TIME_METADATA] = nfsd4_encode_fattr4_time_metadata, + [FATTR4_TIME_MODIFY] = nfsd4_encode_fattr4_time_modify, + [FATTR4_TIME_MODIFY_SET] = nfsd4_encode_fattr4__noop, + [FATTR4_MOUNTED_ON_FILEID] = nfsd4_encode_fattr4_mounted_on_fileid, + [FATTR4_DIR_NOTIF_DELAY] = nfsd4_encode_fattr4__noop, + [FATTR4_DIRENT_NOTIF_DELAY] = nfsd4_encode_fattr4__noop, + [FATTR4_DACL] = nfsd4_encode_fattr4__noop, + [FATTR4_SACL] = nfsd4_encode_fattr4__noop, + [FATTR4_CHANGE_POLICY] = nfsd4_encode_fattr4__noop, + [FATTR4_FS_STATUS] = nfsd4_encode_fattr4__noop, + +#ifdef CONFIG_NFSD_PNFS + [FATTR4_FS_LAYOUT_TYPES] = nfsd4_encode_fattr4_fs_layout_types, + [FATTR4_LAYOUT_HINT] = nfsd4_encode_fattr4__noop, + [FATTR4_LAYOUT_TYPES] = nfsd4_encode_fattr4_layout_types, + [FATTR4_LAYOUT_BLKSIZE] = nfsd4_encode_fattr4_layout_blksize, + [FATTR4_LAYOUT_ALIGNMENT] = nfsd4_encode_fattr4__noop, +#else + [FATTR4_FS_LAYOUT_TYPES] = nfsd4_encode_fattr4__noop, + [FATTR4_LAYOUT_HINT] = nfsd4_encode_fattr4__noop, + [FATTR4_LAYOUT_TYPES] = nfsd4_encode_fattr4__noop, + [FATTR4_LAYOUT_BLKSIZE] = nfsd4_encode_fattr4__noop, + [FATTR4_LAYOUT_ALIGNMENT] = nfsd4_encode_fattr4__noop, +#endif + + [FATTR4_FS_LOCATIONS_INFO] = nfsd4_encode_fattr4__noop, + [FATTR4_MDSTHRESHOLD] = nfsd4_encode_fattr4__noop, + [FATTR4_RETENTION_GET] = nfsd4_encode_fattr4__noop, + [FATTR4_RETENTION_SET] = nfsd4_encode_fattr4__noop, + [FATTR4_RETENTEVT_GET] = nfsd4_encode_fattr4__noop, + [FATTR4_RETENTEVT_SET] = nfsd4_encode_fattr4__noop, + [FATTR4_RETENTION_HOLD] = nfsd4_encode_fattr4__noop, + [FATTR4_MODE_SET_MASKED] = nfsd4_encode_fattr4__noop, + [FATTR4_SUPPATTR_EXCLCREAT] = nfsd4_encode_fattr4_suppattr_exclcreat, + [FATTR4_FS_CHARSET_CAP] = nfsd4_encode_fattr4__noop, + [FATTR4_CLONE_BLKSIZE] = nfsd4_encode_fattr4__noop, + [FATTR4_SPACE_FREED] = nfsd4_encode_fattr4__noop, + [FATTR4_CHANGE_ATTR_TYPE] = nfsd4_encode_fattr4__noop, + +#ifdef CONFIG_NFSD_V4_SECURITY_LABEL + [FATTR4_SEC_LABEL] = nfsd4_encode_fattr4_sec_label, +#else + [FATTR4_SEC_LABEL] = nfsd4_encode_fattr4__noop, +#endif + + [FATTR4_MODE_UMASK] = nfsd4_encode_fattr4__noop, + [FATTR4_XATTR_SUPPORT] = nfsd4_encode_fattr4_xattr_support, +}; + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -3362,13 +3473,10 @@ static __be32 nfsd4_encode_fattr4_xattr_support(struct xdr_stream *xdr, static __be32 nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, struct svc_export *exp, - struct dentry *dentry, u32 *bmval, + struct dentry *dentry, const u32 *bmval, struct svc_rqst *rqstp, int ignore_crossmnt) { struct nfsd4_fattr_args args; - u32 bmval0 = bmval[0]; - u32 bmval1 = bmval[1]; - u32 bmval2 = bmval[2]; struct svc_fh *tempfh = NULL; int starting_len = xdr->buf->len; __be32 *attrlen_p, status; @@ -3380,26 +3488,39 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, .mnt = exp->ex_path.mnt, .dentry = dentry, }; + union { + u32 attrmask[3]; + unsigned long mask[2]; + } u; bool file_modified; + unsigned long bit; u64 size = 0; - BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1); - BUG_ON(!nfsd_attrs_supported(minorversion, bmval)); + WARN_ON_ONCE(bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1); + WARN_ON_ONCE(!nfsd_attrs_supported(minorversion, bmval)); args.rqstp = rqstp; args.exp = exp; args.dentry = dentry; args.ignore_crossmnt = (ignore_crossmnt != 0); + /* + * Make a local copy of the attribute bitmap that can be modified. + */ + memset(&u, 0, sizeof(u)); + u.attrmask[0] = bmval[0]; + u.attrmask[1] = bmval[1]; + u.attrmask[2] = bmval[2]; + args.rdattr_err = 0; if (exp->ex_fslocs.migrated) { - status = fattr_handle_absent_fs(&bmval0, &bmval1, &bmval2, - &args.rdattr_err); + status = fattr_handle_absent_fs(&u.attrmask[0], &u.attrmask[1], + &u.attrmask[2], &args.rdattr_err); if (status) goto out; } args.size = 0; - if (bmval0 & (FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE)) { + if (u.attrmask[0] & (FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE)) { status = nfsd4_deleg_getattr_conflict(rqstp, d_inode(dentry), &file_modified, &size); if (status) @@ -3415,16 +3536,17 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, if (!(args.stat.result_mask & STATX_BTIME)) /* underlying FS does not offer btime so we can't share it */ - bmval1 &= ~FATTR4_WORD1_TIME_CREATE; - if ((bmval0 & (FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE | + u.attrmask[1] &= ~FATTR4_WORD1_TIME_CREATE; + if ((u.attrmask[0] & (FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_MAXNAME)) || - (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | + (u.attrmask[1] & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL))) { err = vfs_statfs(&path, &args.statfs); if (err) goto out_nfserr; } - if ((bmval0 & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) && !fhp) { + if ((u.attrmask[0] & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) && + !fhp) { tempfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL); status = nfserr_jukebox; if (!tempfh) @@ -3438,10 +3560,10 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, args.fhp = fhp; args.acl = NULL; - if (bmval0 & FATTR4_WORD0_ACL) { + if (u.attrmask[0] & FATTR4_WORD0_ACL) { err = nfsd4_get_nfs4_acl(rqstp, dentry, &args.acl); if (err == -EOPNOTSUPP) - bmval0 &= ~FATTR4_WORD0_ACL; + u.attrmask[0] &= ~FATTR4_WORD0_ACL; else if (err == -EINVAL) { status = nfserr_attrnotsupp; goto out; @@ -3453,24 +3575,25 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, #ifdef CONFIG_NFSD_V4_SECURITY_LABEL args.context = NULL; - if ((bmval2 & FATTR4_WORD2_SECURITY_LABEL) || - bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) { + if ((u.attrmask[2] & FATTR4_WORD2_SECURITY_LABEL) || + u.attrmask[0] & FATTR4_WORD0_SUPPORTED_ATTRS) { if (exp->ex_flags & NFSEXP_SECURITY_LABEL) err = security_inode_getsecctx(d_inode(dentry), &args.context, &args.contextlen); else err = -EOPNOTSUPP; args.contextsupport = (err == 0); - if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { + if (u.attrmask[2] & FATTR4_WORD2_SECURITY_LABEL) { if (err == -EOPNOTSUPP) - bmval2 &= ~FATTR4_WORD2_SECURITY_LABEL; + u.attrmask[2] &= ~FATTR4_WORD2_SECURITY_LABEL; else if (err) goto out_nfserr; } } #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ - status = nfsd4_encode_bitmap4(xdr, bmval0, bmval1, bmval2); + status = nfsd4_encode_bitmap4(xdr, u.attrmask[0], + u.attrmask[1], u.attrmask[2]); if (status) goto out; @@ -3478,276 +3601,12 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, attrlen_p = xdr_reserve_space(xdr, XDR_UNIT); if (!attrlen_p) goto out_resource; - - if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) { - status = nfsd4_encode_fattr4_supported_attrs(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_TYPE) { - status = nfsd4_encode_fattr4_type(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) { - status = nfsd4_encode_fattr4_fh_expire_type(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_CHANGE) { - status = nfsd4_encode_fattr4_change(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_SIZE) { - status = nfsd4_encode_fattr4_size(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_LINK_SUPPORT) { - status = nfsd4_encode_fattr4__true(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_SYMLINK_SUPPORT) { - status = nfsd4_encode_fattr4__true(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_NAMED_ATTR) { - status = nfsd4_encode_fattr4__false(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_FSID) { - status = nfsd4_encode_fattr4_fsid(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) { - status = nfsd4_encode_fattr4__false(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_LEASE_TIME) { - status = nfsd4_encode_fattr4_lease_time(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) { - status = nfsd4_encode_fattr4_rdattr_error(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_ACL) { - status = nfsd4_encode_fattr4_acl(xdr, &args); - if (status) - goto out; - } - if (bmval0 & FATTR4_WORD0_ACLSUPPORT) { - status = nfsd4_encode_fattr4_aclsupport(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_CANSETTIME) { - status = nfsd4_encode_fattr4__true(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_CASE_INSENSITIVE) { - status = nfsd4_encode_fattr4__false(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_CASE_PRESERVING) { - status = nfsd4_encode_fattr4__true(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_CHOWN_RESTRICTED) { - status = nfsd4_encode_fattr4__true(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_FILEHANDLE) { - status = nfsd4_encode_fattr4_filehandle(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_FILEID) { - status = nfsd4_encode_fattr4_fileid(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_FILES_AVAIL) { - status = nfsd4_encode_fattr4_files_avail(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_FILES_FREE) { - status = nfsd4_encode_fattr4_files_free(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_FILES_TOTAL) { - status = nfsd4_encode_fattr4_files_total(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) { - status = nfsd4_encode_fattr4_fs_locations(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_HOMOGENEOUS) { - status = nfsd4_encode_fattr4__true(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_MAXFILESIZE) { - status = nfsd4_encode_fattr4_maxfilesize(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_MAXLINK) { - status = nfsd4_encode_fattr4_maxlink(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_MAXNAME) { - status = nfsd4_encode_fattr4_maxname(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_MAXREAD) { - status = nfsd4_encode_fattr4_maxread(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval0 & FATTR4_WORD0_MAXWRITE) { - status = nfsd4_encode_fattr4_maxwrite(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval1 & FATTR4_WORD1_MODE) { - status = nfsd4_encode_fattr4_mode(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval1 & FATTR4_WORD1_NO_TRUNC) { - status = nfsd4_encode_fattr4__true(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval1 & FATTR4_WORD1_NUMLINKS) { - status = nfsd4_encode_fattr4_numlinks(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval1 & FATTR4_WORD1_OWNER) { - status = nfsd4_encode_fattr4_owner(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval1 & FATTR4_WORD1_OWNER_GROUP) { - status = nfsd4_encode_fattr4_owner_group(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval1 & FATTR4_WORD1_RAWDEV) { - status = nfsd4_encode_fattr4_rawdev(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) { - status = nfsd4_encode_fattr4_space_avail(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval1 & FATTR4_WORD1_SPACE_FREE) { - status = nfsd4_encode_fattr4_space_free(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) { - status = nfsd4_encode_fattr4_space_total(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval1 & FATTR4_WORD1_SPACE_USED) { - status = nfsd4_encode_fattr4_space_used(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval1 & FATTR4_WORD1_TIME_ACCESS) { - status = nfsd4_encode_fattr4_time_access(xdr, &args); - if (status) - goto out; - } - if (bmval1 & FATTR4_WORD1_TIME_CREATE) { - status = nfsd4_encode_fattr4_time_create(xdr, &args); - if (status) - goto out; - } - if (bmval1 & FATTR4_WORD1_TIME_DELTA) { - status = nfsd4_encode_fattr4_time_delta(xdr, &args); - if (status != nfs_ok) - goto out; - } - if (bmval1 & FATTR4_WORD1_TIME_METADATA) { - status = nfsd4_encode_fattr4_time_metadata(xdr, &args); - if (status) - goto out; - } - if (bmval1 & FATTR4_WORD1_TIME_MODIFY) { - status = nfsd4_encode_fattr4_time_modify(xdr, &args); - if (status) - goto out; - } - if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { - status = nfsd4_encode_fattr4_mounted_on_fileid(xdr, &args); - if (status != nfs_ok) - goto out; - } -#ifdef CONFIG_NFSD_PNFS - if (bmval1 & FATTR4_WORD1_FS_LAYOUT_TYPES) { - status = nfsd4_encode_fattr4_fs_layout_types(xdr, &args); - if (status) - goto out; - } - - if (bmval2 & FATTR4_WORD2_LAYOUT_TYPES) { - status = nfsd4_encode_fattr4_layout_types(xdr, &args); - if (status) - goto out; - } - - if (bmval2 & FATTR4_WORD2_LAYOUT_BLKSIZE) { - status = nfsd4_encode_fattr4_layout_blksize(xdr, &args); + for_each_set_bit(bit, (const unsigned long *)&u.mask, + ARRAY_SIZE(nfsd4_enc_fattr4_encode_ops)) { + status = nfsd4_enc_fattr4_encode_ops[bit](xdr, &args); if (status != nfs_ok) goto out; } -#endif /* CONFIG_NFSD_PNFS */ - if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { - status = nfsd4_encode_fattr4_suppattr_exclcreat(xdr, &args); - if (status) - goto out; - } - -#ifdef CONFIG_NFSD_V4_SECURITY_LABEL - if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { - status = nfsd4_encode_fattr4_sec_label(xdr, &args); - if (status) - goto out; - } -#endif - - if (bmval2 & FATTR4_WORD2_XATTR_SUPPORT) { - status = nfsd4_encode_fattr4_xattr_support(xdr, &args); - if (status != nfs_ok) - goto out; - } - *attrlen_p = cpu_to_be32(xdr->buf->len - attrlen_offset - XDR_UNIT); status = nfs_ok; -- cgit v1.2.3 From ae1131d45bf9e110a0f95e9ada64a59693ccf21e Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 18 Sep 2023 10:02:18 -0400 Subject: NFSD: Rename nfsd4_encode_fattr() For better alignment with the specification, NFSD's encoder function name should match the name of the XDR data type. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 5c249d806153..1bb03fc0407f 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3471,10 +3471,10 @@ static const nfsd4_enc_attr nfsd4_enc_fattr4_encode_ops[] = { * ourselves. */ static __be32 -nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, - struct svc_export *exp, - struct dentry *dentry, const u32 *bmval, - struct svc_rqst *rqstp, int ignore_crossmnt) +nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr, + struct svc_fh *fhp, struct svc_export *exp, + struct dentry *dentry, const u32 *bmval, + int ignore_crossmnt) { struct nfsd4_fattr_args args; struct svc_fh *tempfh = NULL; @@ -3592,11 +3592,13 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, } #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ + /* attrmask */ status = nfsd4_encode_bitmap4(xdr, u.attrmask[0], u.attrmask[1], u.attrmask[2]); if (status) goto out; + /* attr_vals */ attrlen_offset = xdr->buf->len; attrlen_p = xdr_reserve_space(xdr, XDR_UNIT); if (!attrlen_p) @@ -3656,8 +3658,8 @@ __be32 nfsd4_encode_fattr_to_buf(__be32 **p, int words, __be32 ret; svcxdr_init_encode_from_buffer(&xdr, &dummy, *p, words << 2); - ret = nfsd4_encode_fattr(&xdr, fhp, exp, dentry, bmval, rqstp, - ignore_crossmnt); + ret = nfsd4_encode_fattr4(rqstp, &xdr, fhp, exp, dentry, bmval, + ignore_crossmnt); *p = xdr.p; return ret; } @@ -3716,8 +3718,8 @@ nfsd4_encode_dirent_fattr(struct xdr_stream *xdr, struct nfsd4_readdir *cd, } out_encode: - nfserr = nfsd4_encode_fattr(xdr, NULL, exp, dentry, cd->rd_bmval, - cd->rd_rqstp, ignore_crossmnt); + nfserr = nfsd4_encode_fattr4(cd->rd_rqstp, xdr, NULL, exp, dentry, + cd->rd_bmval, ignore_crossmnt); out_put: dput(dentry); exp_put(exp); @@ -3961,8 +3963,9 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh *fhp = getattr->ga_fhp; struct xdr_stream *xdr = resp->xdr; - return nfsd4_encode_fattr(xdr, fhp, fhp->fh_export, fhp->fh_dentry, - getattr->ga_bmval, resp->rqstp, 0); + /* obj_attributes */ + return nfsd4_encode_fattr4(resp->rqstp, xdr, fhp, fhp->fh_export, + fhp->fh_dentry, getattr->ga_bmval, 0); } static __be32 -- cgit v1.2.3 From 76bebcc7640eaac7213ab6ef97b3376733c69123 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 25 Sep 2023 09:27:38 -0400 Subject: NFSD: Add nfsd4_encode_count4() This is a synonym for nfsd4_encode_uint32_t() that matches the name of the XDR type. It will get at least one more use in a subsequent patch. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 13 +++++++++---- fs/nfsd/xdr4.h | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 1bb03fc0407f..50041380429a 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4619,12 +4619,17 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, union nfsd4_op_u *u) { struct nfsd4_write *write = &u->write; + struct xdr_stream *xdr = resp->xdr; - if (xdr_stream_encode_u32(resp->xdr, write->wr_bytes_written) < 0) - return nfserr_resource; - if (xdr_stream_encode_u32(resp->xdr, write->wr_how_written) < 0) + /* count */ + nfserr = nfsd4_encode_count4(xdr, write->wr_bytes_written); + if (nfserr) + return nfserr; + /* committed */ + if (xdr_stream_encode_u32(xdr, write->wr_how_written) != XDR_UNIT) return nfserr_resource; - return nfsd4_encode_verifier4(resp->xdr, &write->wr_verifier); + /* writeverf */ + return nfsd4_encode_verifier4(xdr, &write->wr_verifier); } static __be32 diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 52322acc1e9f..43b9c53b7795 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -93,6 +93,7 @@ nfsd4_encode_uint32_t(struct xdr_stream *xdr, u32 val) #define nfsd4_encode_aceflag4(x, v) nfsd4_encode_uint32_t(x, v) #define nfsd4_encode_acemask4(x, v) nfsd4_encode_uint32_t(x, v) #define nfsd4_encode_acetype4(x, v) nfsd4_encode_uint32_t(x, v) +#define nfsd4_encode_count4(x, v) nfsd4_encode_uint32_t(x, v) #define nfsd4_encode_mode4(x, v) nfsd4_encode_uint32_t(x, v) #define nfsd4_encode_nfs_lease4(x, v) nfsd4_encode_uint32_t(x, v) -- cgit v1.2.3 From 40bb2baaa8edecfc21a3c176e4af1a3445157677 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 25 Sep 2023 09:27:45 -0400 Subject: NFSD: Clean up nfsd4_encode_stateid() Update the encoder function name to match the type name, as is the convention with other such encoder utility functions, and with nfsd4_decode_stateid4(). Make the @stateid argument a const so that callers of nfsd4_encode_stateid4() in the future can be passed const pointers to structures. Since the compiler is allowed to add padding to structs, use the wire (spec-defined) size when reserving buffer space. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 50041380429a..d42556bf8f95 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3871,18 +3871,18 @@ nfsd4_encode_clientid4(struct xdr_stream *xdr, const clientid_t *clientid) return nfs_ok; } +/* This is a frequently-encoded item; open-coded for speed */ static __be32 -nfsd4_encode_stateid(struct xdr_stream *xdr, stateid_t *sid) +nfsd4_encode_stateid4(struct xdr_stream *xdr, const stateid_t *sid) { __be32 *p; - p = xdr_reserve_space(xdr, sizeof(stateid_t)); + p = xdr_reserve_space(xdr, NFS4_STATEID_SIZE); if (!p) return nfserr_resource; *p++ = cpu_to_be32(sid->si_generation); - p = xdr_encode_opaque_fixed(p, &sid->si_opaque, - sizeof(stateid_opaque_t)); - return 0; + memcpy(p, &sid->si_opaque, sizeof(sid->si_opaque)); + return nfs_ok; } static __be32 @@ -3926,7 +3926,8 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close = &u->close; struct xdr_stream *xdr = resp->xdr; - return nfsd4_encode_stateid(xdr, &close->cl_stateid); + /* open_stateid */ + return nfsd4_encode_stateid4(xdr, &close->cl_stateid); } @@ -4026,7 +4027,7 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct xdr_stream *xdr = resp->xdr; if (!nfserr) - nfserr = nfsd4_encode_stateid(xdr, &lock->lk_resp_stateid); + nfserr = nfsd4_encode_stateid4(xdr, &lock->lk_resp_stateid); else if (nfserr == nfserr_denied) nfserr = nfsd4_encode_lock_denied(xdr, &lock->lk_denied); @@ -4052,7 +4053,8 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku = &u->locku; struct xdr_stream *xdr = resp->xdr; - return nfsd4_encode_stateid(xdr, &locku->lu_stateid); + /* lock_stateid */ + return nfsd4_encode_stateid4(xdr, &locku->lu_stateid); } @@ -4075,7 +4077,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct xdr_stream *xdr = resp->xdr; __be32 *p; - nfserr = nfsd4_encode_stateid(xdr, &open->op_stateid); + nfserr = nfsd4_encode_stateid4(xdr, &open->op_stateid); if (nfserr) return nfserr; nfserr = nfsd4_encode_change_info4(xdr, &open->op_cinfo); @@ -4098,7 +4100,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, case NFS4_OPEN_DELEGATE_NONE: break; case NFS4_OPEN_DELEGATE_READ: - nfserr = nfsd4_encode_stateid(xdr, &open->op_delegate_stateid); + nfserr = nfsd4_encode_stateid4(xdr, &open->op_delegate_stateid); if (nfserr) return nfserr; p = xdr_reserve_space(xdr, 20); @@ -4115,7 +4117,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, *p++ = cpu_to_be32(0); /* XXX: is NULL principal ok? */ break; case NFS4_OPEN_DELEGATE_WRITE: - nfserr = nfsd4_encode_stateid(xdr, &open->op_delegate_stateid); + nfserr = nfsd4_encode_stateid4(xdr, &open->op_delegate_stateid); if (nfserr) return nfserr; @@ -4173,7 +4175,8 @@ nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc = &u->open_confirm; struct xdr_stream *xdr = resp->xdr; - return nfsd4_encode_stateid(xdr, &oc->oc_resp_stateid); + /* open_stateid */ + return nfsd4_encode_stateid4(xdr, &oc->oc_resp_stateid); } static __be32 @@ -4183,7 +4186,8 @@ nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od = &u->open_downgrade; struct xdr_stream *xdr = resp->xdr; - return nfsd4_encode_stateid(xdr, &od->od_stateid); + /* open_stateid */ + return nfsd4_encode_stateid4(xdr, &od->od_stateid); } /* @@ -4923,7 +4927,7 @@ nfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr, return nfserr_resource; *p++ = cpu_to_be32(lrp->lrs_present); if (lrp->lrs_present) - return nfsd4_encode_stateid(xdr, &lrp->lr_sid); + return nfsd4_encode_stateid4(xdr, &lrp->lr_sid); return 0; } #endif /* CONFIG_NFSD_PNFS */ @@ -4942,7 +4946,7 @@ nfsd42_encode_write_res(struct nfsd4_compoundres *resp, else { __be32 nfserr; *p++ = cpu_to_be32(1); - nfserr = nfsd4_encode_stateid(resp->xdr, &write->cb_stateid); + nfserr = nfsd4_encode_stateid4(resp->xdr, &write->cb_stateid); if (nfserr) return nfserr; } @@ -5126,7 +5130,7 @@ nfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr, *p++ = cpu_to_be32(cn->cpn_nsec); /* cnr_stateid */ - nfserr = nfsd4_encode_stateid(xdr, &cn->cpn_cnr_stateid); + nfserr = nfsd4_encode_stateid4(xdr, &cn->cpn_cnr_stateid); if (nfserr) return nfserr; -- cgit v1.2.3 From 73debe47df8e7535e3ca86a050cfd988133fea77 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 25 Sep 2023 09:27:51 -0400 Subject: NFSD: Make @lgp parameter of ->encode_layoutget a const pointer This enables callers to be passed const pointer parameters. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/blocklayoutxdr.c | 4 ++-- fs/nfsd/blocklayoutxdr.h | 2 +- fs/nfsd/flexfilelayoutxdr.c | 4 ++-- fs/nfsd/flexfilelayoutxdr.h | 2 +- fs/nfsd/pnfs.h | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/blocklayoutxdr.c b/fs/nfsd/blocklayoutxdr.c index 1ed2f691ebb9..f8469348e06e 100644 --- a/fs/nfsd/blocklayoutxdr.c +++ b/fs/nfsd/blocklayoutxdr.c @@ -16,9 +16,9 @@ __be32 nfsd4_block_encode_layoutget(struct xdr_stream *xdr, - struct nfsd4_layoutget *lgp) + const struct nfsd4_layoutget *lgp) { - struct pnfs_block_extent *b = lgp->lg_content; + const struct pnfs_block_extent *b = lgp->lg_content; int len = sizeof(__be32) + 5 * sizeof(__be64) + sizeof(__be32); __be32 *p; diff --git a/fs/nfsd/blocklayoutxdr.h b/fs/nfsd/blocklayoutxdr.h index bc5166bfe46b..5f88539e81a1 100644 --- a/fs/nfsd/blocklayoutxdr.h +++ b/fs/nfsd/blocklayoutxdr.h @@ -53,7 +53,7 @@ struct pnfs_block_deviceaddr { __be32 nfsd4_block_encode_getdeviceinfo(struct xdr_stream *xdr, struct nfsd4_getdeviceinfo *gdp); __be32 nfsd4_block_encode_layoutget(struct xdr_stream *xdr, - struct nfsd4_layoutget *lgp); + const struct nfsd4_layoutget *lgp); int nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp, u32 block_size); int nfsd4_scsi_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp, diff --git a/fs/nfsd/flexfilelayoutxdr.c b/fs/nfsd/flexfilelayoutxdr.c index bb205328e043..5319cb97d8a7 100644 --- a/fs/nfsd/flexfilelayoutxdr.c +++ b/fs/nfsd/flexfilelayoutxdr.c @@ -17,9 +17,9 @@ struct ff_idmap { __be32 nfsd4_ff_encode_layoutget(struct xdr_stream *xdr, - struct nfsd4_layoutget *lgp) + const struct nfsd4_layoutget *lgp) { - struct pnfs_ff_layout *fl = lgp->lg_content; + const struct pnfs_ff_layout *fl = lgp->lg_content; int len, mirror_len, ds_len, fh_len; __be32 *p; diff --git a/fs/nfsd/flexfilelayoutxdr.h b/fs/nfsd/flexfilelayoutxdr.h index 8e195aeca023..a447efb7759b 100644 --- a/fs/nfsd/flexfilelayoutxdr.h +++ b/fs/nfsd/flexfilelayoutxdr.h @@ -45,6 +45,6 @@ struct pnfs_ff_layout { __be32 nfsd4_ff_encode_getdeviceinfo(struct xdr_stream *xdr, struct nfsd4_getdeviceinfo *gdp); __be32 nfsd4_ff_encode_layoutget(struct xdr_stream *xdr, - struct nfsd4_layoutget *lgp); + const struct nfsd4_layoutget *lgp); #endif /* _NFSD_FLEXFILELAYOUTXDR_H */ diff --git a/fs/nfsd/pnfs.h b/fs/nfsd/pnfs.h index 4f4282d4eeca..d8e1a333fa0a 100644 --- a/fs/nfsd/pnfs.h +++ b/fs/nfsd/pnfs.h @@ -31,8 +31,8 @@ struct nfsd4_layout_ops { __be32 (*proc_layoutget)(struct inode *, const struct svc_fh *fhp, struct nfsd4_layoutget *lgp); - __be32 (*encode_layoutget)(struct xdr_stream *, - struct nfsd4_layoutget *lgp); + __be32 (*encode_layoutget)(struct xdr_stream *xdr, + const struct nfsd4_layoutget *lgp); __be32 (*proc_layoutcommit)(struct inode *inode, struct nfsd4_layoutcommit *lcp); -- cgit v1.2.3 From 69f5f0194a7f0f6bb22676a75dc81357a6d22698 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 25 Sep 2023 09:27:58 -0400 Subject: NFSD: Clean up nfsd4_encode_layoutget() De-duplicate the open-coded stateid4 encoder. Adopt the use of the conventional current XDR encoding helpers. Refactor the encoder to align with the XDR specification. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 52 ++++++++++++++++++++++++++++++++++------------------ fs/nfsd/xdr4.h | 2 ++ 2 files changed, 36 insertions(+), 18 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index d42556bf8f95..8839788b268d 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4864,32 +4864,48 @@ toosmall: return nfserr_toosmall; } +static __be32 +nfsd4_encode_layout4(struct xdr_stream *xdr, const struct nfsd4_layoutget *lgp) +{ + const struct nfsd4_layout_ops *ops = nfsd4_layout_ops[lgp->lg_layout_type]; + __be32 status; + + /* lo_offset */ + status = nfsd4_encode_offset4(xdr, lgp->lg_seg.offset); + if (status != nfs_ok) + return status; + /* lo_length */ + status = nfsd4_encode_length4(xdr, lgp->lg_seg.length); + if (status != nfs_ok) + return status; + /* lo_iomode */ + if (xdr_stream_encode_u32(xdr, lgp->lg_seg.iomode) != XDR_UNIT) + return nfserr_resource; + /* lo_content */ + if (xdr_stream_encode_u32(xdr, lgp->lg_layout_type) != XDR_UNIT) + return nfserr_resource; + return ops->encode_layoutget(xdr, lgp); +} + static __be32 nfsd4_encode_layoutget(struct nfsd4_compoundres *resp, __be32 nfserr, union nfsd4_op_u *u) { struct nfsd4_layoutget *lgp = &u->layoutget; struct xdr_stream *xdr = resp->xdr; - const struct nfsd4_layout_ops *ops; - __be32 *p; - p = xdr_reserve_space(xdr, 36 + sizeof(stateid_opaque_t)); - if (!p) + /* logr_return_on_close */ + nfserr = nfsd4_encode_bool(xdr, true); + if (nfserr != nfs_ok) + return nfserr; + /* logr_stateid */ + nfserr = nfsd4_encode_stateid4(xdr, &lgp->lg_sid); + if (nfserr != nfs_ok) + return nfserr; + /* logr_layout<> */ + if (xdr_stream_encode_u32(xdr, 1) != XDR_UNIT) return nfserr_resource; - - *p++ = cpu_to_be32(1); /* we always set return-on-close */ - *p++ = cpu_to_be32(lgp->lg_sid.si_generation); - p = xdr_encode_opaque_fixed(p, &lgp->lg_sid.si_opaque, - sizeof(stateid_opaque_t)); - - *p++ = cpu_to_be32(1); /* we always return a single layout */ - p = xdr_encode_hyper(p, lgp->lg_seg.offset); - p = xdr_encode_hyper(p, lgp->lg_seg.length); - *p++ = cpu_to_be32(lgp->lg_seg.iomode); - *p++ = cpu_to_be32(lgp->lg_layout_type); - - ops = nfsd4_layout_ops[lgp->lg_layout_type]; - return ops->encode_layoutget(xdr, lgp); + return nfsd4_encode_layout4(xdr, lgp); } static __be32 diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 43b9c53b7795..1a99db22b25c 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -118,6 +118,8 @@ nfsd4_encode_uint64_t(struct xdr_stream *xdr, u64 val) } #define nfsd4_encode_changeid4(x, v) nfsd4_encode_uint64_t(x, v) +#define nfsd4_encode_length4(x, v) nfsd4_encode_uint64_t(x, v) +#define nfsd4_encode_offset4(x, v) nfsd4_encode_uint64_t(x, v) /** * nfsd4_encode_opaque_fixed - Encode a fixed-length XDR opaque type result -- cgit v1.2.3 From cc313f80d0591aa5076761ce1854e3ef144084ec Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 25 Sep 2023 09:28:04 -0400 Subject: NFSD: Clean up nfsd4_encode_layoutcommit() Adopt the use of conventional XDR utility functions. Restructure the encoder to better align with the XDR definition of the result. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4proc.c | 4 ++-- fs/nfsd/nfs4xdr.c | 21 ++++++++------------- fs/nfsd/xdr4.h | 2 +- 3 files changed, 11 insertions(+), 16 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index d7e88c7beba3..60262fd27b15 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -2357,10 +2357,10 @@ nfsd4_layoutcommit(struct svc_rqst *rqstp, mutex_unlock(&ls->ls_mutex); if (new_size > i_size_read(inode)) { - lcp->lc_size_chg = 1; + lcp->lc_size_chg = true; lcp->lc_newsize = new_size; } else { - lcp->lc_size_chg = 0; + lcp->lc_size_chg = false; } nfserr = ops->proc_layoutcommit(inode, lcp); diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 8839788b268d..0f8f1f7d5840 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4914,20 +4914,15 @@ nfsd4_encode_layoutcommit(struct nfsd4_compoundres *resp, __be32 nfserr, { struct nfsd4_layoutcommit *lcp = &u->layoutcommit; struct xdr_stream *xdr = resp->xdr; - __be32 *p; - - p = xdr_reserve_space(xdr, 4); - if (!p) - return nfserr_resource; - *p++ = cpu_to_be32(lcp->lc_size_chg); - if (lcp->lc_size_chg) { - p = xdr_reserve_space(xdr, 8); - if (!p) - return nfserr_resource; - p = xdr_encode_hyper(p, lcp->lc_newsize); - } - return 0; + /* ns_sizechanged */ + nfserr = nfsd4_encode_bool(xdr, lcp->lc_size_chg); + if (nfserr != nfs_ok) + return nfserr; + if (lcp->lc_size_chg) + /* ns_size */ + return nfsd4_encode_length4(xdr, lcp->lc_newsize); + return nfs_ok; } static __be32 diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 1a99db22b25c..1b393f1734e4 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -618,7 +618,7 @@ struct nfsd4_layoutcommit { u32 lc_layout_type; /* request */ u32 lc_up_len; /* layout length */ void *lc_up_layout; /* decoded by callback */ - u32 lc_size_chg; /* boolean for response */ + bool lc_size_chg; /* response */ u64 lc_newsize; /* response */ }; -- cgit v1.2.3 From 85dbc978b33be6f5e2e06e34b5219d730d5f9aa4 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 25 Sep 2023 09:28:10 -0400 Subject: NFSD: Clean up nfsd4_encode_layoutreturn() Adopt the use of conventional XDR utility functions. Restructure the encoder to better align with the XDR definition of the result. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4layouts.c | 6 +++--- fs/nfsd/nfs4xdr.c | 12 ++++++------ fs/nfsd/xdr4.h | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c index e8a80052cb1b..5e8096bc5eaa 100644 --- a/fs/nfsd/nfs4layouts.c +++ b/fs/nfsd/nfs4layouts.c @@ -515,11 +515,11 @@ nfsd4_return_file_layouts(struct svc_rqst *rqstp, if (!list_empty(&ls->ls_layouts)) { if (found) nfs4_inc_and_copy_stateid(&lrp->lr_sid, &ls->ls_stid); - lrp->lrs_present = 1; + lrp->lrs_present = true; } else { trace_nfsd_layoutstate_unhash(&ls->ls_stid.sc_stateid); nfs4_unhash_stid(&ls->ls_stid); - lrp->lrs_present = 0; + lrp->lrs_present = false; } spin_unlock(&ls->ls_lock); @@ -539,7 +539,7 @@ nfsd4_return_client_layouts(struct svc_rqst *rqstp, struct nfs4_layout *lp, *t; LIST_HEAD(reaplist); - lrp->lrs_present = 0; + lrp->lrs_present = false; spin_lock(&clp->cl_lock); list_for_each_entry_safe(ls, n, &clp->cl_lo_states, ls_perclnt) { diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 0f8f1f7d5840..4e4d1af39528 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4931,15 +4931,15 @@ nfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr, { struct nfsd4_layoutreturn *lrp = &u->layoutreturn; struct xdr_stream *xdr = resp->xdr; - __be32 *p; - p = xdr_reserve_space(xdr, 4); - if (!p) - return nfserr_resource; - *p++ = cpu_to_be32(lrp->lrs_present); + /* lrs_present */ + nfserr = nfsd4_encode_bool(xdr, lrp->lrs_present); + if (nfserr != nfs_ok) + return nfserr; if (lrp->lrs_present) + /* lrs_stateid */ return nfsd4_encode_stateid4(xdr, &lrp->lr_sid); - return 0; + return nfs_ok; } #endif /* CONFIG_NFSD_PNFS */ diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 1b393f1734e4..aba07d5378fc 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -630,7 +630,7 @@ struct nfsd4_layoutreturn { u32 lrf_body_len; /* request */ void *lrf_body; /* request */ stateid_t lr_sid; /* request/response */ - u32 lrs_present; /* response */ + bool lrs_present; /* response */ }; struct nfsd4_fallocate { -- cgit v1.2.3 From 82e93bab50625deef545bc5291fd2749e9aabcd6 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 25 Sep 2023 09:28:17 -0400 Subject: NFSD: Make @gdev parameter of ->encode_getdeviceinfo a const pointer This enables callers to be passed const pointer parameters. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/blocklayoutxdr.c | 2 +- fs/nfsd/blocklayoutxdr.h | 2 +- fs/nfsd/flexfilelayoutxdr.c | 2 +- fs/nfsd/flexfilelayoutxdr.h | 2 +- fs/nfsd/pnfs.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/blocklayoutxdr.c b/fs/nfsd/blocklayoutxdr.c index f8469348e06e..ce78f74715ee 100644 --- a/fs/nfsd/blocklayoutxdr.c +++ b/fs/nfsd/blocklayoutxdr.c @@ -77,7 +77,7 @@ nfsd4_block_encode_volume(struct xdr_stream *xdr, struct pnfs_block_volume *b) __be32 nfsd4_block_encode_getdeviceinfo(struct xdr_stream *xdr, - struct nfsd4_getdeviceinfo *gdp) + const struct nfsd4_getdeviceinfo *gdp) { struct pnfs_block_deviceaddr *dev = gdp->gd_device; int len = sizeof(__be32), ret, i; diff --git a/fs/nfsd/blocklayoutxdr.h b/fs/nfsd/blocklayoutxdr.h index 5f88539e81a1..b0361e8aa9a7 100644 --- a/fs/nfsd/blocklayoutxdr.h +++ b/fs/nfsd/blocklayoutxdr.h @@ -51,7 +51,7 @@ struct pnfs_block_deviceaddr { }; __be32 nfsd4_block_encode_getdeviceinfo(struct xdr_stream *xdr, - struct nfsd4_getdeviceinfo *gdp); + const struct nfsd4_getdeviceinfo *gdp); __be32 nfsd4_block_encode_layoutget(struct xdr_stream *xdr, const struct nfsd4_layoutget *lgp); int nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp, diff --git a/fs/nfsd/flexfilelayoutxdr.c b/fs/nfsd/flexfilelayoutxdr.c index 5319cb97d8a7..aeb71c10ff1b 100644 --- a/fs/nfsd/flexfilelayoutxdr.c +++ b/fs/nfsd/flexfilelayoutxdr.c @@ -77,7 +77,7 @@ nfsd4_ff_encode_layoutget(struct xdr_stream *xdr, __be32 nfsd4_ff_encode_getdeviceinfo(struct xdr_stream *xdr, - struct nfsd4_getdeviceinfo *gdp) + const struct nfsd4_getdeviceinfo *gdp) { struct pnfs_ff_device_addr *da = gdp->gd_device; int len; diff --git a/fs/nfsd/flexfilelayoutxdr.h b/fs/nfsd/flexfilelayoutxdr.h index a447efb7759b..6d5a1066a903 100644 --- a/fs/nfsd/flexfilelayoutxdr.h +++ b/fs/nfsd/flexfilelayoutxdr.h @@ -43,7 +43,7 @@ struct pnfs_ff_layout { }; __be32 nfsd4_ff_encode_getdeviceinfo(struct xdr_stream *xdr, - struct nfsd4_getdeviceinfo *gdp); + const struct nfsd4_getdeviceinfo *gdp); __be32 nfsd4_ff_encode_layoutget(struct xdr_stream *xdr, const struct nfsd4_layoutget *lgp); diff --git a/fs/nfsd/pnfs.h b/fs/nfsd/pnfs.h index d8e1a333fa0a..de1e0dfed06a 100644 --- a/fs/nfsd/pnfs.h +++ b/fs/nfsd/pnfs.h @@ -27,7 +27,7 @@ struct nfsd4_layout_ops { struct nfs4_client *clp, struct nfsd4_getdeviceinfo *gdevp); __be32 (*encode_getdeviceinfo)(struct xdr_stream *xdr, - struct nfsd4_getdeviceinfo *gdevp); + const struct nfsd4_getdeviceinfo *gdevp); __be32 (*proc_layoutget)(struct inode *, const struct svc_fh *fhp, struct nfsd4_layoutget *lgp); -- cgit v1.2.3 From 4bbe42e8724bc5a65f6129a4e49fa4b11f617226 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 25 Sep 2023 09:28:23 -0400 Subject: NFSD: Clean up nfsd4_encode_getdeviceinfo() Adopt the conventional XDR utility functions. Also, restructure to make the function align more closely with the spec -- there doesn't seem to be a performance need for speciality code, so prioritize readability. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 72 +++++++++++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 37 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 4e4d1af39528..dafb3a91235e 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4811,59 +4811,57 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr, #ifdef CONFIG_NFSD_PNFS static __be32 -nfsd4_encode_getdeviceinfo(struct nfsd4_compoundres *resp, __be32 nfserr, - union nfsd4_op_u *u) +nfsd4_encode_device_addr4(struct xdr_stream *xdr, + const struct nfsd4_getdeviceinfo *gdev) { - struct nfsd4_getdeviceinfo *gdev = &u->getdeviceinfo; - struct xdr_stream *xdr = resp->xdr; + u32 needed_len, starting_len = xdr->buf->len; const struct nfsd4_layout_ops *ops; - u32 starting_len = xdr->buf->len, needed_len; - __be32 *p; + __be32 status; - p = xdr_reserve_space(xdr, 4); - if (!p) + /* da_layout_type */ + if (xdr_stream_encode_u32(xdr, gdev->gd_layout_type) != XDR_UNIT) return nfserr_resource; - - *p++ = cpu_to_be32(gdev->gd_layout_type); - + /* da_addr_body */ ops = nfsd4_layout_ops[gdev->gd_layout_type]; - nfserr = ops->encode_getdeviceinfo(xdr, gdev); - if (nfserr) { + status = ops->encode_getdeviceinfo(xdr, gdev); + if (status != nfs_ok) { /* - * We don't bother to burden the layout drivers with - * enforcing gd_maxcount, just tell the client to - * come back with a bigger buffer if it's not enough. + * Don't burden the layout drivers with enforcing + * gd_maxcount. Just tell the client to come back + * with a bigger buffer if it's not enough. */ - if (xdr->buf->len + 4 > gdev->gd_maxcount) + if (xdr->buf->len + XDR_UNIT > gdev->gd_maxcount) goto toosmall; - return nfserr; + return status; } - if (gdev->gd_notify_types) { - p = xdr_reserve_space(xdr, 4 + 4); - if (!p) - return nfserr_resource; - *p++ = cpu_to_be32(1); /* bitmap length */ - *p++ = cpu_to_be32(gdev->gd_notify_types); - } else { - p = xdr_reserve_space(xdr, 4); - if (!p) - return nfserr_resource; - *p++ = 0; - } + return nfs_ok; - return 0; toosmall: - dprintk("%s: maxcount too small\n", __func__); - needed_len = xdr->buf->len + 4 /* notifications */; + needed_len = xdr->buf->len + XDR_UNIT; /* notifications */ xdr_truncate_encode(xdr, starting_len); - p = xdr_reserve_space(xdr, 4); - if (!p) - return nfserr_resource; - *p++ = cpu_to_be32(needed_len); + + status = nfsd4_encode_count4(xdr, needed_len); + if (status != nfs_ok) + return status; return nfserr_toosmall; } +static __be32 +nfsd4_encode_getdeviceinfo(struct nfsd4_compoundres *resp, __be32 nfserr, + union nfsd4_op_u *u) +{ + struct nfsd4_getdeviceinfo *gdev = &u->getdeviceinfo; + struct xdr_stream *xdr = resp->xdr; + + /* gdir_device_addr */ + nfserr = nfsd4_encode_device_addr4(xdr, gdev); + if (nfserr) + return nfserr; + /* gdir_notification */ + return nfsd4_encode_bitmap4(xdr, gdev->gd_notify_types, 0, 0); +} + static __be32 nfsd4_encode_layout4(struct xdr_stream *xdr, const struct nfsd4_layoutget *lgp) { -- cgit v1.2.3 From 92d82e995ee221578a729998d11d0fa7fbb3e41c Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 12 Oct 2023 13:46:39 -0400 Subject: NFSD: Remove a layering violation when encoding lock_denied An XDR encoder is responsible for marshaling results, not releasing memory that was allocated by the upper layer. We have .op_release for that purpose. Move the release of the ld_owner.data string to op_release functions for LOCK and LOCKT. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4proc.c | 2 ++ fs/nfsd/nfs4state.c | 16 ++++++++++++++++ fs/nfsd/nfs4xdr.c | 16 ++-------------- fs/nfsd/xdr4.h | 17 +++++------------ 4 files changed, 25 insertions(+), 26 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 60262fd27b15..f288039545e3 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -3210,6 +3210,7 @@ static const struct nfsd4_operation nfsd4_ops[] = { }, [OP_LOCK] = { .op_func = nfsd4_lock, + .op_release = nfsd4_lock_release, .op_flags = OP_MODIFIES_SOMETHING | OP_NONTRIVIAL_ERROR_ENCODE, .op_name = "OP_LOCK", @@ -3218,6 +3219,7 @@ static const struct nfsd4_operation nfsd4_ops[] = { }, [OP_LOCKT] = { .op_func = nfsd4_lockt, + .op_release = nfsd4_lockt_release, .op_flags = OP_NONTRIVIAL_ERROR_ENCODE, .op_name = "OP_LOCKT", .op_rsize_bop = nfsd4_lock_rsize, diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 07840ee721ef..305c353a416c 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -7773,6 +7773,14 @@ out: return status; } +void nfsd4_lock_release(union nfsd4_op_u *u) +{ + struct nfsd4_lock *lock = &u->lock; + struct nfsd4_lock_denied *deny = &lock->lk_denied; + + kfree(deny->ld_owner.data); +} + /* * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN, * so we do a temporary open here just to get an open file to pass to @@ -7878,6 +7886,14 @@ out: return status; } +void nfsd4_lockt_release(union nfsd4_op_u *u) +{ + struct nfsd4_lockt *lockt = &u->lockt; + struct nfsd4_lock_denied *deny = &lockt->lt_denied; + + kfree(deny->ld_owner.data); +} + __be32 nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index dafb3a91235e..26e7bb6d32ab 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3990,28 +3990,16 @@ nfsd4_encode_lock_denied(struct xdr_stream *xdr, struct nfsd4_lock_denied *ld) struct xdr_netobj *conf = &ld->ld_owner; __be32 *p; -again: p = xdr_reserve_space(xdr, 32 + XDR_LEN(conf->len)); - if (!p) { - /* - * Don't fail to return the result just because we can't - * return the conflicting open: - */ - if (conf->len) { - kfree(conf->data); - conf->len = 0; - conf->data = NULL; - goto again; - } + if (!p) return nfserr_resource; - } + p = xdr_encode_hyper(p, ld->ld_start); p = xdr_encode_hyper(p, ld->ld_length); *p++ = cpu_to_be32(ld->ld_type); if (conf->len) { p = xdr_encode_opaque_fixed(p, &ld->ld_clientid, 8); p = xdr_encode_opaque(p, conf->data, conf->len); - kfree(conf->data); } else { /* non - nfsv4 lock in conflict, no clientid nor owner */ p = xdr_encode_hyper(p, (u64)0); /* clientid */ *p++ = cpu_to_be32(0); /* length of owner name */ diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index aba07d5378fc..e6c9daae196e 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -292,12 +292,8 @@ struct nfsd4_lock { } v; /* response */ - union { - struct { - stateid_t stateid; - } ok; - struct nfsd4_lock_denied denied; - } u; + stateid_t lk_resp_stateid; + struct nfsd4_lock_denied lk_denied; }; #define lk_new_open_seqid v.new.open_seqid #define lk_new_open_stateid v.new.open_stateid @@ -307,20 +303,15 @@ struct nfsd4_lock { #define lk_old_lock_stateid v.old.lock_stateid #define lk_old_lock_seqid v.old.lock_seqid -#define lk_resp_stateid u.ok.stateid -#define lk_denied u.denied - - struct nfsd4_lockt { u32 lt_type; clientid_t lt_clientid; struct xdr_netobj lt_owner; u64 lt_offset; u64 lt_length; - struct nfsd4_lock_denied lt_denied; + struct nfsd4_lock_denied lt_denied; }; - struct nfsd4_locku { u32 lu_type; u32 lu_seqid; @@ -942,8 +933,10 @@ extern __be32 nfsd4_open_downgrade(struct svc_rqst *rqstp, struct nfsd4_compound_state *, union nfsd4_op_u *u); extern __be32 nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *, union nfsd4_op_u *u); +extern void nfsd4_lock_release(union nfsd4_op_u *u); extern __be32 nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *, union nfsd4_op_u *u); +extern void nfsd4_lockt_release(union nfsd4_op_u *u); extern __be32 nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *, union nfsd4_op_u *u); extern __be32 -- cgit v1.2.3 From c4a29c52506519eeb447800d88a22a6f7bce976c Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 29 Sep 2023 09:58:53 -0400 Subject: NFSD: Add nfsd4_encode_lock_owner4() To improve readability and better align the LOCK encoders with the XDR specification, add an explicit encoder named for the lock_owner4 type. In particular, to avoid code duplication, use nfsd4_encode_clientid4() to encode the clientid in the lock owner rather than open-coding it. It looks to me like nfs4_set_lock_denied() already clears the clientid if it won't return an owner (cf: the nevermind: label). The code in the XDR encoder appears to be redundant and can safely be removed. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 26e7bb6d32ab..0c23742ea561 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3980,6 +3980,20 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, return nfsd4_encode_nfs_fh4(xdr, &fhp->fh_handle); } +static __be32 +nfsd4_encode_lock_owner4(struct xdr_stream *xdr, const clientid_t *clientid, + const struct xdr_netobj *owner) +{ + __be32 status; + + /* clientid */ + status = nfsd4_encode_clientid4(xdr, clientid); + if (status != nfs_ok) + return status; + /* owner */ + return nfsd4_encode_opaque(xdr, owner->data, owner->len); +} + /* * Including all fields other than the name, a LOCK4denied structure requires * 8(clientid) + 4(namelen) + 8(offset) + 8(length) + 4(type) = 32 bytes. @@ -3987,23 +4001,20 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, static __be32 nfsd4_encode_lock_denied(struct xdr_stream *xdr, struct nfsd4_lock_denied *ld) { - struct xdr_netobj *conf = &ld->ld_owner; - __be32 *p; + __be32 *p, status; - p = xdr_reserve_space(xdr, 32 + XDR_LEN(conf->len)); + p = xdr_reserve_space(xdr, XDR_UNIT * 5); if (!p) return nfserr_resource; p = xdr_encode_hyper(p, ld->ld_start); p = xdr_encode_hyper(p, ld->ld_length); *p++ = cpu_to_be32(ld->ld_type); - if (conf->len) { - p = xdr_encode_opaque_fixed(p, &ld->ld_clientid, 8); - p = xdr_encode_opaque(p, conf->data, conf->len); - } else { /* non - nfsv4 lock in conflict, no clientid nor owner */ - p = xdr_encode_hyper(p, (u64)0); /* clientid */ - *p++ = cpu_to_be32(0); /* length of owner name */ - } + status = nfsd4_encode_lock_owner4(xdr, &ld->ld_clientid, + &ld->ld_owner); + if (status != nfs_ok) + return status; + return nfserr_denied; } -- cgit v1.2.3 From c564178290ee068efb87d81654fc03aa01464a0c Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 29 Sep 2023 09:58:59 -0400 Subject: NFSD: Refactor nfsd4_encode_lock_denied() Use the modern XDR utility functions. The LOCK and LOCKT encoder functions need to return nfserr_denied when a lock is denied, but nfsd4_encode_lock4denied() should return a status code that is consistent with other XDR encoders. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 61 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 25 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 0c23742ea561..e37aa16e60ec 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3994,28 +3994,26 @@ nfsd4_encode_lock_owner4(struct xdr_stream *xdr, const clientid_t *clientid, return nfsd4_encode_opaque(xdr, owner->data, owner->len); } -/* -* Including all fields other than the name, a LOCK4denied structure requires -* 8(clientid) + 4(namelen) + 8(offset) + 8(length) + 4(type) = 32 bytes. -*/ static __be32 -nfsd4_encode_lock_denied(struct xdr_stream *xdr, struct nfsd4_lock_denied *ld) +nfsd4_encode_lock4denied(struct xdr_stream *xdr, + const struct nfsd4_lock_denied *ld) { - __be32 *p, status; - - p = xdr_reserve_space(xdr, XDR_UNIT * 5); - if (!p) - return nfserr_resource; + __be32 status; - p = xdr_encode_hyper(p, ld->ld_start); - p = xdr_encode_hyper(p, ld->ld_length); - *p++ = cpu_to_be32(ld->ld_type); - status = nfsd4_encode_lock_owner4(xdr, &ld->ld_clientid, - &ld->ld_owner); + /* offset */ + status = nfsd4_encode_offset4(xdr, ld->ld_start); if (status != nfs_ok) return status; - - return nfserr_denied; + /* length */ + status = nfsd4_encode_length4(xdr, ld->ld_length); + if (status != nfs_ok) + return status; + /* locktype */ + if (xdr_stream_encode_u32(xdr, ld->ld_type) != XDR_UNIT) + return nfserr_resource; + /* owner */ + return nfsd4_encode_lock_owner4(xdr, &ld->ld_clientid, + &ld->ld_owner); } static __be32 @@ -4024,13 +4022,21 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, { struct nfsd4_lock *lock = &u->lock; struct xdr_stream *xdr = resp->xdr; + __be32 status; - if (!nfserr) - nfserr = nfsd4_encode_stateid4(xdr, &lock->lk_resp_stateid); - else if (nfserr == nfserr_denied) - nfserr = nfsd4_encode_lock_denied(xdr, &lock->lk_denied); - - return nfserr; + switch (nfserr) { + case nfs_ok: + /* resok4 */ + status = nfsd4_encode_stateid4(xdr, &lock->lk_resp_stateid); + break; + case nfserr_denied: + /* denied */ + status = nfsd4_encode_lock4denied(xdr, &lock->lk_denied); + break; + default: + return nfserr; + } + return status != nfs_ok ? status : nfserr; } static __be32 @@ -4039,9 +4045,14 @@ nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, { struct nfsd4_lockt *lockt = &u->lockt; struct xdr_stream *xdr = resp->xdr; + __be32 status; - if (nfserr == nfserr_denied) - nfsd4_encode_lock_denied(xdr, &lockt->lt_denied); + if (nfserr == nfserr_denied) { + /* denied */ + status = nfsd4_encode_lock4denied(xdr, &lockt->lt_denied); + if (status != nfs_ok) + return status; + } return nfserr; } -- cgit v1.2.3 From e4ad7ce775eee3b1271b9ef0dc1dbdc47cf6a00c Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 29 Sep 2023 09:59:05 -0400 Subject: NFSD: Add nfsd4_encode_open_read_delegation4() Refactor nfsd4_encode_open() so the open_read_delegation4 type is encoded in a separate function. This makes it more straightforward to later add support for returning an nfsace4 in OPEN responses that offer a delegation. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4state.c | 6 +++--- fs/nfsd/nfs4xdr.c | 61 +++++++++++++++++++++++++++++++++++++++-------------- fs/nfsd/xdr4.h | 2 +- 3 files changed, 49 insertions(+), 20 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 305c353a416c..40018cc914a4 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -5688,11 +5688,11 @@ nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp, struct path path; cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); - open->op_recall = 0; + open->op_recall = false; switch (open->op_claim_type) { case NFS4_OPEN_CLAIM_PREVIOUS: if (!cb_up) - open->op_recall = 1; + open->op_recall = true; break; case NFS4_OPEN_CLAIM_NULL: parent = currentfh; @@ -5746,7 +5746,7 @@ out_no_deleg: if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) { dprintk("NFSD: WARNING: refusing delegation reclaim\n"); - open->op_recall = 1; + open->op_recall = true; } /* 4.1 client asking for a delegation? */ diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index e37aa16e60ec..519162a00bf5 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4078,6 +4078,49 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, return nfsd4_encode_change_info4(xdr, &link->li_cinfo); } +/* + * This implementation does not yet support returning an ACE in an + * OPEN that offers a delegation. + */ +static __be32 +nfsd4_encode_open_nfsace4(struct xdr_stream *xdr) +{ + __be32 status; + + /* type */ + status = nfsd4_encode_acetype4(xdr, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE); + if (status != nfs_ok) + return nfserr_resource; + /* flag */ + status = nfsd4_encode_aceflag4(xdr, 0); + if (status != nfs_ok) + return nfserr_resource; + /* access mask */ + status = nfsd4_encode_acemask4(xdr, 0); + if (status != nfs_ok) + return nfserr_resource; + /* who - empty for now */ + if (xdr_stream_encode_u32(xdr, 0) != XDR_UNIT) + return nfserr_resource; + return nfs_ok; +} + +static __be32 +nfsd4_encode_open_read_delegation4(struct xdr_stream *xdr, struct nfsd4_open *open) +{ + __be32 status; + + /* stateid */ + status = nfsd4_encode_stateid4(xdr, &open->op_delegate_stateid); + if (status != nfs_ok) + return status; + /* recall */ + status = nfsd4_encode_bool(xdr, open->op_recall); + if (status != nfs_ok) + return status; + /* permissions */ + return nfsd4_encode_open_nfsace4(xdr); +} static __be32 nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, @@ -4110,22 +4153,8 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, case NFS4_OPEN_DELEGATE_NONE: break; case NFS4_OPEN_DELEGATE_READ: - nfserr = nfsd4_encode_stateid4(xdr, &open->op_delegate_stateid); - if (nfserr) - return nfserr; - p = xdr_reserve_space(xdr, 20); - if (!p) - return nfserr_resource; - *p++ = cpu_to_be32(open->op_recall); - - /* - * TODO: ACE's in delegations - */ - *p++ = cpu_to_be32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE); - *p++ = cpu_to_be32(0); - *p++ = cpu_to_be32(0); - *p++ = cpu_to_be32(0); /* XXX: is NULL principal ok? */ - break; + /* read */ + return nfsd4_encode_open_read_delegation4(xdr, open); case NFS4_OPEN_DELEGATE_WRITE: nfserr = nfsd4_encode_stateid4(xdr, &open->op_delegate_stateid); if (nfserr) diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index e6c9daae196e..cb8e6794a6a1 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -380,9 +380,9 @@ struct nfsd4_open { u32 op_deleg_want; /* request */ stateid_t op_stateid; /* response */ __be32 op_xdr_error; /* see nfsd4_open_omfg() */ - u32 op_recall; /* recall */ struct nfsd4_change_info op_cinfo; /* response */ u32 op_rflags; /* response */ + bool op_recall; /* response */ bool op_truncate; /* used during processing */ bool op_created; /* used during processing */ struct nfs4_openowner *op_openowner; /* used during processing */ -- cgit v1.2.3 From 32efa67435dcd745d689ba373d5259aa61d05eb7 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 29 Sep 2023 09:59:12 -0400 Subject: NFSD: Add nfsd4_encode_open_write_delegation4() Make it easier to adjust the XDR encoder to handle new features related to write delegations. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 59 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 26 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 519162a00bf5..903a6d61b9c2 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4122,6 +4122,37 @@ nfsd4_encode_open_read_delegation4(struct xdr_stream *xdr, struct nfsd4_open *op return nfsd4_encode_open_nfsace4(xdr); } +static __be32 +nfsd4_encode_nfs_space_limit4(struct xdr_stream *xdr, u64 filesize) +{ + /* limitby */ + if (xdr_stream_encode_u32(xdr, NFS4_LIMIT_SIZE) != XDR_UNIT) + return nfserr_resource; + /* filesize */ + return nfsd4_encode_uint64_t(xdr, filesize); +} + +static __be32 +nfsd4_encode_open_write_delegation4(struct xdr_stream *xdr, + struct nfsd4_open *open) +{ + __be32 status; + + /* stateid */ + status = nfsd4_encode_stateid4(xdr, &open->op_delegate_stateid); + if (status != nfs_ok) + return status; + /* recall */ + status = nfsd4_encode_bool(xdr, open->op_recall); + if (status != nfs_ok) + return status; + /* space_limit */ + status = nfsd4_encode_nfs_space_limit4(xdr, 0); + if (status != nfs_ok) + return status; + return nfsd4_encode_open_nfsace4(xdr); +} + static __be32 nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, union nfsd4_op_u *u) @@ -4156,32 +4187,8 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, /* read */ return nfsd4_encode_open_read_delegation4(xdr, open); case NFS4_OPEN_DELEGATE_WRITE: - nfserr = nfsd4_encode_stateid4(xdr, &open->op_delegate_stateid); - if (nfserr) - return nfserr; - - p = xdr_reserve_space(xdr, XDR_UNIT * 8); - if (!p) - return nfserr_resource; - *p++ = cpu_to_be32(open->op_recall); - - /* - * Always flush on close - * - * TODO: space_limit's in delegations - */ - *p++ = cpu_to_be32(NFS4_LIMIT_SIZE); - *p++ = xdr_zero; - *p++ = xdr_zero; - - /* - * TODO: ACE's in delegations - */ - *p++ = cpu_to_be32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE); - *p++ = cpu_to_be32(0); - *p++ = cpu_to_be32(0); - *p++ = cpu_to_be32(0); /* XXX: is NULL principal ok? */ - break; + /* write */ + return nfsd4_encode_open_write_delegation4(xdr, open); case NFS4_OPEN_DELEGATE_NONE_EXT: /* 4.1 */ switch (open->op_why_no_deleg) { case WND4_CONTENTION: -- cgit v1.2.3 From 6dd43c6d5112ffde72fdef782e0970cd27041e79 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 29 Sep 2023 09:59:18 -0400 Subject: NFSD: Add nfsd4_encode_open_none_delegation4() To better align our implementation with the XDR specification, refactor the part of nfsd4_encode_open() that encodes the open_none_delegation4 type. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 903a6d61b9c2..4a1d428066ce 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4153,6 +4153,27 @@ nfsd4_encode_open_write_delegation4(struct xdr_stream *xdr, return nfsd4_encode_open_nfsace4(xdr); } +static __be32 +nfsd4_encode_open_none_delegation4(struct xdr_stream *xdr, + struct nfsd4_open *open) +{ + __be32 status = nfs_ok; + + /* ond_why */ + if (xdr_stream_encode_u32(xdr, open->op_why_no_deleg) != XDR_UNIT) + return nfserr_resource; + switch (open->op_why_no_deleg) { + case WND4_CONTENTION: + /* ond_server_will_push_deleg */ + status = nfsd4_encode_bool(xdr, false); + break; + case WND4_RESOURCE: + /* ond_server_will_signal_avail */ + status = nfsd4_encode_bool(xdr, false); + } + return status; +} + static __be32 nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, union nfsd4_op_u *u) @@ -4189,24 +4210,9 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, case NFS4_OPEN_DELEGATE_WRITE: /* write */ return nfsd4_encode_open_write_delegation4(xdr, open); - case NFS4_OPEN_DELEGATE_NONE_EXT: /* 4.1 */ - switch (open->op_why_no_deleg) { - case WND4_CONTENTION: - case WND4_RESOURCE: - p = xdr_reserve_space(xdr, 8); - if (!p) - return nfserr_resource; - *p++ = cpu_to_be32(open->op_why_no_deleg); - /* deleg signaling not supported yet: */ - *p++ = cpu_to_be32(0); - break; - default: - p = xdr_reserve_space(xdr, 4); - if (!p) - return nfserr_resource; - *p++ = cpu_to_be32(open->op_why_no_deleg); - } - break; + case NFS4_OPEN_DELEGATE_NONE_EXT: + /* od_whynone */ + return nfsd4_encode_open_none_delegation4(xdr, open); default: BUG(); } -- cgit v1.2.3 From 802e191353e496f7ad5b00954b4643a1b8d726b5 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 29 Sep 2023 09:59:24 -0400 Subject: NFSD: Add nfsd4_encode_open_delegation4() To better align our implementation with the XDR specification, refactor the part of nfsd4_encode_open() that encodes delegation metadata. As part of that refactor, remove an unnecessary BUG() call site and a comment that appears to be stale. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 56 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 23 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 4a1d428066ce..cacd06949796 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4174,13 +4174,43 @@ nfsd4_encode_open_none_delegation4(struct xdr_stream *xdr, return status; } +static __be32 +nfsd4_encode_open_delegation4(struct xdr_stream *xdr, struct nfsd4_open *open) +{ + __be32 status; + + /* delegation_type */ + if (xdr_stream_encode_u32(xdr, open->op_delegate_type) != XDR_UNIT) + return nfserr_resource; + switch (open->op_delegate_type) { + case NFS4_OPEN_DELEGATE_NONE: + status = nfs_ok; + break; + case NFS4_OPEN_DELEGATE_READ: + /* read */ + status = nfsd4_encode_open_read_delegation4(xdr, open); + break; + case NFS4_OPEN_DELEGATE_WRITE: + /* write */ + status = nfsd4_encode_open_write_delegation4(xdr, open); + break; + case NFS4_OPEN_DELEGATE_NONE_EXT: + /* od_whynone */ + status = nfsd4_encode_open_none_delegation4(xdr, open); + break; + default: + status = nfserr_serverfault; + } + + return status; +} + static __be32 nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, union nfsd4_op_u *u) { struct nfsd4_open *open = &u->open; struct xdr_stream *xdr = resp->xdr; - __be32 *p; nfserr = nfsd4_encode_stateid4(xdr, &open->op_stateid); if (nfserr) @@ -4196,28 +4226,8 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, if (nfserr) return nfserr; - p = xdr_reserve_space(xdr, 4); - if (!p) - return nfserr_resource; - - *p++ = cpu_to_be32(open->op_delegate_type); - switch (open->op_delegate_type) { - case NFS4_OPEN_DELEGATE_NONE: - break; - case NFS4_OPEN_DELEGATE_READ: - /* read */ - return nfsd4_encode_open_read_delegation4(xdr, open); - case NFS4_OPEN_DELEGATE_WRITE: - /* write */ - return nfsd4_encode_open_write_delegation4(xdr, open); - case NFS4_OPEN_DELEGATE_NONE_EXT: - /* od_whynone */ - return nfsd4_encode_open_none_delegation4(xdr, open); - default: - BUG(); - } - /* XXX save filehandle here */ - return 0; + /* delegation */ + return nfsd4_encode_open_delegation4(xdr, open); } static __be32 -- cgit v1.2.3 From 841735b3fdfe518f21c80ca3ae48a1edfc957525 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 29 Sep 2023 09:59:31 -0400 Subject: NFSD: Clean up nfsd4_encode_open() Finish cleaning up nfsd4_encode_open(). Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index cacd06949796..dcad27f734f6 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4212,20 +4212,23 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open = &u->open; struct xdr_stream *xdr = resp->xdr; + /* stateid */ nfserr = nfsd4_encode_stateid4(xdr, &open->op_stateid); - if (nfserr) + if (nfserr != nfs_ok) return nfserr; + /* cinfo */ nfserr = nfsd4_encode_change_info4(xdr, &open->op_cinfo); - if (nfserr) + if (nfserr != nfs_ok) return nfserr; - if (xdr_stream_encode_u32(xdr, open->op_rflags) < 0) - return nfserr_resource; - + /* rflags */ + nfserr = nfsd4_encode_uint32_t(xdr, open->op_rflags); + if (nfserr != nfs_ok) + return nfserr; + /* attrset */ nfserr = nfsd4_encode_bitmap4(xdr, open->op_bmval[0], open->op_bmval[1], open->op_bmval[2]); - if (nfserr) + if (nfserr != nfs_ok) return nfserr; - /* delegation */ return nfsd4_encode_open_delegation4(xdr, open); } -- cgit v1.2.3 From 65baa60953192a587f2495a98fde9c5e1802a225 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Oct 2023 10:51:17 -0400 Subject: NFSD: Add a utility function for encoding sessionid4 objects There is more than one NFSv4 operation that needs to encode a sessionid4, so extract that data type into a separate helper. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index dcad27f734f6..668254c97924 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3885,6 +3885,14 @@ nfsd4_encode_stateid4(struct xdr_stream *xdr, const stateid_t *sid) return nfs_ok; } +static __be32 +nfsd4_encode_sessionid4(struct xdr_stream *xdr, + const struct nfs4_sessionid *sessionid) +{ + return nfsd4_encode_opaque_fixed(xdr, sessionid->data, + NFS4_MAX_SESSIONID_LEN); +} + static __be32 nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, union nfsd4_op_u *u) @@ -3906,17 +3914,16 @@ static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, { struct nfsd4_bind_conn_to_session *bcts = &u->bind_conn_to_session; struct xdr_stream *xdr = resp->xdr; - __be32 *p; - p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 8); - if (!p) + /* bctsr_sessid */ + nfserr = nfsd4_encode_sessionid4(xdr, &bcts->sessionid); + if (nfserr != nfs_ok) + return nfserr; + /* bctsr_dir */ + if (xdr_stream_encode_u32(xdr, bcts->dir) != XDR_UNIT) return nfserr_resource; - p = xdr_encode_opaque_fixed(p, bcts->sessionid.data, - NFS4_MAX_SESSIONID_LEN); - *p++ = cpu_to_be32(bcts->dir); - /* Upshifting from TCP to RDMA is not supported */ - *p++ = cpu_to_be32(0); - return 0; + /* bctsr_use_conn_in_rdma_mode */ + return nfsd4_encode_bool(xdr, false); } static __be32 -- cgit v1.2.3 From 150990f49dd1781dbee7b6305cf978a47f646811 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Oct 2023 10:51:24 -0400 Subject: NFSD: Add nfsd4_encode_channel_attr4() De-duplicate the encoding of the fore channel and backchannel attributes. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 80 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 36 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 668254c97924..221881cc6384 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4782,6 +4782,44 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, return 0; } +static __be32 +nfsd4_encode_channel_attrs4(struct xdr_stream *xdr, + const struct nfsd4_channel_attrs *attrs) +{ + __be32 status; + + /* ca_headerpadsize */ + status = nfsd4_encode_count4(xdr, 0); + if (status != nfs_ok) + return status; + /* ca_maxrequestsize */ + status = nfsd4_encode_count4(xdr, attrs->maxreq_sz); + if (status != nfs_ok) + return status; + /* ca_maxresponsesize */ + status = nfsd4_encode_count4(xdr, attrs->maxresp_sz); + if (status != nfs_ok) + return status; + /* ca_maxresponsesize_cached */ + status = nfsd4_encode_count4(xdr, attrs->maxresp_cached); + if (status != nfs_ok) + return status; + /* ca_maxoperations */ + status = nfsd4_encode_count4(xdr, attrs->maxops); + if (status != nfs_ok) + return status; + /* ca_maxrequests */ + status = nfsd4_encode_count4(xdr, attrs->maxreqs); + if (status != nfs_ok) + return status; + /* ca_rdma_ird<1> */ + if (xdr_stream_encode_u32(xdr, attrs->nr_rdma_attrs) != XDR_UNIT) + return nfserr_resource; + if (attrs->nr_rdma_attrs) + return nfsd4_encode_uint32_t(xdr, attrs->rdma_attrs); + return nfs_ok; +} + static __be32 nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr, union nfsd4_op_u *u) @@ -4798,42 +4836,12 @@ nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr, *p++ = cpu_to_be32(sess->seqid); *p++ = cpu_to_be32(sess->flags); - p = xdr_reserve_space(xdr, 28); - if (!p) - return nfserr_resource; - *p++ = cpu_to_be32(0); /* headerpadsz */ - *p++ = cpu_to_be32(sess->fore_channel.maxreq_sz); - *p++ = cpu_to_be32(sess->fore_channel.maxresp_sz); - *p++ = cpu_to_be32(sess->fore_channel.maxresp_cached); - *p++ = cpu_to_be32(sess->fore_channel.maxops); - *p++ = cpu_to_be32(sess->fore_channel.maxreqs); - *p++ = cpu_to_be32(sess->fore_channel.nr_rdma_attrs); - - if (sess->fore_channel.nr_rdma_attrs) { - p = xdr_reserve_space(xdr, 4); - if (!p) - return nfserr_resource; - *p++ = cpu_to_be32(sess->fore_channel.rdma_attrs); - } - - p = xdr_reserve_space(xdr, 28); - if (!p) - return nfserr_resource; - *p++ = cpu_to_be32(0); /* headerpadsz */ - *p++ = cpu_to_be32(sess->back_channel.maxreq_sz); - *p++ = cpu_to_be32(sess->back_channel.maxresp_sz); - *p++ = cpu_to_be32(sess->back_channel.maxresp_cached); - *p++ = cpu_to_be32(sess->back_channel.maxops); - *p++ = cpu_to_be32(sess->back_channel.maxreqs); - *p++ = cpu_to_be32(sess->back_channel.nr_rdma_attrs); - - if (sess->back_channel.nr_rdma_attrs) { - p = xdr_reserve_space(xdr, 4); - if (!p) - return nfserr_resource; - *p++ = cpu_to_be32(sess->back_channel.rdma_attrs); - } - return 0; + /* csr_fore_chan_attrs */ + nfserr = nfsd4_encode_channel_attrs4(xdr, &sess->fore_channel); + if (nfserr != nfs_ok) + return nfserr; + /* csr_back_chan_attrs */ + return nfsd4_encode_channel_attrs4(xdr, &sess->back_channel); } static __be32 -- cgit v1.2.3 From b0c1b1ba142601c24333d5d38461396f11dae478 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Oct 2023 10:51:30 -0400 Subject: NFSD: Restructure nfsd4_encode_create_session() Convert nfsd4_encode_create_session() to use the conventional XDR encoding utilities. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 21 ++++++++++++--------- fs/nfsd/xdr4.h | 1 + 2 files changed, 13 insertions(+), 9 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 221881cc6384..7d452a2a8e85 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4826,16 +4826,19 @@ nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr, { struct nfsd4_create_session *sess = &u->create_session; struct xdr_stream *xdr = resp->xdr; - __be32 *p; - - p = xdr_reserve_space(xdr, 24); - if (!p) - return nfserr_resource; - p = xdr_encode_opaque_fixed(p, sess->sessionid.data, - NFS4_MAX_SESSIONID_LEN); - *p++ = cpu_to_be32(sess->seqid); - *p++ = cpu_to_be32(sess->flags); + /* csr_sessionid */ + nfserr = nfsd4_encode_sessionid4(xdr, &sess->sessionid); + if (nfserr != nfs_ok) + return nfserr; + /* csr_sequence */ + nfserr = nfsd4_encode_sequenceid4(xdr, sess->seqid); + if (nfserr != nfs_ok) + return nfserr; + /* csr_flags */ + nfserr = nfsd4_encode_uint32_t(xdr, sess->flags); + if (nfserr != nfs_ok) + return nfserr; /* csr_fore_chan_attrs */ nfserr = nfsd4_encode_channel_attrs4(xdr, &sess->fore_channel); if (nfserr != nfs_ok) diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index cb8e6794a6a1..6716a7904c9f 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -96,6 +96,7 @@ nfsd4_encode_uint32_t(struct xdr_stream *xdr, u32 val) #define nfsd4_encode_count4(x, v) nfsd4_encode_uint32_t(x, v) #define nfsd4_encode_mode4(x, v) nfsd4_encode_uint32_t(x, v) #define nfsd4_encode_nfs_lease4(x, v) nfsd4_encode_uint32_t(x, v) +#define nfsd4_encode_sequenceid4(x, v) nfsd4_encode_uint32_t(x, v) /** * nfsd4_encode_uint64_t - Encode an XDR uint64_t type result -- cgit v1.2.3 From 6621b88b4b2189a0dd601cd036e27a829868df31 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 2 Oct 2023 10:51:37 -0400 Subject: NFSD: Clean up nfsd4_encode_sequence() De-duplicate open-coded encoding of the sessionid, and convert the rest of the function to use conventional XDR utility functions. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 37 +++++++++++++++++++++++++------------ fs/nfsd/xdr4.h | 1 + 2 files changed, 26 insertions(+), 12 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 7d452a2a8e85..a194a608ad90 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4853,22 +4853,35 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr, { struct nfsd4_sequence *seq = &u->sequence; struct xdr_stream *xdr = resp->xdr; - __be32 *p; - p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 20); - if (!p) - return nfserr_resource; - p = xdr_encode_opaque_fixed(p, seq->sessionid.data, - NFS4_MAX_SESSIONID_LEN); - *p++ = cpu_to_be32(seq->seqid); - *p++ = cpu_to_be32(seq->slotid); + /* sr_sessionid */ + nfserr = nfsd4_encode_sessionid4(xdr, &seq->sessionid); + if (nfserr != nfs_ok) + return nfserr; + /* sr_sequenceid */ + nfserr = nfsd4_encode_sequenceid4(xdr, seq->seqid); + if (nfserr != nfs_ok) + return nfserr; + /* sr_slotid */ + nfserr = nfsd4_encode_slotid4(xdr, seq->slotid); + if (nfserr != nfs_ok) + return nfserr; /* Note slotid's are numbered from zero: */ - *p++ = cpu_to_be32(seq->maxslots - 1); /* sr_highest_slotid */ - *p++ = cpu_to_be32(seq->maxslots - 1); /* sr_target_highest_slotid */ - *p++ = cpu_to_be32(seq->status_flags); + /* sr_highest_slotid */ + nfserr = nfsd4_encode_slotid4(xdr, seq->maxslots - 1); + if (nfserr != nfs_ok) + return nfserr; + /* sr_target_highest_slotid */ + nfserr = nfsd4_encode_slotid4(xdr, seq->maxslots - 1); + if (nfserr != nfs_ok) + return nfserr; + /* sr_status_flags */ + nfserr = nfsd4_encode_uint32_t(xdr, seq->status_flags); + if (nfserr != nfs_ok) + return nfserr; resp->cstate.data_offset = xdr->buf->len; /* DRC cache data pointer */ - return 0; + return nfs_ok; } static __be32 diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 6716a7904c9f..c8c21b2d4d14 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -97,6 +97,7 @@ nfsd4_encode_uint32_t(struct xdr_stream *xdr, u32 val) #define nfsd4_encode_mode4(x, v) nfsd4_encode_uint32_t(x, v) #define nfsd4_encode_nfs_lease4(x, v) nfsd4_encode_uint32_t(x, v) #define nfsd4_encode_sequenceid4(x, v) nfsd4_encode_uint32_t(x, v) +#define nfsd4_encode_slotid4(x, v) nfsd4_encode_uint32_t(x, v) /** * nfsd4_encode_uint64_t - Encode an XDR uint64_t type result -- cgit v1.2.3 From a0f3c835159896d2395392436c8994c0b6d948ef Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 4 Oct 2023 09:41:44 -0400 Subject: NFSD: Rename nfsd4_encode_dirent() Rename nfsd4_encode_dirent() to match the naming convention already used in the NFSv2 and NFSv3 readdir paths. The new name reflects the name of the spec-defined XDR data type for an NFSv4 directory entry. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index a194a608ad90..b6bac09b5a10 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3674,8 +3674,8 @@ static inline int attributes_need_mount(u32 *bmval) } static __be32 -nfsd4_encode_dirent_fattr(struct xdr_stream *xdr, struct nfsd4_readdir *cd, - const char *name, int namlen) +nfsd4_encode_entry4_fattr(struct nfsd4_readdir *cd, const char *name, + int namlen) { struct svc_export *exp = cd->rd_fhp->fh_export; struct dentry *dentry; @@ -3718,7 +3718,7 @@ nfsd4_encode_dirent_fattr(struct xdr_stream *xdr, struct nfsd4_readdir *cd, } out_encode: - nfserr = nfsd4_encode_fattr4(cd->rd_rqstp, xdr, NULL, exp, dentry, + nfserr = nfsd4_encode_fattr4(cd->rd_rqstp, cd->xdr, NULL, exp, dentry, cd->rd_bmval, ignore_crossmnt); out_put: dput(dentry); @@ -3744,7 +3744,7 @@ nfsd4_encode_rdattr_error(struct xdr_stream *xdr, __be32 nfserr) } static int -nfsd4_encode_dirent(void *ccdv, const char *name, int namlen, +nfsd4_encode_entry4(void *ccdv, const char *name, int namlen, loff_t offset, u64 ino, unsigned int d_type) { struct readdir_cd *ccd = ccdv; @@ -3781,7 +3781,7 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen, p = xdr_encode_hyper(p, OFFSET_MAX); /* offset of next entry */ p = xdr_encode_array(p, name, namlen); /* name length & name */ - nfserr = nfsd4_encode_dirent_fattr(xdr, cd, name, namlen); + nfserr = nfsd4_encode_entry4_fattr(cd, name, namlen); switch (nfserr) { case nfs_ok: break; @@ -4493,9 +4493,8 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, readdir->cookie_offset = 0; offset = readdir->rd_cookie; - nfserr = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp, - &offset, - &readdir->common, nfsd4_encode_dirent); + nfserr = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp, &offset, + &readdir->common, nfsd4_encode_entry4); if (nfserr == nfs_ok && readdir->common.err == nfserr_toosmall && xdr->buf->len == starting_len + 8) { -- cgit v1.2.3 From a0d042f823fd78eec9e762edd70db1cfa4e3df27 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 4 Oct 2023 09:41:51 -0400 Subject: NFSD: Clean up nfsd4_encode_rdattr_error() No need for specialized code here, as this function is invoked only rarely. Convert it to encode to xdr_stream using conventional XDR helpers. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index b6bac09b5a10..dc98215724cd 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3726,21 +3726,22 @@ out_put: return nfserr; } -static __be32 * -nfsd4_encode_rdattr_error(struct xdr_stream *xdr, __be32 nfserr) +static __be32 +nfsd4_encode_entry4_rdattr_error(struct xdr_stream *xdr, __be32 nfserr) { - __be32 *p; - - p = xdr_reserve_space(xdr, 20); - if (!p) - return NULL; - *p++ = htonl(2); - *p++ = htonl(FATTR4_WORD0_RDATTR_ERROR); /* bmval0 */ - *p++ = htonl(0); /* bmval1 */ + __be32 status; - *p++ = htonl(4); /* attribute length */ - *p++ = nfserr; /* no htonl */ - return p; + /* attrmask */ + status = nfsd4_encode_bitmap4(xdr, FATTR4_WORD0_RDATTR_ERROR, 0, 0); + if (status != nfs_ok) + return status; + /* attr_vals */ + if (xdr_stream_encode_u32(xdr, XDR_UNIT) != XDR_UNIT) + return nfserr_resource; + /* rdattr_error */ + if (xdr_stream_encode_be32(xdr, nfserr) != XDR_UNIT) + return nfserr_resource; + return nfs_ok; } static int @@ -3812,8 +3813,7 @@ nfsd4_encode_entry4(void *ccdv, const char *name, int namlen, */ if (!(cd->rd_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)) goto fail; - p = nfsd4_encode_rdattr_error(xdr, nfserr); - if (p == NULL) { + if (nfsd4_encode_entry4_rdattr_error(xdr, nfserr)) { nfserr = nfserr_toosmall; goto fail; } -- cgit v1.2.3 From 3fc5048cb39f24e6b7c465cd59fb8d454d401a4c Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 4 Oct 2023 09:41:57 -0400 Subject: NFSD: Add an nfsd4_encode_nfs_cookie4() helper De-duplicate the entry4 cookie encoder, similar to the arrangement for the NFSv2 and NFSv3 directory entry encoders. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index dc98215724cd..210cb924b9b4 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3664,6 +3664,22 @@ __be32 nfsd4_encode_fattr_to_buf(__be32 **p, int words, return ret; } +/* + * The buffer space for this field was reserved during a previous + * call to nfsd4_encode_entry4(). + */ +static void nfsd4_encode_entry4_nfs_cookie4(const struct nfsd4_readdir *readdir, + u64 offset) +{ + __be64 cookie = cpu_to_be64(offset); + struct xdr_stream *xdr = readdir->xdr; + + if (!readdir->cookie_offset) + return; + write_bytes_to_xdr_buf(xdr->buf, readdir->cookie_offset, &cookie, + sizeof(cookie)); +} + static inline int attributes_need_mount(u32 *bmval) { if (bmval[0] & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_LEASE_TIME)) @@ -3756,7 +3772,6 @@ nfsd4_encode_entry4(void *ccdv, const char *name, int namlen, u32 name_and_cookie; int entry_bytes; __be32 nfserr = nfserr_toosmall; - __be64 wire_offset; __be32 *p; /* In nfsv4, "." and ".." never make it onto the wire.. */ @@ -3765,11 +3780,8 @@ nfsd4_encode_entry4(void *ccdv, const char *name, int namlen, return 0; } - if (cd->cookie_offset) { - wire_offset = cpu_to_be64(offset); - write_bytes_to_xdr_buf(xdr->buf, cd->cookie_offset, - &wire_offset, 8); - } + /* Encode the previous entry's cookie value */ + nfsd4_encode_entry4_nfs_cookie4(cd, offset); p = xdr_reserve_space(xdr, 4); if (!p) @@ -4451,7 +4463,6 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, int maxcount; int bytes_left; loff_t offset; - __be64 wire_offset; struct xdr_stream *xdr = resp->xdr; int starting_len = xdr->buf->len; __be32 *p; @@ -4509,11 +4520,8 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, if (nfserr) goto err_no_verf; - if (readdir->cookie_offset) { - wire_offset = cpu_to_be64(offset); - write_bytes_to_xdr_buf(xdr->buf, readdir->cookie_offset, - &wire_offset, 8); - } + /* Encode the final entry's cookie value */ + nfsd4_encode_entry4_nfs_cookie4(readdir, offset); p = xdr_reserve_space(xdr, 8); if (!p) { -- cgit v1.2.3 From a1aee9aa35765ad18dfbcf42a05563da33038bbe Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 4 Oct 2023 09:42:03 -0400 Subject: NFSD: Clean up nfsd4_encode_entry4() Reshape nfsd4_encode_entry4() to be more like the legacy dirent encoders, which were recently rewritten to use xdr_stream. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 15 ++++++--------- fs/nfsd/xdr4.h | 3 +++ 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 210cb924b9b4..71f3bc09c1c5 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3772,7 +3772,6 @@ nfsd4_encode_entry4(void *ccdv, const char *name, int namlen, u32 name_and_cookie; int entry_bytes; __be32 nfserr = nfserr_toosmall; - __be32 *p; /* In nfsv4, "." and ".." never make it onto the wire.. */ if (name && isdotent(name, namlen)) { @@ -3783,17 +3782,15 @@ nfsd4_encode_entry4(void *ccdv, const char *name, int namlen, /* Encode the previous entry's cookie value */ nfsd4_encode_entry4_nfs_cookie4(cd, offset); - p = xdr_reserve_space(xdr, 4); - if (!p) + if (xdr_stream_encode_item_present(xdr) != XDR_UNIT) goto fail; - *p++ = xdr_one; /* mark entry present */ + + /* Reserve send buffer space for this entry's cookie value. */ cookie_offset = xdr->buf->len; - p = xdr_reserve_space(xdr, 3*4 + namlen); - if (!p) + if (nfsd4_encode_nfs_cookie4(xdr, OFFSET_MAX) != nfs_ok) + goto fail; + if (nfsd4_encode_component4(xdr, name, namlen) != nfs_ok) goto fail; - p = xdr_encode_hyper(p, OFFSET_MAX); /* offset of next entry */ - p = xdr_encode_array(p, name, namlen); /* name length & name */ - nfserr = nfsd4_encode_entry4_fattr(cd, name, namlen); switch (nfserr) { case nfs_ok: diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index c8c21b2d4d14..a97297915112 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -120,6 +120,7 @@ nfsd4_encode_uint64_t(struct xdr_stream *xdr, u64 val) } #define nfsd4_encode_changeid4(x, v) nfsd4_encode_uint64_t(x, v) +#define nfsd4_encode_nfs_cookie4(x, v) nfsd4_encode_uint64_t(x, v) #define nfsd4_encode_length4(x, v) nfsd4_encode_uint64_t(x, v) #define nfsd4_encode_offset4(x, v) nfsd4_encode_uint64_t(x, v) @@ -174,6 +175,8 @@ nfsd4_encode_opaque(struct xdr_stream *xdr, const void *data, size_t size) return nfs_ok; } +#define nfsd4_encode_component4(x, d, s) nfsd4_encode_opaque(x, d, s) + struct nfsd4_compound_state { struct svc_fh current_fh; struct svc_fh save_fh; -- cgit v1.2.3 From 25c307acc8203fc8b20bcb3f5029b149ce754bbf Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 4 Oct 2023 09:42:10 -0400 Subject: NFSD: Clean up nfsd4_encode_readdir() Untangle nfsd4_encode_readdir() so it is more clear what XDR data item is being encoded by which piece of code. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 112 +++++++++++++++++++++++++++--------------------------- 1 file changed, 55 insertions(+), 57 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 71f3bc09c1c5..a3f04969c3be 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4452,85 +4452,83 @@ out_err: return nfserr; } -static __be32 -nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, - union nfsd4_op_u *u) +static __be32 nfsd4_encode_dirlist4(struct xdr_stream *xdr, + struct nfsd4_readdir *readdir, + u32 max_payload) { - struct nfsd4_readdir *readdir = &u->readdir; - int maxcount; - int bytes_left; + int bytes_left, maxcount, starting_len = xdr->buf->len; loff_t offset; - struct xdr_stream *xdr = resp->xdr; - int starting_len = xdr->buf->len; - __be32 *p; - - nfserr = nfsd4_encode_verifier4(xdr, &readdir->rd_verf); - if (nfserr != nfs_ok) - return nfserr; + __be32 status; /* * Number of bytes left for directory entries allowing for the - * final 8 bytes of the readdir and a following failed op: + * final 8 bytes of the readdir and a following failed op. */ - bytes_left = xdr->buf->buflen - xdr->buf->len - - COMPOUND_ERR_SLACK_SPACE - 8; - if (bytes_left < 0) { - nfserr = nfserr_resource; - goto err_no_verf; - } - maxcount = svc_max_payload(resp->rqstp); - maxcount = min_t(u32, readdir->rd_maxcount, maxcount); + bytes_left = xdr->buf->buflen - xdr->buf->len - + COMPOUND_ERR_SLACK_SPACE - XDR_UNIT * 2; + if (bytes_left < 0) + return nfserr_resource; + maxcount = min_t(u32, readdir->rd_maxcount, max_payload); + /* - * Note the rfc defines rd_maxcount as the size of the - * READDIR4resok structure, which includes the verifier above - * and the 8 bytes encoded at the end of this function: + * The RFC defines rd_maxcount as the size of the + * READDIR4resok structure, which includes the verifier + * and the 8 bytes encoded at the end of this function. */ - if (maxcount < 16) { - nfserr = nfserr_toosmall; - goto err_no_verf; - } - maxcount = min_t(int, maxcount-16, bytes_left); + if (maxcount < XDR_UNIT * 4) + return nfserr_toosmall; + maxcount = min_t(int, maxcount - XDR_UNIT * 4, bytes_left); - /* RFC 3530 14.2.24 allows us to ignore dircount when it's 0: */ + /* RFC 3530 14.2.24 allows us to ignore dircount when it's 0 */ if (!readdir->rd_dircount) - readdir->rd_dircount = svc_max_payload(resp->rqstp); + readdir->rd_dircount = max_payload; + /* *entries */ readdir->xdr = xdr; readdir->rd_maxcount = maxcount; readdir->common.err = 0; readdir->cookie_offset = 0; - offset = readdir->rd_cookie; - nfserr = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp, &offset, + status = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp, &offset, &readdir->common, nfsd4_encode_entry4); - if (nfserr == nfs_ok && - readdir->common.err == nfserr_toosmall && - xdr->buf->len == starting_len + 8) { - /* nothing encoded; which limit did we hit?: */ - if (maxcount - 16 < bytes_left) - /* It was the fault of rd_maxcount: */ - nfserr = nfserr_toosmall; - else - /* We ran out of buffer space: */ - nfserr = nfserr_resource; + if (status) + return status; + if (readdir->common.err == nfserr_toosmall && + xdr->buf->len == starting_len) { + /* No entries were encoded. Which limit did we hit? */ + if (maxcount - XDR_UNIT * 4 < bytes_left) + /* It was the fault of rd_maxcount */ + return nfserr_toosmall; + /* We ran out of buffer space */ + return nfserr_resource; } - if (nfserr) - goto err_no_verf; - /* Encode the final entry's cookie value */ nfsd4_encode_entry4_nfs_cookie4(readdir, offset); + /* No entries follow */ + if (xdr_stream_encode_item_absent(xdr) != XDR_UNIT) + return nfserr_resource; - p = xdr_reserve_space(xdr, 8); - if (!p) { - WARN_ON_ONCE(1); - goto err_no_verf; - } - *p++ = 0; /* no more entries */ - *p++ = htonl(readdir->common.err == nfserr_eof); + /* eof */ + return nfsd4_encode_bool(xdr, readdir->common.err == nfserr_eof); +} - return 0; -err_no_verf: - xdr_truncate_encode(xdr, starting_len); +static __be32 +nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, + union nfsd4_op_u *u) +{ + struct nfsd4_readdir *readdir = &u->readdir; + struct xdr_stream *xdr = resp->xdr; + int starting_len = xdr->buf->len; + + /* cookieverf */ + nfserr = nfsd4_encode_verifier4(xdr, &readdir->rd_verf); + if (nfserr != nfs_ok) + return nfserr; + + /* reply */ + nfserr = nfsd4_encode_dirlist4(xdr, readdir, svc_max_payload(resp->rqstp)); + if (nfserr != nfs_ok) + xdr_truncate_encode(xdr, starting_len); return nfserr; } -- cgit v1.2.3 From d38e570f1915f45708f72129055ea2fb6ad686b3 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 9 Oct 2023 14:29:43 -0400 Subject: NFSD: Clean up nfsd4_encode_access() Convert nfsd4_encode_access() to use modern XDR utility functions. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index a3f04969c3be..5f56f8c02b51 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3908,14 +3908,14 @@ nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, { struct nfsd4_access *access = &u->access; struct xdr_stream *xdr = resp->xdr; - __be32 *p; + __be32 status; - p = xdr_reserve_space(xdr, 8); - if (!p) - return nfserr_resource; - *p++ = cpu_to_be32(access->ac_supported); - *p++ = cpu_to_be32(access->ac_resp_access); - return 0; + /* supported */ + status = nfsd4_encode_uint32_t(xdr, access->ac_supported); + if (status != nfs_ok) + return status; + /* access */ + return nfsd4_encode_uint32_t(xdr, access->ac_resp_access); } static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, -- cgit v1.2.3 From 91c7a9057cfb5a8fda2831e98a6d147817b71744 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 9 Oct 2023 14:29:49 -0400 Subject: NFSD: Clean up nfsd4_do_encode_secinfo() Refactor nfsd4_encode_secinfo() so it is more clear what XDR data item is being encoded by which piece of code. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 56 ++++++++++++++++++++++++++++++++++++++----------------- fs/nfsd/xdr4.h | 1 + 2 files changed, 40 insertions(+), 17 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 5f56f8c02b51..94ed37d8326f 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4555,14 +4555,35 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, return nfsd4_encode_change_info4(xdr, &rename->rn_tinfo); } +static __be32 +nfsd4_encode_rpcsec_gss_info(struct xdr_stream *xdr, + struct rpcsec_gss_info *info) +{ + __be32 status; + + /* oid */ + if (xdr_stream_encode_opaque(xdr, info->oid.data, info->oid.len) < 0) + return nfserr_resource; + /* qop */ + status = nfsd4_encode_qop4(xdr, info->qop); + if (status != nfs_ok) + return status; + /* service */ + if (xdr_stream_encode_u32(xdr, info->service) != XDR_UNIT) + return nfserr_resource; + + return nfs_ok; +} + static __be32 nfsd4_do_encode_secinfo(struct xdr_stream *xdr, struct svc_export *exp) { u32 i, nflavs, supported; struct exp_flavor_info *flavs; struct exp_flavor_info def_flavs[2]; - __be32 *p, *flavorsp; static bool report = true; + __be32 *flavorsp; + __be32 status; if (exp->ex_nflavors) { flavs = exp->ex_flavors; @@ -4585,10 +4606,9 @@ nfsd4_do_encode_secinfo(struct xdr_stream *xdr, struct svc_export *exp) } supported = 0; - p = xdr_reserve_space(xdr, 4); - if (!p) + flavorsp = xdr_reserve_space(xdr, XDR_UNIT); + if (!flavorsp) return nfserr_resource; - flavorsp = p++; /* to be backfilled later */ for (i = 0; i < nflavs; i++) { rpc_authflavor_t pf = flavs[i].pseudoflavor; @@ -4596,20 +4616,22 @@ nfsd4_do_encode_secinfo(struct xdr_stream *xdr, struct svc_export *exp) if (rpcauth_get_gssinfo(pf, &info) == 0) { supported++; - p = xdr_reserve_space(xdr, 4 + 4 + - XDR_LEN(info.oid.len) + 4 + 4); - if (!p) - return nfserr_resource; - *p++ = cpu_to_be32(RPC_AUTH_GSS); - p = xdr_encode_opaque(p, info.oid.data, info.oid.len); - *p++ = cpu_to_be32(info.qop); - *p++ = cpu_to_be32(info.service); + + /* flavor */ + status = nfsd4_encode_uint32_t(xdr, RPC_AUTH_GSS); + if (status != nfs_ok) + return status; + /* flavor_info */ + status = nfsd4_encode_rpcsec_gss_info(xdr, &info); + if (status != nfs_ok) + return status; } else if (pf < RPC_AUTH_MAXFLAVOR) { supported++; - p = xdr_reserve_space(xdr, 4); - if (!p) - return nfserr_resource; - *p++ = cpu_to_be32(pf); + + /* flavor */ + status = nfsd4_encode_uint32_t(xdr, pf); + if (status != nfs_ok) + return status; } else { if (report) pr_warn("NFS: SECINFO: security flavor %u " @@ -4619,7 +4641,7 @@ nfsd4_do_encode_secinfo(struct xdr_stream *xdr, struct svc_export *exp) if (nflavs != supported) report = false; - *flavorsp = htonl(supported); + *flavorsp = cpu_to_be32(supported); return 0; } diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index a97297915112..f97977bbd6fb 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -96,6 +96,7 @@ nfsd4_encode_uint32_t(struct xdr_stream *xdr, u32 val) #define nfsd4_encode_count4(x, v) nfsd4_encode_uint32_t(x, v) #define nfsd4_encode_mode4(x, v) nfsd4_encode_uint32_t(x, v) #define nfsd4_encode_nfs_lease4(x, v) nfsd4_encode_uint32_t(x, v) +#define nfsd4_encode_qop4(x, v) nfsd4_encode_uint32_t(x, v) #define nfsd4_encode_sequenceid4(x, v) nfsd4_encode_uint32_t(x, v) #define nfsd4_encode_slotid4(x, v) nfsd4_encode_uint32_t(x, v) -- cgit v1.2.3 From abef972cf58255749ec0fbd6b581f533401c8473 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 9 Oct 2023 14:29:56 -0400 Subject: NFSD: Clean up nfsd4_encode_exchange_id() Restructure nfsd4_encode_exchange_id() so that it will be more straightforward to add support for SSV one day. Also, adopt the use of the conventional XDR utility functions. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 129 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 74 insertions(+), 55 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 94ed37d8326f..958535cb5f67 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4733,77 +4733,96 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, } static __be32 -nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, - union nfsd4_op_u *u) +nfsd4_encode_state_protect_ops4(struct xdr_stream *xdr, + struct nfsd4_exchange_id *exid) { - struct nfsd4_exchange_id *exid = &u->exchange_id; - struct xdr_stream *xdr = resp->xdr; - __be32 *p; - char *major_id; - char *server_scope; - int major_id_sz; - int server_scope_sz; - uint64_t minor_id = 0; - struct nfsd_net *nn = net_generic(SVC_NET(resp->rqstp), nfsd_net_id); + __be32 status; - major_id = nn->nfsd_name; - major_id_sz = strlen(nn->nfsd_name); - server_scope = nn->nfsd_name; - server_scope_sz = strlen(nn->nfsd_name); + /* spo_must_enforce */ + status = nfsd4_encode_bitmap4(xdr, exid->spo_must_enforce[0], + exid->spo_must_enforce[1], + exid->spo_must_enforce[2]); + if (status != nfs_ok) + return status; + /* spo_must_allow */ + return nfsd4_encode_bitmap4(xdr, exid->spo_must_allow[0], + exid->spo_must_allow[1], + exid->spo_must_allow[2]); +} - if (nfsd4_encode_clientid4(xdr, &exid->clientid) != nfs_ok) - return nfserr_resource; - if (xdr_stream_encode_u32(xdr, exid->seqid) < 0) - return nfserr_resource; - if (xdr_stream_encode_u32(xdr, exid->flags) < 0) - return nfserr_resource; +static __be32 +nfsd4_encode_state_protect4_r(struct xdr_stream *xdr, struct nfsd4_exchange_id *exid) +{ + __be32 status; - if (xdr_stream_encode_u32(xdr, exid->spa_how) < 0) + if (xdr_stream_encode_u32(xdr, exid->spa_how) != XDR_UNIT) return nfserr_resource; switch (exid->spa_how) { case SP4_NONE: + status = nfs_ok; break; case SP4_MACH_CRED: - /* spo_must_enforce bitmap: */ - nfserr = nfsd4_encode_bitmap4(xdr, - exid->spo_must_enforce[0], - exid->spo_must_enforce[1], - exid->spo_must_enforce[2]); - if (nfserr) - return nfserr; - /* spo_must_allow bitmap: */ - nfserr = nfsd4_encode_bitmap4(xdr, - exid->spo_must_allow[0], - exid->spo_must_allow[1], - exid->spo_must_allow[2]); - if (nfserr) - return nfserr; + /* spr_mach_ops */ + status = nfsd4_encode_state_protect_ops4(xdr, exid); break; default: - WARN_ON_ONCE(1); + status = nfserr_serverfault; } + return status; +} - p = xdr_reserve_space(xdr, - 8 /* so_minor_id */ + - 4 /* so_major_id.len */ + - (XDR_QUADLEN(major_id_sz) * 4) + - 4 /* eir_server_scope.len */ + - (XDR_QUADLEN(server_scope_sz) * 4) + - 4 /* eir_server_impl_id.count (0) */); - if (!p) - return nfserr_resource; +static __be32 +nfsd4_encode_server_owner4(struct xdr_stream *xdr, struct svc_rqst *rqstp) +{ + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); + __be32 status; - /* The server_owner struct */ - p = xdr_encode_hyper(p, minor_id); /* Minor id */ - /* major id */ - p = xdr_encode_opaque(p, major_id, major_id_sz); + /* so_minor_id */ + status = nfsd4_encode_uint64_t(xdr, 0); + if (status != nfs_ok) + return status; + /* so_major_id */ + return nfsd4_encode_opaque(xdr, nn->nfsd_name, strlen(nn->nfsd_name)); +} - /* Server scope */ - p = xdr_encode_opaque(p, server_scope, server_scope_sz); +static __be32 +nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, + union nfsd4_op_u *u) +{ + struct nfsd_net *nn = net_generic(SVC_NET(resp->rqstp), nfsd_net_id); + struct nfsd4_exchange_id *exid = &u->exchange_id; + struct xdr_stream *xdr = resp->xdr; - /* Implementation id */ - *p++ = cpu_to_be32(0); /* zero length nfs_impl_id4 array */ - return 0; + /* eir_clientid */ + nfserr = nfsd4_encode_clientid4(xdr, &exid->clientid); + if (nfserr != nfs_ok) + return nfserr; + /* eir_sequenceid */ + nfserr = nfsd4_encode_sequenceid4(xdr, exid->seqid); + if (nfserr != nfs_ok) + return nfserr; + /* eir_flags */ + nfserr = nfsd4_encode_uint32_t(xdr, exid->flags); + if (nfserr != nfs_ok) + return nfserr; + /* eir_state_protect */ + nfserr = nfsd4_encode_state_protect4_r(xdr, exid); + if (nfserr != nfs_ok) + return nfserr; + /* eir_server_owner */ + nfserr = nfsd4_encode_server_owner4(xdr, resp->rqstp); + if (nfserr != nfs_ok) + return nfserr; + /* eir_server_scope */ + nfserr = nfsd4_encode_opaque(xdr, nn->nfsd_name, + strlen(nn->nfsd_name)); + if (nfserr != nfs_ok) + return nfserr; + /* eir_server_impl_id<1> */ + if (xdr_stream_encode_u32(xdr, 0) != XDR_UNIT) + return nfserr_resource; + + return nfs_ok; } static __be32 -- cgit v1.2.3 From 08b4436afb5034be9054b33035c5bb3ff5eec0ea Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 9 Oct 2023 14:30:03 -0400 Subject: NFSD: Clean up nfsd4_encode_test_stateid() Use conventional XDR utilities. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 958535cb5f67..5545e71b0ccb 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4932,20 +4932,18 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr, union nfsd4_op_u *u) { struct nfsd4_test_stateid *test_stateid = &u->test_stateid; - struct xdr_stream *xdr = resp->xdr; struct nfsd4_test_stateid_id *stateid, *next; - __be32 *p; + struct xdr_stream *xdr = resp->xdr; - p = xdr_reserve_space(xdr, 4 + (4 * test_stateid->ts_num_ids)); - if (!p) + /* tsr_status_codes<> */ + if (xdr_stream_encode_u32(xdr, test_stateid->ts_num_ids) != XDR_UNIT) return nfserr_resource; - *p++ = htonl(test_stateid->ts_num_ids); - - list_for_each_entry_safe(stateid, next, &test_stateid->ts_stateid_list, ts_id_list) { - *p++ = stateid->ts_id_status; + list_for_each_entry_safe(stateid, next, + &test_stateid->ts_stateid_list, ts_id_list) { + if (xdr_stream_encode_be32(xdr, stateid->ts_id_status) != XDR_UNIT) + return nfserr_resource; } - - return 0; + return nfs_ok; } #ifdef CONFIG_NFSD_PNFS -- cgit v1.2.3 From 02e0297f160aa1ba9835fed3c97845c9450c2dc3 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 9 Oct 2023 14:30:09 -0400 Subject: NFSD: Clean up nfsd4_encode_copy() Restructure this function using conventional XDR utility functions and so it aligns better with the XDR in the specification. I've also moved nfsd4_encode_copy() closer to the data type encoders that only it uses. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 84 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 45 insertions(+), 39 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 5545e71b0ccb..ce894aba19ce 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -5079,32 +5079,56 @@ nfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr, #endif /* CONFIG_NFSD_PNFS */ static __be32 -nfsd42_encode_write_res(struct nfsd4_compoundres *resp, - struct nfsd42_write_res *write, bool sync) +nfsd4_encode_write_response4(struct xdr_stream *xdr, + const struct nfsd4_copy *copy) { - __be32 *p; - p = xdr_reserve_space(resp->xdr, 4); - if (!p) - return nfserr_resource; + const struct nfsd42_write_res *write = ©->cp_res; + u32 count = nfsd4_copy_is_sync(copy) ? 0 : 1; + __be32 status; - if (sync) - *p++ = cpu_to_be32(0); - else { - __be32 nfserr; - *p++ = cpu_to_be32(1); - nfserr = nfsd4_encode_stateid4(resp->xdr, &write->cb_stateid); - if (nfserr) - return nfserr; + /* wr_callback_id<1> */ + if (xdr_stream_encode_u32(xdr, count) != XDR_UNIT) + return nfserr_resource; + if (count) { + status = nfsd4_encode_stateid4(xdr, &write->cb_stateid); + if (status != nfs_ok) + return status; } - p = xdr_reserve_space(resp->xdr, 8 + 4 + NFS4_VERIFIER_SIZE); - if (!p) + + /* wr_count */ + status = nfsd4_encode_length4(xdr, write->wr_bytes_written); + if (status != nfs_ok) + return status; + /* wr_committed */ + if (xdr_stream_encode_u32(xdr, write->wr_stable_how) != XDR_UNIT) return nfserr_resource; + /* wr_writeverf */ + return nfsd4_encode_verifier4(xdr, &write->wr_verifier); +} - p = xdr_encode_hyper(p, write->wr_bytes_written); - *p++ = cpu_to_be32(write->wr_stable_how); - p = xdr_encode_opaque_fixed(p, write->wr_verifier.data, - NFS4_VERIFIER_SIZE); - return nfs_ok; +static __be32 nfsd4_encode_copy_requirements4(struct xdr_stream *xdr, + const struct nfsd4_copy *copy) +{ + __be32 status; + + /* cr_consecutive */ + status = nfsd4_encode_bool(xdr, true); + if (status != nfs_ok) + return status; + /* cr_synchronous */ + return nfsd4_encode_bool(xdr, nfsd4_copy_is_sync(copy)); +} + +static __be32 +nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr, + union nfsd4_op_u *u) +{ + struct nfsd4_copy *copy = &u->copy; + + nfserr = nfsd4_encode_write_response4(resp->xdr, copy); + if (nfserr != nfs_ok) + return nfserr; + return nfsd4_encode_copy_requirements4(resp->xdr, copy); } static __be32 @@ -5147,24 +5171,6 @@ nfsd42_encode_nl4_server(struct nfsd4_compoundres *resp, struct nl4_server *ns) return 0; } -static __be32 -nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr, - union nfsd4_op_u *u) -{ - struct nfsd4_copy *copy = &u->copy; - __be32 *p; - - nfserr = nfsd42_encode_write_res(resp, ©->cp_res, - nfsd4_copy_is_sync(copy)); - if (nfserr) - return nfserr; - - p = xdr_reserve_space(resp->xdr, 4 + 4); - *p++ = xdr_one; /* cr_consecutive */ - *p = nfsd4_copy_is_sync(copy) ? xdr_one : xdr_zero; - return 0; -} - static __be32 nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr, union nfsd4_op_u *u) -- cgit v1.2.3 From 21d316a767ac2ebc9de281cd2ec5f3c22827dd8e Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 9 Oct 2023 14:30:16 -0400 Subject: NFSD: Clean up nfsd4_encode_copy_notify() Replace open-coded encoding logic with the use of conventional XDR utility functions. Note that if we replace the cpn_sec and cpn_nsec fields with a single struct timespec64 field, the encoder can use nfsd4_encode_nfstime4(), as that is the data type specified by the XDR spec. NFS4ERR_INVAL seems inappropriate if the encoder doesn't support encoding the response. Instead use NFS4ERR_SERVERFAULT, since this condition is a software bug on the server. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4proc.c | 4 +- fs/nfsd/nfs4xdr.c | 106 +++++++++++++++++++++-------------------------------- fs/nfsd/xdr4.h | 3 +- 3 files changed, 44 insertions(+), 69 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index f288039545e3..35987b98d773 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1939,8 +1939,8 @@ nfsd4_copy_notify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (status) return status; - cn->cpn_sec = nn->nfsd4_lease; - cn->cpn_nsec = 0; + cn->cpn_lease_time.tv_sec = nn->nfsd4_lease; + cn->cpn_lease_time.tv_nsec = 0; status = nfserrno(-ENOMEM); cps = nfs4_alloc_init_cpntf_state(nn, stid); diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index ce894aba19ce..c72240c3f4db 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2575,6 +2575,19 @@ nfsd4_encode_change_info4(struct xdr_stream *xdr, const struct nfsd4_change_info return nfsd4_encode_changeid4(xdr, c->after_change); } +static __be32 nfsd4_encode_netaddr4(struct xdr_stream *xdr, + const struct nfs42_netaddr *addr) +{ + __be32 status; + + /* na_r_netid */ + status = nfsd4_encode_opaque(xdr, addr->netid, addr->netid_len); + if (status != nfs_ok) + return status; + /* na_r_addr */ + return nfsd4_encode_opaque(xdr, addr->addr, addr->addr_len); +} + /* Encode as an array of strings the string given with components * separated @sep, escaped with esc_enter and esc_exit. */ @@ -5132,43 +5145,42 @@ nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr, } static __be32 -nfsd42_encode_nl4_server(struct nfsd4_compoundres *resp, struct nl4_server *ns) +nfsd4_encode_netloc4(struct xdr_stream *xdr, const struct nl4_server *ns) { - struct xdr_stream *xdr = resp->xdr; - struct nfs42_netaddr *addr; - __be32 *p; - - p = xdr_reserve_space(xdr, 4); - *p++ = cpu_to_be32(ns->nl4_type); + __be32 status; + if (xdr_stream_encode_u32(xdr, ns->nl4_type) != XDR_UNIT) + return nfserr_resource; switch (ns->nl4_type) { case NL4_NETADDR: - addr = &ns->u.nl4_addr; - - /* netid_len, netid, uaddr_len, uaddr (port included - * in RPCBIND_MAXUADDRLEN) - */ - p = xdr_reserve_space(xdr, - 4 /* netid len */ + - (XDR_QUADLEN(addr->netid_len) * 4) + - 4 /* uaddr len */ + - (XDR_QUADLEN(addr->addr_len) * 4)); - if (!p) - return nfserr_resource; - - *p++ = cpu_to_be32(addr->netid_len); - p = xdr_encode_opaque_fixed(p, addr->netid, - addr->netid_len); - *p++ = cpu_to_be32(addr->addr_len); - p = xdr_encode_opaque_fixed(p, addr->addr, - addr->addr_len); + /* nl_addr */ + status = nfsd4_encode_netaddr4(xdr, &ns->u.nl4_addr); break; default: - WARN_ON_ONCE(ns->nl4_type != NL4_NETADDR); - return nfserr_inval; + status = nfserr_serverfault; } + return status; +} - return 0; +static __be32 +nfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr, + union nfsd4_op_u *u) +{ + struct nfsd4_copy_notify *cn = &u->copy_notify; + struct xdr_stream *xdr = resp->xdr; + + /* cnr_lease_time */ + nfserr = nfsd4_encode_nfstime4(xdr, &cn->cpn_lease_time); + if (nfserr) + return nfserr; + /* cnr_stateid */ + nfserr = nfsd4_encode_stateid4(xdr, &cn->cpn_cnr_stateid); + if (nfserr) + return nfserr; + /* cnr_source_server<> */ + if (xdr_stream_encode_u32(xdr, 1) != XDR_UNIT) + return nfserr_resource; + return nfsd4_encode_netloc4(xdr, cn->cpn_src); } static __be32 @@ -5261,42 +5273,6 @@ out: return nfserr; } -static __be32 -nfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr, - union nfsd4_op_u *u) -{ - struct nfsd4_copy_notify *cn = &u->copy_notify; - struct xdr_stream *xdr = resp->xdr; - __be32 *p; - - if (nfserr) - return nfserr; - - /* 8 sec, 4 nsec */ - p = xdr_reserve_space(xdr, 12); - if (!p) - return nfserr_resource; - - /* cnr_lease_time */ - p = xdr_encode_hyper(p, cn->cpn_sec); - *p++ = cpu_to_be32(cn->cpn_nsec); - - /* cnr_stateid */ - nfserr = nfsd4_encode_stateid4(xdr, &cn->cpn_cnr_stateid); - if (nfserr) - return nfserr; - - /* cnr_src.nl_nsvr */ - p = xdr_reserve_space(xdr, 4); - if (!p) - return nfserr_resource; - - *p++ = cpu_to_be32(1); - - nfserr = nfsd42_encode_nl4_server(resp, cn->cpn_src); - return nfserr; -} - static __be32 nfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr, union nfsd4_op_u *u) diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index f97977bbd6fb..80e859dc84d8 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -745,8 +745,7 @@ struct nfsd4_copy_notify { /* response */ stateid_t cpn_cnr_stateid; - u64 cpn_sec; - u32 cpn_nsec; + struct timespec64 cpn_lease_time; struct nl4_server *cpn_src; }; -- cgit v1.2.3 From b609ad60b7adcb0594fa2278f1d8ffecc4fd07d4 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 9 Oct 2023 14:30:23 -0400 Subject: NFSD: Clean up nfsd4_encode_offset_status() Use modern XDR encoder utilities. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index c72240c3f4db..aa477ba2a654 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -5189,14 +5189,15 @@ nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr, { struct nfsd4_offload_status *os = &u->offload_status; struct xdr_stream *xdr = resp->xdr; - __be32 *p; - p = xdr_reserve_space(xdr, 8 + 4); - if (!p) + /* osr_count */ + nfserr = nfsd4_encode_length4(xdr, os->count); + if (nfserr != nfs_ok) + return nfserr; + /* osr_complete<1> */ + if (xdr_stream_encode_u32(xdr, 0) != XDR_UNIT) return nfserr_resource; - p = xdr_encode_hyper(p, os->count); - *p++ = cpu_to_be32(0); - return nfserr; + return nfs_ok; } static __be32 -- cgit v1.2.3 From 1f121e2de4857258ac9ecf6d1844f2d581612395 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 9 Oct 2023 14:30:29 -0400 Subject: NFSD: Clean up nfsd4_encode_seek() Use modern XDR encoder utilities. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index aa477ba2a654..ec4ed6206df1 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -5279,13 +5279,14 @@ nfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr, union nfsd4_op_u *u) { struct nfsd4_seek *seek = &u->seek; - __be32 *p; - - p = xdr_reserve_space(resp->xdr, 4 + 8); - *p++ = cpu_to_be32(seek->seek_eof); - p = xdr_encode_hyper(p, seek->seek_pos); + struct xdr_stream *xdr = resp->xdr; - return 0; + /* sr_eof */ + nfserr = nfsd4_encode_bool(xdr, seek->seek_eof); + if (nfserr != nfs_ok) + return nfserr; + /* sr_offset */ + return nfsd4_encode_offset4(xdr, seek->seek_pos); } static __be32 -- cgit v1.2.3 From bf32075256e9dd9c6b736859e2c5813981339908 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 25 Sep 2023 12:06:44 +1000 Subject: NFSD: simplify error paths in nfsd_svc() The error paths in nfsd_svc() are needlessly complex and can result in a final call to svc_put() without nfsd_last_thread() being called. This results in the listening sockets not being closed properly. The per-netns setup provided by nfsd_startup_new() and removed by nfsd_shutdown_net() is needed precisely when there are running threads. So we don't need nfsd_up_before. We don't need to know if it *was* up. We only need to know if any threads are left. If none are, then we must call nfsd_shutdown_net(). But we don't need to do that explicitly as nfsd_last_thread() does that for us. So simply call nfsd_last_thread() before the last svc_put() if there are no running threads. That will always do the right thing. Also discard: pr_info("nfsd: last server has exited, flushing export cache\n"); It may not be true if an attempt to start the first server failed, and it isn't particularly helpful and it simply reports normal behaviour. Signed-off-by: NeilBrown Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfssvc.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index c5890cdfe97b..d6122bb2d167 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -572,7 +572,6 @@ static void nfsd_last_thread(struct net *net) return; nfsd_shutdown_net(net); - pr_info("nfsd: last server has exited, flushing export cache\n"); nfsd_export_flush(net); } @@ -786,7 +785,6 @@ int nfsd_svc(int nrservs, struct net *net, const struct cred *cred) { int error; - bool nfsd_up_before; struct nfsd_net *nn = net_generic(net, nfsd_net_id); struct svc_serv *serv; @@ -806,8 +804,6 @@ nfsd_svc(int nrservs, struct net *net, const struct cred *cred) error = nfsd_create_serv(net); if (error) goto out; - - nfsd_up_before = nn->nfsd_net_up; serv = nn->nfsd_serv; error = nfsd_startup_net(net, cred); @@ -815,17 +811,15 @@ nfsd_svc(int nrservs, struct net *net, const struct cred *cred) goto out_put; error = svc_set_num_threads(serv, NULL, nrservs); if (error) - goto out_shutdown; + goto out_put; error = serv->sv_nrthreads; - if (error == 0) - nfsd_last_thread(net); -out_shutdown: - if (error < 0 && !nfsd_up_before) - nfsd_shutdown_net(net); out_put: /* Threads now hold service active */ if (xchg(&nn->keep_active, 0)) svc_put(serv); + + if (serv->sv_nrthreads == 0) + nfsd_last_thread(net); svc_put(serv); out: mutex_unlock(&nfsd_mutex); -- cgit v1.2.3 From 0e5559ebe7f48d7957587e441abdaa331133d503 Mon Sep 17 00:00:00 2001 From: KaiLong Wang Date: Thu, 28 Sep 2023 10:35:16 +0800 Subject: NFSD: Clean up errors in stats.c Fix the following errors reported by checkpatch: ERROR: space required after that ',' (ctx:VxV) Signed-off-by: KaiLong Wang Signed-off-by: Chuck Lever --- fs/nfsd/stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/stats.c b/fs/nfsd/stats.c index 63797635e1c3..8914445dafb8 100644 --- a/fs/nfsd/stats.c +++ b/fs/nfsd/stats.c @@ -60,7 +60,7 @@ static int nfsd_show(struct seq_file *seq, void *v) #ifdef CONFIG_NFSD_V4 /* Show count for individual nfsv4 operations */ /* Writing operation numbers 0 1 2 also for maintaining uniformity */ - seq_printf(seq,"proc4ops %u", LAST_NFS4_OP + 1); + seq_printf(seq, "proc4ops %u", LAST_NFS4_OP + 1); for (i = 0; i <= LAST_NFS4_OP; i++) { seq_printf(seq, " %lld", percpu_counter_sum_positive(&nfsdstats.counter[NFSD_STATS_NFS4_OP(i)])); -- cgit v1.2.3 From 03a0497f83c25292e11c934ee1a2f769f14b4f3c Mon Sep 17 00:00:00 2001 From: KaiLong Wang Date: Thu, 28 Sep 2023 10:43:04 +0800 Subject: nfsd: Clean up errors in nfs4state.c Fix the following errors reported by checkpatch: ERROR: spaces required around that '=' (ctx:VxW) ERROR: space required after that ',' (ctx:VxO) ERROR: space required before that '~' (ctx:OxV) Signed-off-by: KaiLong Wang Signed-off-by: Chuck Lever --- fs/nfsd/nfs4state.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 40018cc914a4..54ad16d6d920 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -59,7 +59,7 @@ #define NFSDDBG_FACILITY NFSDDBG_PROC -#define all_ones {{~0,~0},~0} +#define all_ones {{ ~0, ~0}, ~0} static const stateid_t one_stateid = { .si_generation = ~0, .si_opaque = all_ones, @@ -298,7 +298,7 @@ find_or_allocate_block(struct nfs4_lockowner *lo, struct knfsd_fh *fh, nbl = find_blocked_lock(lo, fh, nn); if (!nbl) { - nbl= kmalloc(sizeof(*nbl), GFP_KERNEL); + nbl = kmalloc(sizeof(*nbl), GFP_KERNEL); if (nbl) { INIT_LIST_HEAD(&nbl->nbl_list); INIT_LIST_HEAD(&nbl->nbl_lru); -- cgit v1.2.3 From afb8aae519bcdbcc9d9d8d07e249fe4131381e8c Mon Sep 17 00:00:00 2001 From: KaiLong Wang Date: Thu, 28 Sep 2023 10:51:55 +0800 Subject: nfsd: Clean up errors in nfs3proc.c Fix the following errors reported by checkpatch: ERROR: need consistent spacing around '+' (ctx:WxV) ERROR: spaces required around that '?' (ctx:VxW) Signed-off-by: KaiLong Wang Signed-off-by: Chuck Lever --- fs/nfsd/nfs3proc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 268ef57751c4..9571141701ff 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -171,7 +171,8 @@ nfsd3_proc_read(struct svc_rqst *rqstp) * + 1 (xdr opaque byte count) = 26 */ resp->count = argp->count; - svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4); + svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3) << 2) + + resp->count + 4); fh_copy(&resp->fh, &argp->fh); resp->status = nfsd_read(rqstp, &resp->fh, argp->offset, @@ -194,7 +195,7 @@ nfsd3_proc_write(struct svc_rqst *rqstp) SVCFH_fmt(&argp->fh), argp->len, (unsigned long long) argp->offset, - argp->stable? " stable" : ""); + argp->stable ? " stable" : ""); resp->status = nfserr_fbig; if (argp->offset > (u64)OFFSET_MAX || -- cgit v1.2.3 From 5ec39944f874e1ecc09f624a70dfaa8ac3bf9d08 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 1 Oct 2023 13:25:09 -0400 Subject: NFSD: Rewrite synopsis of nfsd_percpu_counters_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In function ‘export_stats_init’, inlined from ‘svc_export_alloc’ at fs/nfsd/export.c:866:6: fs/nfsd/export.c:337:16: warning: ‘nfsd_percpu_counters_init’ accessing 40 bytes in a region of size 0 [-Wstringop-overflow=] 337 | return nfsd_percpu_counters_init(&stats->counter, EXP_STATS_COUNTERS_NUM); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ fs/nfsd/export.c:337:16: note: referencing argument 1 of type ‘struct percpu_counter[0]’ fs/nfsd/stats.h: In function ‘svc_export_alloc’: fs/nfsd/stats.h:40:5: note: in a call to function ‘nfsd_percpu_counters_init’ 40 | int nfsd_percpu_counters_init(struct percpu_counter counters[], int num); | ^~~~~~~~~~~~~~~~~~~~~~~~~ Cc: Amir Goldstein Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/stats.c | 2 +- fs/nfsd/stats.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/stats.c b/fs/nfsd/stats.c index 8914445dafb8..12d79f5d4eb1 100644 --- a/fs/nfsd/stats.c +++ b/fs/nfsd/stats.c @@ -76,7 +76,7 @@ static int nfsd_show(struct seq_file *seq, void *v) DEFINE_PROC_SHOW_ATTRIBUTE(nfsd); -int nfsd_percpu_counters_init(struct percpu_counter counters[], int num) +int nfsd_percpu_counters_init(struct percpu_counter *counters, int num) { int i, err = 0; diff --git a/fs/nfsd/stats.h b/fs/nfsd/stats.h index cf5524e7ca06..a3e9e2f47ec4 100644 --- a/fs/nfsd/stats.h +++ b/fs/nfsd/stats.h @@ -37,9 +37,9 @@ extern struct nfsd_stats nfsdstats; extern struct svc_stat nfsd_svcstats; -int nfsd_percpu_counters_init(struct percpu_counter counters[], int num); -void nfsd_percpu_counters_reset(struct percpu_counter counters[], int num); -void nfsd_percpu_counters_destroy(struct percpu_counter counters[], int num); +int nfsd_percpu_counters_init(struct percpu_counter *counters, int num); +void nfsd_percpu_counters_reset(struct percpu_counter *counters, int num); +void nfsd_percpu_counters_destroy(struct percpu_counter *counters, int num); int nfsd_stat_init(void); void nfsd_stat_shutdown(void); -- cgit v1.2.3 From 6939ace1f22681fface7841cdbf34d3204cc94b5 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 1 Oct 2023 13:25:16 -0400 Subject: NFSD: Fix frame size warning in svc_export_parse() fs/nfsd/export.c: In function 'svc_export_parse': fs/nfsd/export.c:737:1: warning: the frame size of 1040 bytes is larger than 1024 bytes [-Wframe-larger-than=] 737 | } On my systems, svc_export_parse() has a stack frame of over 800 bytes, not 1040, but nonetheless, it could do with some reduction. When a struct svc_export is on the stack, it's a temporary structure used as an argument, and not visible as an actual exported FS. No need to reserve space for export_stats in such cases. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202310012359.YEw5IrK6-lkp@intel.com/ Cc: Amir Goldstein Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/export.c | 32 +++++++++++++++++++++++--------- fs/nfsd/export.h | 4 ++-- fs/nfsd/stats.h | 12 ++++++------ 3 files changed, 31 insertions(+), 17 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 11a0eaa2f914..b7da17e53007 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -339,12 +339,16 @@ static int export_stats_init(struct export_stats *stats) static void export_stats_reset(struct export_stats *stats) { - nfsd_percpu_counters_reset(stats->counter, EXP_STATS_COUNTERS_NUM); + if (stats) + nfsd_percpu_counters_reset(stats->counter, + EXP_STATS_COUNTERS_NUM); } static void export_stats_destroy(struct export_stats *stats) { - nfsd_percpu_counters_destroy(stats->counter, EXP_STATS_COUNTERS_NUM); + if (stats) + nfsd_percpu_counters_destroy(stats->counter, + EXP_STATS_COUNTERS_NUM); } static void svc_export_put(struct kref *ref) @@ -353,7 +357,8 @@ static void svc_export_put(struct kref *ref) path_put(&exp->ex_path); auth_domain_put(exp->ex_client); nfsd4_fslocs_free(&exp->ex_fslocs); - export_stats_destroy(&exp->ex_stats); + export_stats_destroy(exp->ex_stats); + kfree(exp->ex_stats); kfree(exp->ex_uuid); kfree_rcu(exp, ex_rcu); } @@ -767,13 +772,15 @@ static int svc_export_show(struct seq_file *m, seq_putc(m, '\t'); seq_escape(m, exp->ex_client->name, " \t\n\\"); if (export_stats) { - seq_printf(m, "\t%lld\n", exp->ex_stats.start_time); + struct percpu_counter *counter = exp->ex_stats->counter; + + seq_printf(m, "\t%lld\n", exp->ex_stats->start_time); seq_printf(m, "\tfh_stale: %lld\n", - percpu_counter_sum_positive(&exp->ex_stats.counter[EXP_STATS_FH_STALE])); + percpu_counter_sum_positive(&counter[EXP_STATS_FH_STALE])); seq_printf(m, "\tio_read: %lld\n", - percpu_counter_sum_positive(&exp->ex_stats.counter[EXP_STATS_IO_READ])); + percpu_counter_sum_positive(&counter[EXP_STATS_IO_READ])); seq_printf(m, "\tio_write: %lld\n", - percpu_counter_sum_positive(&exp->ex_stats.counter[EXP_STATS_IO_WRITE])); + percpu_counter_sum_positive(&counter[EXP_STATS_IO_WRITE])); seq_putc(m, '\n'); return 0; } @@ -819,7 +826,7 @@ static void svc_export_init(struct cache_head *cnew, struct cache_head *citem) new->ex_layout_types = 0; new->ex_uuid = NULL; new->cd = item->cd; - export_stats_reset(&new->ex_stats); + export_stats_reset(new->ex_stats); } static void export_update(struct cache_head *cnew, struct cache_head *citem) @@ -856,7 +863,14 @@ static struct cache_head *svc_export_alloc(void) if (!i) return NULL; - if (export_stats_init(&i->ex_stats)) { + i->ex_stats = kmalloc(sizeof(*(i->ex_stats)), GFP_KERNEL); + if (!i->ex_stats) { + kfree(i); + return NULL; + } + + if (export_stats_init(i->ex_stats)) { + kfree(i->ex_stats); kfree(i); return NULL; } diff --git a/fs/nfsd/export.h b/fs/nfsd/export.h index 2df8ae25aad3..ca9dc230ae3d 100644 --- a/fs/nfsd/export.h +++ b/fs/nfsd/export.h @@ -64,10 +64,10 @@ struct svc_export { struct cache_head h; struct auth_domain * ex_client; int ex_flags; + int ex_fsid; struct path ex_path; kuid_t ex_anon_uid; kgid_t ex_anon_gid; - int ex_fsid; unsigned char * ex_uuid; /* 16 byte fsid */ struct nfsd4_fs_locations ex_fslocs; uint32_t ex_nflavors; @@ -76,8 +76,8 @@ struct svc_export { struct nfsd4_deviceid_map *ex_devid_map; struct cache_detail *cd; struct rcu_head ex_rcu; - struct export_stats ex_stats; unsigned long ex_xprtsec_modes; + struct export_stats *ex_stats; }; /* an "export key" (expkey) maps a filehandlefragement to an diff --git a/fs/nfsd/stats.h b/fs/nfsd/stats.h index a3e9e2f47ec4..14f50c660b61 100644 --- a/fs/nfsd/stats.h +++ b/fs/nfsd/stats.h @@ -61,22 +61,22 @@ static inline void nfsd_stats_rc_nocache_inc(void) static inline void nfsd_stats_fh_stale_inc(struct svc_export *exp) { percpu_counter_inc(&nfsdstats.counter[NFSD_STATS_FH_STALE]); - if (exp) - percpu_counter_inc(&exp->ex_stats.counter[EXP_STATS_FH_STALE]); + if (exp && exp->ex_stats) + percpu_counter_inc(&exp->ex_stats->counter[EXP_STATS_FH_STALE]); } static inline void nfsd_stats_io_read_add(struct svc_export *exp, s64 amount) { percpu_counter_add(&nfsdstats.counter[NFSD_STATS_IO_READ], amount); - if (exp) - percpu_counter_add(&exp->ex_stats.counter[EXP_STATS_IO_READ], amount); + if (exp && exp->ex_stats) + percpu_counter_add(&exp->ex_stats->counter[EXP_STATS_IO_READ], amount); } static inline void nfsd_stats_io_write_add(struct svc_export *exp, s64 amount) { percpu_counter_add(&nfsdstats.counter[NFSD_STATS_IO_WRITE], amount); - if (exp) - percpu_counter_add(&exp->ex_stats.counter[EXP_STATS_IO_WRITE], amount); + if (exp && exp->ex_stats) + percpu_counter_add(&exp->ex_stats->counter[EXP_STATS_IO_WRITE], amount); } static inline void nfsd_stats_payload_misses_inc(struct nfsd_net *nn) -- cgit v1.2.3 From 2ffda63c98f4eb2fdca49a93017bed1ad3ae00e7 Mon Sep 17 00:00:00 2001 From: Sicong Huang Date: Thu, 12 Oct 2023 16:34:58 +0800 Subject: NFSD: clean up alloc_init_deleg() Modify the conditional statement for null pointer check in the function 'alloc_init_deleg' to make this function more robust and clear. Otherwise, this function may have potential pointer dereference problem in the future, when modifying or expanding the nfs4_delegation structure. Signed-off-by: Sicong Huang Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4state.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 54ad16d6d920..65fd5510323a 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1160,6 +1160,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate, u32 dl_type) { struct nfs4_delegation *dp; + struct nfs4_stid *stid; long n; dprintk("NFSD alloc_init_deleg\n"); @@ -1168,9 +1169,10 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, goto out_dec; if (delegation_blocked(&fp->fi_fhandle)) goto out_dec; - dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg)); - if (dp == NULL) + stid = nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg); + if (stid == NULL) goto out_dec; + dp = delegstateid(stid); /* * delegation seqid's are never incremented. The 4.1 special -- cgit v1.2.3